Merge "Remap existing EAI_SYSTEM to avoid relying on global errno variable"
diff --git a/resolv/getaddrinfo.cpp b/resolv/getaddrinfo.cpp
index 7f7683b..4795d38 100644
--- a/resolv/getaddrinfo.cpp
+++ b/resolv/getaddrinfo.cpp
@@ -1441,25 +1441,29 @@
      */
     res_setnetcontext(res, netcontext);
 
-    int herrno = NETDB_INTERNAL;
-    if (res_searchN(name, &q, res, &herrno) < 0) {
-        // Pass herrno to catch more detailed errors rather than EAI_NODATA.
-        return herrnoToAiErrno(herrno);
+    int he;
+    if (res_searchN(name, &q, res, &he) < 0) {
+        // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA.
+        // Note that res_searchN() doesn't set the pair NETDB_INTERNAL and errno.
+        // See also herrnoToAiErrno().
+        return herrnoToAiErrno(he);
     }
 
     addrinfo sentinel = {};
     addrinfo* cur = &sentinel;
-    addrinfo* ai = getanswer(buf.get(), q.n, q.name, q.qtype, pai, &herrno);
+    addrinfo* ai = getanswer(buf.get(), q.n, q.name, q.qtype, pai, &he);
     if (ai) {
         cur->ai_next = ai;
         while (cur && cur->ai_next) cur = cur->ai_next;
     }
     if (q.next) {
-        ai = getanswer(buf2.get(), q2.n, q2.name, q2.qtype, pai, &herrno);
+        ai = getanswer(buf2.get(), q2.n, q2.name, q2.qtype, pai, &he);
         if (ai) cur->ai_next = ai;
     }
     if (sentinel.ai_next == NULL) {
-        return herrnoToAiErrno(herrno);
+        // Note that getanswer() doesn't set the pair NETDB_INTERNAL and errno.
+        // See also herrnoToAiErrno().
+        return herrnoToAiErrno(he);
     }
 
     _rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid);
diff --git a/resolv/gethnamaddr.cpp b/resolv/gethnamaddr.cpp
index 0c0a865..b3ae91a 100644
--- a/resolv/gethnamaddr.cpp
+++ b/resolv/gethnamaddr.cpp
@@ -421,7 +421,6 @@
             size = NS_IN6ADDRSZ;
             break;
         default:
-            errno = EAFNOSUPPORT;
             return EAI_FAMILY;
     }
     if (buflen < size) goto nospc;
@@ -467,13 +466,10 @@
     info.buflen = buflen;
     if (_hf_gethtbyname2(name, af, &info)) {
         int error = dns_gethtbyname(name, af, &info);
-        if (error != 0) {
-            return error;
-        }
+        if (error != 0) return error;
     }
     return 0;
 nospc:
-    errno = ENOSPC;
     return EAI_MEMORY;
 fake:
     HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
@@ -532,22 +528,21 @@
             size = NS_IN6ADDRSZ;
             break;
         default:
-            errno = EAFNOSUPPORT;
             return EAI_FAMILY;
     }
     if (size != len) {
-        errno = EINVAL;
-        // TODO: Consider to remap error code without relying on errno.
-        return EAI_SYSTEM;
+        // TODO: Consider converting to a private extended EAI_* error code.
+        // Currently, the EAI_* value has no corresponding error code for invalid argument socket
+        // length. In order to not rely on errno, convert the original error code pair, EAI_SYSTEM
+        // and EINVAL, to EAI_FAIL.
+        return EAI_FAIL;
     }
     info.hp = hp;
     info.buf = buf;
     info.buflen = buflen;
     if (_hf_gethtbyaddr(uaddr, len, af, &info)) {
         int error = dns_gethtbyaddr(uaddr, len, af, netcontext, &info);
-        if (error != 0) {
-            return error;
-        }
+        if (error != 0) return error;
     }
     return 0;
 }
@@ -558,6 +553,8 @@
     return android_gethostbyaddrfornetcontext_real(addr, len, af, hp, hbuf, hbuflen, netcontext);
 }
 
