ares_queryloop.c (5043B)
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 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 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 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 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 }