2 * Copyright 1996 by Craig Metz
3 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4 * Portions from the GNU C library,
5 * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
7 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
10 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
12 /* The Inner Net License, Version 2.00
14 The author(s) grant permission for redistribution and use in source and
15 binary forms, with or without modification, of the software and documentation
16 provided that the following conditions are met:
18 0. If you receive a version of the software that is specifically labelled
19 as not being for redistribution (check the version message and/or README),
20 you are not permitted to redistribute that version of the software in any
22 1. All terms of the all other applicable copyrights and licenses must be
24 2. Redistributions of source code must retain the authors' copyright
25 notice(s), this list of conditions, and the following disclaimer.
26 3. Redistributions in binary form must reproduce the authors' copyright
27 notice(s), this list of conditions, and the following disclaimer in the
28 documentation and/or other materials provided with the distribution.
29 4. All advertising materials mentioning features or use of this software
30 must display the following acknowledgement with the name(s) of the
31 authors as specified in the copyright notice(s) substituted where
34 This product includes software developed by <name(s)>, The Inner
35 Net, and other contributors.
37 5. Neither the name(s) of the author(s) nor the names of its contributors
38 may be used to endorse or promote products derived from this software
39 without specific prior written permission.
41 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
42 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
45 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
48 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 If these license terms cause you a real problem, contact the author. */
64 #include <arpa/inet.h>
65 #include <sys/socket.h>
66 #include <netinet/in.h>
67 #include <sys/types.h>
69 #include <sys/utsname.h>
73 /* Experimentally off - libc_hidden_proto(memcpy) */
74 /* Experimentally off - libc_hidden_proto(memset) */
75 /* libc_hidden_proto(strcmp) */
76 /* libc_hidden_proto(stpcpy) */
77 /* Experimentally off - libc_hidden_proto(strchr) */
78 /* Experimentally off - libc_hidden_proto(strcpy) */
79 /* Experimentally off - libc_hidden_proto(strlen) */
80 /* libc_hidden_proto(socket) */
81 /* libc_hidden_proto(close) */
82 /* libc_hidden_proto(getservbyname_r) */
83 /* libc_hidden_proto(gethostbyname2_r) */
84 /* libc_hidden_proto(gethostbyaddr_r) */
85 /* libc_hidden_proto(inet_pton) */
86 /* libc_hidden_proto(inet_ntop) */
87 /* libc_hidden_proto(strtoul) */
88 /* libc_hidden_proto(if_nametoindex) */
89 /* libc_hidden_proto(__h_errno_location) */
90 /* libc_hidden_proto(uname) */
91 #ifdef __UCLIBC_HAS_IPV6__
92 /* libc_hidden_proto(in6addr_loopback) */
95 #define GAIH_OKIFUNSPEC 0x0100
96 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
99 #define UNIX_PATH_MAX 108
102 /* Useful for having small structure members/global variables */
103 typedef int8_t socktype_t;
104 typedef int8_t family_t;
105 typedef int8_t protocol_t;
106 struct BUG_too_small {
107 char BUG_socktype_t_too_small[(0
112 char BUG_family_t_too_small[(0
117 char BUG_protocol_t_too_small[(0
123 struct gaih_service {
128 struct gaih_servtuple {
129 struct gaih_servtuple *next;
135 struct gaih_addrtuple {
136 struct gaih_addrtuple *next;
142 struct gaih_typeproto {
148 /* Values for `protoflag'. */
149 #define GAI_PROTO_NOSERVICE 1
150 #define GAI_PROTO_PROTOANY 2
152 static const struct gaih_typeproto gaih_inet_typeproto[] = {
154 { SOCK_STREAM, IPPROTO_TCP, 0, "tcp" },
155 { SOCK_DGRAM , IPPROTO_UDP, 0, "udp" },
156 { SOCK_RAW , 0 , GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, "raw" },
162 int (*gaih)(const char *name, const struct gaih_service *service,
163 const struct addrinfo *req, struct addrinfo **pai);
169 static unsigned __check_pf(void)
172 #if defined __UCLIBC_SUPPORT_AI_ADDRCONFIG__
174 /* Get the interface list via getifaddrs. */
175 struct ifaddrs *ifa = NULL;
176 struct ifaddrs *runp;
177 if (getifaddrs(&ifa) != 0) {
178 /* We cannot determine what interfaces are available.
180 #if defined __UCLIBC_HAS_IPV4__
182 #endif /* __UCLIBC_HAS_IPV4__ */
183 #if defined __UCLIBC_HAS_IPV6__
185 #endif /* __UCLIBC_HAS_IPV6__ */
189 for (runp = ifa; runp != NULL; runp = runp->ifa_next) {
190 #if defined __UCLIBC_HAS_IPV4__
191 if (runp->ifa_addr->sa_family == PF_INET)
193 #endif /* __UCLIBC_HAS_IPV4__ */
194 #if defined __UCLIBC_HAS_IPV6__
195 if (runp->ifa_addr->sa_family == PF_INET6)
197 #endif /* __UCLIBC_HAS_IPV6__ */
202 /* AI_ADDRCONFIG is disabled, assume both ipv4 and ipv6 available. */
203 #if defined __UCLIBC_HAS_IPV4__
205 #endif /* __UCLIBC_HAS_IPV4__ */
206 #if defined __UCLIBC_HAS_IPV6__
208 #endif /* __UCLIBC_HAS_IPV6__ */
210 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
214 static int addrconfig(sa_family_t af)
218 int saved_errno = errno;
222 #if defined __UCLIBC_HAS_IPV4__
224 ret = seen & SEEN_IPV4;
227 #if defined __UCLIBC_HAS_IPV6__
229 ret = seen & SEEN_IPV6;
233 s = socket(af, SOCK_DGRAM, 0);
234 ret = 1; /* Assume PF_UNIX. */
241 __set_errno(saved_errno);
246 /* Using Unix sockets this way is a security risk. */
248 gaih_local(const char *name, const struct gaih_service *service,
249 const struct addrinfo *req, struct addrinfo **pai)
251 struct utsname utsname;
252 struct addrinfo *ai = *pai;
254 if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
255 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
257 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
258 if (uname(&utsname) < 0)
262 if (strcmp(name, "localhost") &&
263 strcmp(name, "local") &&
264 strcmp(name, "unix") &&
265 strcmp(name, utsname.nodename))
266 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
269 if (req->ai_protocol || req->ai_socktype) {
270 const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
273 && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
274 || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
275 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol))
280 if (req->ai_socktype)
281 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
282 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
286 *pai = ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
287 + ((req->ai_flags & AI_CANONNAME)
288 ? (strlen(utsname.nodename) + 1) : 0));
293 ai->ai_flags = req->ai_flags;
294 ai->ai_family = AF_LOCAL;
295 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
296 ai->ai_protocol = req->ai_protocol;
297 ai->ai_addrlen = sizeof(struct sockaddr_un);
298 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
300 ((struct sockaddr_un *)ai->ai_addr)->sun_len = sizeof(struct sockaddr_un);
303 ((struct sockaddr_un *)ai->ai_addr)->sun_family = AF_LOCAL;
304 memset(((struct sockaddr_un *)ai->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
307 struct sockaddr_un *sunp = (struct sockaddr_un *)ai->ai_addr;
309 if (strchr(service->name, '/') != NULL) {
310 if (strlen(service->name) >= sizeof(sunp->sun_path))
311 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
313 strcpy(sunp->sun_path, service->name);
315 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(sunp->sun_path))
316 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
317 stpcpy(stpcpy(sunp->sun_path, P_tmpdir "/"), service->name);
320 /* This is a dangerous use of the interface since there is a time
321 window between the test for the file and the actual creation
322 (done by the caller) in which a file with the same name could
324 char *buf = ((struct sockaddr_un *)ai->ai_addr)->sun_path;
326 if (__path_search(buf, L_tmpnam, NULL, NULL, 0) != 0
327 || __gen_tempname(buf, __GT_NOCREATE) != 0
333 ai->ai_canonname = NULL;
334 if (req->ai_flags & AI_CANONNAME)
335 ai->ai_canonname = strcpy((char *)(ai + 1) + sizeof(struct sockaddr_un),
342 gaih_inet_serv(const char *servicename, const struct gaih_typeproto *tp,
343 const struct addrinfo *req, struct gaih_servtuple *st)
346 size_t tmpbuflen = 1024;
352 tmpbuf = alloca(tmpbuflen);
353 r = getservbyname_r(servicename, tp->name, &ts, tmpbuf, tmpbuflen, &s);
354 if (r == 0 && s != NULL)
357 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
361 st->socktype = tp->socktype;
362 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) ? req->ai_protocol : tp->protocol);
363 st->port = s->s_port;
367 /* NB: also uses h,pat,rc,no_data variables */
368 #define gethosts(_family, _type) \
379 tmpbuf = alloca(tmpbuflen); \
380 rc = gethostbyname2_r(name, _family, &th, tmpbuf, \
381 tmpbuflen, &h, &herrno); \
382 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
384 if (herrno == NETDB_INTERNAL) { \
385 __set_h_errno(herrno); \
386 return -EAI_SYSTEM; \
388 if (herrno == TRY_AGAIN) \
389 no_data = EAI_AGAIN; \
391 no_data = (herrno == NO_DATA); \
392 } else if (h != NULL) { \
393 for (i = 0; h->h_addr_list[i]; i++) { \
394 if (*pat == NULL) { \
395 *pat = alloca(sizeof(struct gaih_addrtuple)); \
396 (*pat)->scopeid = 0; \
398 (*pat)->next = NULL; \
399 (*pat)->family = _family; \
400 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(_type)); \
401 pat = &((*pat)->next); \
407 gaih_inet(const char *name, const struct gaih_service *service,
408 const struct addrinfo *req, struct addrinfo **pai)
410 struct gaih_servtuple nullserv;
412 const struct gaih_typeproto *tp = gaih_inet_typeproto;
413 struct gaih_servtuple *st = &nullserv;
414 struct gaih_addrtuple *at = NULL;
416 int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6)
417 && (req->ai_flags & AI_V4MAPPED);
418 unsigned seen = __check_pf();
420 memset(&nullserv, 0, sizeof(nullserv));
422 if (req->ai_protocol || req->ai_socktype) {
425 && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
426 || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol)
432 if (req->ai_socktype)
433 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
434 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
438 if (service != NULL) {
439 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
440 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
442 if (service->num < 0) {
444 st = alloca(sizeof(struct gaih_servtuple));
445 rc = gaih_inet_serv(service->name, tp, req, st);
449 struct gaih_servtuple **pst = &st;
450 for (tp++; tp->name[0]; tp++) {
451 struct gaih_servtuple *newp;
453 if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
456 if (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
458 if (req->ai_protocol != 0
459 && !(tp->protoflag & GAI_PROTO_PROTOANY)
460 && req->ai_protocol != tp->protocol)
463 newp = alloca(sizeof(struct gaih_servtuple));
464 rc = gaih_inet_serv(service->name, tp, req, newp);
466 if (rc & GAIH_OKIFUNSPEC)
475 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
478 st = alloca(sizeof(struct gaih_servtuple));
480 st->socktype = tp->socktype;
481 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
482 ? req->ai_protocol : tp->protocol);
483 st->port = htons(service->num);
485 } else if (req->ai_socktype || req->ai_protocol) {
486 st = alloca(sizeof(struct gaih_servtuple));
488 st->socktype = tp->socktype;
489 st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
490 ? req->ai_protocol : tp->protocol);
494 * Neither socket type nor protocol is set. Return all socket types
497 struct gaih_servtuple **lastp = &st;
498 for (++tp; tp->name[0]; ++tp) {
499 struct gaih_servtuple *newp;
501 newp = alloca(sizeof(struct gaih_servtuple));
503 newp->socktype = tp->socktype;
504 newp->protocol = tp->protocol;
513 at = alloca(sizeof(struct gaih_addrtuple));
514 at->family = AF_UNSPEC;
518 if (inet_pton(AF_INET, name, at->addr) > 0) {
519 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
520 at->family = AF_INET;
525 #if defined __UCLIBC_HAS_IPV6__
526 if (at->family == AF_UNSPEC) {
527 char *namebuf = strdupa(name);
530 scope_delim = strchr(namebuf, SCOPE_DELIMITER);
531 if (scope_delim != NULL)
534 if (inet_pton(AF_INET6, namebuf, at->addr) > 0) {
535 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
536 at->family = AF_INET6;
540 if (scope_delim != NULL) {
541 int try_numericscope = 0;
542 if (IN6_IS_ADDR_LINKLOCAL(at->addr) || IN6_IS_ADDR_MC_LINKLOCAL(at->addr)) {
543 at->scopeid = if_nametoindex(scope_delim + 1);
544 if (at->scopeid == 0)
545 try_numericscope = 1;
547 try_numericscope = 1;
549 if (try_numericscope != 0) {
551 assert(sizeof(uint32_t) <= sizeof(unsigned long));
552 at->scopeid = (uint32_t)strtoul(scope_delim + 1, &end, 10);
554 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
561 if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) {
563 struct gaih_addrtuple **pat = &at;
568 * If we are looking for both IPv4 and IPv6 address we don't want
569 * the lookup functions to automatically promote IPv4 addresses to
572 #if defined __UCLIBC_HAS_IPV6__
573 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
574 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV6))
575 gethosts(AF_INET6, struct in6_addr);
577 no_inet6_data = no_data;
579 if (req->ai_family == AF_INET
580 || (!v4mapped && req->ai_family == AF_UNSPEC)
581 || (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL)))
583 if (!(req->ai_flags & AI_ADDRCONFIG) || (seen & SEEN_IPV4))
584 gethosts(AF_INET, struct in_addr);
587 if (no_data != 0 && no_inet6_data != 0) {
588 /* If both requests timed out report this. */
589 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
592 * We made requests but they turned out no data.
593 * The name is known, though.
595 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
599 if (at->family == AF_UNSPEC)
600 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
602 struct gaih_addrtuple *atr;
604 atr = at = alloca(sizeof(struct gaih_addrtuple));
605 memset(at, '\0', sizeof(struct gaih_addrtuple));
606 if (req->ai_family == 0) {
607 at->next = alloca(sizeof(struct gaih_addrtuple));
608 memset(at->next, '\0', sizeof(struct gaih_addrtuple));
610 #if defined __UCLIBC_HAS_IPV6__
611 if (req->ai_family == 0 || req->ai_family == AF_INET6) {
612 at->family = AF_INET6;
613 if ((req->ai_flags & AI_PASSIVE) == 0)
614 memcpy(at->addr, &in6addr_loopback, sizeof(struct in6_addr));
618 if (req->ai_family == 0 || req->ai_family == AF_INET) {
619 atr->family = AF_INET;
620 if ((req->ai_flags & AI_PASSIVE) == 0)
621 *(uint32_t*)atr->addr = htonl(INADDR_LOOPBACK);
629 const char *c = NULL;
630 struct gaih_servtuple *st2;
631 struct gaih_addrtuple *at2 = at;
632 size_t socklen, namelen;
636 * buffer is the size of an unformatted IPv6 address in
639 char buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
641 while (at2 != NULL) {
642 if (req->ai_flags & AI_CANONNAME) {
643 struct hostent *h = NULL;
646 size_t tmpbuflen = 512;
651 tmpbuf = alloca(tmpbuflen);
652 //if (tmpbuf == NULL)
653 // return -EAI_MEMORY;
654 rc = gethostbyaddr_r(at2->addr,
655 ((at2->family == AF_INET6)
656 ? sizeof(struct in6_addr)
657 : sizeof(struct in_addr)),
659 &th, tmpbuf, tmpbuflen,
661 } while (rc == errno && herrno == NETDB_INTERNAL);
663 if (rc != 0 && herrno == NETDB_INTERNAL) {
664 __set_h_errno(herrno);
669 c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
674 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
676 namelen = strlen(c) + 1;
680 #if defined __UCLIBC_HAS_IPV6__
681 if (at2->family == AF_INET6 || v4mapped) {
683 socklen = sizeof(struct sockaddr_in6);
686 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
689 #if defined __UCLIBC_HAS_IPV4__
692 socklen = sizeof(struct sockaddr_in);
695 for (st2 = st; st2 != NULL; st2 = st2->next) {
696 if (req->ai_flags & AI_ADDRCONFIG) {
697 if (family == AF_INET && !(seen & SEEN_IPV4))
699 #if defined __UCLIBC_HAS_IPV6__
700 else if (family == AF_INET6 && !(seen & SEEN_IPV6))
704 *pai = malloc(sizeof(struct addrinfo) + socklen + namelen);
708 (*pai)->ai_flags = req->ai_flags;
709 (*pai)->ai_family = family;
710 (*pai)->ai_socktype = st2->socktype;
711 (*pai)->ai_protocol = st2->protocol;
712 (*pai)->ai_addrlen = socklen;
713 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
715 (*pai)->ai_addr->sa_len = socklen;
717 (*pai)->ai_addr->sa_family = family;
719 #if defined __UCLIBC_HAS_IPV6__
720 if (family == AF_INET6) {
721 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *) (*pai)->ai_addr;
723 sin6p->sin6_flowinfo = 0;
724 if (at2->family == AF_INET6) {
725 memcpy(&sin6p->sin6_addr,
726 at2->addr, sizeof(struct in6_addr));
728 sin6p->sin6_addr.s6_addr32[0] = 0;
729 sin6p->sin6_addr.s6_addr32[1] = 0;
730 sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
731 memcpy(&sin6p->sin6_addr.s6_addr32[3],
732 at2->addr, sizeof(sin6p->sin6_addr.s6_addr32[3]));
734 sin6p->sin6_port = st2->port;
735 sin6p->sin6_scope_id = at2->scopeid;
738 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
741 #if defined __UCLIBC_HAS_IPV4__
743 struct sockaddr_in *sinp = (struct sockaddr_in *) (*pai)->ai_addr;
745 memcpy(&sinp->sin_addr, at2->addr, sizeof(struct in_addr));
746 sinp->sin_port = st2->port;
747 memset(sinp->sin_zero, '\0', sizeof(sinp->sin_zero));
751 (*pai)->ai_canonname = ((void *) (*pai) +
752 sizeof(struct addrinfo) + socklen);
753 strcpy((*pai)->ai_canonname, c);
755 (*pai)->ai_canonname = NULL;
757 (*pai)->ai_next = NULL;
758 pai = &((*pai)->ai_next);
767 static const struct gaih gaih[] = {
768 #if defined __UCLIBC_HAS_IPV6__
769 { PF_INET6, gaih_inet },
771 { PF_INET, gaih_inet },
773 { PF_LOCAL, gaih_local },
778 /* libc_hidden_proto(freeaddrinfo) */
780 freeaddrinfo(struct addrinfo *ai)
790 libc_hidden_def(freeaddrinfo)
792 /* libc_hidden_proto(getaddrinfo) */
794 getaddrinfo(const char *name, const char *service,
795 const struct addrinfo *hints, struct addrinfo **pai)
797 int i = 0, j, last_i = 0;
798 struct addrinfo *p = NULL, **end;
799 const struct gaih *g = gaih, *pg = NULL;
800 struct gaih_service gaih_service, *pservice;
801 struct addrinfo default_hints;
803 if (name != NULL && name[0] == '*' && name[1] == 0)
806 if (service != NULL && service[0] == '*' && service[1] == 0)
809 if (name == NULL && service == NULL)
813 memset(&default_hints, 0, sizeof(default_hints));
815 default_hints.ai_family = AF_UNSPEC;
816 hints = &default_hints;
819 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
820 AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))
823 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
826 if (service && service[0]) {
828 gaih_service.name = service;
829 gaih_service.num = strtoul(gaih_service.name, &c, 10);
831 if (hints->ai_flags & AI_NUMERICSERV)
833 gaih_service.num = -1;
836 * Can't specify a numerical socket unless a protocol
839 if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
842 pservice = &gaih_service;
852 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {
853 if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {
858 if (pg == NULL || pg->gaih != g->gaih) {
860 i = g->gaih(name, pservice, hints, end);
863 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
867 return -(i & GAIH_EAI);
871 end = &((*end)->ai_next);
885 if (pai == NULL && last_i == 0)
888 /* if (p) - never happens, see above */
889 /* freeaddrinfo(p); */
891 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
893 libc_hidden_def(getaddrinfo)