From 3845d02d4da59c21f28c7dcf986cfa5f7c4d7175 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Thu, 19 Aug 2010 16:52:24 +0000 Subject: [PATCH] * Updated the text client with the new tcp client socket implementation which supports multiple addresses per host and IPv4/IPv6. --- citadel/include/citadel_ipc.h | 2 +- citadel/utillib/citadel_ipc.c | 97 +++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 34 deletions(-) diff --git a/citadel/include/citadel_ipc.h b/citadel/include/citadel_ipc.h index 6c9424fb5..e03fa340b 100644 --- a/citadel/include/citadel_ipc.h +++ b/citadel/include/citadel_ipc.h @@ -6,7 +6,7 @@ #else #define DEFAULT_HOST UDS #endif -#define DEFAULT_PORT "citadel" +#define DEFAULT_PORT "504" #include "sysdep.h" #ifdef HAVE_PTHREAD_H diff --git a/citadel/utillib/citadel_ipc.c b/citadel/utillib/citadel_ipc.c index 016207aa2..769ffd31a 100644 --- a/citadel/utillib/citadel_ipc.c +++ b/citadel/utillib/citadel_ipc.c @@ -2613,51 +2613,82 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc, } -static int tcp_connectsock(char *host, char *service, int defaultPort) +/* + * Connect to a Citadel on a remote host using a TCP/IP socket + */ +static int tcp_connectsock(char *host, char *service) { - struct hostent *phe; - struct servent *pse; - struct protoent *ppe; - struct sockaddr_in sin; - int s, type; + struct in6_addr serveraddr; + struct addrinfo hints, *res = NULL; + int rc; + int sock = (-1); - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - - pse = getservbyname(service, "tcp"); - if (pse != NULL) { - sin.sin_port = pse->s_port; + if ((host == NULL) || IsEmptyStr(host)) { + service = DEFAULT_HOST ; } - else if (atoi(service) > 0) { - sin.sin_port = htons(atoi(service)); + if ((service == NULL) || IsEmptyStr(service)) { + service = DEFAULT_PORT ; } - else { - sin.sin_port = htons(defaultPort); - } - 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) { - 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 { + rc = inet_pton(AF_INET6, host, &serveraddr); + if (rc == 1) { /* IPv6 address */ + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; + } } - if ((ppe = getprotobyname("tcp")) == 0) { - return -1; + + /* 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); } - type = SOCK_STREAM; - s = socket(PF_INET, type, ppe->p_proto); - if (s < 0) { - return -1; + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) { + // CtdlLogPrintf(CTDL_ERR, "socket() failed: %s\n", strerror(errno)); + return(-1); } - if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - close(s); - return -1; + /* + * Try all available addresses until we connect to one or until we run out. + */ + struct addrinfo *ai; + for (ai = res; ai != NULL; ai = ai->ai_next) { + /* FIXME display the address to which we are trying to connect */ + rc = connect(sock, res->ai_addr, res->ai_addrlen); + if (rc >= 0) { + return(sock); + } + else { + // CtdlLogPrintf(CTDL_ERR, "connect() failed: %s\n", strerror(errno)); + } } - return (s); + return(-1); } + + + + +/* + * Connect to a Citadel on the local host using a unix domain socket + */ static int uds_connectsock(int *isLocal, char *sockpath) { struct sockaddr_un addr; @@ -3238,7 +3269,7 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf) return ipc; } - ipc->sock = tcp_connectsock(cithost, citport, 504); + ipc->sock = tcp_connectsock(cithost, citport); if (ipc->sock == -1) { ifree(ipc); return 0; -- 2.39.2