]> git.saurik.com Git - apple/libinfo.git/commitdiff
Libinfo-330.10.tar.gz mac-os-x-1068 v330.10
authorApple <opensource@apple.com>
Fri, 15 Apr 2011 18:54:54 +0000 (18:54 +0000)
committerApple <opensource@apple.com>
Fri, 15 Apr 2011 18:54:54 +0000 (18:54 +0000)
lookup.subproj/mdns_module.c
lookup.subproj/si_getaddrinfo.c

index ef3e88eff7650f990a859865c17140d600510e94..980380e72f473f224faa567430999c98e165c0b1 100644 (file)
 #include <dns_util.h>
 #include <TargetConditionals.h>
 
 #include <dns_util.h>
 #include <TargetConditionals.h>
 
+__private_extern__ int si_inet_config(uint32_t *inet4, uint32_t *inet6);
+
 /* from dns_util.c */
 #define DNS_MAX_RECEIVE_SIZE 65536
 
 /* from dns_util.c */
 #define DNS_MAX_RECEIVE_SIZE 65536
 
 
 #define IPPROTO_UNSPEC 0
 
 
 #define IPPROTO_UNSPEC 0
 
+#define GOT_DATA 1
+#define GOT_ERROR 2
+#define SHORT_AAAA_EXTRA 2
+#define MEDIUM_AAAA_EXTRA 5
+#define LONG_AAAA_EXTRA 10
+
 static int _mdns_debug = 0;
 
 // mutex protects DNSServiceProcessResult and DNSServiceRefDeallocate
 static int _mdns_debug = 0;
 
 // mutex protects DNSServiceProcessResult and DNSServiceRefDeallocate
@@ -1793,8 +1801,13 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int
        struct kevent ev;
        struct timespec start, finish, delta, timeout;
        int res = 0;
        struct kevent ev;
        struct timespec start, finish, delta, timeout;
        int res = 0;
-       int i, complete, got_response = 0;
+       int i, complete, got_a_response = 0;
        int initialize = 1;
        int initialize = 1;
+       uint32_t n_iface_4 = 0;
+
+       // determine number of IPv4 interfaces (ignore loopback)
+       si_inet_config(&n_iface_4, NULL);
+       if (n_iface_4 > 0) n_iface_4--;
 
        // 2 for A and AAAA parallel queries
        int n_ctx = 0;
 
        // 2 for A and AAAA parallel queries
        int n_ctx = 0;
