Improve glibc compatibility of gethostby*_r functions.

And add more tests.

Bug: N/A (but I'm here because a recent test broke existing tests)
Test: ran tests
Change-Id: Ib78430f179b43484a49bb50ff447ea6870c1ee3a
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 4e416fd..7118a29 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -170,6 +170,15 @@
 	{ 0, 0 }
 };
 
+static int h_errno_to_result(int* herrno_p) {
+  // glibc considers ERANGE a special case (and BSD uses ENOSPC instead).
+  if (*herrno_p == NETDB_INTERNAL && errno == ENOSPC) {
+    errno = ERANGE;
+    return errno;
+  }
+  // glibc considers HOST_NOT_FOUND not an error for the _r functions' return value.
+  return (*herrno_p != HOST_NOT_FOUND) ? *herrno_p : 0;
+}
 
 #ifdef DEBUG
 static void
@@ -519,9 +528,8 @@
     struct hostent **result, int *errorp)
 {
 	res_state res = __res_get_state();
-
 	if (res == NULL) {
-	  *result = NULL;
+		*result = NULL;
 		*errorp = NETDB_INTERNAL;
 		return -1;
 	}
@@ -538,12 +546,7 @@
 	}
 	*result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp,
 	                                 &NETCONTEXT_UNSET);
-	__res_put_state(res);
-	if (!*result && errno == ENOSPC) {
-	  errno = ERANGE;
-	  return ERANGE; /* Return error as in linux manual page. */
-	}
-	return (*result) ? 0 : -1;
+	return h_errno_to_result(errorp);
 }
 
 /* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
@@ -552,7 +555,6 @@
     size_t buflen, struct hostent **result, int *errorp)
 {
 	res_state res = __res_get_state();
-
 	if (res == NULL) {
 		*result = NULL;
 		*errorp = NETDB_INTERNAL;
@@ -560,12 +562,7 @@
 	}
 	*result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp,
 	                                 &NETCONTEXT_UNSET);
-	__res_put_state(res);
-	if (!*result && errno == ENOSPC) {
-		errno = ERANGE;
-		return ERANGE;
-	}
-	return (*result) ? 0 : -1;
+	return h_errno_to_result(errorp);
 }
 
 __LIBC_HIDDEN__ FILE* android_open_proxy() {
@@ -859,11 +856,7 @@
 {
 	*result = android_gethostbyaddrfornetcontext_proxy_internal(
 		addr, len, af, hp, buf, buflen, h_errnop, &NETCONTEXT_UNSET);
-	if (!*result && errno == ENOSPC) {
-		errno = ERANGE;
-		return ERANGE;
-	}
-	return (*result) ? 0 : -1;
+	return h_errno_to_result(h_errnop);
 }
 
 static struct hostent *
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
index 66c305f..a743a54 100644
--- a/libc/dns/net/sethostent.c
+++ b/libc/dns/net/sethostent.c
@@ -129,6 +129,9 @@
 	hp = _hf_gethtbyname2(name, af, info);
 #endif
 	if (hp == NULL) {
+		if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+			return NS_UNAVAIL; // glibc compatibility.
+		}
 		*info->he = HOST_NOT_FOUND;
 		return NS_NOTFOUND;
 	}
@@ -171,8 +174,12 @@
 
 		hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
 		    info->he);
-		if (hp == NULL)
+		if (hp == NULL) {
+			if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+				goto nospc; // glibc compatibility.
+			}
 			break;
+		}
 
 		if (strcasecmp(hp->h_name, name) != 0) {
 			char **cp;
@@ -270,6 +277,7 @@
 	endhostent_r(&hf);
 
 	if (hp == NULL) {
+		if (errno == ENOSPC) return NS_UNAVAIL; // glibc compatibility.
 		*info->he = HOST_NOT_FOUND;
 		return NS_NOTFOUND;
 	}
diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp
index e699701..a624138 100644
--- a/tests/netdb_test.cpp
+++ b/tests/netdb_test.cpp
@@ -271,8 +271,9 @@
   char buf[4]; // Use too small buffer.
   int err;
   int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
-  ASSERT_EQ(ERANGE, result);
-  ASSERT_EQ(NULL, hp);
+  EXPECT_EQ(NETDB_INTERNAL, err);
+  EXPECT_EQ(ERANGE, result);
+  EXPECT_EQ(NULL, hp);
 }
 
 TEST(netdb, gethostbyname2_r_ERANGE) {
@@ -281,8 +282,9 @@
   char buf[4]; // Use too small buffer.
   int err;
   int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
-  ASSERT_EQ(ERANGE, result);
-  ASSERT_EQ(NULL, hp);
+  EXPECT_EQ(NETDB_INTERNAL, err);
+  EXPECT_EQ(ERANGE, result);
+  EXPECT_EQ(NULL, hp);
 }
 
 TEST(netdb, gethostbyaddr_r_ERANGE) {
@@ -292,8 +294,43 @@
   char buf[4]; // Use too small buffer.
   int err;
   int result = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
-  ASSERT_EQ(ERANGE, result);
-  ASSERT_EQ(NULL, hp);
+  EXPECT_EQ(NETDB_INTERNAL, err);
+  EXPECT_EQ(ERANGE, result);
+  EXPECT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyname_r_HOST_NOT_FOUND) {
+  hostent hent;
+  hostent *hp;
+  char buf[BUFSIZ];
+  int err;
+  int result = gethostbyname_r("does.not.exist.google.com", &hent, buf, sizeof(buf), &hp, &err);
+  EXPECT_EQ(HOST_NOT_FOUND, err);
+  EXPECT_EQ(0, result);
+  EXPECT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyname2_r_HOST_NOT_FOUND) {
+  hostent hent;
+  hostent *hp;
+  char buf[BUFSIZ];
+  int err;
+  int result = gethostbyname2_r("does.not.exist.google.com", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  EXPECT_EQ(HOST_NOT_FOUND, err);
+  EXPECT_EQ(0, result);
+  EXPECT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyaddr_r_HOST_NOT_FOUND) {
+  in_addr addr = { htonl(0xffffffff) };
+  hostent hent;
+  hostent *hp;
+  char buf[BUFSIZ];
+  int err;
+  int result = gethostbyaddr_r(&addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+  EXPECT_EQ(HOST_NOT_FOUND, err);
+  EXPECT_EQ(0, result);
+  EXPECT_EQ(NULL, hp);
 }
 
 TEST(netdb, getservbyname) {