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) {