Remove thread-local variable h_errno in gethostby{name, addr} related APIs

Using a thread-local variable to return an int to the caller is a hack and
adds a lot of complexity. Return error code with an int pointer instead.

Test: built, flashed, booted
      system/netd/tests/runtests.sh pass

Change-Id: Ie9da1a6b18525967f0e8fe3d54b0df18e37d2b0e
diff --git a/gethnamaddr.cpp b/gethnamaddr.cpp
index 0ccc3d7..fd56f26 100644
--- a/gethnamaddr.cpp
+++ b/gethnamaddr.cpp
@@ -140,12 +140,11 @@
 static int _dns_gethtbyname(const char* name, int af, getnamaddr* info);
 
 static int gethostbyname_internal(const char* name, int af, res_state res, hostent* hp, char* hbuf,
-                                  size_t hbuflen, int* errorp,
-                                  const android_net_context* netcontext);
+                                  size_t hbuflen, const android_net_context* netcontext);
 static int gethostbyname_internal_real(const char* name, int af, res_state res, hostent* hp,
-                                       char* buf, size_t buflen, int* he);
+                                       char* buf, size_t buflen);
 static int android_gethostbyaddrfornetcontext_proxy_internal(const void*, socklen_t, int,
-                                                             struct hostent*, char*, size_t, int*,
+                                                             struct hostent*, char*, size_t,
                                                              const struct android_net_context*);
 static int android_gethostbyaddrfornetcontext_proxy(const void* addr, socklen_t len, int af,
                                                     const struct android_net_context* netcontext,
@@ -471,9 +470,11 @@
 }
 
 static int gethostbyname_internal_real(const char* name, int af, res_state res, hostent* hp,
-                                       char* buf, size_t buflen, int* he) {
+                                       char* buf, size_t buflen) {
     getnamaddr info;
     size_t size;
+    // TODO: Remove it once the data member "he" of struct getnamaddr is removed.
+    int he = NETDB_INTERNAL;
 
     _DIAGASSERT(name != NULL);
 
@@ -485,7 +486,6 @@
             size = NS_IN6ADDRSZ;
             break;
         default:
-            *he = NETDB_INTERNAL;
             errno = EAFNOSUPPORT;
             return EAI_FAMILY;
     }
@@ -527,24 +527,20 @@
         }
     }
 
-    *he = NETDB_INTERNAL;
     info.hp = hp;
     info.buf = buf;
     info.buflen = buflen;
-    info.he = he;
-    if (!_hf_gethtbyname2(name, af, &info)) {
+    info.he = &he;  // TODO: Remove the data member "he" of struct getnamaddr.
+    if (_hf_gethtbyname2(name, af, &info)) {
         int error = _dns_gethtbyname(name, af, &info);
         if (error != 0) {
             return error;
         }
     }
-    *he = NETDB_SUCCESS;
     return 0;
 nospc:
-    *he = NETDB_INTERNAL;
     errno = ENOSPC;
-    // Bad arguments
-    return EAI_FAIL;
+    return EAI_MEMORY;
 fake:
     HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
     HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
@@ -553,7 +549,6 @@
     if (size > buflen) goto nospc;
 
     if (inet_pton(af, name, buf) <= 0) {
-        *he = HOST_NOT_FOUND;
         return EAI_NODATA;
     }
     hp->h_addr_list[0] = buf;
@@ -562,32 +557,30 @@
     buflen -= size;
     HENT_SCOPY(hp->h_name, name, buf, buflen);
     if (res->options & RES_USE_INET6) map_v4v6_hostent(hp, &buf, buf + buflen);
-    *he = NETDB_SUCCESS;
     return 0;
 }
 
 // very similar in proxy-ness to android_getaddrinfo_proxy
 static int gethostbyname_internal(const char* name, int af, res_state res, hostent* hp, char* hbuf,
-                                  size_t hbuflen, int* errorp,
-                                  const android_net_context* netcontext) {
+                                  size_t hbuflen, const android_net_context* netcontext) {
     res_setnetcontext(res, netcontext);
-    return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
+    return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen);
 }
 
 static int android_gethostbyaddrfornetcontext_real(const void* addr, socklen_t len, int af,
                                                    struct hostent* hp, char* buf, size_t buflen,
-                                                   int* he,
                                                    const struct android_net_context* netcontext) {
     const u_char* uaddr = (const u_char*) addr;
     socklen_t size;
     struct getnamaddr info;
+    // TODO: Remove it once the data member "he" of struct getnamaddr is removed.
+    int he = NETDB_INTERNAL;
 
     _DIAGASSERT(addr != NULL);
 
     if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
         (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr*) addr) ||
          IN6_IS_ADDR_SITELOCAL((const struct in6_addr*) addr))) {
-        *he = HOST_NOT_FOUND;
         return EAI_NODATA;
     }
     if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
