OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[uclinux-h8/uClibc.git] / libc / inet / getaddrinfo.c
1 /*
2  * Copyright 1996 by Craig Metz 
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7
8 /* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
9
10 /* The Inner Net License, Version 2.00
11
12   The author(s) grant permission for redistribution and use in source and
13 binary forms, with or without modification, of the software and documentation
14 provided that the following conditions are met:
15
16 0. If you receive a version of the software that is specifically labelled
17    as not being for redistribution (check the version message and/or README),
18    you are not permitted to redistribute that version of the software in any
19    way or form.
20 1. All terms of the all other applicable copyrights and licenses must be
21    followed.
22 2. Redistributions of source code must retain the authors' copyright
23    notice(s), this list of conditions, and the following disclaimer.
24 3. Redistributions in binary form must reproduce the authors' copyright
25    notice(s), this list of conditions, and the following disclaimer in the
26    documentation and/or other materials provided with the distribution.
27 4. All advertising materials mentioning features or use of this software
28    must display the following acknowledgement with the name(s) of the
29    authors as specified in the copyright notice(s) substituted where
30    indicated:
31
32         This product includes software developed by <name(s)>, The Inner
33         Net, and other contributors.
34
35 5. Neither the name(s) of the author(s) nor the names of its contributors
36    may be used to endorse or promote products derived from this software
37    without specific prior written permission.
38
39 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
40 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
41 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
42 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
43 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
46 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
48 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49
50   If these license terms cause you a real problem, contact the author.  */
51
52 #define _GNU_SOURCE
53 #define __FORCE_GLIBC
54 #include <features.h>
55 #include <assert.h>
56 #include <errno.h>
57 #include <netdb.h>
58 #include <resolv.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 #include <arpa/inet.h>
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <sys/types.h>
67 #include <sys/un.h>
68 #include <sys/utsname.h>
69 #include <net/if.h>
70
71 libc_hidden_proto(memcpy)
72 libc_hidden_proto(memset)
73 /* libc_hidden_proto(strcmp) */
74 /* libc_hidden_proto(stpcpy) */
75 libc_hidden_proto(strchr)
76 libc_hidden_proto(strcpy)
77 libc_hidden_proto(strlen)
78 libc_hidden_proto(socket)
79 libc_hidden_proto(close)
80 libc_hidden_proto(getservbyname_r)
81 libc_hidden_proto(gethostbyname_r)
82 libc_hidden_proto(gethostbyname2_r)
83 libc_hidden_proto(gethostbyaddr_r)
84 libc_hidden_proto(inet_pton)
85 libc_hidden_proto(inet_ntop)
86 libc_hidden_proto(strtoul)
87 libc_hidden_proto(if_nametoindex)
88 /* libc_hidden_proto(uname) */
89 #ifdef __UCLIBC_HAS_IPV6__
90 libc_hidden_proto(in6addr_loopback)
91 #endif
92
93 /* The following declarations and definitions have been removed from
94  *    the public header since we don't want people to use them.  */
95 #define AI_V4MAPPED     0x0008  /* IPv4-mapped addresses are acceptable.  */
96 #define AI_ALL          0x0010  /* Return both IPv4 and IPv6 addresses.  */
97 #define AI_ADDRCONFIG   0x0020  /* Use configuration of this host to choose 
98                                     returned address type.  */
99 #define AI_DEFAULT    (AI_V4MAPPED | AI_ADDRCONFIG)
100
101
102 #define GAIH_OKIFUNSPEC 0x0100
103 #define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
104
105 #ifndef UNIX_PATH_MAX
106 #define UNIX_PATH_MAX  108
107 #endif
108
109 struct gaih_service
110 {
111     const char *name;
112     int num;
113 };
114
115 struct gaih_servtuple
116 {
117     struct gaih_servtuple *next;
118     int socktype;
119     int protocol;
120     int port;
121 };
122
123 static const struct gaih_servtuple nullserv;
124
125 struct gaih_addrtuple
126 {
127     struct gaih_addrtuple *next;
128     int family;
129     char addr[16];
130     uint32_t scopeid;
131 };
132
133 struct gaih_typeproto
134 {
135     int socktype;
136     int protocol;
137     char name[4];
138     int protoflag;
139 };
140
141 /* Values for `protoflag'.  */
142 #define GAI_PROTO_NOSERVICE     1
143 #define GAI_PROTO_PROTOANY      2
144
145 static const struct gaih_typeproto gaih_inet_typeproto[] =
146 {
147     { 0, 0, "", 0 },
148     { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
149     { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
150     { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
151     { 0, 0, "", 0 }
152 };
153
154 struct gaih
155 {
156     int family;
157     int (*gaih)(const char *name, const struct gaih_service *service,
158                 const struct addrinfo *req, struct addrinfo **pai);
159 };
160
161 #if PF_UNSPEC == 0
162 static const struct addrinfo default_hints;
163 #else
164 static const struct addrinfo default_hints =
165 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
166 #endif
167
168
169 static int addrconfig (sa_family_t af)
170 {
171     int s;
172     int ret;
173     int saved_errno = errno;
174     s = socket(af, SOCK_DGRAM, 0);
175     if (s < 0)
176         ret = (errno == EMFILE) ? 1 : 0;
177     else
178     {
179         close(s);
180         ret = 1;
181     }
182     __set_errno (saved_errno);
183     return ret;
184 }
185
186 #if 0
187 /* Using Unix sockets this way is a security risk.  */
188 static int
189 gaih_local (const char *name, const struct gaih_service *service,
190             const struct addrinfo *req, struct addrinfo **pai)
191 {
192     struct utsname utsname;
193
194     if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
195         return GAIH_OKIFUNSPEC | -EAI_NONAME;
196
197     if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
198         if (uname (&utsname) < 0)
199             return -EAI_SYSTEM;
200
201     if (name != NULL)
202     {
203         if (strcmp(name, "localhost") &&
204             strcmp(name, "local") &&
205             strcmp(name, "unix") &&
206             strcmp(name, utsname.nodename))
207             return GAIH_OKIFUNSPEC | -EAI_NONAME;
208     }
209
210     if (req->ai_protocol || req->ai_socktype)
211     {
212         const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
213
214         while (tp->name[0]
215                && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
216                    || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
217                    || (req->ai_protocol != 0
218                        && !(tp->protoflag & GAI_PROTO_PROTOANY)
219                        && req->ai_protocol != tp->protocol)))
220             ++tp;
221
222         if (! tp->name[0])
223         {
224             if (req->ai_socktype)
225                 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
226             else
227                 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
228         }
229     }
230
231     *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
232                    + ((req->ai_flags & AI_CANONNAME)
233                       ? (strlen(utsname.nodename) + 1): 0));
234     if (*pai == NULL)
235         return -EAI_MEMORY;
236
237     (*pai)->ai_next = NULL;
238     (*pai)->ai_flags = req->ai_flags;
239     (*pai)->ai_family = AF_LOCAL;
240     (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
241     (*pai)->ai_protocol = req->ai_protocol;
242     (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
243     (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
244
245 #if SALEN
246     ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
247         sizeof (struct sockaddr_un);
248 #endif /* SALEN */
249
250     ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
251     memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
252
253     if (service)
254     {
255         struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
256
257         if (strchr (service->name, '/') != NULL)
258         {
259             if (strlen (service->name) >= sizeof (sunp->sun_path))
260                 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
261
262             strcpy (sunp->sun_path, service->name);
263         }
264         else
265         {
266             if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
267                 sizeof (sunp->sun_path))
268                 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
269
270             stpcpy (stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
271         }
272     }
273     else
274     {
275         /* This is a dangerous use of the interface since there is a time
276            window between the test for the file and the actual creation
277            (done by the caller) in which a file with the same name could
278            be created.  */
279         char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
280
281         if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
282                               0) != 0
283             || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
284             return -EAI_SYSTEM;
285     }
286
287     if (req->ai_flags & AI_CANONNAME)
288         (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
289                                        + sizeof (struct sockaddr_un),
290                                        utsname.nodename);
291     else
292         (*pai)->ai_canonname = NULL;
293     return 0;
294 }
295 #endif  /* 0 */
296
297 static int
298 gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
299                 const struct addrinfo *req, struct gaih_servtuple *st)
300 {
301     struct servent *s;
302     size_t tmpbuflen = 1024;
303     struct servent ts;
304     char *tmpbuf;
305     int r;
306
307     do
308     {
309         tmpbuf = alloca (tmpbuflen);
310
311         r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
312                              &s);
313         if (r != 0 || s == NULL)
314         {
315             if (r == ERANGE)
316                 tmpbuflen *= 2;
317             else
318                 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
319         }
320     }
321     while (r);
322
323     st->next = NULL;
324     st->socktype = tp->socktype;
325     st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
326                     ? req->ai_protocol : tp->protocol);
327     st->port = s->s_port;
328
329     return 0;
330 }
331
332 #define gethosts(_family, _type)                                        \
333 {                                                                       \
334     int i, herrno;                                                      \
335     size_t tmpbuflen;                                                   \
336     struct hostent th;                                                  \
337     char *tmpbuf;                                                       \
338     tmpbuflen = 512;                                                    \
339     no_data = 0;                                                        \
340     do {                                                                \
341         tmpbuflen *= 2;                                                 \
342         tmpbuf = alloca (tmpbuflen);                                    \
343         rc = gethostbyname2_r (name, _family, &th, tmpbuf,              \
344                                tmpbuflen, &h, &herrno);                 \
345     } while (rc == ERANGE && herrno == NETDB_INTERNAL);                 \
346     if (rc != 0)                                                        \
347     {                                                                   \
348         if (herrno == NETDB_INTERNAL)                                   \
349         {                                                               \
350             __set_h_errno (herrno);                                     \
351                 return -EAI_SYSTEM;                                     \
352         }                                                               \
353         if (herrno == TRY_AGAIN)                                        \
354             no_data = EAI_AGAIN;                                        \
355         else                                                            \
356             no_data = herrno == NO_DATA;                                \
357     }                                                                   \
358     else if (h != NULL)                                                 \
359     {                                                                   \
360         for (i = 0; h->h_addr_list[i]; i++)                             \
361         {                                                               \
362             if (*pat == NULL) {                                         \
363                 *pat = alloca (sizeof(struct gaih_addrtuple));          \
364                     (*pat)->scopeid = 0;                                \
365             }                                                           \
366             (*pat)->next = NULL;                                        \
367                 (*pat)->family = _family;                               \
368                 memcpy ((*pat)->addr, h->h_addr_list[i],                \
369                         sizeof(_type));                                 \
370                 pat = &((*pat)->next);                                  \
371         }                                                               \
372     }                                                                   \
373 }
374
375 static int
376 gaih_inet (const char *name, const struct gaih_service *service,
377            const struct addrinfo *req, struct addrinfo **pai)
378 {
379     const struct gaih_typeproto *tp = gaih_inet_typeproto;
380     struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
381     struct gaih_addrtuple *at = NULL;
382     int rc;
383     int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
384         (req->ai_flags & AI_V4MAPPED);
385
386     if (req->ai_protocol || req->ai_socktype)
387     {
388         ++tp;
389
390         while (tp->name[0]
391                && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
392                    || (req->ai_protocol != 0
393                        && !(tp->protoflag & GAI_PROTO_PROTOANY)
394                        && req->ai_protocol != tp->protocol)))
395             ++tp;
396
397         if (! tp->name[0])
398         {
399             if (req->ai_socktype)
400                 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
401             else
402                 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
403         }
404     }
405
406     if (service != NULL)
407     {
408         if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
409             return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
410
411         if (service->num < 0)
412         {
413             if (tp->name[0])
414             {
415                 st = (struct gaih_servtuple *)
416                     alloca (sizeof (struct gaih_servtuple));
417
418                 if ((rc = gaih_inet_serv (service->name, tp, req, st)))
419                     return rc;
420             }
421             else
422             {
423                 struct gaih_servtuple **pst = &st;
424                 for (tp++; tp->name[0]; tp++)
425                 {
426                     struct gaih_servtuple *newp;
427
428                     if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
429                         continue;
430
431                     if (req->ai_socktype != 0
432                         && req->ai_socktype != tp->socktype)
433                         continue;
434                     if (req->ai_protocol != 0
435                         && !(tp->protoflag & GAI_PROTO_PROTOANY)
436                         && req->ai_protocol != tp->protocol)
437                         continue;
438
439                     newp = (struct gaih_servtuple *)
440                         alloca (sizeof (struct gaih_servtuple));
441
442                     if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
443                     {
444                         if (rc & GAIH_OKIFUNSPEC)
445                             continue;
446                         return rc;
447                     }
448
449                     *pst = newp;
450                     pst = &(newp->next);
451                 }
452                 if (st == (struct gaih_servtuple *) &nullserv)
453                     return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
454             }
455         }
456         else
457         {
458             st = alloca (sizeof (struct gaih_servtuple));
459             st->next = NULL;
460             st->socktype = tp->socktype;
461             st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
462                             ? req->ai_protocol : tp->protocol);
463             st->port = htons (service->num);
464         }
465     }
466     else if (req->ai_socktype || req->ai_protocol)
467     {
468         st = alloca (sizeof (struct gaih_servtuple));
469         st->next = NULL;
470         st->socktype = tp->socktype;
471         st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
472                         ? req->ai_protocol : tp->protocol);
473         st->port = 0;
474     }
475     else
476     {
477         /* 
478          * Neither socket type nor protocol is set.  Return all socket types
479          * we know about.
480          */
481         struct gaih_servtuple **lastp = &st;
482         for (++tp; tp->name[0]; ++tp)
483         {
484             struct gaih_servtuple *newp;
485
486             newp = alloca (sizeof (struct gaih_servtuple));
487             newp->next = NULL;
488             newp->socktype = tp->socktype;
489             newp->protocol = tp->protocol;
490             newp->port = 0;
491
492             *lastp = newp;
493             lastp = &newp->next;
494         }
495     }
496
497     if (name != NULL)
498     {
499         at = alloca (sizeof (struct gaih_addrtuple));
500
501         at->family = AF_UNSPEC;
502         at->scopeid = 0;
503         at->next = NULL;
504
505         if (inet_pton (AF_INET, name, at->addr) > 0)
506         {
507             if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
508                 at->family = AF_INET;
509             else
510                 return -EAI_FAMILY;
511         }
512
513 #if __UCLIBC_HAS_IPV6__
514         if (at->family == AF_UNSPEC)
515         {
516             char *namebuf = strdupa (name);
517             char *scope_delim;
518
519             scope_delim = strchr (namebuf, SCOPE_DELIMITER);
520             if (scope_delim != NULL)
521                 *scope_delim = '\0';
522
523             if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
524             {
525                 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
526                     at->family = AF_INET6;
527                 else
528                     return -EAI_FAMILY;
529
530                 if (scope_delim != NULL)
531                 {
532                     int try_numericscope = 0;
533                     if (IN6_IS_ADDR_LINKLOCAL (at->addr)
534                         || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
535                     {
536                         at->scopeid = if_nametoindex (scope_delim + 1);
537                         if (at->scopeid == 0)
538                             try_numericscope = 1;
539                     }
540                     else
541                         try_numericscope = 1;
542
543                     if (try_numericscope != 0)
544                     {
545                         char *end;
546                         assert (sizeof (uint32_t) <= sizeof (unsigned long));
547                         at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
548                                                           10);
549                         if (*end != '\0')
550                             return GAIH_OKIFUNSPEC | -EAI_NONAME;
551                     }
552                 }
553             }
554         }
555 #endif
556
557         if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
558         {
559             struct hostent *h;
560             struct gaih_addrtuple **pat = &at;
561             int no_data = 0;
562             int no_inet6_data;
563
564             /*
565              * If we are looking for both IPv4 and IPv6 address we don't want
566              * the lookup functions to automatically promote IPv4 addresses to
567              * IPv6 addresses.
568              */
569
570 #if __UCLIBC_HAS_IPV6__
571             if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
572                 gethosts (AF_INET6, struct in6_addr);
573 #endif
574             no_inet6_data = no_data;
575
576             if (req->ai_family == AF_INET ||
577                 (!v4mapped && req->ai_family == AF_UNSPEC) ||
578                 (v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
579                 gethosts (AF_INET, struct in_addr);
580
581             if (no_data != 0 && no_inet6_data != 0)
582             {
583                 /* If both requests timed out report this. */
584                 if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
585                     return -EAI_AGAIN;
586
587                 /*
588                  * We made requests but they turned out no data.
589                  * The name is known, though.
590                  */
591                 return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
592             }
593         }
594
595         if (at->family == AF_UNSPEC)
596             return (GAIH_OKIFUNSPEC | -EAI_NONAME);
597     }
598     else
599     {
600         struct gaih_addrtuple *atr;
601         atr = at = alloca (sizeof (struct gaih_addrtuple));
602         memset (at, '\0', sizeof (struct gaih_addrtuple));
603
604         if (req->ai_family == 0)
605         {
606             at->next = alloca (sizeof (struct gaih_addrtuple));
607             memset (at->next, '\0', sizeof (struct gaih_addrtuple));
608         }
609
610 #if __UCLIBC_HAS_IPV6__
611         if (req->ai_family == 0 || req->ai_family == AF_INET6)
612         {
613             at->family = AF_INET6;
614             if ((req->ai_flags & AI_PASSIVE) == 0)
615                 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
616             atr = at->next;
617         }
618 #endif
619
620         if (req->ai_family == 0 || req->ai_family == AF_INET)
621         {
622             atr->family = AF_INET;
623             if ((req->ai_flags & AI_PASSIVE) == 0)
624                 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
625         }
626     }
627
628     if (pai == NULL)
629         return 0;
630
631     {
632         const char *c = NULL;
633         struct gaih_servtuple *st2;
634         struct gaih_addrtuple *at2 = at;
635         size_t socklen, namelen;
636         sa_family_t family;
637
638         /*
639          * buffer is the size of an unformatted IPv6 address in
640          * printable format.
641          */
642         char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
643
644         while (at2 != NULL)
645         {
646             if (req->ai_flags & AI_CANONNAME)
647             {
648                 struct hostent *h = NULL;
649
650                 int herrno;
651                 struct hostent th;
652                 size_t tmpbuflen = 512;
653                 char *tmpbuf;
654
655                 do
656                 {
657                     tmpbuflen *= 2;
658                     tmpbuf = alloca (tmpbuflen);
659
660                     if (tmpbuf == NULL)
661                         return -EAI_MEMORY;
662
663                     rc = gethostbyaddr_r (at2->addr,
664                                           ((at2->family == AF_INET6)
665                                            ? sizeof(struct in6_addr)
666                                            : sizeof(struct in_addr)),
667                                           at2->family, &th, tmpbuf, tmpbuflen,
668                                           &h, &herrno);
669
670                 }
671                 while (rc == errno && herrno == NETDB_INTERNAL);
672
673                 if (rc != 0 && herrno == NETDB_INTERNAL)
674                 {
675                     __set_h_errno (herrno);
676                     return -EAI_SYSTEM;
677                 }
678
679                 if (h == NULL)
680                     c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
681                 else
682                     c = h->h_name;
683
684                 if (c == NULL)
685                     return GAIH_OKIFUNSPEC | -EAI_NONAME;
686
687                 namelen = strlen (c) + 1;
688             }
689             else
690                 namelen = 0;
691
692 #if __UCLIBC_HAS_IPV6__
693             if (at2->family == AF_INET6 || v4mapped)
694             {
695                 family = AF_INET6;
696                 socklen = sizeof (struct sockaddr_in6);
697             }
698             else
699 #endif
700             {
701                 family = AF_INET;
702                 socklen = sizeof (struct sockaddr_in);
703             }
704
705             for (st2 = st; st2 != NULL; st2 = st2->next)
706             {
707                 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
708                 if (*pai == NULL)
709                     return -EAI_MEMORY;
710
711                 (*pai)->ai_flags = req->ai_flags;
712                 (*pai)->ai_family = family;
713                 (*pai)->ai_socktype = st2->socktype;
714                 (*pai)->ai_protocol = st2->protocol;
715                 (*pai)->ai_addrlen = socklen;
716                 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
717 #if SALEN
718                 (*pai)->ai_addr->sa_len = socklen;
719 #endif /* SALEN */
720                 (*pai)->ai_addr->sa_family = family;
721
722 #if __UCLIBC_HAS_IPV6__
723                 if (family == AF_INET6)
724                 {
725                     struct sockaddr_in6 *sin6p =
726                         (struct sockaddr_in6 *) (*pai)->ai_addr;
727
728                     sin6p->sin6_flowinfo = 0;
729                     if (at2->family == AF_INET6)
730                     {
731                         memcpy (&sin6p->sin6_addr,
732                                 at2->addr, sizeof (struct in6_addr));
733                     }
734                     else
735                     {
736                         sin6p->sin6_addr.s6_addr32[0] = 0;
737                         sin6p->sin6_addr.s6_addr32[1] = 0;
738                         sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
739                         memcpy(&sin6p->sin6_addr.s6_addr32[3], 
740                                at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
741                     }
742                     sin6p->sin6_port = st2->port;
743                     sin6p->sin6_scope_id = at2->scopeid;
744                 }
745                 else
746 #endif
747                 {
748                     struct sockaddr_in *sinp =
749                         (struct sockaddr_in *) (*pai)->ai_addr;
750
751                     memcpy (&sinp->sin_addr,
752                             at2->addr, sizeof (struct in_addr));
753                     sinp->sin_port = st2->port;
754                     memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
755                 }
756
757                 if (c)
758                 {
759                     (*pai)->ai_canonname = ((void *) (*pai) +
760                                             sizeof (struct addrinfo) + socklen);
761                     strcpy ((*pai)->ai_canonname, c);
762                 }
763                 else
764                     (*pai)->ai_canonname = NULL;
765
766                 (*pai)->ai_next = NULL;
767                 pai = &((*pai)->ai_next);
768             }
769
770             at2 = at2->next;
771         }
772     }
773     return 0;
774 }
775
776 static struct gaih gaih[] =
777 {
778 #if __UCLIBC_HAS_IPV6__
779     { PF_INET6, gaih_inet },
780 #endif
781     { PF_INET, gaih_inet },
782 #if 0
783     { PF_LOCAL, gaih_local },
784 #endif
785     { PF_UNSPEC, NULL }
786 };
787
788 void
789 freeaddrinfo (struct addrinfo *ai)
790 {
791     struct addrinfo *p;
792
793     while (ai != NULL)
794     {
795         p = ai;
796         ai = ai->ai_next;
797         free (p);
798     }
799 }
800 libc_hidden_proto(freeaddrinfo)
801 libc_hidden_def(freeaddrinfo)
802
803 int
804 getaddrinfo (const char *name, const char *service,
805              const struct addrinfo *hints, struct addrinfo **pai)
806 {
807     int i = 0, j = 0, last_i = 0;
808     struct addrinfo *p = NULL, **end;
809     struct gaih *g = gaih, *pg = NULL;
810     struct gaih_service gaih_service, *pservice;
811
812     if (name != NULL && name[0] == '*' && name[1] == 0)
813         name = NULL;
814
815     if (service != NULL && service[0] == '*' && service[1] == 0)
816         service = NULL;
817
818     if (name == NULL && service == NULL)
819         return EAI_NONAME;
820
821     if (hints == NULL)
822         hints = &default_hints;
823
824     if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
825                             AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
826         return EAI_BADFLAGS;
827
828     if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
829         return EAI_BADFLAGS;
830
831     if (service && service[0])
832     {
833         char *c;
834         gaih_service.name = service;
835         gaih_service.num = strtoul (gaih_service.name, &c, 10);
836         if (*c)
837             gaih_service.num = -1;
838         else
839             /*
840              * Can't specify a numerical socket unless a protocol
841              * family was given.
842              */
843             if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
844                 return EAI_SERVICE;
845         pservice = &gaih_service;
846     }
847     else
848         pservice = NULL;
849
850     if (pai)
851         end = &p;
852     else
853         end = NULL;
854
855     while (g->gaih)
856     {
857         if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
858         {
859             if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
860                 continue;
861             j++;
862             if (pg == NULL || pg->gaih != g->gaih)
863             {
864                 pg = g;
865                 i = g->gaih (name, pservice, hints, end);
866                 if (i != 0)
867                 {
868                     last_i = i;
869
870                     if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
871                         continue;
872
873                     if (p)
874                         freeaddrinfo (p);
875
876                     return -(i & GAIH_EAI);
877                 }
878                 if (end)
879                     while(*end) end = &((*end)->ai_next);
880             }
881         }
882         ++g;
883     }
884
885     if (j == 0)
886         return EAI_FAMILY;
887
888     if (p)
889     {
890         *pai = p;
891         return 0;
892     }
893
894     if (pai == NULL && last_i == 0)
895         return 0;
896
897     if (p)
898         freeaddrinfo (p);
899
900     return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
901 }
902 libc_hidden_proto(getaddrinfo)
903 libc_hidden_def(getaddrinfo)