No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / export / samples / sample-async.c
blob1b2a436d1f8516339d723d6f77bc54210ffbb50d
1 /* $NetBSD$ */
3 /*
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 */
21 #include <config.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
26 #include <netinet/in.h>
28 #include <arpa/inet.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
35 #include <isc/app.h>
36 #include <isc/buffer.h>
37 #include <isc/lib.h>
38 #include <isc/mem.h>
39 #include <isc/socket.h>
40 #include <isc/sockaddr.h>
41 #include <isc/task.h>
42 #include <isc/timer.h>
43 #include <isc/util.h>
45 #include <dns/client.h>
46 #include <dns/fixedname.h>
47 #include <dns/lib.h>
48 #include <dns/name.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";
61 static FILE *fp;
63 struct query_trans {
64 int id;
65 isc_boolean_t inuse;
66 dns_rdatatype_t type;
67 dns_fixedname_t fixedname;
68 dns_name_t *qname;
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);
77 static void
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);
91 if (*actxp != NULL)
92 isc_appctx_destroy(actxp);
94 if (*mctxp != NULL)
95 isc_mem_destroy(mctxp);
98 static isc_result_t
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)
103 isc_result_t result;
105 result = isc_mem_create(0, 0, mctxp);
106 if (result != ISC_R_SUCCESS)
107 goto fail;
109 result = isc_appctx_create(*mctxp, actxp);
110 if (result != ISC_R_SUCCESS)
111 goto fail;
113 result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
114 if (result != ISC_R_SUCCESS)
115 goto fail;
117 result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
118 if (result != ISC_R_SUCCESS)
119 goto fail;
121 result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
122 if (result != ISC_R_SUCCESS)
123 goto fail;
125 return (ISC_R_SUCCESS);
127 fail:
128 ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
130 return (result);
133 static isc_result_t
134 printdata(dns_rdataset_t *rdataset, dns_name_t *owner) {
135 isc_buffer_t target;
136 isc_result_t result;
137 isc_region_t r;
138 char t[4096];
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,
145 &target);
146 if (result != ISC_R_SUCCESS)
147 return (result);
148 isc_buffer_usedregion(&target, &r);
149 printf(" %.*s", (int)r.length, (char *)r.base);
151 return (ISC_R_SUCCESS);
154 static void
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;
158 dns_name_t *name;
159 dns_rdataset_t *rdataset;
160 isc_result_t result;
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);
175 rdataset != NULL;
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);
188 trans->qname = NULL;
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);
199 #endif
200 if (result == ISC_R_NOMORE && outstanding_queries == 0)
201 isc_app_ctxshutdown(query_actx);
204 static isc_result_t
205 dispatch_query(struct query_trans *trans) {
206 isc_result_t result;
207 size_t namelen;
208 isc_buffer_t b;
209 char buf[4096]; /* XXX ad hoc constant, but should be enough */
210 char *cp;
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);
219 if (cp == NULL)
220 return (ISC_R_NOMORE);
221 /* zap NL if any */
222 if ((cp = strchr(buf, '\n')) != NULL)
223 *cp = '\0';
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)
231 goto cleanup;
233 /* Start resolution */
234 result = dns_client_startresolve(client, trans->qname,
235 dns_rdataclass_in, trans->type, 0,
236 query_task, process_answer, trans,
237 &trans->xid);
238 if (result != ISC_R_SUCCESS)
239 goto cleanup;
241 trans->inuse = ISC_TRUE;
242 outstanding_queries++;
244 return (ISC_R_SUCCESS);
246 cleanup:
247 dns_fixedname_invalidate(&trans->fixedname);
249 return (result);
252 ISC_PLATFORM_NORETURN_PRE static void
253 usage(void) ISC_PLATFORM_NORETURN_POST;
255 static void
256 usage(void) {
257 fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] "
258 "input_file\n");
260 exit(1);
264 main(int argc, char *argv[]) {
265 int ch;
266 isc_textregion_t tr;
267 isc_mem_t *mctx = NULL;
268 isc_taskmgr_t *taskmgr = NULL;
269 isc_socketmgr_t *socketmgr = NULL;
270 isc_timermgr_t *timermgr = NULL;
271 int nservers = 0;
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;
277 isc_result_t result;
278 int i;
280 while ((ch = getopt(argc, argv, "s:t:")) != -1) {
281 switch (ch) {
282 case 't':
283 tr.base = optarg;
284 tr.length = strlen(optarg);
285 result = dns_rdatatype_fromtext(&type, &tr);
286 if (result != ISC_R_SUCCESS) {
287 fprintf(stderr,
288 "invalid RRtype: %s\n", optarg);
289 exit(1);
291 break;
292 case 's':
293 if (nservers == MAX_SERVERS) {
294 fprintf(stderr,
295 "too many servers (up to %d)\n",
296 MAX_SERVERS);
297 exit(1);
299 serveraddr[nservers++] = (const char *)optarg;
300 break;
301 default:
302 usage();
306 argc -= optind;
307 argv += optind;
308 if (argc < 1)
309 usage();
311 if (nservers == 0) {
312 nservers = 1;
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;
326 isc_lib_register();
327 result = dns_lib_init();
328 if (result != ISC_R_SUCCESS) {
329 fprintf(stderr, "dns_lib_init failed: %d\n", result);
330 exit(1);
333 result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr,
334 &timermgr);
335 if (result != ISC_R_SUCCESS) {
336 fprintf(stderr, "ctx create failed: %d\n", result);
337 exit(1);
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);
346 exit(1);
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",
354 serveraddr[i]);
355 exit(1);
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,
361 &servers);
362 if (result != ISC_R_SUCCESS) {
363 fprintf(stderr, "set server failed: %d\n", result);
364 exit(1);
367 /* Create the main task */
368 query_task = NULL;
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);
372 exit(1);
375 /* Open input file */
376 fp = fopen(argv[0], "r");
377 if (fp == NULL) {
378 fprintf(stderr, "failed to open input file: %s\n", argv[1]);
379 exit(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)
386 break;
389 /* Start event loop */
390 isc_app_ctxrun(query_actx);
392 /* Sanity check */
393 for (i = 0; i < MAX_QUERIES; i++)
394 INSIST(query_array[i].inuse == ISC_FALSE);
396 /* Cleanup */
397 isc_task_detach(&query_task);
398 dns_client_destroy(&client);
399 dns_lib_shutdown();
400 isc_app_ctxfinish(query_actx);
401 ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr);
403 exit(0);