@@ -608,35 +601,30 @@
             break;
         default:
             errno = EAFNOSUPPORT;
-            *he = NETDB_INTERNAL;
             return EAI_FAMILY;
     }
     if (size != len) {
         errno = EINVAL;
-        *he = NETDB_INTERNAL;
         // TODO: Consider to remap error code without relying on errno.
         return EAI_SYSTEM;
     }
     info.hp = hp;
     info.buf = buf;
     info.buflen = buflen;
-    info.he = he;
-    *he = NETDB_INTERNAL;
-    if (!_hf_gethtbyaddr(uaddr, len, af, &info)) {
+    info.he = &he;  // TODO: Remove the data member "he" of struct getnamaddr.
+    if (_hf_gethtbyaddr(uaddr, len, af, &info)) {
         int error = _dns_gethtbyaddr(uaddr, len, af, netcontext, &info);
         if (error != 0) {
             return error;
         }
     }
-    *he = NETDB_SUCCESS;
     return 0;
 }
 
 static int android_gethostbyaddrfornetcontext_proxy_internal(
         const void* addr, socklen_t len, int af, struct hostent* hp, char* hbuf, size_t hbuflen,
-        int* he, const struct android_net_context* netcontext) {
-    return android_gethostbyaddrfornetcontext_real(addr, len, af, hp, hbuf, hbuflen, he,
-                                                   netcontext);
+        const struct android_net_context* netcontext) {
+    return android_gethostbyaddrfornetcontext_real(addr, len, af, hp, hbuf, hbuflen, netcontext);
 }
 
 struct hostent* netbsd_gethostent_r(FILE* hf, struct hostent* hent, char* buf, size_t buflen,
@@ -878,7 +866,8 @@
     }
 
     int ai_error = EAI_NODATA;
-    n = res_nsearch(res, name, C_IN, type, buf->buf, (int) sizeof(buf->buf), &ai_error);
+    int herrno = NETDB_INTERNAL;
+    n = res_nsearch(res, name, C_IN, type, buf->buf, (int) sizeof(buf->buf), &ai_error, &herrno);
     if (n < 0) {
         free(buf);
         debugprintf("res_nsearch failed (%d)\n", res, n);
@@ -887,14 +876,14 @@
         // get the nulltpr hp.
         // TODO: Adjust the error closed to res_nsend instead of here after h_errno is removed.
         if (ai_error == 0) {
-            return herrnoToAiError(h_errno);
+            return herrnoToAiError(herrno);
         }
         return ai_error;
     }
-    hp = getanswer(buf, n, name, type, res, info->hp, info->buf, info->buflen, info->he);
+    hp = getanswer(buf, n, name, type, res, info->hp, info->buf, info->buflen, &herrno);
     free(buf);
     if (hp == NULL) {
-        return herrnoToAiError(h_errno);
+        return herrnoToAiError(herrno);
     }
     return 0;
 }
@@ -952,7 +941,8 @@
     }
     res_setnetcontext(res, netcontext);
     int ai_error = 0;
