2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
38 #include <rpc/types.h>
40 #include <mach/mach.h>
41 #include <servers/bootstrap.h>
44 #include "netdb_async.h"
47 #define IPPROTO_UNSPEC 0
49 #define LONG_STRING_LENGTH 8192
50 #define _LU_MAXLUSTRLEN 256
51 #define LU_QBUF_SIZE 8192
53 #define MAX_LOOKUP_ATTEMPTS 10
55 #define INET_NTOP_AF_INET_OFFSET 4
56 #define INET_NTOP_AF_INET6_OFFSET 8
58 extern mach_port_t
_lookupd_port();
60 static int gai_proc
= -1;
61 static int gni_proc
= -1;
63 static int32_t supported_family
[] =
69 static int32_t supported_family_count
= 3;
71 static int32_t supported_socket
[] =
78 static int32_t supported_socket_count
= 4;
80 static int32_t supported_protocol
[] =
87 static int32_t supported_protocol_count
= 4;
89 static int32_t supported_socket_protocol_pair
[] =
91 SOCK_RAW
, IPPROTO_UNSPEC
,
92 SOCK_RAW
, IPPROTO_UDP
,
93 SOCK_RAW
, IPPROTO_TCP
,
94 SOCK_RAW
, IPPROTO_ICMPV6
,
95 SOCK_UNSPEC
, IPPROTO_UNSPEC
,
96 SOCK_UNSPEC
, IPPROTO_UDP
,
97 SOCK_UNSPEC
, IPPROTO_TCP
,
98 SOCK_UNSPEC
, IPPROTO_ICMPV6
,
99 SOCK_DGRAM
, IPPROTO_UNSPEC
,
100 SOCK_DGRAM
, IPPROTO_UDP
,
101 SOCK_STREAM
, IPPROTO_UNSPEC
,
102 SOCK_STREAM
, IPPROTO_TCP
104 static int32_t supported_socket_protocol_pair_count
= 12;
107 gai_family_type_check(int32_t f
)
111 for (i
= 0; i
< supported_family_count
; i
++)
113 if (f
== supported_family
[i
]) return 0;
120 gai_socket_type_check(int32_t s
)
124 for (i
= 0; i
< supported_socket_count
; i
++)
126 if (s
== supported_socket
[i
]) return 0;
133 gai_protocol_type_check(int32_t p
)
137 for (i
= 0; i
< supported_protocol_count
; i
++)
139 if (p
== supported_protocol
[i
]) return 0;
146 gai_socket_protocol_type_check(int32_t s
, int32_t p
)
148 int32_t i
, j
, ss
, sp
;
150 for (i
= 0, j
= 0; i
< supported_socket_protocol_pair_count
; i
++, j
+=2)
152 ss
= supported_socket_protocol_pair
[j
];
153 sp
= supported_socket_protocol_pair
[j
+1];
154 if ((s
== ss
) && (p
== sp
)) return 0;
161 gai_strerror(int32_t err
)
165 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
166 case EAI_AGAIN
: return "Temporary failure in name resolution";
167 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
168 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
169 case EAI_FAMILY
: return "ai_family not supported";
170 case EAI_MEMORY
: return "Memory allocation failure";
171 case EAI_NODATA
: return "No address associated with nodename";
172 case EAI_NONAME
: return "nodename nor servname provided, or not known";
173 case EAI_SERVICE
: return "servname not supported for ai_socktype";
174 case EAI_SOCKTYPE
: return "ai_socktype not supported";
175 case EAI_SYSTEM
: return "System error";
176 case EAI_BADHINTS
: return "Bad hints";
177 case EAI_PROTOCOL
: return "ai_protocol not supported";
180 return "Unknown error";
184 append_addrinfo(struct addrinfo
**l
, struct addrinfo
*a
)
188 if (l
== NULL
) return;
189 if (a
== NULL
) return;
199 if (a
->ai_family
== PF_INET6
)
201 if (x
->ai_family
== PF_INET
)
208 while ((x
->ai_next
!= NULL
) && (x
->ai_next
->ai_family
!= PF_INET
)) x
= x
->ai_next
;
209 a
->ai_next
= x
->ai_next
;
214 while (x
->ai_next
!= NULL
) x
= x
->ai_next
;
221 encode_kv(XDR
*x
, const char *k
, const char *v
)
225 if (!xdr_string(x
, (char **)&k
, _LU_MAXLUSTRLEN
)) return 1;
226 if (!xdr_int(x
, &n
)) return 1;
227 if (!xdr_string(x
, (char **)&v
, _LU_MAXLUSTRLEN
)) return 1;
233 freeaddrinfo(struct addrinfo
*a
)
235 struct addrinfo
*next
;
240 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
241 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
247 static struct addrinfo
*
248 new_addrinfo_v4(int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in_addr addr
, uint32_t iface
, char *cname
)
251 struct sockaddr_in
*sa
;
254 a
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
255 if (a
== NULL
) return NULL
;
260 a
->ai_family
= PF_INET
;
261 a
->ai_socktype
= sock
;
262 a
->ai_protocol
= proto
;
264 a
->ai_addrlen
= sizeof(struct sockaddr_in
);
266 sa
= (struct sockaddr_in
*)calloc(1, a
->ai_addrlen
);
273 sa
->sin_len
= a
->ai_addrlen
;
274 sa
->sin_family
= PF_INET
;
275 sa
->sin_port
= htons(port
);
278 /* Kludge: Jam the interface number into sin_zero. */
279 memmove(sa
->sin_zero
, &iface
, sizeof(uint32_t));
281 a
->ai_addr
= (struct sockaddr
*)sa
;
285 len
= strlen(cname
) + 1;
286 a
->ai_canonname
= malloc(len
);
287 memmove(a
->ai_canonname
, cname
, len
);
293 static struct addrinfo
*
294 new_addrinfo_v6(int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in6_addr addr
, uint32_t scopeid
, char *cname
)
297 struct sockaddr_in6
*sa
;
300 a
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
301 if (a
== NULL
) return NULL
;
306 a
->ai_family
= PF_INET6
;
307 a
->ai_socktype
= sock
;
308 a
->ai_protocol
= proto
;
310 a
->ai_addrlen
= sizeof(struct sockaddr_in6
);
312 sa
= (struct sockaddr_in6
*)calloc(1, a
->ai_addrlen
);
319 sa
->sin6_len
= a
->ai_addrlen
;
320 sa
->sin6_family
= PF_INET6
;
321 sa
->sin6_port
= htons(port
);
322 sa
->sin6_addr
= addr
;
323 sa
->sin6_scope_id
= scopeid
;
324 a
->ai_addr
= (struct sockaddr
*)sa
;
328 len
= strlen(cname
) + 1;
329 a
->ai_canonname
= malloc(len
);
330 memmove(a
->ai_canonname
, cname
, len
);
337 * getaddrinfo support in lookupd
338 * Input dict may contain the following
342 * protocol: [IPPROTO_UNSPEC] | IPPROTO_UDP | IPPROTO_TCP
343 * socktype: [SOCK_UNSPEC] | SOCK_DGRAM | SOCK_STREAM
344 * family: [PF_UNSPEC] | PF_INET | PF_INET6
347 * numerichost: [0] | 1
349 * Output dictionary may contain the following
350 * All values are encoded as strings.
352 * flags: unsigned long
353 * family: unsigned long
354 * socktype: unsigned long
355 * protocol: unsigned long
356 * port: unsigned long
358 * scopeid: unsigned long
363 static struct addrinfo
*
364 gai_lookupd_process_dictionary(XDR
*inxdr
)
366 int32_t i
, nkeys
, nvals
;
368 uint32_t flags
, family
, socktype
, protocol
, longport
, scopeid
;
370 char *addr
, *canonname
;
377 socktype
= SOCK_UNSPEC
;
378 protocol
= IPPROTO_UNSPEC
;
384 if (!xdr_int(inxdr
, &nkeys
)) return NULL
;
386 for (i
= 0; i
< nkeys
; i
++)
391 if (!xdr_string(inxdr
, &key
, LONG_STRING_LENGTH
)) return NULL
;
392 if (!xdr_int(inxdr
, &nvals
))
404 if (!xdr_string(inxdr
, &val
, LONG_STRING_LENGTH
))
410 if (!strcmp(key
, "flags"))
414 else if (!strcmp(key
, "family"))
418 else if (!strcmp(key
, "socktype"))
420 socktype
= atoi(val
);
422 else if (!strcmp(key
, "protocol"))
424 protocol
= atoi(val
);
426 else if (!strcmp(key
, "port"))
428 longport
= atoi(val
);
431 else if (!strcmp(key
, "scopeid"))
435 else if (!strcmp(key
, "address")) addr
= strdup(val
);
436 else if (!strcmp(key
, "canonname")) canonname
= strdup(val
);
441 if (family
== PF_UNSPEC
)
443 if (addr
!= NULL
) free(addr
);
444 if (canonname
!= NULL
) free(canonname
);
449 if (family
== PF_INET
)
451 inet_aton(addr
, &a4
);
452 a
= new_addrinfo_v4(flags
, socktype
, protocol
, port
, a4
, scopeid
, canonname
);
454 else if (family
== PF_INET6
)
456 inet_pton(AF_INET6
, addr
, &a6
);
457 a
= new_addrinfo_v6(flags
, socktype
, protocol
, port
, a6
, scopeid
, canonname
);
460 if (addr
!= NULL
) free(addr
);
461 if (canonname
!= NULL
) free(canonname
);
467 gai_make_query(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, char *buf
, uint32_t *len
)
469 int32_t numerichost
, family
, proto
, socktype
, canonname
, passive
;
472 char str
[64], *cname
;
476 proto
= IPPROTO_UNSPEC
;
477 socktype
= SOCK_UNSPEC
;
484 family
= hints
->ai_family
;
485 if (hints
->ai_flags
& AI_NUMERICHOST
) numerichost
= 1;
486 if (hints
->ai_flags
& AI_CANONNAME
) canonname
= 1;
487 if ((hints
->ai_flags
& AI_PASSIVE
) == 1) passive
= 1;
489 proto
= hints
->ai_protocol
;
490 if (hints
->ai_socktype
== SOCK_DGRAM
)
492 socktype
= SOCK_DGRAM
;
495 if (hints
->ai_socktype
== SOCK_STREAM
)
497 socktype
= SOCK_STREAM
;
502 xdrmem_create(&outxdr
, buf
, *len
, XDR_ENCODE
);
504 /* Attribute count */
506 if (nodename
!= NULL
) na
++;
507 if (servname
!= NULL
) na
++;
508 if (proto
!= IPPROTO_UNSPEC
) na
++;
509 if (socktype
!= SOCK_UNSPEC
) na
++;
510 if (family
!= PF_UNSPEC
) na
++;
511 if (canonname
!= 0) na
++;
512 if (passive
!= 0) na
++;
513 if (numerichost
!= 0) na
++;
515 if (!xdr_int(&outxdr
, &na
))
517 xdr_destroy(&outxdr
);
521 if (nodename
!= NULL
)
523 if (encode_kv(&outxdr
, "name", nodename
) != 0)
525 xdr_destroy(&outxdr
);
530 if (servname
!= NULL
)
532 if (encode_kv(&outxdr
, "service", servname
) != 0)
534 xdr_destroy(&outxdr
);
539 if (proto
!= IPPROTO_UNSPEC
)
541 snprintf(str
, 64, "%u", proto
);
542 if (encode_kv(&outxdr
, "protocol", str
) != 0)
544 xdr_destroy(&outxdr
);
549 if (socktype
!= SOCK_UNSPEC
)
551 snprintf(str
, 64, "%u", socktype
);
552 if (encode_kv(&outxdr
, "socktype", str
) != 0)
554 xdr_destroy(&outxdr
);
559 if (family
!= PF_UNSPEC
)
561 snprintf(str
, 64, "%u", family
);
562 if (encode_kv(&outxdr
, "family", str
) != 0)
564 xdr_destroy(&outxdr
);
571 if (encode_kv(&outxdr
, "canonname", "1") != 0)
573 xdr_destroy(&outxdr
);
580 if (encode_kv(&outxdr
, "passive", "1") != 0)
582 xdr_destroy(&outxdr
);
587 if (numerichost
!= 0)
589 if (encode_kv(&outxdr
, "numerichost", "1") != 0)
591 xdr_destroy(&outxdr
);
596 *len
= xdr_getpos(&outxdr
);
598 xdr_destroy(&outxdr
);
604 is_a_number(const char *s
)
608 if (s
== NULL
) return 0;
611 for (i
= 0; i
< len
; i
++)
613 if (isdigit(s
[i
]) == 0) return 0;
620 gai_files(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
622 int32_t i
, numericserv
, numerichost
, family
, proto
, wantv4
, wantv6
;
626 char *protoname
, *loopv4
, *loopv6
;
632 if (servname
!= NULL
) numericserv
= is_a_number(servname
);
635 if (hints
!= NULL
) family
= hints
->ai_family
;
639 if (nodename
== NULL
)
643 loopv4
= "127.0.0.1";
644 loopv6
= "0:0:0:0:0:0:0:1";
646 if ((hints
!= NULL
) && ((hints
->ai_flags
& AI_PASSIVE
) == 1))
649 loopv6
= "0:0:0:0:0:0:0:0";
652 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
654 inet_pton(AF_INET
, loopv4
, &a4
);
657 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
659 inet_pton(AF_INET6
, loopv6
, &a6
);
664 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
666 numerichost
= inet_pton(AF_INET
, nodename
, &a4
);
667 if ((numerichost
== 1) && (family
== PF_UNSPEC
)) family
= PF_INET
;
670 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
672 numerichost
= inet_pton(AF_INET6
, nodename
, &a6
);
673 if ((numerichost
== 1) && (family
== PF_UNSPEC
)) family
= PF_INET6
;
679 if (family
== PF_INET6
) wantv4
= 0;
680 if (family
== PF_INET
) wantv6
= 0;
682 proto
= IPPROTO_UNSPEC
;
687 proto
= hints
->ai_protocol
;
688 if (proto
== IPPROTO_UNSPEC
)
690 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
691 else if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
695 if (proto
== IPPROTO_UDP
) protoname
= "udp";
696 else if (proto
== IPPROTO_TCP
) protoname
= "tcp";
701 if (numericserv
!= 0)
703 port
= htons(atoi(servname
));
705 else if (servname
!= NULL
)
707 s
= getservbyname(servname
, protoname
);
708 if (s
!= NULL
) port
= s
->s_port
;
711 /* new_addrinfo_v4 and new_addrinfo_v6 expect port in host byte order */
714 if (numerichost
!= 0)
718 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
720 a
= new_addrinfo_v4(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, NULL
);
721 append_addrinfo(res
, a
);
724 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
726 a
= new_addrinfo_v4(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, NULL
);
727 append_addrinfo(res
, a
);
733 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
735 a
= new_addrinfo_v6(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, 0, NULL
);
736 append_addrinfo(res
, a
);
739 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
741 a
= new_addrinfo_v6(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, 0, NULL
);
742 append_addrinfo(res
, a
);
751 h
= gethostbyname(nodename
);
752 if (h
== NULL
) return 0;
754 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
756 memmove((void *)&a4
.s_addr
, h
->h_addr_list
[i
], h
->h_length
);
758 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
760 a
= new_addrinfo_v4(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, NULL
);
761 append_addrinfo(res
, a
);
764 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
766 a
= new_addrinfo_v4(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, NULL
);
767 append_addrinfo(res
, a
);
776 gai_lookupd(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
778 uint32_t n
, i
, qlen
, rlen
;
780 char qbuf
[LU_QBUF_SIZE
];
783 mach_port_t server_port
;
784 kern_return_t status
;
787 server_port
= MACH_PORT_NULL
;
788 if (_lu_running()) server_port
= _lookupd_port(0);
789 if (server_port
== MACH_PORT_NULL
)
791 /* lookupd isn't available - fall back to the flat files */
792 return gai_files(nodename
, servname
, hints
, res
);
797 status
= _lookup_link(server_port
, "getaddrinfo", &gai_proc
);
798 if (status
!= KERN_SUCCESS
) return EAI_SYSTEM
;
802 i
= gai_make_query(nodename
, servname
, hints
, qbuf
, &qlen
);
803 if (i
!= 0) return EAI_SYSTEM
;
805 qlen
/= BYTES_PER_XDR_UNIT
;
809 status
= _lookup_all(server_port
, gai_proc
, (unit
*)qbuf
, qlen
, &rbuf
, &rlen
);
810 if (status
!= KERN_SUCCESS
) return EAI_NODATA
;
812 rlen
*= BYTES_PER_XDR_UNIT
;
814 xdrmem_create(&inxdr
, rbuf
, rlen
, XDR_DECODE
);
816 if (!xdr_int(&inxdr
, &n
))
823 for (i
= 0; i
< n
; i
++)
825 a
= gai_lookupd_process_dictionary(&inxdr
);
826 if ((cname
== NULL
) && (a
->ai_canonname
!= NULL
)) cname
= a
->ai_canonname
;
827 append_addrinfo(res
, a
);
831 if (rbuf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)rbuf
, rlen
);
833 if ((cname
!= NULL
) && (res
!= NULL
) && (res
[0] != NULL
) && (res
[0]->ai_canonname
== NULL
))
835 res
[0]->ai_canonname
= strdup(cname
);
842 gai_checkhints(const struct addrinfo
*hints
)
844 if (hints
== NULL
) return 0;
845 if (hints
->ai_addrlen
!= 0) return EAI_BADHINTS
;
846 if (hints
->ai_canonname
!= NULL
) return EAI_BADHINTS
;
847 if (hints
->ai_addr
!= NULL
) return EAI_BADHINTS
;
848 if (hints
->ai_next
!= NULL
) return EAI_BADHINTS
;
850 /* Check for supported protocol family */
851 if (gai_family_type_check(hints
->ai_family
) != 0) return EAI_FAMILY
;
853 /* Check for supported socket */
854 if (gai_socket_type_check(hints
->ai_socktype
) != 0) return EAI_BADHINTS
;
856 /* Check for supported protocol */
857 if (gai_protocol_type_check(hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
859 /* Check that socket type is compatible with protocol */
860 if (gai_socket_protocol_type_check(hints
->ai_socktype
, hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
866 getaddrinfo(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
868 int32_t status
, nodenull
, servnull
;
870 if (res
== NULL
) return 0;
875 if ((nodename
== NULL
) || (nodename
[0] == '\0')) nodenull
= 1;
878 if ((servname
== NULL
) || (servname
[0] == '\0')) servnull
= 1;
880 if ((nodenull
== 1) && (servnull
== 1)) return EAI_NONAME
;
881 status
= gai_checkhints(hints
);
882 if (status
!= 0) return status
;
884 if (nodenull
== 1) status
= gai_lookupd(NULL
, servname
, hints
, res
);
885 else if (servnull
== 1) status
= gai_lookupd(nodename
, NULL
, hints
, res
);
886 else status
= gai_lookupd(nodename
, servname
, hints
, res
);
888 if ((status
== 0) && (*res
== NULL
)) status
= EAI_NODATA
;
894 getaddrinfo_async_start(mach_port_t
*p
, const char *nodename
, const char *servname
, const struct addrinfo
*hints
, getaddrinfo_async_callback callback
, void *context
)
898 char qbuf
[LU_QBUF_SIZE
];
899 mach_port_t server_port
;
903 if ((nodename
== NULL
) && (servname
== NULL
)) return EAI_NONAME
;
905 status
= gai_checkhints(hints
);
906 if (status
!= 0) return EAI_BADHINTS
;
908 server_port
= MACH_PORT_NULL
;
909 if (_lu_running()) server_port
= _lookupd_port(0);
910 if (server_port
== MACH_PORT_NULL
) return EAI_SYSTEM
;
914 status
= _lookup_link(server_port
, "getaddrinfo", &gai_proc
);
915 if (status
!= KERN_SUCCESS
) return EAI_SYSTEM
;
919 i
= gai_make_query(nodename
, servname
, hints
, qbuf
, &qlen
);
920 if (i
!= 0) return EAI_SYSTEM
;
922 qlen
/= BYTES_PER_XDR_UNIT
;
924 return lu_async_start(p
, gai_proc
, qbuf
, qlen
, (void *)callback
, context
);
928 getaddrinfo_async_send(mach_port_t
*p
, const char *nodename
, const char *servname
, const struct addrinfo
*hints
)
930 return getaddrinfo_async_start(p
, nodename
, servname
, hints
, NULL
, NULL
);
934 gai_extract_data(char *buf
, uint32_t len
, struct addrinfo
**res
)
943 if (buf
== NULL
) return EAI_NODATA
;
944 if (len
== 0) return EAI_NODATA
;
946 xdrmem_create(&xdr
, buf
, len
, XDR_DECODE
);
948 if (!xdr_int(&xdr
, &n
))
955 for (i
= 0; i
< n
; i
++)
957 a
= gai_lookupd_process_dictionary(&xdr
);
958 if (a
== NULL
) break;
960 if ((cname
== NULL
) && (a
->ai_canonname
!= NULL
)) cname
= a
->ai_canonname
;
961 append_addrinfo(res
, a
);
966 if ((cname
!= NULL
) && (res
!= NULL
) && (res
[0] != NULL
) && (res
[0]->ai_canonname
== NULL
))
968 res
[0]->ai_canonname
= strdup(cname
);
971 if (*res
== NULL
) return EAI_NODATA
;
976 getaddrinfo_async_receive(mach_port_t p
, struct addrinfo
**res
)
978 kern_return_t status
;
982 if (res
== NULL
) return 0;
988 status
= lu_async_receive(p
, &buf
, &len
);
989 if (status
< 0) return EAI_FAIL
;
991 status
= gai_extract_data(buf
, len
, res
);
992 if (buf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)buf
, len
);
993 if (status
!= 0) return status
;
995 if (*res
== NULL
) return EAI_NODATA
;
1001 getaddrinfo_async_handle_reply(void *msg
)
1003 getaddrinfo_async_callback callback
;
1008 struct addrinfo
*res
;
1010 callback
= (getaddrinfo_async_callback
)NULL
;
1016 status
= lu_async_handle_reply(msg
, &buf
, &len
, (void **)&callback
, &context
);
1017 if (status
!= KERN_SUCCESS
)
1019 if (status
== MIG_REPLY_MISMATCH
) return 0;
1020 if (callback
!= NULL
) callback(EAI_SYSTEM
, NULL
, context
);
1024 status
= gai_extract_data(buf
, len
, &res
);
1025 if (buf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)buf
, len
);
1028 if (callback
!= NULL
) callback(status
, NULL
, context
);
1034 callback(EAI_NODATA
, NULL
, context
);
1038 callback(0, res
, context
);
1047 * getnameinfo support in lookupd
1048 * Input dict may contain the following
1050 * ip_address: node address
1051 * ipv6_address: node address
1052 * port: service number
1053 * protocol: [tcp] | udp
1055 * numerichost: [0] | 1
1056 * name_required: [0] | 1
1057 * numericserv: [0] | 1
1059 * Output dictionary may contain the following
1060 * All values are encoded as strings.
1067 gni_lookupd_process_dictionary(XDR
*inxdr
, char **host
, char **serv
)
1069 int32_t i
, nkeys
, nvals
;
1072 if ((host
== NULL
) || (serv
== NULL
)) return EAI_SYSTEM
;
1073 if (!xdr_int(inxdr
, &nkeys
)) return EAI_SYSTEM
;
1075 for (i
= 0; i
< nkeys
; i
++)
1080 if (!xdr_string(inxdr
, &key
, LONG_STRING_LENGTH
)) return EAI_SYSTEM
;
1081 if (!xdr_int(inxdr
, &nvals
))
1093 if (!xdr_string(inxdr
, &val
, LONG_STRING_LENGTH
))
1099 if (!strcmp(key
, "name"))
1105 else if (!strcmp(key
, "service"))
1111 if (key
!= NULL
) free(key
);
1112 if (val
!= NULL
) free(val
);
1119 gni_make_query(const struct sockaddr
*sa
, size_t salen
, int wanthost
, int wantserv
, int flags
, char *buf
, uint32_t *len
)
1123 char str
[_LU_MAXLUSTRLEN
], *key
, ifname
[IF_NAMESIZE
];
1124 uint32_t a4
, ifnum
, offset
, na
, proto
, fqdn
, numerichost
, numericserv
, name_req
;
1125 struct sockaddr_in6
*s6
;
1127 if (sa
== NULL
) return EAI_FAIL
;
1128 if (sa
->sa_len
!= salen
) return EAI_FAMILY
;
1130 proto
= IPPROTO_TCP
;
1136 offset
= INET_NTOP_AF_INET_OFFSET
;
1140 if (sa
->sa_family
== PF_INET
)
1142 a4
= ntohl(((const struct sockaddr_in
*)sa
)->sin_addr
.s_addr
);
1143 if (IN_MULTICAST(a4
) || IN_EXPERIMENTAL(a4
)) flags
|= NI_NUMERICHOST
;
1144 a4
>>= IN_CLASSA_NSHIFT
;
1145 if (a4
== 0) flags
|= NI_NUMERICHOST
;
1147 port
= ((struct sockaddr_in
*)sa
)->sin_port
;
1149 else if (sa
->sa_family
== PF_INET6
)
1151 s6
= (struct sockaddr_in6
*)sa
;
1152 switch (s6
->sin6_addr
.s6_addr
[0])
1155 if (IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
1158 else if (IN6_IS_ADDR_LOOPBACK(&s6
->sin6_addr
))
1163 flags
|= NI_NUMERICHOST
;
1167 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
))
1169 flags
|= NI_NUMERICHOST
;
1171 else if (IN6_IS_ADDR_MULTICAST(&s6
->sin6_addr
))
1173 flags
|= NI_NUMERICHOST
;
1178 offset
= INET_NTOP_AF_INET6_OFFSET
;
1179 key
= "ipv6_address";
1180 port
= s6
->sin6_port
;
1189 if (wanthost
!= 0) na
++;
1190 if (wantserv
!= 0) na
++;
1192 if (flags
& NI_NOFQDN
)
1198 if (flags
& NI_NUMERICHOST
)
1204 if (flags
& NI_NUMERICSERV
)
1210 if (flags
& NI_NAMEREQD
)
1216 if (flags
& NI_DGRAM
)
1218 proto
= IPPROTO_UDP
;
1222 xdrmem_create(&outxdr
, buf
, *len
, XDR_ENCODE
);
1224 if (!xdr_int(&outxdr
, &na
))
1226 xdr_destroy(&outxdr
);
1232 inet_ntop(sa
->sa_family
, (char *)(sa
) + offset
, str
, _LU_MAXLUSTRLEN
);
1234 if ((flags
& NI_WITHSCOPEID
) && (sa
->sa_family
== AF_INET6
))
1236 ifnum
= ((struct sockaddr_in6
*)sa
)->sin6_scope_id
;
1237 if (if_indextoname(ifnum
, ifname
) != NULL
)
1240 strcat(str
, ifname
);
1244 if (encode_kv(&outxdr
, key
, str
) != 0)
1246 xdr_destroy(&outxdr
);
1253 snprintf(str
, _LU_MAXLUSTRLEN
, "%hu", port
);
1254 if (encode_kv(&outxdr
, "port", str
) != 0)
1256 xdr_destroy(&outxdr
);
1261 if (proto
== IPPROTO_UDP
)
1263 if (encode_kv(&outxdr
, "protocol", "udp") != 0)
1265 xdr_destroy(&outxdr
);
1272 if (encode_kv(&outxdr
, "fqdn", "0") != 0)
1274 xdr_destroy(&outxdr
);
1279 if (numerichost
== 1)
1281 if (encode_kv(&outxdr
, "numerichost", "1") != 0)
1283 xdr_destroy(&outxdr
);
1288 if (numericserv
== 1)
1290 if (encode_kv(&outxdr
, "numericserv", "1") != 0)
1292 xdr_destroy(&outxdr
);
1299 if (encode_kv(&outxdr
, "name_required", "1") != 0)
1301 xdr_destroy(&outxdr
);
1306 *len
= xdr_getpos(&outxdr
);
1308 xdr_destroy(&outxdr
);
1314 getnameinfo(const struct sockaddr
*sa
, socklen_t salen
, char *host
, size_t hostlen
, char *serv
, size_t servlen
, int flags
)
1316 uint32_t n
, i
, qlen
, rlen
;
1319 char qbuf
[LU_QBUF_SIZE
];
1320 char *rbuf
, *hval
, *sval
;
1321 mach_port_t server_port
;
1322 kern_return_t status
;
1323 struct sockaddr_in
*s4
;
1324 struct sockaddr_in6
*s6
;
1327 if (sa
== NULL
) return EAI_FAIL
;
1329 /* V4 mapped and compat addresses are converted to plain V4 */
1330 if (sa
->sa_family
== AF_INET6
)
1332 s6
= (struct sockaddr_in6
*)sa
;
1333 if ((IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
)) || (IN6_IS_ADDR_V4COMPAT(&s6
->sin6_addr
)))
1335 s4
= (struct sockaddr_in
*)calloc(1, sizeof(struct sockaddr_in
));
1336 s4
->sin_len
= sizeof(struct sockaddr_in
);
1337 s4
->sin_family
= AF_INET
;
1338 s4
->sin_port
= s6
->sin6_port
;
1339 memcpy(&(s4
->sin_addr
.s_addr
), &(s6
->sin6_addr
.s6_addr
[12]), 4);
1341 i
= getnameinfo((const struct sockaddr
*)s4
, s4
->sin_len
, host
, hostlen
, serv
, servlen
, flags
);
1348 if ((host
!= NULL
) && (hostlen
!= 0)) wanth
= 1;
1351 if ((serv
!= NULL
) && (servlen
!= 0)) wants
= 1;
1353 if ((wanth
== 0) && (wants
== 0)) return 0;
1356 * Special cases handled by the library
1358 if ((wanth
== 1) && (flags
& NI_NUMERICHOST
))
1360 i
= INET_NTOP_AF_INET_OFFSET
;
1361 if (sa
->sa_family
== PF_INET6
) i
= INET_NTOP_AF_INET6_OFFSET
;
1362 if (inet_ntop(sa
->sa_family
, (char *)(sa
) + i
, host
, hostlen
) == NULL
) return EAI_FAIL
;
1364 if (wants
== 0) return 0;
1367 if ((wants
== 1) && (flags
& NI_NUMERICSERV
))
1369 if (sa
->sa_family
== PF_INET
)
1371 s4
= (struct sockaddr_in
*)sa
;
1372 n
= snprintf(serv
, servlen
, "%hu", ntohs(s4
->sin_port
));
1373 if (n
>= servlen
) return EAI_FAIL
;
1375 else if (sa
->sa_family
== PF_INET6
)
1377 s6
= (struct sockaddr_in6
*)sa
;
1378 n
= snprintf(serv
, servlen
, "%hu", ntohs(s6
->sin6_port
));
1379 if (n
>= servlen
) return EAI_FAIL
;
1381 else return EAI_FAMILY
;
1383 if (wanth
== 0) return 0;
1386 if ((wanth
== 1) && (flags
& NI_NUMERICHOST
) && (wants
== 1) && (flags
& NI_NUMERICSERV
)) return 0;
1391 server_port
= MACH_PORT_NULL
;
1392 if (_lu_running()) server_port
= _lookupd_port(0);
1393 if (server_port
== MACH_PORT_NULL
) return EAI_SYSTEM
;
1397 status
= _lookup_link(server_port
, "getnameinfo", &gni_proc
);
1398 if (status
!= KERN_SUCCESS
) return EAI_SYSTEM
;
1401 qlen
= LU_QBUF_SIZE
;
1402 i
= gni_make_query(sa
, salen
, wanth
, wants
, flags
, qbuf
, &qlen
);
1403 if (i
!= 0) return EAI_SYSTEM
;
1405 qlen
/= BYTES_PER_XDR_UNIT
;
1409 status
= _lookup_all(server_port
, gni_proc
, (unit
*)qbuf
, qlen
, &rbuf
, &rlen
);
1410 if (status
!= KERN_SUCCESS
) return EAI_NONAME
;
1412 rlen
*= BYTES_PER_XDR_UNIT
;
1414 xdrmem_create(&inxdr
, rbuf
, rlen
, XDR_DECODE
);
1416 if (!xdr_int(&inxdr
, &n
))
1418 xdr_destroy(&inxdr
);
1424 xdr_destroy(&inxdr
);
1431 i
= gni_lookupd_process_dictionary(&inxdr
, &hval
, &sval
);
1433 xdr_destroy(&inxdr
);
1434 if (rbuf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)rbuf
, rlen
);
1436 if (i
!= 0) return i
;
1439 if (hval
!= NULL
) i
= strlen(hval
) + 1;
1440 if ((host
!= NULL
) && (hostlen
!= 0) && (i
!= 0))
1442 if (i
> hostlen
) return EAI_FAIL
;
1443 memcpy(host
, hval
, i
);
1448 if (sval
!= NULL
) i
= strlen(sval
) + 1;
1449 if ((serv
!= NULL
) && (servlen
!= 0) && (i
!= 0))
1451 if (i
> servlen
) return EAI_FAIL
;
1452 memcpy(serv
, sval
, i
);
1460 getnameinfo_async_start(mach_port_t
*p
, const struct sockaddr
*sa
, size_t salen
, int flags
, getnameinfo_async_callback callback
, void *context
)
1463 char qbuf
[LU_QBUF_SIZE
];
1464 mach_port_t server_port
;
1465 kern_return_t status
;
1468 if (sa
== NULL
) return EAI_FAIL
;
1470 server_port
= MACH_PORT_NULL
;
1471 if (_lu_running()) server_port
= _lookupd_port(0);
1472 if (server_port
== MACH_PORT_NULL
) return EAI_SYSTEM
;
1476 status
= _lookup_link(server_port
, "getnameinfo", &gni_proc
);
1477 if (status
!= KERN_SUCCESS
) return EAI_SYSTEM
;
1480 qlen
= LU_QBUF_SIZE
;
1481 i
= gni_make_query(sa
, salen
, 1, 1, flags
, qbuf
, &qlen
);
1482 if (i
!= 0) return EAI_SYSTEM
;
1484 qlen
/= BYTES_PER_XDR_UNIT
;
1486 return lu_async_start(p
, gni_proc
, qbuf
, qlen
, (void *)callback
, context
);
1490 getnameinfo_async_send(mach_port_t
*p
, const struct sockaddr
*sa
, size_t salen
, int flags
)
1492 return getnameinfo_async_start(p
, sa
, salen
, flags
, NULL
, NULL
);
1496 gni_extract_data(char *buf
, uint32_t len
, char **host
, char **serv
)
1504 if (buf
== NULL
) return EAI_NODATA
;
1505 if (len
== 0) return EAI_NODATA
;
1507 xdrmem_create(&xdr
, buf
, len
, XDR_DECODE
);
1509 if (!xdr_int(&xdr
, &n
))
1521 return gni_lookupd_process_dictionary(&xdr
, host
, serv
);
1525 getnameinfo_async_receive(mach_port_t p
, char **host
, char **serv
)
1527 kern_return_t status
;
1534 status
= lu_async_receive(p
, &buf
, &len
);
1535 if (status
< 0) return EAI_FAIL
;
1537 status
= gni_extract_data(buf
, len
, host
, serv
);
1538 if (buf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)buf
, len
);
1539 if (status
!= 0) return status
;
1545 getnameinfo_async_handle_reply(void *msg
)
1547 getnameinfo_async_callback callback
;
1549 char *buf
, *hval
, *sval
;
1553 callback
= (getnameinfo_async_callback
)NULL
;
1558 status
= lu_async_handle_reply(msg
, &buf
, &len
, (void **)&callback
, &context
);
1559 if (status
!= KERN_SUCCESS
)
1561 if (status
== MIG_REPLY_MISMATCH
) return 0;
1562 if (callback
!= NULL
) callback(EAI_SYSTEM
, NULL
, NULL
, context
);
1569 status
= gni_extract_data(buf
, len
, &hval
, &sval
);
1570 if (buf
!= NULL
) vm_deallocate(mach_task_self(), (vm_address_t
)buf
, len
);
1573 if (callback
!= NULL
) callback(status
, NULL
, NULL
, context
);
1577 callback(0, hval
, sval
, context
);