From ba811120ae10ddca1ffc8855bf1d83e99b08bcd9 Mon Sep 17 00:00:00 2001 From: Derek Xue Date: Wed, 13 Aug 2014 14:19:17 +0100 Subject: [PATCH] Migrate system/extra getaddrinfo test, and fix a bug in getservbyname(3). This change is to migrate the getaddrinfo tests defined in the old file system/extras/tests/bionic/libc/common/test_getaddrinfo.c to the new place bionic/tests/netdb_test.cpp. The test here is more thorough, and catches a bug in getservbyname(3) that was breaking getaddrinfo(3)'s ability to look up services by name without a hint that would cause it to ask for a specific protocol. Change-Id: Ief5ebd0869496d1bc6a97861dfefa04bdf24bab1 Signed-off-by: Yongqin Liu --- libc/dns/net/getservbyname.c | 32 ++++++------------ tests/netdb_test.cpp | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/libc/dns/net/getservbyname.c b/libc/dns/net/getservbyname.c index c95c9b045..c32416c19 100644 --- a/libc/dns/net/getservbyname.c +++ b/libc/dns/net/getservbyname.c @@ -25,29 +25,19 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include -#include + #include + #include "servent.h" -struct servent * -getservbyname(const char *name, const char *proto) -{ - res_static rs = __res_get_static(); - - if (rs == NULL || proto == NULL || name == NULL) { - errno = EINVAL; - return NULL; +struct servent* getservbyname(const char* name, const char* proto) { + res_static rs = __res_get_static(); + rs->servent_ptr = NULL; + struct servent* s; + while ((s = getservent_r(rs)) != NULL) { + if (strcmp(s->s_name, name) == 0 && (proto == NULL || strcmp(s->s_proto, proto) == 0)) { + return s; } - - rs->servent_ptr = NULL; - while (1) { - struct servent* s = getservent_r(rs); - if (s == NULL) - break; - if ( !strcmp( s->s_name, name ) && !strcmp( s->s_proto, proto ) ) - return s; - } - - return NULL; + } + return NULL; } diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp index cc08715f2..ef2c8dac2 100644 --- a/tests/netdb_test.cpp +++ b/tests/netdb_test.cpp @@ -24,6 +24,47 @@ TEST(netdb, getaddrinfo_NULL_hints) { addrinfo* ai = NULL; ASSERT_EQ(0, getaddrinfo("localhost", "9999", NULL, &ai)); + + bool saw_tcp = false; + bool saw_udp = false; + for (addrinfo* p = ai; p != NULL; p = p->ai_next) { + ASSERT_TRUE(p->ai_family == AF_INET || p->ai_family == AF_INET6); + if (p->ai_socktype == SOCK_STREAM) { + ASSERT_EQ(IPPROTO_TCP, p->ai_protocol); + saw_tcp = true; + } else if (p->ai_socktype == SOCK_DGRAM) { + ASSERT_EQ(IPPROTO_UDP, p->ai_protocol); + saw_udp = true; + } + } + ASSERT_TRUE(saw_tcp); + ASSERT_TRUE(saw_udp); + + freeaddrinfo(ai); +} + +TEST(netdb, getaddrinfo_service_lookup) { + addrinfo* ai = NULL; + ASSERT_EQ(0, getaddrinfo("localhost", "smtp", NULL, &ai)); + ASSERT_EQ(SOCK_STREAM, ai->ai_socktype); + ASSERT_EQ(IPPROTO_TCP, ai->ai_protocol); + ASSERT_EQ(25, ntohs(reinterpret_cast(ai->ai_addr)->sin_port)); + freeaddrinfo(ai); +} + +TEST(netdb, getaddrinfo_hints) { + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + addrinfo* ai = NULL; + ASSERT_EQ(0, getaddrinfo( "localhost", "9999", &hints, &ai)); + ASSERT_EQ(AF_INET, ai->ai_family); + ASSERT_EQ(SOCK_STREAM, ai->ai_socktype); + ASSERT_EQ(IPPROTO_TCP, ai->ai_protocol); + ASSERT_TRUE(ai->ai_next == NULL); freeaddrinfo(ai); } @@ -65,3 +106,27 @@ TEST(netdb, gethostbyname) { ASSERT_EQ(hent->h_addr[2], 0); ASSERT_EQ(hent->h_addr[3], 1); } + +TEST(netdb, getservbyname) { + // smtp is TCP-only, so we know we'll get 25/tcp back. + servent* s = getservbyname("smtp", NULL); + ASSERT_TRUE(s != NULL); + ASSERT_EQ(25, ntohs(s->s_port)); + ASSERT_STREQ("tcp", s->s_proto); + + // We get the same result by explicitly asking for tcp. + s = getservbyname("smtp", "tcp"); + ASSERT_TRUE(s != NULL); + ASSERT_EQ(25, ntohs(s->s_port)); + ASSERT_STREQ("tcp", s->s_proto); + + // And we get a failure if we explicitly ask for udp. + s = getservbyname("smtp", "udp"); + ASSERT_TRUE(s == NULL); + + // But there are actually udp services. + s = getservbyname("echo", "udp"); + ASSERT_TRUE(s != NULL); + ASSERT_EQ(7, ntohs(s->s_port)); + ASSERT_STREQ("udp", s->s_proto); +}