1 /* The Inner Net License, Version 2.00
3 The author(s) grant permission for redistribution and use in source and
4 binary forms, with or without modification, of the software and documentation
5 provided that the following conditions are met:
7 0. If you receive a version of the software that is specifically labelled
8 as not being for redistribution (check the version message and/or README),
9 you are not permitted to redistribute that version of the software in any
11 1. All terms of the all other applicable copyrights and licenses must be
13 2. Redistributions of source code must retain the authors' copyright
14 notice(s), this list of conditions, and the following disclaimer.
15 3. Redistributions in binary form must reproduce the authors' copyright
16 notice(s), this list of conditions, and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
18 4. All advertising materials mentioning features or use of this software
19 must display the following acknowledgement with the name(s) of the
20 authors as specified in the copyright notice(s) substituted where
23 This product includes software developed by <name(s)>, The Inner
24 Net, and other contributors.
26 5. Neither the name(s) of the author(s) nor the names of its contributors
27 may be used to endorse or promote products derived from this software
28 without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
37 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 If these license terms cause you a real problem, contact the author. */
43 /* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
45 /* getaddrinfo() v1.13 */
47 #include <sys/types.h>
50 #include <sys/socket.h>
53 #include <sys/utsname.h>
55 #include <netinet/in.h>
58 #include <arpa/inet.h>
60 #define GAIH_OKIFUNSPEC 0x0100
61 #define GAIH_EAI ~(GAIH_OKIFUNSPEC)
64 #define UNIX_PATH_MAX 108
75 struct gaih_servtuple *next;
81 static struct gaih_servtuple nullserv = { NULL, 0, 0, 0 };
85 struct gaih_addrtuple *next;
97 static struct gaih_typeproto gaih_inet_typeproto[] =
100 { SOCK_STREAM, IPPROTO_TCP, (char *) "tcp" },
101 { SOCK_DGRAM, IPPROTO_UDP, (char *) "udp" },
108 int (*gaih)(const char *name, const struct gaih_service *service,
109 const struct addrinfo *req, struct addrinfo **pai);
112 static struct addrinfo default_hints =
113 { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
117 gaih_local (const char *name, const struct gaih_service *service,
118 const struct addrinfo *req, struct addrinfo **pai)
120 struct utsname utsname;
122 if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
123 if (uname (&utsname))
128 if (strcmp(name, "localhost") &&
129 strcmp(name, "local") &&
130 strcmp(name, "unix") &&
131 strcmp(name, utsname.nodename))
132 return GAIH_OKIFUNSPEC | -EAI_NONAME;
135 if (req->ai_protocol || req->ai_socktype)
137 struct gaih_typeproto *tp = gaih_inet_typeproto;
139 for (tp++; tp->name &&
140 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
141 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
142 if (tp->name == NULL)
144 if (req->ai_socktype)
145 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
147 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
151 *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
152 + ((req->ai_flags & AI_CANONNAME)
153 ? (strlen(utsname.nodename) + 1): 0));
157 (*pai)->ai_next = NULL;
158 (*pai)->ai_flags = req->ai_flags;
159 (*pai)->ai_family = AF_LOCAL;
160 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
161 (*pai)->ai_protocol = req->ai_protocol;
162 (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
163 (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
166 ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
167 sizeof (struct sockaddr_un);
170 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
171 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
175 struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
177 if (strchr (service->name, '/') != NULL)
179 if (strlen (service->name) >= sizeof (sunp->sun_path))
180 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
182 strcpy (sunp->sun_path, service->name);
186 if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
187 sizeof (sunp->sun_path))
188 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
190 __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
195 if (tmpnam (((struct sockaddr_un *) (*pai)->ai_addr)->sun_path) == NULL)
199 if (req->ai_flags & AI_CANONNAME)
200 (*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
201 + sizeof (struct sockaddr_un),
204 (*pai)->ai_canonname = NULL;
209 gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp,
210 struct gaih_servtuple *st)
213 size_t tmpbuflen = 1024;
220 tmpbuf = __alloca (tmpbuflen);
222 r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
224 if (r != 0 || s == NULL)
229 return GAIH_OKIFUNSPEC | -EAI_SERVICE;
235 st->socktype = tp->socktype;
236 st->protocol = tp->protocol;
237 st->port = s->s_port;
242 #define gethosts(_family, _type) \
251 tmpbuf = __alloca (tmpbuflen); \
252 rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
253 tmpbuflen, &h, &herrno); \
254 } while (rc == ERANGE && herrno == NETDB_INTERNAL); \
255 if (rc != 0 && herrno == NETDB_INTERNAL) \
257 __set_h_errno (herrno); \
258 return -EAI_SYSTEM; \
262 for (i = 0; h->h_addr_list[i]; i++) \
265 *pat = __alloca (sizeof(struct gaih_addrtuple)); \
266 (*pat)->next = NULL; \
267 (*pat)->family = _family; \
268 memcpy ((*pat)->addr, h->h_addr_list[i], \
270 pat = &((*pat)->next); \
273 no_data = rc != 0 && herrno == NO_DATA; \
277 gaih_inet (const char *name, const struct gaih_service *service,
278 const struct addrinfo *req, struct addrinfo **pai)
280 struct gaih_typeproto *tp = gaih_inet_typeproto;
281 struct gaih_servtuple *st = &nullserv;
282 struct gaih_addrtuple *at = NULL;
285 if (req->ai_protocol || req->ai_socktype)
287 for (tp++; tp->name &&
288 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
289 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
290 if (tp->name == NULL)
292 if (req->ai_socktype)
293 return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
295 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
301 if (service->num < 0)
303 if (tp->name != NULL)
305 st = (struct gaih_servtuple *)
306 __alloca (sizeof (struct gaih_servtuple));
308 if ((rc = gaih_inet_serv (service->name, tp, st)))
313 struct gaih_servtuple **pst = &st;
314 for (tp++; tp->name; tp++)
316 struct gaih_servtuple *newp = (struct gaih_servtuple *)
317 __alloca (sizeof (struct gaih_servtuple));
319 if ((rc = gaih_inet_serv (service->name, tp, newp)))
321 if (rc & GAIH_OKIFUNSPEC)
330 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
335 st = __alloca (sizeof (struct gaih_servtuple));
337 st->socktype = tp->socktype;
338 st->protocol = tp->protocol;
339 st->port = htons (service->num);
345 at = __alloca (sizeof (struct gaih_addrtuple));
347 at->family = AF_UNSPEC;
350 if (inet_pton (AF_INET, name, at->addr) > 0)
352 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
353 at->family = AF_INET;
355 return -EAI_ADDRFAMILY;
358 if (at->family == AF_UNSPEC && inet_pton (AF_INET6, name, at->addr) > 0)
360 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
361 at->family = AF_INET6;
363 return -EAI_ADDRFAMILY;
366 if (at->family == AF_UNSPEC)
369 struct gaih_addrtuple **pat = &at;
372 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
373 gethosts (AF_INET6, struct in6_addr);
375 if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
376 gethosts (AF_INET, struct in_addr);
379 /* We made requests but they turned out no data. The name
381 return (GAIH_OKIFUNSPEC | -EAI_NODATA);
384 if (at->family == AF_UNSPEC)
385 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
389 struct gaih_addrtuple *atr;
390 atr = at = __alloca (sizeof (struct gaih_addrtuple));
391 memset (at, '\0', sizeof (struct gaih_addrtuple));
393 if (req->ai_family == 0)
395 at->next = __alloca (sizeof (struct gaih_addrtuple));
396 memset (at->next, '\0', sizeof (struct gaih_addrtuple));
399 if (req->ai_family == 0 || req->ai_family == AF_INET6)
401 at->family = AF_INET6;
402 if ((req->ai_flags & AI_PASSIVE) == 0)
403 memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
407 if (req->ai_family == 0 || req->ai_family == AF_INET)
409 atr->family = AF_INET;
410 if ((req->ai_flags & AI_PASSIVE) == 0)
411 *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
419 const char *c = NULL;
420 struct gaih_servtuple *st2;
421 struct gaih_addrtuple *at2 = at;
422 size_t socklen, namelen;
425 buffer is the size of an unformatted IPv6 address in printable format.
427 char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
431 if (req->ai_flags & AI_CANONNAME)
433 struct hostent *h = NULL;
437 size_t tmpbuflen = 512;
443 tmpbuf = __alloca (tmpbuflen);
448 rc = __gethostbyaddr_r (at2->addr,
449 ((at2->family == AF_INET6)
450 ? sizeof(struct in6_addr)
451 : sizeof(struct in_addr)),
452 at2->family, &th, tmpbuf, tmpbuflen,
456 while (rc == errno && herrno == NETDB_INTERNAL);
458 if (rc != 0 && herrno == NETDB_INTERNAL)
460 __set_h_errno (herrno);
465 c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
470 return GAIH_OKIFUNSPEC | -EAI_NONAME;
472 namelen = strlen (c) + 1;
477 if (at2->family == AF_INET6)
478 socklen = sizeof (struct sockaddr_in6);
480 socklen = sizeof (struct sockaddr_in);
482 for (st2 = st; st2 != NULL; st2 = st2->next)
484 *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
488 (*pai)->ai_flags = req->ai_flags;
489 (*pai)->ai_family = at2->family;
490 (*pai)->ai_socktype = st2->socktype;
491 (*pai)->ai_protocol = st2->protocol;
492 (*pai)->ai_addrlen = socklen;
493 (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
495 ((struct sockaddr_in *) (*pai)->ai_addr)->sin_len = i;
497 ((struct sockaddr_in *) (*pai)->ai_addr)->sin_family = at2->family;
498 ((struct sockaddr_in *) (*pai)->ai_addr)->sin_port = st2->port;
500 if (at2->family == AF_INET6)
502 struct sockaddr_in6 *sin6p =
503 (struct sockaddr_in6 *) (*pai)->ai_addr;
505 sin6p->sin6_flowinfo = 0;
506 memcpy (&sin6p->sin6_addr,
507 at2->addr, sizeof (struct in6_addr));
511 struct sockaddr_in *sinp =
512 (struct sockaddr_in *) (*pai)->ai_addr;
513 memcpy (&sinp->sin_addr,
514 at2->addr, sizeof (struct in_addr));
515 memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
520 (*pai)->ai_canonname = ((void *) (*pai) +
521 sizeof (struct addrinfo) + socklen);
522 strcpy ((*pai)->ai_canonname, c);
525 (*pai)->ai_canonname = NULL;
527 (*pai)->ai_next = NULL;
528 pai = &((*pai)->ai_next);
537 static struct gaih gaih[] =
539 { PF_INET6, gaih_inet },
540 { PF_INET, gaih_inet },
541 { PF_LOCAL, gaih_local },
546 getaddrinfo (const char *name, const char *service,
547 const struct addrinfo *hints, struct addrinfo **pai)
549 int i = 0, j = 0, last_i = 0;
550 struct addrinfo *p = NULL, **end;
551 struct gaih *g = gaih, *pg = NULL;
552 struct gaih_service gaih_service, *pservice;
554 if (name != NULL && name[0] == '*' && name[1] == 0)
557 if (service != NULL && service[0] == '*' && service[1] == 0)
560 if (name == NULL && service == NULL)
564 hints = &default_hints;
566 if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST))
569 if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
572 if (service && service[0])
575 gaih_service.name = service;
576 gaih_service.num = strtoul (gaih_service.name, &c, 10);
578 gaih_service.num = -1;
580 /* Can't specify a numerical socket unless a protocol family was
582 if (hints->ai_socktype == 0)
584 pservice = &gaih_service;
596 if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
599 if (pg == NULL || pg->gaih != g->gaih)
602 i = g->gaih (name, pservice, hints, end);
605 /* EAI_NODATA is a more specific result as it says that
606 we found a result but it is not usable. */
607 if (last_i != (GAIH_OKIFUNSPEC | -EAI_NODATA))
610 if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
616 return -(i & GAIH_EAI);
619 while(*end) end = &((*end)->ai_next);
634 if (pai == NULL && last_i == 0)
640 return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
644 freeaddrinfo (struct addrinfo *ai)