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