@@ -1937,7 +1950,8 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int
                for (i = 0; i < n_ctx; ++i) {
                        if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error != 0) {
                                if (ctx[i].type == ns_t_a) {
                for (i = 0; i < n_ctx; ++i) {
                        if (_mdns_query_is_complete(&ctx[i]) || ctx[i].error != 0) {
                                if (ctx[i].type == ns_t_a) {
-                                       got_response = 1;
+                                       got_a_response = GOT_DATA;
+                                       if (ctx[i].error != 0) got_a_response = GOT_ERROR;
                                }
                        } else {
                                complete = 0;
                                }
                        } else {
                                complete = 0;
@@ -1951,21 +1965,31 @@ _mdns_query_mDNSResponder(const char *name, int class, int type, const char *int
                } else if (complete == 1) {
                        if (_mdns_debug) printf(";; done\n");
                        break;
                } else if (complete == 1) {
                        if (_mdns_debug) printf(";; done\n");
                        break;
-               } else if (got_response == 1) {
-                       // got A, adjust deadline for AAAA
-                       struct timespec now, tn, ms100;
+               } else if (got_a_response != 0) {
+                       // Got A record or NXERROR for A query, adjust deadline for AAAA.
+                       struct timespec now, tn, extra;
 
                        // delta = now - start
                        _mdns_now(&now);
                        _mdns_sub_time(&delta, &now, &start);
 
 
                        // delta = now - start
                        _mdns_now(&now);
                        _mdns_sub_time(&delta, &now, &start);
 
+                       extra.tv_sec = SHORT_AAAA_EXTRA;
+                       extra.tv_nsec = 0;
+
+                       // if delta is really small, we probably got a result from mDNSResponder's cache
+                       if ((delta.tv_sec == 0) && (delta.tv_nsec <= 200000000)) {
+                               extra.tv_sec = LONG_AAAA_EXTRA;
+                       }
+                       else if (n_iface_4 == 0) {
+                               extra.tv_sec = LONG_AAAA_EXTRA;
+                       } else if (got_a_response == GOT_ERROR) {
+                               extra.tv_sec = MEDIUM_AAAA_EXTRA;
+                       }
                        // tn = 2 * delta
                        _mdns_add_time(&tn, &delta, &delta);
 
                        // 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);
+                       // delta = tn + extra
+                       _mdns_add_time(&delta, &tn, &extra);
 
                        // check that delta doesn't exceed our total timeout
                        _mdns_sub_time(&tn, &timeout, &delta);
 
                        // check that delta doesn't exceed our total timeout
                        _mdns_sub_time(&tn, &timeout, &delta);
index bf852b99ce690e5063d1691292b7e7a455a12862..780a13368aca539601acc6e6f2a9bc528cfe0b89 100644 (file)
 #define WANT_A6_PLUS_MAPPED_A4 3
 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
 
 #define WANT_A6_PLUS_MAPPED_A4 3
 #define WANT_A6_OR_MAPPED_A4_IF_NO_A6 4
 
+#define TEREDO_PREFIX_32 0x20010000
 #define V6TO4_PREFIX_16 0x2002
 #define V6TO4_PREFIX_16 0x2002
+#define ULA_PREFIX_8 0xfc
+
+#define NET_TYPE_UNKNOWN       0x00000000
+#define NET_TYPE_V4                    0x00000001
+#define NET_TYPE_V6                    0x00000002
+#define NET_TYPE_TEREDO                0x00000012
+#define NET_TYPE_6TO4          0x00000022
+#define NET_TYPE_LINKLOCAL     0x00000042
+#define NET_TYPE_SITELOCAL     0x00000082
+#define NET_TYPE_ULA           0x00000102
+#define NET_MASK_T6LSU         0x000001f0
+
+typedef struct
+{
+       int v4_count;
+       int v6_count;
+       int v6to4_count;
+       int teredo_count;
+       int ula_count;
+       int ll_count;
+       int sl_count;
+       int gai_v6_preferred;
+} config_stats_t;
 
 static int net_config_token = -1;
 
 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 config_stats_t config_stats_global;
 static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 typedef struct {
 static pthread_mutex_t net_config_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 typedef struct {
@@ -69,14 +91,45 @@ typedef struct {
 } build_hostent_t;
 
 static int
 } build_hostent_t;
 
 static int
-_si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4)
+_si_net_addr_type(const struct sockaddr *s)
+{
+       const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)s;
+
+       if (s == NULL) return NET_TYPE_UNKNOWN;
+       else if (s->sa_family == AF_INET) return NET_TYPE_V4;
+       else if (s->sa_family != AF_INET6) return NET_TYPE_UNKNOWN;
+       else if (sa6->sin6_addr.__u6_addr.__u6_addr32[0] == ntohs(TEREDO_PREFIX_32)) return NET_TYPE_TEREDO;
+       else if (sa6->sin6_addr.__u6_addr.__u6_addr16[0] == ntohs(V6TO4_PREFIX_16)) return NET_TYPE_6TO4;
+       else if (IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))) return NET_TYPE_LINKLOCAL;
+       else if (IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr))) return NET_TYPE_SITELOCAL;
+       else if ((sa6->sin6_addr.__u6_addr.__u6_addr8[0] & 0xfe) == ULA_PREFIX_8) return NET_TYPE_ULA;
+
+       return NET_TYPE_V6;
+}
+
+static int
+_si_net_type_is_IPv6_globably_reachable_non_transitional(int t)
 {
 {
-       int status, checkit;
+       if (t & NET_TYPE_V6)
+       {
+               if (t & NET_MASK_T6LSU) return 0;
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
+_si_netconfig(config_stats_t *stats)
+{
+       int status, checkit, net_type;
        struct ifaddrs *ifa, *ifap;
        struct ifaddrs *ifa, *ifap;
-       struct sockaddr_in6 *sa6;
+
+       if (stats == NULL) return 0;
 
        pthread_mutex_lock(&net_config_mutex);
 
 
        pthread_mutex_lock(&net_config_mutex);
 
+       status = 0;
        checkit = 1;
 
        if (net_config_token < 0)
        checkit = 1;
 
        if (net_config_token < 0)
@@ -91,8 +144,6 @@ _si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4)
                if (status != 0) checkit = 1;
        }
 
                if (status != 0) checkit = 1;
        }
 
-       status = 0;
-
        if (checkit != 0)
        {
                if (getifaddrs(&ifa) < 0)
        if (checkit != 0)
        {
                if (getifaddrs(&ifa) < 0)
@@ -101,23 +152,53 @@ _si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4)
                }
                else
                {
                }
                else
                {
-                       net_v4_count = 0;
-                       net_v6_count = 0;
-                       net_v6to4_count = 0;
+                       memset(&config_stats_global, 0, sizeof(config_stats_t));
+
                        for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next)
                        {
                                if (ifap->ifa_addr == NULL) continue;
                                if ((ifap->ifa_flags & IFF_UP) == 0) continue;
 
                        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_type = _si_net_addr_type(ifap->ifa_addr);
+               
+                               if (net_type == NET_TYPE_UNKNOWN)
                                {
                                {
-                                       net_v4_count++;
                                }
                                }
-                               else if (ifap->ifa_addr->sa_family == AF_INET6)
+                               else if (net_type == NET_TYPE_V4)
                                {
                                {
-                                       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++;
+                                       config_stats_global.v4_count++;
+                               }
+                               else
+                               {
+                                       config_stats_global.v6_count++;
+
+                                       if (net_type == NET_TYPE_LINKLOCAL)
+                                       {
+                                               config_stats_global.ll_count++;
+                                               continue;
+                                       }
+                                       else if (net_type == NET_TYPE_ULA)
+                                       {
+                                               config_stats_global.ula_count++;
+                                               if (!strncmp(ifap->ifa_name, "utun", 4)) continue;
+                                       }
+                                       if (net_type == NET_TYPE_TEREDO)
+                                       {
+                                               config_stats_global.teredo_count++;
+                                       }
+                                       else if (net_type == NET_TYPE_6TO4)
+                                       {
+                                               config_stats_global.v6to4_count++;
+                                       }
+                                       else if (net_type == NET_TYPE_SITELOCAL)
+                                       {
+                                               config_stats_global.sl_count++;
+                                       }
+
+                                       if (_si_net_type_is_IPv6_globably_reachable_non_transitional(net_type))
+                                       {
+                                               config_stats_global.gai_v6_preferred = 1;
+                                       }
                                }
                        }
 
                                }
                        }
 
