1 /* $NetBSD: sample-async.c,v 1.1.1.4 2014/12/10 03:34:46 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* Id: sample-async.c,v 1.5 2009/09/29 15:06:07 fdupont Exp */ 20 21 #include <config.h> 22 23 #ifndef WIN32 24 #include <sys/types.h> 25 #include <sys/socket.h> 26 27 #include <netinet/in.h> 28 29 #include <arpa/inet.h> 30 31 #include <unistd.h> 32 #endif 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include <isc/app.h> 39 #include <isc/buffer.h> 40 #include <isc/commandline.h> 41 #include <isc/lib.h> 42 #include <isc/mem.h> 43 #include <isc/socket.h> 44 #include <isc/sockaddr.h> 45 #include <isc/task.h> 46 #include <isc/timer.h> 47 #include <isc/util.h> 48 49 #include <dns/client.h> 50 #include <dns/fixedname.h> 51 #include <dns/lib.h> 52 #include <dns/name.h> 53 #include <dns/rdataset.h> 54 #include <dns/rdatatype.h> 55 #include <dns/result.h> 56 57 #define MAX_SERVERS 10 58 #define MAX_QUERIES 100 59 60 static dns_client_t *client = NULL; 61 static isc_task_t *query_task = NULL; 62 static isc_appctx_t *query_actx = NULL; 63 static unsigned int outstanding_queries = 0; 64 static const char *def_server = "127.0.0.1"; 65 static FILE *fp; 66 67 struct query_trans { 68 int id; 69 isc_boolean_t inuse; 70 dns_rdatatype_t type; 71 dns_fixedname_t fixedname; 72 dns_name_t *qname; 73 dns_namelist_t answerlist; 74 dns_clientrestrans_t *xid; 75 }; 76 77 static struct query_trans query_array[MAX_QUERIES]; 78 79 static isc_result_t dispatch_query(struct query_trans *trans); 80 81 static void 82 ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, 83 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, 84 isc_timermgr_t **timermgrp) 85 { 86 if (*taskmgrp != NULL) 87 isc_taskmgr_destroy(taskmgrp); 88 89 if (*timermgrp != NULL) 90 isc_timermgr_destroy(timermgrp); 91 92 if (*socketmgrp != NULL) 93 isc_socketmgr_destroy(socketmgrp); 94 95 if (*actxp != NULL) 96 isc_appctx_destroy(actxp); 97 98 if (*mctxp != NULL) 99 isc_mem_destroy(mctxp); 100 } 101 102 static isc_result_t 103 ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, 104 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, 105 isc_timermgr_t **timermgrp) 106 { 107 isc_result_t result; 108 109 result = isc_mem_create(0, 0, mctxp); 110 if (result != ISC_R_SUCCESS) 111 goto fail; 112 113 result = isc_appctx_create(*mctxp, actxp); 114 if (result != ISC_R_SUCCESS) 115 goto fail; 116 117 result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); 118 if (result != ISC_R_SUCCESS) 119 goto fail; 120 121 result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); 122 if (result != ISC_R_SUCCESS) 123 goto fail; 124 125 result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); 126 if (result != ISC_R_SUCCESS) 127 goto fail; 128 129 return (ISC_R_SUCCESS); 130 131 fail: 132 ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp); 133 134 return (result); 135 } 136 137 static isc_result_t 138 printdata(dns_rdataset_t *rdataset, dns_name_t *owner) { 139 isc_buffer_t target; 140 isc_result_t result; 141 isc_region_t r; 142 char t[4096]; 143 144 isc_buffer_init(&target, t, sizeof(t)); 145 146 if (!dns_rdataset_isassociated(rdataset)) 147 return (ISC_R_SUCCESS); 148 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, 149 &target); 150 if (result != ISC_R_SUCCESS) 151 return (result); 152 isc_buffer_usedregion(&target, &r); 153 printf(" %.*s", (int)r.length, (char *)r.base); 154 155 return (ISC_R_SUCCESS); 156 } 157 158 static void 159 process_answer(isc_task_t *task, isc_event_t *event) { 160 struct query_trans *trans = event->ev_arg; 161 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 162 dns_name_t *name; 163 dns_rdataset_t *rdataset; 164 isc_result_t result; 165 166 REQUIRE(task == query_task); 167 REQUIRE(trans->inuse == ISC_TRUE); 168 REQUIRE(outstanding_queries > 0); 169 170 printf("answer[%2d]\n", trans->id); 171 172 if (rev->result != ISC_R_SUCCESS) 173 printf(" failed: %d(%s)\n", rev->result, 174 dns_result_totext(rev->result)); 175 176 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 177 name = ISC_LIST_NEXT(name, link)) { 178 for (rdataset = ISC_LIST_HEAD(name->list); 179 rdataset != NULL; 180 rdataset = ISC_LIST_NEXT(rdataset, link)) { 181 (void)printdata(rdataset, name); 182 } 183 } 184 185 dns_client_freeresanswer(client, &rev->answerlist); 186 dns_client_destroyrestrans(&trans->xid); 187 188 isc_event_free(&event); 189 190 trans->inuse = ISC_FALSE; 191 dns_fixedname_invalidate(&trans->fixedname); 192 trans->qname = NULL; 193 outstanding_queries--; 194 195 result = dispatch_query(trans); 196 #if 0 /* for cancel test */ 197 if (result == ISC_R_SUCCESS) { 198 static int count = 0; 199 200 if ((++count) % 10 == 0) 201 dns_client_cancelresolve(trans->xid); 202 } 203 #endif 204 if (result == ISC_R_NOMORE && outstanding_queries == 0) 205 isc_app_ctxshutdown(query_actx); 206 } 207 208 static isc_result_t 209 dispatch_query(struct query_trans *trans) { 210 isc_result_t result; 211 unsigned int namelen; 212 isc_buffer_t b; 213 char buf[4096]; /* XXX ad hoc constant, but should be enough */ 214 char *cp; 215 216 REQUIRE(trans != NULL); 217 REQUIRE(trans->inuse == ISC_FALSE); 218 REQUIRE(ISC_LIST_EMPTY(trans->answerlist)); 219 REQUIRE(outstanding_queries < MAX_QUERIES); 220 221 /* Construct qname */ 222 cp = fgets(buf, sizeof(buf), fp); 223 if (cp == NULL) 224 return (ISC_R_NOMORE); 225 /* zap NL if any */ 226 if ((cp = strchr(buf, '\n')) != NULL) 227 *cp = '\0'; 228 namelen = strlen(buf); 229 isc_buffer_init(&b, buf, namelen); 230 isc_buffer_add(&b, namelen); 231 dns_fixedname_init(&trans->fixedname); 232 trans->qname = dns_fixedname_name(&trans->fixedname); 233 result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL); 234 if (result != ISC_R_SUCCESS) 235 goto cleanup; 236 237 /* Start resolution */ 238 result = dns_client_startresolve(client, trans->qname, 239 dns_rdataclass_in, trans->type, 0, 240 query_task, process_answer, trans, 241 &trans->xid); 242 if (result != ISC_R_SUCCESS) 243 goto cleanup; 244 245 trans->inuse = ISC_TRUE; 246 outstanding_queries++; 247 248 return (ISC_R_SUCCESS); 249 250 cleanup: 251 dns_fixedname_invalidate(&trans->fixedname); 252 253 return (result); 254 } 255 256 ISC_PLATFORM_NORETURN_PRE static void 257 usage(void) ISC_PLATFORM_NORETURN_POST; 258 259 static void 260 usage(void) { 261 fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] " 262 "input_file\n"); 263 264 exit(1); 265 } 266 267 int 268 main(int argc, char *argv[]) { 269 int ch; 270 isc_textregion_t tr; 271 isc_mem_t *mctx = NULL; 272 isc_taskmgr_t *taskmgr = NULL; 273 isc_socketmgr_t *socketmgr = NULL; 274 isc_timermgr_t *timermgr = NULL; 275 int nservers = 0; 276 const char *serveraddr[MAX_SERVERS]; 277 isc_sockaddr_t sa[MAX_SERVERS]; 278 isc_sockaddrlist_t servers; 279 dns_rdatatype_t type = dns_rdatatype_a; 280 struct in_addr inaddr; 281 isc_result_t result; 282 int i; 283 284 while ((ch = isc_commandline_parse(argc, argv, "s:t:")) != -1) { 285 switch (ch) { 286 case 't': 287 tr.base = isc_commandline_argument; 288 tr.length = strlen(isc_commandline_argument); 289 result = dns_rdatatype_fromtext(&type, &tr); 290 if (result != ISC_R_SUCCESS) { 291 fprintf(stderr, 292 "invalid RRtype: %s\n", 293 isc_commandline_argument); 294 exit(1); 295 } 296 break; 297 case 's': 298 if (nservers == MAX_SERVERS) { 299 fprintf(stderr, 300 "too many servers (up to %d)\n", 301 MAX_SERVERS); 302 exit(1); 303 } 304 serveraddr[nservers++] = 305 (const char *)isc_commandline_argument; 306 break; 307 default: 308 usage(); 309 } 310 } 311 312 argc -= isc_commandline_index; 313 argv += isc_commandline_index; 314 if (argc < 1) 315 usage(); 316 317 if (nservers == 0) { 318 nservers = 1; 319 serveraddr[0] = def_server; 320 } 321 322 for (i = 0; i < MAX_QUERIES; i++) { 323 query_array[i].id = i; 324 query_array[i].inuse = ISC_FALSE; 325 query_array[i].type = type; 326 dns_fixedname_init(&query_array[i].fixedname); 327 query_array[i].qname = NULL; 328 ISC_LIST_INIT(query_array[i].answerlist); 329 query_array[i].xid = NULL; 330 } 331 332 isc_lib_register(); 333 result = dns_lib_init(); 334 if (result != ISC_R_SUCCESS) { 335 fprintf(stderr, "dns_lib_init failed: %d\n", result); 336 exit(1); 337 } 338 339 result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr, 340 &timermgr); 341 if (result != ISC_R_SUCCESS) { 342 fprintf(stderr, "ctx create failed: %d\n", result); 343 exit(1); 344 } 345 346 isc_app_ctxstart(query_actx); 347 348 result = dns_client_createx(mctx, query_actx, taskmgr, socketmgr, 349 timermgr, 0, &client); 350 if (result != ISC_R_SUCCESS) { 351 fprintf(stderr, "dns_client_createx failed: %d\n", result); 352 exit(1); 353 } 354 355 /* Set nameservers */ 356 ISC_LIST_INIT(servers); 357 for (i = 0; i < nservers; i++) { 358 if (inet_pton(AF_INET, serveraddr[i], &inaddr) != 1) { 359 fprintf(stderr, "failed to parse IPv4 address %s\n", 360 serveraddr[i]); 361 exit(1); 362 } 363 isc_sockaddr_fromin(&sa[i], &inaddr, 53); 364 ISC_LIST_APPEND(servers, &sa[i], link); 365 } 366 result = dns_client_setservers(client, dns_rdataclass_in, NULL, 367 &servers); 368 if (result != ISC_R_SUCCESS) { 369 fprintf(stderr, "set server failed: %d\n", result); 370 exit(1); 371 } 372 373 /* Create the main task */ 374 query_task = NULL; 375 result = isc_task_create(taskmgr, 0, &query_task); 376 if (result != ISC_R_SUCCESS) { 377 fprintf(stderr, "failed to create task: %d\n", result); 378 exit(1); 379 } 380 381 /* Open input file */ 382 fp = fopen(argv[0], "r"); 383 if (fp == NULL) { 384 fprintf(stderr, "failed to open input file: %s\n", argv[1]); 385 exit(1); 386 } 387 388 /* Dispatch initial queries */ 389 for (i = 0; i < MAX_QUERIES; i++) { 390 result = dispatch_query(&query_array[i]); 391 if (result == ISC_R_NOMORE) 392 break; 393 } 394 395 /* Start event loop */ 396 isc_app_ctxrun(query_actx); 397 398 /* Sanity check */ 399 for (i = 0; i < MAX_QUERIES; i++) 400 INSIST(query_array[i].inuse == ISC_FALSE); 401 402 /* Cleanup */ 403 isc_task_detach(&query_task); 404 dns_client_destroy(&client); 405 dns_lib_shutdown(); 406 isc_app_ctxfinish(query_actx); 407 ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr); 408 409 return (0); 410 } 411