• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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