aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/testcode/asynclook.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/testcode/asynclook.c')
-rw-r--r--external/unbound/testcode/asynclook.c528
1 files changed, 0 insertions, 528 deletions
diff --git a/external/unbound/testcode/asynclook.c b/external/unbound/testcode/asynclook.c
deleted file mode 100644
index a2bdb6213..000000000
--- a/external/unbound/testcode/asynclook.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * testcode/asynclook.c - debug program perform async libunbound queries.
- *
- * Copyright (c) 2008, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This program shows the results from several background lookups,
- * while printing time in the foreground.
- */
-
-#include "config.h"
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-#include "libunbound/unbound.h"
-#include "libunbound/context.h"
-#include "util/locks.h"
-#include "util/log.h"
-#include "sldns/rrdef.h"
-#ifdef UNBOUND_ALLOC_LITE
-#undef malloc
-#undef calloc
-#undef realloc
-#undef free
-#undef strdup
-#endif
-
-/** keeping track of the async ids */
-struct track_id {
- /** the id to pass to libunbound to cancel */
- int id;
- /** true if cancelled */
- int cancel;
- /** a lock on this structure for thread safety */
- lock_basic_type lock;
-};
-
-/**
- * result list for the lookups
- */
-struct lookinfo {
- /** name to look up */
- char* name;
- /** tracking number that can be used to cancel the query */
- int async_id;
- /** error code from libunbound */
- int err;
- /** result from lookup */
- struct ub_result* result;
-};
-
-/** global variable to see how many queries we have left */
-static int num_wait = 0;
-
-/** usage information for asynclook */
-static void usage(char* argv[])
-{
- printf("usage: %s [options] name ...\n", argv[0]);
- printf("names are looked up at the same time, asynchronously.\n");
- printf(" -b : use blocking requests\n");
- printf(" -c : cancel the requests\n");
- printf(" -d : enable debug output\n");
- printf(" -f addr : use addr, forward to that server\n");
- printf(" -h : this help message\n");
- printf(" -H fname : read hosts from fname\n");
- printf(" -r fname : read resolv.conf from fname\n");
- printf(" -t : use a resolver thread instead of forking a process\n");
- printf(" -x : perform extended threaded test\n");
- exit(1);
-}
-
-/** print result from lookup nicely */
-static void
-print_result(struct lookinfo* info)
-{
- char buf[100];
- if(info->err) /* error (from libunbound) */
- printf("%s: error %s\n", info->name,
- ub_strerror(info->err));
- else if(!info->result)
- printf("%s: cancelled\n", info->name);
- else if(info->result->havedata)
- printf("%s: %s\n", info->name,
- inet_ntop(AF_INET, info->result->data[0],
- buf, (socklen_t)sizeof(buf)));
- else {
- /* there is no data, why that? */
- if(info->result->rcode == 0 /*noerror*/ ||
- info->result->nxdomain)
- printf("%s: no data %s\n", info->name,
- info->result->nxdomain?"(no such host)":
- "(no IP4 address)");
- else /* some error (from the server) */
- printf("%s: DNS error %d\n", info->name,
- info->result->rcode);
- }
-}
-
-/** this is a function of type ub_callback_t */
-static void
-lookup_is_done(void* mydata, int err, struct ub_result* result)
-{
- /* cast mydata back to the correct type */
- struct lookinfo* info = (struct lookinfo*)mydata;
- fprintf(stderr, "name %s resolved\n", info->name);
- info->err = err;
- info->result = result;
- /* one less to wait for */
- num_wait--;
-}
-
-/** check error, if bad, exit with error message */
-static void
-checkerr(const char* desc, int err)
-{
- if(err != 0) {
- printf("%s error: %s\n", desc, ub_strerror(err));
- exit(1);
- }
-}
-
-#ifdef THREADS_DISABLED
-/** only one process can communicate with async worker */
-#define NUMTHR 1
-#else /* have threads */
-/** number of threads to make in extended test */
-#define NUMTHR 10
-#endif
-
-/** struct for extended thread info */
-struct ext_thr_info {
- /** thread num for debug */
- int thread_num;
- /** thread id */
- ub_thread_type tid;
- /** context */
- struct ub_ctx* ctx;
- /** size of array to query */
- int argc;
- /** array of names to query */
- char** argv;
- /** number of queries to do */
- int numq;
-};
-
-/** if true, we are testing against 'localhost' and extra checking is done */
-static int q_is_localhost = 0;
-
-/** check result structure for the 'correct' answer */
-static void
-ext_check_result(const char* desc, int err, struct ub_result* result)
-{
- checkerr(desc, err);
- if(result == NULL) {
- printf("%s: error result is NULL.\n", desc);
- exit(1);
- }
- if(q_is_localhost) {
- if(strcmp(result->qname, "localhost") != 0) {
- printf("%s: error result has wrong qname.\n", desc);
- exit(1);
- }
- if(result->qtype != LDNS_RR_TYPE_A) {
- printf("%s: error result has wrong qtype.\n", desc);
- exit(1);
- }
- if(result->qclass != LDNS_RR_CLASS_IN) {
- printf("%s: error result has wrong qclass.\n", desc);
- exit(1);
- }
- if(result->data == NULL) {
- printf("%s: error result->data is NULL.\n", desc);
- exit(1);
- }
- if(result->len == NULL) {
- printf("%s: error result->len is NULL.\n", desc);
- exit(1);
- }
- if(result->rcode != 0) {
- printf("%s: error result->rcode is set.\n", desc);
- exit(1);
- }
- if(result->havedata == 0) {
- printf("%s: error result->havedata is unset.\n", desc);
- exit(1);
- }
- if(result->nxdomain != 0) {
- printf("%s: error result->nxdomain is set.\n", desc);
- exit(1);
- }
- if(result->secure || result->bogus) {
- printf("%s: error result->secure or bogus is set.\n",
- desc);
- exit(1);
- }
- if(result->data[0] == NULL) {
- printf("%s: error result->data[0] is NULL.\n", desc);
- exit(1);
- }
- if(result->len[0] != 4) {
- printf("%s: error result->len[0] is wrong.\n", desc);
- exit(1);
- }
- if(result->len[1] != 0 || result->data[1] != NULL) {
- printf("%s: error result->data[1] or len[1] is "
- "wrong.\n", desc);
- exit(1);
- }
- if(result->answer_packet == NULL) {
- printf("%s: error result->answer_packet is NULL.\n",
- desc);
- exit(1);
- }
- if(result->answer_len != 54) {
- printf("%s: error result->answer_len is wrong.\n",
- desc);
- exit(1);
- }
- }
-}
-
-/** extended bg result callback, this function is ub_callback_t */
-static void
-ext_callback(void* mydata, int err, struct ub_result* result)
-{
- struct track_id* my_id = (struct track_id*)mydata;
- int doprint = 0;
- if(my_id) {
- /* I have an id, make sure we are not cancelled */
- lock_basic_lock(&my_id->lock);
- if(doprint)
- printf("cb %d: ", my_id->id);
- if(my_id->cancel) {
- printf("error: query id=%d returned, but was cancelled\n",
- my_id->id);
- abort();
- exit(1);
- }
- lock_basic_unlock(&my_id->lock);
- }
- ext_check_result("ext_callback", err, result);
- log_assert(result);
- if(doprint) {
- struct lookinfo pi;
- pi.name = result?result->qname:"noname";
- pi.result = result;
- pi.err = 0;
- print_result(&pi);
- }
- ub_resolve_free(result);
-}
-
-/** extended thread worker */
-static void*
-ext_thread(void* arg)
-{
- struct ext_thr_info* inf = (struct ext_thr_info*)arg;
- int i, r;
- struct ub_result* result;
- struct track_id* async_ids = NULL;
- log_thread_set(&inf->thread_num);
- if(inf->thread_num > NUMTHR*2/3) {
- async_ids = (struct track_id*)calloc((size_t)inf->numq, sizeof(struct track_id));
- if(!async_ids) {
- printf("out of memory\n");
- exit(1);
- }
- for(i=0; i<inf->numq; i++) {
- lock_basic_init(&async_ids[i].lock);
- }
- }
- for(i=0; i<inf->numq; i++) {
- if(async_ids) {
- r = ub_resolve_async(inf->ctx,
- inf->argv[i%inf->argc], LDNS_RR_TYPE_A,
- LDNS_RR_CLASS_IN, &async_ids[i], ext_callback,
- &async_ids[i].id);
- checkerr("ub_resolve_async", r);
- if(i > 100) {
- lock_basic_lock(&async_ids[i-100].lock);
- r = ub_cancel(inf->ctx, async_ids[i-100].id);
- if(r != UB_NOID)
- async_ids[i-100].cancel=1;
- lock_basic_unlock(&async_ids[i-100].lock);
- if(r != UB_NOID)
- checkerr("ub_cancel", r);
- }
- } else if(inf->thread_num > NUMTHR/2) {
- /* async */
- r = ub_resolve_async(inf->ctx,
- inf->argv[i%inf->argc], LDNS_RR_TYPE_A,
- LDNS_RR_CLASS_IN, NULL, ext_callback, NULL);
- checkerr("ub_resolve_async", r);
- } else {
- /* blocking */
- r = ub_resolve(inf->ctx, inf->argv[i%inf->argc],
- LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &result);
- ext_check_result("ub_resolve", r, result);
- ub_resolve_free(result);
- }
- }
- if(inf->thread_num > NUMTHR/2) {
- r = ub_wait(inf->ctx);
- checkerr("ub_ctx_wait", r);
- }
- /* if these locks are destroyed, or if the async_ids is freed, then
- a use-after-free happens in another thread.
- The allocation is only part of this test, though. */
- /*
- if(async_ids) {
- for(i=0; i<inf->numq; i++) {
- lock_basic_destroy(&async_ids[i].lock);
- }
- }
- free(async_ids);
- */
-
- return NULL;
-}
-
-/** perform extended threaded test */
-static int
-ext_test(struct ub_ctx* ctx, int argc, char** argv)
-{
- struct ext_thr_info inf[NUMTHR];
- int i;
- if(argc == 1 && strcmp(argv[0], "localhost") == 0)
- q_is_localhost = 1;
- printf("extended test start (%d threads)\n", NUMTHR);
- for(i=0; i<NUMTHR; i++) {
- /* 0 = this, 1 = library bg worker */
- inf[i].thread_num = i+2;
- inf[i].ctx = ctx;
- inf[i].argc = argc;
- inf[i].argv = argv;
- inf[i].numq = 100;
- ub_thread_create(&inf[i].tid, ext_thread, &inf[i]);
- }
- /* the work happens here */
- for(i=0; i<NUMTHR; i++) {
- ub_thread_join(inf[i].tid);
- }
- printf("extended test end\n");
- ub_ctx_delete(ctx);
- checklock_stop();
- return 0;
-}
-
-/** getopt global, in case header files fail to declare it. */
-extern int optind;
-/** getopt global, in case header files fail to declare it. */
-extern char* optarg;
-
-/** main program for asynclook */
-int main(int argc, char** argv)
-{
- int c;
- struct ub_ctx* ctx;
- struct lookinfo* lookups;
- int i, r, cancel=0, blocking=0, ext=0;
-
- /* init log now because solaris thr_key_create() is not threadsafe */
- log_init(0,0,0);
- /* lock debug start (if any) */
- checklock_start();
-
- /* create context */
- ctx = ub_ctx_create();
- if(!ctx) {
- printf("could not create context, %s\n", strerror(errno));
- return 1;
- }
-
- /* command line options */
- if(argc == 1) {
- usage(argv);
- }
- while( (c=getopt(argc, argv, "bcdf:hH:r:tx")) != -1) {
- switch(c) {
- case 'd':
- r = ub_ctx_debuglevel(ctx, 3);
- checkerr("ub_ctx_debuglevel", r);
- break;
- case 't':
- r = ub_ctx_async(ctx, 1);
- checkerr("ub_ctx_async", r);
- break;
- case 'c':
- cancel = 1;
- break;
- case 'b':
- blocking = 1;
- break;
- case 'r':
- r = ub_ctx_resolvconf(ctx, optarg);
- if(r != 0) {
- printf("ub_ctx_resolvconf "
- "error: %s : %s\n",
- ub_strerror(r),
- strerror(errno));
- return 1;
- }
- break;
- case 'H':
- r = ub_ctx_hosts(ctx, optarg);
- if(r != 0) {
- printf("ub_ctx_hosts "
- "error: %s : %s\n",
- ub_strerror(r),
- strerror(errno));
- return 1;
- }
- break;
- case 'f':
- r = ub_ctx_set_fwd(ctx, optarg);
- checkerr("ub_ctx_set_fwd", r);
- break;
- case 'x':
- ext = 1;
- break;
- case 'h':
- case '?':
- default:
- usage(argv);
- }
- }
- argc -= optind;
- argv += optind;
-
- if(ext)
- return ext_test(ctx, argc, argv);
-
- /* allocate array for results. */
- lookups = (struct lookinfo*)calloc((size_t)argc,
- sizeof(struct lookinfo));
- if(!lookups) {
- printf("out of memory\n");
- return 1;
- }
-
- /* perform asynchronous calls */
- num_wait = argc;
- for(i=0; i<argc; i++) {
- lookups[i].name = argv[i];
- if(blocking) {
- fprintf(stderr, "lookup %s\n", argv[i]);
- r = ub_resolve(ctx, argv[i], LDNS_RR_TYPE_A,
- LDNS_RR_CLASS_IN, &lookups[i].result);
- checkerr("ub_resolve", r);
- } else {
- fprintf(stderr, "start async lookup %s\n", argv[i]);
- r = ub_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A,
- LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done,
- &lookups[i].async_id);
- checkerr("ub_resolve_async", r);
- }
- }
- if(blocking)
- num_wait = 0;
- else if(cancel) {
- for(i=0; i<argc; i++) {
- fprintf(stderr, "cancel %s\n", argv[i]);
- r = ub_cancel(ctx, lookups[i].async_id);
- if(r != UB_NOID)
- checkerr("ub_cancel", r);
- }
- num_wait = 0;
- }
-
- /* wait while the hostnames are looked up. Do something useful here */
- if(num_wait > 0)
- for(i=0; i<1000; i++) {
- usleep(100000);
- fprintf(stderr, "%g seconds passed\n", 0.1*(double)i);
- r = ub_process(ctx);
- checkerr("ub_process", r);
- if(num_wait == 0)
- break;
- }
- if(i>=999) {
- printf("timed out\n");
- return 0;
- }
- printf("lookup complete\n");
-
- /* print lookup results */
- for(i=0; i<argc; i++) {
- print_result(&lookups[i]);
- ub_resolve_free(lookups[i].result);
- }
-
- ub_ctx_delete(ctx);
- free(lookups);
- checklock_stop();
- return 0;
-}