Libinfo-129.tar.gz
[apple/libinfo.git] / lookup.subproj / lu_host_async.c
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 2002 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 <netdb_async.h> /* async gethostbyXXX function prototypes */
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <mach/mach.h>
30 #include <netinfo/_lu_types.h>
31 #include <netinfo/lookup.h>
32 #include <rpc/types.h>
33 #include <rpc/xdr.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <ifaddrs.h>
38 #include <net/if.h>
39
40 #include "lu_host.h"
41 #include "lu_utils.h"
42
43 extern mach_port_t _lu_port;
44 extern int _lu_running(void);
45
46 extern int h_errno;
47
48
49 #define msgh_request_port msgh_remote_port
50 #define msgh_reply_port msgh_local_port
51
52
53 typedef union {
54 gethostbyaddr_async_callback hostAddr;
55 gethostbyname_async_callback hostName;
56 getipnodebyaddr_async_callback nodeAddr;
57 getipnodebyname_async_callback nodeName;
58 } a_request_callout_t;
59
60 typedef struct a_requests {
61 struct a_requests *next;
62 int retry;
63 struct {
64 int proc;
65 ooline_data data;
66 unsigned int dataLen;
67 int want;
68 } request;
69 mach_port_t replyPort;
70 a_request_callout_t callout;
71 void *context;
72 struct hostent *hent; /* if reply known in XXX_start() */
73 } a_requests_t;
74
75 static a_requests_t *a_requests = NULL;
76 static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
77
78 #define MAX_LOOKUP_ATTEMPTS 10
79
80
81 static kern_return_t
82 _lookup_all_tx
83 (
84 mach_port_t server,
85 int proc,
86 ooline_data indata,
87 mach_msg_type_number_t indataCnt,
88 mach_port_t *replyPort
89 )
90 {
91 typedef struct {
92 mach_msg_header_t Head;
93 NDR_record_t NDR;
94 int proc;
95 mach_msg_type_number_t indataCnt;
96 unit indata[4096];
97 } Request;
98
99 Request In;
100 register Request *InP = &In;
101 mach_msg_return_t mr;
102 unsigned int msgh_size;
103
104 if (indataCnt > 4096) {
105 return MIG_ARRAY_TOO_LARGE;
106 }
107
108 if (*replyPort == MACH_PORT_NULL) {
109 mr = mach_port_allocate(mach_task_self(),
110 MACH_PORT_RIGHT_RECEIVE,
111 replyPort);
112 if (mr != KERN_SUCCESS) {
113 return mr;
114 }
115 }
116
117 msgh_size = (sizeof(Request) - 16384) + ((4 * indataCnt));
118 InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);
119 /* InP->Head.msgh_size = msgh_size; /* msgh_size passed as argument */
120 InP->Head.msgh_request_port = server;
121 InP->Head.msgh_reply_port = *replyPort;
122 InP->Head.msgh_id = 4241776;
123 InP->NDR = NDR_record;
124 InP->proc = proc;
125 InP->indataCnt = indataCnt;
126 (void)memcpy((char *)InP->indata, (const char *)indata, 4 * indataCnt);
127
128 mr = mach_msg(&InP->Head, /* msg */
129 MACH_SEND_MSG, /* options */
130 msgh_size, /* send_size */
131 0, /* rcv_size */
132 MACH_PORT_NULL, /* rcv_name */
133 MACH_MSG_TIMEOUT_NONE, /* timeout */
134 MACH_PORT_NULL); /* notify */
135 switch (mr) {
136 case MACH_MSG_SUCCESS :
137 mr = KERN_SUCCESS;
138 break;
139 case MACH_SEND_INVALID_REPLY :
140 (void)mach_port_destroy(mach_task_self(), *replyPort);
141 break;
142 default:
143 break;
144 }
145
146 return mr;
147 }
148
149
150 static kern_return_t
151 _lookup_all_rx
152 (
153 void *msg,
154 ooline_data *outdata,
155 mach_msg_type_number_t *outdataCnt,
156 security_token_t *token
157 )
158 {
159 typedef struct {
160 mach_msg_header_t Head;
161 mach_msg_body_t msgh_body;
162 mach_msg_ool_descriptor_t outdata;
163 NDR_record_t NDR;
164 mach_msg_type_number_t outdataCnt;
165 mach_msg_format_0_trailer_t trailer;
166 } Reply;
167
168 /*
169 * typedef struct {
170 * mach_msg_header_t Head;
171 * NDR_record_t NDR;
172 * kern_return_t RetCode;
173 * } mig_reply_error_t;
174 */
175
176 register Reply *OutP = msg;
177 mach_msg_format_0_trailer_t *TrailerP;
178 boolean_t msgh_simple;
179
180 if (OutP->Head.msgh_id != (4241776 + 100)) {
181 if (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)
182 return MIG_SERVER_DIED;
183 else
184 return MIG_REPLY_MISMATCH;
185 }
186
187 msgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);
188
189 TrailerP = (mach_msg_format_0_trailer_t *)((vm_offset_t)OutP +
190 round_msg(OutP->Head.msgh_size));
191 if (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0)
192 return MIG_TRAILER_ERROR;
193
194 if (msgh_simple && ((mig_reply_error_t *)OutP)->RetCode != KERN_SUCCESS)
195 return ((mig_reply_error_t *)OutP)->RetCode;
196
197 *outdata = (ooline_data)(OutP->outdata.address);
198 *outdataCnt = OutP->outdataCnt;
199
200 *token = TrailerP->msgh_sender;
201
202 return KERN_SUCCESS;
203 }
204
205
206 static a_requests_t *
207 request_extract(mach_port_t port)
208 {
209 a_requests_t *request0, *request;
210
211 pthread_mutex_lock(&a_requests_lock);
212 request0 = NULL;
213 request = a_requests;
214 while (request) {
215 if (port == request->replyPort) {
216 /* request found, remove from list */
217 if (request0) {
218 request0->next = request->next;
219 } else {
220 a_requests = request->next;
221 }
222 break;
223 } else {
224 /* not this request, skip to next */
225 request0 = request;
226 request = request->next;
227 }
228 }
229 pthread_mutex_unlock(&a_requests_lock);
230
231 return request;
232 }
233
234
235 static void
236 request_queue(a_requests_t *request)
237 {
238 pthread_mutex_lock(&a_requests_lock);
239 request->next = a_requests;
240 a_requests = request;
241 pthread_mutex_unlock(&a_requests_lock);
242
243 return;
244 }
245
246
247 static boolean_t
248 sendCannedReply(a_requests_t *request, int *error)
249 {
250 /*
251 * typedef struct {
252 * mach_msg_header_t Head;
253 * NDR_record_t NDR;
254 * kern_return_t RetCode;
255 * } mig_reply_error_t;
256 */
257
258 mig_reply_error_t Out;
259 register mig_reply_error_t *OutP = &Out;
260
261 kern_return_t kr;
262 mach_msg_return_t mr;
263 unsigned int msgh_size;
264
265 /*
266 * allocate reply port
267 */
268 kr = mach_port_allocate(mach_task_self(),
269 MACH_PORT_RIGHT_RECEIVE,
270 &request->replyPort);
271 if (kr != KERN_SUCCESS) {
272 *error = NO_RECOVERY;
273 return FALSE;
274 }
275
276 kr = mach_port_insert_right(mach_task_self(),
277 request->replyPort,
278 request->replyPort,
279 MACH_MSG_TYPE_MAKE_SEND);
280 if (kr != KERN_SUCCESS) {
281 (void) mach_port_destroy(mach_task_self(), request->replyPort);
282 *error = NO_RECOVERY;
283 return FALSE;
284 }
285
286 /*
287 * queue reply message
288 */
289 msgh_size = sizeof(Out);
290 OutP->Head.msgh_bits = MACH_MSGH_BITS(19, 0);
291 /* OutP->Head.msgh_size = msgh_size; /* msgh_size passed as argument */
292 OutP->Head.msgh_request_port = request->replyPort;
293 OutP->Head.msgh_reply_port = MACH_PORT_NULL;
294 OutP->Head.msgh_id = 4241776 + 100;
295 OutP->RetCode = MIG_REMOTE_ERROR;
296 OutP->NDR = NDR_record;
297
298 mr = mach_msg(&OutP->Head, /* msg */
299 MACH_SEND_MSG, /* options */
300 msgh_size, /* send_size */
301 0, /* rcv_size */
302 MACH_PORT_NULL, /* rcv_name */
303 MACH_MSG_TIMEOUT_NONE, /* timeout */
304 MACH_PORT_NULL); /* notify */
305 if (mr != MACH_MSG_SUCCESS) {
306 if (mr == MACH_SEND_INVALID_REPLY) {
307 (void)mach_port_destroy(mach_task_self(), request->replyPort);
308 }
309 *error = NO_RECOVERY;
310 return FALSE;
311 }
312
313 return TRUE;
314 }
315
316
317 mach_port_t
318 _gethostbyaddr_async_start(const char *addr,
319 int len,
320 int type,
321 a_request_callout_t callout,
322 void *context,
323 int *error)
324 {
325 void *address;
326 int proc;
327 a_requests_t *request;
328 int want;
329
330 switch (type) {
331 case AF_INET :
332 {
333 static int proc4 = -1;
334 struct in_addr *v4addr;
335
336 if (proc4 < 0) {
337 if (_lookup_link(_lu_port, "gethostbyaddr", &proc4) != KERN_SUCCESS) {
338 *error = NO_RECOVERY;
339 return MACH_PORT_NULL;
340 }
341 }
342
343 if (len != sizeof(struct in_addr)) {
344 *error = NO_RECOVERY;
345 return NULL;
346 }
347
348 v4addr = malloc(len);
349 memmove(v4addr, addr, len);
350 v4addr->s_addr = htonl(v4addr->s_addr);
351
352 address = (void *)v4addr;
353 proc = proc4;
354 want = WANT_A4_ONLY;
355 break;
356 }
357
358 case AF_INET6 :
359 {
360 static int proc6 = -1;
361 struct in6_addr *v6addr;
362
363 if (proc6 < 0) {
364 if (_lookup_link(_lu_port, "getipv6nodebyaddr", &proc6) != KERN_SUCCESS) {
365 *error = NO_RECOVERY;
366 return MACH_PORT_NULL;
367 }
368 }
369
370 if (len != sizeof(struct in6_addr)) {
371 *error = NO_RECOVERY;
372 return NULL;
373 }
374
375 v6addr = malloc(len);
376 memmove(v6addr, addr, len);
377 v6addr->__u6_addr.__u6_addr32[0] = htonl(v6addr->__u6_addr.__u6_addr32[0]);
378 v6addr->__u6_addr.__u6_addr32[1] = htonl(v6addr->__u6_addr.__u6_addr32[1]);
379 v6addr->__u6_addr.__u6_addr32[2] = htonl(v6addr->__u6_addr.__u6_addr32[2]);
380 v6addr->__u6_addr.__u6_addr32[3] = htonl(v6addr->__u6_addr.__u6_addr32[3]);
381
382 address = (void *)v6addr;
383 proc = proc6;
384 want = WANT_A6_ONLY;
385 break;
386 }
387
388 default:
389 *error = NO_RECOVERY;
390 return MACH_PORT_NULL;
391 }
392
393 request = malloc(sizeof(a_requests_t));
394 request->next = NULL;
395 request->retry = MAX_LOOKUP_ATTEMPTS;
396 request->request.proc = proc;
397 request->request.data = (ooline_data)address;
398 request->request.dataLen = len / BYTES_PER_XDR_UNIT;
399 request->request.want = want;
400 request->replyPort = MACH_PORT_NULL;
401 request->callout = callout;
402 request->context = context;
403 request->hent = NULL;
404
405 /*
406 * allocate reply port, send query to lookupd
407 */
408 if (_lookup_all_tx(_lu_port,
409 request->request.proc,
410 request->request.data,
411 request->request.dataLen,
412 &request->replyPort) == KERN_SUCCESS) {
413 request_queue(request);
414 } else {
415 if (request->request.data) free(request->request.data);
416 free(request);
417 *error = NO_RECOVERY;
418 return MACH_PORT_NULL;
419 }
420
421 return request->replyPort;
422 }
423
424
425 boolean_t
426 _gethostbyaddr_async_handleReply(void *replyMsg,
427 a_requests_t **requestP,
428 struct hostent **he,
429 int *error)
430 {
431 int count;
432 ooline_data data;
433 unsigned int datalen;
434 XDR inxdr;
435 mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
436 a_requests_t *request;
437 kern_return_t status;
438 security_token_t token;
439
440 request = request_extract(msg->msgh_local_port);
441 if (!request) {
442 /* excuse me, what happenned to the request info? */
443 return FALSE;
444 }
445
446 *requestP = request;
447 *he = NULL;
448 *error = 0;
449
450 /* unpack the reply */
451 status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
452 switch (status) {
453 case KERN_SUCCESS :
454 break;
455
456 case MIG_SERVER_DIED :
457 if (--request->retry > 0) {
458 /* retry the request */
459 if (_lookup_all_tx(_lu_port,
460 request->request.proc,
461 request->request.data,
462 request->request.dataLen,
463 &request->replyPort) == KERN_SUCCESS) {
464 request_queue(request);
465 return FALSE;
466 }
467 }
468 /* fall through */
469
470 default :
471 *error = HOST_NOT_FOUND;
472 return TRUE;
473 }
474
475 datalen *= BYTES_PER_XDR_UNIT;
476
477 if (token.val[0] != 0) {
478 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
479 *error = NO_RECOVERY;
480 return TRUE;
481 }
482
483 xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
484
485 count = 0;
486 if (!xdr_int(&inxdr, &count)) {
487 xdr_destroy(&inxdr);
488 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
489 *error = NO_RECOVERY;
490 return TRUE;
491 }
492
493 if (count == 0) {
494 xdr_destroy(&inxdr);
495 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
496 *error = HOST_NOT_FOUND;
497 *he = NULL;
498 return TRUE;
499 }
500
501 *he = extract_host(&inxdr, request->request.want, error);
502 xdr_destroy(&inxdr);
503 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
504 return TRUE;
505 }
506
507
508 mach_port_t
509 gethostbyaddr_async_start(const char *addr,
510 int len,
511 int type,
512 gethostbyaddr_async_callback callout,
513 void *context)
514 {
515 a_request_callout_t cb;
516 mach_port_t mp;
517
518 if (!_lu_running()) {
519 h_errno = NO_RECOVERY;
520 return MACH_PORT_NULL;
521 }
522
523 cb.hostAddr = callout;
524 mp = _gethostbyaddr_async_start(addr, len, type, cb, context, &h_errno);
525 return mp;
526 }
527
528
529 void
530 gethostbyaddr_async_handleReply(void *replyMsg)
531 {
532 int error = 0;
533 struct hostent *he = NULL;
534 a_requests_t *request = NULL;
535
536 if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error)) {
537 /* if we have an answer to provide */
538 h_errno = error;
539 (request->callout.hostAddr)(he, request->context);
540
541 (void)mach_port_destroy(mach_task_self(), request->replyPort);
542 if (request->request.data) free(request->request.data);
543 free(request);
544 if (he) freehostent(he);
545 }
546
547 return;
548 }
549
550
551 mach_port_t
552 getipnodebyaddr_async_start(const void *addr,
553 size_t len,
554 int af,
555 int *error,
556 getipnodebyaddr_async_callback callout,
557 void *context)
558 {
559 a_request_callout_t cb;
560 mach_port_t mp;
561
562 if (!_lu_running()) {
563 *error = NO_RECOVERY;
564 return MACH_PORT_NULL;
565 }
566
567 if ((af == AF_INET6) &&
568 (len == sizeof(struct in6_addr)) &&
569 (is_a4_mapped((const char *)addr) || is_a4_compat((const char *)addr))) {
570 /*
571 * this is really a v4 address
572 */
573 addr += sizeof(struct in6_addr) - sizeof(struct in_addr);
574 len = sizeof(struct in_addr);
575 af = AF_INET;
576 }
577
578 cb.nodeAddr = callout;
579 mp = _gethostbyaddr_async_start(addr, len, af, cb, context, error);
580 return mp;
581 }
582
583
584 void
585 getipnodebyaddr_async_handleReply(void *replyMsg)
586 {
587 int error = 0;
588 struct hostent *he = NULL;
589 a_requests_t *request = NULL;
590
591 if (_gethostbyaddr_async_handleReply(replyMsg, &request, &he, &error)) {
592 /* if we have an answer to provide */
593 (request->callout.nodeAddr)(he, error, request->context);
594
595 (void)mach_port_destroy(mach_task_self(), request->replyPort);
596 if (request->request.data) free(request->request.data);
597 free(request);
598 /*
599 * Note: it is up to the callback function to call
600 * freehostent().
601 */
602 }
603
604 return;
605 }
606
607
608 mach_port_t
609 _gethostbyname_async_start(const char *name,
610 int want,
611 int *error,
612 a_request_callout_t callout,
613 void *context)
614 {
615 int af;
616 boolean_t is_addr = FALSE;
617 mach_port_t mp = MACH_PORT_NULL;
618 XDR outxdr;
619 static int proc;
620 a_requests_t *request;
621
622 if ((name == NULL) || (name[0] == '\0')) {
623 *error = NO_DATA;
624 return MACH_PORT_NULL;
625 }
626
627 af = (want == WANT_A4_ONLY) ? AF_INET : AF_INET6;
628
629 if ((af == AF_INET) || (want == WANT_MAPPED_A4_ONLY)) {
630 static int proc4 = -1;
631
632 if (proc4 < 0) {
633 if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS) {
634 *error = NO_RECOVERY;
635 return MACH_PORT_NULL;
636 }
637 }
638 proc = proc4;
639 } else /* if (af == AF_INET6) */ {
640 static int proc6 = -1;
641
642 if (proc6 < 0) {
643 if (_lookup_link(_lu_port, "getipv6nodebyname", &proc6) != KERN_SUCCESS)
644 {
645 *error = NO_RECOVERY;
646 return MACH_PORT_NULL;
647 }
648 }
649 proc = proc6;
650 }
651
652 request = malloc(sizeof(a_requests_t));
653 request->next = NULL;
654 request->retry = MAX_LOOKUP_ATTEMPTS;
655 request->request.proc = proc;
656 request->request.data = NULL;
657 request->request.dataLen = 0;
658 request->request.want = want;
659 request->replyPort = MACH_PORT_NULL;
660 request->callout = callout;
661 request->context = context;
662 request->hent = NULL;
663
664 switch (af) {
665 case AF_INET :
666 {
667 struct in_addr v4addr;
668
669 memset(&v4addr, 0, sizeof(struct in_addr));
670 if (inet_aton(name, &v4addr) == 1) {
671 /* return a fake hostent */
672 request->hent = fake_hostent(name, v4addr);
673 is_addr = TRUE;
674 }
675 break;
676 }
677
678 case AF_INET6 :
679 {
680 struct in_addr v4addr;
681 struct in6_addr v6addr;
682
683 memset(&v6addr, 0, sizeof(struct in6_addr));
684 if (inet_pton(af, name, &v6addr) == 1) {
685 /* return a fake hostent */
686 request->hent = fake_hostent6(name, v6addr);
687 is_addr = TRUE;
688 break;
689 }
690
691 memset(&v4addr, 0, sizeof(struct in_addr));
692 if (inet_aton(name, &v4addr) == 1) {
693 if (want == WANT_A4_ONLY) {
694 free(request);
695 *error = HOST_NOT_FOUND;
696 return MACH_PORT_NULL;
697 }
698
699 v6addr.__u6_addr.__u6_addr32[0] = 0x00000000;
700 v6addr.__u6_addr.__u6_addr32[1] = 0x00000000;
701 v6addr.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff);
702 memmove(&(v6addr.__u6_addr.__u6_addr32[3]), &(v4addr.s_addr), sizeof(struct in_addr));
703
704 /* return a fake hostent */
705 request->hent = fake_hostent6(name, v6addr);
706 is_addr = TRUE;
707 }
708 break;
709 }
710
711 default:
712 free(request);
713 *error = NO_RECOVERY;
714 return MACH_PORT_NULL;
715 }
716
717 if (is_addr) {
718 /*
719 * queue reply message
720 */
721 if (sendCannedReply(request, error)) {
722 request_queue(request);
723 return request->replyPort;
724 } else {
725 freehostent(request->hent);
726 free(request);
727 return MACH_PORT_NULL;
728 }
729 }
730
731 request->request.dataLen = _LU_MAXLUSTRLEN + BYTES_PER_XDR_UNIT;
732 request->request.data = malloc(request->request.dataLen);
733
734 xdrmem_create(&outxdr, request->request.data, request->request.dataLen, XDR_ENCODE);
735 if (!xdr__lu_string(&outxdr, (_lu_string *)&name)) {
736 xdr_destroy(&outxdr);
737 free(request->request.data);
738 free(request);
739 *error = NO_RECOVERY;
740 return MACH_PORT_NULL;
741 }
742
743 request->request.dataLen = xdr_getpos(&outxdr) / BYTES_PER_XDR_UNIT;
744
745 /*
746 * allocate reply port, send query to lookupd
747 */
748 if (_lookup_all_tx(_lu_port,
749 request->request.proc,
750 request->request.data,
751 request->request.dataLen,
752 &request->replyPort) == KERN_SUCCESS) {
753 request_queue(request);
754 mp = request->replyPort;
755 } else {
756 free(request->request.data);
757 free(request);
758 *error = NO_RECOVERY;
759 mp = NULL;
760 }
761
762 xdr_destroy(&outxdr);
763 return mp;
764 }
765
766
767 boolean_t
768 _gethostbyname_async_handleReply(void *replyMsg,
769 a_requests_t **requestP,
770 struct hostent **he,
771 int *error)
772 {
773
774 int count;
775 unsigned int datalen;
776 XDR inxdr;
777 ooline_data data;
778 mach_msg_header_t *msg = (mach_msg_header_t *)replyMsg;
779 a_requests_t *request;
780 kern_return_t status;
781 security_token_t token;
782 int want;
783
784 request = request_extract(msg->msgh_local_port);
785 if (!request) {
786 /* excuse me, what happenned to the request info? */
787 return FALSE;
788 }
789
790 *requestP = request;
791 *he = NULL;
792 *error = 0;
793
794 if (request->hent) {
795 /*
796 * if the reply was already available when the
797 * request was made
798 */
799 *he = request->hent;
800 return TRUE;
801 }
802
803 /* unpack the reply */
804 status = _lookup_all_rx(replyMsg, &data, &datalen, &token);
805 switch (status) {
806 case KERN_SUCCESS :
807 break;
808
809 case MIG_SERVER_DIED :
810 if (--request->retry > 0) {
811 /*
812 * retry the request
813 */
814 if (_lookup_all_tx(_lu_port,
815 request->request.proc,
816 request->request.data,
817 request->request.dataLen,
818 &request->replyPort) == KERN_SUCCESS) {
819 request_queue(request);
820 return FALSE;
821 }
822 }
823 /* fall through */
824
825 default :
826 *error = HOST_NOT_FOUND;
827 return TRUE;
828 }
829
830 datalen *= BYTES_PER_XDR_UNIT;
831
832 if (token.val[0] != 0) {
833 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
834 *error = NO_RECOVERY;
835 return TRUE;
836 }
837
838 xdrmem_create(&inxdr, data, datalen, XDR_DECODE);
839
840 count = 0;
841 if (!xdr_int(&inxdr, &count)) {
842 xdr_destroy(&inxdr);
843 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
844 *error = NO_RECOVERY;
845 return TRUE;
846 }
847
848 if (count == 0) {
849 xdr_destroy(&inxdr);
850 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
851 *error = HOST_NOT_FOUND;
852 return TRUE;
853 }
854
855 want = request->request.want;
856 if (want == WANT_A6_OR_MAPPED_A4_IF_NO_A6) want = WANT_A6_ONLY;
857
858 *he = extract_host(&inxdr, want, error);
859 xdr_destroy(&inxdr);
860 vm_deallocate(mach_task_self(), (vm_address_t)data, datalen);
861 return TRUE;
862 }
863
864
865 mach_port_t
866 gethostbyname_async_start(const char *name,
867 gethostbyname_async_callback callout,
868 void *context)
869 {
870 a_request_callout_t cb;
871 int error;
872 mach_port_t mp = MACH_PORT_NULL;
873
874 if (!_lu_running()) {
875 h_errno = NO_RECOVERY;
876 return MACH_PORT_NULL;
877 }
878
879 cb.hostName = callout;
880 mp = _gethostbyname_async_start(name, WANT_A4_ONLY, &error, cb, context);
881 if (!mp) {
882 h_errno = error;
883 }
884 return mp;
885 }
886
887
888 void
889 gethostbyname_async_handleReply(void *replyMsg)
890 {
891 int error;
892 struct hostent *he;
893 a_requests_t *request;
894
895 if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) {
896 /* if we have an answer to provide */
897 h_errno = error;
898 (request->callout.hostAddr)(he, request->context);
899
900 (void)mach_port_destroy(mach_task_self(), request->replyPort);
901 if (request->request.data) free(request->request.data);
902 free(request);
903 if (he) freehostent(he);
904 }
905
906 return;
907 }
908
909
910 mach_port_t
911 getipnodebyname_async_start(const char *name,
912 int af,
913 int flags,
914 int *error,
915 getipnodebyname_async_callback callout,
916 void *context)
917 {
918 a_request_callout_t cb;
919 int if4 = 0;
920 int if6 = 0;
921 mach_port_t mp = MACH_PORT_NULL;
922 int want = WANT_A4_ONLY;
923
924 if (!_lu_running()) {
925 h_errno = NO_RECOVERY;
926 return MACH_PORT_NULL;
927 }
928
929 /*
930 * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
931 */
932 if (flags & AI_ADDRCONFIG) {
933 struct ifaddrs *ifa, *ifap;
934
935 if (getifaddrs(&ifa) < 0) {
936 *error = NO_RECOVERY;
937 return MACH_PORT_NULL;
938 }
939
940 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
941 if (ifap->ifa_addr == NULL)
942 continue;
943 if ((ifap->ifa_flags & IFF_UP) == 0)
944 continue;
945 if (ifap->ifa_addr->sa_family == AF_INET) {
946 if4++;
947 } else if (ifap->ifa_addr->sa_family == AF_INET6) {
948 if6++;
949 }
950 }
951
952 freeifaddrs(ifa);
953
954 /* Bail out if there are no interfaces */
955 if ((if4 == 0) && (if6 == 0)) {
956 *error = NO_ADDRESS;
957 return MACH_PORT_NULL;
958 }
959 }
960
961 /*
962 * Figure out what we want.
963 * If user asked for AF_INET, we only want V4 addresses.
964 */
965 switch (af) {
966 case AF_INET :
967 {
968 want = WANT_A4_ONLY;
969 if ((flags & AI_ADDRCONFIG) && (if4 == 0)) {
970 *error = NO_ADDRESS;
971 return MACH_PORT_NULL;
972 }
973 }
974 break;
975 case AF_INET6 :
976 {
977 want = WANT_A6_ONLY;
978 if (flags & (AI_V4MAPPED|AI_V4MAPPED_CFG)) {
979 if (flags & AI_ALL) {
980 want = WANT_A6_PLUS_MAPPED_A4;
981 } else {
982 want = WANT_A6_OR_MAPPED_A4_IF_NO_A6;
983 }
984 } else {
985 if ((flags & AI_ADDRCONFIG) && (if6 == 0)) {
986 *error = NO_ADDRESS;
987 return MACH_PORT_NULL;
988 }
989 }
990 }
991 break;
992 }
993
994 cb.nodeName = callout;
995 mp = _gethostbyname_async_start(name, want, &h_errno, cb, context);
996 return mp;
997 }
998
999
1000 void
1001 getipnodebyname_async_handleReply(void *replyMsg)
1002 {
1003 int error = 0;
1004 struct hostent *he = NULL;
1005 a_requests_t *request = NULL;
1006
1007 if (_gethostbyname_async_handleReply(replyMsg, &request, &he, &error)) {
1008 /*
1009 * we have an answer to provide
1010 */
1011 if ((he == NULL) &&
1012 (error == HOST_NOT_FOUND) &&
1013 ((request->request.want == WANT_A6_PLUS_MAPPED_A4) ||
1014 (request->request.want == WANT_A6_OR_MAPPED_A4_IF_NO_A6))) {
1015 /*
1016 * no host found (yet), if requested we send a
1017 * followup query to lookupd.
1018 */
1019 static int proc4 = -1;
1020
1021 if (proc4 < 0) {
1022 if (_lookup_link(_lu_port, "gethostbyname", &proc4) != KERN_SUCCESS) {
1023 error = NO_RECOVERY;
1024 goto answer;
1025 }
1026 }
1027
1028 request->request.proc = proc4;
1029 request->request.want = WANT_MAPPED_A4_ONLY;
1030 if (_lookup_all_tx(_lu_port,
1031 request->request.proc,
1032 request->request.data,
1033 request->request.dataLen,
1034 &request->replyPort) == KERN_SUCCESS) {
1035 request_queue(request);
1036 return;
1037 } else {
1038 error = NO_RECOVERY;
1039 }
1040 }
1041
1042 answer :
1043 (request->callout.nodeName)(he, error, request->context);
1044 (void)mach_port_destroy(mach_task_self(), request->replyPort);
1045 if (request->request.data) free(request->request.data);
1046 free(request);
1047 /*
1048 * Note: it is up to the callback function to call
1049 * freehostent().
1050 */
1051 }
1052
1053 return;
1054 }