@@ -125,15 +206,24 @@ _si_netconfig(uint32_t *v4, uint32_t *v6, uint32_t *v6to4)
                }
        }
 
                }
        }
 
-       if (v4 != NULL) *v4 = net_v4_count;
-       if (v6 != NULL) *v6 = net_v6_count;
-       if (v6to4 != NULL) *v6to4 = net_v6to4_count;
+       *stats = config_stats_global;
 
        pthread_mutex_unlock(&net_config_mutex);
 
        return status;
 }
 
        pthread_mutex_unlock(&net_config_mutex);
 
        return status;
 }
-       
+
+__private_extern__ int
+si_inet_config(uint32_t *inet4, uint32_t *inet6)
+{
+       config_stats_t x;
+
+       if (_si_netconfig(&x) < 0) return -1;
+       if (inet4 != NULL) *inet4 = x.v4_count;
+       if (inet6 != NULL) *inet6 = x.v6_count;
+       return 0;
+}
+
 void
 freeaddrinfo(struct addrinfo *a)
 {
 void
 freeaddrinfo(struct addrinfo *a)
 {
@@ -650,54 +740,69 @@ si_addrinfo_list_from_hostent(si_mod_t *si, uint32_t socktype, uint32_t proto, u
        return out;
 }
 
        return out;
 }
 
-static si_list_t *
-_gai_sort_list(si_list_t *in)
+int
+_gai_sa_dst_compare(const struct sockaddr *a, const struct sockaddr *b, int unused)
 {
 {
-       si_list_t *out;
-       int lead;
-       uint32_t i, v6to4;
-       si_addrinfo_t *a;
+       int ta, tb, posn_a, posn_b;
 
 
-       if (in == NULL) return NULL;
+       ta = _si_net_addr_type(a);
+       tb = _si_net_addr_type(b);
 
 
-       v6to4 = 0;
-       if (_si_netconfig(NULL, NULL, &v6to4) < 0) v6to4 = 0;
+       posn_a = 2;
+       posn_b = 2;
 
 
-       out = (si_list_t *)calloc(1, sizeof(si_list_t));
-       if (out == NULL) return in;
+       if (ta & NET_TYPE_V4) posn_a = 1;
+       if (tb & NET_TYPE_V4) posn_b = 1;
 
 
-       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;
-       }
+       if (_si_net_type_is_IPv6_globably_reachable_non_transitional(ta)) posn_a = 0;
+       if (_si_net_type_is_IPv6_globably_reachable_non_transitional(tb)) posn_b = 0;
 
 
-       lead = AF_INET6;
-       if (v6to4 > 0) lead = AF_INET;
+       return (posn_a - posn_b);
+}
 
 
-       out->curr = 0;
+int
+_gai_addr_sort(void *thunk, const void *a, const void *b)
+{
+       si_item_t **ia, **ib;
+       si_addrinfo_t *p, *q;
+       struct sockaddr *sp, *sq;
+       uint32_t *v4first = (uint32_t *)thunk;
 
 
-       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];
-       }
+       ia = (si_item_t **)a;
+       ib = (si_item_t **)b;
+       
+       p = (si_addrinfo_t *)((uintptr_t)*ia + sizeof(si_item_t));
+       q = (si_addrinfo_t *)((uintptr_t)*ib + sizeof(si_item_t));
 
 
-       for (i = 0; i < in->count; i++)
+       sp = (struct sockaddr *)p->ai_addr.x;
+       sq = (struct sockaddr *)q->ai_addr.x;
+
+       if (*v4first == 1)
        {
        {
-               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];
+               if (sp->sa_family == sq->sa_family) return 0;
+               if (sp->sa_family == AF_INET) return -1;
+               return 1;
        }
 
        }
 
