1224090Sdougb/* 2254402Serwin * Copyright (C) 2009, 2013 Internet Systems Consortium, Inc. ("ISC") 3224090Sdougb * 4224090Sdougb * Permission to use, copy, modify, and/or distribute this software for any 5224090Sdougb * purpose with or without fee is hereby granted, provided that the above 6224090Sdougb * copyright notice and this permission notice appear in all copies. 7224090Sdougb * 8224090Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9224090Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10224090Sdougb * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11224090Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12224090Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13224090Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14224090Sdougb * PERFORMANCE OF THIS SOFTWARE. 15224090Sdougb */ 16224090Sdougb 17234010Sdougb/* $Id: sample-async.c,v 1.5 2009/09/29 15:06:07 fdupont Exp $ */ 18224090Sdougb 19224090Sdougb#include <config.h> 20224090Sdougb 21224090Sdougb#include <sys/types.h> 22224090Sdougb#include <sys/socket.h> 23224090Sdougb 24224090Sdougb#include <netinet/in.h> 25224090Sdougb 26224090Sdougb#include <arpa/inet.h> 27224090Sdougb 28224090Sdougb#include <unistd.h> 29224090Sdougb#include <stdio.h> 30224090Sdougb#include <stdlib.h> 31224090Sdougb#include <string.h> 32224090Sdougb 33224090Sdougb#include <isc/app.h> 34224090Sdougb#include <isc/buffer.h> 35224090Sdougb#include <isc/lib.h> 36224090Sdougb#include <isc/mem.h> 37224090Sdougb#include <isc/socket.h> 38224090Sdougb#include <isc/sockaddr.h> 39224090Sdougb#include <isc/task.h> 40224090Sdougb#include <isc/timer.h> 41224090Sdougb#include <isc/util.h> 42224090Sdougb 43224090Sdougb#include <dns/client.h> 44224090Sdougb#include <dns/fixedname.h> 45224090Sdougb#include <dns/lib.h> 46224090Sdougb#include <dns/name.h> 47224090Sdougb#include <dns/rdataset.h> 48224090Sdougb#include <dns/rdatatype.h> 49224090Sdougb#include <dns/result.h> 50224090Sdougb 51224090Sdougb#define MAX_SERVERS 10 52224090Sdougb#define MAX_QUERIES 100 53224090Sdougb 54224090Sdougbstatic dns_client_t *client = NULL; 55224090Sdougbstatic isc_task_t *query_task = NULL; 56224090Sdougbstatic isc_appctx_t *query_actx = NULL; 57224090Sdougbstatic unsigned int outstanding_queries = 0; 58224090Sdougbstatic const char *def_server = "127.0.0.1"; 59224090Sdougbstatic FILE *fp; 60224090Sdougb 61224090Sdougbstruct query_trans { 62224090Sdougb int id; 63224090Sdougb isc_boolean_t inuse; 64224090Sdougb dns_rdatatype_t type; 65224090Sdougb dns_fixedname_t fixedname; 66224090Sdougb dns_name_t *qname; 67224090Sdougb dns_namelist_t answerlist; 68224090Sdougb dns_clientrestrans_t *xid; 69224090Sdougb}; 70224090Sdougb 71224090Sdougbstatic struct query_trans query_array[MAX_QUERIES]; 72224090Sdougb 73224090Sdougbstatic isc_result_t dispatch_query(struct query_trans *trans); 74224090Sdougb 75224090Sdougbstatic void 76224090Sdougbctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp, 77224090Sdougb isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, 78224090Sdougb isc_timermgr_t **timermgrp) 79224090Sdougb{ 80224090Sdougb if (*taskmgrp != NULL) 81224090Sdougb isc_taskmgr_destroy(taskmgrp); 82224090Sdougb 83224090Sdougb if (*timermgrp != NULL) 84224090Sdougb isc_timermgr_destroy(timermgrp); 85224090Sdougb 86224090Sdougb if (*socketmgrp != NULL) 87224090Sdougb isc_socketmgr_destroy(socketmgrp); 88224090Sdougb 89224090Sdougb if (*actxp != NULL) 90224090Sdougb isc_appctx_destroy(actxp); 91224090Sdougb 92224090Sdougb if (*mctxp != NULL) 93224090Sdougb isc_mem_destroy(mctxp); 94224090Sdougb} 95224090Sdougb 96224090Sdougbstatic isc_result_t 97224090Sdougbctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp, 98224090Sdougb isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp, 99224090Sdougb isc_timermgr_t **timermgrp) 100224090Sdougb{ 101224090Sdougb isc_result_t result; 102224090Sdougb 103224090Sdougb result = isc_mem_create(0, 0, mctxp); 104224090Sdougb if (result != ISC_R_SUCCESS) 105224090Sdougb goto fail; 106224090Sdougb 107224090Sdougb result = isc_appctx_create(*mctxp, actxp); 108224090Sdougb if (result != ISC_R_SUCCESS) 109224090Sdougb goto fail; 110224090Sdougb 111224090Sdougb result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp); 112224090Sdougb if (result != ISC_R_SUCCESS) 113224090Sdougb goto fail; 114224090Sdougb 115224090Sdougb result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp); 116224090Sdougb if (result != ISC_R_SUCCESS) 117224090Sdougb goto fail; 118224090Sdougb 119224090Sdougb result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp); 120224090Sdougb if (result != ISC_R_SUCCESS) 121224090Sdougb goto fail; 122224090Sdougb 123224090Sdougb return (ISC_R_SUCCESS); 124224090Sdougb 125224090Sdougb fail: 126224090Sdougb ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp); 127224090Sdougb 128224090Sdougb return (result); 129224090Sdougb} 130224090Sdougb 131224090Sdougbstatic isc_result_t 132224090Sdougbprintdata(dns_rdataset_t *rdataset, dns_name_t *owner) { 133224090Sdougb isc_buffer_t target; 134224090Sdougb isc_result_t result; 135224090Sdougb isc_region_t r; 136224090Sdougb char t[4096]; 137224090Sdougb 138224090Sdougb isc_buffer_init(&target, t, sizeof(t)); 139224090Sdougb 140224090Sdougb if (!dns_rdataset_isassociated(rdataset)) 141224090Sdougb return (ISC_R_SUCCESS); 142224090Sdougb result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, 143224090Sdougb &target); 144224090Sdougb if (result != ISC_R_SUCCESS) 145224090Sdougb return (result); 146224090Sdougb isc_buffer_usedregion(&target, &r); 147224090Sdougb printf(" %.*s", (int)r.length, (char *)r.base); 148224090Sdougb 149224090Sdougb return (ISC_R_SUCCESS); 150224090Sdougb} 151224090Sdougb 152224090Sdougbstatic void 153224090Sdougbprocess_answer(isc_task_t *task, isc_event_t *event) { 154224090Sdougb struct query_trans *trans = event->ev_arg; 155224090Sdougb dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 156224090Sdougb dns_name_t *name; 157224090Sdougb dns_rdataset_t *rdataset; 158224090Sdougb isc_result_t result; 159224090Sdougb 160224090Sdougb REQUIRE(task == query_task); 161224090Sdougb REQUIRE(trans->inuse == ISC_TRUE); 162224090Sdougb REQUIRE(outstanding_queries > 0); 163224090Sdougb 164224090Sdougb printf("answer[%2d]\n", trans->id); 165224090Sdougb 166224090Sdougb if (rev->result != ISC_R_SUCCESS) 167224090Sdougb printf(" failed: %d(%s)\n", rev->result, 168224090Sdougb dns_result_totext(rev->result)); 169224090Sdougb 170224090Sdougb for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 171224090Sdougb name = ISC_LIST_NEXT(name, link)) { 172224090Sdougb for (rdataset = ISC_LIST_HEAD(name->list); 173224090Sdougb rdataset != NULL; 174224090Sdougb rdataset = ISC_LIST_NEXT(rdataset, link)) { 175224090Sdougb (void)printdata(rdataset, name); 176224090Sdougb } 177224090Sdougb } 178224090Sdougb 179224090Sdougb dns_client_freeresanswer(client, &rev->answerlist); 180224090Sdougb dns_client_destroyrestrans(&trans->xid); 181224090Sdougb 182224090Sdougb isc_event_free(&event); 183224090Sdougb 184224090Sdougb trans->inuse = ISC_FALSE; 185224090Sdougb dns_fixedname_invalidate(&trans->fixedname); 186224090Sdougb trans->qname = NULL; 187224090Sdougb outstanding_queries--; 188224090Sdougb 189224090Sdougb result = dispatch_query(trans); 190224090Sdougb#if 0 /* for cancel test */ 191224090Sdougb if (result == ISC_R_SUCCESS) { 192224090Sdougb static int count = 0; 193224090Sdougb 194224090Sdougb if ((++count) % 10 == 0) 195224090Sdougb dns_client_cancelresolve(trans->xid); 196224090Sdougb } 197224090Sdougb#endif 198224090Sdougb if (result == ISC_R_NOMORE && outstanding_queries == 0) 199224090Sdougb isc_app_ctxshutdown(query_actx); 200224090Sdougb} 201224090Sdougb 202224090Sdougbstatic isc_result_t 203224090Sdougbdispatch_query(struct query_trans *trans) { 204224090Sdougb isc_result_t result; 205224090Sdougb size_t namelen; 206224090Sdougb isc_buffer_t b; 207224090Sdougb char buf[4096]; /* XXX ad hoc constant, but should be enough */ 208224090Sdougb char *cp; 209224090Sdougb 210224090Sdougb REQUIRE(trans != NULL); 211224090Sdougb REQUIRE(trans->inuse == ISC_FALSE); 212224090Sdougb REQUIRE(ISC_LIST_EMPTY(trans->answerlist)); 213224090Sdougb REQUIRE(outstanding_queries < MAX_QUERIES); 214224090Sdougb 215224090Sdougb /* Construct qname */ 216224090Sdougb cp = fgets(buf, sizeof(buf), fp); 217224090Sdougb if (cp == NULL) 218224090Sdougb return (ISC_R_NOMORE); 219224090Sdougb /* zap NL if any */ 220224090Sdougb if ((cp = strchr(buf, '\n')) != NULL) 221224090Sdougb *cp = '\0'; 222224090Sdougb namelen = strlen(buf); 223224090Sdougb isc_buffer_init(&b, buf, namelen); 224224090Sdougb isc_buffer_add(&b, namelen); 225224090Sdougb dns_fixedname_init(&trans->fixedname); 226224090Sdougb trans->qname = dns_fixedname_name(&trans->fixedname); 227224090Sdougb result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL); 228224090Sdougb if (result != ISC_R_SUCCESS) 229224090Sdougb goto cleanup; 230224090Sdougb 231224090Sdougb /* Start resolution */ 232224090Sdougb result = dns_client_startresolve(client, trans->qname, 233224090Sdougb dns_rdataclass_in, trans->type, 0, 234224090Sdougb query_task, process_answer, trans, 235224090Sdougb &trans->xid); 236224090Sdougb if (result != ISC_R_SUCCESS) 237224090Sdougb goto cleanup; 238224090Sdougb 239224090Sdougb trans->inuse = ISC_TRUE; 240224090Sdougb outstanding_queries++; 241224090Sdougb 242224090Sdougb return (ISC_R_SUCCESS); 243224090Sdougb 244224090Sdougb cleanup: 245224090Sdougb dns_fixedname_invalidate(&trans->fixedname); 246224090Sdougb 247224090Sdougb return (result); 248224090Sdougb} 249224090Sdougb 250224090SdougbISC_PLATFORM_NORETURN_PRE static void 251224090Sdougbusage(void) ISC_PLATFORM_NORETURN_POST; 252224090Sdougb 253224090Sdougbstatic void 254224090Sdougbusage(void) { 255224090Sdougb fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] " 256224090Sdougb "input_file\n"); 257224090Sdougb 258224090Sdougb exit(1); 259224090Sdougb} 260224090Sdougb 261224090Sdougbint 262224090Sdougbmain(int argc, char *argv[]) { 263224090Sdougb int ch; 264224090Sdougb isc_textregion_t tr; 265224090Sdougb isc_mem_t *mctx = NULL; 266224090Sdougb isc_taskmgr_t *taskmgr = NULL; 267224090Sdougb isc_socketmgr_t *socketmgr = NULL; 268224090Sdougb isc_timermgr_t *timermgr = NULL; 269224090Sdougb int nservers = 0; 270224090Sdougb const char *serveraddr[MAX_SERVERS]; 271224090Sdougb isc_sockaddr_t sa[MAX_SERVERS]; 272224090Sdougb isc_sockaddrlist_t servers; 273224090Sdougb dns_rdatatype_t type = dns_rdatatype_a; 274224090Sdougb struct in_addr inaddr; 275224090Sdougb isc_result_t result; 276224090Sdougb int i; 277224090Sdougb 278224090Sdougb while ((ch = getopt(argc, argv, "s:t:")) != -1) { 279224090Sdougb switch (ch) { 280224090Sdougb case 't': 281224090Sdougb tr.base = optarg; 282224090Sdougb tr.length = strlen(optarg); 283224090Sdougb result = dns_rdatatype_fromtext(&type, &tr); 284224090Sdougb if (result != ISC_R_SUCCESS) { 285224090Sdougb fprintf(stderr, 286224090Sdougb "invalid RRtype: %s\n", optarg); 287224090Sdougb exit(1); 288224090Sdougb } 289224090Sdougb break; 290224090Sdougb case 's': 291224090Sdougb if (nservers == MAX_SERVERS) { 292224090Sdougb fprintf(stderr, 293224090Sdougb "too many servers (up to %d)\n", 294224090Sdougb MAX_SERVERS); 295224090Sdougb exit(1); 296224090Sdougb } 297224090Sdougb serveraddr[nservers++] = (const char *)optarg; 298224090Sdougb break; 299224090Sdougb default: 300224090Sdougb usage(); 301224090Sdougb } 302224090Sdougb } 303224090Sdougb 304224090Sdougb argc -= optind; 305224090Sdougb argv += optind; 306224090Sdougb if (argc < 1) 307224090Sdougb usage(); 308224090Sdougb 309224090Sdougb if (nservers == 0) { 310224090Sdougb nservers = 1; 311224090Sdougb serveraddr[0] = def_server; 312224090Sdougb } 313224090Sdougb 314224090Sdougb for (i = 0; i < MAX_QUERIES; i++) { 315224090Sdougb query_array[i].id = i; 316224090Sdougb query_array[i].inuse = ISC_FALSE; 317224090Sdougb query_array[i].type = type; 318224090Sdougb dns_fixedname_init(&query_array[i].fixedname); 319224090Sdougb query_array[i].qname = NULL; 320224090Sdougb ISC_LIST_INIT(query_array[i].answerlist); 321224090Sdougb query_array[i].xid = NULL; 322224090Sdougb } 323224090Sdougb 324224090Sdougb isc_lib_register(); 325224090Sdougb result = dns_lib_init(); 326224090Sdougb if (result != ISC_R_SUCCESS) { 327224090Sdougb fprintf(stderr, "dns_lib_init failed: %d\n", result); 328224090Sdougb exit(1); 329224090Sdougb } 330224090Sdougb 331224090Sdougb result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr, 332224090Sdougb &timermgr); 333224090Sdougb if (result != ISC_R_SUCCESS) { 334224090Sdougb fprintf(stderr, "ctx create failed: %d\n", result); 335224090Sdougb exit(1); 336224090Sdougb } 337224090Sdougb 338224090Sdougb isc_app_ctxstart(query_actx); 339224090Sdougb 340224090Sdougb result = dns_client_createx(mctx, query_actx, taskmgr, socketmgr, 341224090Sdougb timermgr, 0, &client); 342224090Sdougb if (result != ISC_R_SUCCESS) { 343224090Sdougb fprintf(stderr, "dns_client_createx failed: %d\n", result); 344224090Sdougb exit(1); 345224090Sdougb } 346224090Sdougb 347224090Sdougb /* Set nameservers */ 348224090Sdougb ISC_LIST_INIT(servers); 349224090Sdougb for (i = 0; i < nservers; i++) { 350224090Sdougb if (inet_pton(AF_INET, serveraddr[i], &inaddr) != 1) { 351224090Sdougb fprintf(stderr, "failed to parse IPv4 address %s\n", 352224090Sdougb serveraddr[i]); 353224090Sdougb exit(1); 354224090Sdougb } 355224090Sdougb isc_sockaddr_fromin(&sa[i], &inaddr, 53); 356224090Sdougb ISC_LIST_APPEND(servers, &sa[i], link); 357224090Sdougb } 358224090Sdougb result = dns_client_setservers(client, dns_rdataclass_in, NULL, 359224090Sdougb &servers); 360224090Sdougb if (result != ISC_R_SUCCESS) { 361224090Sdougb fprintf(stderr, "set server failed: %d\n", result); 362224090Sdougb exit(1); 363224090Sdougb } 364224090Sdougb 365224090Sdougb /* Create the main task */ 366224090Sdougb query_task = NULL; 367224090Sdougb result = isc_task_create(taskmgr, 0, &query_task); 368224090Sdougb if (result != ISC_R_SUCCESS) { 369224090Sdougb fprintf(stderr, "failed to create task: %d\n", result); 370224090Sdougb exit(1); 371224090Sdougb } 372224090Sdougb 373224090Sdougb /* Open input file */ 374224090Sdougb fp = fopen(argv[0], "r"); 375224090Sdougb if (fp == NULL) { 376224090Sdougb fprintf(stderr, "failed to open input file: %s\n", argv[1]); 377224090Sdougb exit(1); 378224090Sdougb } 379224090Sdougb 380224090Sdougb /* Dispatch initial queries */ 381224090Sdougb for (i = 0; i < MAX_QUERIES; i++) { 382224090Sdougb result = dispatch_query(&query_array[i]); 383224090Sdougb if (result == ISC_R_NOMORE) 384224090Sdougb break; 385224090Sdougb } 386224090Sdougb 387224090Sdougb /* Start event loop */ 388224090Sdougb isc_app_ctxrun(query_actx); 389224090Sdougb 390224090Sdougb /* Sanity check */ 391224090Sdougb for (i = 0; i < MAX_QUERIES; i++) 392224090Sdougb INSIST(query_array[i].inuse == ISC_FALSE); 393224090Sdougb 394224090Sdougb /* Cleanup */ 395224090Sdougb isc_task_detach(&query_task); 396224090Sdougb dns_client_destroy(&client); 397224090Sdougb dns_lib_shutdown(); 398224090Sdougb isc_app_ctxfinish(query_actx); 399224090Sdougb ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr); 400224090Sdougb 401254402Serwin return (0); 402224090Sdougb} 403