--- otp_src_R10B-2.orig/erts/etc/common/inet_gethost.c 2003-07-07 14:07:55.000000000 +0200 +++ otp_src_R10B-2/erts/etc/common/inet_gethost.c 2005-01-03 15:08:11.000000000 +0100 @@ -39,6 +39,8 @@ #include #include +#define HAVE_GETADDRINFO 1 + #ifdef HAVE_SYS_TIME_H #include #else @@ -238,13 +240,22 @@ static int get_int32(AddrByte *buff); static void put_int32(AddrByte *buff, int value); static int create_worker(Worker *pworker, int save_que); -static int map_netdb_error(int netdb_code); +#ifdef HAVE_GETADDRINFO +static int map_netdb_error_ai(int netdb_code); +#else +static int map_netdb_error_he(int netdb_code); +#endif static char *errcode_to_string(int errcode); static size_t build_error_reply(SerialType serial, int errnum, AddrByte **preply, size_t *preply_size); +#ifdef HAVE_GETADDRINFO +static size_t build_reply_ai(SerialType serial, int, struct addrinfo *, + AddrByte **preply, size_t *preply_size); +#else static size_t build_reply(SerialType serial, struct hostent *he, AddrByte **preply, size_t *preply_size); +#endif static int read_request(AddrByte **buff, size_t *buff_size); static OpType get_op(AddrByte *buff); static AddrByte *get_op_addr(AddrByte *buff); @@ -1465,7 +1476,9 @@ static int worker_loop(void) #endif { +#ifndef HAVE_GETADDRINFO struct hostent *he; +#endif AddrByte *req = NULL; size_t req_size = 0; int this_size; @@ -1523,13 +1536,61 @@ free_he = 0; switch (op) { case OP_GETHOSTBYNAME: + { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *res = NULL; + int addrlen; + + DEBUGF(10, ("getaddrinfo: %s.", data)); + + error_num = 0; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + hints.ai_socktype = SOCK_STREAM; + hints.ai_addrlen = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + switch (proto) { + case PROTO_IPV4: + hints.ai_family = PF_INET; + addrlen = 4; + break; +#ifdef PF_INET6 + case PROTO_IPV6: + hints.ai_family = PF_INET6; + addrlen = 16; + break; +#endif + default: + addrlen = 0; + error_num = ERRCODE_NOTSUP; + break; + } + if (error_num == 0) { + error_num = getaddrinfo(data, NULL, &hints, &res); + if (error_num) + error_num = map_netdb_error_ai(error_num); + } + DEBUGF(10, ("getaddrinfo returns: %d.", error_num)); + if (error_num) { + data_size = build_error_reply(serial, error_num, + &reply, &reply_size); + } else { + data_size = build_reply_ai(serial, addrlen, res, + &reply, &reply_size); + } + if (res) + freeaddrinfo(res); + break; +#else /* HAVE_GETADDRINFO */ if (proto != PROTO_IPV4) { #if defined(HAVE_GETIPNODEBYNAME) && !defined(WIN32) /* IP V6 support */ if (proto == PROTO_IPV6) { he = getipnodebyname(data, AF_INET6, AI_DEFAULT, &error_num); free_he = 1; - error_num = map_netdb_error(error_num); + error_num = map_netdb_error_he(error_num); } else { /* Not supported... */ he = NULL; @@ -1545,7 +1606,7 @@ he = gethostbyname(data); DEBUGF(4,("gethostbyname(%s) gave %s",data, (he) ? "success" : "error")); - error_num = (he) ? 0 : map_netdb_error(h_errno); + error_num = (he) ? 0 : map_netdb_error_he(h_errno); } if (!he) { data_size = build_error_reply(serial, error_num, @@ -1558,8 +1619,85 @@ } #endif } +#endif /* HAVE_GETADDRINFO */ break; + } case OP_GETHOSTBYADDR: + { +#ifdef HAVE_GETADDRINFO + struct sockaddr *sa = NULL; + char name[NI_MAXHOST]; + socklen_t salen; + int addrlen; + + error_num = 0; + switch (proto) { + case PROTO_IPV4: { + struct sockaddr_in *sin; + addrlen = 4; + salen = sizeof(*sin); + sin = malloc(salen); + if (sin == NULL) { + error_num = ERRCODE_NETDB_INTERNAL; + break; + } +#ifndef NO_SA_LEN + sin->sin_len = salen; +#endif + sin->sin_family = AF_INET; + sin->sin_port = 0; + memcpy(&sin->sin_addr, data, addrlen); + sa = (struct sockaddr *)sin; + break; + } +#ifdef PF_INET6 + case PROTO_IPV6: { + struct sockaddr_in6 *sin; + addrlen = 16; + salen = sizeof(*sin); + sin = malloc(salen); + if (sin == NULL) { + error_num = ERRCODE_NETDB_INTERNAL; + break; + } +#ifndef NO_SA_LEN + sin->sin6_len = salen; +#endif + sin->sin6_family = AF_INET6; + sin->sin6_port = 0; + memcpy(&sin->sin6_addr, data, addrlen); + sa = (struct sockaddr *)sin; + break; + } +#endif + default: + error_num = ERRCODE_NOTSUP; + break; + } + if (error_num == 0) { + error_num = getnameinfo(sa, salen, name, sizeof(name), + NULL, 0, NI_NAMEREQD); + DEBUGF(50,("getnameinfo %d.", error_num)); + if (error_num) + error_num = map_netdb_error_ai(error_num); + } + if (error_num) + data_size = build_error_reply(serial, error_num, + &reply, &reply_size); + else { + struct addrinfo res; + memset(&res, 0, sizeof(res)); + DEBUGF(50,("getnameinfo %s.", name)); + res.ai_canonname = name; + res.ai_addr = sa; + res.ai_next = NULL; + data_size = build_reply_ai(serial, addrlen, &res, + &reply, &reply_size); + } + if (sa) + free(sa); + break; +#else /* HAVE_GETADDRINFO */ if (proto != PROTO_IPV4) { #if defined(HAVE_GETIPNODEBYADDR) && !defined(WIN32) /* IP V6 support */ if (proto == PROTO_IPV6) { @@ -1567,7 +1705,7 @@ memcpy(ia.s6_addr, data, 16); he = getipnodebyaddr(&ia, 16, AF_INET6, &error_num); free_he = 1; - error_num = map_netdb_error(error_num); + error_num = map_netdb_error_he(error_num); } else { /* Not supported... */ he = NULL; @@ -1582,7 +1720,7 @@ struct in_addr ia; memcpy(&ia.s_addr, data, 4); /* Alignment required... */ he = gethostbyaddr((const char *) &ia, 4, AF_INET); - error_num = map_netdb_error(h_errno); + error_num = map_netdb_error_he(h_errno); } if (!he) { data_size = build_error_reply(serial, error_num, @@ -1596,6 +1734,8 @@ #endif } break; +#endif /* HAVE_GETADDRINFO */ + } default: data_size = build_error_reply(serial, ERRCODE_NOTSUP, &reply, &reply_size); @@ -1628,7 +1768,39 @@ #endif } -static int map_netdb_error(int netdb_code) +#ifdef HAVE_GETADDRINFO +static int map_netdb_error_ai(int netdb_code) +{ + switch(netdb_code) { +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: + return ERRCODE_NETDB_INTERNAL; +#endif + case EAI_AGAIN: + return ERRCODE_TRY_AGAIN; + case EAI_BADFLAGS: + return ERRCODE_NETDB_INTERNAL; + case EAI_FAIL: + return ERRCODE_HOST_NOT_FOUND; + case EAI_FAMILY: + return ERRCODE_NETDB_INTERNAL; + case EAI_MEMORY: + return ERRCODE_NETDB_INTERNAL; +#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME + case EAI_NODATA: + return ERRCODE_HOST_NOT_FOUND; +#endif + case EAI_NONAME: + return ERRCODE_HOST_NOT_FOUND; + case EAI_SERVICE: + return ERRCODE_NETDB_INTERNAL; + case EAI_SOCKTYPE: + return ERRCODE_NETDB_INTERNAL; + default: + return ERRCODE_NETDB_INTERNAL; + } +#else /* HAVE_GETADDRINFO */ +static int map_netdb_error_he(int netdb_code) { switch (netdb_code) { #ifdef HOST_NOT_FOUND @@ -1657,6 +1829,7 @@ default: return ERRCODE_NETDB_INTERNAL; } +#endif /* HAVE_GETADDRINFO */ } static char *errcode_to_string(int errcode) @@ -1712,7 +1885,79 @@ return need; } +#ifdef HAVE_GETADDRINFO + +static size_t build_reply_ai(SerialType serial, int addrlen, + struct addrinfo *res0, + AddrByte **preply, size_t *preply_size) +{ + struct addrinfo *res; + int num_strings; + int num_addresses; + AddrByte *ptr; + int need; + + num_addresses = 0; + num_strings = 0; + need = PACKET_BYTES + + 4 /* Serial */ + 1 /* addrlen */ + + 4 /* Naddr */ + 4 /* Nnames */; + + for (res = res0; res != NULL; res = res->ai_next) { + if (res->ai_addr) { + num_addresses++; + need += addrlen; + } + if (res->ai_canonname) { + num_strings++; + need += strlen(res->ai_canonname) + 1; + } + } + + if (*preply_size < need) { + if (*preply_size == 0) { + *preply = ALLOC((*preply_size = need)); + } else { + *preply = REALLOC(*preply, + (*preply_size = need)); + } + } + ptr = *preply; + PUT_PACKET_BYTES(ptr,need - PACKET_BYTES); + ptr += PACKET_BYTES; + put_int32(ptr,serial); + ptr +=4; + *ptr++ = (AddrByte) addrlen; /* 4 or 16 */ + put_int32(ptr, num_addresses); + ptr += 4; + for (res = res0; res != NULL && num_addresses; res = res->ai_next) { + if (res->ai_addr == NULL) + continue; + if (addrlen == 4) + memcpy(ptr, &((struct sockaddr_in *)res->ai_addr)->sin_addr, addrlen); +#ifdef PF_INET6 + else if (addrlen == 16) + memcpy(ptr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, addrlen); +#endif + else + memcpy(ptr, res->ai_addr->sa_data, addrlen); + ptr += addrlen; + num_addresses--; + } + put_int32(ptr, num_strings); + ptr += 4; + for (res = res0; res != NULL && num_strings; res = res->ai_next) { + if (res->ai_canonname == NULL) + continue; + strcpy(ptr, res->ai_canonname); + ptr += strlen(res->ai_canonname) + 1; + num_strings--; + } + return need; +} + +#else /* !HAVE_GETADDRINFO */ static size_t build_reply(SerialType serial, struct hostent *he, AddrByte **preply, size_t *preply_size) @@ -1773,6 +2018,8 @@ return need; } +#endif /* HAVE_GETADDRINFO */ + /* * Encode/decode/read/write */