4 * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
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.
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.
19 /* Id: sample-async.c,v 1.5 2009/09/29 15:06:07 fdupont Exp */
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <netinet/in.h>
28 #include <arpa/inet.h>
36 #include <isc/buffer.h>
39 #include <isc/socket.h>
40 #include <isc/sockaddr.h>
42 #include <isc/timer.h>
45 #include <dns/client.h>
46 #include <dns/fixedname.h>
49 #include <dns/rdataset.h>
50 #include <dns/rdatatype.h>
51 #include <dns/result.h>
53 #define MAX_SERVERS 10
54 #define MAX_QUERIES 100
56 static dns_client_t
*client
= NULL
;
57 static isc_task_t
*query_task
= NULL
;
58 static isc_appctx_t
*query_actx
= NULL
;
59 static unsigned int outstanding_queries
= 0;
60 static const char *def_server
= "127.0.0.1";
67 dns_fixedname_t fixedname
;
69 dns_namelist_t answerlist
;
70 dns_clientrestrans_t
*xid
;
73 static struct query_trans query_array
[MAX_QUERIES
];
75 static isc_result_t
dispatch_query(struct query_trans
*trans
);
78 ctxs_destroy(isc_mem_t
**mctxp
, isc_appctx_t
**actxp
,
79 isc_taskmgr_t
**taskmgrp
, isc_socketmgr_t
**socketmgrp
,
80 isc_timermgr_t
**timermgrp
)
82 if (*taskmgrp
!= NULL
)
83 isc_taskmgr_destroy(taskmgrp
);
85 if (*timermgrp
!= NULL
)
86 isc_timermgr_destroy(timermgrp
);
88 if (*socketmgrp
!= NULL
)
89 isc_socketmgr_destroy(socketmgrp
);
92 isc_appctx_destroy(actxp
);
95 isc_mem_destroy(mctxp
);
99 ctxs_init(isc_mem_t
**mctxp
, isc_appctx_t
**actxp
,
100 isc_taskmgr_t
**taskmgrp
, isc_socketmgr_t
**socketmgrp
,
101 isc_timermgr_t
**timermgrp
)
105 result
= isc_mem_create(0, 0, mctxp
);
106 if (result
!= ISC_R_SUCCESS
)
109 result
= isc_appctx_create(*mctxp
, actxp
);
110 if (result
!= ISC_R_SUCCESS
)
113 result
= isc_taskmgr_createinctx(*mctxp
, *actxp
, 1, 0, taskmgrp
);
114 if (result
!= ISC_R_SUCCESS
)
117 result
= isc_socketmgr_createinctx(*mctxp
, *actxp
, socketmgrp
);
118 if (result
!= ISC_R_SUCCESS
)
121 result
= isc_timermgr_createinctx(*mctxp
, *actxp
, timermgrp
);
122 if (result
!= ISC_R_SUCCESS
)
125 return (ISC_R_SUCCESS
);
128 ctxs_destroy(mctxp
, actxp
, taskmgrp
, socketmgrp
, timermgrp
);
134 printdata(dns_rdataset_t
*rdataset
, dns_name_t
*owner
) {
140 isc_buffer_init(&target
, t
, sizeof(t
));
142 if (!dns_rdataset_isassociated(rdataset
))
143 return (ISC_R_SUCCESS
);
144 result
= dns_rdataset_totext(rdataset
, owner
, ISC_FALSE
, ISC_FALSE
,
146 if (result
!= ISC_R_SUCCESS
)
148 isc_buffer_usedregion(&target
, &r
);
149 printf(" %.*s", (int)r
.length
, (char *)r
.base
);
151 return (ISC_R_SUCCESS
);
155 process_answer(isc_task_t
*task
, isc_event_t
*event
) {
156 struct query_trans
*trans
= event
->ev_arg
;
157 dns_clientresevent_t
*rev
= (dns_clientresevent_t
*)event
;
159 dns_rdataset_t
*rdataset
;
162 REQUIRE(task
== query_task
);
163 REQUIRE(trans
->inuse
== ISC_TRUE
);
164 REQUIRE(outstanding_queries
> 0);
166 printf("answer[%2d]\n", trans
->id
);
168 if (rev
->result
!= ISC_R_SUCCESS
)
169 printf(" failed: %d(%s)\n", rev
->result
,
170 dns_result_totext(rev
->result
));
172 for (name
= ISC_LIST_HEAD(rev
->answerlist
); name
!= NULL
;
173 name
= ISC_LIST_NEXT(name
, link
)) {
174 for (rdataset
= ISC_LIST_HEAD(name
->list
);
176 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
177 (void)printdata(rdataset
, name
);
181 dns_client_freeresanswer(client
, &rev
->answerlist
);
182 dns_client_destroyrestrans(&trans
->xid
);
184 isc_event_free(&event
);
186 trans
->inuse
= ISC_FALSE
;
187 dns_fixedname_invalidate(&trans
->fixedname
);
189 outstanding_queries
--;
191 result
= dispatch_query(trans
);
192 #if 0 /* for cancel test */
193 if (result
== ISC_R_SUCCESS
) {
194 static int count
= 0;
196 if ((++count
) % 10 == 0)
197 dns_client_cancelresolve(trans
->xid
);
200 if (result
== ISC_R_NOMORE
&& outstanding_queries
== 0)
201 isc_app_ctxshutdown(query_actx
);
205 dispatch_query(struct query_trans
*trans
) {
209 char buf
[4096]; /* XXX ad hoc constant, but should be enough */
212 REQUIRE(trans
!= NULL
);
213 REQUIRE(trans
->inuse
== ISC_FALSE
);
214 REQUIRE(ISC_LIST_EMPTY(trans
->answerlist
));
215 REQUIRE(outstanding_queries
< MAX_QUERIES
);
217 /* Construct qname */
218 cp
= fgets(buf
, sizeof(buf
), fp
);
220 return (ISC_R_NOMORE
);
222 if ((cp
= strchr(buf
, '\n')) != NULL
)
224 namelen
= strlen(buf
);
225 isc_buffer_init(&b
, buf
, namelen
);
226 isc_buffer_add(&b
, namelen
);
227 dns_fixedname_init(&trans
->fixedname
);
228 trans
->qname
= dns_fixedname_name(&trans
->fixedname
);
229 result
= dns_name_fromtext(trans
->qname
, &b
, dns_rootname
, 0, NULL
);
230 if (result
!= ISC_R_SUCCESS
)
233 /* Start resolution */
234 result
= dns_client_startresolve(client
, trans
->qname
,
235 dns_rdataclass_in
, trans
->type
, 0,
236 query_task
, process_answer
, trans
,
238 if (result
!= ISC_R_SUCCESS
)
241 trans
->inuse
= ISC_TRUE
;
242 outstanding_queries
++;
244 return (ISC_R_SUCCESS
);
247 dns_fixedname_invalidate(&trans
->fixedname
);
252 ISC_PLATFORM_NORETURN_PRE
static void
253 usage(void) ISC_PLATFORM_NORETURN_POST
;
257 fprintf(stderr
, "usage: sample-async [-s server_address] [-t RR type] "
264 main(int argc
, char *argv
[]) {
267 isc_mem_t
*mctx
= NULL
;
268 isc_taskmgr_t
*taskmgr
= NULL
;
269 isc_socketmgr_t
*socketmgr
= NULL
;
270 isc_timermgr_t
*timermgr
= NULL
;
272 const char *serveraddr
[MAX_SERVERS
];
273 isc_sockaddr_t sa
[MAX_SERVERS
];
274 isc_sockaddrlist_t servers
;
275 dns_rdatatype_t type
= dns_rdatatype_a
;
276 struct in_addr inaddr
;
280 while ((ch
= getopt(argc
, argv
, "s:t:")) != -1) {
284 tr
.length
= strlen(optarg
);
285 result
= dns_rdatatype_fromtext(&type
, &tr
);
286 if (result
!= ISC_R_SUCCESS
) {
288 "invalid RRtype: %s\n", optarg
);
293 if (nservers
== MAX_SERVERS
) {
295 "too many servers (up to %d)\n",
299 serveraddr
[nservers
++] = (const char *)optarg
;
313 serveraddr
[0] = def_server
;
316 for (i
= 0; i
< MAX_QUERIES
; i
++) {
317 query_array
[i
].id
= i
;
318 query_array
[i
].inuse
= ISC_FALSE
;
319 query_array
[i
].type
= type
;
320 dns_fixedname_init(&query_array
[i
].fixedname
);
321 query_array
[i
].qname
= NULL
;
322 ISC_LIST_INIT(query_array
[i
].answerlist
);
323 query_array
[i
].xid
= NULL
;
327 result
= dns_lib_init();
328 if (result
!= ISC_R_SUCCESS
) {
329 fprintf(stderr
, "dns_lib_init failed: %d\n", result
);
333 result
= ctxs_init(&mctx
, &query_actx
, &taskmgr
, &socketmgr
,
335 if (result
!= ISC_R_SUCCESS
) {
336 fprintf(stderr
, "ctx create failed: %d\n", result
);
340 isc_app_ctxstart(query_actx
);
342 result
= dns_client_createx(mctx
, query_actx
, taskmgr
, socketmgr
,
343 timermgr
, 0, &client
);
344 if (result
!= ISC_R_SUCCESS
) {
345 fprintf(stderr
, "dns_client_createx failed: %d\n", result
);
349 /* Set nameservers */
350 ISC_LIST_INIT(servers
);
351 for (i
= 0; i
< nservers
; i
++) {
352 if (inet_pton(AF_INET
, serveraddr
[i
], &inaddr
) != 1) {
353 fprintf(stderr
, "failed to parse IPv4 address %s\n",
357 isc_sockaddr_fromin(&sa
[i
], &inaddr
, 53);
358 ISC_LIST_APPEND(servers
, &sa
[i
], link
);
360 result
= dns_client_setservers(client
, dns_rdataclass_in
, NULL
,
362 if (result
!= ISC_R_SUCCESS
) {
363 fprintf(stderr
, "set server failed: %d\n", result
);
367 /* Create the main task */
369 result
= isc_task_create(taskmgr
, 0, &query_task
);
370 if (result
!= ISC_R_SUCCESS
) {
371 fprintf(stderr
, "failed to create task: %d\n", result
);
375 /* Open input file */
376 fp
= fopen(argv
[0], "r");
378 fprintf(stderr
, "failed to open input file: %s\n", argv
[1]);
382 /* Dispatch initial queries */
383 for (i
= 0; i
< MAX_QUERIES
; i
++) {
384 result
= dispatch_query(&query_array
[i
]);
385 if (result
== ISC_R_NOMORE
)
389 /* Start event loop */
390 isc_app_ctxrun(query_actx
);
393 for (i
= 0; i
< MAX_QUERIES
; i
++)
394 INSIST(query_array
[i
].inuse
== ISC_FALSE
);
397 isc_task_detach(&query_task
);
398 dns_client_destroy(&client
);
400 isc_app_ctxfinish(query_actx
);
401 ctxs_destroy(&mctx
, &query_actx
, &taskmgr
, &socketmgr
, &timermgr
);