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.
This commit is contained in:
Damjan Marion 2014-05-22 13:02:45 +02:00
parent 087089c204
commit 02642ce851

View file

@ -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) {