ipc/chromium/src/third_party/libevent/test/regress_dns.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
     3  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
     4  *
     5  * Redistribution and use in source and binary forms, with or without
     6  * modification, are permitted provided that the following conditions
     7  * are met:
     8  * 1. Redistributions of source code must retain the above copyright
     9  *    notice, this list of conditions and the following disclaimer.
    10  * 2. Redistributions in binary form must reproduce the above copyright
    11  *    notice, this list of conditions and the following disclaimer in the
    12  *    documentation and/or other materials provided with the distribution.
    13  * 3. The name of the author may not be used to endorse or promote products
    14  *    derived from this software without specific prior written permission.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    26  */
    28 #ifdef WIN32
    29 #include <winsock2.h>
    30 #include <windows.h>
    31 #include <ws2tcpip.h>
    32 #endif
    34 #include "event2/event-config.h"
    36 #include <sys/types.h>
    37 #include <sys/stat.h>
    38 #ifdef _EVENT_HAVE_SYS_TIME_H
    39 #include <sys/time.h>
    40 #endif
    41 #include <sys/queue.h>
    42 #ifndef WIN32
    43 #include <sys/socket.h>
    44 #include <signal.h>
    45 #include <netinet/in.h>
    46 #include <arpa/inet.h>
    47 #include <unistd.h>
    48 #endif
    49 #ifdef _EVENT_HAVE_NETINET_IN6_H
    50 #include <netinet/in6.h>
    51 #endif
    52 #ifdef HAVE_NETDB_H
    53 #include <netdb.h>
    54 #endif
    55 #include <fcntl.h>
    56 #include <stdlib.h>
    57 #include <stdio.h>
    58 #include <string.h>
    59 #include <errno.h>
    61 #include "event2/dns.h"
    62 #include "event2/dns_compat.h"
    63 #include "event2/dns_struct.h"
    64 #include "event2/event.h"
    65 #include "event2/event_compat.h"
    66 #include "event2/event_struct.h"
    67 #include "event2/util.h"
    68 #include "event2/listener.h"
    69 #include "event2/bufferevent.h"
    70 #include "log-internal.h"
    71 #include "regress.h"
    72 #include "regress_testutils.h"
    74 #include "../util-internal.h"
    76 static int dns_ok = 0;
    77 static int dns_got_cancel = 0;
    78 static int dns_err = 0;
    81 static void
    82 dns_gethostbyname_cb(int result, char type, int count, int ttl,
    83     void *addresses, void *arg)
    84 {
    85 	dns_ok = dns_err = 0;
    87 	if (result == DNS_ERR_TIMEOUT) {
    88 		printf("[Timed out] ");
    89 		dns_err = result;
    90 		goto out;
    91 	}
    93 	if (result != DNS_ERR_NONE) {
    94 		printf("[Error code %d] ", result);
    95 		goto out;
    96 	}
    98 	TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl));
   100 	switch (type) {
   101 	case DNS_IPv6_AAAA: {
   102 #if defined(_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
   103 		struct in6_addr *in6_addrs = addresses;
   104 		char buf[INET6_ADDRSTRLEN+1];
   105 		int i;
   106 		/* a resolution that's not valid does not help */
   107 		if (ttl < 0)
   108 			goto out;
   109 		for (i = 0; i < count; ++i) {
   110 			const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
   111 			if (b)
   112 				TT_BLATHER(("%s ", b));
   113 			else
   114 				TT_BLATHER(("%s ", strerror(errno)));
   115 		}
   116 #endif
   117 		break;
   118 	}
   119 	case DNS_IPv4_A: {
   120 		struct in_addr *in_addrs = addresses;
   121 		int i;
   122 		/* a resolution that's not valid does not help */
   123 		if (ttl < 0)
   124 			goto out;
   125 		for (i = 0; i < count; ++i)
   126 			TT_BLATHER(("%s ", inet_ntoa(in_addrs[i])));
   127 		break;
   128 	}
   129 	case DNS_PTR:
   130 		/* may get at most one PTR */
   131 		if (count != 1)
   132 			goto out;
   134 		TT_BLATHER(("%s ", *(char **)addresses));
   135 		break;
   136 	default:
   137 		goto out;
   138 	}
   140 	dns_ok = type;
   142 out:
   143 	if (arg == NULL)
   144 		event_loopexit(NULL);
   145 	else
   146 		event_base_loopexit((struct event_base *)arg, NULL);
   147 }
   149 static void
   150 dns_gethostbyname(void)
   151 {
   152 	dns_ok = 0;
   153 	evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
   154 	event_dispatch();
   156 	tt_int_op(dns_ok, ==, DNS_IPv4_A);
   157 	test_ok = dns_ok;
   158 end:
   159 	;
   160 }
   162 static void
   163 dns_gethostbyname6(void)
   164 {
   165 	dns_ok = 0;
   166 	evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
   167 	event_dispatch();
   169 	if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
   170 		tt_skip();
   171 	}
   173 	tt_int_op(dns_ok, ==, DNS_IPv6_AAAA);
   174 	test_ok = 1;
   175 end:
   176 	;
   177 }
   179 static void
   180 dns_gethostbyaddr(void)
   181 {
   182 	struct in_addr in;
   183 	in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
   184 	dns_ok = 0;
   185 	evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
   186 	event_dispatch();
   188 	tt_int_op(dns_ok, ==, DNS_PTR);
   189 	test_ok = dns_ok;
   190 end:
   191 	;
   192 }
   194 static void
   195 dns_resolve_reverse(void *ptr)
   196 {
   197 	struct in_addr in;
   198 	struct event_base *base = event_base_new();
   199 	struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */);
   200 	struct evdns_request *req = NULL;
   202 	tt_assert(base);
   203 	tt_assert(dns);
   204 	in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
   205 	dns_ok = 0;
   207 	req = evdns_base_resolve_reverse(
   208 		dns, &in, 0, dns_gethostbyname_cb, base);
   209 	tt_assert(req);
   211 	event_base_dispatch(base);
   213 	tt_int_op(dns_ok, ==, DNS_PTR);
   215 end:
   216 	if (dns)
   217 		evdns_base_free(dns, 0);
   218 	if (base)
   219 		event_base_free(base);
   220 }
   222 static int n_server_responses = 0;
   224 static void
   225 dns_server_request_cb(struct evdns_server_request *req, void *data)
   226 {
   227 	int i, r;
   228 	const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
   229 	const char TEST_IN6[] =
   230 	    "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1."
   231 	    "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa";
   233 	for (i = 0; i < req->nquestions; ++i) {
   234 		const int qtype = req->questions[i]->type;
   235 		const int qclass = req->questions[i]->dns_question_class;
   236 		const char *qname = req->questions[i]->name;
   238 		struct in_addr ans;
   239 		ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
   240 		if (qtype == EVDNS_TYPE_A &&
   241 		    qclass == EVDNS_CLASS_INET &&
   242 		    !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
   243 			r = evdns_server_request_add_a_reply(req, qname,
   244 			    1, &ans.s_addr, 12345);
   245 			if (r<0)
   246 				dns_ok = 0;
   247 		} else if (qtype == EVDNS_TYPE_AAAA &&
   248 		    qclass == EVDNS_CLASS_INET &&
   249 		    !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
   250 			char addr6[17] = "abcdefghijklmnop";
   251 			r = evdns_server_request_add_aaaa_reply(req,
   252 			    qname, 1, addr6, 123);
   253 			if (r<0)
   254 				dns_ok = 0;
   255 		} else if (qtype == EVDNS_TYPE_PTR &&
   256 		    qclass == EVDNS_CLASS_INET &&
   257 		    !evutil_ascii_strcasecmp(qname, TEST_ARPA)) {
   258 			r = evdns_server_request_add_ptr_reply(req, NULL,
   259 			    qname, "ZZ.EXAMPLE.COM", 54321);
   260 			if (r<0)
   261 				dns_ok = 0;
   262 		} else if (qtype == EVDNS_TYPE_PTR &&
   263 		    qclass == EVDNS_CLASS_INET &&
   264 		    !evutil_ascii_strcasecmp(qname, TEST_IN6)){
   265 			r = evdns_server_request_add_ptr_reply(req, NULL,
   266 			    qname,
   267 			    "ZZ-INET6.EXAMPLE.COM", 54322);
   268 			if (r<0)
   269 				dns_ok = 0;
   270 		} else if (qtype == EVDNS_TYPE_A &&
   271 		    qclass == EVDNS_CLASS_INET &&
   272 		    !evutil_ascii_strcasecmp(qname, "drop.example.com")) {
   273 			if (evdns_server_request_drop(req)<0)
   274 				dns_ok = 0;
   275 			return;
   276 		} else {
   277 			printf("Unexpected question %d %d \"%s\" ",
   278 			    qtype, qclass, qname);
   279 			dns_ok = 0;
   280 		}
   281 	}
   282 	r = evdns_server_request_respond(req, 0);
   283 	if (r<0) {
   284 		printf("Couldn't send reply. ");
   285 		dns_ok = 0;
   286 	}
   287 }
   289 static void
   290 dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
   291     void *addresses, void *arg)
   292 {
   293 	if (result == DNS_ERR_CANCEL) {
   294 		if (arg != (void*)(char*)90909) {
   295 			printf("Unexpected cancelation");
   296 			dns_ok = 0;
   297 		}
   298 		dns_got_cancel = 1;
   299 		goto out;
   300 	}
   301 	if (result != DNS_ERR_NONE) {
   302 		printf("Unexpected result %d. ", result);
   303 		dns_ok = 0;
   304 		goto out;
   305 	}
   306 	if (count != 1) {
   307 		printf("Unexpected answer count %d. ", count);
   308 		dns_ok = 0;
   309 		goto out;
   310 	}
   311 	switch (type) {
   312 	case DNS_IPv4_A: {
   313 		struct in_addr *in_addrs = addresses;
   314 		if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
   315 			printf("Bad IPv4 response \"%s\" %d. ",
   316 					inet_ntoa(in_addrs[0]), ttl);
   317 			dns_ok = 0;
   318 			goto out;
   319 		}
   320 		break;
   321 	}
   322 	case DNS_IPv6_AAAA: {
   323 #if defined (_EVENT_HAVE_STRUCT_IN6_ADDR) && defined(_EVENT_HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
   324 		struct in6_addr *in6_addrs = addresses;
   325 		char buf[INET6_ADDRSTRLEN+1];
   326 		if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
   327 		    || ttl != 123) {
   328 			const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
   329 			printf("Bad IPv6 response \"%s\" %d. ", b, ttl);
   330 			dns_ok = 0;
   331 			goto out;
   332 		}
   333 #endif
   334 		break;
   335 	}
   336 	case DNS_PTR: {
   337 		char **addrs = addresses;
   338 		if (arg != (void*)6) {
   339 			if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") ||
   340 			    ttl != 54321) {
   341 				printf("Bad PTR response \"%s\" %d. ",
   342 				    addrs[0], ttl);
   343 				dns_ok = 0;
   344 				goto out;
   345 			}
   346 		} else {
   347 			if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") ||
   348 			    ttl != 54322) {
   349 				printf("Bad ipv6 PTR response \"%s\" %d. ",
   350 				    addrs[0], ttl);
   351 				dns_ok = 0;
   352 				goto out;
   353 			}
   354 		}
   355 		break;
   356 	}
   357 	default:
   358 		printf("Bad response type %d. ", type);
   359 		dns_ok = 0;
   360 	}
   361  out:
   362 	if (++n_server_responses == 3) {
   363 		event_loopexit(NULL);
   364 	}
   365 }
   367 static void
   368 dns_server(void)
   369 {
   370 	evutil_socket_t sock=-1;
   371 	struct sockaddr_in my_addr;
   372 	struct sockaddr_storage ss;
   373 	ev_socklen_t slen;
   374 	struct evdns_server_port *port=NULL;
   375 	struct in_addr resolve_addr;
   376 	struct in6_addr resolve_addr6;
   377 	struct evdns_base *base=NULL;
   378 	struct evdns_request *req=NULL;
   380 	dns_ok = 1;
   382 	base = evdns_base_new(NULL, 0);
   384 	/* Now configure a nameserver port. */
   385 	sock = socket(AF_INET, SOCK_DGRAM, 0);
   386 	if (sock<0) {
   387 		tt_abort_perror("socket");
   388 	}
   390 	evutil_make_socket_nonblocking(sock);
   392 	memset(&my_addr, 0, sizeof(my_addr));
   393 	my_addr.sin_family = AF_INET;
   394 	my_addr.sin_port = 0; /* kernel picks */
   395 	my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
   396 	if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
   397 		tt_abort_perror("bind");
   398 	}
   399 	slen = sizeof(ss);
   400 	if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) {
   401 		tt_abort_perror("getsockname");
   402 	}
   404 	port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
   406 	/* Add ourself as the only nameserver, and make sure we really are
   407 	 * the only nameserver. */
   408 	evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0);
   409 	tt_int_op(evdns_base_count_nameservers(base), ==, 1);
   411 	/* Send some queries. */
   412 	evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
   413 					   dns_server_gethostbyname_cb, NULL);
   414 	evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
   415 					   dns_server_gethostbyname_cb, NULL);
   416 	resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
   417 	evdns_base_resolve_reverse(base, &resolve_addr, 0,
   418 	    dns_server_gethostbyname_cb, NULL);
   419 	memcpy(resolve_addr6.s6_addr,
   420 	    "\xff\xf0\x00\x00\x00\x00\xaa\xaa"
   421 	    "\x11\x11\x00\x00\x00\x00\xef\xef", 16);
   422 	evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0,
   423 	    dns_server_gethostbyname_cb, (void*)6);
   425 	req = evdns_base_resolve_ipv4(base,
   426 	    "drop.example.com", DNS_QUERY_NO_SEARCH,
   427 	    dns_server_gethostbyname_cb, (void*)(char*)90909);
   429 	evdns_cancel_request(base, req);
   431 	event_dispatch();
   433 	tt_assert(dns_got_cancel);
   434 	test_ok = dns_ok;
   436 end:
   437 	if (port)
   438 		evdns_close_server_port(port);
   439 	if (sock >= 0)
   440 		evutil_closesocket(sock);
   441 	if (base)
   442 		evdns_base_free(base, 0);
   443 }
   445 static int n_replies_left;
   446 static struct event_base *exit_base;
   448 struct generic_dns_callback_result {
   449 	int result;
   450 	char type;
   451 	int count;
   452 	int ttl;
   453 	size_t addrs_len;
   454 	void *addrs;
   455 	char addrs_buf[256];
   456 };
   458 static void
   459 generic_dns_callback(int result, char type, int count, int ttl, void *addresses,
   460     void *arg)
   461 {
   462 	size_t len;
   463 	struct generic_dns_callback_result *res = arg;
   464 	res->result = result;
   465 	res->type = type;
   466 	res->count = count;
   467 	res->ttl = ttl;
   469 	if (type == DNS_IPv4_A)
   470 		len = count * 4;
   471 	else if (type == DNS_IPv6_AAAA)
   472 		len = count * 16;
   473 	else if (type == DNS_PTR)
   474 		len = strlen(addresses)+1;
   475 	else {
   476 		res->addrs_len = len = 0;
   477 		res->addrs = NULL;
   478 	}
   479 	if (len) {
   480 		res->addrs_len = len;
   481 		if (len > 256)
   482 			len = 256;
   483 		memcpy(res->addrs_buf, addresses, len);
   484 		res->addrs = res->addrs_buf;
   485 	}
   487 	if (--n_replies_left == 0)
   488 		event_base_loopexit(exit_base, NULL);
   489 }
   491 static struct regress_dns_server_table search_table[] = {
   492 	{ "host.a.example.com", "err", "3", 0 },
   493 	{ "host.b.example.com", "err", "3", 0 },
   494 	{ "host.c.example.com", "A", "11.22.33.44", 0 },
   495 	{ "host2.a.example.com", "err", "3", 0 },
   496 	{ "host2.b.example.com", "A", "200.100.0.100", 0 },
   497 	{ "host2.c.example.com", "err", "3", 0 },
   498 	{ "hostn.a.example.com", "errsoa", "0", 0 },
   499 	{ "hostn.b.example.com", "errsoa", "3", 0 },
   500 	{ "hostn.c.example.com", "err", "0", 0 },
   502 	{ "host", "err", "3", 0 },
   503 	{ "host2", "err", "3", 0 },
   504 	{ "*", "err", "3", 0 },
   505 	{ NULL, NULL, NULL, 0 }
   506 };
   508 static void
   509 dns_search_test(void *arg)
   510 {
   511 	struct basic_test_data *data = arg;
   512 	struct event_base *base = data->base;
   513 	struct evdns_base *dns = NULL;
   514 	ev_uint16_t portnum = 0;
   515 	char buf[64];
   517 	struct generic_dns_callback_result r[8];
   519 	tt_assert(regress_dnsserver(base, &portnum, search_table));
   520 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
   522 	dns = evdns_base_new(base, 0);
   523 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
   525 	evdns_base_search_add(dns, "a.example.com");
   526 	evdns_base_search_add(dns, "b.example.com");
   527 	evdns_base_search_add(dns, "c.example.com");
   529 	n_replies_left = sizeof(r)/sizeof(r[0]);
   530 	exit_base = base;
   532 	evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
   533 	evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]);
   534 	evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]);
   535 	evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]);
   536 	evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]);
   537 	evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
   538 	evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
   539 	evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);
   541 	event_base_dispatch(base);
   543 	tt_int_op(r[0].type, ==, DNS_IPv4_A);
   544 	tt_int_op(r[0].count, ==, 1);
   545 	tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c));
   546 	tt_int_op(r[1].type, ==, DNS_IPv4_A);
   547 	tt_int_op(r[1].count, ==, 1);
   548 	tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064));
   549 	tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST);
   550 	tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST);
   551 	tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST);
   552 	tt_int_op(r[5].result, ==, DNS_ERR_NODATA);
   553 	tt_int_op(r[5].ttl, ==, 42);
   554 	tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST);
   555 	tt_int_op(r[6].ttl, ==, 42);
   556 	tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
   557 	tt_int_op(r[7].ttl, ==, 0);
   559 end:
   560 	if (dns)
   561 		evdns_base_free(dns, 0);
   563 	regress_clean_dnsserver();
   564 }
   566 static int request_count = 0;
   567 static struct evdns_request *current_req = NULL;
   569 static void
   570 search_cancel_server_cb(struct evdns_server_request *req, void *data)
   571 {
   572 	const char *question;
   574 	if (req->nquestions != 1)
   575 		TT_DIE(("Only handling one question at a time; got %d",
   576 			req->nquestions));
   578 	question = req->questions[0]->name;
   580 	TT_BLATHER(("got question, %s", question));
   582 	tt_assert(request_count > 0);
   583 	tt_assert(!evdns_server_request_respond(req, 3));
   585 	if (!--request_count)
   586 		evdns_cancel_request(NULL, current_req);
   588 end:
   589 	;
   590 }
   592 static void
   593 dns_search_cancel_test(void *arg)
   594 {
   595 	struct basic_test_data *data = arg;
   596 	struct event_base *base = data->base;
   597 	struct evdns_base *dns = NULL;
   598 	struct evdns_server_port *port = NULL;
   599 	ev_uint16_t portnum = 0;
   600 	struct generic_dns_callback_result r1;
   601 	char buf[64];
   603 	port = regress_get_dnsserver(base, &portnum, NULL,
   604 	    search_cancel_server_cb, NULL);
   605 	tt_assert(port);
   606 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
   608 	dns = evdns_base_new(base, 0);
   609 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
   611 	evdns_base_search_add(dns, "a.example.com");
   612 	evdns_base_search_add(dns, "b.example.com");
   613 	evdns_base_search_add(dns, "c.example.com");
   614 	evdns_base_search_add(dns, "d.example.com");
   616 	exit_base = base;
   617 	request_count = 3;
   618 	n_replies_left = 1;
   620 	current_req = evdns_base_resolve_ipv4(dns, "host", 0,
   621 					generic_dns_callback, &r1);
   622 	event_base_dispatch(base);
   624 	tt_int_op(r1.result, ==, DNS_ERR_CANCEL);
   626 end:
   627 	if (port)
   628 		evdns_close_server_port(port);
   629 	if (dns)
   630 		evdns_base_free(dns, 0);
   631 }
   633 static void
   634 fail_server_cb(struct evdns_server_request *req, void *data)
   635 {
   636 	const char *question;
   637 	int *count = data;
   638 	struct in_addr in;
   640 	/* Drop the first N requests that we get. */
   641 	if (*count > 0) {
   642 		--*count;
   643 		tt_want(! evdns_server_request_drop(req));
   644 		return;
   645 	}
   647 	if (req->nquestions != 1)
   648 		TT_DIE(("Only handling one question at a time; got %d",
   649 			req->nquestions));
   651 	question = req->questions[0]->name;
   653 	if (!evutil_ascii_strcasecmp(question, "google.com")) {
   654 		/* Detect a probe, and get out of the loop. */
   655 		event_base_loopexit(exit_base, NULL);
   656 	}
   658 	evutil_inet_pton(AF_INET, "16.32.64.128", &in);
   659 	evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
   660 	    100);
   661 	tt_assert(! evdns_server_request_respond(req, 0))
   662 	return;
   663 end:
   664 	tt_want(! evdns_server_request_drop(req));
   665 }
   667 static void
   668 dns_retry_test(void *arg)
   669 {
   670 	struct basic_test_data *data = arg;
   671 	struct event_base *base = data->base;
   672 	struct evdns_server_port *port = NULL;
   673 	struct evdns_base *dns = NULL;
   674 	int drop_count = 2;
   675 	ev_uint16_t portnum = 0;
   676 	char buf[64];
   678 	struct generic_dns_callback_result r1;
   680 	port = regress_get_dnsserver(base, &portnum, NULL,
   681 	    fail_server_cb, &drop_count);
   682 	tt_assert(port);
   683 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
   685 	dns = evdns_base_new(base, 0);
   686 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
   687 	tt_assert(! evdns_base_set_option(dns, "timeout", "0.3"));
   688 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10"));
   689 	tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.5"));
   691 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
   692 	    generic_dns_callback, &r1);
   694 	n_replies_left = 1;
   695 	exit_base = base;
   697 	event_base_dispatch(base);
   699 	tt_int_op(drop_count, ==, 0);
   701 	tt_int_op(r1.type, ==, DNS_IPv4_A);
   702 	tt_int_op(r1.count, ==, 1);
   703 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
   705 	/* Now try again, but this time have the server get treated as
   706 	 * failed, so we can send it a test probe. */
   707 	drop_count = 4;
   708 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "3"));
   709 	tt_assert(! evdns_base_set_option(dns, "attempts:", "4"));
   710 	memset(&r1, 0, sizeof(r1));
   712 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
   713 	    generic_dns_callback, &r1);
   715 	n_replies_left = 2;
   717 	/* This will run until it answers the "google.com" probe request. */
   718 	event_base_dispatch(base);
   720 	/* We'll treat the server as failed here. */
   721 	tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
   723 	/* It should work this time. */
   724 	tt_int_op(drop_count, ==, 0);
   725 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
   726 	    generic_dns_callback, &r1);
   728 	event_base_dispatch(base);
   729 	tt_int_op(r1.result, ==, DNS_ERR_NONE);
   730 	tt_int_op(r1.type, ==, DNS_IPv4_A);
   731 	tt_int_op(r1.count, ==, 1);
   732 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
   734 end:
   735 	if (dns)
   736 		evdns_base_free(dns, 0);
   737 	if (port)
   738 		evdns_close_server_port(port);
   739 }
   741 static struct regress_dns_server_table internal_error_table[] = {
   742 	/* Error 4 (NOTIMPL) makes us reissue the request to another server
   743 	   if we can.
   745 	   XXXX we should reissue under a much wider set of circumstances!
   746 	 */
   747 	{ "foof.example.com", "err", "4", 0 },
   748 	{ NULL, NULL, NULL, 0 }
   749 };
   751 static struct regress_dns_server_table reissue_table[] = {
   752 	{ "foof.example.com", "A", "240.15.240.15", 0 },
   753 	{ NULL, NULL, NULL, 0 }
   754 };
   756 static void
   757 dns_reissue_test(void *arg)
   758 {
   759 	struct basic_test_data *data = arg;
   760 	struct event_base *base = data->base;
   761 	struct evdns_server_port *port1 = NULL, *port2 = NULL;
   762 	struct evdns_base *dns = NULL;
   763 	struct generic_dns_callback_result r1;
   764 	ev_uint16_t portnum1 = 0, portnum2=0;
   765 	char buf1[64], buf2[64];
   767 	port1 = regress_get_dnsserver(base, &portnum1, NULL,
   768 	    regress_dns_server_cb, internal_error_table);
   769 	tt_assert(port1);
   770 	port2 = regress_get_dnsserver(base, &portnum2, NULL,
   771 	    regress_dns_server_cb, reissue_table);
   772 	tt_assert(port2);
   773 	evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1);
   774 	evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2);
   776 	dns = evdns_base_new(base, 0);
   777 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf1));
   778 	tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3"));
   779 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
   780 	tt_assert(! evdns_base_set_option(dns, "attempts:", "5"));
   782 	memset(&r1, 0, sizeof(r1));
   783 	evdns_base_resolve_ipv4(dns, "foof.example.com", 0,
   784 	    generic_dns_callback, &r1);
   786 	/* Add this after, so that we are sure to get a reissue. */
   787 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf2));
   789 	n_replies_left = 1;
   790 	exit_base = base;
   792 	event_base_dispatch(base);
   793 	tt_int_op(r1.result, ==, DNS_ERR_NONE);
   794 	tt_int_op(r1.type, ==, DNS_IPv4_A);
   795 	tt_int_op(r1.count, ==, 1);
   796 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f));
   798 	/* Make sure we dropped at least once. */
   799 	tt_int_op(internal_error_table[0].seen, >, 0);
   801 end:
   802 	if (dns)
   803 		evdns_base_free(dns, 0);
   804 	if (port1)
   805 		evdns_close_server_port(port1);
   806 	if (port2)
   807 		evdns_close_server_port(port2);
   808 }
   810 #if 0
   811 static void
   812 dumb_bytes_fn(char *p, size_t n)
   813 {
   814 	unsigned i;
   815 	/* This gets us 6 bits of entropy per transaction ID, which means we
   816 	 * will have probably have collisions and need to pick again. */
   817 	for (i=0;i<n;++i)
   818 		p[i] = (char)(rand() & 7);
   819 }
   820 #endif
   822 static void
   823 dns_inflight_test(void *arg)
   824 {
   825 	struct basic_test_data *data = arg;
   826 	struct event_base *base = data->base;
   827 	struct evdns_base *dns = NULL;
   828 	ev_uint16_t portnum = 0;
   829 	char buf[64];
   831 	struct generic_dns_callback_result r[20];
   832 	int i;
   834 	tt_assert(regress_dnsserver(base, &portnum, reissue_table));
   835 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
   837 	dns = evdns_base_new(base, 0);
   838 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
   839 	tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3"));
   840 	tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0"));
   842 	for (i=0;i<20;++i)
   843 		evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
   845 	n_replies_left = 20;
   846 	exit_base = base;
   848 	event_base_dispatch(base);
   850 	for (i=0;i<20;++i) {
   851 		tt_int_op(r[i].type, ==, DNS_IPv4_A);
   852 		tt_int_op(r[i].count, ==, 1);
   853 		tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f));
   854 	}
   856 end:
   857 	if (dns)
   858 		evdns_base_free(dns, 0);
   859 	regress_clean_dnsserver();
   860 }
   862 /* === Test for bufferevent_socket_connect_hostname */
   864 static int total_connected_or_failed = 0;
   865 static int total_n_accepted = 0;
   866 static struct event_base *be_connect_hostname_base = NULL;
   868 /* Implements a DNS server for the connect_hostname test and the
   869  * getaddrinfo_async test */
   870 static void
   871 be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data)
   872 {
   873 	int i;
   874 	int *n_got_p=data;
   875 	int added_any=0;
   876 	++*n_got_p;
   878 	for (i=0;i<req->nquestions;++i) {
   879 		const int qtype = req->questions[i]->type;
   880 		const int qclass = req->questions[i]->dns_question_class;
   881 		const char *qname = req->questions[i]->name;
   882 		struct in_addr ans;
   883 		struct in6_addr ans6;
   884 		memset(&ans6, 0, sizeof(ans6));
   886 		if (qtype == EVDNS_TYPE_A &&
   887 		    qclass == EVDNS_CLASS_INET &&
   888 		    !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) {
   889 			ans.s_addr = htonl(0x7f000001);
   890 			evdns_server_request_add_a_reply(req, qname,
   891 			    1, &ans.s_addr, 2000);
   892 			added_any = 1;
   893 		} else if (!evutil_ascii_strcasecmp(qname,
   894 			"nosuchplace.example.com")) {
   895 			/* ok, just say notfound. */
   896 		} else if (!evutil_ascii_strcasecmp(qname,
   897 			"both.example.com")) {
   898 			if (qtype == EVDNS_TYPE_A) {
   899 				ans.s_addr = htonl(0x50502020);
   900 				evdns_server_request_add_a_reply(req, qname,
   901 				    1, &ans.s_addr, 2000);
   902 				added_any = 1;
   903 			} else if (qtype == EVDNS_TYPE_AAAA) {
   904 				ans6.s6_addr[0] = 0x80;
   905 				ans6.s6_addr[1] = 0xff;
   906 				ans6.s6_addr[14] = 0xbb;
   907 				ans6.s6_addr[15] = 0xbb;
   908 				evdns_server_request_add_aaaa_reply(req, qname,
   909 				    1, &ans6.s6_addr, 2000);
   910 				added_any = 1;
   911 			}
   912 			evdns_server_request_add_cname_reply(req, qname,
   913 			    "both-canonical.example.com", 1000);
   914 		} else if (!evutil_ascii_strcasecmp(qname,
   915 			"v4only.example.com") ||
   916 		    !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) {
   917 			if (qtype == EVDNS_TYPE_A) {
   918 				ans.s_addr = htonl(0x12345678);
   919 				evdns_server_request_add_a_reply(req, qname,
   920 				    1, &ans.s_addr, 2000);
   921 				added_any = 1;
   922 			} else if (!evutil_ascii_strcasecmp(qname,
   923 				"v4assert.example.com")) {
   924 				TT_FAIL(("Got an AAAA request for v4assert"));
   925 			}
   926 		} else if (!evutil_ascii_strcasecmp(qname,
   927 			"v6only.example.com") ||
   928 		    !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) {
   929 			if (qtype == EVDNS_TYPE_AAAA) {
   930 				ans6.s6_addr[0] = 0x0b;
   931 				ans6.s6_addr[1] = 0x0b;
   932 				ans6.s6_addr[14] = 0xf0;
   933 				ans6.s6_addr[15] = 0x0d;
   934 				evdns_server_request_add_aaaa_reply(req, qname,
   935 				    1, &ans6.s6_addr, 2000);
   936 				added_any = 1;
   937 			}  else if (!evutil_ascii_strcasecmp(qname,
   938 				"v6assert.example.com")) {
   939 				TT_FAIL(("Got a A request for v6assert"));
   940 			}
   941 		} else if (!evutil_ascii_strcasecmp(qname,
   942 			"v6timeout.example.com")) {
   943 			if (qtype == EVDNS_TYPE_A) {
   944 				ans.s_addr = htonl(0xabcdef01);
   945 				evdns_server_request_add_a_reply(req, qname,
   946 				    1, &ans.s_addr, 2000);
   947 				added_any = 1;
   948 			} else if (qtype == EVDNS_TYPE_AAAA) {
   949 				/* Let the v6 request time out.*/
   950 				evdns_server_request_drop(req);
   951 				return;
   952 			}
   953 		} else if (!evutil_ascii_strcasecmp(qname,
   954 			"v4timeout.example.com")) {
   955 			if (qtype == EVDNS_TYPE_AAAA) {
   956 				ans6.s6_addr[0] = 0x0a;
   957 				ans6.s6_addr[1] = 0x0a;
   958 				ans6.s6_addr[14] = 0xff;
   959 				ans6.s6_addr[15] = 0x01;
   960 				evdns_server_request_add_aaaa_reply(req, qname,
   961 				    1, &ans6.s6_addr, 2000);
   962 				added_any = 1;
   963 			} else if (qtype == EVDNS_TYPE_A) {
   964 				/* Let the v4 request time out.*/
   965 				evdns_server_request_drop(req);
   966 				return;
   967 			}
   968 		} else if (!evutil_ascii_strcasecmp(qname,
   969 			"v6timeout-nonexist.example.com")) {
   970 			if (qtype == EVDNS_TYPE_A) {
   971 				/* Fall through, give an nexist. */
   972 			} else if (qtype == EVDNS_TYPE_AAAA) {
   973 				/* Let the v6 request time out.*/
   974 				evdns_server_request_drop(req);
   975 				return;
   976 			}
   977 		} else if (!evutil_ascii_strcasecmp(qname,
   978 			"all-timeout.example.com")) {
   979 			/* drop all requests */
   980 			evdns_server_request_drop(req);
   981 			return;
   982 		} else {
   983 			TT_GRIPE(("Got weird request for %s",qname));
   984 		}
   985 	}
   986 	if (added_any)
   987 		evdns_server_request_respond(req, 0);
   988 	else
   989 		evdns_server_request_respond(req, 3);
   990 }
   992 /* Implements a listener for connect_hostname test. */
   993 static void
   994 nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s,
   995     int socklen, void *arg)
   996 {
   997 	int *p = arg;
   998 	(*p)++;
   999 	++total_n_accepted;
  1000 	/* don't do anything with the socket; let it close when we exit() */
  1001 	if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
  1002 		event_base_loopexit(be_connect_hostname_base,
  1003 		    NULL);
  1006 struct be_conn_hostname_result {
  1007 	int dnserr;
  1008 	int what;
  1009 };
  1011 /* Bufferevent event callback for the connect_hostname test: remembers what
  1012  * event we got. */
  1013 static void
  1014 be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
  1016 	struct be_conn_hostname_result *got = ctx;
  1017 	if (!got->what) {
  1018 		TT_BLATHER(("Got a bufferevent event %d", what));
  1019 		got->what = what;
  1021 		if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
  1022 			int r;
  1023 			if ((r = bufferevent_socket_get_dns_error(bev))) {
  1024 				got->dnserr = r;
  1025 				TT_BLATHER(("DNS error %d: %s", r,
  1026 					   evutil_gai_strerror(r)));
  1027 			}			++total_connected_or_failed;
  1028 			TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
  1030 			if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
  1031 				event_base_loopexit(be_connect_hostname_base,
  1032 				    NULL);
  1034 	} else {
  1035 		TT_FAIL(("Two events on one bufferevent. %d,%d",
  1036 			got->what, (int)what));
  1040 static void
  1041 test_bufferevent_connect_hostname(void *arg)
  1043 	struct basic_test_data *data = arg;
  1044 	struct evconnlistener *listener = NULL;
  1045 	struct bufferevent *be1=NULL, *be2=NULL, *be3=NULL, *be4=NULL, *be5=NULL;
  1046 	struct be_conn_hostname_result be1_outcome={0,0}, be2_outcome={0,0},
  1047 	       be3_outcome={0,0}, be4_outcome={0,0}, be5_outcome={0,0};
  1048 	int expect_err5;
  1049 	struct evdns_base *dns=NULL;
  1050 	struct evdns_server_port *port=NULL;
  1051 	struct sockaddr_in sin;
  1052 	int listener_port=-1;
  1053 	ev_uint16_t dns_port=0;
  1054 	int n_accept=0, n_dns=0;
  1055 	char buf[128];
  1057 	be_connect_hostname_base = data->base;
  1059 	/* Bind an address and figure out what port it's on. */
  1060 	memset(&sin, 0, sizeof(sin));
  1061 	sin.sin_family = AF_INET;
  1062 	sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
  1063 	sin.sin_port = 0;
  1064 	listener = evconnlistener_new_bind(data->base, nil_accept_cb,
  1065 	    &n_accept,
  1066 	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,
  1067 	    -1, (struct sockaddr *)&sin, sizeof(sin));
  1068 	tt_assert(listener);
  1069 	listener_port = regress_get_socket_port(
  1070 		evconnlistener_get_fd(listener));
  1072 	port = regress_get_dnsserver(data->base, &dns_port, NULL,
  1073 	    be_getaddrinfo_server_cb, &n_dns);
  1074 	tt_assert(port);
  1075 	tt_int_op(dns_port, >=, 0);
  1077 	/* Start an evdns_base that uses the server as its resolver. */
  1078 	dns = evdns_base_new(data->base, 0);
  1079 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port);
  1080 	evdns_base_nameserver_ip_add(dns, buf);
  1082 	/* Now, finally, at long last, launch the bufferevents.	 One should do
  1083 	 * a failing lookup IP, one should do a successful lookup by IP,
  1084 	 * and one should do a successful lookup by hostname. */
  1085 	be1 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
  1086 	be2 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
  1087 	be3 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
  1088 	be4 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
  1089 	be5 = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
  1091 	bufferevent_setcb(be1, NULL, NULL, be_connect_hostname_event_cb,
  1092 	    &be1_outcome);
  1093 	bufferevent_setcb(be2, NULL, NULL, be_connect_hostname_event_cb,
  1094 	    &be2_outcome);
  1095 	bufferevent_setcb(be3, NULL, NULL, be_connect_hostname_event_cb,
  1096 	    &be3_outcome);
  1097 	bufferevent_setcb(be4, NULL, NULL, be_connect_hostname_event_cb,
  1098 	    &be4_outcome);
  1099 	bufferevent_setcb(be5, NULL, NULL, be_connect_hostname_event_cb,
  1100 	    &be5_outcome);
  1102 	/* Launch an async resolve that will fail. */
  1103 	tt_assert(!bufferevent_socket_connect_hostname(be1, dns, AF_INET,
  1104 		"nosuchplace.example.com", listener_port));
  1105 	/* Connect to the IP without resolving. */
  1106 	tt_assert(!bufferevent_socket_connect_hostname(be2, dns, AF_INET,
  1107 		"127.0.0.1", listener_port));
  1108 	/* Launch an async resolve that will succeed. */
  1109 	tt_assert(!bufferevent_socket_connect_hostname(be3, dns, AF_INET,
  1110 		"nobodaddy.example.com", listener_port));
  1111 	/* Use the blocking resolver.  This one will fail if your resolver
  1112 	 * can't resolve localhost to 127.0.0.1 */
  1113 	tt_assert(!bufferevent_socket_connect_hostname(be4, NULL, AF_INET,
  1114 		"localhost", listener_port));
  1115 	/* Use the blocking resolver with a nonexistent hostname. */
  1116 	tt_assert(!bufferevent_socket_connect_hostname(be5, NULL, AF_INET,
  1117 		"nonesuch.nowhere.example.com", 80));
  1119 		/* The blocking resolver will use the system nameserver, which
  1120 		 * might tell us anything.  (Yes, some twits even pretend that
  1121 		 * example.com is real.) Let's see what answer to expect. */
  1122 		struct evutil_addrinfo hints, *ai = NULL;
  1123 		memset(&hints, 0, sizeof(hints));
  1124 		hints.ai_family = AF_INET;
  1125 		hints.ai_socktype = SOCK_STREAM;
  1126 		hints.ai_protocol = IPPROTO_TCP;
  1127 		expect_err5 = evutil_getaddrinfo(
  1128 			"nonesuch.nowhere.example.com", "80", &hints, &ai);
  1131 	event_base_dispatch(data->base);
  1133 	tt_int_op(be1_outcome.what, ==, BEV_EVENT_ERROR);
  1134 	tt_int_op(be1_outcome.dnserr, ==, EVUTIL_EAI_NONAME);
  1135 	tt_int_op(be2_outcome.what, ==, BEV_EVENT_CONNECTED);
  1136 	tt_int_op(be2_outcome.dnserr, ==, 0);
  1137 	tt_int_op(be3_outcome.what, ==, BEV_EVENT_CONNECTED);
  1138 	tt_int_op(be3_outcome.dnserr, ==, 0);
  1139 	tt_int_op(be4_outcome.what, ==, BEV_EVENT_CONNECTED);
  1140 	tt_int_op(be4_outcome.dnserr, ==, 0);
  1141 	if (expect_err5) {
  1142 		tt_int_op(be5_outcome.what, ==, BEV_EVENT_ERROR);
  1143 		tt_int_op(be5_outcome.dnserr, ==, expect_err5);
  1146 	tt_int_op(n_accept, ==, 3);
  1147 	tt_int_op(n_dns, ==, 2);
  1149 end:
  1150 	if (listener)
  1151 		evconnlistener_free(listener);
  1152 	if (port)
  1153 		evdns_close_server_port(port);
  1154 	if (dns)
  1155 		evdns_base_free(dns, 0);
  1156 	if (be1)
  1157 		bufferevent_free(be1);
  1158 	if (be2)
  1159 		bufferevent_free(be2);
  1160 	if (be3)
  1161 		bufferevent_free(be3);
  1162 	if (be4)
  1163 		bufferevent_free(be4);
  1164 	if (be5)
  1165 		bufferevent_free(be5);
  1169 struct gai_outcome {
  1170 	int err;
  1171 	struct evutil_addrinfo *ai;
  1172 };
  1174 static int n_gai_results_pending = 0;
  1175 static struct event_base *exit_base_on_no_pending_results = NULL;
  1177 static void
  1178 gai_cb(int err, struct evutil_addrinfo *res, void *ptr)
  1180 	struct gai_outcome *go = ptr;
  1181 	go->err = err;
  1182 	go->ai = res;
  1183 	if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results)
  1184 		event_base_loopexit(exit_base_on_no_pending_results, NULL);
  1185 	if (n_gai_results_pending < 900)
  1186 		TT_BLATHER(("Got an answer; expecting %d more.",
  1187 			n_gai_results_pending));
  1190 static void
  1191 cancel_gai_cb(evutil_socket_t fd, short what, void *ptr)
  1193 	struct evdns_getaddrinfo_request *r = ptr;
  1194 	evdns_getaddrinfo_cancel(r);
  1197 static void
  1198 test_getaddrinfo_async(void *arg)
  1200 	struct basic_test_data *data = arg;
  1201 	struct evutil_addrinfo hints, *a;
  1202 	struct gai_outcome local_outcome;
  1203 	struct gai_outcome a_out[12];
  1204 	int i;
  1205 	struct evdns_getaddrinfo_request *r;
  1206 	char buf[128];
  1207 	struct evdns_server_port *port = NULL;
  1208 	ev_uint16_t dns_port = 0;
  1209 	int n_dns_questions = 0;
  1211 	struct evdns_base *dns_base = evdns_base_new(data->base, 0);
  1212 	tt_assert(dns_base);
  1214 	/* for localhost */
  1215 	evdns_base_load_hosts(dns_base, NULL);
  1217 	memset(a_out, 0, sizeof(a_out));
  1218 	memset(&local_outcome, 0, sizeof(local_outcome));
  1220 	n_gai_results_pending = 10000; /* don't think about exiting yet. */
  1222 	/* 1. Try some cases that will never hit the asynchronous resolver. */
  1223 	/* 1a. Simple case with a symbolic service name */
  1224 	memset(&hints, 0, sizeof(hints));
  1225 	hints.ai_family = PF_UNSPEC;
  1226 	hints.ai_socktype = SOCK_STREAM;
  1227 	memset(&local_outcome, 0, sizeof(local_outcome));
  1228 	r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http",
  1229 	    &hints, gai_cb, &local_outcome);
  1230 	tt_assert(! r);
  1231 	if (!local_outcome.err) {
  1232 		tt_ptr_op(local_outcome.ai,!=,NULL);
  1233 		test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
  1234 		evutil_freeaddrinfo(local_outcome.ai);
  1235 		local_outcome.ai = NULL;
  1236 	} else {
  1237 		TT_BLATHER(("Apparently we have no getservbyname."));
  1240 	/* 1b. EVUTIL_AI_NUMERICHOST is set */
  1241 	memset(&hints, 0, sizeof(hints));
  1242 	hints.ai_family = PF_UNSPEC;
  1243 	hints.ai_flags = EVUTIL_AI_NUMERICHOST;
  1244 	memset(&local_outcome, 0, sizeof(local_outcome));
  1245 	r = evdns_getaddrinfo(dns_base, "www.google.com", "80",
  1246 	    &hints, gai_cb, &local_outcome);
  1247 	tt_ptr_op(r,==,NULL);
  1248 	tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME);
  1249 	tt_ptr_op(local_outcome.ai,==,NULL);
  1251 	/* 1c. We give a numeric address (ipv6) */
  1252 	memset(&hints, 0, sizeof(hints));
  1253 	memset(&local_outcome, 0, sizeof(local_outcome));
  1254 	hints.ai_family = PF_UNSPEC;
  1255 	hints.ai_protocol = IPPROTO_TCP;
  1256 	r = evdns_getaddrinfo(dns_base, "f::f", "8008",
  1257 	    &hints, gai_cb, &local_outcome);
  1258 	tt_assert(!r);
  1259 	tt_int_op(local_outcome.err,==,0);
  1260 	tt_assert(local_outcome.ai);
  1261 	tt_ptr_op(local_outcome.ai->ai_next,==,NULL);
  1262 	test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP);
  1263 	evutil_freeaddrinfo(local_outcome.ai);
  1264 	local_outcome.ai = NULL;
  1266 	/* 1d. We give a numeric address (ipv4) */
  1267 	memset(&hints, 0, sizeof(hints));
  1268 	memset(&local_outcome, 0, sizeof(local_outcome));
  1269 	hints.ai_family = PF_UNSPEC;
  1270 	r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL,
  1271 	    &hints, gai_cb, &local_outcome);
  1272 	tt_assert(!r);
  1273 	tt_int_op(local_outcome.err,==,0);
  1274 	tt_assert(local_outcome.ai);
  1275 	a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP);
  1276 	tt_assert(a);
  1277 	test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP);
  1278 	a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP);
  1279 	tt_assert(a);
  1280 	test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP);
  1281 	evutil_freeaddrinfo(local_outcome.ai);
  1282 	local_outcome.ai = NULL;
  1284 	/* 1e. nodename is NULL (bind) */
  1285 	memset(&hints, 0, sizeof(hints));
  1286 	memset(&local_outcome, 0, sizeof(local_outcome));
  1287 	hints.ai_family = PF_UNSPEC;
  1288 	hints.ai_socktype = SOCK_DGRAM;
  1289 	hints.ai_flags = EVUTIL_AI_PASSIVE;
  1290 	r = evdns_getaddrinfo(dns_base, NULL, "9090",
  1291 	    &hints, gai_cb, &local_outcome);
  1292 	tt_assert(!r);
  1293 	tt_int_op(local_outcome.err,==,0);
  1294 	tt_assert(local_outcome.ai);
  1295 	/* we should get a v4 address of 0.0.0.0... */
  1296 	a = ai_find_by_family(local_outcome.ai, PF_INET);
  1297 	tt_assert(a);
  1298 	test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP);
  1299 	/* ... and a v6 address of ::0 */
  1300 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
  1301 	tt_assert(a);
  1302 	test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP);
  1303 	evutil_freeaddrinfo(local_outcome.ai);
  1304 	local_outcome.ai = NULL;
  1306 	/* 1f. nodename is NULL (connect) */
  1307 	memset(&hints, 0, sizeof(hints));
  1308 	memset(&local_outcome, 0, sizeof(local_outcome));
  1309 	hints.ai_family = PF_UNSPEC;
  1310 	hints.ai_socktype = SOCK_STREAM;
  1311 	r = evdns_getaddrinfo(dns_base, NULL, "2",
  1312 	    &hints, gai_cb, &local_outcome);
  1313 	tt_assert(!r);
  1314 	tt_int_op(local_outcome.err,==,0);
  1315 	tt_assert(local_outcome.ai);
  1316 	/* we should get a v4 address of 127.0.0.1 .... */
  1317 	a = ai_find_by_family(local_outcome.ai, PF_INET);
  1318 	tt_assert(a);
  1319 	test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP);
  1320 	/* ... and a v6 address of ::1 */
  1321 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
  1322 	tt_assert(a);
  1323 	test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP);
  1324 	evutil_freeaddrinfo(local_outcome.ai);
  1325 	local_outcome.ai = NULL;
  1327 	/* 1g. We find localhost immediately. (pf_unspec) */
  1328 	memset(&hints, 0, sizeof(hints));
  1329 	memset(&local_outcome, 0, sizeof(local_outcome));
  1330 	hints.ai_family = PF_UNSPEC;
  1331 	hints.ai_socktype = SOCK_STREAM;
  1332 	r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80",
  1333 	    &hints, gai_cb, &local_outcome);
  1334 	tt_assert(!r);
  1335 	tt_int_op(local_outcome.err,==,0);
  1336 	tt_assert(local_outcome.ai);
  1337 	/* we should get a v4 address of 127.0.0.1 .... */
  1338 	a = ai_find_by_family(local_outcome.ai, PF_INET);
  1339 	tt_assert(a);
  1340 	test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
  1341 	/* ... and a v6 address of ::1 */
  1342 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
  1343 	tt_assert(a);
  1344 	test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
  1345 	evutil_freeaddrinfo(local_outcome.ai);
  1346 	local_outcome.ai = NULL;
  1348 	/* 1g. We find localhost immediately. (pf_inet6) */
  1349 	memset(&hints, 0, sizeof(hints));
  1350 	memset(&local_outcome, 0, sizeof(local_outcome));
  1351 	hints.ai_family = PF_INET6;
  1352 	hints.ai_socktype = SOCK_STREAM;
  1353 	r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999",
  1354 	    &hints, gai_cb, &local_outcome);
  1355 	tt_assert(! r);
  1356 	tt_int_op(local_outcome.err,==,0);
  1357 	tt_assert(local_outcome.ai);
  1358 	a = local_outcome.ai;
  1359 	test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP);
  1360 	tt_ptr_op(a->ai_next, ==, NULL);
  1361 	evutil_freeaddrinfo(local_outcome.ai);
  1362 	local_outcome.ai = NULL;
  1364 	/* 2. Okay, now we can actually test the asynchronous resolver. */
  1365 	/* Start a dummy local dns server... */
  1366 	port = regress_get_dnsserver(data->base, &dns_port, NULL,
  1367 	    be_getaddrinfo_server_cb, &n_dns_questions);
  1368 	tt_assert(port);
  1369 	tt_int_op(dns_port, >=, 0);
  1370 	/* ... and tell the evdns_base about it. */
  1371 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port);
  1372 	evdns_base_nameserver_ip_add(dns_base, buf);
  1374 	memset(&hints, 0, sizeof(hints));
  1375 	hints.ai_family = PF_UNSPEC;
  1376 	hints.ai_socktype = SOCK_STREAM;
  1377 	hints.ai_flags = EVUTIL_AI_CANONNAME;
  1378 	/* 0: Request for both.example.com should return both addresses. */
  1379 	r = evdns_getaddrinfo(dns_base, "both.example.com", "8000",
  1380 	    &hints, gai_cb, &a_out[0]);
  1381 	tt_assert(r);
  1383 	/* 1: Request for v4only.example.com should return one address. */
  1384 	r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001",
  1385 	    &hints, gai_cb, &a_out[1]);
  1386 	tt_assert(r);
  1388 	/* 2: Request for v6only.example.com should return one address. */
  1389 	hints.ai_flags = 0;
  1390 	r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002",
  1391 	    &hints, gai_cb, &a_out[2]);
  1392 	tt_assert(r);
  1394 	/* 3: PF_INET request for v4assert.example.com should not generate a
  1395 	 * v6 request.	The server will fail the test if it does. */
  1396 	hints.ai_family = PF_INET;
  1397 	r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003",
  1398 	    &hints, gai_cb, &a_out[3]);
  1399 	tt_assert(r);
  1401 	/* 4: PF_INET6 request for v6assert.example.com should not generate a
  1402 	 * v4 request.	The server will fail the test if it does. */
  1403 	hints.ai_family = PF_INET6;
  1404 	r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004",
  1405 	    &hints, gai_cb, &a_out[4]);
  1406 	tt_assert(r);
  1408 	/* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */
  1409 	hints.ai_family = PF_INET;
  1410 	r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005",
  1411 	    &hints, gai_cb, &a_out[5]);
  1412 	tt_assert(r);
  1414 	/* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST.
  1415 	 */
  1416 	hints.ai_family = PF_UNSPEC;
  1417 	r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006",
  1418 	    &hints, gai_cb, &a_out[6]);
  1419 	tt_assert(r);
  1421 	/* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4
  1422 	 * address only. */
  1423 	hints.ai_family = PF_UNSPEC;
  1424 	r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007",
  1425 	    &hints, gai_cb, &a_out[7]);
  1426 	tt_assert(r);
  1428 	/* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give
  1429 	 * a NEXIST */
  1430 	hints.ai_family = PF_UNSPEC;
  1431 	r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com",
  1432 	    "8008", &hints, gai_cb, &a_out[8]);
  1433 	tt_assert(r);
  1435 	/* 9: AI_ADDRCONFIG should at least not crash.	Can't test it more
  1436 	 * without knowing what kind of internet we have. */
  1437 	hints.ai_flags |= EVUTIL_AI_ADDRCONFIG;
  1438 	r = evdns_getaddrinfo(dns_base, "both.example.com",
  1439 	    "8009", &hints, gai_cb, &a_out[9]);
  1440 	tt_assert(r);
  1442 	/* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address
  1443 	 * only. */
  1444 	hints.ai_family = PF_UNSPEC;
  1445 	hints.ai_flags = 0;
  1446 	r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010",
  1447 	    &hints, gai_cb, &a_out[10]);
  1448 	tt_assert(r);
  1450 	/* 11: timeout.example.com: cancel it after 100 msec. */
  1451 	r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011",
  1452 	    &hints, gai_cb, &a_out[11]);
  1453 	tt_assert(r);
  1455 		struct timeval tv;
  1456 		tv.tv_sec = 0;
  1457 		tv.tv_usec = 100*1000; /* 100 msec */
  1458 		event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb,
  1459 		    r, &tv);
  1462 	/* XXXXX There are more tests we could do, including:
  1464 	   - A test to elicit NODATA.
  1466 	 */
  1468 	n_gai_results_pending = 12;
  1469 	exit_base_on_no_pending_results = data->base;
  1471 	event_base_dispatch(data->base);
  1473 	/* 0: both.example.com */
  1474 	tt_int_op(a_out[0].err, ==, 0);
  1475 	tt_assert(a_out[0].ai);
  1476 	tt_assert(a_out[0].ai->ai_next);
  1477 	tt_assert(!a_out[0].ai->ai_next->ai_next);
  1478 	a = ai_find_by_family(a_out[0].ai, PF_INET);
  1479 	tt_assert(a);
  1480 	test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP);
  1481 	a = ai_find_by_family(a_out[0].ai, PF_INET6);
  1482 	tt_assert(a);
  1483 	test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP);
  1484 	tt_assert(a_out[0].ai->ai_canonname);
  1485 	tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com");
  1487 	/* 1: v4only.example.com */
  1488 	tt_int_op(a_out[1].err, ==, 0);
  1489 	tt_assert(a_out[1].ai);
  1490 	tt_assert(! a_out[1].ai->ai_next);
  1491 	test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP);
  1492 	tt_assert(a_out[1].ai->ai_canonname == NULL);
  1495 	/* 2: v6only.example.com */
  1496 	tt_int_op(a_out[2].err, ==, 0);
  1497 	tt_assert(a_out[2].ai);
  1498 	tt_assert(! a_out[2].ai->ai_next);
  1499 	test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP);
  1501 	/* 3: v4assert.example.com */
  1502 	tt_int_op(a_out[3].err, ==, 0);
  1503 	tt_assert(a_out[3].ai);
  1504 	tt_assert(! a_out[3].ai->ai_next);
  1505 	test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP);
  1507 	/* 4: v6assert.example.com */
  1508 	tt_int_op(a_out[4].err, ==, 0);
  1509 	tt_assert(a_out[4].ai);
  1510 	tt_assert(! a_out[4].ai->ai_next);
  1511 	test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP);
  1513 	/* 5: nosuchplace.example.com (inet) */
  1514 	tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME);
  1515 	tt_assert(! a_out[5].ai);
  1517 	/* 6: nosuchplace.example.com (unspec) */
  1518 	tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME);
  1519 	tt_assert(! a_out[6].ai);
  1521 	/* 7: v6timeout.example.com */
  1522 	tt_int_op(a_out[7].err, ==, 0);
  1523 	tt_assert(a_out[7].ai);
  1524 	tt_assert(! a_out[7].ai->ai_next);
  1525 	test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP);
  1527 	/* 8: v6timeout-nonexist.example.com */
  1528 	tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME);
  1529 	tt_assert(! a_out[8].ai);
  1531 	/* 9: both (ADDRCONFIG) */
  1532 	tt_int_op(a_out[9].err, ==, 0);
  1533 	tt_assert(a_out[9].ai);
  1534 	a = ai_find_by_family(a_out[9].ai, PF_INET);
  1535 	if (a)
  1536 		test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP);
  1537 	else
  1538 		tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6));
  1539 	a = ai_find_by_family(a_out[9].ai, PF_INET6);
  1540 	if (a)
  1541 		test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP);
  1542 	else
  1543 		tt_assert(ai_find_by_family(a_out[9].ai, PF_INET));
  1545 	/* 10: v4timeout.example.com */
  1546 	tt_int_op(a_out[10].err, ==, 0);
  1547 	tt_assert(a_out[10].ai);
  1548 	tt_assert(! a_out[10].ai->ai_next);
  1549 	test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP);
  1551 	/* 11: cancelled request. */
  1552 	tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL);
  1553 	tt_assert(a_out[11].ai == NULL);
  1555 end:
  1556 	if (local_outcome.ai)
  1557 		evutil_freeaddrinfo(local_outcome.ai);
  1558 	for (i=0;i<10;++i) {
  1559 		if (a_out[i].ai)
  1560 			evutil_freeaddrinfo(a_out[i].ai);
  1562 	if (port)
  1563 		evdns_close_server_port(port);
  1564 	if (dns_base)
  1565 		evdns_base_free(dns_base, 0);
  1568 struct gaic_request_status {
  1569 	int magic;
  1570 	struct event_base *base;
  1571 	struct evdns_base *dns_base;
  1572 	struct evdns_getaddrinfo_request *request;
  1573 	struct event cancel_event;
  1574 	int canceled;
  1575 };
  1577 #define GAIC_MAGIC 0x1234abcd
  1579 static int pending = 0;
  1581 static void
  1582 gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg)
  1584 	struct gaic_request_status *status = arg;
  1586 	tt_assert(status->magic == GAIC_MAGIC);
  1587 	status->canceled = 1;
  1588 	evdns_getaddrinfo_cancel(status->request);
  1589 	return;
  1590 end:
  1591 	event_base_loopexit(status->base, NULL);
  1594 static void
  1595 gaic_server_cb(struct evdns_server_request *req, void *arg)
  1597 	ev_uint32_t answer = 0x7f000001;
  1598 	tt_assert(req->nquestions);
  1599 	evdns_server_request_add_a_reply(req, req->questions[0]->name, 1,
  1600 	    &answer, 100);
  1601 	evdns_server_request_respond(req, 0);
  1602 	return;
  1603 end:
  1604 	evdns_server_request_respond(req, DNS_ERR_REFUSED);
  1608 static void
  1609 gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg)
  1611 	struct gaic_request_status *status = arg;
  1612 	struct event_base *base = status->base;
  1613 	tt_assert(status->magic == GAIC_MAGIC);
  1615 	if (result == EVUTIL_EAI_CANCEL) {
  1616 		tt_assert(status->canceled);
  1618 	event_del(&status->cancel_event);
  1620 	memset(status, 0xf0, sizeof(*status));
  1621 	free(status);
  1623 end:
  1624 	if (--pending <= 0)
  1625 		event_base_loopexit(base, NULL);
  1628 static void
  1629 gaic_launch(struct event_base *base, struct evdns_base *dns_base)
  1631 	struct gaic_request_status *status = calloc(1,sizeof(*status));
  1632 	struct timeval tv = { 0, 10000 };
  1633 	status->magic = GAIC_MAGIC;
  1634 	status->base = base;
  1635 	status->dns_base = dns_base;
  1636 	event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb,
  1637 	    status);
  1638 	status->request = evdns_getaddrinfo(dns_base,
  1639 	    "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb,
  1640 	    status);
  1641 	event_add(&status->cancel_event, &tv);
  1642 	++pending;
  1645 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
  1646 /* FIXME: We should move this to regress_main.c if anything else needs it.*/
  1648 /* Trivial replacements for malloc/free/realloc to check for memory leaks.
  1649  * Not threadsafe. */
  1650 static int allocated_chunks = 0;
  1652 static void *
  1653 cnt_malloc(size_t sz)
  1655 	allocated_chunks += 1;
  1656 	return malloc(sz);
  1659 static void *
  1660 cnt_realloc(void *old, size_t sz)
  1662 	if (!old)
  1663 		allocated_chunks += 1;
  1664 	if (!sz)
  1665 		allocated_chunks -= 1;
  1666 	return realloc(old, sz);
  1669 static void
  1670 cnt_free(void *ptr)
  1672 	allocated_chunks -= 1;
  1673 	free(ptr);
  1676 struct testleak_env_t {
  1677 	struct event_base *base;
  1678 	struct evdns_base *dns_base;
  1679 	struct evdns_request *req;
  1680 	struct generic_dns_callback_result r;
  1681 };
  1683 static void *
  1684 testleak_setup(const struct testcase_t *testcase)
  1686 	struct testleak_env_t *env;
  1688 	allocated_chunks = 0;
  1689 	event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free);
  1690 	event_enable_debug_mode();
  1692 	/* not mm_calloc: we don't want to mess with the count. */
  1693 	env = calloc(1, sizeof(struct testleak_env_t));
  1694 	env->base = event_base_new();
  1695 	env->dns_base = evdns_base_new(env->base, 0);
  1696 	env->req = evdns_base_resolve_ipv4(
  1697 		env->dns_base, "example.com", DNS_QUERY_NO_SEARCH,
  1698 		generic_dns_callback, &env->r);
  1699 	return env;
  1702 static int
  1703 testleak_cleanup(const struct testcase_t *testcase, void *env_)
  1705 	int ok = 0;
  1706 	struct testleak_env_t *env = env_;
  1707 	tt_assert(env);
  1708 #ifdef _EVENT_DISABLE_DEBUG_MODE
  1709 	tt_int_op(allocated_chunks, ==, 0);
  1710 #else
  1711 	/* FIXME: that's `1' because of event_debug_map_HT_GROW */
  1712 	tt_int_op(allocated_chunks, ==, 1);
  1713 #endif
  1714 	ok = 1;
  1715 end:
  1716 	if (env) {
  1717 		if (env->dns_base)
  1718 			evdns_base_free(env->dns_base, 0);
  1719 		if (env->base)
  1720 			event_base_free(env->base);
  1721 		free(env);
  1723 	return ok;
  1726 static struct testcase_setup_t testleak_funcs = {
  1727 	testleak_setup, testleak_cleanup
  1728 };
  1730 static void
  1731 test_dbg_leak_cancel(void *env_)
  1733 	/* cancel, loop, free/dns, free/base */
  1734 	struct testleak_env_t *env = env_;
  1735 	int send_err_shutdown = 1;
  1736 	evdns_cancel_request(env->dns_base, env->req);
  1737 	env->req = 0;
  1739 	/* `req` is freed in callback, that's why one loop is required. */
  1740 	event_base_loop(env->base, EVLOOP_NONBLOCK);
  1742 	/* send_err_shutdown means nothing as soon as our request is
  1743 	 * already canceled */
  1744 	evdns_base_free(env->dns_base, send_err_shutdown);
  1745 	env->dns_base = 0;
  1746 	event_base_free(env->base);
  1747 	env->base = 0;
  1750 static void
  1751 test_dbg_leak_shutdown(void *env_)
  1753 	/* free/dns, loop, free/base */
  1754 	struct testleak_env_t *env = env_;
  1755 	int send_err_shutdown = 1;
  1757 	/* `req` is freed both with `send_err_shutdown` and without it,
  1758 	 * the only difference is `evdns_callback` call */
  1759 	env->req = 0;
  1761 	evdns_base_free(env->dns_base, send_err_shutdown);
  1762 	env->dns_base = 0;
  1764 	/* `req` is freed in callback, that's why one loop is required */
  1765 	event_base_loop(env->base, EVLOOP_NONBLOCK);
  1766 	event_base_free(env->base);
  1767 	env->base = 0;
  1769 #endif
  1771 static void
  1772 test_getaddrinfo_async_cancel_stress(void *ptr)
  1774 	struct event_base *base;
  1775 	struct evdns_base *dns_base = NULL;
  1776 	struct evdns_server_port *server = NULL;
  1777 	evutil_socket_t fd = -1;
  1778 	struct sockaddr_in sin;
  1779 	struct sockaddr_storage ss;
  1780 	ev_socklen_t slen;
  1781 	int i;
  1783 	base = event_base_new();
  1784 	dns_base = evdns_base_new(base, 0);
  1786 	memset(&sin, 0, sizeof(sin));
  1787 	sin.sin_family = AF_INET;
  1788 	sin.sin_port = 0;
  1789 	sin.sin_addr.s_addr = htonl(0x7f000001);
  1790 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  1791 		tt_abort_perror("socket");
  1793 	evutil_make_socket_nonblocking(fd);
  1794 	if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
  1795 		tt_abort_perror("bind");
  1797 	server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb,
  1798 	    base);
  1800 	memset(&ss, 0, sizeof(ss));
  1801 	slen = sizeof(ss);
  1802 	if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) {
  1803 		tt_abort_perror("getsockname");
  1805 	evdns_base_nameserver_sockaddr_add(dns_base,
  1806 	    (struct sockaddr*)&ss, slen, 0);
  1808 	for (i = 0; i < 1000; ++i) {
  1809 		gaic_launch(base, dns_base);
  1812 	event_base_dispatch(base);
  1814 end:
  1815 	if (dns_base)
  1816 		evdns_base_free(dns_base, 1);
  1817 	if (server)
  1818 		evdns_close_server_port(server);
  1819 	if (fd >= 0)
  1820 		evutil_closesocket(fd);
  1824 #define DNS_LEGACY(name, flags)					       \
  1825 	{ #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup,   \
  1826 		    dns_##name }
  1828 struct testcase_t dns_testcases[] = {
  1829 	DNS_LEGACY(server, TT_FORK|TT_NEED_BASE),
  1830 	DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
  1831 	DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
  1832 	DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS),
  1833 	{ "resolve_reverse", dns_resolve_reverse, TT_FORK, NULL, NULL },
  1834 	{ "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1835 	{ "search_cancel", dns_search_cancel_test,
  1836 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1837 	{ "retry", dns_retry_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1838 	{ "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1839 	{ "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1840 	{ "bufferevent_connect_hostname", test_bufferevent_connect_hostname,
  1841 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
  1843 	{ "getaddrinfo_async", test_getaddrinfo_async,
  1844 	  TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" },
  1845 	{ "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,
  1846 	  TT_FORK, NULL, NULL },
  1848 #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
  1849 	{ "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL },
  1850 	{ "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL },
  1851 #endif
  1853 	END_OF_TESTCASES
  1854 };

mercurial