2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/types.h>
29 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #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 MAX_LOOKUP_ATTEMPTS 10
51 #define INET_NTOP_AF_INET_OFFSET 4
52 #define INET_NTOP_AF_INET6_OFFSET 8
54 static int gai_proc
= -1;
55 static int gni_proc
= -1;
57 static const int32_t supported_family
[] =
63 static const int32_t supported_family_count
= (sizeof(supported_family
) / sizeof(supported_family
[0]));
65 static const int32_t supported_socket
[] =
72 static const int32_t supported_socket_count
= (sizeof(supported_socket
) / sizeof(supported_socket
[0]));
74 static const int32_t supported_protocol
[] =
82 static const int32_t supported_protocol_count
= (sizeof(supported_protocol
) / sizeof(supported_protocol
[0]));
84 static const int32_t supported_socket_protocol_pair
[] =
86 SOCK_RAW
, IPPROTO_UNSPEC
,
87 SOCK_RAW
, IPPROTO_UDP
,
88 SOCK_RAW
, IPPROTO_TCP
,
89 SOCK_RAW
, IPPROTO_ICMP
,
90 SOCK_RAW
, IPPROTO_ICMPV6
,
91 SOCK_UNSPEC
, IPPROTO_UNSPEC
,
92 SOCK_UNSPEC
, IPPROTO_UDP
,
93 SOCK_UNSPEC
, IPPROTO_TCP
,
94 SOCK_UNSPEC
, IPPROTO_ICMP
,
95 SOCK_UNSPEC
, IPPROTO_ICMPV6
,
96 SOCK_DGRAM
, IPPROTO_UNSPEC
,
97 SOCK_DGRAM
, IPPROTO_UDP
,
98 SOCK_STREAM
, IPPROTO_UNSPEC
,
99 SOCK_STREAM
, IPPROTO_TCP
101 static const int32_t supported_socket_protocol_pair_count
= (sizeof(supported_socket_protocol_pair
) / (sizeof(supported_socket_protocol_pair
[0]) * 2));
104 gai_family_type_check(int32_t f
)
108 for (i
= 0; i
< supported_family_count
; i
++)
110 if (f
== supported_family
[i
]) return 0;
117 gai_socket_type_check(int32_t s
)
121 for (i
= 0; i
< supported_socket_count
; i
++)
123 if (s
== supported_socket
[i
]) return 0;
130 gai_protocol_type_check(int32_t p
)
134 for (i
= 0; i
< supported_protocol_count
; i
++)
136 if (p
== supported_protocol
[i
]) return 0;
143 gai_socket_protocol_type_check(int32_t s
, int32_t p
)
145 int32_t i
, j
, ss
, sp
;
147 for (i
= 0, j
= 0; i
< supported_socket_protocol_pair_count
; i
++, j
+=2)
149 ss
= supported_socket_protocol_pair
[j
];
150 sp
= supported_socket_protocol_pair
[j
+1];
151 if ((s
== ss
) && (p
== sp
)) return 0;
158 gai_strerror(int32_t err
)
162 case EAI_ADDRFAMILY
: return "Address family for nodename not supported";
163 case EAI_AGAIN
: return "Temporary failure in name resolution";
164 case EAI_BADFLAGS
: return "Invalid value for ai_flags";
165 case EAI_FAIL
: return "Non-recoverable failure in name resolution";
166 case EAI_FAMILY
: return "ai_family not supported";
167 case EAI_MEMORY
: return "Memory allocation failure";
168 case EAI_NODATA
: return "No address associated with nodename";
169 case EAI_NONAME
: return "nodename nor servname provided, or not known";
170 case EAI_SERVICE
: return "servname not supported for ai_socktype";
171 case EAI_SOCKTYPE
: return "ai_socktype not supported";
172 case EAI_SYSTEM
: return "System error";
173 case EAI_BADHINTS
: return "Bad hints";
174 case EAI_PROTOCOL
: return "ai_protocol not supported";
177 return "Unknown error";
181 append_addrinfo(struct addrinfo
**l
, struct addrinfo
*a
)
185 if (l
== NULL
) return;
186 if (a
== NULL
) return;
196 if (a
->ai_family
== PF_INET6
)
198 if (x
->ai_family
== PF_INET
)
205 while ((x
->ai_next
!= NULL
) && (x
->ai_next
->ai_family
!= PF_INET
)) x
= x
->ai_next
;
206 a
->ai_next
= x
->ai_next
;
211 while (x
->ai_next
!= NULL
) x
= x
->ai_next
;
218 freeaddrinfo(struct addrinfo
*a
)
220 struct addrinfo
*next
;
225 if (a
->ai_addr
!= NULL
) free(a
->ai_addr
);
226 if (a
->ai_canonname
!= NULL
) free(a
->ai_canonname
);
232 static struct addrinfo
*
233 new_addrinfo_v4(int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in_addr addr
, uint32_t iface
, const char *cname
)
236 struct sockaddr_in
*sa
;
239 a
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
240 if (a
== NULL
) return NULL
;
245 a
->ai_family
= PF_INET
;
246 a
->ai_socktype
= sock
;
247 a
->ai_protocol
= proto
;
249 a
->ai_addrlen
= sizeof(struct sockaddr_in
);
251 sa
= (struct sockaddr_in
*)calloc(1, a
->ai_addrlen
);
258 sa
->sin_len
= a
->ai_addrlen
;
259 sa
->sin_family
= PF_INET
;
260 sa
->sin_port
= htons(port
);
263 /* Kludge: Jam the interface number into sin_zero. */
264 memmove(sa
->sin_zero
, &iface
, sizeof(uint32_t));
266 a
->ai_addr
= (struct sockaddr
*)sa
;
270 len
= strlen(cname
) + 1;
271 a
->ai_canonname
= malloc(len
);
272 memmove(a
->ai_canonname
, cname
, len
);
278 static struct addrinfo
*
279 new_addrinfo_v6(int32_t flags
, int32_t sock
, int32_t proto
, uint16_t port
, struct in6_addr addr
, uint16_t scopeid
, const char *cname
)
282 struct sockaddr_in6
*sa
;
286 a
= (struct addrinfo
*)calloc(1, sizeof(struct addrinfo
));
287 if (a
== NULL
) return NULL
;
292 a
->ai_family
= PF_INET6
;
293 a
->ai_socktype
= sock
;
294 a
->ai_protocol
= proto
;
296 a
->ai_addrlen
= sizeof(struct sockaddr_in6
);
298 sa
= (struct sockaddr_in6
*)calloc(1, a
->ai_addrlen
);
305 sa
->sin6_len
= a
->ai_addrlen
;
306 sa
->sin6_family
= PF_INET6
;
307 sa
->sin6_port
= htons(port
);
308 sa
->sin6_addr
= addr
;
310 /* sin6_scope_id is in host byte order */
311 sa
->sin6_scope_id
= scopeid
;
313 a
->ai_addr
= (struct sockaddr
*)sa
;
315 if (IN6_IS_ADDR_LINKLOCAL(&sa
->sin6_addr
))
317 /* check for embedded scopeid */
318 esid
= ntohs(sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
321 sa
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
322 if (scopeid
== 0) sa
->sin6_scope_id
= esid
;
328 len
= strlen(cname
) + 1;
329 a
->ai_canonname
= malloc(len
);
330 memmove(a
->ai_canonname
, cname
, len
);
339 * Input dict may contain the following
343 * protocol: [IPPROTO_UNSPEC] | IPPROTO_UDP | IPPROTO_TCP
344 * socktype: [SOCK_UNSPEC] | SOCK_DGRAM | SOCK_STREAM
345 * family: [PF_UNSPEC] | PF_INET | PF_INET6
348 * numerichost: [0] | 1
350 * Output dictionary may contain the following
351 * All values are encoded as strings.
353 * flags: unsigned long
354 * family: unsigned long
355 * socktype: unsigned long
356 * protocol: unsigned long
357 * port: unsigned long
359 * scopeid: unsigned long
364 static struct addrinfo
*
365 gai_extract(kvarray_t
*in
)
367 uint32_t d
, k
, kcount
;
368 uint32_t flags
, family
, socktype
, protocol
, port32
;
369 uint16_t port
, scopeid
;
370 const char *addr
, *canonname
;
377 socktype
= SOCK_UNSPEC
;
378 protocol
= IPPROTO_UNSPEC
;
384 if (in
== NULL
) return NULL
;
389 if (d
>= in
->count
) return NULL
;
391 kcount
= in
->dict
[d
].kcount
;
393 for (k
= 0; k
< kcount
; k
++)
395 if (!strcmp(in
->dict
[d
].key
[k
], "gai_flags"))
397 if (in
->dict
[d
].vcount
[k
] == 0) continue;
398 flags
= atoi(in
->dict
[d
].val
[k
][0]);
400 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_family"))
402 if (in
->dict
[d
].vcount
[k
] == 0) continue;
403 family
= atoi(in
->dict
[d
].val
[k
][0]);
405 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_socktype"))
407 if (in
->dict
[d
].vcount
[k
] == 0) continue;
408 socktype
= atoi(in
->dict
[d
].val
[k
][0]);
410 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_protocol"))
412 if (in
->dict
[d
].vcount
[k
] == 0) continue;
413 protocol
= atoi(in
->dict
[d
].val
[k
][0]);
415 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_port"))
417 if (in
->dict
[d
].vcount
[k
] == 0) continue;
418 port32
= atoi(in
->dict
[d
].val
[k
][0]);
421 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_scopeid"))
423 if (in
->dict
[d
].vcount
[k
] == 0) continue;
424 scopeid
= atoi(in
->dict
[d
].val
[k
][0]);
426 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_address"))
428 if (in
->dict
[d
].vcount
[k
] == 0) continue;
429 addr
= in
->dict
[d
].val
[k
][0];
431 else if (!strcmp(in
->dict
[d
].key
[k
], "gai_canonname"))
433 if (in
->dict
[d
].vcount
[k
] == 0) continue;
434 canonname
= in
->dict
[d
].val
[k
][0];
438 if (family
== PF_UNSPEC
) return NULL
;
441 if (family
== PF_INET
)
443 inet_aton(addr
, &a4
);
444 a
= new_addrinfo_v4(flags
, socktype
, protocol
, port
, a4
, scopeid
, canonname
);
446 else if (family
== PF_INET6
)
448 inet_pton(AF_INET6
, addr
, &a6
);
449 a
= new_addrinfo_v6(flags
, socktype
, protocol
, port
, a6
, scopeid
, canonname
);
456 gai_make_query(const char *nodename
, const char *servname
, const struct addrinfo
*hints
)
458 int32_t flags
, family
, proto
, socktype
;
460 char str
[64], *cname
;
462 /* new default for SULeoDeo */
465 proto
= IPPROTO_UNSPEC
;
466 socktype
= SOCK_UNSPEC
;
471 family
= hints
->ai_family
;
472 if (hints
->ai_flags
& AI_NUMERICHOST
) flags
|= AI_NUMERICHOST
;
473 if (hints
->ai_flags
& AI_CANONNAME
) flags
|= AI_CANONNAME
;
474 if (hints
->ai_flags
& AI_PASSIVE
) flags
|= AI_PASSIVE
;
476 proto
= hints
->ai_protocol
;
478 if (hints
->ai_socktype
== SOCK_DGRAM
)
480 socktype
= SOCK_DGRAM
;
484 if (hints
->ai_socktype
== SOCK_STREAM
)
486 socktype
= SOCK_STREAM
;
491 request
= kvbuf_new();
498 kvbuf_add_dict(request
);
500 if (nodename
!= NULL
)
502 kvbuf_add_key(request
, "name");
503 kvbuf_add_val(request
, nodename
);
506 if (servname
!= NULL
)
508 kvbuf_add_key(request
, "service");
509 kvbuf_add_val(request
, servname
);
512 if (proto
!= IPPROTO_UNSPEC
)
514 snprintf(str
, sizeof(str
), "%u", proto
);
515 kvbuf_add_key(request
, "protocol");
516 kvbuf_add_val(request
, str
);
519 if (socktype
!= SOCK_UNSPEC
)
521 snprintf(str
, sizeof(str
), "%u", socktype
);
522 kvbuf_add_key(request
, "socktype");
523 kvbuf_add_val(request
, str
);
526 if (family
!= PF_UNSPEC
)
528 snprintf(str
, sizeof(str
), "%u", family
);
529 kvbuf_add_key(request
, "family");
530 kvbuf_add_val(request
, str
);
533 snprintf(str
, sizeof(str
), "%u", flags
);
534 kvbuf_add_key(request
, "ai_flags");
535 kvbuf_add_val(request
, str
);
541 is_a_number(const char *s
)
545 if (s
== NULL
) return 0;
548 for (i
= 0; i
< len
; i
++)
550 if (isdigit(s
[i
]) == 0) return 0;
557 gai_trivial(struct in_addr
*in4
, struct in6_addr
*in6
, int16_t port
, const struct addrinfo
*hints
, struct addrinfo
**res
)
559 int32_t family
, wantv4
, wantv6
, proto
;
560 char *loopv4
, *loopv6
;
566 if (hints
!= NULL
) family
= hints
->ai_family
;
571 if (family
== PF_INET6
) wantv4
= 0;
572 if (family
== PF_INET
) wantv6
= 0;
574 memset(&a4
, 0, sizeof(struct in_addr
));
575 memset(&a6
, 0, sizeof(struct in6_addr
));
577 if ((in4
== NULL
) && (in6
== NULL
))
579 loopv4
= "127.0.0.1";
580 loopv6
= "0:0:0:0:0:0:0:1";
582 if ((hints
!= NULL
) && ((hints
->ai_flags
& AI_PASSIVE
) == 1))
585 loopv6
= "0:0:0:0:0:0:0:0";
588 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
590 inet_pton(AF_INET
, loopv4
, &a4
);
593 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
595 inet_pton(AF_INET6
, loopv6
, &a6
);
598 else if (in4
== NULL
)
600 if (family
== PF_INET
) return EAI_BADHINTS
;
603 memcpy(&a6
, in6
, sizeof(struct in6_addr
));
605 else if (in6
== NULL
)
607 if (family
== PF_INET6
) return EAI_BADHINTS
;
610 memcpy(&a4
, in4
, sizeof(struct in_addr
));
617 proto
= IPPROTO_UNSPEC
;
621 proto
= hints
->ai_protocol
;
622 if (proto
== IPPROTO_UNSPEC
)
624 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
625 else if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
631 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
633 a
= new_addrinfo_v4(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, NULL
);
634 append_addrinfo(res
, a
);
637 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
639 a
= new_addrinfo_v4(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, NULL
);
640 append_addrinfo(res
, a
);
643 if (proto
== IPPROTO_ICMP
)
645 a
= new_addrinfo_v4(0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, NULL
);
646 append_addrinfo(res
, a
);
652 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
654 a
= new_addrinfo_v6(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, 0, NULL
);
655 append_addrinfo(res
, a
);
658 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
660 a
= new_addrinfo_v6(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, 0, NULL
);
661 append_addrinfo(res
, a
);
664 if (proto
== IPPROTO_ICMPV6
)
666 a
= new_addrinfo_v6(0, SOCK_RAW
, IPPROTO_ICMPV6
, port
, a6
, 0, NULL
);
667 append_addrinfo(res
, a
);
675 gai_files(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
677 int32_t i
, status
, numericserv
, numerichost
, family
, proto
, wantv4
, wantv6
, count
;
682 char *protoname
, *loopv4
, *loopv6
;
691 if (servname
!= NULL
) numericserv
= is_a_number(servname
);
694 if (hints
!= NULL
) family
= hints
->ai_family
;
698 if (nodename
== NULL
)
702 loopv4
= "127.0.0.1";
703 loopv6
= "0:0:0:0:0:0:0:1";
705 if ((hints
!= NULL
) && ((hints
->ai_flags
& AI_PASSIVE
) == 1))
708 loopv6
= "0:0:0:0:0:0:0:0";
711 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
713 inet_pton(AF_INET
, loopv4
, &a4
);
716 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
718 inet_pton(AF_INET6
, loopv6
, &a6
);
723 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
725 status
= inet_pton(AF_INET
, nodename
, &a4
);
729 if (family
== PF_UNSPEC
) family
= PF_INET
;
733 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
735 status
= inet_pton(AF_INET6
, nodename
, &a6
);
739 if (family
== PF_UNSPEC
) family
= PF_INET6
;
740 if ((IN6_IS_ADDR_LINKLOCAL(&a6
)) && (a6
.__u6_addr
.__u6_addr16
[1] != 0))
742 scopeid
= ntohs(a6
.__u6_addr
.__u6_addr16
[1]);
743 a6
.__u6_addr
.__u6_addr16
[1] = 0;
751 if (family
== PF_INET6
) wantv4
= 0;
752 if (family
== PF_INET
) wantv6
= 0;
754 proto
= IPPROTO_UNSPEC
;
759 proto
= hints
->ai_protocol
;
760 if (proto
== IPPROTO_UNSPEC
)
762 if (hints
->ai_socktype
== SOCK_DGRAM
) proto
= IPPROTO_UDP
;
763 else if (hints
->ai_socktype
== SOCK_STREAM
) proto
= IPPROTO_TCP
;
767 if (proto
== IPPROTO_UDP
) protoname
= "udp";
768 else if (proto
== IPPROTO_TCP
) protoname
= "tcp";
773 if (numericserv
!= 0)
775 port
= htons(atoi(servname
));
777 else if (servname
!= NULL
)
779 s
= getservbyname(servname
, protoname
);
780 if (s
!= NULL
) port
= s
->s_port
;
783 /* new_addrinfo_v4 and new_addrinfo_v6 expect port in host byte order */
786 if (numerichost
!= 0)
790 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
792 a
= new_addrinfo_v4(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, NULL
);
793 append_addrinfo(res
, a
);
797 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
799 a
= new_addrinfo_v4(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, NULL
);
800 append_addrinfo(res
, a
);
804 if (proto
== IPPROTO_ICMP
)
806 a
= new_addrinfo_v4(0, SOCK_RAW
, IPPROTO_ICMP
, port
, a4
, 0, NULL
);
807 append_addrinfo(res
, a
);
814 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
816 a
= new_addrinfo_v6(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, scopeid
, NULL
);
817 append_addrinfo(res
, a
);
821 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
823 a
= new_addrinfo_v6(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, scopeid
, NULL
);
824 append_addrinfo(res
, a
);
828 if (proto
== IPPROTO_ICMPV6
)
830 a
= new_addrinfo_v6(0, SOCK_RAW
, IPPROTO_ICMPV6
, port
, a6
, scopeid
, NULL
);
831 append_addrinfo(res
, a
);
836 if (count
== 0) return EAI_AGAIN
;
842 h
= gethostbyname(nodename
);
843 if (h
== NULL
) return EAI_AGAIN
;
845 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
847 memmove((void *)&a4
.s_addr
, h
->h_addr_list
[i
], h
->h_length
);
849 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
851 a
= new_addrinfo_v4(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a4
, 0, NULL
);
852 append_addrinfo(res
, a
);
856 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
858 a
= new_addrinfo_v4(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a4
, 0, NULL
);
859 append_addrinfo(res
, a
);
867 h
= gethostbyname2(nodename
, AF_INET6
);
868 if (h
== NULL
) return EAI_AGAIN
;
870 for (i
= 0; h
->h_addr_list
[i
] != 0; i
++)
872 memmove(&(a6
.__u6_addr
.__u6_addr32
[0]), h
->h_addr_list
[i
], h
->h_length
);
874 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_UDP
))
876 a
= new_addrinfo_v6(0, SOCK_DGRAM
, IPPROTO_UDP
, port
, a6
, 0, NULL
);
877 append_addrinfo(res
, a
);
881 if ((proto
== IPPROTO_UNSPEC
) || (proto
== IPPROTO_TCP
))
883 a
= new_addrinfo_v6(0, SOCK_STREAM
, IPPROTO_TCP
, port
, a6
, 0, NULL
);
884 append_addrinfo(res
, a
);
890 if (count
== 0) return EAI_AGAIN
;
895 ds_getaddrinfo(const char *nodename
, const char *servname
, const struct addrinfo
*hints
, struct addrinfo
**res
)
901 kern_return_t status
;
904 if (_ds_running() == 0)
906 return gai_files(nodename
, servname
, hints
, res
);
911 status
= LI_DSLookupGetProcedureNumber("getaddrinfo", &gai_proc
);
912 if (status
!= KERN_SUCCESS
)
914 errno
= ECONNREFUSED
;
919 request
= gai_make_query(nodename
, servname
, hints
);
920 if (request
== NULL
) return EAI_SYSTEM
;
923 status
= LI_DSLookupQuery(gai_proc
, request
, &reply
);
926 if (status
!= KERN_SUCCESS
)
928 errno
= ECONNREFUSED
;
932 if (reply
== NULL
) return EAI_NONAME
;
935 for (i
= 0; i
< reply
->count
; i
++)
937 a
= gai_extract(reply
);
938 if (a
== NULL
) continue;
939 if ((cname
== NULL
) && (a
->ai_canonname
!= NULL
)) cname
= a
->ai_canonname
;
940 append_addrinfo(res
, a
);
945 if ((cname
!= NULL
) && (res
!= NULL
) && (res
[0] != NULL
) && (res
[0]->ai_canonname
== NULL
))
947 res
[0]->ai_canonname
= strdup(cname
);
954 gai_checkhints(const struct addrinfo
*hints
)
956 if (hints
== NULL
) return 0;
957 if (hints
->ai_addrlen
!= 0) return EAI_BADHINTS
;
958 if (hints
->ai_canonname
!= NULL
) return EAI_BADHINTS
;
959 if (hints
->ai_addr
!= NULL
) return EAI_BADHINTS
;
960 if (hints
->ai_next
!= NULL
) return EAI_BADHINTS
;
962 /* Check for supported protocol family */
963 if (gai_family_type_check(hints
->ai_family
) != 0) return EAI_FAMILY
;
965 /* Check for supported socket */
966 if (gai_socket_type_check(hints
->ai_socktype
) != 0) return EAI_BADHINTS
;
968 /* Check for supported protocol */
969 if (gai_protocol_type_check(hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
971 /* Check that socket type is compatible with protocol */
972 if (gai_socket_protocol_type_check(hints
->ai_socktype
, hints
->ai_protocol
) != 0) return EAI_BADHINTS
;
978 getaddrinfo(const char * __restrict nodename
, const char * __restrict servname
, const struct addrinfo
* __restrict hints
, struct addrinfo
** __restrict res
)
980 int32_t status
, nodenull
, servnull
;
981 int32_t numericserv
, numerichost
, family
;
983 struct in_addr a4
, *p4
;
984 struct in6_addr a6
, *p6
;
986 if (res
== NULL
) return 0;
991 if ((nodename
== NULL
) || (nodename
[0] == '\0')) nodenull
= 1;
994 if ((servname
== NULL
) || (servname
[0] == '\0')) servnull
= 1;
996 if ((nodenull
== 1) && (servnull
== 1)) return EAI_NONAME
;
998 status
= gai_checkhints(hints
);
999 if (status
!= 0) return status
;
1002 * Trap the "trivial" cases that can be answered without a query.
1003 * (nodename == numeric) && (servname == NULL)
1004 * (nodename == numeric) && (servname == numeric)
1005 * (nodename == NULL) && (servname == numeric)
1010 memset(&a4
, 0, sizeof(struct in_addr
));
1011 memset(&a6
, 0, sizeof(struct in6_addr
));
1015 if (servnull
== 0) numericserv
= is_a_number(servname
);
1016 if (numericserv
== 1) port
= atoi(servname
);
1019 if (hints
!= NULL
) family
= hints
->ai_family
;
1024 if ((family
== PF_UNSPEC
) || (family
== PF_INET
))
1026 status
= inet_pton(AF_INET
, nodename
, &a4
);
1034 if ((family
== PF_UNSPEC
) || (family
== PF_INET6
))
1036 status
= inet_pton(AF_INET6
, nodename
, &a6
);
1045 if ((nodenull
== 1) && (numericserv
== 1)) return gai_trivial(NULL
, NULL
, port
, hints
, res
);
1046 if ((numerichost
== 1) && (numericserv
== 1)) return gai_trivial(p4
, p6
, port
, hints
, res
);
1047 if ((numerichost
== 1) && (servnull
== 1)) return gai_trivial(p4
, p6
, 0, hints
, res
);
1049 if (nodenull
== 1) status
= ds_getaddrinfo(NULL
, servname
, hints
, res
);
1050 else if (servnull
== 1) status
= ds_getaddrinfo(nodename
, NULL
, hints
, res
);
1051 else status
= ds_getaddrinfo(nodename
, servname
, hints
, res
);
1053 if ((status
== 0) && (*res
== NULL
)) status
= EAI_NONAME
;
1059 getaddrinfo_async_start(mach_port_t
*p
, const char *nodename
, const char *servname
, const struct addrinfo
*hints
, getaddrinfo_async_callback callback
, void *context
)
1064 *p
= MACH_PORT_NULL
;
1066 if ((nodename
== NULL
) && (servname
== NULL
)) return EAI_NONAME
;
1068 status
= gai_checkhints(hints
);
1069 if (status
!= 0) return EAI_BADHINTS
;
1073 status
= LI_DSLookupGetProcedureNumber("getaddrinfo", &gai_proc
);
1074 if (status
!= KERN_SUCCESS
)
1076 errno
= ECONNREFUSED
;
1081 request
= gai_make_query(nodename
, servname
, hints
);
1082 if (request
== NULL
) return EAI_SYSTEM
;
1084 status
= LI_async_start(p
, gai_proc
, request
, (void *)callback
, context
);
1086 kvbuf_free(request
);
1088 if (status
!= KERN_SUCCESS
)
1090 errno
= ECONNREFUSED
;
1098 getaddrinfo_async_cancel(mach_port_t p
)
1100 LI_async_call_cancel(p
, NULL
);
1104 getaddrinfo_async_send(mach_port_t
*p
, const char *nodename
, const char *servname
, const struct addrinfo
*hints
)
1106 return getaddrinfo_async_start(p
, nodename
, servname
, hints
, NULL
, NULL
);
1110 getaddrinfo_async_receive(mach_port_t p
, struct addrinfo
**res
)
1112 kern_return_t status
;
1118 if (res
== NULL
) return 0;
1123 status
= LI_async_receive(p
, &reply
);
1124 if (status
< 0) return EAI_FAIL
;
1125 if (reply
== NULL
) return EAI_NONAME
;
1128 for (i
= 0; i
< reply
->count
; i
++)
1130 a
= gai_extract(reply
);
1131 if (a
== NULL
) continue;
1132 if ((cname
== NULL
) && (a
->ai_canonname
!= NULL
)) cname
= a
->ai_canonname
;
1133 append_addrinfo(res
, a
);
1136 kvarray_free(reply
);
1138 if ((cname
!= NULL
) && (res
!= NULL
) && (res
[0] != NULL
) && (res
[0]->ai_canonname
== NULL
))
1140 res
[0]->ai_canonname
= strdup(cname
);
1144 if (*res
== NULL
) return EAI_NONAME
;
1150 getaddrinfo_async_handle_reply(void *msg
)
1152 getaddrinfo_async_callback callback
;
1158 struct addrinfo
*l
, *a
, **res
;
1160 callback
= (getaddrinfo_async_callback
)NULL
;
1168 status
= LI_async_handle_reply(msg
, &reply
, (void **)&callback
, &context
);
1169 if (status
!= KERN_SUCCESS
)
1171 if (status
== MIG_REPLY_MISMATCH
) return 0;
1172 if (callback
!= NULL
) callback(EAI_FAIL
, NULL
, context
);
1178 if (callback
!= NULL
) callback(EAI_NONAME
, NULL
, context
);
1183 for (i
= 0; i
< reply
->count
; i
++)
1185 a
= gai_extract(reply
);
1186 if (a
== NULL
) continue;
1187 if ((cname
== NULL
) && (a
->ai_canonname
!= NULL
)) cname
= a
->ai_canonname
;
1188 append_addrinfo(res
, a
);
1191 kvarray_free(reply
);
1193 if ((cname
!= NULL
) && (res
[0] != NULL
) && (res
[0]->ai_canonname
== NULL
))
1195 res
[0]->ai_canonname
= strdup(cname
);
1200 callback(EAI_NONAME
, NULL
, context
);
1204 callback(0, *res
, context
);
1213 * getnameinfo support in Directory Service
1214 * Input dict may contain the following
1216 * ip_address: node address
1217 * ipv6_address: node address
1218 * port: service number
1219 * protocol: [tcp] | udp
1221 * numerichost: [0] | 1
1222 * name_required: [0] | 1
1223 * numericserv: [0] | 1
1225 * Output dictionary may contain the following
1226 * All values are encoded as strings.
1233 gni_extract(kvarray_t
*in
, const char **host
, const char **serv
)
1235 uint32_t d
, k
, kcount
;
1237 if (in
== NULL
) return -1;
1239 if ((host
== NULL
) || (serv
== NULL
))
1251 if (d
>= in
->count
) return EAI_NONAME
;
1253 kcount
= in
->dict
[d
].kcount
;
1254 if (kcount
== 0) return EAI_NONAME
;
1256 for (k
= 0; k
< kcount
; k
++)
1258 if (!strcmp(in
->dict
[d
].key
[k
], "gni_name"))
1260 if (in
->dict
[d
].vcount
[k
] == 0) continue;
1261 if (*host
!= NULL
) continue;
1263 *host
= in
->dict
[d
].val
[k
][0];
1265 else if (!strcmp(in
->dict
[d
].key
[k
], "gni_service"))
1267 if (in
->dict
[d
].vcount
[k
] == 0) continue;
1268 if (*serv
!= NULL
) continue;
1270 *serv
= in
->dict
[d
].val
[k
][0];
1274 if ((*host
== NULL
) && (*serv
== NULL
)) return EAI_NONAME
;
1279 gni_make_query(const struct sockaddr
*sa
, size_t salen
, int wanthost
, int wantserv
, int flags
)
1282 uint16_t port
, ifnum
;
1283 char str
[NI_MAXHOST
], ifname
[IF_NAMESIZE
], tmp
[64];
1284 uint32_t a4
, offset
, isll
;
1285 struct sockaddr_in6
*s6
;
1293 if (sa
->sa_len
!= salen
)
1301 offset
= INET_NTOP_AF_INET_OFFSET
;
1304 if (sa
->sa_family
== PF_INET
)
1306 a4
= ntohl(((const struct sockaddr_in
*)sa
)->sin_addr
.s_addr
);
1307 if (IN_MULTICAST(a4
) || IN_EXPERIMENTAL(a4
)) flags
|= NI_NUMERICHOST
;
1308 a4
>>= IN_CLASSA_NSHIFT
;
1309 if (a4
== 0) flags
|= NI_NUMERICHOST
;
1311 port
= ntohs(((struct sockaddr_in
*)sa
)->sin_port
);
1313 else if (sa
->sa_family
== PF_INET6
)
1315 s6
= (struct sockaddr_in6
*)sa
;
1316 switch (s6
->sin6_addr
.s6_addr
[0])
1320 if (IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
1323 else if (IN6_IS_ADDR_LOOPBACK(&s6
->sin6_addr
))
1328 flags
|= NI_NUMERICHOST
;
1334 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
))
1338 else if (IN6_IS_ADDR_MULTICAST(&s6
->sin6_addr
))
1340 flags
|= NI_NUMERICHOST
;
1348 ifnum
= ntohs(s6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
1349 if (ifnum
== 0) ifnum
= s6
->sin6_scope_id
;
1350 else if ((s6
->sin6_scope_id
!= 0) && (ifnum
!= s6
->sin6_scope_id
))
1356 s6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1357 s6
->sin6_scope_id
= ifnum
;
1358 if ((ifnum
!= 0) && (flags
& NI_NUMERICHOST
)) flags
|= NI_WITHSCOPEID
;
1361 offset
= INET_NTOP_AF_INET6_OFFSET
;
1362 port
= ntohs(s6
->sin6_port
);
1366 errno
= EPFNOSUPPORT
;
1370 request
= kvbuf_new();
1371 if (request
== NULL
)
1377 kvbuf_add_dict(request
);
1381 inet_ntop(sa
->sa_family
, (char *)(sa
) + offset
, str
, NI_MAXHOST
);
1385 ifnum
= ((struct sockaddr_in6
*)sa
)->sin6_scope_id
;
1386 if ((ifnum
!= 0) && (if_indextoname(ifnum
, ifname
) != NULL
))
1389 strcat(str
, ifname
);
1393 kvbuf_add_key(request
, "address");
1394 kvbuf_add_val(request
, str
);
1396 kvbuf_add_key(request
, "family");
1397 snprintf(tmp
, sizeof(tmp
), "%u", sa
->sa_family
);
1398 kvbuf_add_val(request
, tmp
);
1403 snprintf(tmp
, sizeof(tmp
), "%hu", port
);
1404 kvbuf_add_key(request
, "port");
1405 kvbuf_add_val(request
, tmp
);
1408 snprintf(tmp
, sizeof(tmp
), "%u", flags
);
1409 kvbuf_add_key(request
, "flags");
1410 kvbuf_add_val(request
, tmp
);
1416 getnameinfo(const struct sockaddr
* __restrict sa
, socklen_t salen
, char * __restrict host
, socklen_t hostlen
, char * __restrict serv
, socklen_t servlen
, int flags
)
1418 uint32_t n
, i
, ifnum
;
1419 int wanth
, wants
, isll
;
1422 char ifname
[IF_NAMESIZE
];
1423 const char *hval
, *sval
;
1424 kern_return_t status
;
1425 struct sockaddr_in
*s4
, s4buf
;
1426 struct sockaddr_in6
*s6
, s6buf
;
1428 struct in6_addr
*a6
;
1431 if (sa
== NULL
) return EAI_FAIL
;
1442 if (sa
->sa_family
== AF_INET
)
1444 memcpy(s4
, sa
, sizeof(struct sockaddr_in
));
1445 a4
= &(s4
->sin_addr
);
1447 else if (sa
->sa_family
== AF_INET6
)
1449 memcpy(s6
, sa
, sizeof(struct sockaddr_in6
));
1450 a6
= &(s6
->sin6_addr
);
1452 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
)) isll
= 1;
1455 * Link-local IPv6 addresses may have a scope id
1456 * in s6->sin6_addr.__u6_addr.__u6_addr16[1] as well as in s6->sin6_scope_id.
1457 * If they are both non-zero, they must be equal.
1458 * We zero s6->sin6_addr.__u6_addr.__u6_addr16[1] and set s6->sin6_scope_id.
1462 ifnum
= ntohs(s6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
1463 if (ifnum
== 0) ifnum
= s6
->sin6_scope_id
;
1464 else if ((s6
->sin6_scope_id
!= 0) && (ifnum
!= s6
->sin6_scope_id
)) return EAI_FAIL
;
1466 s6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
1467 s6
->sin6_scope_id
= ifnum
;
1470 /* V4 mapped and compat addresses are converted to plain V4 */
1471 if ((IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
)) || (IN6_IS_ADDR_V4COMPAT(&s6
->sin6_addr
)))
1473 memset(s4
, 0, sizeof(struct sockaddr_in
));
1475 s4
->sin_len
= sizeof(struct sockaddr_in
);
1476 s4
->sin_family
= AF_INET
;
1477 s4
->sin_port
= s6
->sin6_port
;
1478 memcpy(&(s4
->sin_addr
.s_addr
), &(s6
->sin6_addr
.s6_addr
[12]), 4);
1480 return getnameinfo((const struct sockaddr
*)s4
, s4
->sin_len
, host
, hostlen
, serv
, servlen
, flags
);
1483 else return EAI_FAMILY
;
1486 if ((host
!= NULL
) && (hostlen
!= 0)) wanth
= 1;
1489 if ((serv
!= NULL
) && (servlen
!= 0)) wants
= 1;
1491 if ((wanth
== 0) && (wants
== 0)) return 0;
1494 * Special cases handled by the library
1496 if ((wanth
== 1) && (flags
& NI_NUMERICHOST
))
1498 if (sa
->sa_family
== AF_INET
)
1500 if (inet_ntop(AF_INET
, a4
, host
, hostlen
) == NULL
) return EAI_FAIL
;
1504 if (inet_ntop(AF_INET6
, a6
, host
, hostlen
) == NULL
) return EAI_FAIL
;
1507 if ((isll
!= 0) && (ifnum
!= 0))
1509 /* append interface name */
1510 if (if_indextoname(ifnum
, ifname
) != NULL
)
1513 strcat(host
, ifname
);
1517 if (wants
== 0) return 0;
1520 if ((wants
== 1) && (flags
& NI_NUMERICSERV
))
1522 if (sa
->sa_family
== PF_INET
)
1524 n
= snprintf(serv
, servlen
, "%hu", ntohs(s4
->sin_port
));
1525 if (n
>= servlen
) return EAI_FAIL
;
1529 n
= snprintf(serv
, servlen
, "%hu", ntohs(s6
->sin6_port
));
1530 if (n
>= servlen
) return EAI_FAIL
;
1533 if (wanth
== 0) return 0;
1536 if ((wanth
== 1) && (flags
& NI_NUMERICHOST
) && (wants
== 1) && (flags
& NI_NUMERICSERV
)) return 0;
1538 if (_ds_running() == 0)
1540 errno
= ECONNREFUSED
;
1546 status
= LI_DSLookupGetProcedureNumber("getnameinfo", &gni_proc
);
1547 if (status
!= KERN_SUCCESS
)
1549 errno
= ECONNREFUSED
;
1554 request
= gni_make_query(sa
, salen
, wanth
, wants
, flags
);
1555 if (request
== NULL
) return EAI_SYSTEM
;
1558 status
= LI_DSLookupQuery(gni_proc
, request
, &reply
);
1559 kvbuf_free(request
);
1561 if (status
!= KERN_SUCCESS
)
1563 errno
= ECONNREFUSED
;
1567 if (reply
== NULL
) return EAI_NONAME
;
1572 status
= gni_extract(reply
, &hval
, &sval
);
1576 kvarray_free(reply
);
1581 if (hval
!= NULL
) i
= strlen(hval
) + 1;
1582 if ((host
!= NULL
) && (hostlen
!= 0) && (i
!= 0))
1586 kvarray_free(reply
);
1590 memcpy(host
, hval
, i
);
1594 if (sval
!= NULL
) i
= strlen(sval
) + 1;
1595 if ((serv
!= NULL
) && (servlen
!= 0) && (i
!= 0))
1599 kvarray_free(reply
);
1603 memcpy(serv
, sval
, i
);
1606 kvarray_free(reply
);
1611 getnameinfo_async_start(mach_port_t
*p
, const struct sockaddr
*sa
, size_t salen
, int flags
, getnameinfo_async_callback callback
, void *context
)
1616 *p
= MACH_PORT_NULL
;
1619 if (sa
== NULL
) return EAI_FAIL
;
1623 status
= LI_DSLookupGetProcedureNumber("getnameinfo", &gni_proc
);
1624 if (status
!= KERN_SUCCESS
)
1626 errno
= ECONNREFUSED
;
1631 request
= gni_make_query(sa
, salen
, 1, 1, flags
);
1632 if (request
== NULL
) return EAI_SYSTEM
;
1634 status
= LI_async_start(p
, gni_proc
, request
, (void *)callback
, context
);
1636 kvbuf_free(request
);
1638 if (status
!= KERN_SUCCESS
)
1640 errno
= ECONNREFUSED
;
1648 getnameinfo_async_cancel(mach_port_t p
)
1650 LI_async_call_cancel(p
, NULL
);
1654 getnameinfo_async_send(mach_port_t
*p
, const struct sockaddr
*sa
, size_t salen
, int flags
)
1656 return getnameinfo_async_start(p
, sa
, salen
, flags
, NULL
, NULL
);
1660 getnameinfo_async_receive(mach_port_t p
, char **host
, char **serv
)
1662 kern_return_t status
;
1663 const char *hval
, *sval
;
1668 status
= LI_async_receive(p
, &reply
);
1669 if (status
< 0) return EAI_FAIL
;
1670 if (reply
== NULL
) return EAI_NONAME
;
1675 status
= gni_extract(reply
, &hval
, &sval
);
1678 kvarray_free(reply
);
1682 if (hval
!= NULL
) *host
= strdup(hval
);
1683 if (sval
!= NULL
) *serv
= strdup(sval
);
1685 kvarray_free(reply
);
1690 getnameinfo_async_handle_reply(void *msg
)
1692 getnameinfo_async_callback callback
;
1694 const char *hval
, *sval
;
1700 callback
= (getnameinfo_async_callback
)NULL
;
1705 status
= LI_async_handle_reply(msg
, &reply
, (void **)&callback
, &context
);
1706 if ((status
!= KERN_SUCCESS
) || (reply
== NULL
))
1708 if (status
== MIG_REPLY_MISMATCH
) return 0;
1709 if (callback
!= NULL
) callback(EAI_NONAME
, NULL
, NULL
, context
);
1716 status
= gni_extract(reply
, &hval
, &sval
);
1719 if (callback
!= NULL
) callback(status
, NULL
, NULL
, context
);
1720 kvarray_free(reply
);
1727 if (hval
!= NULL
) host
= strdup(hval
);
1728 if (sval
!= NULL
) serv
= strdup(sval
);
1729 kvarray_free(reply
);
1731 callback(0, host
, serv
, context
);