2 * Copyright (C) 2009, 2013, 2015 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
17 /* $Id: sample-async.c,v 1.5 2009/09/29 15:06:07 fdupont Exp $ */
21 #include <sys/types.h>
22 #include <sys/socket.h>
24 #include <netinet/in.h>
26 #include <arpa/inet.h>
34 #include <isc/buffer.h>
37 #include <isc/print.h>
38 #include <isc/socket.h>
39 #include <isc/sockaddr.h>
41 #include <isc/timer.h>
44 #include <dns/client.h>
45 #include <dns/fixedname.h>
48 #include <dns/rdataset.h>
49 #include <dns/rdatatype.h>
50 #include <dns/result.h>
52 #define MAX_SERVERS 10
53 #define MAX_QUERIES 100
55 static dns_client_t *client = NULL;
56 static isc_task_t *query_task = NULL;
57 static isc_appctx_t *query_actx = NULL;
58 static unsigned int outstanding_queries = 0;
59 static const char *def_server = "127.0.0.1";
66 dns_fixedname_t fixedname;
68 dns_namelist_t answerlist;
69 dns_clientrestrans_t *xid;
72 static struct query_trans query_array[MAX_QUERIES];
74 static isc_result_t dispatch_query(struct query_trans *trans);
77 ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp,
78 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
79 isc_timermgr_t **timermgrp)
81 if (*taskmgrp != NULL)
82 isc_taskmgr_destroy(taskmgrp);
84 if (*timermgrp != NULL)
85 isc_timermgr_destroy(timermgrp);
87 if (*socketmgrp != NULL)
88 isc_socketmgr_destroy(socketmgrp);
91 isc_appctx_destroy(actxp);
94 isc_mem_destroy(mctxp);
98 ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
99 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
100 isc_timermgr_t **timermgrp)
104 result = isc_mem_create(0, 0, mctxp);
105 if (result != ISC_R_SUCCESS)
108 result = isc_appctx_create(*mctxp, actxp);
109 if (result != ISC_R_SUCCESS)
112 result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
113 if (result != ISC_R_SUCCESS)
116 result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
117 if (result != ISC_R_SUCCESS)
120 result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
121 if (result != ISC_R_SUCCESS)
124 return (ISC_R_SUCCESS);
127 ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
133 printdata(dns_rdataset_t *rdataset, dns_name_t *owner) {
139 isc_buffer_init(&target, t, sizeof(t));
141 if (!dns_rdataset_isassociated(rdataset))
142 return (ISC_R_SUCCESS);
143 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
145 if (result != ISC_R_SUCCESS)
147 isc_buffer_usedregion(&target, &r);
148 printf(" %.*s", (int)r.length, (char *)r.base);
150 return (ISC_R_SUCCESS);
154 process_answer(isc_task_t *task, isc_event_t *event) {
155 struct query_trans *trans = event->ev_arg;
156 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
158 dns_rdataset_t *rdataset;
161 REQUIRE(task == query_task);
162 REQUIRE(trans->inuse == ISC_TRUE);
163 REQUIRE(outstanding_queries > 0);
165 printf("answer[%2d]\n", trans->id);
167 if (rev->result != ISC_R_SUCCESS)
168 printf(" failed: %d(%s)\n", rev->result,
169 dns_result_totext(rev->result));
171 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
172 name = ISC_LIST_NEXT(name, link)) {
173 for (rdataset = ISC_LIST_HEAD(name->list);
175 rdataset = ISC_LIST_NEXT(rdataset, link)) {
176 (void)printdata(rdataset, name);
180 dns_client_freeresanswer(client, &rev->answerlist);
181 dns_client_destroyrestrans(&trans->xid);
183 isc_event_free(&event);
185 trans->inuse = ISC_FALSE;
186 dns_fixedname_invalidate(&trans->fixedname);
188 outstanding_queries--;
190 result = dispatch_query(trans);
191 #if 0 /* for cancel test */
192 if (result == ISC_R_SUCCESS) {
193 static int count = 0;
195 if ((++count) % 10 == 0)
196 dns_client_cancelresolve(trans->xid);
199 if (result == ISC_R_NOMORE && outstanding_queries == 0)
200 isc_app_ctxshutdown(query_actx);
204 dispatch_query(struct query_trans *trans) {
208 char buf[4096]; /* XXX ad hoc constant, but should be enough */
211 REQUIRE(trans != NULL);
212 REQUIRE(trans->inuse == ISC_FALSE);
213 REQUIRE(ISC_LIST_EMPTY(trans->answerlist));
214 REQUIRE(outstanding_queries < MAX_QUERIES);
216 /* Construct qname */
217 cp = fgets(buf, sizeof(buf), fp);
219 return (ISC_R_NOMORE);
221 if ((cp = strchr(buf, '\n')) != NULL)
223 namelen = strlen(buf);
224 isc_buffer_init(&b, buf, namelen);
225 isc_buffer_add(&b, namelen);
226 dns_fixedname_init(&trans->fixedname);
227 trans->qname = dns_fixedname_name(&trans->fixedname);
228 result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL);
229 if (result != ISC_R_SUCCESS)
232 /* Start resolution */
233 result = dns_client_startresolve(client, trans->qname,
234 dns_rdataclass_in, trans->type, 0,
235 query_task, process_answer, trans,
237 if (result != ISC_R_SUCCESS)
240 trans->inuse = ISC_TRUE;
241 outstanding_queries++;
243 return (ISC_R_SUCCESS);
246 dns_fixedname_invalidate(&trans->fixedname);
251 ISC_PLATFORM_NORETURN_PRE static void
252 usage(void) ISC_PLATFORM_NORETURN_POST;
256 fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] "
263 main(int argc, char *argv[]) {
266 isc_mem_t *mctx = NULL;
267 isc_taskmgr_t *taskmgr = NULL;
268 isc_socketmgr_t *socketmgr = NULL;
269 isc_timermgr_t *timermgr = NULL;
271 const char *serveraddr[MAX_SERVERS];
272 isc_sockaddr_t sa[MAX_SERVERS];
273 isc_sockaddrlist_t servers;
274 dns_rdatatype_t type = dns_rdatatype_a;
275 struct in_addr inaddr;
279 while ((ch = getopt(argc, argv, "s:t:")) != -1) {
283 tr.length = strlen(optarg);
284 result = dns_rdatatype_fromtext(&type, &tr);
285 if (result != ISC_R_SUCCESS) {
287 "invalid RRtype: %s\n", optarg);
292 if (nservers == MAX_SERVERS) {
294 "too many servers (up to %d)\n",
298 serveraddr[nservers++] = (const char *)optarg;
312 serveraddr[0] = def_server;
315 for (i = 0; i < MAX_QUERIES; i++) {
316 query_array[i].id = i;
317 query_array[i].inuse = ISC_FALSE;
318 query_array[i].type = type;
319 dns_fixedname_init(&query_array[i].fixedname);
320 query_array[i].qname = NULL;
321 ISC_LIST_INIT(query_array[i].answerlist);
322 query_array[i].xid = NULL;
326 result = dns_lib_init();
327 if (result != ISC_R_SUCCESS) {
328 fprintf(stderr, "dns_lib_init failed: %d\n", result);
332 result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr,
334 if (result != ISC_R_SUCCESS) {
335 fprintf(stderr, "ctx create failed: %d\n", result);
339 isc_app_ctxstart(query_actx);
341 result = dns_client_createx(mctx, query_actx, taskmgr, socketmgr,
342 timermgr, 0, &client);
343 if (result != ISC_R_SUCCESS) {
344 fprintf(stderr, "dns_client_createx failed: %d\n", result);
348 /* Set nameservers */
349 ISC_LIST_INIT(servers);
350 for (i = 0; i < nservers; i++) {
351 if (inet_pton(AF_INET, serveraddr[i], &inaddr) != 1) {
352 fprintf(stderr, "failed to parse IPv4 address %s\n",
356 isc_sockaddr_fromin(&sa[i], &inaddr, 53);
357 ISC_LIST_APPEND(servers, &sa[i], link);
359 result = dns_client_setservers(client, dns_rdataclass_in, NULL,
361 if (result != ISC_R_SUCCESS) {
362 fprintf(stderr, "set server failed: %d\n", result);
366 /* Create the main task */
368 result = isc_task_create(taskmgr, 0, &query_task);
369 if (result != ISC_R_SUCCESS) {
370 fprintf(stderr, "failed to create task: %d\n", result);
374 /* Open input file */
375 fp = fopen(argv[0], "r");
377 fprintf(stderr, "failed to open input file: %s\n", argv[1]);
381 /* Dispatch initial queries */
382 for (i = 0; i < MAX_QUERIES; i++) {
383 result = dispatch_query(&query_array[i]);
384 if (result == ISC_R_NOMORE)
388 /* Start event loop */
389 isc_app_ctxrun(query_actx);
392 for (i = 0; i < MAX_QUERIES; i++)
393 INSIST(query_array[i].inuse == ISC_FALSE);
396 isc_task_detach(&query_task);
397 dns_client_destroy(&client);
399 isc_app_ctxfinish(query_actx);
400 ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr);