Libinfo-278.0.3.tar.gz
[apple/libinfo.git] / lookup.subproj / getaddrinfo.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <netdb.h>
26 #include <sys/types.h>
27 #include <stdint.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30 #include <net/if.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <ctype.h>
38 #include <rpc/types.h>
39 #include <rpc/xdr.h>
40 #include <mach/mach.h>
41 #include <servers/bootstrap.h>
42 #include <ifaddrs.h>
43 #include "lu_utils.h"
44 #include "netdb_async.h"
45
46 #define SOCK_UNSPEC 0
47 #define IPPROTO_UNSPEC 0
48
49 #define MAX_LOOKUP_ATTEMPTS 10
50
51 #define INET_NTOP_AF_INET_OFFSET 4
52 #define INET_NTOP_AF_INET6_OFFSET 8
53
54 static int gai_proc = -1;
55 static int gni_proc = -1;
56
57 static const int32_t supported_family[] =
58 {
59 PF_UNSPEC,
60 PF_INET,
61 PF_INET6
62 };
63 static const int32_t supported_family_count = (sizeof(supported_family) / sizeof(supported_family[0]));
64
65 static const int32_t supported_socket[] =
66 {
67 SOCK_RAW,
68 SOCK_UNSPEC,
69 SOCK_DGRAM,
70 SOCK_STREAM
71 };
72 static const int32_t supported_socket_count = (sizeof(supported_socket) / sizeof(supported_socket[0]));
73
74 static const int32_t supported_protocol[] =
75 {
76 IPPROTO_UNSPEC,
77 IPPROTO_ICMP,
78 IPPROTO_ICMPV6,
79 IPPROTO_UDP,
80 IPPROTO_TCP
81 };
82 static const int32_t supported_protocol_count = (sizeof(supported_protocol) / sizeof(supported_protocol[0]));
83
84 static const int32_t supported_socket_protocol_pair[] =
85 {
86 SOCK_RAW, IPPROTO_UNSPEC,
87 SOCK_RAW, IPPROTO_UDP,
88 SOCK_RAW, IPPROTO_TCP,
89 SOCK_RAW, IPPROTO_ICMP,
90 SOCK_RAW, IPPROTO_ICMPV6,
91 SOCK_UNSPEC, IPPROTO_UNSPEC,
92 SOCK_UNSPEC, IPPROTO_UDP,
93 SOCK_UNSPEC, IPPROTO_TCP,
94 SOCK_UNSPEC, IPPROTO_ICMP,
95 SOCK_UNSPEC, IPPROTO_ICMPV6,
96 SOCK_DGRAM, IPPROTO_UNSPEC,
97 SOCK_DGRAM, IPPROTO_UDP,
98 SOCK_STREAM, IPPROTO_UNSPEC,
99 SOCK_STREAM, IPPROTO_TCP
100 };
101 static const int32_t supported_socket_protocol_pair_count = (sizeof(supported_socket_protocol_pair) / (sizeof(supported_socket_protocol_pair[0]) * 2));
102
103 static int
104 gai_family_type_check(int32_t f)
105 {
106 int32_t i;
107
108 for (i = 0; i < supported_family_count; i++)
109 {
110 if (f == supported_family[i]) return 0;
111 }
112
113 return 1;
114 }
115
116 static int
117 gai_socket_type_check(int32_t s)
118 {
119 int32_t i;
120
121 for (i = 0; i < supported_socket_count; i++)
122 {
123 if (s == supported_socket[i]) return 0;
124 }
125
126 return 1;
127 }
128
129 static int
130 gai_protocol_type_check(int32_t p)
131 {
132 int32_t i;
133
134 for (i = 0; i < supported_protocol_count; i++)
135 {
136 if (p == supported_protocol[i]) return 0;
137 }
138
139 return 1;
140 }
141
142 static int
143 gai_socket_protocol_type_check(int32_t s, int32_t p)
144 {
145 int32_t i, j, ss, sp;
146
147 for (i = 0, j = 0; i < supported_socket_protocol_pair_count; i++, j+=2)
148 {
149 ss = supported_socket_protocol_pair[j];
150 sp = supported_socket_protocol_pair[j+1];
151 if ((s == ss) && (p == sp)) return 0;
152 }
153
154 return 1;
155 }
156
157 const char *
158 gai_strerror(int32_t err)
159 {
160 switch (err)
161 {
162 case EAI_ADDRFAMILY: return "Address family for nodename not supported";
163 case EAI_AGAIN: return "Temporary failure in name resolution";
164 case EAI_BADFLAGS: return "Invalid value for ai_flags";
165 case EAI_FAIL: return "Non-recoverable failure in name resolution";
166 case EAI_FAMILY: return "ai_family not supported";
167 case EAI_MEMORY: return "Memory allocation failure";
168 case EAI_NODATA: return "No address associated with nodename";
169 case EAI_NONAME: return "nodename nor servname provided, or not known";
170 case EAI_SERVICE: return "servname not supported for ai_socktype";
171 case EAI_SOCKTYPE: return "ai_socktype not supported";
172 case EAI_SYSTEM: return "System error";
173 case EAI_BADHINTS: return "Bad hints";
174 case EAI_PROTOCOL: return "ai_protocol not supported";
175 }
176
177 return "Unknown error";
178 }
179
180 static void
181 append_addrinfo(struct addrinfo **l, struct addrinfo *a)
182 {
183 struct addrinfo *x;
184
185 if (l == NULL) return;
186 if (a == NULL) return;
187
188 if (*l == NULL)
189 {
190 *l = a;
191 return;
192 }
193
194 x = *l;
195
196 if (a->ai_family == PF_INET6)
197 {
198 if (x->ai_family == PF_INET)
199 {
200 *l = a;
201 a->ai_next = x;
202 return;
203 }
204
205 while ((x->ai_next != NULL) && (x->ai_next->ai_family != PF_INET)) x = x->ai_next;
206 a->ai_next = x->ai_next;
207 x->ai_next = a;
208 }
209 else
210 {
211 while (x->ai_next != NULL) x = x->ai_next;
212 a->ai_next = NULL;
213 x->ai_next = a;
214 }
215 }
216
217 void
218 freeaddrinfo(struct addrinfo *a)
219 {
220 struct addrinfo *next;
221
222 while (a != NULL)
223 {
224 next = a->ai_next;
225 if (a->ai_addr != NULL) free(a->ai_addr);
226 if (a->ai_canonname != NULL) free(a->ai_canonname);
227 free(a);
228 a = next;
229 }
230 }
231
232 static struct addrinfo *
233 new_addrinfo_v4(int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in_addr addr, uint32_t iface, const char *cname)
234 {
235 struct addrinfo *a;
236 struct sockaddr_in *sa;
237 int32_t len;
238
239 a = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
240 if (a == NULL) return NULL;
241
242 a->ai_next = NULL;
243
244 a->ai_flags = flags;
245 a->ai_family = PF_INET;
246 a->ai_socktype = sock;
247 a->ai_protocol = proto;
248
249 a->ai_addrlen = sizeof(struct sockaddr_in);
250
251 sa = (struct sockaddr_in *)calloc(1, a->ai_addrlen);
252 if (sa == NULL)
253 {
254 free(a);
255 return NULL;
256 }
257
258 sa->sin_len = a->ai_addrlen;
259 sa->sin_family = PF_INET;
260 sa->sin_port = htons(port);
261 sa->sin_addr = addr;
262
263 /* Kludge: Jam the interface number into sin_zero. */
264 memmove(sa->sin_zero, &iface, sizeof(uint32_t));
265
266 a->ai_addr = (struct sockaddr *)sa;
267
268 if (cname != NULL)
269 {
270 len = strlen(cname) + 1;
271 a->ai_canonname = malloc(len);
272 memmove(a->ai_canonname, cname, len);
273 }
274
275 return a;
276 }
277
278 static struct addrinfo *
279 new_addrinfo_v6(int32_t flags, int32_t sock, int32_t proto, uint16_t port, struct in6_addr addr, uint16_t scopeid, const char *cname)
280 {
281 struct addrinfo *a;
282 struct sockaddr_in6 *sa;
283 int32_t len;
284 uint16_t esid;
285
286 a = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
287 if (a == NULL) return NULL;
288
289 a->ai_next = NULL;
290
291 a->ai_flags = flags;
292 a->ai_family = PF_INET6;
293 a->ai_socktype = sock;
294 a->ai_protocol = proto;
295
296 a->ai_addrlen = sizeof(struct sockaddr_in6);
297
298 sa = (struct sockaddr_in6 *)calloc(1, a->ai_addrlen);
299 if (sa == NULL)
300 {
301 free(a);
302 return NULL;
303 }
304
305 sa->sin6_len = a->ai_addrlen;
306 sa->sin6_family = PF_INET6;
307 sa->sin6_port = htons(port);
308 sa->sin6_addr = addr;
309
310 /* sin6_scope_id is in host byte order */
311 sa->sin6_scope_id = scopeid;
312
313 a->ai_addr = (struct sockaddr *)sa;
314
315 if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
316 {
317 /* check for embedded scopeid */
318 esid = ntohs(sa->sin6_addr.__u6_addr.__u6_addr16[1]);
319 if (esid != 0)
320 {
321 sa->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
322 if (scopeid == 0) sa->sin6_scope_id = esid;
323 }
324 }
325
326 if (cname != NULL)
327 {
328 len = strlen(cname) + 1;
329 a->ai_canonname = malloc(len);
330 memmove(a->ai_canonname, cname, len);
331 }
332
333 return a;
334 }
335
336 /*
337 * getaddrinfo
338 *
339 * Input dict may contain the following
340 *
341 * name: nodename
342 * service: servname
343 * protocol: [IPPROTO_UNSPEC] | IPPROTO_UDP | IPPROTO_TCP
344 * socktype: [SOCK_UNSPEC] | SOCK_DGRAM | SOCK_STREAM
345 * family: [PF_UNSPEC] | PF_INET | PF_INET6
346 * canonname: [0] | 1
347 * passive: [0] | 1
348 * numerichost: [0] | 1
349 *
350 * Output dictionary may contain the following
351 * All values are encoded as strings.
352 *
353 * flags: unsigned long
354 * family: unsigned long
355 * socktype: unsigned long
356 * protocol: unsigned long
357 * port: unsigned long
358 * address: char *
359 * scopeid: unsigned long
360 * canonname: char *
361 *
362 */
363
364 static struct addrinfo *
365 gai_extract(kvarray_t *in)
366 {
367 uint32_t d, k, kcount;
368 uint32_t flags, family, socktype, protocol, port32;
369 uint16_t port, scopeid;
370 const char *addr, *canonname;
371 struct addrinfo *a;
372 struct in_addr a4;
373 struct in6_addr a6;
374
375 flags = 0;
376 family = PF_UNSPEC;
377 socktype = SOCK_UNSPEC;
378 protocol = IPPROTO_UNSPEC;
379 port = 0;
380 scopeid = 0;
381 addr = NULL;
382 canonname = NULL;
383
384 if (in == NULL) return NULL;
385
386 d = in->curr;
387 in->curr++;
388
389 if (d >= in->count) return NULL;
390
391 kcount = in->dict[d].kcount;
392
393 for (k = 0; k < kcount; k++)
394 {
395 if (!strcmp(in->dict[d].key[k], "gai_flags"))
396 {
397 if (in->dict[d].vcount[k] == 0) continue;
398 flags = atoi(in->dict[d].val[k][0]);
399 }
400 else if (!strcmp(in->dict[d].key[k], "gai_family"))
401 {
402 if (in->dict[d].vcount[k] == 0) continue;
403 family = atoi(in->dict[d].val[k][0]);
404 }
405 else if (!strcmp(in->dict[d].key[k], "gai_socktype"))
406 {
407 if (in->dict[d].vcount[k] == 0) continue;
408 socktype = atoi(in->dict[d].val[k][0]);
409 }
410 else if (!strcmp(in->dict[d].key[k], "gai_protocol"))
411 {
412 if (in->dict[d].vcount[k] == 0) continue;
413 protocol = atoi(in->dict[d].val[k][0]);
414 }
415 else if (!strcmp(in->dict[d].key[k], "gai_port"))
416 {
417 if (in->dict[d].vcount[k] == 0) continue;
418 port32 = atoi(in->dict[d].val[k][0]);
419 port = port32;
420 }
421 else if (!strcmp(in->dict[d].key[k], "gai_scopeid"))
422 {
423 if (in->dict[d].vcount[k] == 0) continue;
424 scopeid = atoi(in->dict[d].val[k][0]);
425 }
426 else if (!strcmp(in->dict[d].key[k], "gai_address"))
427 {
428 if (in->dict[d].vcount[k] == 0) continue;
429 addr = in->dict[d].val[k][0];
430 }
431 else if (!strcmp(in->dict[d].key[k], "gai_canonname"))
432 {
433 if (in->dict[d].vcount[k] == 0) continue;
434 canonname = in->dict[d].val[k][0];
435 }
436 }
437
438 if (family == PF_UNSPEC) return NULL;
439
440 a = NULL;
441 if (family == PF_INET)
442 {
443 inet_aton(addr, &a4);
444 a = new_addrinfo_v4(flags, socktype, protocol, port, a4, scopeid, canonname);
445 }
446 else if (family == PF_INET6)
447 {
448 inet_pton(AF_INET6, addr, &a6);
449 a = new_addrinfo_v6(flags, socktype, protocol, port, a6, scopeid, canonname);
450 }
451
452 return a;
453 }
454
455 static kvbuf_t *
456 gai_make_query(const char *nodename, const char *servname, const struct addrinfo *hints)
457 {
458 int32_t flags, family, proto, socktype;
459 kvbuf_t *request;
460 char str[64], *cname;
461
462 /* new default for SULeoDeo */
463 flags = AI_PARALLEL;
464 family = PF_UNSPEC;
465 proto = IPPROTO_UNSPEC;
466 socktype = SOCK_UNSPEC;
467 cname = NULL;
468
469 if (hints != NULL)
470 {
471 family = hints->ai_family;
472 if (hints->ai_flags & AI_NUMERICHOST) flags |= AI_NUMERICHOST;
473 if (hints->ai_flags & AI_CANONNAME) flags |= AI_CANONNAME;
474 if (hints->ai_flags & AI_PASSIVE) flags |= AI_PASSIVE;
475
476 proto = hints->ai_protocol;
477
478 if (hints->ai_socktype == SOCK_DGRAM)
479 {
480 socktype = SOCK_DGRAM;
481 proto = IPPROTO_UDP;
482 }
483
484 if (hints->ai_socktype == SOCK_STREAM)
485 {
486 socktype = SOCK_STREAM;
487 proto = IPPROTO_TCP;
488 }
489 }
490
491 request = kvbuf_new();
492 if (request == NULL)
493 {
494 errno = ENOMEM;
495 return NULL;
496 }
497
498 kvbuf_add_dict(request);
499
500 if (nodename != NULL)
501 {
502 kvbuf_add_key(request, "name");
503 kvbuf_add_val(request, nodename);
504 }
505
506 if (servname != NULL)
507 {
508 kvbuf_add_key(request, "service");
509 kvbuf_add_val(request, servname);
510 }
511
512 if (proto != IPPROTO_UNSPEC)
513 {
514 snprintf(str, sizeof(str), "%u", proto);
515 kvbuf_add_key(request, "protocol");
516 kvbuf_add_val(request, str);
517 }
518
519 if (socktype != SOCK_UNSPEC)
520 {
521 snprintf(str, sizeof(str), "%u", socktype);
522 kvbuf_add_key(request, "socktype");
523 kvbuf_add_val(request, str);
524 }
525
526 if (family != PF_UNSPEC)
527 {
528 snprintf(str, sizeof(str), "%u", family);
529 kvbuf_add_key(request, "family");
530 kvbuf_add_val(request, str);
531 }
532
533 snprintf(str, sizeof(str), "%u", flags);
534 kvbuf_add_key(request, "ai_flags");
535 kvbuf_add_val(request, str);
536
537 return request;
538 }
539
540 static int32_t
541 is_a_number(const char *s)
542 {
543 int32_t i, len;
544
545 if (s == NULL) return 0;
546
547 len = strlen(s);
548 for (i = 0; i < len; i++)
549 {
550 if (isdigit(s[i]) == 0) return 0;
551 }
552
553 return 1;
554 }
555
556 static int
557 gai_trivial(struct in_addr *in4, struct in6_addr *in6, int16_t port, const struct addrinfo *hints, struct addrinfo **res)
558 {
559 int32_t family, wantv4, wantv6, proto;
560 char *loopv4, *loopv6;
561 struct in_addr a4;
562 struct in6_addr a6;
563 struct addrinfo *a;
564
565 family = PF_UNSPEC;
566 if (hints != NULL) family = hints->ai_family;
567
568 wantv4 = 1;
569 wantv6 = 1;
570
571 if (family == PF_INET6) wantv4 = 0;
572 if (family == PF_INET) wantv6 = 0;
573
574 memset(&a4, 0, sizeof(struct in_addr));
575 memset(&a6, 0, sizeof(struct in6_addr));
576
577 if ((in4 == NULL) && (in6 == NULL))
578 {
579 loopv4 = "127.0.0.1";
580 loopv6 = "0:0:0:0:0:0:0:1";
581
582 if ((hints != NULL) && ((hints->ai_flags & AI_PASSIVE) == 1))
583 {
584 loopv4 = "0.0.0.0";
585 loopv6 = "0:0:0:0:0:0:0:0";
586 }
587
588 if ((family == PF_UNSPEC) || (family == PF_INET))
589 {
590 inet_pton(AF_INET, loopv4, &a4);
591 }
592
593 if ((family == PF_UNSPEC) || (family == PF_INET6))
594 {
595 inet_pton(AF_INET6, loopv6, &a6);
596 }
597 }
598 else if (in4 == NULL)
599 {
600 if (family == PF_INET) return EAI_BADHINTS;
601
602 wantv4 = 0;
603 memcpy(&a6, in6, sizeof(struct in6_addr));
604 }
605 else if (in6 == NULL)
606 {
607 if (family == PF_INET6) return EAI_BADHINTS;
608
609 wantv6 = 0;
610 memcpy(&a4, in4, sizeof(struct in_addr));
611 }
612 else
613 {
614 return EAI_NONAME;
615 }
616
617 proto = IPPROTO_UNSPEC;
618
619 if (hints != NULL)
620 {
621 proto = hints->ai_protocol;
622 if (proto == IPPROTO_UNSPEC)
623 {
624 if (hints->ai_socktype == SOCK_DGRAM) proto = IPPROTO_UDP;
625 else if (hints->ai_socktype == SOCK_STREAM) proto = IPPROTO_TCP;
626 }
627 }
628
629 if (wantv4 == 1)
630 {
631 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
632 {
633 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
634 append_addrinfo(res, a);
635 }
636
637 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
638 {
639 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
640 append_addrinfo(res, a);
641 }
642
643 if (proto == IPPROTO_ICMP)
644 {
645 a = new_addrinfo_v4(0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, NULL);
646 append_addrinfo(res, a);
647 }
648 }
649
650 if (wantv6 == 1)
651 {
652 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
653 {
654 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, 0, NULL);
655 append_addrinfo(res, a);
656 }
657
658 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
659 {
660 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, 0, NULL);
661 append_addrinfo(res, a);
662 }
663
664 if (proto == IPPROTO_ICMPV6)
665 {
666 a = new_addrinfo_v6(0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, 0, NULL);
667 append_addrinfo(res, a);
668 }
669 }
670
671 return 0;
672 }
673
674 static int
675 gai_files(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
676 {
677 int32_t i, status, numericserv, numerichost, family, proto, wantv4, wantv6, count;
678 uint16_t scopeid;
679 int16_t port;
680 struct servent *s;
681 struct hostent *h;
682 char *protoname, *loopv4, *loopv6;
683 struct in_addr a4;
684 struct in6_addr a6;
685 struct addrinfo *a;
686
687 count = 0;
688 scopeid = 0;
689
690 numericserv = 0;
691 if (servname != NULL) numericserv = is_a_number(servname);
692
693 family = PF_UNSPEC;
694 if (hints != NULL) family = hints->ai_family;
695
696 numerichost = 0;
697
698 if (nodename == NULL)
699 {
700 numerichost = 1;
701
702 loopv4 = "127.0.0.1";
703 loopv6 = "0:0:0:0:0:0:0:1";
704
705 if ((hints != NULL) && ((hints->ai_flags & AI_PASSIVE) == 1))
706 {
707 loopv4 = "0.0.0.0";
708 loopv6 = "0:0:0:0:0:0:0:0";
709 }
710
711 if ((family == PF_UNSPEC) || (family == PF_INET))
712 {
713 inet_pton(AF_INET, loopv4, &a4);
714 }
715
716 if ((family == PF_UNSPEC) || (family == PF_INET6))
717 {
718 inet_pton(AF_INET6, loopv6, &a6);
719 }
720 }
721 else
722 {
723 if ((family == PF_UNSPEC) || (family == PF_INET))
724 {
725 status = inet_pton(AF_INET, nodename, &a4);
726 if (status == 1)
727 {
728 numerichost = 1;
729 if (family == PF_UNSPEC) family = PF_INET;
730 }
731 }
732
733 if ((family == PF_UNSPEC) || (family == PF_INET6))
734 {
735 status = inet_pton(AF_INET6, nodename, &a6);
736 if (status == 1)
737 {
738 numerichost = 1;
739 if (family == PF_UNSPEC) family = PF_INET6;
740 if ((IN6_IS_ADDR_LINKLOCAL(&a6)) && (a6.__u6_addr.__u6_addr16[1] != 0))
741 {
742 scopeid = ntohs(a6.__u6_addr.__u6_addr16[1]);
743 a6.__u6_addr.__u6_addr16[1] = 0;
744 }
745 }
746 }
747 }
748
749 wantv4 = 1;
750 wantv6 = 1;
751 if (family == PF_INET6) wantv4 = 0;
752 if (family == PF_INET) wantv6 = 0;
753
754 proto = IPPROTO_UNSPEC;
755 protoname = NULL;
756
757 if (hints != NULL)
758 {
759 proto = hints->ai_protocol;
760 if (proto == IPPROTO_UNSPEC)
761 {
762 if (hints->ai_socktype == SOCK_DGRAM) proto = IPPROTO_UDP;
763 else if (hints->ai_socktype == SOCK_STREAM) proto = IPPROTO_TCP;
764 }
765 }
766
767 if (proto == IPPROTO_UDP) protoname = "udp";
768 else if (proto == IPPROTO_TCP) protoname = "tcp";
769
770 s = NULL;
771 port = 0;
772
773 if (numericserv != 0)
774 {
775 port = htons(atoi(servname));
776 }
777 else if (servname != NULL)
778 {
779 s = getservbyname(servname, protoname);
780 if (s != NULL) port = s->s_port;
781 }
782
783 /* new_addrinfo_v4 and new_addrinfo_v6 expect port in host byte order */
784 port = ntohs(port);
785
786 if (numerichost != 0)
787 {
788 if (wantv4 == 1)
789 {
790 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
791 {
792 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
793 append_addrinfo(res, a);
794 count++;
795 }
796
797 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
798 {
799 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
800 append_addrinfo(res, a);
801 count++;
802 }
803
804 if (proto == IPPROTO_ICMP)
805 {
806 a = new_addrinfo_v4(0, SOCK_RAW, IPPROTO_ICMP, port, a4, 0, NULL);
807 append_addrinfo(res, a);
808 count++;
809 }
810 }
811
812 if (wantv6 == 1)
813 {
814 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
815 {
816 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, scopeid, NULL);
817 append_addrinfo(res, a);
818 count++;
819 }
820
821 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
822 {
823 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, scopeid, NULL);
824 append_addrinfo(res, a);
825 count++;
826 }
827
828 if (proto == IPPROTO_ICMPV6)
829 {
830 a = new_addrinfo_v6(0, SOCK_RAW, IPPROTO_ICMPV6, port, a6, scopeid, NULL);
831 append_addrinfo(res, a);
832 count++;
833 }
834 }
835
836 if (count == 0) return EAI_AGAIN;
837 return 0;
838 }
839
840 if (wantv4 == 1)
841 {
842 h = gethostbyname(nodename);
843 if (h == NULL) return EAI_AGAIN;
844
845 for (i = 0; h->h_addr_list[i] != 0; i++)
846 {
847 memmove((void *)&a4.s_addr, h->h_addr_list[i], h->h_length);
848
849 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
850 {
851 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
852 append_addrinfo(res, a);
853 count++;
854 }
855
856 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
857 {
858 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
859 append_addrinfo(res, a);
860 count++;
861 }
862 }
863 }
864
865 if (wantv6 == 1)
866 {
867 h = gethostbyname2(nodename, AF_INET6);
868 if (h == NULL) return EAI_AGAIN;
869
870 for (i = 0; h->h_addr_list[i] != 0; i++)
871 {
872 memmove(&(a6.__u6_addr.__u6_addr32[0]), h->h_addr_list[i], h->h_length);
873
874 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
875 {
876 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, 0, NULL);
877 append_addrinfo(res, a);
878 count++;
879 }
880
881 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
882 {
883 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, 0, NULL);
884 append_addrinfo(res, a);
885 count++;
886 }
887 }
888 }
889
890 if (count == 0) return EAI_AGAIN;
891 return 0;
892 }
893
894 static int
895 ds_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
896 {
897 uint32_t i;
898 kvbuf_t *request;
899 kvarray_t *reply;
900 char *cname;
901 kern_return_t status;
902 struct addrinfo *a;
903
904 if (_ds_running() == 0)
905 {
906 return gai_files(nodename, servname, hints, res);
907 }
908
909 if (gai_proc < 0)
910 {
911 status = LI_DSLookupGetProcedureNumber("getaddrinfo", &gai_proc);
912 if (status != KERN_SUCCESS)
913 {
914 errno = ECONNREFUSED;
915 return EAI_SYSTEM;
916 }
917 }
918
919 request = gai_make_query(nodename, servname, hints);
920 if (request == NULL) return EAI_SYSTEM;
921
922 reply = NULL;
923 status = LI_DSLookupQuery(gai_proc, request, &reply);
924 kvbuf_free(request);
925
926 if (status != KERN_SUCCESS)
927 {
928 errno = ECONNREFUSED;
929 return EAI_SYSTEM;
930 }
931
932 if (reply == NULL) return EAI_NONAME;
933
934 cname = NULL;
935 for (i = 0; i < reply->count; i++)
936 {
937 a = gai_extract(reply);
938 if (a == NULL) continue;
939 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
940 append_addrinfo(res, a);
941 }
942
943 kvarray_free(reply);
944
945 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
946 {
947 res[0]->ai_canonname = strdup(cname);
948 }
949
950 return 0;
951 }
952
953 static int
954 gai_checkhints(const struct addrinfo *hints)
955 {
956 if (hints == NULL) return 0;
957 if (hints->ai_addrlen != 0) return EAI_BADHINTS;
958 if (hints->ai_canonname != NULL) return EAI_BADHINTS;
959 if (hints->ai_addr != NULL) return EAI_BADHINTS;
960 if (hints->ai_next != NULL) return EAI_BADHINTS;
961
962 /* Check for supported protocol family */
963 if (gai_family_type_check(hints->ai_family) != 0) return EAI_FAMILY;
964
965 /* Check for supported socket */
966 if (gai_socket_type_check(hints->ai_socktype) != 0) return EAI_BADHINTS;
967
968 /* Check for supported protocol */
969 if (gai_protocol_type_check(hints->ai_protocol) != 0) return EAI_BADHINTS;
970
971 /* Check that socket type is compatible with protocol */
972 if (gai_socket_protocol_type_check(hints->ai_socktype, hints->ai_protocol) != 0) return EAI_BADHINTS;
973
974 return 0;
975 }
976
977 int
978 getaddrinfo(const char * __restrict nodename, const char * __restrict servname, const struct addrinfo * __restrict hints, struct addrinfo ** __restrict res)
979 {
980 int32_t status, nodenull, servnull;
981 int32_t numericserv, numerichost, family;
982 int16_t port;
983 struct in_addr a4, *p4;
984 struct in6_addr a6, *p6;
985
986 if (res == NULL) return 0;
987 *res = NULL;
988
989 /* Check input */
990 nodenull = 0;
991 if ((nodename == NULL) || (nodename[0] == '\0')) nodenull = 1;
992
993 servnull = 0;
994 if ((servname == NULL) || (servname[0] == '\0')) servnull = 1;
995
996 if ((nodenull == 1) && (servnull == 1)) return EAI_NONAME;
997
998 status = gai_checkhints(hints);
999 if (status != 0) return status;
1000
1001 /*
1002 * Trap the "trivial" cases that can be answered without a query.
1003 * (nodename == numeric) && (servname == NULL)
1004 * (nodename == numeric) && (servname == numeric)
1005 * (nodename == NULL) && (servname == numeric)
1006 */
1007 p4 = NULL;
1008 p6 = NULL;
1009
1010 memset(&a4, 0, sizeof(struct in_addr));
1011 memset(&a6, 0, sizeof(struct in6_addr));
1012
1013 numericserv = 0;
1014 port = 0;
1015 if (servnull == 0) numericserv = is_a_number(servname);
1016 if (numericserv == 1) port = atoi(servname);
1017
1018 family = PF_UNSPEC;
1019 if (hints != NULL) family = hints->ai_family;
1020
1021 numerichost = 0;
1022 if (nodenull == 0)
1023 {
1024 if ((family == PF_UNSPEC) || (family == PF_INET))
1025 {
1026 status = inet_pton(AF_INET, nodename, &a4);
1027 if (status == 1)
1028 {
1029 p4 = &a4;
1030 numerichost = 1;
1031 }
1032 }
1033
1034 if ((family == PF_UNSPEC) || (family == PF_INET6))
1035 {
1036 status = inet_pton(AF_INET6, nodename, &a6);
1037 if (status == 1)
1038 {
1039 p6 = &a6;
1040 numerichost = 1;
1041 }
1042 }
1043 }
1044
1045 if ((nodenull == 1) && (numericserv == 1)) return gai_trivial(NULL, NULL, port, hints, res);
1046 if ((numerichost == 1) && (numericserv == 1)) return gai_trivial(p4, p6, port, hints, res);
1047 if ((numerichost == 1) && (servnull == 1)) return gai_trivial(p4, p6, 0, hints, res);
1048
1049 if (nodenull == 1) status = ds_getaddrinfo(NULL, servname, hints, res);
1050 else if (servnull == 1) status = ds_getaddrinfo(nodename, NULL, hints, res);
1051 else status = ds_getaddrinfo(nodename, servname, hints, res);
1052
1053 if ((status == 0) && (*res == NULL)) status = EAI_NONAME;
1054
1055 return status;
1056 }
1057
1058 int32_t
1059 getaddrinfo_async_start(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints, getaddrinfo_async_callback callback, void *context)
1060 {
1061 int32_t status;
1062 kvbuf_t *request;
1063
1064 *p = MACH_PORT_NULL;
1065
1066 if ((nodename == NULL) && (servname == NULL)) return EAI_NONAME;
1067
1068 status = gai_checkhints(hints);
1069 if (status != 0) return EAI_BADHINTS;
1070
1071 if (gai_proc < 0)
1072 {
1073 status = LI_DSLookupGetProcedureNumber("getaddrinfo", &gai_proc);
1074 if (status != KERN_SUCCESS)
1075 {
1076 errno = ECONNREFUSED;
1077 return EAI_SYSTEM;
1078 }
1079 }
1080
1081 request = gai_make_query(nodename, servname, hints);
1082 if (request == NULL) return EAI_SYSTEM;
1083
1084 status = LI_async_start(p, gai_proc, request, (void *)callback, context);
1085
1086 kvbuf_free(request);
1087
1088 if (status != KERN_SUCCESS)
1089 {
1090 errno = ECONNREFUSED;
1091 return EAI_SYSTEM;
1092 }
1093
1094 return 0;
1095 }
1096
1097 void
1098 getaddrinfo_async_cancel(mach_port_t p)
1099 {
1100 LI_async_call_cancel(p, NULL);
1101 }
1102
1103 int32_t
1104 getaddrinfo_async_send(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints)
1105 {
1106 return getaddrinfo_async_start(p, nodename, servname, hints, NULL, NULL);
1107 }
1108
1109 int32_t
1110 getaddrinfo_async_receive(mach_port_t p, struct addrinfo **res)
1111 {
1112 kern_return_t status;
1113 char *cname;
1114 kvarray_t *reply;
1115 uint32_t i;
1116 struct addrinfo *a;
1117
1118 if (res == NULL) return 0;
1119 *res = NULL;
1120
1121 reply = NULL;
1122
1123 status = LI_async_receive(p, &reply);
1124 if (status < 0) return EAI_FAIL;
1125 if (reply == NULL) return EAI_NONAME;
1126
1127 cname = NULL;
1128 for (i = 0; i < reply->count; i++)
1129 {
1130 a = gai_extract(reply);
1131 if (a == NULL) continue;
1132 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
1133 append_addrinfo(res, a);
1134 }
1135
1136 kvarray_free(reply);
1137
1138 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
1139 {
1140 res[0]->ai_canonname = strdup(cname);
1141 }
1142
1143
1144 if (*res == NULL) return EAI_NONAME;
1145
1146 return 0;
1147 }
1148
1149 int32_t
1150 getaddrinfo_async_handle_reply(void *msg)
1151 {
1152 getaddrinfo_async_callback callback;
1153 void *context;
1154 char *buf, *cname;
1155 uint32_t i, len;
1156 int status;
1157 kvarray_t *reply;
1158 struct addrinfo *l, *a, **res;
1159
1160 callback = (getaddrinfo_async_callback)NULL;
1161 context = NULL;
1162 buf = NULL;
1163 len = 0;
1164 reply = NULL;
1165 l = NULL;
1166 res = &l;
1167
1168 status = LI_async_handle_reply(msg, &reply, (void **)&callback, &context);
1169 if (status != KERN_SUCCESS)
1170 {
1171 if (status == MIG_REPLY_MISMATCH) return 0;
1172 if (callback != NULL) callback(EAI_FAIL, NULL, context);
1173 return EAI_FAIL;
1174 }
1175
1176 if (reply == NULL)
1177 {
1178 if (callback != NULL) callback(EAI_NONAME, NULL, context);
1179 return EAI_NONAME;
1180 }
1181
1182 cname = NULL;
1183 for (i = 0; i < reply->count; i++)
1184 {
1185 a = gai_extract(reply);
1186 if (a == NULL) continue;
1187 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
1188 append_addrinfo(res, a);
1189 }
1190
1191 kvarray_free(reply);
1192
1193 if ((cname != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
1194 {
1195 res[0]->ai_canonname = strdup(cname);
1196 }
1197
1198 if (*res == NULL)
1199 {
1200 callback(EAI_NONAME, NULL, context);
1201 return EAI_NONAME;
1202 }
1203
1204 callback(0, *res, context);
1205 return 0;
1206 }
1207
1208 /*
1209 * getnameinfo
1210 */
1211
1212 /*
1213 * getnameinfo support in Directory Service
1214 * Input dict may contain the following
1215 *
1216 * ip_address: node address
1217 * ipv6_address: node address
1218 * port: service number
1219 * protocol: [tcp] | udp
1220 * fqdn: [1] | 0
1221 * numerichost: [0] | 1
1222 * name_required: [0] | 1
1223 * numericserv: [0] | 1
1224 *
1225 * Output dictionary may contain the following
1226 * All values are encoded as strings.
1227 *
1228 * name: char *
1229 * service: char *
1230 */
1231
1232 static int
1233 gni_extract(kvarray_t *in, const char **host, const char **serv)
1234 {
1235 uint32_t d, k, kcount;
1236
1237 if (in == NULL) return -1;
1238
1239 if ((host == NULL) || (serv == NULL))
1240 {
1241 errno = EINVAL;
1242 return EAI_SYSTEM;
1243 }
1244
1245 *host = NULL;
1246 *serv = NULL;
1247
1248 d = in->curr;
1249 in->curr++;
1250
1251 if (d >= in->count) return EAI_NONAME;
1252
1253 kcount = in->dict[d].kcount;
1254 if (kcount == 0) return EAI_NONAME;
1255
1256 for (k = 0; k < kcount; k++)
1257 {
1258 if (!strcmp(in->dict[d].key[k], "gni_name"))
1259 {
1260 if (in->dict[d].vcount[k] == 0) continue;
1261 if (*host != NULL) continue;
1262
1263 *host = in->dict[d].val[k][0];
1264 }
1265 else if (!strcmp(in->dict[d].key[k], "gni_service"))
1266 {
1267 if (in->dict[d].vcount[k] == 0) continue;
1268 if (*serv != NULL) continue;
1269
1270 *serv = in->dict[d].val[k][0];
1271 }
1272 }
1273
1274 if ((*host == NULL) && (*serv == NULL)) return EAI_NONAME;
1275 return 0;
1276 }
1277
1278 static kvbuf_t *
1279 gni_make_query(const struct sockaddr *sa, size_t salen, int wanthost, int wantserv, int flags)
1280 {
1281 kvbuf_t *request;
1282 uint16_t port, ifnum;
1283 char str[NI_MAXHOST], ifname[IF_NAMESIZE], tmp[64];
1284 uint32_t a4, offset, isll;
1285 struct sockaddr_in6 *s6;
1286
1287 if (sa == NULL)
1288 {
1289 errno = EINVAL;
1290 return NULL;
1291 }
1292
1293 if (sa->sa_len != salen)
1294 {
1295 errno = EINVAL;
1296 return NULL;
1297 }
1298
1299 isll = 0;
1300
1301 offset = INET_NTOP_AF_INET_OFFSET;
1302 port = 0;
1303
1304 if (sa->sa_family == PF_INET)
1305 {
1306 a4 = ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
1307 if (IN_MULTICAST(a4) || IN_EXPERIMENTAL(a4)) flags |= NI_NUMERICHOST;
1308 a4 >>= IN_CLASSA_NSHIFT;
1309 if (a4 == 0) flags |= NI_NUMERICHOST;
1310
1311 port = ntohs(((struct sockaddr_in *)sa)->sin_port);
1312 }
1313 else if (sa->sa_family == PF_INET6)
1314 {
1315 s6 = (struct sockaddr_in6 *)sa;
1316 switch (s6->sin6_addr.s6_addr[0])
1317 {
1318 case 0x00:
1319 {
1320 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
1321 {
1322 }
1323 else if (IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr))
1324 {
1325 }
1326 else
1327 {
1328 flags |= NI_NUMERICHOST;
1329 }
1330 break;
1331 }
1332 default:
1333 {
1334 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
1335 {
1336 isll = 1;
1337 }
1338 else if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
1339 {
1340 flags |= NI_NUMERICHOST;
1341 }
1342 break;
1343 }
1344 }
1345
1346 if (isll != 0)
1347 {
1348 ifnum = ntohs(s6->sin6_addr.__u6_addr.__u6_addr16[1]);
1349 if (ifnum == 0) ifnum = s6->sin6_scope_id;
1350 else if ((s6->sin6_scope_id != 0) && (ifnum != s6->sin6_scope_id))
1351 {
1352 errno = EINVAL;
1353 return NULL;
1354 }
1355
1356 s6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1357 s6->sin6_scope_id = ifnum;
1358 if ((ifnum != 0) && (flags & NI_NUMERICHOST)) flags |= NI_WITHSCOPEID;
1359 }
1360
1361 offset = INET_NTOP_AF_INET6_OFFSET;
1362 port = ntohs(s6->sin6_port);
1363 }
1364 else
1365 {
1366 errno = EPFNOSUPPORT;
1367 return NULL;
1368 }
1369
1370 request = kvbuf_new();
1371 if (request == NULL)
1372 {
1373 errno = ENOMEM;
1374 return NULL;
1375 }
1376
1377 kvbuf_add_dict(request);
1378
1379 if (wanthost != 0)
1380 {
1381 inet_ntop(sa->sa_family, (char *)(sa) + offset, str, NI_MAXHOST);
1382
1383 if (isll != 0)
1384 {
1385 ifnum = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
1386 if ((ifnum != 0) && (if_indextoname(ifnum, ifname) != NULL))
1387 {
1388 strcat(str, "%");
1389 strcat(str, ifname);
1390 }
1391 }
1392
1393 kvbuf_add_key(request, "address");
1394 kvbuf_add_val(request, str);
1395
1396 kvbuf_add_key(request, "family");
1397 snprintf(tmp, sizeof(tmp), "%u", sa->sa_family);
1398 kvbuf_add_val(request, tmp);
1399 }
1400
1401 if (wantserv != 0)
1402 {
1403 snprintf(tmp, sizeof(tmp), "%hu", port);
1404 kvbuf_add_key(request, "port");
1405 kvbuf_add_val(request, tmp);
1406 }
1407
1408 snprintf(tmp, sizeof(tmp), "%u", flags);
1409 kvbuf_add_key(request, "flags");
1410 kvbuf_add_val(request, tmp);
1411
1412 return request;
1413 }
1414
1415 int
1416 getnameinfo(const struct sockaddr * __restrict sa, socklen_t salen, char * __restrict host, socklen_t hostlen, char * __restrict serv, socklen_t servlen, int flags)
1417 {
1418 uint32_t n, i, ifnum;
1419 int wanth, wants, isll;
1420 kvbuf_t *request;
1421 kvarray_t *reply;
1422 char ifname[IF_NAMESIZE];
1423 const char *hval, *sval;
1424 kern_return_t status;
1425 struct sockaddr_in *s4, s4buf;
1426 struct sockaddr_in6 *s6, s6buf;
1427 struct in_addr *a4;
1428 struct in6_addr *a6;
1429
1430 /* Check input */
1431 if (sa == NULL) return EAI_FAIL;
1432
1433 isll = 0;
1434 ifnum = 0;
1435
1436 s4 = &s4buf;
1437 a4 = NULL;
1438
1439 s6 = &s6buf;
1440 a6 = NULL;
1441
1442 if (sa->sa_family == AF_INET)
1443 {
1444 memcpy(s4, sa, sizeof(struct sockaddr_in));
1445 a4 = &(s4->sin_addr);
1446 }
1447 else if (sa->sa_family == AF_INET6)
1448 {
1449 memcpy(s6, sa, sizeof(struct sockaddr_in6));
1450 a6 = &(s6->sin6_addr);
1451
1452 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) isll = 1;
1453
1454 /*
1455 * Link-local IPv6 addresses may have a scope id
1456 * in s6->sin6_addr.__u6_addr.__u6_addr16[1] as well as in s6->sin6_scope_id.
1457 * If they are both non-zero, they must be equal.
1458 * We zero s6->sin6_addr.__u6_addr.__u6_addr16[1] and set s6->sin6_scope_id.
1459 */
1460 if (isll != 0)
1461 {
1462 ifnum = ntohs(s6->sin6_addr.__u6_addr.__u6_addr16[1]);
1463 if (ifnum == 0) ifnum = s6->sin6_scope_id;
1464 else if ((s6->sin6_scope_id != 0) && (ifnum != s6->sin6_scope_id)) return EAI_FAIL;
1465
1466 s6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
1467 s6->sin6_scope_id = ifnum;
1468 }
1469
1470 /* V4 mapped and compat addresses are converted to plain V4 */
1471 if ((IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) || (IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr)))
1472 {
1473 memset(s4, 0, sizeof(struct sockaddr_in));
1474
1475 s4->sin_len = sizeof(struct sockaddr_in);
1476 s4->sin_family = AF_INET;
1477 s4->sin_port = s6->sin6_port;
1478 memcpy(&(s4->sin_addr.s_addr), &(s6->sin6_addr.s6_addr[12]), 4);
1479
1480 return getnameinfo((const struct sockaddr *)s4, s4->sin_len, host, hostlen, serv, servlen, flags);
1481 }
1482 }
1483 else return EAI_FAMILY;
1484
1485 wanth = 0;
1486 if ((host != NULL) && (hostlen != 0)) wanth = 1;
1487
1488 wants = 0;
1489 if ((serv != NULL) && (servlen != 0)) wants = 1;
1490
1491 if ((wanth == 0) && (wants == 0)) return 0;
1492
1493 /*
1494 * Special cases handled by the library
1495 */
1496 if ((wanth == 1) && (flags & NI_NUMERICHOST))
1497 {
1498 if (sa->sa_family == AF_INET)
1499 {
1500 if (inet_ntop(AF_INET, a4, host, hostlen) == NULL) return EAI_FAIL;
1501 }
1502 else
1503 {
1504 if (inet_ntop(AF_INET6, a6, host, hostlen) == NULL) return EAI_FAIL;
1505 }
1506
1507 if ((isll != 0) && (ifnum != 0))
1508 {
1509 /* append interface name */
1510 if (if_indextoname(ifnum, ifname) != NULL)
1511 {
1512 strcat(host, "%");
1513 strcat(host, ifname);
1514 }
1515 }
1516
1517 if (wants == 0) return 0;
1518 }
1519
1520 if ((wants == 1) && (flags & NI_NUMERICSERV))
1521 {
1522 if (sa->sa_family == PF_INET)
1523 {
1524 n = snprintf(serv, servlen, "%hu", ntohs(s4->sin_port));
1525 if (n >= servlen) return EAI_FAIL;
1526 }
1527 else
1528 {
1529 n = snprintf(serv, servlen, "%hu", ntohs(s6->sin6_port));
1530 if (n >= servlen) return EAI_FAIL;
1531 }
1532
1533 if (wanth == 0) return 0;
1534 }
1535
1536 if ((wanth == 1) && (flags & NI_NUMERICHOST) && (wants == 1) && (flags & NI_NUMERICSERV)) return 0;
1537
1538 if (_ds_running() == 0)
1539 {
1540 errno = ECONNREFUSED;
1541 return EAI_SYSTEM;
1542 }
1543
1544 if (gni_proc < 0)
1545 {
1546 status = LI_DSLookupGetProcedureNumber("getnameinfo", &gni_proc);
1547 if (status != KERN_SUCCESS)
1548 {
1549 errno = ECONNREFUSED;
1550 return EAI_SYSTEM;
1551 }
1552 }
1553
1554 request = gni_make_query(sa, salen, wanth, wants, flags);
1555 if (request == NULL) return EAI_SYSTEM;
1556
1557 reply = NULL;
1558 status = LI_DSLookupQuery(gni_proc, request, &reply);
1559 kvbuf_free(request);
1560
1561 if (status != KERN_SUCCESS)
1562 {
1563 errno = ECONNREFUSED;
1564 return EAI_SYSTEM;
1565 }
1566
1567 if (reply == NULL) return EAI_NONAME;
1568
1569 hval = NULL;
1570 sval = NULL;
1571
1572 status = gni_extract(reply, &hval, &sval);
1573
1574 if (status != 0)
1575 {
1576 kvarray_free(reply);
1577 return status;
1578 }
1579
1580 i = 0;
1581 if (hval != NULL) i = strlen(hval) + 1;
1582 if ((host != NULL) && (hostlen != 0) && (i != 0))
1583 {
1584 if (i > hostlen)
1585 {
1586 kvarray_free(reply);
1587 return EAI_FAIL;
1588 }
1589
1590 memcpy(host, hval, i);
1591 }
1592
1593 i = 0;
1594 if (sval != NULL) i = strlen(sval) + 1;
1595 if ((serv != NULL) && (servlen != 0) && (i != 0))
1596 {
1597 if (i > servlen)
1598 {
1599 kvarray_free(reply);
1600 return EAI_FAIL;
1601 }
1602
1603 memcpy(serv, sval, i);
1604 }
1605
1606 kvarray_free(reply);
1607 return 0;
1608 }
1609
1610 int32_t
1611 getnameinfo_async_start(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags, getnameinfo_async_callback callback, void *context)
1612 {
1613 int32_t status;
1614 kvbuf_t *request;
1615
1616 *p = MACH_PORT_NULL;
1617
1618 /* Check input */
1619 if (sa == NULL) return EAI_FAIL;
1620
1621 if (gni_proc < 0)
1622 {
1623 status = LI_DSLookupGetProcedureNumber("getnameinfo", &gni_proc);
1624 if (status != KERN_SUCCESS)
1625 {
1626 errno = ECONNREFUSED;
1627 return EAI_SYSTEM;
1628 }
1629 }
1630
1631 request = gni_make_query(sa, salen, 1, 1, flags);
1632 if (request == NULL) return EAI_SYSTEM;
1633
1634 status = LI_async_start(p, gni_proc, request, (void *)callback, context);
1635
1636 kvbuf_free(request);
1637
1638 if (status != KERN_SUCCESS)
1639 {
1640 errno = ECONNREFUSED;
1641 return EAI_SYSTEM;
1642 }
1643
1644 return 0;
1645 }
1646
1647 void
1648 getnameinfo_async_cancel(mach_port_t p)
1649 {
1650 LI_async_call_cancel(p, NULL);
1651 }
1652
1653 int32_t
1654 getnameinfo_async_send(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags)
1655 {
1656 return getnameinfo_async_start(p, sa, salen, flags, NULL, NULL);
1657 }
1658
1659 int32_t
1660 getnameinfo_async_receive(mach_port_t p, char **host, char **serv)
1661 {
1662 kern_return_t status;
1663 const char *hval, *sval;
1664 kvarray_t *reply;
1665
1666 reply = NULL;
1667
1668 status = LI_async_receive(p, &reply);
1669 if (status < 0) return EAI_FAIL;
1670 if (reply == NULL) return EAI_NONAME;
1671
1672 hval = NULL;
1673 sval = NULL;
1674
1675 status = gni_extract(reply, &hval, &sval);
1676 if (status != 0)
1677 {
1678 kvarray_free(reply);
1679 return status;
1680 }
1681
1682 if (hval != NULL) *host = strdup(hval);
1683 if (sval != NULL) *serv = strdup(sval);
1684
1685 kvarray_free(reply);
1686 return 0;
1687 }
1688
1689 int32_t
1690 getnameinfo_async_handle_reply(void *msg)
1691 {
1692 getnameinfo_async_callback callback;
1693 void *context;
1694 const char *hval, *sval;
1695 char *host, *serv;
1696 uint32_t len;
1697 int status;
1698 kvarray_t *reply;
1699
1700 callback = (getnameinfo_async_callback)NULL;
1701 context = NULL;
1702 reply = NULL;
1703 len = 0;
1704
1705 status = LI_async_handle_reply(msg, &reply, (void **)&callback, &context);
1706 if ((status != KERN_SUCCESS) || (reply == NULL))
1707 {
1708 if (status == MIG_REPLY_MISMATCH) return 0;
1709 if (callback != NULL) callback(EAI_NONAME, NULL, NULL, context);
1710 return EAI_NONAME;
1711 }
1712
1713 hval = NULL;
1714 sval = NULL;
1715
1716 status = gni_extract(reply, &hval, &sval);
1717 if (status != 0)
1718 {
1719 if (callback != NULL) callback(status, NULL, NULL, context);
1720 kvarray_free(reply);
1721 return status;
1722 }
1723
1724 host = NULL;
1725 serv = NULL;
1726
1727 if (hval != NULL) host = strdup(hval);
1728 if (sval != NULL) serv = strdup(sval);
1729 kvarray_free(reply);
1730
1731 callback(0, host, serv, context);
1732 return 0;
1733 }