+// TODO: Consider leaving function without returning error code as _gethtent() does because
+// the error code of the caller does not currently return to netd.
 struct hostent* netbsd_gethostent_r(FILE* hf, struct hostent* hent, char* buf, size_t buflen,
                                     int* he) {
     const size_t line_buf_size = sizeof(res_get_static()->hostbuf);
@@ -780,18 +777,18 @@
     res_state res = res_get_state();
     if (!res) return EAI_MEMORY;
 
-    int herrno = NETDB_INTERNAL;
-    n = res_nsearch(res, name, C_IN, type, buf->buf, (int) sizeof(buf->buf), &herrno);
+    int he;
+    n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf), &he);
     if (n < 0) {
         LOG(DEBUG) << __func__ << ": res_nsearch failed (" << n << ")";
-        // Pass herrno to catch more detailed errors rather than EAI_NODATA.
-        return herrnoToAiErrno(herrno);
+        // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA.
+        // Note that res_nsearch() doesn't set the pair NETDB_INTERNAL and errno.
+        // See also herrnoToAiErrno().
+        return herrnoToAiErrno(he);
     }
-    hostent* hp =
-            getanswer(buf.get(), n, name, type, res, info->hp, info->buf, info->buflen, &herrno);
-    if (hp == NULL) {
-        return herrnoToAiErrno(herrno);
-    }
+    hostent* hp = getanswer(buf.get(), n, name, type, res, info->hp, info->buf, info->buflen, &he);
+    if (hp == NULL) return herrnoToAiErrno(he);
+
     return 0;
 }
 
@@ -819,13 +816,19 @@
                 if (advance > 0 && qp + advance < ep)
                     qp += advance;
                 else {
-                    // TODO: Consider to remap error code without relying on errno.
-                    return EAI_SYSTEM;
+                    // TODO: Consider converting to a private extended EAI_* error code.
+                    // Currently, the EAI_* value has no corresponding error code for an internal
+                    // out of buffer space. In order to not rely on errno, convert the original
+                    // error code EAI_SYSTEM to EAI_MEMORY.
+                    return EAI_MEMORY;
                 }
             }
             if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
-                // TODO: Consider to remap error code without relying on errno.
-                return EAI_SYSTEM;
+                // TODO: Consider converting to a private extended EAI_* error code.
+                // Currently, the EAI_* value has no corresponding error code for an internal
+                // out of buffer space. In order to not rely on errno, convert the original
+                // error code EAI_SYSTEM to EAI_MEMORY.
+                return EAI_MEMORY;
             }
             break;
         default:
@@ -838,17 +841,17 @@
     if (!res) return EAI_MEMORY;
 
     res_setnetcontext(res, netcontext);
-    int herrno = NETDB_INTERNAL;
-    n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int) sizeof(buf->buf), &herrno);
+    int he;
+    n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf), &he);
     if (n < 0) {
         LOG(DEBUG) << __func__ << ": res_nquery failed (" << n << ")";
-        return herrnoToAiErrno(herrno);
+        // Note that res_nquery() doesn't set the pair NETDB_INTERNAL and errno.
+        // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA.
+        // See also herrnoToAiErrno().
+        return herrnoToAiErrno(he);
     }
-    hostent* hp =
-            getanswer(buf.get(), n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, &herrno);
-    if (hp == NULL) {
-        return herrnoToAiErrno(herrno);
-    }
+    hostent* hp = getanswer(buf.get(), n, qbuf, T_PTR, res, info->hp, info->buf, info->buflen, &he);
+    if (hp == NULL) return herrnoToAiErrno(he);
 
     char* bf = (char*) (hp->h_addr_list + 2);
     size_t blen = (size_t)(bf - info->buf);
@@ -873,7 +876,6 @@
     return 0;
 
 nospc:
-    errno = ENOSPC;
     return EAI_MEMORY;
 }
 
@@ -910,8 +912,8 @@
     return error;
 }
 
