Libinfo-173.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include <netdb.h>
27 #include <sys/types.h>
28 #include <stdint.h>
29 #include <sys/time.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <string.h>
35 #include <stdlib.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;
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 cname = NULL;
481
482 if (hints != NULL)
483 {
484 family = hints->ai_family;
485 if (hints->ai_flags & AI_NUMERICHOST) numerichost = 1;
486 if (hints->ai_flags & AI_CANONNAME) canonname = 1;
487 if ((hints->ai_flags & AI_PASSIVE) == 1) passive = 1;
488
489 proto = hints->ai_protocol;
490 if (hints->ai_socktype == SOCK_DGRAM)
491 {
492 socktype = SOCK_DGRAM;
493 proto = IPPROTO_UDP;
494 }
495 if (hints->ai_socktype == SOCK_STREAM)
496 {
497 socktype = SOCK_STREAM;
498 proto = IPPROTO_TCP;
499 }
500 }
501
502 xdrmem_create(&outxdr, buf, *len, XDR_ENCODE);
503
504 /* Attribute count */
505 na = 0;
506 if (nodename != NULL) na++;
507 if (servname != NULL) na++;
508 if (proto != IPPROTO_UNSPEC) na++;
509 if (socktype != SOCK_UNSPEC) na++;
510 if (family != PF_UNSPEC) na++;
511 if (canonname != 0) na++;
512 if (passive != 0) na++;
513 if (numerichost != 0) na++;
514
515 if (!xdr_int(&outxdr, &na))
516 {
517 xdr_destroy(&outxdr);
518 return EAI_SYSTEM;
519 }
520
521 if (nodename != NULL)
522 {
523 if (encode_kv(&outxdr, "name", nodename) != 0)
524 {
525 xdr_destroy(&outxdr);
526 return EAI_SYSTEM;
527 }
528 }
529
530 if (servname != NULL)
531 {
532 if (encode_kv(&outxdr, "service", servname) != 0)
533 {
534 xdr_destroy(&outxdr);
535 return EAI_SYSTEM;
536 }
537 }
538
539 if (proto != IPPROTO_UNSPEC)
540 {
541 snprintf(str, 64, "%u", proto);
542 if (encode_kv(&outxdr, "protocol", str) != 0)
543 {
544 xdr_destroy(&outxdr);
545 return EAI_SYSTEM;
546 }
547 }
548
549 if (socktype != SOCK_UNSPEC)
550 {
551 snprintf(str, 64, "%u", socktype);
552 if (encode_kv(&outxdr, "socktype", str) != 0)
553 {
554 xdr_destroy(&outxdr);
555 return EAI_SYSTEM;
556 }
557 }
558
559 if (family != PF_UNSPEC)
560 {
561 snprintf(str, 64, "%u", family);
562 if (encode_kv(&outxdr, "family", str) != 0)
563 {
564 xdr_destroy(&outxdr);
565 return EAI_SYSTEM;
566 }
567 }
568
569 if (canonname != 0)
570 {
571 if (encode_kv(&outxdr, "canonname", "1") != 0)
572 {
573 xdr_destroy(&outxdr);
574 return EAI_SYSTEM;
575 }
576 }
577
578 if (passive != 0)
579 {
580 if (encode_kv(&outxdr, "passive", "1") != 0)
581 {
582 xdr_destroy(&outxdr);
583 return EAI_SYSTEM;
584 }
585 }
586
587 if (numerichost != 0)
588 {
589 if (encode_kv(&outxdr, "numerichost", "1") != 0)
590 {
591 xdr_destroy(&outxdr);
592 return EAI_SYSTEM;
593 }
594 }
595
596 *len = xdr_getpos(&outxdr);
597
598 xdr_destroy(&outxdr);
599
600 return 0;
601 }
602
603 static int32_t
604 is_a_number(const char *s)
605 {
606 int32_t i, len;
607
608 if (s == NULL) return 0;
609
610 len = strlen(s);
611 for (i = 0; i < len; i++)
612 {
613 if (isdigit(s[i]) == 0) return 0;
614 }
615
616 return 1;
617 }
618
619 int
620 gai_files(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
621 {
622 int32_t i, numericserv, numerichost, family, proto, wantv4, wantv6;
623 int16_t port;
624 struct servent *s;
625 struct hostent *h;
626 char *protoname, *loopv4, *loopv6;
627 struct in_addr a4;
628 struct in6_addr a6;
629 struct addrinfo *a;
630
631 numericserv = 0;
632 if (servname != NULL) numericserv = is_a_number(servname);
633
634 family = PF_UNSPEC;
635 if (hints != NULL) family = hints->ai_family;
636
637 numerichost = 0;
638
639 if (nodename == NULL)
640 {
641 numerichost = 1;
642
643 loopv4 = "127.0.0.1";
644 loopv6 = "0:0:0:0:0:0:0:1";
645
646 if ((hints != NULL) && ((hints->ai_flags & AI_PASSIVE) == 1))
647 {
648 loopv4 = "0.0.0.0";
649 loopv6 = "0:0:0:0:0:0:0:0";
650 }
651
652 if ((family == PF_UNSPEC) || (family == PF_INET))
653 {
654 inet_pton(AF_INET, loopv4, &a4);
655 }
656
657 if ((family == PF_UNSPEC) || (family == PF_INET6))
658 {
659 inet_pton(AF_INET6, loopv6, &a6);
660 }
661 }
662 else
663 {
664 if ((family == PF_UNSPEC) || (family == PF_INET))
665 {
666 numerichost = inet_pton(AF_INET, nodename, &a4);
667 if ((numerichost == 1) && (family == PF_UNSPEC)) family = PF_INET;
668 }
669
670 if ((family == PF_UNSPEC) || (family == PF_INET6))
671 {
672 numerichost = inet_pton(AF_INET6, nodename, &a6);
673 if ((numerichost == 1) && (family == PF_UNSPEC)) family = PF_INET6;
674 }
675 }
676
677 wantv4 = 1;
678 wantv6 = 1;
679 if (family == PF_INET6) wantv4 = 0;
680 if (family == PF_INET) wantv6 = 0;
681
682 proto = IPPROTO_UNSPEC;
683 protoname = NULL;
684
685 if (hints != NULL)
686 {
687 proto = hints->ai_protocol;
688 if (proto == IPPROTO_UNSPEC)
689 {
690 if (hints->ai_socktype == SOCK_DGRAM) proto = IPPROTO_UDP;
691 else if (hints->ai_socktype == SOCK_STREAM) proto = IPPROTO_TCP;
692 }
693 }
694
695 if (proto == IPPROTO_UDP) protoname = "udp";
696 else if (proto == IPPROTO_TCP) protoname = "tcp";
697
698 s = NULL;
699 port = 0;
700
701 if (numericserv != 0)
702 {
703 port = htons(atoi(servname));
704 }
705 else if (servname != NULL)
706 {
707 s = getservbyname(servname, protoname);
708 if (s != NULL) port = s->s_port;
709 }
710
711 /* new_addrinfo_v4 and new_addrinfo_v6 expect port in host byte order */
712 port = ntohs(port);
713
714 if (numerichost != 0)
715 {
716 if (wantv4 == 1)
717 {
718 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
719 {
720 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
721 append_addrinfo(res, a);
722 }
723
724 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
725 {
726 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
727 append_addrinfo(res, a);
728 }
729 }
730
731 if (wantv6 == 1)
732 {
733 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
734 {
735 a = new_addrinfo_v6(0, SOCK_DGRAM, IPPROTO_UDP, port, a6, 0, NULL);
736 append_addrinfo(res, a);
737 }
738
739 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
740 {
741 a = new_addrinfo_v6(0, SOCK_STREAM, IPPROTO_TCP, port, a6, 0, NULL);
742 append_addrinfo(res, a);
743 }
744 }
745
746 return 0;
747 }
748
749 if (wantv4 == 1)
750 {
751 h = gethostbyname(nodename);
752 if (h == NULL) return 0;
753
754 for (i = 0; h->h_addr_list[i] != 0; i++)
755 {
756 memmove((void *)&a4.s_addr, h->h_addr_list[i], h->h_length);
757
758 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_UDP))
759 {
760 a = new_addrinfo_v4(0, SOCK_DGRAM, IPPROTO_UDP, port, a4, 0, NULL);
761 append_addrinfo(res, a);
762 }
763
764 if ((proto == IPPROTO_UNSPEC) || (proto == IPPROTO_TCP))
765 {
766 a = new_addrinfo_v4(0, SOCK_STREAM, IPPROTO_TCP, port, a4, 0, NULL);
767 append_addrinfo(res, a);
768 }
769 }
770 }
771
772 return 0;
773 }
774
775 static int
776 gai_lookupd(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
777 {
778 uint32_t n, i, qlen, rlen;
779 XDR inxdr;
780 char qbuf[LU_QBUF_SIZE];
781 char *rbuf;
782 char *cname;
783 mach_port_t server_port;
784 kern_return_t status;
785 struct addrinfo *a;
786
787 server_port = MACH_PORT_NULL;
788 if (_lu_running()) server_port = _lookupd_port(0);
789 if (server_port == MACH_PORT_NULL)
790 {
791 /* lookupd isn't available - fall back to the flat files */
792 return gai_files(nodename, servname, hints, res);
793 }
794
795 if (gai_proc < 0)
796 {
797 status = _lookup_link(server_port, "getaddrinfo", &gai_proc);
798 if (status != KERN_SUCCESS) return EAI_SYSTEM;
799 }
800
801 qlen = LU_QBUF_SIZE;
802 i = gai_make_query(nodename, servname, hints, qbuf, &qlen);
803 if (i != 0) return EAI_SYSTEM;
804
805 qlen /= BYTES_PER_XDR_UNIT;
806
807 rbuf = NULL;
808
809 status = _lookup_all(server_port, gai_proc, (unit *)qbuf, qlen, &rbuf, &rlen);
810 if (status != KERN_SUCCESS) return EAI_NODATA;
811
812 rlen *= BYTES_PER_XDR_UNIT;
813
814 xdrmem_create(&inxdr, rbuf, rlen, XDR_DECODE);
815
816 if (!xdr_int(&inxdr, &n))
817 {
818 xdr_destroy(&inxdr);
819 return EAI_SYSTEM;
820 }
821
822 cname = NULL;
823 for (i = 0; i < n; i++)
824 {
825 a = gai_lookupd_process_dictionary(&inxdr);
826 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
827 append_addrinfo(res, a);
828 }
829
830 xdr_destroy(&inxdr);
831 if (rbuf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)rbuf, rlen);
832
833 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
834 {
835 res[0]->ai_canonname = strdup(cname);
836 }
837
838 return 0;
839 }
840
841 static int
842 gai_checkhints(const struct addrinfo *hints)
843 {
844 if (hints == NULL) return 0;
845 if (hints->ai_addrlen != 0) return EAI_BADHINTS;
846 if (hints->ai_canonname != NULL) return EAI_BADHINTS;
847 if (hints->ai_addr != NULL) return EAI_BADHINTS;
848 if (hints->ai_next != NULL) return EAI_BADHINTS;
849
850 /* Check for supported protocol family */
851 if (gai_family_type_check(hints->ai_family) != 0) return EAI_FAMILY;
852
853 /* Check for supported socket */
854 if (gai_socket_type_check(hints->ai_socktype) != 0) return EAI_BADHINTS;
855
856 /* Check for supported protocol */
857 if (gai_protocol_type_check(hints->ai_protocol) != 0) return EAI_BADHINTS;
858
859 /* Check that socket type is compatible with protocol */
860 if (gai_socket_protocol_type_check(hints->ai_socktype, hints->ai_protocol) != 0) return EAI_BADHINTS;
861
862 return 0;
863 }
864
865 int
866 getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
867 {
868 int32_t status, nodenull, servnull;
869
870 if (res == NULL) return 0;
871 *res = NULL;
872
873 /* Check input */
874 nodenull = 0;
875 if ((nodename == NULL) || (nodename[0] == '\0')) nodenull = 1;
876
877 servnull = 0;
878 if ((servname == NULL) || (servname[0] == '\0')) servnull = 1;
879
880 if ((nodenull == 1) && (servnull == 1)) return EAI_NONAME;
881 status = gai_checkhints(hints);
882 if (status != 0) return status;
883
884 if (nodenull == 1) status = gai_lookupd(NULL, servname, hints, res);
885 else if (servnull == 1) status = gai_lookupd(nodename, NULL, hints, res);
886 else status = gai_lookupd(nodename, servname, hints, res);
887
888 if ((status == 0) && (*res == NULL)) status = EAI_NODATA;
889
890 return status;
891 }
892
893 int32_t
894 getaddrinfo_async_start(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints, getaddrinfo_async_callback callback, void *context)
895 {
896 int32_t status;
897 uint32_t i, qlen;
898 char qbuf[LU_QBUF_SIZE];
899 mach_port_t server_port;
900
901 *p = MACH_PORT_NULL;
902
903 if ((nodename == NULL) && (servname == NULL)) return EAI_NONAME;
904
905 status = gai_checkhints(hints);
906 if (status != 0) return EAI_BADHINTS;
907
908 server_port = MACH_PORT_NULL;
909 if (_lu_running()) server_port = _lookupd_port(0);
910 if (server_port == MACH_PORT_NULL) return EAI_SYSTEM;
911
912 if (gai_proc < 0)
913 {
914 status = _lookup_link(server_port, "getaddrinfo", &gai_proc);
915 if (status != KERN_SUCCESS) return EAI_SYSTEM;
916 }
917
918 qlen = LU_QBUF_SIZE;
919 i = gai_make_query(nodename, servname, hints, qbuf, &qlen);
920 if (i != 0) return EAI_SYSTEM;
921
922 qlen /= BYTES_PER_XDR_UNIT;
923
924 return lu_async_start(p, gai_proc, qbuf, qlen, (void *)callback, context);
925 }
926
927 int32_t
928 getaddrinfo_async_send(mach_port_t *p, const char *nodename, const char *servname, const struct addrinfo *hints)
929 {
930 return getaddrinfo_async_start(p, nodename, servname, hints, NULL, NULL);
931 }
932
933 static int
934 gai_extract_data(char *buf, uint32_t len, struct addrinfo **res)
935 {
936 XDR xdr;
937 uint32_t i, n;
938 char *cname;
939 struct addrinfo *a;
940
941 *res = NULL;
942
943 if (buf == NULL) return EAI_NODATA;
944 if (len == 0) return EAI_NODATA;
945
946 xdrmem_create(&xdr, buf, len, XDR_DECODE);
947
948 if (!xdr_int(&xdr, &n))
949 {
950 xdr_destroy(&xdr);
951 return EAI_SYSTEM;
952 }
953
954 cname = NULL;
955 for (i = 0; i < n; i++)
956 {
957 a = gai_lookupd_process_dictionary(&xdr);
958 if (a == NULL) break;
959
960 if ((cname == NULL) && (a->ai_canonname != NULL)) cname = a->ai_canonname;
961 append_addrinfo(res, a);
962 }
963
964 xdr_destroy(&xdr);
965
966 if ((cname != NULL) && (res != NULL) && (res[0] != NULL) && (res[0]->ai_canonname == NULL))
967 {
968 res[0]->ai_canonname = strdup(cname);
969 }
970
971 if (*res == NULL) return EAI_NODATA;
972 return 0;
973 }
974
975 int32_t
976 getaddrinfo_async_receive(mach_port_t p, struct addrinfo **res)
977 {
978 kern_return_t status;
979 char *buf;
980 uint32_t len;
981
982 if (res == NULL) return 0;
983 *res = NULL;
984
985 buf = NULL;
986 len = 0;
987
988 status = lu_async_receive(p, &buf, &len);
989 if (status < 0) return EAI_FAIL;
990
991 status = gai_extract_data(buf, len, res);
992 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
993 if (status != 0) return status;
994
995 if (*res == NULL) return EAI_NODATA;
996
997 return 0;
998 }
999
1000 int32_t
1001 getaddrinfo_async_handle_reply(void *msg)
1002 {
1003 getaddrinfo_async_callback callback;
1004 void *context;
1005 char *buf;
1006 uint32_t len;
1007 int status;
1008 struct addrinfo *res;
1009
1010 callback = (getaddrinfo_async_callback)NULL;
1011 context = NULL;
1012 buf = NULL;
1013 len = 0;
1014 res = NULL;
1015
1016 status = lu_async_handle_reply(msg, &buf, &len, (void **)&callback, &context);
1017 if (status != KERN_SUCCESS)
1018 {
1019 if (status == MIG_REPLY_MISMATCH) return 0;
1020 if (callback != NULL) callback(EAI_SYSTEM, NULL, context);
1021 return EAI_SYSTEM;
1022 }
1023
1024 status = gai_extract_data(buf, len, &res);
1025 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1026 if (status != 0)
1027 {
1028 if (callback != NULL) callback(status, NULL, context);
1029 return status;
1030 }
1031
1032 if (res == NULL)
1033 {
1034 callback(EAI_NODATA, NULL, context);
1035 return EAI_NODATA;
1036 }
1037
1038 callback(0, res, context);
1039 return 0;
1040 }
1041
1042 /*
1043 * getnameinfo
1044 */
1045
1046 /*
1047 * getnameinfo support in lookupd
1048 * Input dict may contain the following
1049 *
1050 * ip_address: node address
1051 * ipv6_address: node address
1052 * port: service number
1053 * protocol: [tcp] | udp
1054 * fqdn: [1] | 0
1055 * numerichost: [0] | 1
1056 * name_required: [0] | 1
1057 * numericserv: [0] | 1
1058 *
1059 * Output dictionary may contain the following
1060 * All values are encoded as strings.
1061 *
1062 * name: char *
1063 * service: char *
1064 */
1065
1066 static int
1067 gni_lookupd_process_dictionary(XDR *inxdr, char **host, char **serv)
1068 {
1069 int32_t i, nkeys, nvals;
1070 char *key, *val;
1071
1072 if ((host == NULL) || (serv == NULL)) return EAI_SYSTEM;
1073 if (!xdr_int(inxdr, &nkeys)) return EAI_SYSTEM;
1074
1075 for (i = 0; i < nkeys; i++)
1076 {
1077 key = NULL;
1078 val = NULL;
1079
1080 if (!xdr_string(inxdr, &key, LONG_STRING_LENGTH)) return EAI_SYSTEM;
1081 if (!xdr_int(inxdr, &nvals))
1082 {
1083 free(key);
1084 return EAI_SYSTEM;
1085 }
1086
1087 if (nvals != 1)
1088 {
1089 free(key);
1090 return EAI_SYSTEM;
1091 }
1092
1093 if (!xdr_string(inxdr, &val, LONG_STRING_LENGTH))
1094 {
1095 free(key);
1096 return EAI_SYSTEM;
1097 }
1098
1099 if (!strcmp(key, "name"))
1100 {
1101 *host = val;
1102 val = NULL;
1103 }
1104
1105 else if (!strcmp(key, "service"))
1106 {
1107 *serv = val;
1108 val = NULL;
1109 }
1110
1111 if (key != NULL) free(key);
1112 if (val != NULL) free(val);
1113 }
1114
1115 return 0;
1116 }
1117
1118 static int
1119 gni_make_query(const struct sockaddr *sa, size_t salen, int wanthost, int wantserv, int flags, char *buf, uint32_t *len)
1120 {
1121 XDR outxdr;
1122 uint16_t port;
1123 char str[_LU_MAXLUSTRLEN], *key, ifname[IF_NAMESIZE];
1124 uint32_t a4, ifnum, offset, na, proto, fqdn, numerichost, numericserv, name_req;
1125 struct sockaddr_in6 *s6;
1126
1127 if (sa == NULL) return EAI_FAIL;
1128 if (sa->sa_len != salen) return EAI_FAMILY;
1129
1130 proto = IPPROTO_TCP;
1131 fqdn = 1;
1132 numerichost = 0;
1133 numericserv = 0;
1134 name_req = 0;
1135
1136 offset = INET_NTOP_AF_INET_OFFSET;
1137 key = "ip_address";
1138 port = 0;
1139
1140 if (sa->sa_family == PF_INET)
1141 {
1142 a4 = ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
1143 if (IN_MULTICAST(a4) || IN_EXPERIMENTAL(a4)) flags |= NI_NUMERICHOST;
1144 a4 >>= IN_CLASSA_NSHIFT;
1145 if (a4 == 0) flags |= NI_NUMERICHOST;
1146
1147 port = ((struct sockaddr_in *)sa)->sin_port;
1148 }
1149 else if (sa->sa_family == PF_INET6)
1150 {
1151 s6 = (struct sockaddr_in6 *)sa;
1152 switch (s6->sin6_addr.s6_addr[0])
1153 {
1154 case 0x00:
1155 if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
1156 {
1157 }
1158 else if (IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr))
1159 {
1160 }
1161 else
1162 {
1163 flags |= NI_NUMERICHOST;
1164 }
1165 break;
1166 default:
1167 if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr))
1168 {
1169 flags |= NI_NUMERICHOST;
1170 }
1171 else if (IN6_IS_ADDR_MULTICAST(&s6->sin6_addr))
1172 {
1173 flags |= NI_NUMERICHOST;
1174 }
1175 break;
1176 }
1177
1178 offset = INET_NTOP_AF_INET6_OFFSET;
1179 key = "ipv6_address";
1180 port = s6->sin6_port;
1181 }
1182 else
1183 {
1184 return EAI_FAMILY;
1185 }
1186
1187 na = 0;
1188
1189 if (wanthost != 0) na++;
1190 if (wantserv != 0) na++;
1191
1192 if (flags & NI_NOFQDN)
1193 {
1194 fqdn = 0;
1195 na++;
1196 }
1197
1198 if (flags & NI_NUMERICHOST)
1199 {
1200 numerichost = 1;
1201 na++;
1202 }
1203
1204 if (flags & NI_NUMERICSERV)
1205 {
1206 numericserv = 1;
1207 na++;
1208 }
1209
1210 if (flags & NI_NAMEREQD)
1211 {
1212 name_req = 1;
1213 na++;
1214 }
1215
1216 if (flags & NI_DGRAM)
1217 {
1218 proto = IPPROTO_UDP;
1219 na++;
1220 }
1221
1222 xdrmem_create(&outxdr, buf, *len, XDR_ENCODE);
1223
1224 if (!xdr_int(&outxdr, &na))
1225 {
1226 xdr_destroy(&outxdr);
1227 return EAI_SYSTEM;
1228 }
1229
1230 if (wanthost != 0)
1231 {
1232 inet_ntop(sa->sa_family, (char *)(sa) + offset, str, _LU_MAXLUSTRLEN);
1233
1234 if ((flags & NI_WITHSCOPEID) && (sa->sa_family == AF_INET6))
1235 {
1236 ifnum = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
1237 if (if_indextoname(ifnum, ifname) != NULL)
1238 {
1239 strcat(str, "%");
1240 strcat(str, ifname);
1241 }
1242 }
1243
1244 if (encode_kv(&outxdr, key, str) != 0)
1245 {
1246 xdr_destroy(&outxdr);
1247 return EAI_SYSTEM;
1248 }
1249 }
1250
1251 if (wantserv != 0)
1252 {
1253 snprintf(str, _LU_MAXLUSTRLEN, "%hu", port);
1254 if (encode_kv(&outxdr, "port", str) != 0)
1255 {
1256 xdr_destroy(&outxdr);
1257 return EAI_SYSTEM;
1258 }
1259 }
1260
1261 if (proto == IPPROTO_UDP)
1262 {
1263 if (encode_kv(&outxdr, "protocol", "udp") != 0)
1264 {
1265 xdr_destroy(&outxdr);
1266 return EAI_SYSTEM;
1267 }
1268 }
1269
1270 if (fqdn == 0)
1271 {
1272 if (encode_kv(&outxdr, "fqdn", "0") != 0)
1273 {
1274 xdr_destroy(&outxdr);
1275 return EAI_SYSTEM;
1276 }
1277 }
1278
1279 if (numerichost == 1)
1280 {
1281 if (encode_kv(&outxdr, "numerichost", "1") != 0)
1282 {
1283 xdr_destroy(&outxdr);
1284 return EAI_SYSTEM;
1285 }
1286 }
1287
1288 if (numericserv == 1)
1289 {
1290 if (encode_kv(&outxdr, "numericserv", "1") != 0)
1291 {
1292 xdr_destroy(&outxdr);
1293 return EAI_SYSTEM;
1294 }
1295 }
1296
1297 if (name_req == 1)
1298 {
1299 if (encode_kv(&outxdr, "name_required", "1") != 0)
1300 {
1301 xdr_destroy(&outxdr);
1302 return EAI_SYSTEM;
1303 }
1304 }
1305
1306 *len = xdr_getpos(&outxdr);
1307
1308 xdr_destroy(&outxdr);
1309
1310 return 0;
1311 }
1312
1313 int
1314 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
1315 {
1316 uint32_t n, i, qlen, rlen;
1317 int wanth, wants;
1318 XDR inxdr;
1319 char qbuf[LU_QBUF_SIZE];
1320 char *rbuf, *hval, *sval;
1321 mach_port_t server_port;
1322 kern_return_t status;
1323 struct sockaddr_in *s4;
1324 struct sockaddr_in6 *s6;
1325
1326 /* Check input */
1327 if (sa == NULL) return EAI_FAIL;
1328
1329 /* V4 mapped and compat addresses are converted to plain V4 */
1330 if (sa->sa_family == AF_INET6)
1331 {
1332 s6 = (struct sockaddr_in6 *)sa;
1333 if ((IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) || (IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr)))
1334 {
1335 s4 = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in));
1336 s4->sin_len = sizeof(struct sockaddr_in);
1337 s4->sin_family = AF_INET;
1338 s4->sin_port = s6->sin6_port;
1339 memcpy(&(s4->sin_addr.s_addr), &(s6->sin6_addr.s6_addr[12]), 4);
1340
1341 i = getnameinfo((const struct sockaddr *)s4, s4->sin_len, host, hostlen, serv, servlen, flags);
1342 free(s4);
1343 return i;
1344 }
1345 }
1346
1347 wanth = 0;
1348 if ((host != NULL) && (hostlen != 0)) wanth = 1;
1349
1350 wants = 0;
1351 if ((serv != NULL) && (servlen != 0)) wants = 1;
1352
1353 if ((wanth == 0) && (wants == 0)) return 0;
1354
1355 /*
1356 * Special cases handled by the library
1357 */
1358 if ((wanth == 1) && (flags & NI_NUMERICHOST))
1359 {
1360 i = INET_NTOP_AF_INET_OFFSET;
1361 if (sa->sa_family == PF_INET6) i = INET_NTOP_AF_INET6_OFFSET;
1362 if (inet_ntop(sa->sa_family, (char *)(sa) + i, host, hostlen) == NULL) return EAI_FAIL;
1363
1364 if (wants == 0) return 0;
1365 }
1366
1367 if ((wants == 1) && (flags & NI_NUMERICSERV))
1368 {
1369 if (sa->sa_family == PF_INET)
1370 {
1371 s4 = (struct sockaddr_in *)sa;
1372 n = snprintf(serv, servlen, "%hu", ntohs(s4->sin_port));
1373 if (n >= servlen) return EAI_FAIL;
1374 }
1375 else if (sa->sa_family == PF_INET6)
1376 {
1377 s6 = (struct sockaddr_in6 *)sa;
1378 n = snprintf(serv, servlen, "%hu", ntohs(s6->sin6_port));
1379 if (n >= servlen) return EAI_FAIL;
1380 }
1381 else return EAI_FAMILY;
1382
1383 if (wanth == 0) return 0;
1384 }
1385
1386 if ((wanth == 1) && (flags & NI_NUMERICHOST) && (wants == 1) && (flags & NI_NUMERICSERV)) return 0;
1387
1388 /*
1389 * Ask lookupd
1390 */
1391 server_port = MACH_PORT_NULL;
1392 if (_lu_running()) server_port = _lookupd_port(0);
1393 if (server_port == MACH_PORT_NULL) return EAI_SYSTEM;
1394
1395 if (gni_proc < 0)
1396 {
1397 status = _lookup_link(server_port, "getnameinfo", &gni_proc);
1398 if (status != KERN_SUCCESS) return EAI_SYSTEM;
1399 }
1400
1401 qlen = LU_QBUF_SIZE;
1402 i = gni_make_query(sa, salen, wanth, wants, flags, qbuf, &qlen);
1403 if (i != 0) return EAI_SYSTEM;
1404
1405 qlen /= BYTES_PER_XDR_UNIT;
1406
1407 rbuf = NULL;
1408
1409 status = _lookup_all(server_port, gni_proc, (unit *)qbuf, qlen, &rbuf, &rlen);
1410 if (status != KERN_SUCCESS) return EAI_NONAME;
1411
1412 rlen *= BYTES_PER_XDR_UNIT;
1413
1414 xdrmem_create(&inxdr, rbuf, rlen, XDR_DECODE);
1415
1416 if (!xdr_int(&inxdr, &n))
1417 {
1418 xdr_destroy(&inxdr);
1419 return EAI_SYSTEM;
1420 }
1421
1422 if (n != 1)
1423 {
1424 xdr_destroy(&inxdr);
1425 return EAI_NONAME;
1426 }
1427
1428 hval = NULL;
1429 sval = NULL;
1430
1431 i = gni_lookupd_process_dictionary(&inxdr, &hval, &sval);
1432
1433 xdr_destroy(&inxdr);
1434 if (rbuf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)rbuf, rlen);
1435
1436 if (i != 0) return i;
1437
1438 i = 0;
1439 if (hval != NULL) i = strlen(hval) + 1;
1440 if ((host != NULL) && (hostlen != 0) && (i != 0))
1441 {
1442 if (i > hostlen) return EAI_FAIL;
1443 memcpy(host, hval, i);
1444 free(hval);
1445 }
1446
1447 i = 0;
1448 if (sval != NULL) i = strlen(sval) + 1;
1449 if ((serv != NULL) && (servlen != 0) && (i != 0))
1450 {
1451 if (i > servlen) return EAI_FAIL;
1452 memcpy(serv, sval, i);
1453 free(sval);
1454 }
1455
1456 return 0;
1457 }
1458
1459 int32_t
1460 getnameinfo_async_start(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags, getnameinfo_async_callback callback, void *context)
1461 {
1462 uint32_t i, qlen;
1463 char qbuf[LU_QBUF_SIZE];
1464 mach_port_t server_port;
1465 kern_return_t status;
1466
1467 /* Check input */
1468 if (sa == NULL) return EAI_FAIL;
1469
1470 server_port = MACH_PORT_NULL;
1471 if (_lu_running()) server_port = _lookupd_port(0);
1472 if (server_port == MACH_PORT_NULL) return EAI_SYSTEM;
1473
1474 if (gni_proc < 0)
1475 {
1476 status = _lookup_link(server_port, "getnameinfo", &gni_proc);
1477 if (status != KERN_SUCCESS) return EAI_SYSTEM;
1478 }
1479
1480 qlen = LU_QBUF_SIZE;
1481 i = gni_make_query(sa, salen, 1, 1, flags, qbuf, &qlen);
1482 if (i != 0) return EAI_SYSTEM;
1483
1484 qlen /= BYTES_PER_XDR_UNIT;
1485
1486 return lu_async_start(p, gni_proc, qbuf, qlen, (void *)callback, context);
1487 }
1488
1489 int32_t
1490 getnameinfo_async_send(mach_port_t *p, const struct sockaddr *sa, size_t salen, int flags)
1491 {
1492 return getnameinfo_async_start(p, sa, salen, flags, NULL, NULL);
1493 }
1494
1495 static int
1496 gni_extract_data(char *buf, uint32_t len, char **host, char **serv)
1497 {
1498 XDR xdr;
1499 uint32_t n;
1500
1501 *host = NULL;
1502 *serv = NULL;
1503
1504 if (buf == NULL) return EAI_NODATA;
1505 if (len == 0) return EAI_NODATA;
1506
1507 xdrmem_create(&xdr, buf, len, XDR_DECODE);
1508
1509 if (!xdr_int(&xdr, &n))
1510 {
1511 xdr_destroy(&xdr);
1512 return EAI_SYSTEM;
1513 }
1514
1515 if (n != 1)
1516 {
1517 xdr_destroy(&xdr);
1518 return EAI_NONAME;
1519 }
1520
1521 return gni_lookupd_process_dictionary(&xdr, host, serv);
1522 }
1523
1524 int32_t
1525 getnameinfo_async_receive(mach_port_t p, char **host, char **serv)
1526 {
1527 kern_return_t status;
1528 char *buf;
1529 uint32_t len;
1530
1531 buf = NULL;
1532 len = 0;
1533
1534 status = lu_async_receive(p, &buf, &len);
1535 if (status < 0) return EAI_FAIL;
1536
1537 status = gni_extract_data(buf, len, host, serv);
1538 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1539 if (status != 0) return status;
1540
1541 return 0;
1542 }
1543
1544 int32_t
1545 getnameinfo_async_handle_reply(void *msg)
1546 {
1547 getnameinfo_async_callback callback;
1548 void *context;
1549 char *buf, *hval, *sval;
1550 uint32_t len;
1551 int status;
1552
1553 callback = (getnameinfo_async_callback)NULL;
1554 context = NULL;
1555 buf = NULL;
1556 len = 0;
1557
1558 status = lu_async_handle_reply(msg, &buf, &len, (void **)&callback, &context);
1559 if (status != KERN_SUCCESS)
1560 {
1561 if (status == MIG_REPLY_MISMATCH) return 0;
1562 if (callback != NULL) callback(EAI_SYSTEM, NULL, NULL, context);
1563 return EAI_SYSTEM;
1564 }
1565
1566 hval = NULL;
1567 sval = NULL;
1568
1569 status = gni_extract_data(buf, len, &hval, &sval);
1570 if (buf != NULL) vm_deallocate(mach_task_self(), (vm_address_t)buf, len);
1571 if (status != 0)
1572 {
1573 if (callback != NULL) callback(status, NULL, NULL, context);
1574 return status;
1575 }
1576
1577 callback(0, hval, sval, context);
1578 return 0;
1579 }