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