From 3c5f35a38ea554c942309440a2d12ad1da4e3f78 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 21 Nov 2018 14:38:40 +0800 Subject: [PATCH] Test for asynchronous DNS query API Add basic test for asynchronous DNS query API Test: build atest CtsNativeNetDnsTestCases Change-Id: Ib757ba8f0128d3efe7dfbcbfb45d36e4350834f9 --- tests/cts/net/native/dns_async/Android.bp | 36 +++++ .../cts/net/native/dns_async/AndroidTest.xml | 29 ++++ .../dns_async/src/NativeDnsAsyncTest.cpp | 148 ++++++++++++++++++ 3 files changed, 213 insertions(+) create mode 100644 tests/cts/net/native/dns_async/Android.bp create mode 100644 tests/cts/net/native/dns_async/AndroidTest.xml create mode 100644 tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp diff --git a/tests/cts/net/native/dns_async/Android.bp b/tests/cts/net/native/dns_async/Android.bp new file mode 100644 index 0000000000..2b9346fc0b --- /dev/null +++ b/tests/cts/net/native/dns_async/Android.bp @@ -0,0 +1,36 @@ +cc_defaults { + name: "dns_async_defaults", + + cflags: [ + "-fstack-protector-all", + "-g", + "-Wall", + "-Wextra", + "-Werror", + "-fno-builtin", + ], + srcs: [ + "src/NativeDnsAsyncTest.cpp", + ], + shared_libs: [ + "liblog", + "libutils", + "libandroid", + ], +} + +cc_test { + name: "CtsNativeNetDnsTestCases", + defaults: ["dns_async_defaults"], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + test_suites: [ + "cts", + ], +} \ No newline at end of file diff --git a/tests/cts/net/native/dns_async/AndroidTest.xml b/tests/cts/net/native/dns_async/AndroidTest.xml new file mode 100644 index 0000000000..e092b36186 --- /dev/null +++ b/tests/cts/net/native/dns_async/AndroidTest.xml @@ -0,0 +1,29 @@ + + + + diff --git a/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp b/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp new file mode 100644 index 0000000000..087eb5ed5a --- /dev/null +++ b/tests/cts/net/native/dns_async/src/NativeDnsAsyncTest.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* poll */ +#include +#include + +#include +#include + +namespace { +constexpr int MAXPACKET = 8 * 1024; +constexpr int PTON_MAX = 16; + +int getAsyncResponse(int fd, int timeoutMs, int* rcode, u_char* buf, int bufLen) { + struct pollfd wait_fd[1]; + wait_fd[0].fd = fd; + wait_fd[0].events = POLLIN; + short revents; + int ret; + ret = poll(wait_fd, 1, timeoutMs); + revents = wait_fd[0].revents; + if (revents & POLLIN) { + int n = android_res_nresult(fd, rcode, buf, bufLen); + return n; + } + + return -1; +} + +std::vector extractIpAddressAnswers(u_char* buf, int bufLen, int ipType) { + ns_msg handle; + if (ns_initparse((const uint8_t*) buf, bufLen, &handle) < 0) { + return {}; + } + int ancount = ns_msg_count(handle, ns_s_an); + ns_rr rr; + std::vector answers; + for (int i = 0; i < ancount; i++) { + if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) { + continue; + } + const u_char* rdata = ns_rr_rdata(rr); + char buffer[INET6_ADDRSTRLEN]; + if (inet_ntop(ipType, (const char*) rdata, buffer, sizeof(buffer))) { + answers.push_back(buffer); + } + } + return answers; +} + +void expectAnswersValid(int fd, int ipType, int expectedRcode) { + int rcode = -1; + u_char buf[MAXPACKET] = {}; + int res = getAsyncResponse(fd, 10000, &rcode, buf, MAXPACKET); + EXPECT_GT(res, 0); + EXPECT_EQ(rcode, expectedRcode); + + + if (expectedRcode == NOERROR) { + auto answers = extractIpAddressAnswers(buf, res, ipType); + EXPECT_GT(answers.size(), 0U); + for (auto &answer : answers) { + char pton[PTON_MAX]; + EXPECT_EQ(1, inet_pton(ipType, answer.c_str(), pton)); + } + } +} + +} // namespace + +TEST (NativeDnsAsyncTest, Async_Query) { + // V4 + int fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_a); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NOERROR); + + // V6 + fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_aaaa); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET6, NOERROR); +} + +TEST (NativeDnsAsyncTest, Async_Send) { + // V4 + u_char buf[MAXPACKET] = {}; + int len = res_mkquery(QUERY, "www.youtube.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NOERROR); + + // V6 + memset(buf, 0, MAXPACKET); + len = res_mkquery(QUERY, "www.youtube.com", + ns_c_in, ns_t_aaaa, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET6, NOERROR); +} + +TEST (NativeDnsAsyncTest, Async_NXDOMAIN) { + u_char buf[MAXPACKET] = {}; + int len = res_mkquery(QUERY, "test-nx.metric.gstatic.com", + ns_c_in, ns_t_a, nullptr, 0, nullptr, buf, sizeof(buf)); + EXPECT_GT(len, 0); + int fd = android_res_nsend(NETWORK_UNSPECIFIED , buf, len); + EXPECT_GT(fd, 0); + expectAnswersValid(fd, AF_INET, NXDOMAIN); +} + +TEST (NativeDnsAsyncTest, Async_Cancel) { + int fd = android_res_nquery(NETWORK_UNSPECIFIED ,"www.google.com", ns_c_in, ns_t_a); + int rcode = -1; + u_char buf[MAXPACKET] = {}; + android_res_cancel(fd); + + int res = android_res_nresult(fd, &rcode, buf, MAXPACKET); + EXPECT_EQ(res, -EBADF); +} + +int main(int argc, char **argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}