1 /* MIT License
2 *
3 * Copyright (c) The c-ares project and its contributors
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 * SPDX-License-Identifier: MIT
25 */
26
27 /* This test program is meant to loop indefinitely performing a query for the
28 * same domain once per second. The purpose of this is to test the event loop
29 * configuration change detection. You can modify the system configuration
30 * and verify queries work or don't work as expected. */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef _WIN32
36 # include <winsock2.h>
37 # include <windows.h>
38 #else
39 # include <unistd.h>
40 # include <signal.h>
41 # include <netinet/in.h>
42 # include <arpa/inet.h>
43 # include <netdb.h>
44 #endif
45 #include "ares.h"
46
ai_callback(void * arg,int status,int timeouts,struct ares_addrinfo * result)47 static void ai_callback(void *arg, int status, int timeouts,
48 struct ares_addrinfo *result)
49 {
50 struct ares_addrinfo_node *node = NULL;
51 (void)timeouts;
52
53
54 if (status != ARES_SUCCESS) {
55 fprintf(stderr, "%s: %s\n", (char *)arg, ares_strerror(status));
56 return;
57 }
58
59 for (node = result->nodes; node != NULL; node = node->ai_next) {
60 char addr_buf[64] = "";
61 const void *ptr = NULL;
62 if (node->ai_family == AF_INET) {
63 const struct sockaddr_in *in_addr =
64 (const struct sockaddr_in *)((void *)node->ai_addr);
65 ptr = &in_addr->sin_addr;
66 } else if (node->ai_family == AF_INET6) {
67 const struct sockaddr_in6 *in_addr =
68 (const struct sockaddr_in6 *)((void *)node->ai_addr);
69 ptr = &in_addr->sin6_addr;
70 } else {
71 continue;
72 }
73 ares_inet_ntop(node->ai_family, ptr, addr_buf, sizeof(addr_buf));
74 printf("%-32s\t%s\n", result->name, addr_buf);
75 }
76
77 ares_freeaddrinfo(result);
78 }
79
80 static volatile ares_bool_t is_running = ARES_TRUE;
81
82
83 #ifdef _WIN32
ctrlc_handler(_In_ DWORD dwCtrlType)84 static BOOL WINAPI ctrlc_handler(_In_ DWORD dwCtrlType)
85 {
86 switch (dwCtrlType) {
87 case CTRL_C_EVENT:
88 is_running = ARES_FALSE;
89 return TRUE;
90 default:
91 break;
92 }
93 return FALSE;
94 }
95 #else
ctrlc_handler(int sig)96 static void ctrlc_handler(int sig)
97 {
98 switch (sig) {
99 case SIGINT:
100 is_running = ARES_FALSE;
101 break;
102 default:
103 break;
104 }
105 }
106 #endif
107
main(int argc,char * argv[])108 int main(int argc, char *argv[])
109 {
110 struct ares_options options;
111 int optmask = 0;
112 ares_channel_t *channel;
113 size_t count;
114 ares_status_t status;
115
116 #ifdef _WIN32
117 WORD wVersionRequested = MAKEWORD(2, 2);
118 WSADATA wsaData;
119 WSAStartup(wVersionRequested, &wsaData);
120 #endif
121
122 if (argc != 2) {
123 printf("Usage: %s domain\n", argv[0]);
124 return 1;
125 }
126
127 status = (ares_status_t)ares_library_init(ARES_LIB_INIT_ALL);
128 if (status != ARES_SUCCESS) {
129 fprintf(stderr, "ares_library_init: %s\n", ares_strerror((int)status));
130 return 1;
131 }
132
133 memset(&options, 0, sizeof(options));
134 optmask |= ARES_OPT_EVENT_THREAD;
135 options.evsys = ARES_EVSYS_DEFAULT;
136 optmask |= ARES_OPT_QUERY_CACHE;
137 options.qcache_max_ttl = 0;
138
139 status = (ares_status_t)ares_init_options(&channel, &options, optmask);
140 if (status != ARES_SUCCESS) {
141 fprintf(stderr, "ares_init: %s\n", ares_strerror((int)status));
142 return 1;
143 }
144
145 #ifdef _WIN32
146 SetConsoleCtrlHandler(ctrlc_handler, TRUE);
147 #else
148 signal(SIGINT, ctrlc_handler);
149 #endif
150
151 printf("Querying for %s every 1s, press CTRL-C to quit...\n", argv[1]);
152
153 for (count = 1; is_running == ARES_TRUE; count++) {
154 struct ares_addrinfo_hints hints;
155 char *servers = ares_get_servers_csv(channel);
156
157 memset(&hints, 0, sizeof(hints));
158 hints.ai_family = AF_UNSPEC;
159 printf("Attempt %u using server list: %s ...\n", (unsigned int)count,
160 servers);
161 ares_free_string(servers);
162
163 ares_getaddrinfo(channel, argv[1], NULL, &hints, ai_callback, argv[1]);
164 #ifdef _WIN32
165 Sleep(1000);
166 #else
167 sleep(1);
168 #endif
169 }
170
171 printf("CTRL-C captured, cleaning up...\n");
172 ares_destroy(channel);
173 ares_library_cleanup();
174
175 #ifdef _WIN32
176 WSACleanup();
177 #endif
178 return 0;
179 }
180