diff options
-rw-r--r-- | libc/inet/getaddrinfo.c | 1368 |
1 files changed, 630 insertions, 738 deletions
diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c index b4f49607b..3af422b72 100644 --- a/libc/inet/getaddrinfo.c +++ b/libc/inet/getaddrinfo.c @@ -120,886 +120,778 @@ struct BUG_too_small { ) <= 127 ? 1 : -1]; }; -struct gaih_service -{ - const char *name; - int num; +struct gaih_service { + const char *name; + int num; }; -struct gaih_servtuple -{ - struct gaih_servtuple *next; - int socktype; - int protocol; - int port; +struct gaih_servtuple { + struct gaih_servtuple *next; + int socktype; + int protocol; + int port; }; -struct gaih_addrtuple -{ - struct gaih_addrtuple *next; - int family; - char addr[16]; - uint32_t scopeid; +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]; +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 - -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 , "" }, +#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, "" }, }; -struct gaih -{ - int family; - int (*gaih)(const char *name, const struct gaih_service *service, - const struct addrinfo *req, struct addrinfo **pai); +struct gaih { + int family; + int (*gaih)(const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai); }; #define SEEN_IPV4 1 #define SEEN_IPV6 2 -static unsigned __check_pf (void) +static unsigned __check_pf(void) { - unsigned seen = 0; + unsigned seen = 0; #if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__ - { - /* Get the interface list via getifaddrs. */ - struct ifaddrs *ifa = NULL; - struct ifaddrs *runp; - if (getifaddrs (&ifa) != 0) - { - /* We cannot determine what interfaces are available. Be - optimistic. */ + { + /* Get the interface list via getifaddrs. */ + struct ifaddrs *ifa = NULL; + struct ifaddrs *runp; + if (getifaddrs(&ifa) != 0) { + /* We cannot determine what interfaces are available. + * Be optimistic. */ #if defined __UCLIBC_HAS_IPV4__ - seen |= SEEN_IPV4; + seen |= SEEN_IPV4; #endif /* __UCLIBC_HAS_IPV4__ */ #if defined __UCLIBC_HAS_IPV6__ - seen |= SEEN_IPV6; + seen |= SEEN_IPV6; #endif /* __UCLIBC_HAS_IPV6__ */ - return seen; - } + return seen; + } - for (runp = ifa; runp != NULL; runp = runp->ifa_next) + for (runp = ifa; runp != NULL; runp = runp->ifa_next) #if defined __UCLIBC_HAS_IPV4__ - if (runp->ifa_addr->sa_family == PF_INET) - seen |= SEEN_IPV4; + if (runp->ifa_addr->sa_family == PF_INET) + seen |= SEEN_IPV4; #endif /* __UCLIBC_HAS_IPV4__ */ #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ - else /* can't be both at once */ + else /* can't be both at once */ #endif /* __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ */ #if defined __UCLIBC_HAS_IPV6__ - if (runp->ifa_addr->sa_family == PF_INET6) - seen |= SEEN_IPV6; + if (runp->ifa_addr->sa_family == PF_INET6) + seen |= SEEN_IPV6; #endif /* __UCLIBC_HAS_IPV6__ */ - (void) freeifaddrs (ifa); - } + freeifaddrs(ifa); + } #else - /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */ + /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */ #if defined __UCLIBC_HAS_IPV4__ - seen |= SEEN_IPV4; + seen |= SEEN_IPV4; #endif /* __UCLIBC_HAS_IPV4__ */ #if defined __UCLIBC_HAS_IPV6__ - seen |= SEEN_IPV6; + seen |= SEEN_IPV6; #endif /* __UCLIBC_HAS_IPV6__ */ #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */ - return seen; + return seen; } -static int addrconfig (sa_family_t af) +static int addrconfig(sa_family_t af) { - int s; - int ret; - int saved_errno = errno; - unsigned seen; + int s; + int ret; + int saved_errno = errno; + unsigned seen; - seen = __check_pf(); + seen = __check_pf(); #if defined __UCLIBC_HAS_IPV4__ - if (af == AF_INET) - ret = seen & SEEN_IPV4; - else + if (af == AF_INET) + ret = seen & SEEN_IPV4; + else #endif #if defined __UCLIBC_HAS_IPV6__ - if (af == AF_INET6) - ret = seen & SEEN_IPV6; - else + 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; + { + s = socket(af, SOCK_DGRAM, 0); + ret = 1; /* Assume PF_UNIX. */ + if (s < 0) { + if (errno != EMFILE) + ret = 0; + } else + close(s); } - else - close(s); - } - __set_errno (saved_errno); - return ret; + __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, +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); - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); - } - } - - *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); + 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); + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + } + } + + *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); + ((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); + ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL; + memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX); - if (service) - { - struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr; + if (service) { + struct sockaddr_un *sunp = (struct sockaddr_un *)(*pai)->ai_addr; - if (strchr (service->name, '/') != NULL) - { - if (strlen (service->name) >= sizeof (sunp->sun_path)) - return GAIH_OKIFUNSPEC | -EAI_SERVICE; + if (strchr(service->name, '/') != NULL) { + if (strlen(service->name) >= sizeof(sunp->sun_path)) + return GAIH_OKIFUNSPEC | -EAI_SERVICE; - strcpy (sunp->sun_path, service->name); + 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 *)(*pai)->ai_addr)->sun_path; + + if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0 + || __gen_tempname(buf, __GT_NOCREATE) != 0 + ) { + return -EAI_SYSTEM; + } } - 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 *) (*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; + 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; } #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) { - struct gaih_servtuple nullserv; - - const struct gaih_typeproto *tp = gaih_inet_typeproto; - struct gaih_servtuple *st = &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); - unsigned seen = __check_pf(); - - memset(&nullserv, 0, sizeof(nullserv)); - - 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); - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); - } - } - - 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); + struct gaih_servtuple nullserv; + + const struct gaih_typeproto *tp = gaih_inet_typeproto; + struct gaih_servtuple *st = &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); + unsigned seen = __check_pf(); + + memset(&nullserv, 0, sizeof(nullserv)); + + 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); + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); } - 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 (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; - } + 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; + } #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) - 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 (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); + } + } + } } - } - } #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 (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 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); + 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)))) - 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 (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; + 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; - } + 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*)atr->addr = 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); - - } - 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; + const char *c = NULL; + struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + size_t socklen, namelen; + sa_family_t family; - if (c == NULL) - return GAIH_OKIFUNSPEC | -EAI_NONAME; - - namelen = strlen (c) + 1; - } - else - namelen = 0; + /* + * 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) { + 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); + } 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 defined __UCLIBC_HAS_IPV6__ - if (at2->family == AF_INET6 || v4mapped) - { - family = AF_INET6; - socklen = sizeof (struct sockaddr_in6); - } + if (at2->family == AF_INET6 || v4mapped) { + family = AF_INET6; + socklen = sizeof(struct sockaddr_in6); + } #endif #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ - else + else #endif #if defined __UCLIBC_HAS_IPV4__ - { - family = AF_INET; - socklen = sizeof (struct sockaddr_in); - } + { + 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; + 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; + 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); + } + *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; + (*pai)->ai_addr->sa_len = socklen; #endif /* SALEN */ - (*pai)->ai_addr->sa_family = family; + (*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; - } + 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 + 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)); - } + { + 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); + 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 const struct gaih gaih[] = -{ +static const struct gaih gaih[] = { #if defined __UCLIBC_HAS_IPV6__ - { PF_INET6, gaih_inet }, + { 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 } }; libc_hidden_proto(freeaddrinfo) void -freeaddrinfo (struct addrinfo *ai) +freeaddrinfo(struct addrinfo *ai) { - struct addrinfo *p; - - while (ai != NULL) - { - p = ai; - ai = ai->ai_next; - free (p); - } + struct addrinfo *p; + + while (ai != NULL) { + p = ai; + ai = ai->ai_next; + free(p); + } } libc_hidden_def(freeaddrinfo) libc_hidden_proto(getaddrinfo) int -getaddrinfo (const char *name, const char *service, +getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, struct addrinfo **pai) { - int i = 0, j = 0, last_i = 0; - struct addrinfo *p = NULL, **end; - const struct gaih *g = gaih, *pg = NULL; - 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) - default_hints.ai_family = AF_UNSPEC; - hints = &default_hints; - } - - 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; + int i = 0, j = 0, last_i = 0; + struct addrinfo *p = NULL, **end; + const struct gaih *g = gaih, *pg = NULL; + 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) + default_hints.ai_family = AF_UNSPEC; + hints = &default_hints; } + + 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; + } 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 - /* - * 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 - 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)) - { - ++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 (p); - - return -(i & GAIH_EAI); + 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)) { + ++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(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 (p) { + *pai = p; + return 0; + } - if (pai == NULL && last_i == 0) - return 0; + if (pai == NULL && last_i == 0) + return 0; - if (p) - freeaddrinfo (p); + if (p) + freeaddrinfo(p); - return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME; + return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME; } libc_hidden_def(getaddrinfo) |