-       free(in->entry);
-       free(in);
+       return _gai_sa_dst_compare(sp, sq, 0);
+}
+
+static si_list_t *
+_gai_sort_list(si_list_t *in)
+{
+       uint32_t v4first;
+       config_stats_t x;
+
+       if (in == NULL) return NULL;
+
+       memset(&x, 0, sizeof(config_stats_t));
+       if (_si_netconfig(&x) < 0) return in;
 
 
-       out->curr = 0;
+       v4first = 1;
+       if (x.gai_v6_preferred != 0) v4first = 0;
 
 
-       return out;
+       qsort_r(&in->entry[0], in->count, sizeof(si_item_t *), (void *)&v4first, _gai_addr_sort);
+       return in;
 }
 
 /* _gai_simple
 }
 
 /* _gai_simple
@@ -1268,13 +1373,13 @@ __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;
 si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const char *interface, uint32_t *err)
 {
        int i, status, want;
-       uint32_t if4, if6;
        struct in_addr addr4;
        struct in6_addr addr6;
        si_item_t *item4, *item6;
        build_hostent_t *out;
        struct hostent *h;
        uint64_t unused;
        struct in_addr addr4;
        struct in6_addr addr6;
        si_item_t *item4, *item6;
        build_hostent_t *out;
        struct hostent *h;
        uint64_t unused;
+       config_stats_t ifstats;
 
        memset(&addr4, 0, sizeof(struct in_addr));
        memset(&addr6, 0, sizeof(struct in6_addr));
 
        memset(&addr4, 0, sizeof(struct in_addr));
        memset(&addr6, 0, sizeof(struct in6_addr));
@@ -1348,19 +1453,18 @@ si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const ch
         * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
         */
 
         * IF AI_ADDRCONFIG is set, we need to know what interface flavors we really have.
         */
 
-       if4 = 0;
-       if6 = 0;
+       memset(&ifstats, 0, sizeof(config_stats_t));
 
        if (flags & AI_ADDRCONFIG)
        {
 
        if (flags & AI_ADDRCONFIG)
        {
-               if (_si_netconfig(&if4, &if6, NULL) < 0)
+               if (_si_netconfig(&ifstats) < 0)
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
                }
 
                /* Bail out if there are no interfaces */
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
                }
 
                /* Bail out if there are no interfaces */
-               if ((if4 == 0) && (if6 == 0))
+               if ((ifstats.v4_count == 0) && (ifstats.v6_count == 0))
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
@@ -1375,7 +1479,7 @@ si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const ch
 
        if (family == AF_INET)
        {
 
        if (family == AF_INET)
        {
-               if ((flags & AI_ADDRCONFIG) && (if4 == 0))
+               if ((flags & AI_ADDRCONFIG) && (ifstats.v4_count == 0))
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
                {
                        if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                        return NULL;
@@ -1399,7 +1503,7 @@ si_ipnode_byname(si_mod_t *si, const char *name, int family, int flags, const ch
                }
                else
                {
                }
                else
                {
-                       if ((flags & AI_ADDRCONFIG) && (if6 == 0)) 
+                       if ((flags & AI_ADDRCONFIG) && (ifstats.v6_count == 0)) 
                        {
                                if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                                return NULL;
                        {
                                if (err != NULL) *err = SI_STATUS_H_ERRNO_NO_RECOVERY;
                                return NULL;