Move setting of ioready 'wait' earlier in call chain, to
[python/dscho.git] / Modules / getaddrinfo.c
blobdc6376fa2f3bdeb4c7561db680d90bee577dd240
1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked.
35 * - Return values. There are nonstandard return values defined and used
36 * in the source code. This is because RFC2133 is silent about which error
37 * code must be returned for which situation.
38 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag.
41 #if 0
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/sysctl.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <arpa/nameser.h>
49 #include <netdb.h>
50 #include <resolv.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <stddef.h>
54 #include <ctype.h>
55 #include <unistd.h>
57 #include "addrinfo.h"
58 #endif
60 #if defined(__KAME__) && defined(ENABLE_IPV6)
61 # define FAITH
62 #endif
64 #define SUCCESS 0
65 #define GAI_ANY 0
66 #define YES 1
67 #define NO 0
69 #ifdef FAITH
70 static int translate = NO;
71 static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT;
72 #endif
74 static const char in_addrany[] = { 0, 0, 0, 0 };
75 static const char in6_addrany[] = {
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
78 static const char in_loopback[] = { 127, 0, 0, 1 };
79 static const char in6_loopback[] = {
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
83 struct sockinet {
84 u_char si_len;
85 u_char si_family;
86 u_short si_port;
89 static struct gai_afd {
90 int a_af;
91 int a_addrlen;
92 int a_socklen;
93 int a_off;
94 const char *a_addrany;
95 const char *a_loopback;
96 } gai_afdl [] = {
97 #ifdef ENABLE_IPV6
98 #define N_INET6 0
99 {PF_INET6, sizeof(struct in6_addr),
100 sizeof(struct sockaddr_in6),
101 offsetof(struct sockaddr_in6, sin6_addr),
102 in6_addrany, in6_loopback},
103 #define N_INET 1
104 #else
105 #define N_INET 0
106 #endif
107 {PF_INET, sizeof(struct in_addr),
108 sizeof(struct sockaddr_in),
109 offsetof(struct sockaddr_in, sin_addr),
110 in_addrany, in_loopback},
111 {0, 0, 0, 0, NULL, NULL},
114 #ifdef ENABLE_IPV6
115 #define PTON_MAX 16
116 #else
117 #define PTON_MAX 4
118 #endif
120 #ifndef IN_MULTICAST
121 #define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U)
122 #endif
124 #ifndef IN_EXPERIMENTAL
125 #define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U)
126 #endif
128 #ifndef IN_LOOPBACKNET
129 #define IN_LOOPBACKNET 127
130 #endif
132 static int get_name Py_PROTO((const char *, struct gai_afd *,
133 struct addrinfo **, char *, struct addrinfo *,
134 int));
135 static int get_addr Py_PROTO((const char *, int, struct addrinfo **,
136 struct addrinfo *, int));
137 static int str_isnumber Py_PROTO((const char *));
139 static char *ai_errlist[] = {
140 "success.",
141 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
142 "temporary failure in name resolution.", /* EAI_AGAIN */
143 "invalid value for ai_flags.", /* EAI_BADFLAGS */
144 "non-recoverable failure in name resolution.", /* EAI_FAIL */
145 "ai_family not supported.", /* EAI_FAMILY */
146 "memory allocation failure.", /* EAI_MEMORY */
147 "no address associated with hostname.", /* EAI_NODATA */
148 "hostname nor servname provided, or not known.",/* EAI_NONAME */
149 "servname not supported for ai_socktype.", /* EAI_SERVICE */
150 "ai_socktype not supported.", /* EAI_SOCKTYPE */
151 "system error returned in errno.", /* EAI_SYSTEM */
152 "invalid value for hints.", /* EAI_BADHINTS */
153 "resolved protocol is unknown.", /* EAI_PROTOCOL */
154 "unknown error.", /* EAI_MAX */
157 #define GET_CANONNAME(ai, str) \
158 if (pai->ai_flags & AI_CANONNAME) {\
159 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
160 strcpy((ai)->ai_canonname, (str));\
161 } else {\
162 error = EAI_MEMORY;\
163 goto free;\
167 #ifdef HAVE_SOCKADDR_SA_LEN
168 #define GET_AI(ai, gai_afd, addr, port) {\
169 char *p;\
170 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
171 ((gai_afd)->a_socklen)))\
172 == NULL) goto free;\
173 memcpy(ai, pai, sizeof(struct addrinfo));\
174 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
175 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
176 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\
177 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
178 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
179 p = (char *)((ai)->ai_addr);\
180 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
182 #else
183 #define GET_AI(ai, gai_afd, addr, port) {\
184 char *p;\
185 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
186 ((gai_afd)->a_socklen)))\
187 == NULL) goto free;\
188 memcpy(ai, pai, sizeof(struct addrinfo));\
189 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
190 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\
191 (ai)->ai_addrlen = (gai_afd)->a_socklen;\
192 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\
193 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
194 p = (char *)((ai)->ai_addr);\
195 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\
197 #endif
199 #define ERR(err) { error = (err); goto bad; }
201 char *
202 gai_strerror(int ecode)
204 if (ecode < 0 || ecode > EAI_MAX)
205 ecode = EAI_MAX;
206 return ai_errlist[ecode];
209 void
210 freeaddrinfo(struct addrinfo *ai)
212 struct addrinfo *next;
214 do {
215 next = ai->ai_next;
216 if (ai->ai_canonname)
217 free(ai->ai_canonname);
218 /* no need to free(ai->ai_addr) */
219 free(ai);
220 } while ((ai = next) != NULL);
223 static int
224 str_isnumber(const char *p)
226 unsigned char *q = (unsigned char *)p;
227 while (*q) {
228 if (! isdigit(*q))
229 return NO;
230 q++;
232 return YES;
236 getaddrinfo(const char*hostname, const char*servname,
237 const struct addrinfo *hints, struct addrinfo **res)
239 struct addrinfo sentinel;
240 struct addrinfo *top = NULL;
241 struct addrinfo *cur;
242 int i, error = 0;
243 char pton[PTON_MAX];
244 struct addrinfo ai;
245 struct addrinfo *pai;
246 u_short port;
248 #ifdef FAITH
249 static int firsttime = 1;
251 if (firsttime) {
252 /* translator hack */
254 char *q = getenv("GAI");
255 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
256 translate = YES;
258 firsttime = 0;
260 #endif
262 /* initialize file static vars */
263 sentinel.ai_next = NULL;
264 cur = &sentinel;
265 pai = &ai;
266 pai->ai_flags = 0;
267 pai->ai_family = PF_UNSPEC;
268 pai->ai_socktype = GAI_ANY;
269 pai->ai_protocol = GAI_ANY;
270 pai->ai_addrlen = 0;
271 pai->ai_canonname = NULL;
272 pai->ai_addr = NULL;
273 pai->ai_next = NULL;
274 port = GAI_ANY;
276 if (hostname == NULL && servname == NULL)
277 return EAI_NONAME;
278 if (hints) {
279 /* error check for hints */
280 if (hints->ai_addrlen || hints->ai_canonname ||
281 hints->ai_addr || hints->ai_next)
282 ERR(EAI_BADHINTS); /* xxx */
283 if (hints->ai_flags & ~AI_MASK)
284 ERR(EAI_BADFLAGS);
285 switch (hints->ai_family) {
286 case PF_UNSPEC:
287 case PF_INET:
288 #ifdef ENABLE_IPV6
289 case PF_INET6:
290 #endif
291 break;
292 default:
293 ERR(EAI_FAMILY);
295 memcpy(pai, hints, sizeof(*pai));
296 switch (pai->ai_socktype) {
297 case GAI_ANY:
298 switch (pai->ai_protocol) {
299 case GAI_ANY:
300 break;
301 case IPPROTO_UDP:
302 pai->ai_socktype = SOCK_DGRAM;
303 break;
304 case IPPROTO_TCP:
305 pai->ai_socktype = SOCK_STREAM;
306 break;
307 default:
308 pai->ai_socktype = SOCK_RAW;
309 break;
311 break;
312 case SOCK_RAW:
313 break;
314 case SOCK_DGRAM:
315 if (pai->ai_protocol != IPPROTO_UDP &&
316 pai->ai_protocol != GAI_ANY)
317 ERR(EAI_BADHINTS); /*xxx*/
318 pai->ai_protocol = IPPROTO_UDP;
319 break;
320 case SOCK_STREAM:
321 if (pai->ai_protocol != IPPROTO_TCP &&
322 pai->ai_protocol != GAI_ANY)
323 ERR(EAI_BADHINTS); /*xxx*/
324 pai->ai_protocol = IPPROTO_TCP;
325 break;
326 default:
327 ERR(EAI_SOCKTYPE);
328 /* unreachable */
333 * service port
335 if (servname) {
336 if (str_isnumber(servname)) {
337 if (pai->ai_socktype == GAI_ANY) {
338 /* caller accept *GAI_ANY* socktype */
339 pai->ai_socktype = SOCK_DGRAM;
340 pai->ai_protocol = IPPROTO_UDP;
342 port = htons((u_short)atoi(servname));
343 } else {
344 struct servent *sp;
345 char *proto;
347 proto = NULL;
348 switch (pai->ai_socktype) {
349 case GAI_ANY:
350 proto = NULL;
351 break;
352 case SOCK_DGRAM:
353 proto = "udp";
354 break;
355 case SOCK_STREAM:
356 proto = "tcp";
357 break;
358 default:
359 fprintf(stderr, "panic!\n");
360 break;
362 if ((sp = getservbyname(servname, proto)) == NULL)
363 ERR(EAI_SERVICE);
364 port = sp->s_port;
365 if (pai->ai_socktype == GAI_ANY) {
366 if (strcmp(sp->s_proto, "udp") == 0) {
367 pai->ai_socktype = SOCK_DGRAM;
368 pai->ai_protocol = IPPROTO_UDP;
369 } else if (strcmp(sp->s_proto, "tcp") == 0) {
370 pai->ai_socktype = SOCK_STREAM;
371 pai->ai_protocol = IPPROTO_TCP;
372 } else
373 ERR(EAI_PROTOCOL); /*xxx*/
379 * hostname == NULL.
380 * passive socket -> anyaddr (0.0.0.0 or ::)
381 * non-passive socket -> localhost (127.0.0.1 or ::1)
383 if (hostname == NULL) {
384 struct gai_afd *gai_afd;
386 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) {
387 if (!(pai->ai_family == PF_UNSPEC
388 || pai->ai_family == gai_afd->a_af)) {
389 continue;
392 if (pai->ai_flags & AI_PASSIVE) {
393 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port);
394 /* xxx meaningless?
395 * GET_CANONNAME(cur->ai_next, "anyaddr");
397 } else {
398 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback,
399 port);
400 /* xxx meaningless?
401 * GET_CANONNAME(cur->ai_next, "localhost");
404 cur = cur->ai_next;
406 top = sentinel.ai_next;
407 if (top)
408 goto good;
409 else
410 ERR(EAI_FAMILY);
413 /* hostname as numeric name */
414 for (i = 0; gai_afdl[i].a_af; i++) {
415 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) {
416 u_long v4a;
417 #ifdef ENABLE_IPV6
418 u_char pfx;
419 #endif
421 switch (gai_afdl[i].a_af) {
422 case AF_INET:
423 v4a = ((struct in_addr *)pton)->s_addr;
424 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
425 pai->ai_flags &= ~AI_CANONNAME;
426 v4a >>= IN_CLASSA_NSHIFT;
427 if (v4a == 0 || v4a == IN_LOOPBACKNET)
428 pai->ai_flags &= ~AI_CANONNAME;
429 break;
430 #ifdef ENABLE_IPV6
431 case AF_INET6:
432 pfx = ((struct in6_addr *)pton)->s6_addr8[0];
433 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
434 pai->ai_flags &= ~AI_CANONNAME;
435 break;
436 #endif
439 if (pai->ai_family == gai_afdl[i].a_af ||
440 pai->ai_family == PF_UNSPEC) {
441 if (! (pai->ai_flags & AI_CANONNAME)) {
442 GET_AI(top, &gai_afdl[i], pton, port);
443 goto good;
446 * if AI_CANONNAME and if reverse lookup
447 * fail, return ai anyway to pacify
448 * calling application.
450 * XXX getaddrinfo() is a name->address
451 * translation function, and it looks strange
452 * that we do addr->name translation here.
454 get_name(pton, &gai_afdl[i], &top, pton, pai, port);
455 goto good;
456 } else
457 ERR(EAI_FAMILY); /*xxx*/
461 if (pai->ai_flags & AI_NUMERICHOST)
462 ERR(EAI_NONAME);
464 /* hostname as alphabetical name */
465 error = get_addr(hostname, pai->ai_family, &top, pai, port);
466 if (error == 0) {
467 if (top) {
468 good:
469 *res = top;
470 return SUCCESS;
471 } else
472 error = EAI_FAIL;
474 free:
475 if (top)
476 freeaddrinfo(top);
477 bad:
478 *res = NULL;
479 return error;
482 static int
483 get_name(addr, gai_afd, res, numaddr, pai, port0)
484 const char *addr;
485 struct gai_afd *gai_afd;
486 struct addrinfo **res;
487 char *numaddr;
488 struct addrinfo *pai;
489 int port0;
491 u_short port = port0 & 0xffff;
492 struct hostent *hp;
493 struct addrinfo *cur;
494 int error = 0;
495 #ifdef ENABLE_IPV6
496 int h_error;
497 #endif
499 #ifdef ENABLE_IPV6
500 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error);
501 #else
502 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET);
503 #endif
504 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
505 GET_AI(cur, gai_afd, hp->h_addr_list[0], port);
506 GET_CANONNAME(cur, hp->h_name);
507 } else
508 GET_AI(cur, gai_afd, numaddr, port);
510 #ifdef ENABLE_IPV6
511 if (hp)
512 freehostent(hp);
513 #endif
514 *res = cur;
515 return SUCCESS;
516 free:
517 if (cur)
518 freeaddrinfo(cur);
519 #ifdef ENABLE_IPV6
520 if (hp)
521 freehostent(hp);
522 #endif
523 /* bad: */
524 *res = NULL;
525 return error;
528 static int
529 get_addr(hostname, af, res, pai, port0)
530 const char *hostname;
531 int af;
532 struct addrinfo **res;
533 struct addrinfo *pai;
534 int port0;
536 u_short port = port0 & 0xffff;
537 struct addrinfo sentinel;
538 struct hostent *hp;
539 struct addrinfo *top, *cur;
540 struct gai_afd *gai_afd;
541 int i, error = 0, h_error;
542 char *ap;
544 top = NULL;
545 sentinel.ai_next = NULL;
546 cur = &sentinel;
547 #ifdef ENABLE_IPV6
548 if (af == AF_UNSPEC) {
549 hp = getipnodebyname(hostname, AF_INET6,
550 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
551 } else
552 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
553 #else
554 hp = gethostbyname(hostname);
555 h_error = h_errno;
556 #endif
557 if (hp == NULL) {
558 switch (h_error) {
559 case HOST_NOT_FOUND:
560 case NO_DATA:
561 error = EAI_NODATA;
562 break;
563 case TRY_AGAIN:
564 error = EAI_AGAIN;
565 break;
566 case NO_RECOVERY:
567 default:
568 error = EAI_FAIL;
569 break;
571 goto free;
574 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
575 (hp->h_addr_list[0] == NULL)) {
576 error = EAI_FAIL;
577 goto free;
580 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
581 switch (af) {
582 #ifdef ENABLE_IPV6
583 case AF_INET6:
584 gai_afd = &gai_afdl[N_INET6];
585 break;
586 #endif
587 #ifndef ENABLE_IPV6
588 default: /* AF_UNSPEC */
589 #endif
590 case AF_INET:
591 gai_afd = &gai_afdl[N_INET];
592 break;
593 #ifdef ENABLE_IPV6
594 default: /* AF_UNSPEC */
595 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
596 ap += sizeof(struct in6_addr) -
597 sizeof(struct in_addr);
598 gai_afd = &gai_afdl[N_INET];
599 } else
600 gai_afd = &gai_afdl[N_INET6];
601 break;
602 #endif
604 #ifdef FAITH
605 if (translate && gai_afd->a_af == AF_INET) {
606 struct in6_addr *in6;
608 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port);
609 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
610 memcpy(&in6->s6_addr32[0], &faith_prefix,
611 sizeof(struct in6_addr) - sizeof(struct in_addr));
612 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
613 } else
614 #endif /* FAITH */
615 GET_AI(cur->ai_next, gai_afd, ap, port);
616 if (cur == &sentinel) {
617 top = cur->ai_next;
618 GET_CANONNAME(top, hp->h_name);
620 cur = cur->ai_next;
622 #ifdef ENABLE_IPV6
623 freehostent(hp);
624 #endif
625 *res = top;
626 return SUCCESS;
627 free:
628 if (top)
629 freeaddrinfo(top);
630 #ifdef ENABLE_IPV6
631 if (hp)
632 freehostent(hp);
633 #endif
634 /* bad: */
635 *res = NULL;
636 return error;