X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fclientsocket.c;h=1f66a261bab66bcb72c46c6d2a30e8f86ba7b17a;hb=56d69e5d8434e98835a2582c59b771ba69475431;hp=a9190754c96c55e9d582184fa4a9b58f11746c8f;hpb=4835a9cb595d4302bdc2be4d94e86321b4138e95;p=citadel.git diff --git a/citadel/clientsocket.c b/citadel/clientsocket.c index a9190754c..1f66a261b 100644 --- a/citadel/clientsocket.c +++ b/citadel/clientsocket.c @@ -1,26 +1,24 @@ /* - * $Id$ - * * This module handles client-side sockets opened by the Citadel server (for * the client side of Internet protocols, etc.) It does _not_ handle client * sockets for the Citadel client; for that you must look in ipc_c_tcp.c * (which, uncoincidentally, bears a striking similarity to this file). * - * Copyright (c) 1987-2009 by the citadel.org team + * Copyright (c) 1987-2010 by the citadel.org team * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdep.h" @@ -47,89 +45,70 @@ #include "sysdep_decls.h" #include "config.h" #include "clientsocket.h" - #include "ctdl_module.h" -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff -#endif - -int sock_connect(char *host, char *service, char *protocol) +int sock_connect(char *host, char *service) { - struct hostent *phe; - struct servent *pse; - struct protoent *ppe; - struct sockaddr_in sin; - struct sockaddr_in egress_sin; - int s, type; - - if ((host == NULL) || IsEmptyStr(host)) - return(-1); - if ((service == NULL) || IsEmptyStr(service)) - return(-1); - if ((protocol == NULL) || IsEmptyStr(protocol)) - return(-1); - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - - pse = getservbyname(service, protocol); - if (pse) { - sin.sin_port = pse->s_port; - } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) { - CtdlLogPrintf(CTDL_CRIT, "Can't get %s service entry: %s\n", - service, strerror(errno)); - return(-1); - } - phe = gethostbyname(host); - if (phe) { - memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); - } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) { - CtdlLogPrintf(CTDL_ERR, "Can't get %s host entry: %s\n", - host, strerror(errno)); - return(-1); - } - if ((ppe = getprotobyname(protocol)) == 0) { - CtdlLogPrintf(CTDL_CRIT, "Can't get %s protocol entry: %s\n", - protocol, strerror(errno)); - return(-1); - } - if (!strcmp(protocol, "udp")) { - type = SOCK_DGRAM; + struct in6_addr serveraddr; + struct addrinfo hints; + struct addrinfo *res = NULL; + struct addrinfo *ai = NULL; + int rc = (-1); + int sock = (-1); + + if ((host == NULL) || IsEmptyStr(host)) + return (-1); + if ((service == NULL) || IsEmptyStr(service)) + return (-1); + + memset(&hints, 0x00, sizeof(hints)); + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* + * Handle numeric IPv4 and IPv6 addresses + */ + rc = inet_pton(AF_INET, host, &serveraddr); + if (rc == 1) { /* dotted quad */ + hints.ai_family = AF_INET; + hints.ai_flags |= AI_NUMERICHOST; } else { - type = SOCK_STREAM; + rc = inet_pton(AF_INET6, host, &serveraddr); + if (rc == 1) { /* IPv6 address */ + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; + } } - s = socket(PF_INET, type, ppe->p_proto); - if (s < 0) { - CtdlLogPrintf(CTDL_CRIT, "Can't create socket: %s\n", strerror(errno)); + /* Begin the connection process */ + + rc = getaddrinfo(host, service, &hints, &res); + if (rc != 0) { + CtdlLogPrintf(CTDL_ERR, "%s: %s\n", host, gai_strerror(rc)); return(-1); } - /* If citserver is bound to a specific IP address on the host, make - * sure we use that address for outbound connections. + /* + * Try all available addresses until we connect to one or until we run out. */ - memset(&egress_sin, 0, sizeof(egress_sin)); - egress_sin.sin_family = AF_INET; - if (!IsEmptyStr(config.c_ip_addr)) { - egress_sin.sin_addr.s_addr = inet_addr(config.c_ip_addr); - if (egress_sin.sin_addr.s_addr == !INADDR_ANY) { - egress_sin.sin_addr.s_addr = INADDR_ANY; + for (ai = res; ai != NULL; ai = ai->ai_next) { + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + CtdlLogPrintf(CTDL_ERR, "socket() failed: %s\n", strerror(errno)); + return(-1); + } + rc = connect(sock, ai->ai_addr, ai->ai_addrlen); + if (rc >= 0) { + return(sock); + } + else { + CtdlLogPrintf(CTDL_ERR, "connect() failed: %s\n", strerror(errno)); + close(sock); } - - /* If this bind fails, no problem; we can still use INADDR_ANY */ - bind(s, (struct sockaddr *)&egress_sin, sizeof(egress_sin)); - } - - /* Now try to connect to the remote host. */ - if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - CtdlLogPrintf(CTDL_ERR, "Can't connect to %s:%s: %s\n", - host, service, strerror(errno)); - close(s); - return(-1); } - return (s); + return(-1); } @@ -147,55 +126,40 @@ int sock_connect(char *host, char *service, char *protocol) * 0 Request timed out. * -1 Connection is broken, or other error. */ -int socket_read_blob(int *Socket, - StrBuf *Target, - int bytes, - int timeout) +int socket_read_blob(int *Socket, StrBuf * Target, int bytes, int timeout) { - CitContext *CCC=CC; + CitContext *CCC = MyContext(); const char *Error; int retval = 0; - retval = StrBufReadBLOBBuffered(Target, + retval = StrBufReadBLOBBuffered(Target, CCC->sReadBuf, &CCC->sPos, - Socket, - 1, - bytes, - O_TERM, - &Error); + Socket, 1, bytes, O_TERM, &Error); if (retval < 0) { - CtdlLogPrintf(CTDL_CRIT, - "%s failed: %s\n", - __FUNCTION__, - Error); + CtdlLogPrintf(CTDL_CRIT, + "%s failed: %s\n", __FUNCTION__, Error); } return retval; } -int sock_read_to(int *sock, char *buf, int bytes, int timeout, int keep_reading_until_full) +int sock_read_to(int *sock, char *buf, int bytes, int timeout, + int keep_reading_until_full) { - CitContext *CCC=CC; + CitContext *CCC = MyContext(); int rc; - rc = socket_read_blob(sock, - CCC->sMigrateBuf, - bytes, - timeout); - if (rc < 0) - { + FlushStrBuf(CCC->MigrateBuf); + rc = socket_read_blob(sock, CCC->sMigrateBuf, bytes, timeout); + if (rc < 0) { *buf = '\0'; return rc; - } - else - { + } else { if (StrLength(CCC->MigrateBuf) < bytes) bytes = StrLength(CCC->MigrateBuf); - memcpy(buf, - ChrPtr(CCC->MigrateBuf), - bytes); + memcpy(buf, ChrPtr(CCC->MigrateBuf), bytes); FlushStrBuf(CCC->MigrateBuf); return rc; @@ -203,24 +167,20 @@ int sock_read_to(int *sock, char *buf, int bytes, int timeout, int keep_reading_ } -int CtdlSockGetLine(int *sock, StrBuf *Target) +int CtdlSockGetLine(int *sock, StrBuf * Target) { - CitContext *CCC=CC; + CitContext *CCC = MyContext(); const char *Error; int rc; - rc = StrBufTCP_read_buffered_line_fast(Target, + FlushStrBuf(Target); + rc = StrBufTCP_read_buffered_line_fast(Target, CCC->sReadBuf, &CCC->sPos, - sock, - 5, - 1, - &Error); + sock, 5, 1, &Error); if ((rc < 0) && (Error != NULL)) - CtdlLogPrintf(CTDL_CRIT, - "%s failed: %s\n", - __FUNCTION__, - Error); + CtdlLogPrintf(CTDL_CRIT, + "%s failed: %s\n", __FUNCTION__, Error); return rc; } @@ -233,9 +193,10 @@ int CtdlSockGetLine(int *sock, StrBuf *Target) int sock_getln(int *sock, char *buf, int bufsize) { int i, retval; - CitContext *CCC=CC; + CitContext *CCC = MyContext(); const char *pCh; + FlushStrBuf(CCC->sMigrateBuf); retval = CtdlSockGetLine(sock, CCC->sMigrateBuf); i = StrLength(CCC->sMigrateBuf); @@ -244,9 +205,9 @@ int sock_getln(int *sock, char *buf, int bufsize) */ if (bufsize <= i) i = bufsize - 1; - while ( (i > 0) - && ( (pCh[i - 1]==13) - || ( pCh[i - 1]==10)) ) { + while ((i > 0) + && ((pCh[i - 1] == 13) + || (pCh[i - 1] == 10))) { i--; } memcpy(buf, pCh, i); @@ -265,9 +226,11 @@ int sock_getln(int *sock, char *buf, int bufsize) * sock_read() - input binary data from socket. * Returns the number of bytes read, or -1 for error. */ -INLINE int sock_read(int *sock, char *buf, int bytes, int keep_reading_until_full) +INLINE int sock_read(int *sock, char *buf, int bytes, + int keep_reading_until_full) { - return sock_read_to(sock, buf, bytes, CLIENT_TIMEOUT, keep_reading_until_full); + return sock_read_to(sock, buf, bytes, CLIENT_TIMEOUT, + keep_reading_until_full); } @@ -280,9 +243,7 @@ int sock_write(int *sock, const char *buf, int nbytes) int bytes_written = 0; int retval; - while ((*sock != -1) && - (bytes_written < nbytes)) - { + while ((*sock != -1) && (bytes_written < nbytes)) { retval = write(*sock, &buf[bytes_written], nbytes - bytes_written); if (retval < 1) { @@ -301,20 +262,24 @@ int sock_write(int *sock, const char *buf, int nbytes) * client side protocol implementations. It only returns the first line of * a multiline response, discarding the rest. */ -int ml_sock_gets(int *sock, char *buf) { +int ml_sock_gets(int *sock, char *buf) +{ char bigbuf[1024]; int g; g = sock_getln(sock, buf, SIZ); - if (g < 4) return(g); - if (buf[3] != '-') return(g); + if (g < 4) + return (g); + if (buf[3] != '-') + return (g); do { g = sock_getln(sock, bigbuf, SIZ); - if (g < 0) return(g); - } while ( (g >= 4) && (bigbuf[3] == '-') ); + if (g < 0) + return (g); + } while ((g >= 4) && (bigbuf[3] == '-')); - return(strlen(buf)); + return (strlen(buf)); } @@ -327,8 +292,10 @@ int sock_puts(int *sock, char *buf) int i, j; i = sock_write(sock, buf, strlen(buf)); - if (i<0) return(i); + if (i < 0) + return (i); j = sock_write(sock, "\n", 1); - if (j<0) return(j); - return(i+j); + if (j < 0) + return (j); + return (i + j); }