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