]> git.saurik.com Git - apple/libinfo.git/commitdiff
Libinfo-330.7.tar.gz mac-os-x-1065 mac-os-x-1066 v330.7
authorApple <opensource@apple.com>
Thu, 12 Aug 2010 22:23:36 +0000 (22:23 +0000)
committerApple <opensource@apple.com>
Thu, 12 Aug 2010 22:23:36 +0000 (22:23 +0000)
lookup.subproj/mdns_module.c
lookup.subproj/si_getaddrinfo.c

index a67ef54abbd9ef657659e9880f28a19d5de5814d..5a216a856d2e6a6a4e38e1ce5c1f4a7c533f9abd 100644 (file)
@@ -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;
index a55af6b693b7333d82c6e8bbf4329d6288266f37..bf852b99ce690e5063d1691292b7e7a455a12862 100644 (file)
@@ -34,6 +34,9 @@
 #include <net/if.h>
 #include <string.h>
 #include <sys/param.h>
+#include <notify.h>
+#include <notify_keys.h>
+#include <pthread.h>
 #include <TargetConditionals.h>
 #include "netdb_async.h"
 #include "si_module.h"
 #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))
                {