]>
git.saurik.com Git - apple/network_cmds.git/blob - unbound/testcode/asynclook.c
2 * testcode/asynclook.c - debug program perform async libunbound queries.
4 * Copyright (c) 2008, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * This program shows the results from several background lookups,
40 * while printing time in the foreground.
47 #include "libunbound/unbound.h"
48 #include "libunbound/context.h"
49 #include "util/locks.h"
51 #include "ldns/rrdef.h"
52 #ifdef UNBOUND_ALLOC_LITE
60 /** keeping track of the async ids */
62 /** the id to pass to libunbound to cancel */
64 /** true if cancelled */
66 /** a lock on this structure for thread safety */
71 * result list for the lookups
74 /** name to look up */
76 /** tracking number that can be used to cancel the query */
78 /** error code from libunbound */
80 /** result from lookup */
81 struct ub_result
* result
;
84 /** global variable to see how many queries we have left */
85 static int num_wait
= 0;
87 /** usage information for asynclook */
88 static void usage(char* argv
[])
90 printf("usage: %s [options] name ...\n", argv
[0]);
91 printf("names are looked up at the same time, asynchronously.\n");
92 printf(" -b : use blocking requests\n");
93 printf(" -c : cancel the requests\n");
94 printf(" -d : enable debug output\n");
95 printf(" -f addr : use addr, forward to that server\n");
96 printf(" -h : this help message\n");
97 printf(" -H fname : read hosts from fname\n");
98 printf(" -r fname : read resolv.conf from fname\n");
99 printf(" -t : use a resolver thread instead of forking a process\n");
100 printf(" -x : perform extended threaded test\n");
104 /** print result from lookup nicely */
106 print_result(struct lookinfo
* info
)
109 if(info
->err
) /* error (from libunbound) */
110 printf("%s: error %s\n", info
->name
,
111 ub_strerror(info
->err
));
112 else if(!info
->result
)
113 printf("%s: cancelled\n", info
->name
);
114 else if(info
->result
->havedata
)
115 printf("%s: %s\n", info
->name
,
116 inet_ntop(AF_INET
, info
->result
->data
[0],
117 buf
, (socklen_t
)sizeof(buf
)));
119 /* there is no data, why that? */
120 if(info
->result
->rcode
== 0 /*noerror*/ ||
121 info
->result
->nxdomain
)
122 printf("%s: no data %s\n", info
->name
,
123 info
->result
->nxdomain
?"(no such host)":
125 else /* some error (from the server) */
126 printf("%s: DNS error %d\n", info
->name
,
127 info
->result
->rcode
);
131 /** this is a function of type ub_callback_t */
133 lookup_is_done(void* mydata
, int err
, struct ub_result
* result
)
135 /* cast mydata back to the correct type */
136 struct lookinfo
* info
= (struct lookinfo
*)mydata
;
137 fprintf(stderr
, "name %s resolved\n", info
->name
);
139 info
->result
= result
;
140 /* one less to wait for */
144 /** check error, if bad, exit with error message */
146 checkerr(const char* desc
, int err
)
149 printf("%s error: %s\n", desc
, ub_strerror(err
));
154 #ifdef THREADS_DISABLED
155 /** only one process can communicate with async worker */
157 #else /* have threads */
158 /** number of threads to make in extended test */
162 /** struct for extended thread info */
163 struct ext_thr_info
{
164 /** thread num for debug */
170 /** size of array to query */
172 /** array of names to query */
174 /** number of queries to do */
178 /** if true, we are testing against 'localhost' and extra checking is done */
179 static int q_is_localhost
= 0;
181 /** check result structure for the 'correct' answer */
183 ext_check_result(const char* desc
, int err
, struct ub_result
* result
)
187 printf("%s: error result is NULL.\n", desc
);
191 if(strcmp(result
->qname
, "localhost") != 0) {
192 printf("%s: error result has wrong qname.\n", desc
);
195 if(result
->qtype
!= LDNS_RR_TYPE_A
) {
196 printf("%s: error result has wrong qtype.\n", desc
);
199 if(result
->qclass
!= LDNS_RR_CLASS_IN
) {
200 printf("%s: error result has wrong qclass.\n", desc
);
203 if(result
->data
== NULL
) {
204 printf("%s: error result->data is NULL.\n", desc
);
207 if(result
->len
== NULL
) {
208 printf("%s: error result->len is NULL.\n", desc
);
211 if(result
->rcode
!= 0) {
212 printf("%s: error result->rcode is set.\n", desc
);
215 if(result
->havedata
== 0) {
216 printf("%s: error result->havedata is unset.\n", desc
);
219 if(result
->nxdomain
!= 0) {
220 printf("%s: error result->nxdomain is set.\n", desc
);
223 if(result
->secure
|| result
->bogus
) {
224 printf("%s: error result->secure or bogus is set.\n",
228 if(result
->data
[0] == NULL
) {
229 printf("%s: error result->data[0] is NULL.\n", desc
);
232 if(result
->len
[0] != 4) {
233 printf("%s: error result->len[0] is wrong.\n", desc
);
236 if(result
->len
[1] != 0 || result
->data
[1] != NULL
) {
237 printf("%s: error result->data[1] or len[1] is "
241 if(result
->answer_packet
== NULL
) {
242 printf("%s: error result->answer_packet is NULL.\n",
246 if(result
->answer_len
!= 54) {
247 printf("%s: error result->answer_len is wrong.\n",
254 /** extended bg result callback, this function is ub_callback_t */
256 ext_callback(void* mydata
, int err
, struct ub_result
* result
)
258 struct track_id
* my_id
= (struct track_id
*)mydata
;
261 /* I have an id, make sure we are not cancelled */
262 lock_basic_lock(&my_id
->lock
);
264 printf("cb %d: ", my_id
->id
);
266 printf("error: query id=%d returned, but was cancelled\n",
271 lock_basic_unlock(&my_id
->lock
);
273 ext_check_result("ext_callback", err
, result
);
277 pi
.name
= result
?result
->qname
:"noname";
282 ub_resolve_free(result
);
285 /** extended thread worker */
287 ext_thread(void* arg
)
289 struct ext_thr_info
* inf
= (struct ext_thr_info
*)arg
;
291 struct ub_result
* result
;
292 struct track_id
* async_ids
= NULL
;
293 log_thread_set(&inf
->thread_num
);
294 if(inf
->thread_num
> NUMTHR
*2/3) {
295 async_ids
= (struct track_id
*)calloc((size_t)inf
->numq
, sizeof(struct track_id
));
297 printf("out of memory\n");
300 for(i
=0; i
<inf
->numq
; i
++) {
301 lock_basic_init(&async_ids
[i
].lock
);
304 for(i
=0; i
<inf
->numq
; i
++) {
306 r
= ub_resolve_async(inf
->ctx
,
307 inf
->argv
[i%inf
->argc
], LDNS_RR_TYPE_A
,
308 LDNS_RR_CLASS_IN
, &async_ids
[i
], ext_callback
,
310 checkerr("ub_resolve_async", r
);
312 lock_basic_lock(&async_ids
[i
-100].lock
);
313 r
= ub_cancel(inf
->ctx
, async_ids
[i
-100].id
);
315 async_ids
[i
-100].cancel
=1;
316 lock_basic_unlock(&async_ids
[i
-100].lock
);
318 checkerr("ub_cancel", r
);
320 } else if(inf
->thread_num
> NUMTHR
/2) {
322 r
= ub_resolve_async(inf
->ctx
,
323 inf
->argv
[i%inf
->argc
], LDNS_RR_TYPE_A
,
324 LDNS_RR_CLASS_IN
, NULL
, ext_callback
, NULL
);
325 checkerr("ub_resolve_async", r
);
328 r
= ub_resolve(inf
->ctx
, inf
->argv
[i%inf
->argc
],
329 LDNS_RR_TYPE_A
, LDNS_RR_CLASS_IN
, &result
);
330 ext_check_result("ub_resolve", r
, result
);
331 ub_resolve_free(result
);
334 if(inf
->thread_num
> NUMTHR
/2) {
335 r
= ub_wait(inf
->ctx
);
336 checkerr("ub_ctx_wait", r
);
339 for(i
=0; i
<inf
->numq
; i
++) {
340 lock_basic_destroy(&async_ids
[i
].lock
);
348 /** perform extended threaded test */
350 ext_test(struct ub_ctx
* ctx
, int argc
, char** argv
)
352 struct ext_thr_info inf
[NUMTHR
];
354 if(argc
== 1 && strcmp(argv
[0], "localhost") == 0)
356 printf("extended test start (%d threads)\n", NUMTHR
);
357 for(i
=0; i
<NUMTHR
; i
++) {
358 /* 0 = this, 1 = library bg worker */
359 inf
[i
].thread_num
= i
+2;
364 ub_thread_create(&inf
[i
].tid
, ext_thread
, &inf
[i
]);
366 /* the work happens here */
367 for(i
=0; i
<NUMTHR
; i
++) {
368 ub_thread_join(inf
[i
].tid
);
370 printf("extended test end\n");
376 /** getopt global, in case header files fail to declare it. */
378 /** getopt global, in case header files fail to declare it. */
381 /** main program for asynclook */
382 int main(int argc
, char** argv
)
386 struct lookinfo
* lookups
;
387 int i
, r
, cancel
=0, blocking
=0, ext
=0;
389 /* init log now because solaris thr_key_create() is not threadsafe */
391 /* lock debug start (if any) */
395 ctx
= ub_ctx_create();
397 printf("could not create context, %s\n", strerror(errno
));
401 /* command line options */
405 while( (c
=getopt(argc
, argv
, "bcdf:hH:r:tx")) != -1) {
408 r
= ub_ctx_debuglevel(ctx
, 3);
409 checkerr("ub_ctx_debuglevel", r
);
412 r
= ub_ctx_async(ctx
, 1);
413 checkerr("ub_ctx_async", r
);
422 r
= ub_ctx_resolvconf(ctx
, optarg
);
424 printf("ub_ctx_resolvconf "
432 r
= ub_ctx_hosts(ctx
, optarg
);
434 printf("ub_ctx_hosts "
442 r
= ub_ctx_set_fwd(ctx
, optarg
);
443 checkerr("ub_ctx_set_fwd", r
);
458 return ext_test(ctx
, argc
, argv
);
460 /* allocate array for results. */
461 lookups
= (struct lookinfo
*)calloc((size_t)argc
,
462 sizeof(struct lookinfo
));
464 printf("out of memory\n");
468 /* perform asyncronous calls */
470 for(i
=0; i
<argc
; i
++) {
471 lookups
[i
].name
= argv
[i
];
473 fprintf(stderr
, "lookup %s\n", argv
[i
]);
474 r
= ub_resolve(ctx
, argv
[i
], LDNS_RR_TYPE_A
,
475 LDNS_RR_CLASS_IN
, &lookups
[i
].result
);
476 checkerr("ub_resolve", r
);
478 fprintf(stderr
, "start async lookup %s\n", argv
[i
]);
479 r
= ub_resolve_async(ctx
, argv
[i
], LDNS_RR_TYPE_A
,
480 LDNS_RR_CLASS_IN
, &lookups
[i
], &lookup_is_done
,
481 &lookups
[i
].async_id
);
482 checkerr("ub_resolve_async", r
);
488 for(i
=0; i
<argc
; i
++) {
489 fprintf(stderr
, "cancel %s\n", argv
[i
]);
490 r
= ub_cancel(ctx
, lookups
[i
].async_id
);
492 checkerr("ub_cancel", r
);
497 /* wait while the hostnames are looked up. Do something useful here */
499 for(i
=0; i
<1000; i
++) {
501 fprintf(stderr
, "%g seconds passed\n", 0.1*(double)i
);
503 checkerr("ub_process", r
);
508 printf("timed out\n");
511 printf("lookup complete\n");
513 /* print lookup results */
514 for(i
=0; i
<argc
; i
++) {
515 print_result(&lookups
[i
]);
516 ub_resolve_free(lookups
[i
].result
);