-    n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int) sizeof(buf->buf), &ai_error);
+    int herrno = NETDB_INTERNAL;
+    n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int) sizeof(buf->buf), &ai_error, &herrno);
     if (n < 0) {
         free(buf);
         debugprintf("res_nquery failed (%d)\n", res, n);
@@ -963,12 +953,12 @@
         // query progress. DNS server may respond a DNS packet without any answer for queried
         // address. In this case, return error code from h_errno NO_DATA rather than rcode NOERROR
         // (ai_error).
-        return herrnoToAiError(h_errno);
+        return herrnoToAiError(herrno);
     }
-    hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, info->he);
+    hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, &herrno);
     free(buf);
     if (hp == NULL) {
-        return herrnoToAiError(h_errno);
+        return herrnoToAiError(herrno);
     }
 
     char* bf = (char*) (hp->h_addr_list + 2);
@@ -1011,7 +1001,7 @@
     if (res == NULL) return EAI_MEMORY;
     res_static* rs = res_get_static();  // For thread-safety.
     error = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
-                                   &h_errno, netcontext);
+                                   netcontext);
     if (error == 0) {
         *hp = &rs->host;
     }
@@ -1028,7 +1018,7 @@
                                                     hostent** hp) {
     struct res_static* rs = res_get_static();  // For thread-safety.
     int error = android_gethostbyaddrfornetcontext_proxy_internal(
-            addr, len, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno, netcontext);
+            addr, len, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), netcontext);
     if (error == 0) *hp = &rs->host;
     return error;
 }
diff --git a/hostent.h b/hostent.h
index 892ed88..6052489 100644
--- a/hostent.h
+++ b/hostent.h
@@ -42,8 +42,8 @@
 };
 
 // /etc/hosts lookup
-bool _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info);
-hostent* _hf_gethtbyname2(const char* name, int af, getnamaddr* info);
+int _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info);
+int _hf_gethtbyname2(const char* name, int af, getnamaddr* info);
 hostent* netbsd_gethostent_r(FILE*, struct hostent*, char*, size_t, int*);
 
 // Reserved padding for remapping IPv4 address to NAT64 synthesis IPv6 address
diff --git a/res_query.cpp b/res_query.cpp
index 6faa504..513c1db 100644
--- a/res_query.cpp
+++ b/res_query.cpp
@@ -103,7 +103,7 @@
  * Perform preliminary check of answer, returning success only
  * if no error is indicated and the answer count is nonzero.
  * Return the size of the response on success, -1 on error.
- * Error number is left in H_ERRNO.
+ * Error number is left in *herrno.
  *
  * Caller must parse answer and determine whether it answers the question.
  */
@@ -111,7 +111,8 @@
                int cl, int type,                   // class and type of query
                u_char* answer,                     // buffer to put answer
                int anslen,                         // size of answer buffer
-               int* ai_error)                      // error will be set based on rcode
+               int* ai_error,                      // error will be set based on rcode
+               int* herrno)                        // legacy h_errno
 {
     u_char buf[MAXPACKET];
     HEADER* hp = (HEADER*) (void*) answer;
@@ -136,7 +137,7 @@
 #ifdef DEBUG
         if (statp->options & RES_DEBUG) printf(";; res_query: mkquery failed\n");
 #endif
-        RES_SET_H_ERRNO(statp, NO_RECOVERY);
+        *herrno = NO_RECOVERY;
         return n;
     }
     n = res_nsend(statp, buf, n, answer, anslen, &rcode);
@@ -152,7 +153,7 @@
 #ifdef DEBUG
         if (statp->options & RES_DEBUG) printf(";; res_query: send error\n");
 #endif
-        RES_SET_H_ERRNO(statp, TRY_AGAIN);
+        *herrno = TRY_AGAIN;
         return n;
     }
 
@@ -164,19 +165,19 @@
 #endif
         switch (hp->rcode) {
             case NXDOMAIN:
-                RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+                *herrno = HOST_NOT_FOUND;
                 break;
             case SERVFAIL:
-                RES_SET_H_ERRNO(statp, TRY_AGAIN);
+                *herrno = TRY_AGAIN;
                 break;
             case NOERROR:
-                RES_SET_H_ERRNO(statp, NO_DATA);
+                *herrno = NO_DATA;
                 break;
             case FORMERR:
             case NOTIMP:
             case REFUSED:
             default:
-                RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                *herrno = NO_RECOVERY;
                 break;
         }
         return -1;