-int herrnoToAiErrno(int herrno) {
-    switch (herrno) {
+int herrnoToAiErrno(int he) {
+    switch (he) {
         // extended h_errno
         case NETD_RESOLV_H_ERRNO_EXT_TIMEOUT:
             return NETD_RESOLV_TIMEOUT;
@@ -924,9 +926,17 @@
         case TRY_AGAIN:
             return EAI_AGAIN;
         case NETDB_INTERNAL:
+            // TODO: Remove ENOSPC and call abort() immediately whenever any allocation fails.
+            if (errno == ENOSPC) return EAI_MEMORY;
+            // Theoretically, this should not happen. Leave this here just in case.
+            // Currently, getanswer() of {gethnamaddr, getaddrinfo}.cpp, res_nsearch() and
+            // res_searchN() use this function to convert error code. Only getanswer()
+            // of gethnamaddr.cpp may return the error code pair, herrno NETDB_INTERNAL and
+            // errno ENOSPC, which has already converted to EAI_MEMORY. The remaining functions
+            // don't set the pair herrno and errno.
             return EAI_SYSTEM;  // see errno for detail
         case NO_RECOVERY:
         default:
-            return EAI_FAIL;
+            return EAI_FAIL;  // TODO: Perhaps convert default to EAI_MAX (unknown error) instead
     }
-}
+}
\ No newline at end of file
diff --git a/resolv/sethostent.cpp b/resolv/sethostent.cpp
index 49cc236..2885fbc 100644
--- a/resolv/sethostent.cpp
+++ b/resolv/sethostent.cpp
@@ -61,6 +61,8 @@
     }
 }
 
+// TODO: Consider returning a boolean result as files_getaddrinfo() does because the error code
+// does not currently return to netd.
 int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
     struct hostent *hp, hent;
     char *buf, *ptr;
@@ -71,9 +73,11 @@
     FILE* hf = NULL;
     sethostent_r(&hf);
     if (hf == NULL) {
-        errno = EINVAL;
-        // TODO: Consider to remap error code without relying on errno.
-        return EAI_SYSTEM;
+        // TODO: Consider converting to a private extended EAI_* error code.
+        // Currently, the EAI_* value has no corresponding error code for invalid argument socket
+        // length. In order to not rely on errno, convert the original error code pair, EAI_SYSTEM
+        // and EINVAL, to EAI_FAIL.
+        return EAI_FAIL;
     }
 
     if ((ptr = buf = (char*) malloc(len = info->buflen)) == NULL) {
@@ -89,10 +93,10 @@
         info->hp->h_addrtype = af;
         info->hp->h_length = 0;
 
-        int herrno;
-        hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &herrno);
+        int he;
+        hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &he);
         if (hp == NULL) {
-            if (herrno == NETDB_INTERNAL && errno == ENOSPC) {
+            if (he == NETDB_INTERNAL && errno == ENOSPC) {
                 goto nospc;  // glibc compatibility.
             }
             break;
@@ -165,10 +169,11 @@
     return 0;
 nospc:
     free(buf);
-    errno = ENOSPC;
     return EAI_MEMORY;
 }
 
+// TODO: Consider returning a boolean result as files_getaddrinfo() does because the error code
+// does not currently return to netd.
 int _hf_gethtbyaddr(const unsigned char* uaddr, int len, int af, getnamaddr* info) {
     info->hp->h_length = len;
     info->hp->h_addrtype = af;
@@ -176,12 +181,15 @@
     FILE* hf = NULL;
     sethostent_r(&hf);
     if (hf == NULL) {
-        // TODO: Consider to remap error code without relying on errno.
-        return EAI_SYSTEM;
+        // TODO: Consider converting to a private extended EAI_* error code.
+        // Currently, the EAI_* value has no corresponding error code for invalid argument socket
+        // length. In order to not rely on errno, convert the original error code pair, EAI_SYSTEM
+        // and EINVAL, to EAI_FAIL.
+        return EAI_FAIL;
     }
     struct hostent* hp;
-    int herrno;
-    while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &herrno)) != NULL)
+    int he;
+    while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, &he)) != NULL)
         if (!memcmp(hp->h_addr_list[0], uaddr, (size_t) hp->h_length)) break;
     endhostent_r(&hf);