From 02642ce851613d458b9bf980fc1d9fad4fbb3842 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Thu, 22 May 2014 13:02:45 +0200 Subject: [PATCH] tcp: use getaddrinfo() for hostname resolution gethostbyname_r() is GNU extension not supported on some platforms. This commit replaces it with POSIX standard getaddrinfo() call. --- src/tcp.c | 84 ++++++++++--------------------------------------------- 1 file changed, 15 insertions(+), 69 deletions(-) diff --git a/src/tcp.c b/src/tcp.c index af60bc10..0608abf2 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -51,63 +51,25 @@ int tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout) { - const char *errtxt; - struct hostent hostbuf, *hp; - char *tmphstbuf; - size_t hstbuflen; - int herr, fd, r, res, err; - struct sockaddr_in6 in6; - struct sockaddr_in in; + int fd, r, res, err; + struct addrinfo *ai; + char portstr[6]; socklen_t errlen = sizeof(int); - hstbuflen = 1024; - tmphstbuf = malloc(hstbuflen); - - while((res = gethostbyname_r(hostname, &hostbuf, tmphstbuf, hstbuflen, - &hp, &herr)) == ERANGE) { - hstbuflen *= 2; - tmphstbuf = realloc(tmphstbuf, hstbuflen); - } + snprintf(portstr, 6, "%u", port); + res = getaddrinfo(hostname, portstr, NULL, &ai); - if(res != 0) { - snprintf(errbuf, errbufsize, "Resolver internal error"); - free(tmphstbuf); - return -1; - } else if(herr != 0) { - switch(herr) { - case HOST_NOT_FOUND: - errtxt = "The specified host is unknown"; - break; - case NO_ADDRESS: - errtxt = "The requested name is valid but does not have an IP address"; - break; - - case NO_RECOVERY: - errtxt = "A non-recoverable name server error occurred"; - break; - - case TRY_AGAIN: - errtxt = "A temporary error occurred on an authoritative name server"; - break; - - default: - errtxt = "Unknown error"; - break; - } - - snprintf(errbuf, errbufsize, "%s", errtxt); - free(tmphstbuf); - return -1; - } else if(hp == NULL) { - snprintf(errbuf, errbufsize, "Resolver internal error"); - free(tmphstbuf); + if (res != 0) { + snprintf(errbuf, errbufsize, "%s", gai_strerror(res)); + freeaddrinfo(ai); return -1; } - fd = tvh_socket(hp->h_addrtype, SOCK_STREAM, 0); + + fd = tvh_socket(ai->ai_family, SOCK_STREAM, 0); if(fd == -1) { snprintf(errbuf, errbufsize, "Unable to create socket: %s", strerror(errno)); - free(tmphstbuf); + freeaddrinfo(ai); return -1; } @@ -116,30 +78,14 @@ tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, */ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - switch(hp->h_addrtype) { - case AF_INET: - memset(&in, 0, sizeof(in)); - in.sin_family = AF_INET; - in.sin_port = htons(port); - memcpy(&in.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); - r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); - break; - - case AF_INET6: - memset(&in6, 0, sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = htons(port); - memcpy(&in6.sin6_addr, hp->h_addr_list[0], sizeof(struct in6_addr)); - r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in6)); - break; - - default: + if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6)) { snprintf(errbuf, errbufsize, "Invalid protocol family"); - free(tmphstbuf); + freeaddrinfo(ai); return -1; } - free(tmphstbuf); + r = connect(fd, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); if(r == -1) { if(errno == EINPROGRESS && timeout < 0) {