Merge "Remove separate IPv4-only nsaddr_list from res_state"
diff --git a/res_cache.cpp b/res_cache.cpp
index 55d9514..b9737fe 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -1583,16 +1583,7 @@
             }
 
             if ((size_t) ai->ai_addrlen <= sizeof(statp->_u._ext.ext->nsaddrs[0])) {
-                if (statp->_u._ext.ext != NULL) {
-                    memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
-                    statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
-                } else {
-                    if ((size_t) ai->ai_addrlen <= sizeof(statp->nsaddr_list[0])) {
-                        memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen);
-                    } else {
-                        statp->nsaddr_list[nserv].sin_family = AF_UNSPEC;
-                    }
-                }
+                memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen);
             } else {
                 LOG(INFO) << __func__ << ": found too long addrlen";
             }
diff --git a/res_init.cpp b/res_init.cpp
index ecfb35d..502f9ea 100644
--- a/res_init.cpp
+++ b/res_init.cpp
@@ -94,22 +94,12 @@
 #include "resolv_private.h"
 
 // Set up Resolver state default settings.
-// Note that res_ninit() is called with an initialized res_state,
-// the memories it allocated must be freed after the task is done.
-// Or memory leak will happen.
-int res_ninit(res_state statp) {
-    int nserv = 0;  // number of nameserver records
-    sockaddr_union u[2];
-
+// Note: this is called with statp zero-initialized
+void res_init(res_state statp) {
     statp->netid = NETID_UNSET;
     statp->id = arc4random_uniform(65536);
     statp->_mark = MARK_UNSET;
 
-    memset(u, 0, sizeof(u));
-    u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
-    u[nserv].sin.sin_family = AF_INET;
-    u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
-    nserv++;
     statp->nscount = 0;
     statp->ndots = 1;
     statp->_vcsock = -1;
@@ -119,17 +109,20 @@
     statp->netcontext_flags = 0;
     if (statp->_u._ext.ext != NULL) {
         memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
-        statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
     }
-    res_setservers(statp, u, nserv);
 
-    if (nserv > 0) {
-        statp->nscount = nserv;
-    }
-    return (0);
+    // The following dummy initialization is probably useless because
+    // it's overwritten later by _resolv_populate_res_for_net().
+    // TODO: check if it's safe to remove.
+    const sockaddr_union u{
+            .sin.sin_addr.s_addr = INADDR_ANY,
+            .sin.sin_family = AF_INET,
+            .sin.sin_port = htons(NAMESERVER_PORT),
+    };
+    memcpy(&statp->_u._ext.ext->nsaddrs[0], &u, sizeof(u));
+    statp->nscount = 1;
 }
 
-
 /*
  * This routine is for closing the socket if a virtual circuit is used and
  * the program wants to close it.  This provides support for endhostent()
@@ -159,90 +152,6 @@
     statp->_u._ext.ext = NULL;
 }
 
-void res_setservers(res_state statp, const sockaddr_union* set, int cnt) {
-    int i, nserv;
-    size_t size;
-
-    /* close open servers */
-    res_nclose(statp);
-
-    /* cause rtt times to be forgotten */
-    statp->_u._ext.nscount = 0;
-
-    nserv = 0;
-    for (i = 0; i < cnt && nserv < MAXNS; i++) {
-        switch (set->sin.sin_family) {
-            case AF_INET:
-                size = sizeof(set->sin);
-                if (statp->_u._ext.ext)
-                    memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin, size);
-                if (size <= sizeof(statp->nsaddr_list[nserv]))
-                    memcpy(&statp->nsaddr_list[nserv], &set->sin, size);
-                else
-                    statp->nsaddr_list[nserv].sin_family = 0;
-                nserv++;
-                break;
-
-#ifdef HAS_INET6_STRUCTS
-            case AF_INET6:
-                size = sizeof(set->sin6);
-                if (statp->_u._ext.ext)
-                    memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin6, size);
-                if (size <= sizeof(statp->nsaddr_list[nserv]))
-                    memcpy(&statp->nsaddr_list[nserv], &set->sin6, size);
-                else
-                    statp->nsaddr_list[nserv].sin_family = 0;
-                nserv++;
-                break;
-#endif
-
-            default:
-                break;
-        }
-        set++;
-    }
-    statp->nscount = nserv;
-}
-
-int res_getservers(res_state statp, sockaddr_union* set, int cnt) {
-    int i;
-    size_t size;
-    uint16_t family;
-
-    for (i = 0; i < statp->nscount && i < cnt; i++) {
-        if (statp->_u._ext.ext)
-            family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
-        else
-            family = statp->nsaddr_list[i].sin_family;
-
-        switch (family) {
-            case AF_INET:
-                size = sizeof(set->sin);
-                if (statp->_u._ext.ext)
-                    memcpy(&set->sin, &statp->_u._ext.ext->nsaddrs[i], size);
-                else
-                    memcpy(&set->sin, &statp->nsaddr_list[i], size);
-                break;
-
-#ifdef HAS_INET6_STRUCTS
-            case AF_INET6:
-                size = sizeof(set->sin6);
-                if (statp->_u._ext.ext)
-                    memcpy(&set->sin6, &statp->_u._ext.ext->nsaddrs[i], size);
-                else
-                    memcpy(&set->sin6, &statp->nsaddr_list[i], size);
-                break;
-#endif
-
-            default:
-                set->sin.sin_family = 0;
-                break;
-        }
-        set++;
-    }
-    return (statp->nscount);
-}
-
 void res_setnetcontext(res_state statp, const struct android_net_context* netcontext,
                        android::net::NetworkDnsEventReported* _Nonnull event) {
     if (statp != nullptr) {
diff --git a/res_init.h b/res_init.h
new file mode 100644
index 0000000..af76414
--- /dev/null
+++ b/res_init.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+struct __res_state;
+void res_init(__res_state* statp);
diff --git a/res_send.cpp b/res_send.cpp
index be5ec0b..af60376 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -470,13 +470,6 @@
             needclose++;
         } else {
             for (int ns = 0; ns < statp->nscount; ns++) {
-                if (statp->nsaddr_list[ns].sin_family &&
-                    !sock_eq((struct sockaddr*) (void*) &statp->nsaddr_list[ns],
-                             (struct sockaddr*) (void*) &statp->_u._ext.ext->nsaddrs[ns])) {
-                    needclose++;
-                    break;
-                }
-
                 if (statp->_u._ext.nssocks[ns] == -1) continue;
                 peerlen = sizeof(peer);
                 if (getpeername(statp->_u._ext.nssocks[ns], (struct sockaddr*) (void*) &peer,
@@ -503,8 +496,6 @@
         for (int ns = 0; ns < statp->nscount; ns++) {
             statp->_u._ext.nstimes[ns] = RES_MAXTIME;
             statp->_u._ext.nssocks[ns] = -1;
-            if (!statp->nsaddr_list[ns].sin_family) continue;
-            statp->_u._ext.ext->nsaddrs[ns].sin = statp->nsaddr_list[ns];
         }
         statp->_u._ext.nscount = statp->nscount;
     }
@@ -692,25 +683,8 @@
         return (0); /* unknown, die on connect */
 }
 
-/*
- * pick appropriate nsaddr_list for use.  see res_init() for initialization.
- */
 static struct sockaddr* get_nsaddr(res_state statp, size_t n) {
-    if (!statp->nsaddr_list[n].sin_family && statp->_u._ext.ext) {
-        /*
-         * - statp->_u._ext.ext->nsaddrs[n] holds an address that is larger
-         *   than struct sockaddr, and
-         * - user code did not update statp->nsaddr_list[n].
-         */
-        return (struct sockaddr*) (void*) &statp->_u._ext.ext->nsaddrs[n];
-    } else {
-        /*
-         * - user code updated statp->nsaddr_list[n], or
-         * - statp->nsaddr_list[n] has the same content as
-         *   statp->_u._ext.ext->nsaddrs[n].
-         */
-        return (struct sockaddr*) (void*) &statp->nsaddr_list[n];
-    }
+    return (struct sockaddr*)(void*)&statp->_u._ext.ext->nsaddrs[n];
 }
 
 static struct timespec get_timeout(res_state statp, const res_params* params, const int ns) {
diff --git a/res_state.cpp b/res_state.cpp
index 0a90733..372c37a 100644
--- a/res_state.cpp
+++ b/res_state.cpp
@@ -38,6 +38,7 @@
 
 #include <android-base/logging.h>
 
+#include "res_init.h"
 #include "resolv_cache.h"
 #include "resolv_private.h"
 
@@ -99,14 +100,7 @@
     pthread_setspecific(_res_key, rt);
 
     LOG(VERBOSE) << __func__ << ": tid=" << gettid() << ", rt=" << rt;
-    if (res_ninit(rt->_nres) < 0) {
-        /* This should not happen */
-        LOG(VERBOSE) << __func__ << ": tid=" << gettid() << " rt=" << rt
-                     << ", res_ninit() returned < 0";
-        res_thread_free(rt);
-        pthread_setspecific(_res_key, NULL);
-        return NULL;
-    }
+    res_init(rt->_nres);
     return rt;
 }
 
diff --git a/resolv_private.h b/resolv_private.h
index 8ab6939..0029254 100644
--- a/resolv_private.h
+++ b/resolv_private.h
@@ -89,8 +89,6 @@
     unsigned netid;                           // NetId: cache key and socket mark
     uid_t uid;                                // uid of the app that sent the DNS lookup
     int nscount;                              // number of name srvers
-    struct sockaddr_in nsaddr_list[MAXNS];    // address of name server
-#define nsaddr nsaddr_list[0]                 // for backward compatibility
     uint16_t id;                              // current message id
     std::vector<std::string> search_domains;  // domains to search
     unsigned ndots : 4;                       // threshold for initial abs. query
@@ -167,8 +165,6 @@
 
 int res_nameinquery(const char*, int, int, const uint8_t*, const uint8_t*);
 int res_queriesmatch(const uint8_t*, const uint8_t*, const uint8_t*, const uint8_t*);
-/* Things involving a resolver context. */
-int res_ninit(res_state);
 
 int res_nquery(res_state, const char*, int, int, uint8_t*, int, int*);
 int res_nsearch(res_state, const char*, int, int, uint8_t*, int, int*);