X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=libc%2Finet%2Fgetaddrinfo.c;h=168adb1156b45ca1f1817cd23aff2c4dcb88210f;hb=HEAD;hp=70bdfbbd1382c85eb7e39b606300b44bf664c013;hpb=ebb7fa188fe88fafecdbe4ad9b87d2afa703b503;p=uclinux-h8%2FuClibc.git diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c index 70bdfbbd1..168adb115 100644 --- a/libc/inet/getaddrinfo.c +++ b/libc/inet/getaddrinfo.c @@ -1,3 +1,12 @@ +/* + * Copyright 1996 by Craig Metz + * Copyright (C) 2000-2006 Erik Andersen + * Portions from the GNU C library, + * Copyright (C) 2003, 2006 Free Software Foundation, Inc. + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */ /* The Inner Net License, Version 2.00 @@ -42,14 +51,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. If these license terms cause you a real problem, contact the author. */ -/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */ - -#define _GNU_SOURCE -#define __FORCE_GLIBC -#include #include #include #include +#ifdef __UCLIBC_HAS_TLS__ +#include +#endif #include #include #include @@ -62,15 +69,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include - -/* The following declarations and definitions have been removed from - * the public header since we don't want people to use them. */ -#define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */ -#define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */ -#define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose - returned address type. */ -#define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) - +#include #define GAIH_OKIFUNSPEC 0x0100 #define GAIH_EAI ~(GAIH_OKIFUNSPEC) @@ -79,794 +78,811 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define UNIX_PATH_MAX 108 #endif -struct gaih_service -{ - const char *name; - int num; +/* Useful for having small structure members/global variables */ +typedef int8_t socktype_t; +typedef int8_t family_t; +typedef int8_t protocol_t; +struct BUG_too_small { + char BUG_socktype_t_too_small[(0 + | SOCK_STREAM + | SOCK_DGRAM + | SOCK_RAW + ) <= 127 ? 1 : -1]; + char BUG_family_t_too_small[(0 + | AF_UNSPEC + | AF_INET + | AF_INET6 + ) <= 127 ? 1 : -1]; + char BUG_protocol_t_too_small[(0 + | IPPROTO_TCP + | IPPROTO_UDP + ) <= 127 ? 1 : -1]; }; -struct gaih_servtuple -{ - struct gaih_servtuple *next; - int socktype; - int protocol; - int port; +struct gaih_service { + const char *name; + int num; }; -static const struct gaih_servtuple nullserv; - -struct gaih_addrtuple -{ - struct gaih_addrtuple *next; - int family; - char addr[16]; - uint32_t scopeid; +struct gaih_servtuple { + struct gaih_servtuple *next; + int socktype; + int protocol; + int port; }; -struct gaih_typeproto -{ - int socktype; - int protocol; - char name[4]; - int protoflag; +struct gaih_addrtuple { + struct gaih_addrtuple *next; + int family; + char addr[16]; + uint32_t scopeid; }; +struct gaih_typeproto { + socktype_t socktype; + protocol_t protocol; + int8_t protoflag; + char name[4]; +}; /* Values for `protoflag'. */ -#define GAI_PROTO_NOSERVICE 1 -#define GAI_PROTO_PROTOANY 2 +#define GAI_PROTO_NOSERVICE 1 +#define GAI_PROTO_PROTOANY 2 + +static const struct gaih_typeproto gaih_inet_typeproto[] = { + { 0 , 0 , 0, "" }, + { SOCK_STREAM, IPPROTO_TCP, 0, "tcp" }, + { SOCK_DGRAM , IPPROTO_UDP, 0, "udp" }, + { SOCK_RAW , 0 , GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, "raw" }, + { 0 , 0 , 0, "" }, +}; -static const struct gaih_typeproto gaih_inet_typeproto[] = -{ - { 0, 0, "", 0 }, - { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 }, - { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 }, - { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE }, - { 0, 0, "", 0 } +struct gaih { + int family; + int (*gaih)(const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai); }; -struct gaih +#define SEEN_IPV4 1 +#define SEEN_IPV6 2 + +static unsigned __check_pf(void) { - int family; - int (*gaih)(const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai); -}; + unsigned seen = 0; + +#if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__ + + struct ifaddrs *ifa; + struct ifaddrs *runp; + + /* Get the interface list via getifaddrs. */ + if (getifaddrs(&ifa) != 0) { + /* We cannot determine what interfaces are available. + * Be optimistic. */ +#if defined __UCLIBC_HAS_IPV4__ + seen |= SEEN_IPV4; +#endif +#if defined __UCLIBC_HAS_IPV6__ + seen |= SEEN_IPV6; +#endif + return seen; + } + + for (runp = ifa; runp != NULL; runp = runp->ifa_next) { + if (runp->ifa_addr == NULL) + continue; +#if defined __UCLIBC_HAS_IPV4__ + if (runp->ifa_addr->sa_family == PF_INET) + seen |= SEEN_IPV4; +#endif +#if defined __UCLIBC_HAS_IPV6__ + if (runp->ifa_addr->sa_family == PF_INET6) + seen |= SEEN_IPV6; +#endif + } + freeifaddrs(ifa); -#if PF_UNSPEC == 0 -static const struct addrinfo default_hints; #else -static const struct addrinfo default_hints = -{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; + + /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */ +#if defined __UCLIBC_HAS_IPV4__ + seen |= SEEN_IPV4; +#endif +#if defined __UCLIBC_HAS_IPV6__ + seen |= SEEN_IPV6; #endif +#endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */ + + return seen; +} -static int addrconfig (sa_family_t af) +static int addrconfig(sa_family_t af) { - int s; - int ret; - int saved_errno = errno; - s = socket(af, SOCK_DGRAM, 0); - if (s < 0) - ret = (errno == EMFILE) ? 1 : 0; - else - { - close(s); - ret = 1; - } - __set_errno (saved_errno); - return ret; + int s; + int ret; + int saved_errno = errno; + unsigned seen; + + seen = __check_pf(); +#if defined __UCLIBC_HAS_IPV4__ + if (af == AF_INET) + ret = seen & SEEN_IPV4; + else +#endif +#if defined __UCLIBC_HAS_IPV6__ + if (af == AF_INET6) + ret = seen & SEEN_IPV6; + else +#endif + { + s = socket(af, SOCK_DGRAM, 0); + ret = 1; /* Assume PF_UNIX. */ + if (s < 0) { + if (errno != EMFILE) + ret = 0; + } else + close(s); + } + __set_errno(saved_errno); + return ret; } #if 0 /* Using Unix sockets this way is a security risk. */ static int -gaih_local (const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai) +gaih_local(const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai) { - struct utsname utsname; - - if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST)) - return GAIH_OKIFUNSPEC | -EAI_NONAME; - - if ((name != NULL) || (req->ai_flags & AI_CANONNAME)) - if (uname (&utsname) < 0) - return -EAI_SYSTEM; - - if (name != NULL) - { - if (strcmp(name, "localhost") && - strcmp(name, "local") && - strcmp(name, "unix") && - strcmp(name, utsname.nodename)) - return GAIH_OKIFUNSPEC | -EAI_NONAME; - } - - if (req->ai_protocol || req->ai_socktype) - { - const struct gaih_typeproto *tp = gaih_inet_typeproto + 1; - - while (tp->name[0] - && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0 - || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype) - || (req->ai_protocol != 0 - && !(tp->protoflag & GAI_PROTO_PROTOANY) - && req->ai_protocol != tp->protocol))) - ++tp; - - if (! tp->name[0]) - { - if (req->ai_socktype) - return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); - else - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + struct utsname utsname; + struct addrinfo *ai = *pai; + + if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST)) + return (GAIH_OKIFUNSPEC | -EAI_NONAME); + + if ((name != NULL) || (req->ai_flags & AI_CANONNAME)) + if (uname(&utsname) < 0) + return -EAI_SYSTEM; + + if (name != NULL) { + if (strcmp(name, "localhost") && + strcmp(name, "local") && + strcmp(name, "unix") && + strcmp(name, utsname.nodename)) + return (GAIH_OKIFUNSPEC | -EAI_NONAME); } - } - - *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un) - + ((req->ai_flags & AI_CANONNAME) - ? (strlen(utsname.nodename) + 1): 0)); - if (*pai == NULL) - return -EAI_MEMORY; - - (*pai)->ai_next = NULL; - (*pai)->ai_flags = req->ai_flags; - (*pai)->ai_family = AF_LOCAL; - (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; - (*pai)->ai_protocol = req->ai_protocol; - (*pai)->ai_addrlen = sizeof (struct sockaddr_un); - (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo); - -#if SALEN - ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len = - sizeof (struct sockaddr_un); -#endif /* SALEN */ - ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL; - memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX); + if (req->ai_protocol || req->ai_socktype) { + const struct gaih_typeproto *tp = gaih_inet_typeproto + 1; - if (service) - { - struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr; + while (tp->name[0] + && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0 + || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype) + || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol)) + ) { + ++tp; + } + if (! tp->name[0]) { + if (req->ai_socktype) + return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + } + } - if (strchr (service->name, '/') != NULL) - { - if (strlen (service->name) >= sizeof (sunp->sun_path)) - return GAIH_OKIFUNSPEC | -EAI_SERVICE; + *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + + ((req->ai_flags & AI_CANONNAME) + ? (strlen(utsname.nodename) + 1) : 0)); + if (ai == NULL) + return -EAI_MEMORY; + + ai->ai_next = NULL; + ai->ai_flags = req->ai_flags; + ai->ai_family = AF_LOCAL; + ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM; + ai->ai_protocol = req->ai_protocol; + ai->ai_addrlen = sizeof(struct sockaddr_un); + ai->ai_addr = (void *)ai + sizeof(struct addrinfo); +#if 0 /* SALEN */ + ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un); +#endif /* SALEN */ - strcpy (sunp->sun_path, service->name); - } - else - { - if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >= - sizeof (sunp->sun_path)) - return GAIH_OKIFUNSPEC | -EAI_SERVICE; + ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL; + memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX); + + if (service) { + struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr; - __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name); + if (strchr(service->name, '/') != NULL) { + if (strlen(service->name) >= sizeof(sunp->sun_path)) + return GAIH_OKIFUNSPEC | -EAI_SERVICE; + strcpy(sunp->sun_path, service->name); + } else { + if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path)) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name); + } + } else { + /* This is a dangerous use of the interface since there is a time + window between the test for the file and the actual creation + (done by the caller) in which a file with the same name could + be created. */ + char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path; + + if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0 + || __gen_tempname(buf, __GT_NOCREATE, 0, 0) != 0 + ) { + return -EAI_SYSTEM; + } } - } - else - { - /* This is a dangerous use of the interface since there is a time - window between the test for the file and the actual creation - (done by the caller) in which a file with the same name could - be created. */ - char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path; - - if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0), - 0) != 0 - || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0) - return -EAI_SYSTEM; - } - - if (req->ai_flags & AI_CANONNAME) - (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo) - + sizeof (struct sockaddr_un), - utsname.nodename); - else - (*pai)->ai_canonname = NULL; - return 0; + + ai->ai_canonname = NULL; + if (req->ai_flags & AI_CANONNAME) + ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un), + utsname.nodename); + return 0; } #endif /* 0 */ static int -gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, +gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp, const struct addrinfo *req, struct gaih_servtuple *st) { - struct servent *s; - size_t tmpbuflen = 1024; - struct servent ts; - char *tmpbuf; - int r; - - do - { - tmpbuf = alloca (tmpbuflen); - - r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen, - &s); - if (r != 0 || s == NULL) - { - if (r == ERANGE) + struct servent *s; + size_t tmpbuflen = 1024; + struct servent ts; + char *tmpbuf; + int r; + + while (1) { + tmpbuf = alloca(tmpbuflen); + r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s); + if (r == 0 && s != NULL) + break; + if (r != ERANGE) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); tmpbuflen *= 2; - else - return GAIH_OKIFUNSPEC | -EAI_SERVICE; } - } - while (r); - - st->next = NULL; - st->socktype = tp->socktype; - st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) - ? req->ai_protocol : tp->protocol); - st->port = s->s_port; - - return 0; + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol); + st->port = s->s_port; + return 0; } -#define gethosts(_family, _type) \ -{ \ - int i, herrno; \ - size_t tmpbuflen; \ - struct hostent th; \ - char *tmpbuf; \ - tmpbuflen = 512; \ - no_data = 0; \ - do { \ - tmpbuflen *= 2; \ - tmpbuf = alloca (tmpbuflen); \ - rc = gethostbyname2_r (name, _family, &th, tmpbuf, \ - tmpbuflen, &h, &herrno); \ - } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ - if (rc != 0) \ - { \ - if (herrno == NETDB_INTERNAL) \ - { \ - __set_h_errno (herrno); \ - return -EAI_SYSTEM; \ - } \ - if (herrno == TRY_AGAIN) \ - no_data = EAI_AGAIN; \ - else \ - no_data = herrno == NO_DATA; \ - } \ - else if (h != NULL) \ - { \ - for (i = 0; h->h_addr_list[i]; i++) \ - { \ - if (*pat == NULL) { \ - *pat = alloca (sizeof(struct gaih_addrtuple)); \ - (*pat)->scopeid = 0; \ - } \ - (*pat)->next = NULL; \ - (*pat)->family = _family; \ - memcpy ((*pat)->addr, h->h_addr_list[i], \ - sizeof(_type)); \ - pat = &((*pat)->next); \ - } \ - } \ +/* NB: also uses h,pat,rc,no_data variables */ +#define gethosts(_family, _type) \ +{ \ + int i, herrno; \ + size_t tmpbuflen; \ + struct hostent th; \ + char *tmpbuf; \ + \ + tmpbuflen = 512; \ + no_data = 0; \ + do { \ + tmpbuflen *= 2; \ + tmpbuf = alloca(tmpbuflen); \ + rc = gethostbyname2_r(name, _family, &th, tmpbuf, \ + tmpbuflen, &h, &herrno); \ + } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ + if (rc != 0) { \ + if (herrno == NETDB_INTERNAL) { \ + __set_h_errno(herrno); \ + return -EAI_SYSTEM; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ + no_data = (herrno == NO_DATA); \ + } else if (h != NULL) { \ + for (i = 0; h->h_addr_list[i]; i++) { \ + if (*pat == NULL) { \ + *pat = alloca(sizeof(struct gaih_addrtuple)); \ + (*pat)->scopeid = 0; \ + } \ + (*pat)->next = NULL; \ + (*pat)->family = _family; \ + memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \ + pat = &((*pat)->next); \ + } \ + } \ } static int -gaih_inet (const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai) +gaih_inet(const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai) { - const struct gaih_typeproto *tp = gaih_inet_typeproto; - struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; - struct gaih_addrtuple *at = NULL; - int rc; - int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) && - (req->ai_flags & AI_V4MAPPED); - - if (req->ai_protocol || req->ai_socktype) - { - ++tp; - - while (tp->name[0] - && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype) - || (req->ai_protocol != 0 - && !(tp->protoflag & GAI_PROTO_PROTOANY) - && req->ai_protocol != tp->protocol))) - ++tp; - - if (! tp->name[0]) - { - if (req->ai_socktype) - return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); - else - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + struct gaih_servtuple nullserv; + + const struct gaih_typeproto *tp; + struct gaih_servtuple *st; + struct gaih_addrtuple *at; + int rc; + int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) + && (req->ai_flags & AI_V4MAPPED); + unsigned seen = 0; + if (req->ai_flags & AI_ADDRCONFIG) { + /* "seen" is only used when AI_ADDRCONFIG is specified. + Avoid unnecessary call to __check_pf() otherwise + since it can be costly especially when RSBAC-Net is enabled. */ + seen = __check_pf(); } - } - if (service != NULL) - { - if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); - - if (service->num < 0) - { - if (tp->name[0]) - { - st = (struct gaih_servtuple *) - alloca (sizeof (struct gaih_servtuple)); - - if ((rc = gaih_inet_serv (service->name, tp, req, st))) - return rc; - } - else - { - struct gaih_servtuple **pst = &st; - for (tp++; tp->name[0]; tp++) - { - struct gaih_servtuple *newp; - - if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) - continue; - - if (req->ai_socktype != 0 - && req->ai_socktype != tp->socktype) - continue; - if (req->ai_protocol != 0 - && !(tp->protoflag & GAI_PROTO_PROTOANY) - && req->ai_protocol != tp->protocol) - continue; - - newp = (struct gaih_servtuple *) - alloca (sizeof (struct gaih_servtuple)); - - if ((rc = gaih_inet_serv (service->name, tp, req, newp))) - { - if (rc & GAIH_OKIFUNSPEC) - continue; - return rc; - } - - *pst = newp; - pst = &(newp->next); + memset(&nullserv, 0, sizeof(nullserv)); + + tp = gaih_inet_typeproto; + if (req->ai_protocol || req->ai_socktype) { + ++tp; + while (tp->name[0]) { + if ((req->ai_socktype == 0 || req->ai_socktype == tp->socktype) + && (req->ai_protocol == 0 || req->ai_protocol == tp->protocol || (tp->protoflag & GAI_PROTO_PROTOANY)) + ) { + goto found; + } + ++tp; } - if (st == (struct gaih_servtuple *) &nullserv) - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); - } - } - else - { - st = alloca (sizeof (struct gaih_servtuple)); - st->next = NULL; - st->socktype = tp->socktype; - st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) - ? req->ai_protocol : tp->protocol); - st->port = htons (service->num); + if (req->ai_socktype) + return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + found: ; } - } - else if (req->ai_socktype || req->ai_protocol) - { - st = alloca (sizeof (struct gaih_servtuple)); - st->next = NULL; - st->socktype = tp->socktype; - st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) - ? req->ai_protocol : tp->protocol); - st->port = 0; - } - else - { - /* - * Neither socket type nor protocol is set. Return all socket types - * we know about. - */ - struct gaih_servtuple **lastp = &st; - for (++tp; tp->name[0]; ++tp) - { - struct gaih_servtuple *newp; - - newp = alloca (sizeof (struct gaih_servtuple)); - newp->next = NULL; - newp->socktype = tp->socktype; - newp->protocol = tp->protocol; - newp->port = 0; - *lastp = newp; - lastp = &newp->next; + st = &nullserv; + if (service != NULL) { + if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + + if (service->num < 0) { + if (tp->name[0]) { + st = alloca(sizeof(struct gaih_servtuple)); + rc = gaih_inet_serv(service->name, tp, req, st); + if (rc) + return rc; + } else { + struct gaih_servtuple **pst = &st; + for (tp++; tp->name[0]; tp++) { + struct gaih_servtuple *newp; + + if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) + continue; + + if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype) + continue; + if (req->ai_protocol != 0 + && !(tp->protoflag & GAI_PROTO_PROTOANY) + && req->ai_protocol != tp->protocol) + continue; + + newp = alloca(sizeof(struct gaih_servtuple)); + rc = gaih_inet_serv(service->name, tp, req, newp); + if (rc) { + if (rc & GAIH_OKIFUNSPEC) + continue; + return rc; + } + + *pst = newp; + pst = &(newp->next); + } + if (st == &nullserv) + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + } + } else { + st = alloca(sizeof(struct gaih_servtuple)); + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) + ? req->ai_protocol : tp->protocol); + st->port = htons(service->num); + } + } else if (req->ai_socktype || req->ai_protocol) { + st = alloca(sizeof(struct gaih_servtuple)); + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) + ? req->ai_protocol : tp->protocol); + st->port = 0; + } else { + /* + * Neither socket type nor protocol is set. Return all socket types + * we know about. + */ + struct gaih_servtuple **lastp = &st; + for (++tp; tp->name[0]; ++tp) { + struct gaih_servtuple *newp; + + newp = alloca(sizeof(struct gaih_servtuple)); + newp->next = NULL; + newp->socktype = tp->socktype; + newp->protocol = tp->protocol; + newp->port = 0; + + *lastp = newp; + lastp = &newp->next; + } } - } - - if (name != NULL) - { - at = alloca (sizeof (struct gaih_addrtuple)); - at->family = AF_UNSPEC; - at->scopeid = 0; - at->next = NULL; - - if (inet_pton (AF_INET, name, at->addr) > 0) - { - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped) - at->family = AF_INET; - else - return -EAI_FAMILY; - } + at = NULL; + if (name != NULL) { + at = alloca(sizeof(struct gaih_addrtuple)); + at->family = AF_UNSPEC; + at->scopeid = 0; + at->next = NULL; + + if (inet_pton(AF_INET, name, at->addr) > 0) { + if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET && !v4mapped) + return -EAI_FAMILY; + at->family = AF_INET; + } -#if __UCLIBC_HAS_IPV6__ - if (at->family == AF_UNSPEC) - { - char *namebuf = strdupa (name); - char *scope_delim; - - scope_delim = strchr (namebuf, SCOPE_DELIMITER); - if (scope_delim != NULL) - *scope_delim = '\0'; - - if (inet_pton (AF_INET6, namebuf, at->addr) > 0) - { - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) - at->family = AF_INET6; - else - return -EAI_FAMILY; - - if (scope_delim != NULL) - { - int try_numericscope = 0; - if (IN6_IS_ADDR_LINKLOCAL (at->addr) - || IN6_IS_ADDR_MC_LINKLOCAL (at->addr)) - { - at->scopeid = if_nametoindex (scope_delim + 1); - if (at->scopeid == 0) - try_numericscope = 1; - } - else - try_numericscope = 1; - - if (try_numericscope != 0) - { - char *end; - assert (sizeof (uint32_t) <= sizeof (unsigned long)); - at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end, - 10); - if (*end != '\0') - return GAIH_OKIFUNSPEC | -EAI_NONAME; - } +#if defined __UCLIBC_HAS_IPV6__ + if (at->family == AF_UNSPEC) { + char *namebuf = strdupa(name); + char *scope_delim; + + scope_delim = strchr(namebuf, SCOPE_DELIMITER); + if (scope_delim != NULL) + *scope_delim = '\0'; + + if (inet_pton(AF_INET6, namebuf, at->addr) > 0) { + if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET6) + return -EAI_FAMILY; + at->family = AF_INET6; + if (scope_delim != NULL) { + int try_numericscope = 0; + uint32_t *a32 = (uint32_t*)at->addr; + if (IN6_IS_ADDR_LINKLOCAL(a32) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) { + at->scopeid = if_nametoindex(scope_delim + 1); + if (at->scopeid == 0) + try_numericscope = 1; + } else + try_numericscope = 1; + + if (try_numericscope != 0) { + char *end; + assert(sizeof(uint32_t) <= sizeof(unsigned long)); + at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10); + if (*end != '\0') + return (GAIH_OKIFUNSPEC | -EAI_NONAME); + } + } + } } - } - } #endif - if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) - { - struct hostent *h; - struct gaih_addrtuple **pat = &at; - int no_data = 0; - int no_inet6_data; - - /* - * If we are looking for both IPv4 and IPv6 address we don't want - * the lookup functions to automatically promote IPv4 addresses to - * IPv6 addresses. - */ - -#if __UCLIBC_HAS_IPV6__ - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) - gethosts (AF_INET6, struct in6_addr); + if (at->family == AF_UNSPEC && !(req->ai_flags & AI_NUMERICHOST)) { + struct hostent *h; + struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data; + + /* + * If we are looking for both IPv4 and IPv6 address we don't want + * the lookup functions to automatically promote IPv4 addresses to + * IPv6 addresses. + */ +#if defined __UCLIBC_HAS_IPV6__ + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6)) + gethosts(AF_INET6, struct in6_addr); #endif - no_inet6_data = no_data; - - if (req->ai_family == AF_INET || - (!v4mapped && req->ai_family == AF_UNSPEC) || - (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))) - gethosts (AF_INET, struct in_addr); - - if (no_data != 0 && no_inet6_data != 0) - { - /* If both requests timed out report this. */ - if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) - return -EAI_AGAIN; - - /* - * We made requests but they turned out no data. - * The name is known, though. - */ - return (GAIH_OKIFUNSPEC | -EAI_AGAIN); - } - } - - if (at->family == AF_UNSPEC) - return (GAIH_OKIFUNSPEC | -EAI_NONAME); - } - else - { - struct gaih_addrtuple *atr; - atr = at = alloca (sizeof (struct gaih_addrtuple)); - memset (at, '\0', sizeof (struct gaih_addrtuple)); + no_inet6_data = no_data; + + if (req->ai_family == AF_INET + || (!v4mapped && req->ai_family == AF_UNSPEC) + || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))) + ) { + if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4)) + gethosts(AF_INET, struct in_addr); + } + + if (no_data != 0 && no_inet6_data != 0) { + /* If both requests timed out report this. */ + if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) + return -EAI_AGAIN; + /* + * We made requests but they turned out no data. + * The name is known, though. + */ + return (GAIH_OKIFUNSPEC | -EAI_AGAIN); + } + } - if (req->ai_family == 0) - { - at->next = alloca (sizeof (struct gaih_addrtuple)); - memset (at->next, '\0', sizeof (struct gaih_addrtuple)); - } + if (at->family == AF_UNSPEC) + return (GAIH_OKIFUNSPEC | -EAI_NONAME); + } else { + struct gaih_addrtuple *atr; -#if __UCLIBC_HAS_IPV6__ - if (req->ai_family == 0 || req->ai_family == AF_INET6) - { - at->family = AF_INET6; - if ((req->ai_flags & AI_PASSIVE) == 0) - memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr)); - atr = at->next; - } + atr = at = alloca(sizeof(struct gaih_addrtuple)); + memset(at, '\0', sizeof(struct gaih_addrtuple)); + if (req->ai_family == 0) { + at->next = alloca(sizeof(struct gaih_addrtuple)); + memset(at->next, '\0', sizeof(struct gaih_addrtuple)); + } +#if defined __UCLIBC_HAS_IPV6__ + if (req->ai_family == 0 || req->ai_family == AF_INET6) { + at->family = AF_INET6; + if ((req->ai_flags & AI_PASSIVE) == 0) + memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr)); + atr = at->next; + } #endif - - if (req->ai_family == 0 || req->ai_family == AF_INET) - { - atr->family = AF_INET; - if ((req->ai_flags & AI_PASSIVE) == 0) - *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK); + if (req->ai_family == 0 || req->ai_family == AF_INET) { + atr->family = AF_INET; + if ((req->ai_flags & AI_PASSIVE) == 0) { + uint32_t *a = (uint32_t*)atr->addr; + *a = htonl(INADDR_LOOPBACK); + } + } } - } - - if (pai == NULL) - return 0; - - { - const char *c = NULL; - struct gaih_servtuple *st2; - struct gaih_addrtuple *at2 = at; - size_t socklen, namelen; - sa_family_t family; - /* - * buffer is the size of an unformatted IPv6 address in - * printable format. - */ - char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + if (pai == NULL) + return 0; - while (at2 != NULL) { - if (req->ai_flags & AI_CANONNAME) - { - struct hostent *h = NULL; - - int herrno; - struct hostent th; - size_t tmpbuflen = 512; - char *tmpbuf; - - do - { - tmpbuflen *= 2; - tmpbuf = alloca (tmpbuflen); - - if (tmpbuf == NULL) - return -EAI_MEMORY; - - rc = gethostbyaddr_r (at2->addr, - ((at2->family == AF_INET6) - ? sizeof(struct in6_addr) - : sizeof(struct in_addr)), - at2->family, &th, tmpbuf, tmpbuflen, - &h, &herrno); + const char *c = NULL; + struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + size_t socklen, namelen; + sa_family_t family; - } - while (rc == errno && herrno == NETDB_INTERNAL); - - if (rc != 0 && herrno == NETDB_INTERNAL) - { - __set_h_errno (herrno); - return -EAI_SYSTEM; - } - - if (h == NULL) - c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer)); - else - c = h->h_name; - - if (c == NULL) - return GAIH_OKIFUNSPEC | -EAI_NONAME; - - namelen = strlen (c) + 1; - } - else - namelen = 0; - -#if __UCLIBC_HAS_IPV6__ - if (at2->family == AF_INET6 || v4mapped) - { - family = AF_INET6; - socklen = sizeof (struct sockaddr_in6); - } - else + /* + * buffer is the size of an unformatted IPv6 address in + * printable format. + */ + char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + + while (at2 != NULL) { + c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer)); + if (c) { + namelen = strlen(c) + 1; + } else if (req->ai_flags & AI_CANONNAME) { + struct hostent *h = NULL; + int herrno; + struct hostent th; + size_t tmpbuflen = 512; + char *tmpbuf; + + /* Hint says numeric, but address is not */ + if (req->ai_flags & AI_NUMERICHOST) + return -EAI_NONAME; + + do { + tmpbuflen *= 2; + tmpbuf = alloca(tmpbuflen); + rc = gethostbyaddr_r(at2->addr, +#ifdef __UCLIBC_HAS_IPV6__ + ((at2->family == AF_INET6) + ? sizeof(struct in6_addr) + : sizeof(struct in_addr)), +#else + sizeof(struct in_addr), #endif - { - family = AF_INET; - socklen = sizeof (struct sockaddr_in); - } - - for (st2 = st; st2 != NULL; st2 = st2->next) - { - *pai = malloc (sizeof (struct addrinfo) + socklen + namelen); - if (*pai == NULL) - return -EAI_MEMORY; - - (*pai)->ai_flags = req->ai_flags; - (*pai)->ai_family = family; - (*pai)->ai_socktype = st2->socktype; - (*pai)->ai_protocol = st2->protocol; - (*pai)->ai_addrlen = socklen; - (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo); -#if SALEN - (*pai)->ai_addr->sa_len = socklen; -#endif /* SALEN */ - (*pai)->ai_addr->sa_family = family; - -#if __UCLIBC_HAS_IPV6__ - if (family == AF_INET6) - { - struct sockaddr_in6 *sin6p = - (struct sockaddr_in6 *) (*pai)->ai_addr; - - sin6p->sin6_flowinfo = 0; - if (at2->family == AF_INET6) - { - memcpy (&sin6p->sin6_addr, - at2->addr, sizeof (struct in6_addr)); - } - else - { - sin6p->sin6_addr.s6_addr32[0] = 0; - sin6p->sin6_addr.s6_addr32[1] = 0; - sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff); - memcpy(&sin6p->sin6_addr.s6_addr32[3], - at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3])); - } - sin6p->sin6_port = st2->port; - sin6p->sin6_scope_id = at2->scopeid; - } - else + at2->family, + &th, tmpbuf, tmpbuflen, + &h, &herrno); + } while (rc == ERANGE && herrno == NETDB_INTERNAL); + + if (rc != 0 && herrno == NETDB_INTERNAL) { + __set_h_errno(herrno); + return -EAI_SYSTEM; + } + + if (h != NULL) + c = h->h_name; + + if (c == NULL) + return (GAIH_OKIFUNSPEC | -EAI_NONAME); + + namelen = strlen(c) + 1; + } else + namelen = 0; + +#if defined __UCLIBC_HAS_IPV6__ + if (at2->family == AF_INET6 || v4mapped) { + family = AF_INET6; + socklen = sizeof(struct sockaddr_in6); + } #endif - { - struct sockaddr_in *sinp = - (struct sockaddr_in *) (*pai)->ai_addr; - - memcpy (&sinp->sin_addr, - at2->addr, sizeof (struct in_addr)); - sinp->sin_port = st2->port; - memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); - } - - if (c) - { - (*pai)->ai_canonname = ((void *) (*pai) + - sizeof (struct addrinfo) + socklen); - strcpy ((*pai)->ai_canonname, c); +#if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ + else +#endif +#if defined __UCLIBC_HAS_IPV4__ + { + family = AF_INET; + socklen = sizeof(struct sockaddr_in); + } +#endif + for (st2 = st; st2 != NULL; st2 = st2->next) { + if (req->ai_flags & AI_ADDRCONFIG) { + if (family == AF_INET && !(seen & SEEN_IPV4)) + break; +#if defined __UCLIBC_HAS_IPV6__ + else if (family == AF_INET6 && !(seen & SEEN_IPV6)) + break; +#endif + } + *pai = malloc(sizeof(struct addrinfo) + socklen + namelen); + if (*pai == NULL) + return -EAI_MEMORY; + + (*pai)->ai_flags = req->ai_flags; + (*pai)->ai_family = family; + (*pai)->ai_socktype = st2->socktype; + (*pai)->ai_protocol = st2->protocol; + (*pai)->ai_addrlen = socklen; + (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo); +#if 0 /* SALEN */ + (*pai)->ai_addr->sa_len = socklen; +#endif + (*pai)->ai_addr->sa_family = family; + +#if defined __UCLIBC_HAS_IPV6__ + if (family == AF_INET6) { + struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr; + + sin6p->sin6_flowinfo = 0; + if (at2->family == AF_INET6) { + memcpy(&sin6p->sin6_addr, + at2->addr, sizeof(struct in6_addr)); + } else { + sin6p->sin6_addr.s6_addr32[0] = 0; + sin6p->sin6_addr.s6_addr32[1] = 0; + sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff); + memcpy(&sin6p->sin6_addr.s6_addr32[3], + at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3])); + } + sin6p->sin6_port = st2->port; + sin6p->sin6_scope_id = at2->scopeid; + } +#endif +#if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ + else +#endif +#if defined __UCLIBC_HAS_IPV4__ + { + struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr; + + memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr)); + sinp->sin_port = st2->port; + memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero)); + } +#endif + if (c) { + (*pai)->ai_canonname = ((void *) (*pai) + + sizeof(struct addrinfo) + socklen); + strcpy((*pai)->ai_canonname, c); + } else { + (*pai)->ai_canonname = NULL; + } + (*pai)->ai_next = NULL; + pai = &((*pai)->ai_next); + } + + at2 = at2->next; } - else - (*pai)->ai_canonname = NULL; - - (*pai)->ai_next = NULL; - pai = &((*pai)->ai_next); - } - - at2 = at2->next; } - } - return 0; + return 0; } -static struct gaih gaih[] = -{ -#if __UCLIBC_HAS_IPV6__ - { PF_INET6, gaih_inet }, +static const struct gaih gaih[] = { +#if defined __UCLIBC_HAS_IPV6__ + { PF_INET6, gaih_inet }, #endif - { PF_INET, gaih_inet }, + { PF_INET, gaih_inet }, #if 0 - { PF_LOCAL, gaih_local }, + { PF_LOCAL, gaih_local }, #endif - { PF_UNSPEC, NULL } + { PF_UNSPEC, NULL } }; -int -getaddrinfo (const char *name, const char *service, - const struct addrinfo *hints, struct addrinfo **pai) +void +freeaddrinfo(struct addrinfo *ai) { - int i = 0, j = 0, last_i = 0; - struct addrinfo *p = NULL, **end; - struct gaih *g = gaih, *pg = NULL; - struct gaih_service gaih_service, *pservice; - - if (name != NULL && name[0] == '*' && name[1] == 0) - name = NULL; - - if (service != NULL && service[0] == '*' && service[1] == 0) - service = NULL; + struct addrinfo *p; - if (name == NULL && service == NULL) - return EAI_NONAME; - - if (hints == NULL) - hints = &default_hints; + while (ai != NULL) { + p = ai; + ai = ai->ai_next; + free(p); + } +} +libc_hidden_def(freeaddrinfo) - if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST| - AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL)) - return EAI_BADFLAGS; +int +getaddrinfo(const char *name, const char *service, + const struct addrinfo *hints, struct addrinfo **pai) +{ + int i, j, last_i; + struct addrinfo *p, **end; + const struct gaih *g, *pg; + struct gaih_service gaih_service, *pservice; + struct addrinfo default_hints; + + if (name != NULL && name[0] == '*' && name[1] == 0) + name = NULL; + + if (service != NULL && service[0] == '*' && service[1] == 0) + service = NULL; + + if (name == NULL && service == NULL) + return EAI_NONAME; + + if (hints == NULL) { + memset(&default_hints, 0, sizeof(default_hints)); + if (AF_UNSPEC != 0) + default_hints.ai_family = AF_UNSPEC; + hints = &default_hints; + } - if ((hints->ai_flags & AI_CANONNAME) && name == NULL) - return EAI_BADFLAGS; + if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST| + AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL)) + return EAI_BADFLAGS; + + if ((hints->ai_flags & AI_CANONNAME) && name == NULL) + return EAI_BADFLAGS; + + if (service && service[0]) { + char *c; + gaih_service.name = service; + gaih_service.num = strtoul(gaih_service.name, &c, 10); + if (*c != '\0') { + if (hints->ai_flags & AI_NUMERICSERV) + return EAI_NONAME; + gaih_service.num = -1; + } + pservice = &gaih_service; + } else + pservice = NULL; - if (service && service[0]) - { - char *c; - gaih_service.name = service; - gaih_service.num = strtoul (gaih_service.name, &c, 10); - if (*c) - gaih_service.num = -1; - else - /* - * Can't specify a numerical socket unless a protocol - * family was given. - */ - if (hints->ai_socktype == 0 && hints->ai_protocol == 0) - return EAI_SERVICE; - pservice = &gaih_service; - } - else - pservice = NULL; - - if (pai) - end = &p; - else + g = gaih; + pg = NULL; + p = NULL; end = NULL; - - while (g->gaih) - { - if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) - { - if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) - continue; - j++; - if (pg == NULL || pg->gaih != g->gaih) - { - pg = g; - i = g->gaih (name, pservice, hints, end); - if (i != 0) - { - last_i = i; - - if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC)) - continue; - - if (p) - freeaddrinfo (p); - - return -(i & GAIH_EAI); + if (pai) + end = &p; + i = 0; + last_i = 0; + j = 0; + while (g->gaih) { + if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) { + if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) { + ++g; + continue; + } + j++; + if (pg == NULL || pg->gaih != g->gaih) { + pg = g; + i = g->gaih(name, pservice, hints, end); + if (i != 0) { + last_i = i; + if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC)) + continue; + /*if (p) - freeaddrinfo works ok on NULL too */ + freeaddrinfo(p); + return -(i & GAIH_EAI); + } + if (end) + while (*end) + end = &((*end)->ai_next); + } } - if (end) - while(*end) end = &((*end)->ai_next); - } + ++g; } - ++g; - } - if (j == 0) - return EAI_FAMILY; + if (j == 0) + return EAI_FAMILY; - if (p) - { - *pai = p; - return 0; - } - - if (pai == NULL && last_i == 0) - return 0; + if (p) { + *pai = p; + return 0; + } - if (p) - freeaddrinfo (p); + if (pai == NULL && last_i == 0) + return 0; - return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME; -} + /* if (p) - never happens, see above */ + /* freeaddrinfo(p); */ -void -freeaddrinfo (struct addrinfo *ai) -{ - struct addrinfo *p; - - while (ai != NULL) - { - p = ai; - ai = ai->ai_next; - free (p); - } + return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME; } +libc_hidden_def(getaddrinfo)