From f19b8b3a0c164ced08dbb5645b2f1f322c1a5128 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 12 Aug 2010 22:23:36 +0000 Subject: [PATCH] Libinfo-330.7.tar.gz --- lookup.subproj/mdns_module.c | 85 ++++++++++------- lookup.subproj/si_getaddrinfo.c | 158 ++++++++++++++++++++++++++++---- 2 files changed, 191 insertions(+), 52 deletions(-) diff --git a/lookup.subproj/mdns_module.c b/lookup.subproj/mdns_module.c index a67ef54..5a216a8 100644 --- a/lookup.subproj/mdns_module.c +++ b/lookup.subproj/mdns_module.c @@ -178,9 +178,10 @@ typedef struct { DNSServiceRef _mdns_sdref; DNSServiceRef _mdns_old_sdref; -static int _mdns_query_mDNSResponder(const char *name, int class, int type, const char *interface, - uint8_t *answer, uint32_t *anslen, - mdns_reply_t *reply, uint32_t timeout); +static int _mdns_query_mDNSResponder(const char *name, int class, int type, + const char *interface, DNSServiceFlags flags, + uint8_t *answer, uint32_t *anslen, + mdns_reply_t *reply, uint32_t timeout); static int _mdns_resolver_get_option(dns_resolver_t *resolver, const char* option); static void _mdns_hostent_clear(mdns_hostent_t *h); @@ -564,7 +565,7 @@ _mdns_timeout_for_name(mdns_config_t *config, const char *name) * of the default resolver's domains). */ static int -_mdns_query_unqualified(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) +_mdns_query_unqualified(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) { int i, res = -1; @@ -573,7 +574,7 @@ _mdns_query_unqualified(mdns_config_t *config, const char *name, uint32_t class, char *qname; asprintf(&qname, "%s.%s", name, resolver->domain ? resolver->domain : ""); - res = _mdns_query_mDNSResponder(qname, class, type, interface, buf, len, reply, resolver->timeout); + res = _mdns_query_mDNSResponder(qname, class, type, interface, flags, buf, len, reply, resolver->timeout); free(qname); if (res == 0) break; @@ -587,7 +588,7 @@ _mdns_query_unqualified(mdns_config_t *config, const char *name, uint32_t class, * additional domains). */ static int -_mdns_query_absolute(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, uint32_t fqdn, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) +_mdns_query_absolute(mdns_config_t *config, const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint32_t fqdn, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) { int res = -1; char *qname = (char *)name; @@ -595,14 +596,14 @@ _mdns_query_absolute(mdns_config_t *config, const char *name, uint32_t class, ui uint32_t timeout = _mdns_timeout_for_name(config, name); if (fqdn == 0) asprintf(&qname, "%s.", name); - res = _mdns_query_mDNSResponder(qname, class, type, interface, buf, len, reply, timeout); + res = _mdns_query_mDNSResponder(qname, class, type, interface, flags, buf, len, reply, timeout); if (fqdn == 0) free(qname); if (res != 0) _mdns_reply_clear(reply); return res; } static int -_mdns_search(const char *name, uint32_t class, uint32_t type, const char *interface, uint32_t fqdn, uint32_t recurse, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) +_mdns_search(const char *name, uint32_t class, uint32_t type, const char *interface, DNSServiceFlags flags, uint32_t fqdn, uint32_t recurse, uint8_t *buf, uint32_t *len, mdns_reply_t *reply) { int res = -1; int i, n, ndots; @@ -632,7 +633,7 @@ _mdns_search(const char *name, uint32_t class, uint32_t type, const char *interf // if the name has at least ndots, try first as an absolute query. // FQDN and PTR queries are always absolute. if (n >= ndots || fqdn == 1 || type == ns_t_ptr) { - res = _mdns_query_absolute(config, name, class, type, interface, fqdn, buf, len, reply); + res = _mdns_query_absolute(config, name, class, type, interface, flags, fqdn, buf, len, reply); if (res == 0) { _mdns_config_release(config); return res; @@ -652,7 +653,7 @@ _mdns_search(const char *name, uint32_t class, uint32_t type, const char *interf for (i = 0; i < MAXDNSRCH && search[i] != NULL; ++i) { char *qname; asprintf(&qname, "%s.%s", name, search[i]); - res = _mdns_search(qname, class, type, interface, 0, 0, buf, len, reply); + res = _mdns_search(qname, class, type, interface, flags, 0, 0, buf, len, reply); free(qname); if (res == 0) break; } @@ -660,7 +661,7 @@ _mdns_search(const char *name, uint32_t class, uint32_t type, const char *interf // The name is not fully qualified and there is no search list. // Try each default resolver, qualifying the name with that // resolver's domain. - res = _mdns_query_unqualified(config, name, class, type, interface, buf, len, reply); + res = _mdns_query_unqualified(config, name, class, type, interface, flags, buf, len, reply); } _mdns_config_release(config); return res; @@ -844,6 +845,7 @@ _mdns_hostbyname(si_mod_t *si, const char *name, int af, const char *interface, si_item_t *out = NULL; uint64_t bb; int status; + DNSServiceFlags flags = 0; if (err != NULL) *err = SI_STATUS_NO_ERROR; @@ -872,7 +874,7 @@ _mdns_hostbyname(si_mod_t *si, const char *name, int af, const char *interface, } h.host.h_addrtype = af; - status = _mdns_search(name, ns_c_in, type, interface, 0, 1, NULL, NULL, &reply); + status = _mdns_search(name, ns_c_in, type, interface, flags, 0, 1, NULL, NULL, &reply); if (status != 0 || h.addr_count == 0) { _mdns_reply_clear(&reply); if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; @@ -907,6 +909,7 @@ _mdns_hostbyaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint64_t bb; int cat; int status; + DNSServiceFlags flags = 0; if (err != NULL) *err = SI_STATUS_NO_ERROR; @@ -937,7 +940,7 @@ _mdns_hostbyaddr(si_mod_t *si, const void *addr, int af, const char *interface, } h.host.h_addrtype = af; - status = _mdns_search(name, ns_c_in, ns_t_ptr, interface, 0, 1, NULL, NULL, &reply); + status = _mdns_search(name, ns_c_in, ns_t_ptr, interface, flags, 0, 1, NULL, NULL, &reply); free(name); if (status != 0) { _mdns_reply_clear(&reply); @@ -1030,8 +1033,12 @@ _mdns_addrinfo(si_mod_t *si, const void *node, const void *serv, uint32_t family } out = si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname); } else { + DNSServiceFlags dns_flags = 0; + if (flags & AI_ADDRCONFIG) { + dns_flags |= kDNSServiceFlagsSuppressUnusable; + } int res; - res = _mdns_search(node, ns_c_in, type, interface, 0, 1, NULL, NULL, &reply); + res = _mdns_search(node, ns_c_in, type, interface, dns_flags, 0, 1, NULL, NULL, &reply); if (res == 0 && (h4.addr_count > 0 || h6.addr_count > 0)) { out = si_addrinfo_list_from_hostent(si, socktype, proto, port, 0, @@ -1053,11 +1060,12 @@ _mdns_srv_byname(si_mod_t* si, const char *qname, const char *interface, uint32_ mdns_srv_t *srv; int res; const uint64_t unused = 0; + DNSServiceFlags flags = 0; if (err != NULL) *err = SI_STATUS_NO_ERROR; memset(&reply, 0, sizeof(reply)); - res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, 0, 1, NULL, NULL, &reply); + res = _mdns_search(qname, ns_c_in, ns_t_srv, interface, flags, 0, 1, NULL, NULL, &reply); if (res == 0) { srv = reply.srv; while (srv) { @@ -1086,6 +1094,7 @@ _mdns_item_call(si_mod_t *si, int call, const char *name, const char *ignored, c mdns_hostent_t h6; si_item_t *out; int norecurse = 0; + DNSServiceFlags flags = 0; if (err != NULL) *err = SI_STATUS_NO_ERROR; @@ -1117,7 +1126,7 @@ _mdns_item_call(si_mod_t *si, int call, const char *name, const char *ignored, c reply.h4 = &h4; reply.h6 = &h6; - res = _mdns_search(name, class, type, interface, norecurse, 1, buf, &len, &reply); + res = _mdns_search(name, class, type, interface, flags, norecurse, 1, buf, &len, &reply); if (res != 0 || len <= 0 || len > DNS_MAX_RECEIVE_SIZE) { _mdns_reply_clear(&reply); if (err != NULL) *err = SI_STATUS_H_ERRNO_HOST_NOT_FOUND; @@ -1423,11 +1432,12 @@ _mdns_query_callback(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorTy * initializes the context and starts a DNS-SD query. */ static DNSServiceErrorType -_mdns_query_start(mdns_query_context_t *ctx, mdns_reply_t *reply, uint8_t *answer, uint32_t *anslen, const char* name, int class, int type, const char *interface, int kq) +_mdns_query_start(mdns_query_context_t *ctx, mdns_reply_t *reply, uint8_t *answer, uint32_t *anslen, const char* name, int class, int type, const char *interface, DNSServiceFlags flags, int kq) { DNSServiceErrorType status; - int dns_flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates; + flags |= kDNSServiceFlagsShareConnection; + flags |= kDNSServiceFlagsReturnIntermediates; memset(ctx, 0, sizeof(mdns_query_context_t)); @@ -1469,7 +1479,7 @@ _mdns_query_start(mdns_query_context_t *ctx, mdns_reply_t *reply, uint8_t *answe } if (_mdns_debug) printf(";; mdns query %s %d %d\n", qname, type, class); - status = DNSServiceQueryRecord(&ctx->sd, dns_flags, iface, qname, type, class, _mdns_query_callback, ctx); + status = DNSServiceQueryRecord(&ctx->sd, flags, iface, qname, type, class, _mdns_query_callback, ctx); if (qname != name) free(qname); return status; } @@ -1768,7 +1778,7 @@ _mdns_timeout(struct timespec *timeout, const struct timespec *deadline) } int -_mdns_query_mDNSResponder(const char *name, int class, int type, const char *interface, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply, uint32_t timeout_sec) +_mdns_query_mDNSResponder(const char *name, int class, int type, const char *interface, DNSServiceFlags flags, uint8_t *answer, uint32_t *anslen, mdns_reply_t *reply, uint32_t timeout_sec) { DNSServiceErrorType err = 0; int kq, n, wait = 1; @@ -1847,12 +1857,12 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int err = _mdns_query_start(&ctx[n_ctx++], reply, answer, anslen, name, class, - (type == 0) ? ns_t_a : type, interface, kq); + (type == 0) ? ns_t_a : type, interface, flags, kq); } if (err == 0 && type == 0) { err = _mdns_query_start(&ctx[n_ctx++], reply, answer, anslen, - name, class, ns_t_aaaa, interface, kq); + name, class, ns_t_aaaa, interface, flags, kq); } if (err && _mdns_debug) printf(";; initialization error %d\n", err); // try to reinitialize @@ -1910,7 +1920,7 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int // Check if all queries are complete (including errors) complete = 1; for (i = 0; i < n_ctx; ++i) { - if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error) { + if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error != 0) { if (ctx[i].type == ns_t_a) { got_response = 1; } @@ -1928,25 +1938,32 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int break; } else if (got_response == 1) { // got A, adjust deadline for AAAA - struct timespec now; + struct timespec now, tn, ms100; + + // delta = now - start _mdns_now(&now); - _mdns_sub_time(&delta, &now, &start); // delta = N - // minimum N of 50ms - if (delta.tv_sec == 0 && delta.tv_nsec < 50000000) { - delta.tv_nsec = 50000000; - } + _mdns_sub_time(&delta, &now, &start); - // only move deadline if timeout > 2N - _mdns_sub_time(&now, &timeout, &delta); - if (now.tv_sec >= 0) { - if (_mdns_debug) printf(";; new timeout %ld.%ld\n", delta.tv_sec, delta.tv_nsec); + // tn = 2 * delta + _mdns_add_time(&tn, &delta, &delta); + + // delta = tn + 100ms + ms100.tv_sec = 0; + ms100.tv_nsec = 100000000; + _mdns_add_time(&delta, &tn, &ms100); + + // check that delta doesn't exceed our total timeout + _mdns_sub_time(&tn, &timeout, &delta); + if (tn.tv_sec >= 0) { + if (_mdns_debug) printf(";; new timeout (waiting for AAAA) %ld.%ld\n", delta.tv_sec, delta.tv_nsec); _mdns_deadline(&finish, &delta); } } // calculate remaining timeout _mdns_timeout(&timeout, &finish); - // no time remaining + + // check for time remaining if (timeout.tv_sec < 0) { if (_mdns_debug) printf(";; timeout\n"); break; diff --git a/lookup.subproj/si_getaddrinfo.c b/lookup.subproj/si_getaddrinfo.c index a55af6b..bf852b9 100644 --- a/lookup.subproj/si_getaddrinfo.c +++ b/lookup.subproj/si_getaddrinfo.c @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include #include "netdb_async.h" #include "si_module.h" @@ -50,6 +53,14 @@ #define WANT_A6_PLUS_MAPPED_A4 3 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4 +#define V6TO4_PREFIX_16 0x2002 + +static int net_config_token = -1; +static uint32_t net_v4_count = 0; +static uint32_t net_v6_count = 0; // includes 6to4 addresses +static uint32_t net_v6to4_count = 0; +static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER; + typedef struct { struct hostent host; int alias_count; @@ -57,6 +68,72 @@ typedef struct { uint64_t ttl; } build_hostent_t; +static int +_si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4) +{ + int status, checkit; + struct ifaddrs *ifa, *ifap; + struct sockaddr_in6 *sa6; + + pthread_mutex_lock(&net_config_mutex); + + checkit = 1; + + if (net_config_token < 0) + { + status = notify_register_check(kNotifySCNetworkChange, &net_config_token); + if (status != 0) net_config_token = -1; + } + + if (net_config_token >= 0) + { + status = notify_check(net_config_token, &checkit); + if (status != 0) checkit = 1; + } + + status = 0; + + if (checkit != 0) + { + if (getifaddrs(&ifa) < 0) + { + status = -1; + } + else + { + net_v4_count = 0; + net_v6_count = 0; + net_v6to4_count = 0; + for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) + { + if (ifap->ifa_addr == NULL) continue; + if ((ifap->ifa_flags & IFF_UP) == 0) continue; + + if (ifap->ifa_addr->sa_family == AF_INET) + { + net_v4_count++; + } + else if (ifap->ifa_addr->sa_family == AF_INET6) + { + net_v6_count++; + sa6 = (struct sockaddr_in6 *)ifap->ifa_addr; + if (sa6->sin6_addr.__u6_addr.__u6_addr16[0] == ntohs(V6TO4_PREFIX_16)) net_v6to4_count++; + } + } + + freeifaddrs(ifa); + } + } + + if (v4 != NULL) *v4 = net_v4_count; + if (v6 != NULL) *v6 = net_v6_count; + if (v6to4 != NULL) *v6to4 = net_v6to4_count; + + pthread_mutex_unlock(&net_config_mutex); + + return status; +} + void freeaddrinfo(struct addrinfo *a) { @@ -573,6 +650,56 @@ si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t socktype, uint32_t proto, u return out; } +static si_list_t * +_gai_sort_list(si_list_t *in) +{ + si_list_t *out; + int lead; + uint32_t i, v6to4; + si_addrinfo_t *a; + + if (in == NULL) return NULL; + + v6to4 = 0; + if (_si_netconfig(NULL, NULL, &v6to4) < 0) v6to4 = 0; + + out = (si_list_t *)calloc(1, sizeof(si_list_t)); + if (out == NULL) return in; + + out->refcount = in->refcount; + out->count = in->count; + out->entry = (si_item_t **)calloc(in->count, sizeof(si_item_t *)); + if (out->entry == NULL) + { + free(out); + return in; + } + + lead = AF_INET6; + if (v6to4 > 0) lead = AF_INET; + + out->curr = 0; + + for (i = 0; i < in->count; i++) + { + a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t)); + if (a->ai_family == lead) out->entry[out->curr++] = in->entry[i]; + } + + for (i = 0; i < in->count; i++) + { + a = (si_addrinfo_t *)((uintptr_t)in->entry[i] + sizeof(si_item_t)); + if (a->ai_family != lead) out->entry[out->curr++] = in->entry[i]; + } + + free(in->entry); + free(in); + + out->curr = 0; + + return out; +} + /* _gai_simple * Simple lookup via gethostbyname2(3) mechanism. */ @@ -635,7 +762,7 @@ _gai_simple(si_mod_t *si, const void *nodeptr, const void *servptr, uint32_t fam si_item_release(h4_item); si_item_release(h6_item); - return out; + return _gai_sort_list(out); } __private_extern__ si_list_t * @@ -747,6 +874,7 @@ si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, u struct in_addr a4, *p4; struct in6_addr a6, *p6; const char *cname; + si_list_t *out; if (err != NULL) *err = SI_STATUS_NO_ERROR; @@ -825,7 +953,8 @@ si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, u if ((flags & AI_SRV) != 0) { /* AI_SRV SPI */ - return _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err); + out = _gai_srv(si, node, serv, family, socktype, proto, flags, interface, err); + return _gai_sort_list(out); } else { @@ -904,16 +1033,19 @@ si_addrinfo(si_mod_t *si, const char *node, const char *serv, uint32_t family, u if (node == NULL) cname = "localhost"; /* handle trivial questions */ - return si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname); + out = si_addrinfo_list(si, socktype, proto, p4, p6, port, 0, cname, cname); + return _gai_sort_list(out); } else if ((si->sim_wants_addrinfo != NULL) && si->sim_wants_addrinfo(si)) { /* or let the current module handle the host lookups intelligently */ - return si->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); + out = si->sim_addrinfo(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); + return _gai_sort_list(out); } /* fall back to a default path */ - return _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); + out = _gai_simple(si, nodeptr, servptr, family, socktype, proto, flags, interface, err); + return _gai_sort_list(out); } static struct addrinfo * @@ -1135,8 +1267,8 @@ free_build_hostent(build_hostent_t *h) __private_extern__ si_item_t * si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err) { - int i, status, want, if4, if6; - struct ifaddrs *ifa, *ifap; + int i, status, want; + uint32_t if4, if6; struct in_addr addr4; struct in6_addr addr6; si_item_t *item4, *item6; @@ -1221,22 +1353,12 @@ si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const ch if (flags & AI_ADDRCONFIG) { - if (getifaddrs(&ifa) < 0) + if (_si_netconfig(&if4, &if6, NULL) < 0) { if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY; return NULL; } - for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) - { - if (ifap->ifa_addr == NULL) continue; - if ((ifap->ifa_flags & IFF_UP) == 0) continue; - if (ifap->ifa_addr->sa_family == AF_INET) if4++; - else if (ifap->ifa_addr->sa_family == AF_INET6) if6++; - } - - freeifaddrs(ifa); - /* Bail out if there are no interfaces */ if ((if4 == 0) && (if6 == 0)) { -- 2.45.2