| /* |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * Copyright (c) 2013-2017 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * 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. |
| */ |
| |
| /** |
| * @file |
| * This file implements a process to effect a functional test for |
| * LwIP's Domain Name Service (DNS) interface. |
| * |
| */ |
| |
| #include <inet/InetConfig.h> |
| |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include <sys/time.h> |
| |
| #if INET_LWIP |
| #include <lwip/dns.h> |
| #include <lwip/ip_addr.h> |
| #endif // INET_LWIP |
| |
| #include <CHIPVersion.h> |
| |
| #include <inet/InetLayer.h> |
| |
| #include "TestInetCommon.h" |
| |
| using namespace chip; |
| using namespace chip::Inet; |
| |
| #define TOOL_NAME "TestLwIPDNS" |
| |
| static bool HandleNonOptionArgs(const char * progName, int argc, char * argv[]); |
| |
| // Globals |
| |
| #if INET_LWIP |
| static uint8_t sNumIpAddrs = DNS_MAX_ADDRS_PER_NAME; |
| static ip_addr_t sIpAddrs[DNS_MAX_ADDRS_PER_NAME]; |
| #endif // INET_LWIP |
| |
| static const char * sHostname = nullptr; |
| static const char * sDNSServerAddr = nullptr; |
| |
| // clang-format off |
| static ArgParser::HelpOptions gHelpOptions(TOOL_NAME, |
| "Usage: " TOOL_NAME " [<options...>] <hostname> <dns-server-address>\n", |
| CHIP_VERSION_STRING "\n" CHIP_TOOL_COPYRIGHT); |
| |
| static ArgParser::OptionSet * gToolOptionSets[] = |
| { |
| &gNetworkOptions, |
| &gFaultInjectionOptions, |
| &gHelpOptions, |
| nullptr |
| }; |
| // clang-format on |
| |
| #if INET_LWIP |
| static void found_multi(const char * aName, ip_addr_t * aIpAddrs, uint8_t aNumIpAddrs, void * callback_arg) |
| { |
| printf("\tfound_multi response\n"); |
| printf("\tName: %s\n", aName); |
| printf("\tnumipaddrs: %d (DNS_MAX_ADDRS_PER_NAME: %d)\n", aNumIpAddrs, DNS_MAX_ADDRS_PER_NAME); |
| |
| for (uint8_t i = 0; i < aNumIpAddrs; ++i) |
| { |
| char addrStr[INET6_ADDRSTRLEN]; |
| |
| IPAddress::FromIPv4(aIpAddrs[i]).ToString(addrStr, sizeof(addrStr)); |
| |
| printf("\t(%d) IPv4: %s\n", i, addrStr); |
| } |
| |
| Done = true; |
| } |
| |
| static void TestLwIPDNS(void) |
| { |
| uint8_t numdns = 1; |
| ip_addr_t dnsserver[1]; |
| IPAddress DNSServerIPv4Addr; |
| |
| IPAddress::FromString(sDNSServerAddr, DNSServerIPv4Addr); |
| |
| dnsserver[0] = DNSServerIPv4Addr.ToIPv4(); |
| |
| dns_setserver(numdns, dnsserver); |
| |
| printf("\nStarted dns_gethostbyname_multi test...\n\n"); |
| |
| // Expected request / response |
| printf("Expected request / response #1\n"); |
| printf("hn: %s, ips: %p, nips: %d, fm: %p, arg: %p\n", hostname, sIpAddrs, sNumIpAddrs, found_multi, NULL); |
| printf("ip[0]: %d, ip[1]: %d\n", sIpAddrs[0], sIpAddrs[1]); |
| err_t res = dns_gethostbyname_multi(hostname, sIpAddrs, &sNumIpAddrs, found_multi, NULL); |
| if (res == ERR_INPROGRESS) |
| { |
| printf("\tdns_gethostbyname_multi: %d (ERR_INPROGRESS)\n", res); |
| } |
| else |
| { |
| printf("\tdns_gethostbyname_multi: %d (expected -5: ERR_INPROGRESS)\n", res); |
| } |
| |
| while (!Done) |
| { |
| struct timeval sleepTime; |
| sleepTime.tv_sec = 0; |
| sleepTime.tv_usec = 10000; |
| |
| ServiceNetwork(sleepTime); |
| } |
| |
| // Expected cached response |
| printf("Expected cached response #1\n"); |
| sNumIpAddrs = DNS_MAX_ADDRS_PER_NAME; |
| printf("hn: %s, ips: %p, nips: %d, fm: %p, arg: %p\n", hostname, ipaddrs, sNumIpAddrs, found_multi, NULL); |
| printf("ip[0]: %d, ip[1]: %d\n", sIpAddrs[0], sIpAddrs[1]); |
| res = dns_gethostbyname_multi(hostname, ipaddrs, &sNumIpAddrs, found_multi, NULL); |
| if (res == ERR_OK) |
| { |
| printf("\tdns_gethostbyname_multi: %d (ERR_OK)\n", res); |
| printf("\tlocal DNS cache response\n"); |
| printf("\tName: %s\n", hostname); |
| printf("\tnumipaddrs: %d\n", sNumIpAddrs); |
| for (uint8_t i = 0; i < sNumIpAddrs; ++i) |
| { |
| char addrStr[64]; |
| IPAddress::FromIPv4(sIpAddrs[i]).ToString(addrStr, sizeof(addrStr)); |
| printf("\t(%d) IPv4: %s\n", i, addrStr); |
| } |
| } |
| else |
| { |
| printf("\tdns_gethostbyname_multi: %d (expected : ERR_OK)\n", res); |
| } |
| |
| // Expected cached response |
| printf("Expected cached response #2\n"); |
| sNumIpAddrs = DNS_MAX_ADDRS_PER_NAME - 1; |
| printf("hn: %s, ips: %p, nips: %d, fm: %p, arg: %p\n", hostname, ipaddrs, sNumIpAddrs, found_multi, NULL); |
| printf("ip[0]: %d, ip[1]: %d\n", sIpAddrs[0], sIpAddrs[1]); |
| |
| res = dns_gethostbyname_multi(hostname, sIpAddrs, &sNumIpAddrs, found_multi, NULL); |
| |
| if (res == ERR_OK) |
| { |
| printf("\tdns_gethostbyname_multi: %d (ERR_OK)\n", res); |
| printf("\tlocal DNS cache response\n"); |
| printf("\tName: %s\n", hostname); |
| printf("\tnumipaddrs: %d\n", sNumIpAddrs); |
| for (i = 0; i < sNumIpAddrs; ++i) |
| { |
| char addrStr[64]; |
| IPAddress::FromIPv4(sIpAddrs[i]).ToString(addrStr, sizeof(addrStr)); |
| printf("\t(%d) IPv4: %s\n", i, addrStr); |
| } |
| } |
| else |
| { |
| printf("\tdns_gethostbyname_multi: %d (expected : ERR_OK)\n", res); |
| } |
| |
| // Expected cached response |
| printf("Expected cached response #3\n"); |
| sNumIpAddrs = 0; |
| printf("hn: %s, ips: %p, nips: %d, fm: %p, arg: %p\n", hostname, ipaddrs, sNumIpAddrs, found_multi, NULL); |
| printf("ip[0]: %d, ip[1]: %d\n", sIpAddrs[0], sIpAddrs[1]); |
| |
| res = dns_gethostbyname_multi(hostname, ipaddrs, &sNumIpAddrs, found_multi, NULL); |
| |
| if (res == ERR_OK) |
| { |
| printf("\tdns_gethostbyname_multi: %d (ERR_OK)\n", res); |
| printf("\tlocal DNS cache response\n"); |
| printf("\tName: %s\n", hostname); |
| printf("\tnumipaddrs: %d\n", sNumIpAddrs); |
| for (i = 0; i < sNumIpAddrs; ++i) |
| { |
| char addrStr[64]; |
| IPAddress::FromIPv4(sIpAddrs[i]).ToString(addrStr, sizeof(addrStr)); |
| printf("\t(%d) IPv4: %s\n", i, addrStr); |
| } |
| } |
| else |
| { |
| printf("\tdns_gethostbyname_multi: %d (expected : ERR_OK)\n", res); |
| } |
| } |
| #endif // INET_LWIP |
| |
| int main(int argc, char * argv[]) |
| { |
| SetSIGUSR1Handler(); |
| |
| if (argc == 1) |
| { |
| gHelpOptions.PrintBriefUsage(stderr); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets, HandleNonOptionArgs)) |
| { |
| exit(EXIT_FAILURE); |
| } |
| |
| InitSystemLayer(); |
| |
| InitNetwork(); |
| |
| #if INET_LWIP |
| TestLwIPDNS(); |
| #else |
| fprintf(stderr, "Please assert INET_LWIP to use this test.\n"); |
| #endif // INET_LWIP |
| |
| ShutdownNetwork(); |
| |
| ShutdownSystemLayer(); |
| |
| return (EXIT_SUCCESS); |
| } |
| |
| static bool HandleNonOptionArgs(const char * progName, int argc, char * argv[]) |
| { |
| if (argc < 2) |
| { |
| printf("TestDNS: Missing %s argument\n", argc == 0 ? "<hostname>" : "<dns-server-address>"); |
| return false; |
| } |
| |
| if (argc > 2) |
| { |
| printf("Unexpected argument: %s\n", argv[1]); |
| } |
| |
| sHostname = argv[0]; |
| sDNSServerAddr = argv[1]; |
| |
| return true; |
| } |