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 <yongqin.liu@linaro.org>
diff --git a/libc/dns/net/getservbyname.c b/libc/dns/net/getservbyname.c
index c95c9b0..c32416c 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 <sys/cdefs.h>
-#include <sys/types.h>
+
#include <netdb.h>
+
#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 cc08715..ef2c8da 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<sockaddr_in*>(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 @@
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);
+}