@@ -188,13 +189,14 @@
  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  * Return the size of the response on success, -1 on error.
  * If enabled, implement search rules until answer or unrecoverable failure
- * is detected.  Error code, if any, is left in H_ERRNO.
+ * is detected.  Error code, if any, is left in *herrno.
  */
 int res_nsearch(res_state statp, const char* name, /* domain name */
                 int cl, int type,                  /* class and type of query */
                 u_char* answer,                    /* buffer to put answer */
                 int anslen,                        /* size of answer */
-                int* ai_error)                     /* error will be set based on rcode*/
+                int* ai_error,                     /* error will be set based on rcode */
+                int* herrno)                       /* legacy h_errno */
 {
     const char *cp, *const *domain;
     HEADER* hp = (HEADER*) (void*) answer;
@@ -205,7 +207,7 @@
     int searched = 0;
 
     errno = 0;
-    RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */
+    *herrno = HOST_NOT_FOUND; /* True if we never query. */
 
     dots = 0;
     for (cp = name; *cp != '\0'; cp++) dots += (*cp == '.');
@@ -219,9 +221,9 @@
      */
     saved_herrno = -1;
     if (dots >= statp->ndots || trailing_dot) {
-        ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error);
+        ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error, herrno);
         if (ret > 0 || trailing_dot) return ret;
-        saved_herrno = statp->res_h_errno;
+        saved_herrno = *herrno;
         tried_as_is++;
     }
 
@@ -250,7 +252,8 @@
             if (domain[0][0] == '\0' || (domain[0][0] == '.' && domain[0][1] == '\0'))
                 root_on_list++;
 
-            ret = res_nquerydomain(statp, name, *domain, cl, type, answer, anslen, ai_error);
+            ret = res_nquerydomain(statp, name, *domain, cl, type, answer, anslen, ai_error,
+                                   herrno);
             if (ret > 0) return ret;
 
             /*
@@ -267,11 +270,11 @@
              * fully-qualified.
              */
             if (errno == ECONNREFUSED) {
-                RES_SET_H_ERRNO(statp, TRY_AGAIN);
+                *herrno = TRY_AGAIN;
                 return -1;
             }
 
-            switch (statp->res_h_errno) {
+            switch (*herrno) {
                 case NO_DATA:
                     got_nodata++;
                     break;
@@ -303,7 +306,7 @@
      */
     if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
         !(tried_as_is || root_on_list)) {
-        ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error);
+        ret = res_nquerydomain(statp, name, NULL, cl, type, answer, anslen, ai_error, herrno);
         if (ret > 0) return ret;
     }
 
@@ -315,11 +318,11 @@
      * the last DNSRCH we did.
      */
     if (saved_herrno != -1)
-        RES_SET_H_ERRNO(statp, saved_herrno);
+        *herrno = saved_herrno;
     else if (got_nodata)
-        RES_SET_H_ERRNO(statp, NO_DATA);
+        *herrno = NO_DATA;
     else if (got_servfail)
-        RES_SET_H_ERRNO(statp, TRY_AGAIN);
+        *herrno = TRY_AGAIN;
     return -1;
 }
 
@@ -331,7 +334,8 @@
                      int type,       /* class and type of query */
                      u_char* answer, /* buffer to put answer */
                      int anslen,     /* size of answer */
-                     int* ai_error)  /* error will be set based on rcode*/
+                     int* ai_error,  /* error will be set based on rcode */
+                     int* herrno)    /* legacy h_errno */
 {
     char nbuf[MAXDNAME];
     const char* longname = nbuf;
@@ -349,7 +353,7 @@
          */
         n = strlen(name);
         if (n >= MAXDNAME) {
-            RES_SET_H_ERRNO(statp, NO_RECOVERY);
+            *herrno = NO_RECOVERY;
             return -1;
         }
         n--;
@@ -362,10 +366,10 @@
         n = strlen(name);
         d = strlen(domain);
         if (n + d + 1 >= MAXDNAME) {
-            RES_SET_H_ERRNO(statp, NO_RECOVERY);
+            *herrno = NO_RECOVERY;
             return -1;
         }
         snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
     }
