/contrib/bind9/lib/export/samples/sample-async.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 402 lines · 307 code · 69 blank · 26 comment · 80 complexity · a6226477eae4725d88af39b11e1cac94 MD5 · raw file

  1. /*
  2. * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
  3. *
  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.
  7. *
  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.
  15. */
  16. /* $Id: sample-async.c,v 1.5 2009/09/29 15:06:07 fdupont Exp $ */
  17. #include <config.h>
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <arpa/inet.h>
  22. #include <unistd.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <isc/app.h>
  27. #include <isc/buffer.h>
  28. #include <isc/lib.h>
  29. #include <isc/mem.h>
  30. #include <isc/socket.h>
  31. #include <isc/sockaddr.h>
  32. #include <isc/task.h>
  33. #include <isc/timer.h>
  34. #include <isc/util.h>
  35. #include <dns/client.h>
  36. #include <dns/fixedname.h>
  37. #include <dns/lib.h>
  38. #include <dns/name.h>
  39. #include <dns/rdataset.h>
  40. #include <dns/rdatatype.h>
  41. #include <dns/result.h>
  42. #define MAX_SERVERS 10
  43. #define MAX_QUERIES 100
  44. static dns_client_t *client = NULL;
  45. static isc_task_t *query_task = NULL;
  46. static isc_appctx_t *query_actx = NULL;
  47. static unsigned int outstanding_queries = 0;
  48. static const char *def_server = "127.0.0.1";
  49. static FILE *fp;
  50. struct query_trans {
  51. int id;
  52. isc_boolean_t inuse;
  53. dns_rdatatype_t type;
  54. dns_fixedname_t fixedname;
  55. dns_name_t *qname;
  56. dns_namelist_t answerlist;
  57. dns_clientrestrans_t *xid;
  58. };
  59. static struct query_trans query_array[MAX_QUERIES];
  60. static isc_result_t dispatch_query(struct query_trans *trans);
  61. static void
  62. ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp,
  63. isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
  64. isc_timermgr_t **timermgrp)
  65. {
  66. if (*taskmgrp != NULL)
  67. isc_taskmgr_destroy(taskmgrp);
  68. if (*timermgrp != NULL)
  69. isc_timermgr_destroy(timermgrp);
  70. if (*socketmgrp != NULL)
  71. isc_socketmgr_destroy(socketmgrp);
  72. if (*actxp != NULL)
  73. isc_appctx_destroy(actxp);
  74. if (*mctxp != NULL)
  75. isc_mem_destroy(mctxp);
  76. }
  77. static isc_result_t
  78. ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
  79. isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
  80. isc_timermgr_t **timermgrp)
  81. {
  82. isc_result_t result;
  83. result = isc_mem_create(0, 0, mctxp);
  84. if (result != ISC_R_SUCCESS)
  85. goto fail;
  86. result = isc_appctx_create(*mctxp, actxp);
  87. if (result != ISC_R_SUCCESS)
  88. goto fail;
  89. result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
  90. if (result != ISC_R_SUCCESS)
  91. goto fail;
  92. result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
  93. if (result != ISC_R_SUCCESS)
  94. goto fail;
  95. result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
  96. if (result != ISC_R_SUCCESS)
  97. goto fail;
  98. return (ISC_R_SUCCESS);
  99. fail:
  100. ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
  101. return (result);
  102. }
  103. static isc_result_t
  104. printdata(dns_rdataset_t *rdataset, dns_name_t *owner) {
  105. isc_buffer_t target;
  106. isc_result_t result;
  107. isc_region_t r;
  108. char t[4096];
  109. isc_buffer_init(&target, t, sizeof(t));
  110. if (!dns_rdataset_isassociated(rdataset))
  111. return (ISC_R_SUCCESS);
  112. result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
  113. &target);
  114. if (result != ISC_R_SUCCESS)
  115. return (result);
  116. isc_buffer_usedregion(&target, &r);
  117. printf(" %.*s", (int)r.length, (char *)r.base);
  118. return (ISC_R_SUCCESS);
  119. }
  120. static void
  121. process_answer(isc_task_t *task, isc_event_t *event) {
  122. struct query_trans *trans = event->ev_arg;
  123. dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
  124. dns_name_t *name;
  125. dns_rdataset_t *rdataset;
  126. isc_result_t result;
  127. REQUIRE(task == query_task);
  128. REQUIRE(trans->inuse == ISC_TRUE);
  129. REQUIRE(outstanding_queries > 0);
  130. printf("answer[%2d]\n", trans->id);
  131. if (rev->result != ISC_R_SUCCESS)
  132. printf(" failed: %d(%s)\n", rev->result,
  133. dns_result_totext(rev->result));
  134. for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
  135. name = ISC_LIST_NEXT(name, link)) {
  136. for (rdataset = ISC_LIST_HEAD(name->list);
  137. rdataset != NULL;
  138. rdataset = ISC_LIST_NEXT(rdataset, link)) {
  139. (void)printdata(rdataset, name);
  140. }
  141. }
  142. dns_client_freeresanswer(client, &rev->answerlist);
  143. dns_client_destroyrestrans(&trans->xid);
  144. isc_event_free(&event);
  145. trans->inuse = ISC_FALSE;
  146. dns_fixedname_invalidate(&trans->fixedname);
  147. trans->qname = NULL;
  148. outstanding_queries--;
  149. result = dispatch_query(trans);
  150. #if 0 /* for cancel test */
  151. if (result == ISC_R_SUCCESS) {
  152. static int count = 0;
  153. if ((++count) % 10 == 0)
  154. dns_client_cancelresolve(trans->xid);
  155. }
  156. #endif
  157. if (result == ISC_R_NOMORE && outstanding_queries == 0)
  158. isc_app_ctxshutdown(query_actx);
  159. }
  160. static isc_result_t
  161. dispatch_query(struct query_trans *trans) {
  162. isc_result_t result;
  163. size_t namelen;
  164. isc_buffer_t b;
  165. char buf[4096]; /* XXX ad hoc constant, but should be enough */
  166. char *cp;
  167. REQUIRE(trans != NULL);
  168. REQUIRE(trans->inuse == ISC_FALSE);
  169. REQUIRE(ISC_LIST_EMPTY(trans->answerlist));
  170. REQUIRE(outstanding_queries < MAX_QUERIES);
  171. /* Construct qname */
  172. cp = fgets(buf, sizeof(buf), fp);
  173. if (cp == NULL)
  174. return (ISC_R_NOMORE);
  175. /* zap NL if any */
  176. if ((cp = strchr(buf, '\n')) != NULL)
  177. *cp = '\0';
  178. namelen = strlen(buf);
  179. isc_buffer_init(&b, buf, namelen);
  180. isc_buffer_add(&b, namelen);
  181. dns_fixedname_init(&trans->fixedname);
  182. trans->qname = dns_fixedname_name(&trans->fixedname);
  183. result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL);
  184. if (result != ISC_R_SUCCESS)
  185. goto cleanup;
  186. /* Start resolution */
  187. result = dns_client_startresolve(client, trans->qname,
  188. dns_rdataclass_in, trans->type, 0,
  189. query_task, process_answer, trans,
  190. &trans->xid);
  191. if (result != ISC_R_SUCCESS)
  192. goto cleanup;
  193. trans->inuse = ISC_TRUE;
  194. outstanding_queries++;
  195. return (ISC_R_SUCCESS);
  196. cleanup:
  197. dns_fixedname_invalidate(&trans->fixedname);
  198. return (result);
  199. }
  200. ISC_PLATFORM_NORETURN_PRE static void
  201. usage(void) ISC_PLATFORM_NORETURN_POST;
  202. static void
  203. usage(void) {
  204. fprintf(stderr, "usage: sample-async [-s server_address] [-t RR type] "
  205. "input_file\n");
  206. exit(1);
  207. }
  208. int
  209. main(int argc, char *argv[]) {
  210. int ch;
  211. isc_textregion_t tr;
  212. isc_mem_t *mctx = NULL;
  213. isc_taskmgr_t *taskmgr = NULL;
  214. isc_socketmgr_t *socketmgr = NULL;
  215. isc_timermgr_t *timermgr = NULL;
  216. int nservers = 0;
  217. const char *serveraddr[MAX_SERVERS];
  218. isc_sockaddr_t sa[MAX_SERVERS];
  219. isc_sockaddrlist_t servers;
  220. dns_rdatatype_t type = dns_rdatatype_a;
  221. struct in_addr inaddr;
  222. isc_result_t result;
  223. int i;
  224. while ((ch = getopt(argc, argv, "s:t:")) != -1) {
  225. switch (ch) {
  226. case 't':
  227. tr.base = optarg;
  228. tr.length = strlen(optarg);
  229. result = dns_rdatatype_fromtext(&type, &tr);
  230. if (result != ISC_R_SUCCESS) {
  231. fprintf(stderr,
  232. "invalid RRtype: %s\n", optarg);
  233. exit(1);
  234. }
  235. break;
  236. case 's':
  237. if (nservers == MAX_SERVERS) {
  238. fprintf(stderr,
  239. "too many servers (up to %d)\n",
  240. MAX_SERVERS);
  241. exit(1);
  242. }
  243. serveraddr[nservers++] = (const char *)optarg;
  244. break;
  245. default:
  246. usage();
  247. }
  248. }
  249. argc -= optind;
  250. argv += optind;
  251. if (argc < 1)
  252. usage();
  253. if (nservers == 0) {
  254. nservers = 1;
  255. serveraddr[0] = def_server;
  256. }
  257. for (i = 0; i < MAX_QUERIES; i++) {
  258. query_array[i].id = i;
  259. query_array[i].inuse = ISC_FALSE;
  260. query_array[i].type = type;
  261. dns_fixedname_init(&query_array[i].fixedname);
  262. query_array[i].qname = NULL;
  263. ISC_LIST_INIT(query_array[i].answerlist);
  264. query_array[i].xid = NULL;
  265. }
  266. isc_lib_register();
  267. result = dns_lib_init();
  268. if (result != ISC_R_SUCCESS) {
  269. fprintf(stderr, "dns_lib_init failed: %d\n", result);
  270. exit(1);
  271. }
  272. result = ctxs_init(&mctx, &query_actx, &taskmgr, &socketmgr,
  273. &timermgr);
  274. if (result != ISC_R_SUCCESS) {
  275. fprintf(stderr, "ctx create failed: %d\n", result);
  276. exit(1);
  277. }
  278. isc_app_ctxstart(query_actx);
  279. result = dns_client_createx(mctx, query_actx, taskmgr, socketmgr,
  280. timermgr, 0, &client);
  281. if (result != ISC_R_SUCCESS) {
  282. fprintf(stderr, "dns_client_createx failed: %d\n", result);
  283. exit(1);
  284. }
  285. /* Set nameservers */
  286. ISC_LIST_INIT(servers);
  287. for (i = 0; i < nservers; i++) {
  288. if (inet_pton(AF_INET, serveraddr[i], &inaddr) != 1) {
  289. fprintf(stderr, "failed to parse IPv4 address %s\n",
  290. serveraddr[i]);
  291. exit(1);
  292. }
  293. isc_sockaddr_fromin(&sa[i], &inaddr, 53);
  294. ISC_LIST_APPEND(servers, &sa[i], link);
  295. }
  296. result = dns_client_setservers(client, dns_rdataclass_in, NULL,
  297. &servers);
  298. if (result != ISC_R_SUCCESS) {
  299. fprintf(stderr, "set server failed: %d\n", result);
  300. exit(1);
  301. }
  302. /* Create the main task */
  303. query_task = NULL;
  304. result = isc_task_create(taskmgr, 0, &query_task);
  305. if (result != ISC_R_SUCCESS) {
  306. fprintf(stderr, "failed to create task: %d\n", result);
  307. exit(1);
  308. }
  309. /* Open input file */
  310. fp = fopen(argv[0], "r");
  311. if (fp == NULL) {
  312. fprintf(stderr, "failed to open input file: %s\n", argv[1]);
  313. exit(1);
  314. }
  315. /* Dispatch initial queries */
  316. for (i = 0; i < MAX_QUERIES; i++) {
  317. result = dispatch_query(&query_array[i]);
  318. if (result == ISC_R_NOMORE)
  319. break;
  320. }
  321. /* Start event loop */
  322. isc_app_ctxrun(query_actx);
  323. /* Sanity check */
  324. for (i = 0; i < MAX_QUERIES; i++)
  325. INSIST(query_array[i].inuse == ISC_FALSE);
  326. /* Cleanup */
  327. isc_task_detach(&query_task);
  328. dns_client_destroy(&client);
  329. dns_lib_shutdown();
  330. isc_app_ctxfinish(query_actx);
  331. ctxs_destroy(&mctx, &query_actx, &taskmgr, &socketmgr, &timermgr);
  332. exit(0);
  333. }