-    return res_nquery(statp, longname, cl, type, answer, anslen, ai_error);
+    return res_nquery(statp, longname, cl, type, answer, anslen, ai_error, herrno);
 }
diff --git a/resolv_private.h b/resolv_private.h
index bd48660..85907ac 100644
--- a/resolv_private.h
+++ b/resolv_private.h
@@ -258,9 +258,11 @@
 /* Things involving a resolver context. */
 int res_ninit(res_state);
 void res_pquery(const res_state, const u_char*, int, FILE*);
-int res_nquery(res_state, const char*, int, int, u_char*, int, int*);
-int res_nsearch(res_state, const char*, int, int, u_char*, int, int*);
-int res_nquerydomain(res_state, const char*, const char*, int, int, u_char*, int, int*);
+// TODO: Consider that refactor res_nquery, res_nsearch and res_nquerydomain to return one error
+// code but two error codes.
+int res_nquery(res_state, const char*, int, int, u_char*, int, int*, int*);
+int res_nsearch(res_state, const char*, int, int, u_char*, int, int*, int*);
+int res_nquerydomain(res_state, const char*, const char*, int, int, u_char*, int, int*, int*);
 int res_nmkquery(res_state, int, const char*, int, int, const u_char*, int, const u_char*, u_char*,
                  int);
 int res_nsend(res_state, const u_char*, int, u_char*, int, int*);
diff --git a/sethostent.cpp b/sethostent.cpp
index 7c5b905..b0d2c75 100644
--- a/sethostent.cpp
+++ b/sethostent.cpp
@@ -61,7 +61,7 @@
     }
 }
 
-hostent* _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
+int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
     struct hostent *hp, hent;
     char *buf, *ptr;
     size_t len, num, i;
@@ -73,12 +73,13 @@
     if (hf == NULL) {
         errno = EINVAL;
         *info->he = NETDB_INTERNAL;
-        return NULL;
+        // TODO: Consider to remap error code without relying on errno.
+        return EAI_SYSTEM;
     }
 
     if ((ptr = buf = (char*) malloc(len = info->buflen)) == NULL) {
         *info->he = NETDB_INTERNAL;
-        return NULL;
+        return EAI_MEMORY;
     }
 
     hent.h_name = NULL;
@@ -129,7 +130,7 @@
     if (num == 0) {
         *info->he = HOST_NOT_FOUND;
         free(buf);
-        return NULL;
+        return EAI_NODATA;
     }
 
     hp = info->hp;
@@ -160,15 +161,15 @@
     hp->h_aliases[anum] = NULL;
 
     free(buf);
-    return hp;
+    return 0;
 nospc:
     *info->he = NETDB_INTERNAL;
     free(buf);
     errno = ENOSPC;
-    return NULL;
+    return EAI_MEMORY;
 }
 
-bool _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info) {
+int _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info) {
     info->hp->h_length = len;
     info->hp->h_addrtype = af;
 
@@ -176,7 +177,8 @@
     sethostent_r(&hf);
     if (hf == NULL) {
         *info->he = NETDB_INTERNAL;
-        return false;
+        // TODO: Consider to remap error code without relying on errno.
+        return EAI_SYSTEM;
     }
     struct hostent* hp;
     while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, info->he)) != NULL)
@@ -184,9 +186,9 @@
     endhostent_r(&hf);
 
     if (hp == NULL) {
-        if (errno == ENOSPC) return false;  // glibc compatibility.
+        if (errno == ENOSPC) return EAI_MEMORY;  // glibc compatibility.
         *info->he = HOST_NOT_FOUND;
-        return false;
+        return EAI_NODATA;
     }
-    return true;
+    return 0;
 }