xref: /freebsd/contrib/libevent/test/regress_dns.c (revision b50261e2)
1c43e99fdSEd Maste /*
2c43e99fdSEd Maste  * Copyright (c) 2003-2007 Niels Provos <provos@citi.umich.edu>
3c43e99fdSEd Maste  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
4c43e99fdSEd Maste  *
5c43e99fdSEd Maste  * Redistribution and use in source and binary forms, with or without
6c43e99fdSEd Maste  * modification, are permitted provided that the following conditions
7c43e99fdSEd Maste  * are met:
8c43e99fdSEd Maste  * 1. Redistributions of source code must retain the above copyright
9c43e99fdSEd Maste  *    notice, this list of conditions and the following disclaimer.
10c43e99fdSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11c43e99fdSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12c43e99fdSEd Maste  *    documentation and/or other materials provided with the distribution.
13c43e99fdSEd Maste  * 3. The name of the author may not be used to endorse or promote products
14c43e99fdSEd Maste  *    derived from this software without specific prior written permission.
15c43e99fdSEd Maste  *
16c43e99fdSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17c43e99fdSEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18c43e99fdSEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19c43e99fdSEd Maste  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20c43e99fdSEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21c43e99fdSEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22c43e99fdSEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23c43e99fdSEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24c43e99fdSEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25c43e99fdSEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26c43e99fdSEd Maste  */
27c43e99fdSEd Maste #include "../util-internal.h"
28c43e99fdSEd Maste 
29c43e99fdSEd Maste #ifdef _WIN32
30c43e99fdSEd Maste #include <winsock2.h>
31c43e99fdSEd Maste #include <windows.h>
32c43e99fdSEd Maste #include <ws2tcpip.h>
33c43e99fdSEd Maste #endif
34c43e99fdSEd Maste 
35c43e99fdSEd Maste #include "event2/event-config.h"
36c43e99fdSEd Maste 
37c43e99fdSEd Maste #include <sys/types.h>
38c43e99fdSEd Maste #include <sys/stat.h>
39c43e99fdSEd Maste #ifdef EVENT__HAVE_SYS_TIME_H
40c43e99fdSEd Maste #include <sys/time.h>
41c43e99fdSEd Maste #endif
42c43e99fdSEd Maste #include <sys/queue.h>
43c43e99fdSEd Maste #ifndef _WIN32
44c43e99fdSEd Maste #include <sys/socket.h>
45c43e99fdSEd Maste #include <signal.h>
46c43e99fdSEd Maste #include <netinet/in.h>
47c43e99fdSEd Maste #include <arpa/inet.h>
48c43e99fdSEd Maste #include <unistd.h>
49c43e99fdSEd Maste #endif
50c43e99fdSEd Maste #ifdef EVENT__HAVE_NETINET_IN6_H
51c43e99fdSEd Maste #include <netinet/in6.h>
52c43e99fdSEd Maste #endif
53c43e99fdSEd Maste #ifdef HAVE_NETDB_H
54c43e99fdSEd Maste #include <netdb.h>
55c43e99fdSEd Maste #endif
56c43e99fdSEd Maste #include <fcntl.h>
57c43e99fdSEd Maste #include <stdlib.h>
58c43e99fdSEd Maste #include <stdio.h>
59c43e99fdSEd Maste #include <string.h>
60c43e99fdSEd Maste #include <errno.h>
61c43e99fdSEd Maste 
62*b50261e2SCy Schubert #ifdef EVENT__HAVE_SYS_RESOURCE_H
63*b50261e2SCy Schubert #include <sys/resource.h>
64*b50261e2SCy Schubert #endif
65*b50261e2SCy Schubert 
66c43e99fdSEd Maste #include "event2/dns.h"
67c43e99fdSEd Maste #include "event2/dns_compat.h"
68c43e99fdSEd Maste #include "event2/dns_struct.h"
69c43e99fdSEd Maste #include "event2/event.h"
70c43e99fdSEd Maste #include "event2/event_compat.h"
71c43e99fdSEd Maste #include "event2/event_struct.h"
72c43e99fdSEd Maste #include "event2/util.h"
73c43e99fdSEd Maste #include "event2/listener.h"
74c43e99fdSEd Maste #include "event2/bufferevent.h"
75*b50261e2SCy Schubert #include <event2/thread.h>
76c43e99fdSEd Maste #include "log-internal.h"
77*b50261e2SCy Schubert #include "evthread-internal.h"
78c43e99fdSEd Maste #include "regress.h"
79c43e99fdSEd Maste #include "regress_testutils.h"
80*b50261e2SCy Schubert #include "regress_thread.h"
81c43e99fdSEd Maste 
82c43e99fdSEd Maste #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
83c43e99fdSEd Maste 
84c43e99fdSEd Maste static int dns_ok = 0;
85c43e99fdSEd Maste static int dns_got_cancel = 0;
86c43e99fdSEd Maste static int dns_err = 0;
87c43e99fdSEd Maste 
88c43e99fdSEd Maste 
89c43e99fdSEd Maste static void
dns_gethostbyname_cb(int result,char type,int count,int ttl,void * addresses,void * arg)90c43e99fdSEd Maste dns_gethostbyname_cb(int result, char type, int count, int ttl,
91c43e99fdSEd Maste     void *addresses, void *arg)
92c43e99fdSEd Maste {
93c43e99fdSEd Maste 	dns_ok = dns_err = 0;
94c43e99fdSEd Maste 
95c43e99fdSEd Maste 	if (result == DNS_ERR_TIMEOUT) {
96c43e99fdSEd Maste 		printf("[Timed out] ");
97c43e99fdSEd Maste 		dns_err = result;
98c43e99fdSEd Maste 		goto out;
99c43e99fdSEd Maste 	}
100c43e99fdSEd Maste 
101c43e99fdSEd Maste 	if (result != DNS_ERR_NONE) {
102c43e99fdSEd Maste 		printf("[Error code %d] ", result);
103c43e99fdSEd Maste 		goto out;
104c43e99fdSEd Maste 	}
105c43e99fdSEd Maste 
106c43e99fdSEd Maste 	TT_BLATHER(("type: %d, count: %d, ttl: %d: ", type, count, ttl));
107c43e99fdSEd Maste 
108c43e99fdSEd Maste 	switch (type) {
109c43e99fdSEd Maste 	case DNS_IPv6_AAAA: {
110c43e99fdSEd Maste #if defined(EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
111c43e99fdSEd Maste 		struct in6_addr *in6_addrs = addresses;
112c43e99fdSEd Maste 		char buf[INET6_ADDRSTRLEN+1];
113c43e99fdSEd Maste 		int i;
114c43e99fdSEd Maste 		/* a resolution that's not valid does not help */
115c43e99fdSEd Maste 		if (ttl < 0)
116c43e99fdSEd Maste 			goto out;
117c43e99fdSEd Maste 		for (i = 0; i < count; ++i) {
118c43e99fdSEd Maste 			const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[i], buf,sizeof(buf));
119c43e99fdSEd Maste 			if (b)
120c43e99fdSEd Maste 				TT_BLATHER(("%s ", b));
121c43e99fdSEd Maste 			else
122c43e99fdSEd Maste 				TT_BLATHER(("%s ", strerror(errno)));
123c43e99fdSEd Maste 		}
124c43e99fdSEd Maste #endif
125c43e99fdSEd Maste 		break;
126c43e99fdSEd Maste 	}
127c43e99fdSEd Maste 	case DNS_IPv4_A: {
128c43e99fdSEd Maste 		struct in_addr *in_addrs = addresses;
129c43e99fdSEd Maste 		int i;
130c43e99fdSEd Maste 		/* a resolution that's not valid does not help */
131c43e99fdSEd Maste 		if (ttl < 0)
132c43e99fdSEd Maste 			goto out;
133c43e99fdSEd Maste 		for (i = 0; i < count; ++i)
134c43e99fdSEd Maste 			TT_BLATHER(("%s ", inet_ntoa(in_addrs[i])));
135c43e99fdSEd Maste 		break;
136c43e99fdSEd Maste 	}
137c43e99fdSEd Maste 	case DNS_PTR:
138c43e99fdSEd Maste 		/* may get at most one PTR */
139c43e99fdSEd Maste 		if (count != 1)
140c43e99fdSEd Maste 			goto out;
141c43e99fdSEd Maste 
142c43e99fdSEd Maste 		TT_BLATHER(("%s ", *(char **)addresses));
143c43e99fdSEd Maste 		break;
144c43e99fdSEd Maste 	default:
145c43e99fdSEd Maste 		goto out;
146c43e99fdSEd Maste 	}
147c43e99fdSEd Maste 
148c43e99fdSEd Maste 	dns_ok = type;
149c43e99fdSEd Maste 
150c43e99fdSEd Maste out:
151c43e99fdSEd Maste 	if (arg == NULL)
152c43e99fdSEd Maste 		event_loopexit(NULL);
153c43e99fdSEd Maste 	else
154c43e99fdSEd Maste 		event_base_loopexit((struct event_base *)arg, NULL);
155c43e99fdSEd Maste }
156c43e99fdSEd Maste 
157c43e99fdSEd Maste static void
dns_gethostbyname(void)158c43e99fdSEd Maste dns_gethostbyname(void)
159c43e99fdSEd Maste {
160c43e99fdSEd Maste 	dns_ok = 0;
161c43e99fdSEd Maste 	evdns_resolve_ipv4("www.monkey.org", 0, dns_gethostbyname_cb, NULL);
162c43e99fdSEd Maste 	event_dispatch();
163c43e99fdSEd Maste 
164c43e99fdSEd Maste 	tt_int_op(dns_ok, ==, DNS_IPv4_A);
165c43e99fdSEd Maste 	test_ok = dns_ok;
166c43e99fdSEd Maste end:
167c43e99fdSEd Maste 	;
168c43e99fdSEd Maste }
169c43e99fdSEd Maste 
170c43e99fdSEd Maste static void
dns_gethostbyname6(void)171c43e99fdSEd Maste dns_gethostbyname6(void)
172c43e99fdSEd Maste {
173c43e99fdSEd Maste 	dns_ok = 0;
174c43e99fdSEd Maste 	evdns_resolve_ipv6("www.ietf.org", 0, dns_gethostbyname_cb, NULL);
175c43e99fdSEd Maste 	event_dispatch();
176c43e99fdSEd Maste 
177c43e99fdSEd Maste 	if (!dns_ok && dns_err == DNS_ERR_TIMEOUT) {
178c43e99fdSEd Maste 		tt_skip();
179c43e99fdSEd Maste 	}
180c43e99fdSEd Maste 
181c43e99fdSEd Maste 	tt_int_op(dns_ok, ==, DNS_IPv6_AAAA);
182c43e99fdSEd Maste 	test_ok = 1;
183c43e99fdSEd Maste end:
184c43e99fdSEd Maste 	;
185c43e99fdSEd Maste }
186c43e99fdSEd Maste 
187c43e99fdSEd Maste static void
dns_gethostbyaddr(void)188c43e99fdSEd Maste dns_gethostbyaddr(void)
189c43e99fdSEd Maste {
190c43e99fdSEd Maste 	struct in_addr in;
191c43e99fdSEd Maste 	in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
192c43e99fdSEd Maste 	dns_ok = 0;
193c43e99fdSEd Maste 	evdns_resolve_reverse(&in, 0, dns_gethostbyname_cb, NULL);
194c43e99fdSEd Maste 	event_dispatch();
195c43e99fdSEd Maste 
196c43e99fdSEd Maste 	tt_int_op(dns_ok, ==, DNS_PTR);
197c43e99fdSEd Maste 	test_ok = dns_ok;
198c43e99fdSEd Maste end:
199c43e99fdSEd Maste 	;
200c43e99fdSEd Maste }
201c43e99fdSEd Maste 
202c43e99fdSEd Maste static void
dns_resolve_reverse(void * ptr)203c43e99fdSEd Maste dns_resolve_reverse(void *ptr)
204c43e99fdSEd Maste {
205c43e99fdSEd Maste 	struct in_addr in;
206c43e99fdSEd Maste 	struct event_base *base = event_base_new();
207*b50261e2SCy Schubert 	struct evdns_base *dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS);
208c43e99fdSEd Maste 	struct evdns_request *req = NULL;
209c43e99fdSEd Maste 
210c43e99fdSEd Maste 	tt_assert(base);
211c43e99fdSEd Maste 	tt_assert(dns);
212c43e99fdSEd Maste 	in.s_addr = htonl(0x7f000001ul); /* 127.0.0.1 */
213c43e99fdSEd Maste 	dns_ok = 0;
214c43e99fdSEd Maste 
215c43e99fdSEd Maste 	req = evdns_base_resolve_reverse(
216c43e99fdSEd Maste 		dns, &in, 0, dns_gethostbyname_cb, base);
217c43e99fdSEd Maste 	tt_assert(req);
218c43e99fdSEd Maste 
219c43e99fdSEd Maste 	event_base_dispatch(base);
220c43e99fdSEd Maste 
221c43e99fdSEd Maste 	tt_int_op(dns_ok, ==, DNS_PTR);
222c43e99fdSEd Maste 
223c43e99fdSEd Maste end:
224c43e99fdSEd Maste 	if (dns)
225c43e99fdSEd Maste 		evdns_base_free(dns, 0);
226c43e99fdSEd Maste 	if (base)
227c43e99fdSEd Maste 		event_base_free(base);
228c43e99fdSEd Maste }
229c43e99fdSEd Maste 
230c43e99fdSEd Maste static int n_server_responses = 0;
231c43e99fdSEd Maste 
232c43e99fdSEd Maste static void
dns_server_request_cb(struct evdns_server_request * req,void * data)233c43e99fdSEd Maste dns_server_request_cb(struct evdns_server_request *req, void *data)
234c43e99fdSEd Maste {
235c43e99fdSEd Maste 	int i, r;
236c43e99fdSEd Maste 	const char TEST_ARPA[] = "11.11.168.192.in-addr.arpa";
237c43e99fdSEd Maste 	const char TEST_IN6[] =
238c43e99fdSEd Maste 	    "f.e.f.e." "0.0.0.0." "0.0.0.0." "1.1.1.1."
239c43e99fdSEd Maste 	    "a.a.a.a." "0.0.0.0." "0.0.0.0." "0.f.f.f.ip6.arpa";
240c43e99fdSEd Maste 
241c43e99fdSEd Maste 	for (i = 0; i < req->nquestions; ++i) {
242c43e99fdSEd Maste 		const int qtype = req->questions[i]->type;
243c43e99fdSEd Maste 		const int qclass = req->questions[i]->dns_question_class;
244c43e99fdSEd Maste 		const char *qname = req->questions[i]->name;
245c43e99fdSEd Maste 
246c43e99fdSEd Maste 		struct in_addr ans;
247c43e99fdSEd Maste 		ans.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
248c43e99fdSEd Maste 		if (qtype == EVDNS_TYPE_A &&
249c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
250c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
251c43e99fdSEd Maste 			r = evdns_server_request_add_a_reply(req, qname,
252c43e99fdSEd Maste 			    1, &ans.s_addr, 12345);
253c43e99fdSEd Maste 			if (r<0)
254c43e99fdSEd Maste 				dns_ok = 0;
255c43e99fdSEd Maste 		} else if (qtype == EVDNS_TYPE_AAAA &&
256c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
257c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "zz.example.com")) {
258c43e99fdSEd Maste 			char addr6[17] = "abcdefghijklmnop";
259c43e99fdSEd Maste 			r = evdns_server_request_add_aaaa_reply(req,
260c43e99fdSEd Maste 			    qname, 1, addr6, 123);
261c43e99fdSEd Maste 			if (r<0)
262c43e99fdSEd Maste 				dns_ok = 0;
263c43e99fdSEd Maste 		} else if (qtype == EVDNS_TYPE_PTR &&
264c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
265c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, TEST_ARPA)) {
266c43e99fdSEd Maste 			r = evdns_server_request_add_ptr_reply(req, NULL,
267c43e99fdSEd Maste 			    qname, "ZZ.EXAMPLE.COM", 54321);
268c43e99fdSEd Maste 			if (r<0)
269c43e99fdSEd Maste 				dns_ok = 0;
270c43e99fdSEd Maste 		} else if (qtype == EVDNS_TYPE_PTR &&
271c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
272c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, TEST_IN6)){
273c43e99fdSEd Maste 			r = evdns_server_request_add_ptr_reply(req, NULL,
274c43e99fdSEd Maste 			    qname,
275c43e99fdSEd Maste 			    "ZZ-INET6.EXAMPLE.COM", 54322);
276c43e99fdSEd Maste 			if (r<0)
277c43e99fdSEd Maste 				dns_ok = 0;
278c43e99fdSEd Maste 		} else if (qtype == EVDNS_TYPE_A &&
279c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
280c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "drop.example.com")) {
281c43e99fdSEd Maste 			if (evdns_server_request_drop(req)<0)
282c43e99fdSEd Maste 				dns_ok = 0;
283c43e99fdSEd Maste 			return;
284c43e99fdSEd Maste 		} else {
285c43e99fdSEd Maste 			printf("Unexpected question %d %d \"%s\" ",
286c43e99fdSEd Maste 			    qtype, qclass, qname);
287c43e99fdSEd Maste 			dns_ok = 0;
288c43e99fdSEd Maste 		}
289c43e99fdSEd Maste 	}
290c43e99fdSEd Maste 	r = evdns_server_request_respond(req, 0);
291c43e99fdSEd Maste 	if (r<0) {
292c43e99fdSEd Maste 		printf("Couldn't send reply. ");
293c43e99fdSEd Maste 		dns_ok = 0;
294c43e99fdSEd Maste 	}
295c43e99fdSEd Maste }
296c43e99fdSEd Maste 
297c43e99fdSEd Maste static void
dns_server_gethostbyname_cb(int result,char type,int count,int ttl,void * addresses,void * arg)298c43e99fdSEd Maste dns_server_gethostbyname_cb(int result, char type, int count, int ttl,
299c43e99fdSEd Maste     void *addresses, void *arg)
300c43e99fdSEd Maste {
301c43e99fdSEd Maste 	if (result == DNS_ERR_CANCEL) {
302c43e99fdSEd Maste 		if (arg != (void*)(char*)90909) {
303c43e99fdSEd Maste 			printf("Unexpected cancelation");
304c43e99fdSEd Maste 			dns_ok = 0;
305c43e99fdSEd Maste 		}
306c43e99fdSEd Maste 		dns_got_cancel = 1;
307c43e99fdSEd Maste 		goto out;
308c43e99fdSEd Maste 	}
309c43e99fdSEd Maste 	if (result != DNS_ERR_NONE) {
310c43e99fdSEd Maste 		printf("Unexpected result %d. ", result);
311c43e99fdSEd Maste 		dns_ok = 0;
312c43e99fdSEd Maste 		goto out;
313c43e99fdSEd Maste 	}
314c43e99fdSEd Maste 	if (count != 1) {
315c43e99fdSEd Maste 		printf("Unexpected answer count %d. ", count);
316c43e99fdSEd Maste 		dns_ok = 0;
317c43e99fdSEd Maste 		goto out;
318c43e99fdSEd Maste 	}
319c43e99fdSEd Maste 	switch (type) {
320c43e99fdSEd Maste 	case DNS_IPv4_A: {
321c43e99fdSEd Maste 		struct in_addr *in_addrs = addresses;
322c43e99fdSEd Maste 		if (in_addrs[0].s_addr != htonl(0xc0a80b0bUL) || ttl != 12345) {
323c43e99fdSEd Maste 			printf("Bad IPv4 response \"%s\" %d. ",
324c43e99fdSEd Maste 					inet_ntoa(in_addrs[0]), ttl);
325c43e99fdSEd Maste 			dns_ok = 0;
326c43e99fdSEd Maste 			goto out;
327c43e99fdSEd Maste 		}
328c43e99fdSEd Maste 		break;
329c43e99fdSEd Maste 	}
330c43e99fdSEd Maste 	case DNS_IPv6_AAAA: {
331c43e99fdSEd Maste #if defined (EVENT__HAVE_STRUCT_IN6_ADDR) && defined(EVENT__HAVE_INET_NTOP) && defined(INET6_ADDRSTRLEN)
332c43e99fdSEd Maste 		struct in6_addr *in6_addrs = addresses;
333c43e99fdSEd Maste 		char buf[INET6_ADDRSTRLEN+1];
334c43e99fdSEd Maste 		if (memcmp(&in6_addrs[0].s6_addr, "abcdefghijklmnop", 16)
335c43e99fdSEd Maste 		    || ttl != 123) {
336c43e99fdSEd Maste 			const char *b = evutil_inet_ntop(AF_INET6, &in6_addrs[0],buf,sizeof(buf));
337c43e99fdSEd Maste 			printf("Bad IPv6 response \"%s\" %d. ", b, ttl);
338c43e99fdSEd Maste 			dns_ok = 0;
339c43e99fdSEd Maste 			goto out;
340c43e99fdSEd Maste 		}
341c43e99fdSEd Maste #endif
342c43e99fdSEd Maste 		break;
343c43e99fdSEd Maste 	}
344c43e99fdSEd Maste 	case DNS_PTR: {
345c43e99fdSEd Maste 		char **addrs = addresses;
346c43e99fdSEd Maste 		if (arg != (void*)6) {
347c43e99fdSEd Maste 			if (strcmp(addrs[0], "ZZ.EXAMPLE.COM") ||
348c43e99fdSEd Maste 			    ttl != 54321) {
349c43e99fdSEd Maste 				printf("Bad PTR response \"%s\" %d. ",
350c43e99fdSEd Maste 				    addrs[0], ttl);
351c43e99fdSEd Maste 				dns_ok = 0;
352c43e99fdSEd Maste 				goto out;
353c43e99fdSEd Maste 			}
354c43e99fdSEd Maste 		} else {
355c43e99fdSEd Maste 			if (strcmp(addrs[0], "ZZ-INET6.EXAMPLE.COM") ||
356c43e99fdSEd Maste 			    ttl != 54322) {
357c43e99fdSEd Maste 				printf("Bad ipv6 PTR response \"%s\" %d. ",
358c43e99fdSEd Maste 				    addrs[0], ttl);
359c43e99fdSEd Maste 				dns_ok = 0;
360c43e99fdSEd Maste 				goto out;
361c43e99fdSEd Maste 			}
362c43e99fdSEd Maste 		}
363c43e99fdSEd Maste 		break;
364c43e99fdSEd Maste 	}
365c43e99fdSEd Maste 	default:
366c43e99fdSEd Maste 		printf("Bad response type %d. ", type);
367c43e99fdSEd Maste 		dns_ok = 0;
368c43e99fdSEd Maste 	}
369c43e99fdSEd Maste  out:
370c43e99fdSEd Maste 	if (++n_server_responses == 3) {
371c43e99fdSEd Maste 		event_loopexit(NULL);
372c43e99fdSEd Maste 	}
373c43e99fdSEd Maste }
374c43e99fdSEd Maste 
375c43e99fdSEd Maste static void
dns_server(void)376c43e99fdSEd Maste dns_server(void)
377c43e99fdSEd Maste {
378c43e99fdSEd Maste 	evutil_socket_t sock=-1;
379c43e99fdSEd Maste 	struct sockaddr_in my_addr;
380c43e99fdSEd Maste 	struct sockaddr_storage ss;
381c43e99fdSEd Maste 	ev_socklen_t slen;
382c43e99fdSEd Maste 	struct evdns_server_port *port=NULL;
383c43e99fdSEd Maste 	struct in_addr resolve_addr;
384c43e99fdSEd Maste 	struct in6_addr resolve_addr6;
385c43e99fdSEd Maste 	struct evdns_base *base=NULL;
386c43e99fdSEd Maste 	struct evdns_request *req=NULL;
387c43e99fdSEd Maste 
388c43e99fdSEd Maste 	dns_ok = 1;
389c43e99fdSEd Maste 
390c43e99fdSEd Maste 	base = evdns_base_new(NULL, 0);
391c43e99fdSEd Maste 
392c43e99fdSEd Maste 	/* Now configure a nameserver port. */
393c43e99fdSEd Maste 	sock = socket(AF_INET, SOCK_DGRAM, 0);
394c43e99fdSEd Maste 	if (sock<0) {
395c43e99fdSEd Maste 		tt_abort_perror("socket");
396c43e99fdSEd Maste 	}
397c43e99fdSEd Maste 
398c43e99fdSEd Maste 	evutil_make_socket_nonblocking(sock);
399c43e99fdSEd Maste 
400c43e99fdSEd Maste 	memset(&my_addr, 0, sizeof(my_addr));
401c43e99fdSEd Maste 	my_addr.sin_family = AF_INET;
402c43e99fdSEd Maste 	my_addr.sin_port = 0; /* kernel picks */
403c43e99fdSEd Maste 	my_addr.sin_addr.s_addr = htonl(0x7f000001UL);
404c43e99fdSEd Maste 	if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) < 0) {
405c43e99fdSEd Maste 		tt_abort_perror("bind");
406c43e99fdSEd Maste 	}
407c43e99fdSEd Maste 	slen = sizeof(ss);
408c43e99fdSEd Maste 	if (getsockname(sock, (struct sockaddr*)&ss, &slen) < 0) {
409c43e99fdSEd Maste 		tt_abort_perror("getsockname");
410c43e99fdSEd Maste 	}
411c43e99fdSEd Maste 
412c43e99fdSEd Maste 	port = evdns_add_server_port(sock, 0, dns_server_request_cb, NULL);
413c43e99fdSEd Maste 
414c43e99fdSEd Maste 	/* Add ourself as the only nameserver, and make sure we really are
415c43e99fdSEd Maste 	 * the only nameserver. */
416c43e99fdSEd Maste 	evdns_base_nameserver_sockaddr_add(base, (struct sockaddr*)&ss, slen, 0);
417c43e99fdSEd Maste 	tt_int_op(evdns_base_count_nameservers(base), ==, 1);
418c43e99fdSEd Maste 	{
419c43e99fdSEd Maste 		struct sockaddr_storage ss2;
420c43e99fdSEd Maste 		int slen2;
421c43e99fdSEd Maste 
422c43e99fdSEd Maste 		memset(&ss2, 0, sizeof(ss2));
423c43e99fdSEd Maste 
424c43e99fdSEd Maste 		slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, 3);
425c43e99fdSEd Maste 		tt_int_op(slen2, ==, slen);
426c43e99fdSEd Maste 		tt_int_op(ss2.ss_family, ==, 0);
427c43e99fdSEd Maste 		slen2 = evdns_base_get_nameserver_addr(base, 0, (struct sockaddr *)&ss2, sizeof(ss2));
428c43e99fdSEd Maste 		tt_int_op(slen2, ==, slen);
429c43e99fdSEd Maste 		tt_mem_op(&ss2, ==, &ss, slen);
430c43e99fdSEd Maste 
431c43e99fdSEd Maste 		slen2 = evdns_base_get_nameserver_addr(base, 1, (struct sockaddr *)&ss2, sizeof(ss2));
432c43e99fdSEd Maste 		tt_int_op(-1, ==, slen2);
433c43e99fdSEd Maste 	}
434c43e99fdSEd Maste 
435c43e99fdSEd Maste 	/* Send some queries. */
436c43e99fdSEd Maste 	evdns_base_resolve_ipv4(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
437c43e99fdSEd Maste 					   dns_server_gethostbyname_cb, NULL);
438c43e99fdSEd Maste 	evdns_base_resolve_ipv6(base, "zz.example.com", DNS_QUERY_NO_SEARCH,
439c43e99fdSEd Maste 					   dns_server_gethostbyname_cb, NULL);
440c43e99fdSEd Maste 	resolve_addr.s_addr = htonl(0xc0a80b0bUL); /* 192.168.11.11 */
441c43e99fdSEd Maste 	evdns_base_resolve_reverse(base, &resolve_addr, 0,
442c43e99fdSEd Maste 	    dns_server_gethostbyname_cb, NULL);
443c43e99fdSEd Maste 	memcpy(resolve_addr6.s6_addr,
444c43e99fdSEd Maste 	    "\xff\xf0\x00\x00\x00\x00\xaa\xaa"
445c43e99fdSEd Maste 	    "\x11\x11\x00\x00\x00\x00\xef\xef", 16);
446c43e99fdSEd Maste 	evdns_base_resolve_reverse_ipv6(base, &resolve_addr6, 0,
447c43e99fdSEd Maste 	    dns_server_gethostbyname_cb, (void*)6);
448c43e99fdSEd Maste 
449c43e99fdSEd Maste 	req = evdns_base_resolve_ipv4(base,
450c43e99fdSEd Maste 	    "drop.example.com", DNS_QUERY_NO_SEARCH,
451c43e99fdSEd Maste 	    dns_server_gethostbyname_cb, (void*)(char*)90909);
452c43e99fdSEd Maste 
453c43e99fdSEd Maste 	evdns_cancel_request(base, req);
454c43e99fdSEd Maste 
455c43e99fdSEd Maste 	event_dispatch();
456c43e99fdSEd Maste 
457c43e99fdSEd Maste 	tt_assert(dns_got_cancel);
458c43e99fdSEd Maste 	test_ok = dns_ok;
459c43e99fdSEd Maste 
460c43e99fdSEd Maste end:
461c43e99fdSEd Maste 	if (port)
462c43e99fdSEd Maste 		evdns_close_server_port(port);
463c43e99fdSEd Maste 	if (sock >= 0)
464c43e99fdSEd Maste 		evutil_closesocket(sock);
465c43e99fdSEd Maste 	if (base)
466c43e99fdSEd Maste 		evdns_base_free(base, 0);
467c43e99fdSEd Maste }
468c43e99fdSEd Maste 
469c43e99fdSEd Maste static int n_replies_left;
470c43e99fdSEd Maste static struct event_base *exit_base;
471c43e99fdSEd Maste static struct evdns_server_port *exit_port;
472c43e99fdSEd Maste 
473c43e99fdSEd Maste struct generic_dns_callback_result {
474c43e99fdSEd Maste 	int result;
475c43e99fdSEd Maste 	char type;
476c43e99fdSEd Maste 	int count;
477c43e99fdSEd Maste 	int ttl;
478c43e99fdSEd Maste 	size_t addrs_len;
479c43e99fdSEd Maste 	void *addrs;
480c43e99fdSEd Maste 	char addrs_buf[256];
481c43e99fdSEd Maste };
482c43e99fdSEd Maste 
483c43e99fdSEd Maste static void
generic_dns_callback(int result,char type,int count,int ttl,void * addresses,void * arg)484c43e99fdSEd Maste generic_dns_callback(int result, char type, int count, int ttl, void *addresses,
485c43e99fdSEd Maste     void *arg)
486c43e99fdSEd Maste {
487c43e99fdSEd Maste 	size_t len;
488c43e99fdSEd Maste 	struct generic_dns_callback_result *res = arg;
489c43e99fdSEd Maste 	res->result = result;
490c43e99fdSEd Maste 	res->type = type;
491c43e99fdSEd Maste 	res->count = count;
492c43e99fdSEd Maste 	res->ttl = ttl;
493c43e99fdSEd Maste 
494c43e99fdSEd Maste 	if (type == DNS_IPv4_A)
495c43e99fdSEd Maste 		len = count * 4;
496c43e99fdSEd Maste 	else if (type == DNS_IPv6_AAAA)
497c43e99fdSEd Maste 		len = count * 16;
498c43e99fdSEd Maste 	else if (type == DNS_PTR)
499c43e99fdSEd Maste 		len = strlen(addresses)+1;
500c43e99fdSEd Maste 	else {
501c43e99fdSEd Maste 		res->addrs_len = len = 0;
502c43e99fdSEd Maste 		res->addrs = NULL;
503c43e99fdSEd Maste 	}
504c43e99fdSEd Maste 	if (len) {
505c43e99fdSEd Maste 		res->addrs_len = len;
506c43e99fdSEd Maste 		if (len > 256)
507c43e99fdSEd Maste 			len = 256;
508c43e99fdSEd Maste 		memcpy(res->addrs_buf, addresses, len);
509c43e99fdSEd Maste 		res->addrs = res->addrs_buf;
510c43e99fdSEd Maste 	}
511c43e99fdSEd Maste 
512c43e99fdSEd Maste 	--n_replies_left;
513c43e99fdSEd Maste 	if (n_replies_left == 0) {
514c43e99fdSEd Maste 		if (exit_port) {
515c43e99fdSEd Maste 			evdns_close_server_port(exit_port);
516c43e99fdSEd Maste 			exit_port = NULL;
517c43e99fdSEd Maste 		} else
518c43e99fdSEd Maste 			event_base_loopexit(exit_base, NULL);
519c43e99fdSEd Maste 	}
520c43e99fdSEd Maste }
521c43e99fdSEd Maste 
522c43e99fdSEd Maste static struct regress_dns_server_table search_table[] = {
523c43e99fdSEd Maste 	{ "host.a.example.com", "err", "3", 0, 0 },
524c43e99fdSEd Maste 	{ "host.b.example.com", "err", "3", 0, 0 },
525c43e99fdSEd Maste 	{ "host.c.example.com", "A", "11.22.33.44", 0, 0 },
526c43e99fdSEd Maste 	{ "host2.a.example.com", "err", "3", 0, 0 },
527c43e99fdSEd Maste 	{ "host2.b.example.com", "A", "200.100.0.100", 0, 0 },
528c43e99fdSEd Maste 	{ "host2.c.example.com", "err", "3", 0, 0 },
529c43e99fdSEd Maste 	{ "hostn.a.example.com", "errsoa", "0", 0, 0 },
530c43e99fdSEd Maste 	{ "hostn.b.example.com", "errsoa", "3", 0, 0 },
531c43e99fdSEd Maste 	{ "hostn.c.example.com", "err", "0", 0, 0 },
532c43e99fdSEd Maste 
533c43e99fdSEd Maste 	{ "host", "err", "3", 0, 0 },
534c43e99fdSEd Maste 	{ "host2", "err", "3", 0, 0 },
535c43e99fdSEd Maste 	{ "*", "err", "3", 0, 0 },
536c43e99fdSEd Maste 	{ NULL, NULL, NULL, 0, 0 }
537c43e99fdSEd Maste };
538c43e99fdSEd Maste static void
dns_search_test_impl(void * arg,int lower)539c43e99fdSEd Maste dns_search_test_impl(void *arg, int lower)
540c43e99fdSEd Maste {
541c43e99fdSEd Maste 	struct regress_dns_server_table table[ARRAY_SIZE(search_table)];
542c43e99fdSEd Maste 	struct basic_test_data *data = arg;
543c43e99fdSEd Maste 	struct event_base *base = data->base;
544c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
545c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
546c43e99fdSEd Maste 	char buf[64];
547c43e99fdSEd Maste 
548c43e99fdSEd Maste 	struct generic_dns_callback_result r[8];
549c43e99fdSEd Maste 	size_t i;
550c43e99fdSEd Maste 
551c43e99fdSEd Maste 	for (i = 0; i < ARRAY_SIZE(table); ++i) {
552c43e99fdSEd Maste 		table[i] = search_table[i];
553c43e99fdSEd Maste 		table[i].lower = lower;
554c43e99fdSEd Maste 	}
555c43e99fdSEd Maste 
556c43e99fdSEd Maste 	tt_assert(regress_dnsserver(base, &portnum, table));
557c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
558c43e99fdSEd Maste 
559c43e99fdSEd Maste 	dns = evdns_base_new(base, 0);
560c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
561c43e99fdSEd Maste 
562c43e99fdSEd Maste 	evdns_base_search_add(dns, "a.example.com");
563c43e99fdSEd Maste 	evdns_base_search_add(dns, "b.example.com");
564c43e99fdSEd Maste 	evdns_base_search_add(dns, "c.example.com");
565c43e99fdSEd Maste 
566c43e99fdSEd Maste 	n_replies_left = ARRAY_SIZE(r);
567c43e99fdSEd Maste 	exit_base = base;
568c43e99fdSEd Maste 
569c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
570c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host2", 0, generic_dns_callback, &r[1]);
571c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host", DNS_NO_SEARCH, generic_dns_callback, &r[2]);
572c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host2", DNS_NO_SEARCH, generic_dns_callback, &r[3]);
573c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host3", 0, generic_dns_callback, &r[4]);
574c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
575c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
576c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);
577c43e99fdSEd Maste 
578c43e99fdSEd Maste 	event_base_dispatch(base);
579c43e99fdSEd Maste 
580c43e99fdSEd Maste 	tt_int_op(r[0].type, ==, DNS_IPv4_A);
581c43e99fdSEd Maste 	tt_int_op(r[0].count, ==, 1);
582c43e99fdSEd Maste 	tt_int_op(((ev_uint32_t*)r[0].addrs)[0], ==, htonl(0x0b16212c));
583c43e99fdSEd Maste 	tt_int_op(r[1].type, ==, DNS_IPv4_A);
584c43e99fdSEd Maste 	tt_int_op(r[1].count, ==, 1);
585c43e99fdSEd Maste 	tt_int_op(((ev_uint32_t*)r[1].addrs)[0], ==, htonl(0xc8640064));
586c43e99fdSEd Maste 	tt_int_op(r[2].result, ==, DNS_ERR_NOTEXIST);
587c43e99fdSEd Maste 	tt_int_op(r[3].result, ==, DNS_ERR_NOTEXIST);
588c43e99fdSEd Maste 	tt_int_op(r[4].result, ==, DNS_ERR_NOTEXIST);
589c43e99fdSEd Maste 	tt_int_op(r[5].result, ==, DNS_ERR_NODATA);
590c43e99fdSEd Maste 	tt_int_op(r[5].ttl, ==, 42);
591c43e99fdSEd Maste 	tt_int_op(r[6].result, ==, DNS_ERR_NOTEXIST);
592c43e99fdSEd Maste 	tt_int_op(r[6].ttl, ==, 42);
593c43e99fdSEd Maste 	tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
594c43e99fdSEd Maste 	tt_int_op(r[7].ttl, ==, 0);
595c43e99fdSEd Maste 
596c43e99fdSEd Maste end:
597c43e99fdSEd Maste 	if (dns)
598c43e99fdSEd Maste 		evdns_base_free(dns, 0);
599c43e99fdSEd Maste 
600c43e99fdSEd Maste 	regress_clean_dnsserver();
601c43e99fdSEd Maste }
602c43e99fdSEd Maste static void
dns_search_empty_test(void * arg)603c43e99fdSEd Maste dns_search_empty_test(void *arg)
604c43e99fdSEd Maste {
605c43e99fdSEd Maste 	struct basic_test_data *data = arg;
606c43e99fdSEd Maste 	struct event_base *base = data->base;
607c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
608c43e99fdSEd Maste 
609c43e99fdSEd Maste 	dns = evdns_base_new(base, 0);
610c43e99fdSEd Maste 
611c43e99fdSEd Maste 	evdns_base_search_add(dns, "whatever.example.com");
612c43e99fdSEd Maste 
613c43e99fdSEd Maste 	n_replies_left = 1;
614c43e99fdSEd Maste 	exit_base = base;
615c43e99fdSEd Maste 
616c43e99fdSEd Maste 	tt_ptr_op(evdns_base_resolve_ipv4(dns, "", 0, generic_dns_callback, NULL), ==, NULL);
617c43e99fdSEd Maste 
618c43e99fdSEd Maste end:
619c43e99fdSEd Maste 	if (dns)
620c43e99fdSEd Maste 		evdns_base_free(dns, 0);
621c43e99fdSEd Maste }
dns_search_test(void * arg)622*b50261e2SCy Schubert static void dns_search_test(void *arg) { dns_search_test_impl(arg, 0); }
dns_search_lower_test(void * arg)623*b50261e2SCy Schubert static void dns_search_lower_test(void *arg) { dns_search_test_impl(arg, 1); }
624c43e99fdSEd Maste 
625c43e99fdSEd Maste static int request_count = 0;
626c43e99fdSEd Maste static struct evdns_request *current_req = NULL;
627c43e99fdSEd Maste 
628c43e99fdSEd Maste static void
search_cancel_server_cb(struct evdns_server_request * req,void * data)629c43e99fdSEd Maste search_cancel_server_cb(struct evdns_server_request *req, void *data)
630c43e99fdSEd Maste {
631c43e99fdSEd Maste 	const char *question;
632c43e99fdSEd Maste 
633c43e99fdSEd Maste 	if (req->nquestions != 1)
634c43e99fdSEd Maste 		TT_DIE(("Only handling one question at a time; got %d",
635c43e99fdSEd Maste 			req->nquestions));
636c43e99fdSEd Maste 
637c43e99fdSEd Maste 	question = req->questions[0]->name;
638c43e99fdSEd Maste 
639c43e99fdSEd Maste 	TT_BLATHER(("got question, %s", question));
640c43e99fdSEd Maste 
641c43e99fdSEd Maste 	tt_assert(request_count > 0);
642c43e99fdSEd Maste 	tt_assert(!evdns_server_request_respond(req, 3));
643c43e99fdSEd Maste 
644c43e99fdSEd Maste 	if (!--request_count)
645c43e99fdSEd Maste 		evdns_cancel_request(NULL, current_req);
646c43e99fdSEd Maste 
647c43e99fdSEd Maste end:
648c43e99fdSEd Maste 	;
649c43e99fdSEd Maste }
650c43e99fdSEd Maste 
651c43e99fdSEd Maste static void
dns_search_cancel_test(void * arg)652c43e99fdSEd Maste dns_search_cancel_test(void *arg)
653c43e99fdSEd Maste {
654c43e99fdSEd Maste 	struct basic_test_data *data = arg;
655c43e99fdSEd Maste 	struct event_base *base = data->base;
656c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
657c43e99fdSEd Maste 	struct evdns_server_port *port = NULL;
658c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
659c43e99fdSEd Maste 	struct generic_dns_callback_result r1;
660c43e99fdSEd Maste 	char buf[64];
661c43e99fdSEd Maste 
662c43e99fdSEd Maste 	port = regress_get_dnsserver(base, &portnum, NULL,
663c43e99fdSEd Maste 	    search_cancel_server_cb, NULL);
664c43e99fdSEd Maste 	tt_assert(port);
665c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
666c43e99fdSEd Maste 
667c43e99fdSEd Maste 	dns = evdns_base_new(base, 0);
668c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
669c43e99fdSEd Maste 
670c43e99fdSEd Maste 	evdns_base_search_add(dns, "a.example.com");
671c43e99fdSEd Maste 	evdns_base_search_add(dns, "b.example.com");
672c43e99fdSEd Maste 	evdns_base_search_add(dns, "c.example.com");
673c43e99fdSEd Maste 	evdns_base_search_add(dns, "d.example.com");
674c43e99fdSEd Maste 
675c43e99fdSEd Maste 	exit_base = base;
676c43e99fdSEd Maste 	request_count = 3;
677c43e99fdSEd Maste 	n_replies_left = 1;
678c43e99fdSEd Maste 
679c43e99fdSEd Maste 	current_req = evdns_base_resolve_ipv4(dns, "host", 0,
680c43e99fdSEd Maste 					generic_dns_callback, &r1);
681c43e99fdSEd Maste 	event_base_dispatch(base);
682c43e99fdSEd Maste 
683c43e99fdSEd Maste 	tt_int_op(r1.result, ==, DNS_ERR_CANCEL);
684c43e99fdSEd Maste 
685c43e99fdSEd Maste end:
686c43e99fdSEd Maste 	if (port)
687c43e99fdSEd Maste 		evdns_close_server_port(port);
688c43e99fdSEd Maste 	if (dns)
689c43e99fdSEd Maste 		evdns_base_free(dns, 0);
690c43e99fdSEd Maste }
691c43e99fdSEd Maste 
692c43e99fdSEd Maste static void
fail_server_cb(struct evdns_server_request * req,void * data)693c43e99fdSEd Maste fail_server_cb(struct evdns_server_request *req, void *data)
694c43e99fdSEd Maste {
695c43e99fdSEd Maste 	const char *question;
696c43e99fdSEd Maste 	int *count = data;
697c43e99fdSEd Maste 	struct in_addr in;
698c43e99fdSEd Maste 
699c43e99fdSEd Maste 	/* Drop the first N requests that we get. */
700c43e99fdSEd Maste 	if (*count > 0) {
701c43e99fdSEd Maste 		--*count;
702c43e99fdSEd Maste 		tt_want(! evdns_server_request_drop(req));
703c43e99fdSEd Maste 		return;
704c43e99fdSEd Maste 	}
705c43e99fdSEd Maste 
706c43e99fdSEd Maste 	if (req->nquestions != 1)
707c43e99fdSEd Maste 		TT_DIE(("Only handling one question at a time; got %d",
708c43e99fdSEd Maste 			req->nquestions));
709c43e99fdSEd Maste 
710c43e99fdSEd Maste 	question = req->questions[0]->name;
711c43e99fdSEd Maste 
712c43e99fdSEd Maste 	if (!evutil_ascii_strcasecmp(question, "google.com")) {
713c43e99fdSEd Maste 		/* Detect a probe, and get out of the loop. */
714c43e99fdSEd Maste 		event_base_loopexit(exit_base, NULL);
715c43e99fdSEd Maste 	}
716c43e99fdSEd Maste 
717c43e99fdSEd Maste 	tt_assert(evutil_inet_pton(AF_INET, "16.32.64.128", &in));
718c43e99fdSEd Maste 	evdns_server_request_add_a_reply(req, question, 1, &in.s_addr,
719c43e99fdSEd Maste 	    100);
720c43e99fdSEd Maste 	tt_assert(! evdns_server_request_respond(req, 0))
721c43e99fdSEd Maste 	return;
722c43e99fdSEd Maste end:
723c43e99fdSEd Maste 	tt_want(! evdns_server_request_drop(req));
724c43e99fdSEd Maste }
725c43e99fdSEd Maste 
726c43e99fdSEd Maste static void
dns_retry_test_impl(void * arg,int flags)727c43e99fdSEd Maste dns_retry_test_impl(void *arg, int flags)
728c43e99fdSEd Maste {
729c43e99fdSEd Maste 	struct basic_test_data *data = arg;
730c43e99fdSEd Maste 	struct event_base *base = data->base;
731c43e99fdSEd Maste 	struct evdns_server_port *port = NULL;
732c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
733c43e99fdSEd Maste 	int drop_count = 2;
734c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
735c43e99fdSEd Maste 	char buf[64];
736c43e99fdSEd Maste 
737c43e99fdSEd Maste 	struct generic_dns_callback_result r1;
738c43e99fdSEd Maste 
739c43e99fdSEd Maste 	port = regress_get_dnsserver(base, &portnum, NULL,
740c43e99fdSEd Maste 	    fail_server_cb, &drop_count);
741c43e99fdSEd Maste 	tt_assert(port);
742c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
743c43e99fdSEd Maste 
744c43e99fdSEd Maste 	dns = evdns_base_new(base, flags);
745c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
746c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "timeout", "0.2"));
747c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "10"));
748c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "initial-probe-timeout", "0.1"));
749c43e99fdSEd Maste 
750c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
751c43e99fdSEd Maste 	    generic_dns_callback, &r1);
752c43e99fdSEd Maste 
753c43e99fdSEd Maste 	n_replies_left = 1;
754c43e99fdSEd Maste 	exit_base = base;
755c43e99fdSEd Maste 
756c43e99fdSEd Maste 	event_base_dispatch(base);
757c43e99fdSEd Maste 
758c43e99fdSEd Maste 	tt_int_op(drop_count, ==, 0);
759c43e99fdSEd Maste 
760c43e99fdSEd Maste 	tt_int_op(r1.type, ==, DNS_IPv4_A);
761c43e99fdSEd Maste 	tt_int_op(r1.count, ==, 1);
762c43e99fdSEd Maste 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
763c43e99fdSEd Maste 
764c43e99fdSEd Maste 	/* Now try again, but this time have the server get treated as
765c43e99fdSEd Maste 	 * failed, so we can send it a test probe. */
766c43e99fdSEd Maste 	drop_count = 4;
767c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
768c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "attempts:", "3"));
769c43e99fdSEd Maste 	memset(&r1, 0, sizeof(r1));
770c43e99fdSEd Maste 
771c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
772c43e99fdSEd Maste 	    generic_dns_callback, &r1);
773c43e99fdSEd Maste 
774c43e99fdSEd Maste 	n_replies_left = 2;
775c43e99fdSEd Maste 
776c43e99fdSEd Maste 	/* This will run until it answers the "google.com" probe request. */
777c43e99fdSEd Maste 	event_base_dispatch(base);
778c43e99fdSEd Maste 
779c43e99fdSEd Maste 	/* We'll treat the server as failed here. */
780c43e99fdSEd Maste 	tt_int_op(r1.result, ==, DNS_ERR_TIMEOUT);
781c43e99fdSEd Maste 
782c43e99fdSEd Maste 	/* It should work this time. */
783c43e99fdSEd Maste 	tt_int_op(drop_count, ==, 0);
784c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "host.example.com", 0,
785c43e99fdSEd Maste 	    generic_dns_callback, &r1);
786c43e99fdSEd Maste 
787c43e99fdSEd Maste 	event_base_dispatch(base);
788c43e99fdSEd Maste 	tt_int_op(r1.result, ==, DNS_ERR_NONE);
789c43e99fdSEd Maste 	tt_int_op(r1.type, ==, DNS_IPv4_A);
790c43e99fdSEd Maste 	tt_int_op(r1.count, ==, 1);
791c43e99fdSEd Maste 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0x10204080));
792c43e99fdSEd Maste 
793c43e99fdSEd Maste end:
794c43e99fdSEd Maste 	if (dns)
795c43e99fdSEd Maste 		evdns_base_free(dns, 0);
796c43e99fdSEd Maste 	if (port)
797c43e99fdSEd Maste 		evdns_close_server_port(port);
798c43e99fdSEd Maste }
799c43e99fdSEd Maste static void
dns_retry_test(void * arg)800c43e99fdSEd Maste dns_retry_test(void *arg)
801c43e99fdSEd Maste {
802c43e99fdSEd Maste 	dns_retry_test_impl(arg, 0);
803c43e99fdSEd Maste }
804c43e99fdSEd Maste static void
dns_retry_disable_when_inactive_test(void * arg)805c43e99fdSEd Maste dns_retry_disable_when_inactive_test(void *arg)
806c43e99fdSEd Maste {
807c43e99fdSEd Maste 	dns_retry_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
808c43e99fdSEd Maste }
809c43e99fdSEd Maste 
810c43e99fdSEd Maste static struct regress_dns_server_table internal_error_table[] = {
811c43e99fdSEd Maste 	/* Error 4 (NOTIMPL) makes us reissue the request to another server
812c43e99fdSEd Maste 	   if we can.
813c43e99fdSEd Maste 
814c43e99fdSEd Maste 	   XXXX we should reissue under a much wider set of circumstances!
815c43e99fdSEd Maste 	 */
816c43e99fdSEd Maste 	{ "foof.example.com", "err", "4", 0, 0 },
817c43e99fdSEd Maste 	{ NULL, NULL, NULL, 0, 0 }
818c43e99fdSEd Maste };
819c43e99fdSEd Maste 
820c43e99fdSEd Maste static struct regress_dns_server_table reissue_table[] = {
821c43e99fdSEd Maste 	{ "foof.example.com", "A", "240.15.240.15", 0, 0 },
822c43e99fdSEd Maste 	{ NULL, NULL, NULL, 0, 0 }
823c43e99fdSEd Maste };
824c43e99fdSEd Maste 
825c43e99fdSEd Maste static void
dns_reissue_test_impl(void * arg,int flags)826c43e99fdSEd Maste dns_reissue_test_impl(void *arg, int flags)
827c43e99fdSEd Maste {
828c43e99fdSEd Maste 	struct basic_test_data *data = arg;
829c43e99fdSEd Maste 	struct event_base *base = data->base;
830c43e99fdSEd Maste 	struct evdns_server_port *port1 = NULL, *port2 = NULL;
831c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
832c43e99fdSEd Maste 	struct generic_dns_callback_result r1;
833c43e99fdSEd Maste 	ev_uint16_t portnum1 = 0, portnum2=0;
834c43e99fdSEd Maste 	char buf1[64], buf2[64];
835c43e99fdSEd Maste 
836c43e99fdSEd Maste 	port1 = regress_get_dnsserver(base, &portnum1, NULL,
837c43e99fdSEd Maste 	    regress_dns_server_cb, internal_error_table);
838c43e99fdSEd Maste 	tt_assert(port1);
839c43e99fdSEd Maste 	port2 = regress_get_dnsserver(base, &portnum2, NULL,
840c43e99fdSEd Maste 	    regress_dns_server_cb, reissue_table);
841c43e99fdSEd Maste 	tt_assert(port2);
842c43e99fdSEd Maste 	evutil_snprintf(buf1, sizeof(buf1), "127.0.0.1:%d", (int)portnum1);
843c43e99fdSEd Maste 	evutil_snprintf(buf2, sizeof(buf2), "127.0.0.1:%d", (int)portnum2);
844c43e99fdSEd Maste 
845c43e99fdSEd Maste 	dns = evdns_base_new(base, flags);
846c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf1));
847c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "timeout:", "0.3"));
848c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "max-timeouts:", "2"));
849c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "attempts:", "5"));
850c43e99fdSEd Maste 
851c43e99fdSEd Maste 	memset(&r1, 0, sizeof(r1));
852c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "foof.example.com", 0,
853c43e99fdSEd Maste 	    generic_dns_callback, &r1);
854c43e99fdSEd Maste 
855c43e99fdSEd Maste 	/* Add this after, so that we are sure to get a reissue. */
856c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf2));
857c43e99fdSEd Maste 
858c43e99fdSEd Maste 	n_replies_left = 1;
859c43e99fdSEd Maste 	exit_base = base;
860c43e99fdSEd Maste 
861c43e99fdSEd Maste 	event_base_dispatch(base);
862c43e99fdSEd Maste 	tt_int_op(r1.result, ==, DNS_ERR_NONE);
863c43e99fdSEd Maste 	tt_int_op(r1.type, ==, DNS_IPv4_A);
864c43e99fdSEd Maste 	tt_int_op(r1.count, ==, 1);
865c43e99fdSEd Maste 	tt_int_op(((ev_uint32_t*)r1.addrs)[0], ==, htonl(0xf00ff00f));
866c43e99fdSEd Maste 
867c43e99fdSEd Maste 	/* Make sure we dropped at least once. */
868c43e99fdSEd Maste 	tt_int_op(internal_error_table[0].seen, >, 0);
869c43e99fdSEd Maste 
870c43e99fdSEd Maste end:
871c43e99fdSEd Maste 	if (dns)
872c43e99fdSEd Maste 		evdns_base_free(dns, 0);
873c43e99fdSEd Maste 	if (port1)
874c43e99fdSEd Maste 		evdns_close_server_port(port1);
875c43e99fdSEd Maste 	if (port2)
876c43e99fdSEd Maste 		evdns_close_server_port(port2);
877c43e99fdSEd Maste }
878c43e99fdSEd Maste static void
dns_reissue_test(void * arg)879c43e99fdSEd Maste dns_reissue_test(void *arg)
880c43e99fdSEd Maste {
881c43e99fdSEd Maste 	dns_reissue_test_impl(arg, 0);
882c43e99fdSEd Maste }
883c43e99fdSEd Maste static void
dns_reissue_disable_when_inactive_test(void * arg)884c43e99fdSEd Maste dns_reissue_disable_when_inactive_test(void *arg)
885c43e99fdSEd Maste {
886c43e99fdSEd Maste 	dns_reissue_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
887c43e99fdSEd Maste }
888c43e99fdSEd Maste 
889c43e99fdSEd Maste #if 0
890c43e99fdSEd Maste static void
891c43e99fdSEd Maste dumb_bytes_fn(char *p, size_t n)
892c43e99fdSEd Maste {
893c43e99fdSEd Maste 	unsigned i;
894c43e99fdSEd Maste 	/* This gets us 6 bits of entropy per transaction ID, which means we
895c43e99fdSEd Maste 	 * will have probably have collisions and need to pick again. */
896c43e99fdSEd Maste 	for (i=0;i<n;++i)
897c43e99fdSEd Maste 		p[i] = (char)(rand() & 7);
898c43e99fdSEd Maste }
899c43e99fdSEd Maste #endif
900c43e99fdSEd Maste 
901c43e99fdSEd Maste static void
dns_inflight_test_impl(void * arg,int flags)902c43e99fdSEd Maste dns_inflight_test_impl(void *arg, int flags)
903c43e99fdSEd Maste {
904c43e99fdSEd Maste 	struct basic_test_data *data = arg;
905c43e99fdSEd Maste 	struct event_base *base = data->base;
906c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
907c43e99fdSEd Maste 	struct evdns_server_port *dns_port = NULL;
908c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
909c43e99fdSEd Maste 	char buf[64];
910c43e99fdSEd Maste 	int disable_when_inactive = flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE;
911c43e99fdSEd Maste 
912c43e99fdSEd Maste 	struct generic_dns_callback_result r[20];
913c43e99fdSEd Maste 	int i;
914c43e99fdSEd Maste 
915c43e99fdSEd Maste 	dns_port = regress_get_dnsserver(base, &portnum, NULL,
916c43e99fdSEd Maste 		regress_dns_server_cb, reissue_table);
917c43e99fdSEd Maste 	tt_assert(dns_port);
918c43e99fdSEd Maste 	if (disable_when_inactive) {
919c43e99fdSEd Maste 		exit_port = dns_port;
920c43e99fdSEd Maste 	}
921c43e99fdSEd Maste 
922c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
923c43e99fdSEd Maste 
924c43e99fdSEd Maste 	dns = evdns_base_new(base, flags);
925c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
926c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "max-inflight:", "3"));
927c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "randomize-case:", "0"));
928c43e99fdSEd Maste 
929c43e99fdSEd Maste 	for (i=0;i<20;++i)
930c43e99fdSEd Maste 		evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
931c43e99fdSEd Maste 
932c43e99fdSEd Maste 	n_replies_left = 20;
933c43e99fdSEd Maste 	exit_base = base;
934c43e99fdSEd Maste 
935c43e99fdSEd Maste 	event_base_dispatch(base);
936c43e99fdSEd Maste 
937c43e99fdSEd Maste 	for (i=0;i<20;++i) {
938c43e99fdSEd Maste 		tt_int_op(r[i].type, ==, DNS_IPv4_A);
939c43e99fdSEd Maste 		tt_int_op(r[i].count, ==, 1);
940c43e99fdSEd Maste 		tt_int_op(((ev_uint32_t*)r[i].addrs)[0], ==, htonl(0xf00ff00f));
941c43e99fdSEd Maste 	}
942c43e99fdSEd Maste 
943c43e99fdSEd Maste end:
944c43e99fdSEd Maste 	if (dns)
945c43e99fdSEd Maste 		evdns_base_free(dns, 0);
946c43e99fdSEd Maste 	if (exit_port) {
947c43e99fdSEd Maste 		evdns_close_server_port(exit_port);
948c43e99fdSEd Maste 		exit_port = NULL;
949c43e99fdSEd Maste 	} else if (! disable_when_inactive) {
950c43e99fdSEd Maste 		evdns_close_server_port(dns_port);
951c43e99fdSEd Maste 	}
952c43e99fdSEd Maste }
953c43e99fdSEd Maste 
954c43e99fdSEd Maste static void
dns_inflight_test(void * arg)955c43e99fdSEd Maste dns_inflight_test(void *arg)
956c43e99fdSEd Maste {
957c43e99fdSEd Maste 	dns_inflight_test_impl(arg, 0);
958c43e99fdSEd Maste }
959c43e99fdSEd Maste 
960c43e99fdSEd Maste static void
dns_disable_when_inactive_test(void * arg)961c43e99fdSEd Maste dns_disable_when_inactive_test(void *arg)
962c43e99fdSEd Maste {
963c43e99fdSEd Maste 	dns_inflight_test_impl(arg, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
964c43e99fdSEd Maste }
965c43e99fdSEd Maste 
966c43e99fdSEd Maste static void
dns_disable_when_inactive_no_ns_test(void * arg)967c43e99fdSEd Maste dns_disable_when_inactive_no_ns_test(void *arg)
968c43e99fdSEd Maste {
969c43e99fdSEd Maste 	struct basic_test_data *data = arg;
970c43e99fdSEd Maste 	struct event_base *base = data->base, *inactive_base;
971c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
972c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
973c43e99fdSEd Maste 	char buf[64];
974c43e99fdSEd Maste 	struct generic_dns_callback_result r;
975c43e99fdSEd Maste 
976c43e99fdSEd Maste 	inactive_base = event_base_new();
977c43e99fdSEd Maste 	tt_assert(inactive_base);
978c43e99fdSEd Maste 
979c43e99fdSEd Maste 	/** Create dns server with inactive base, to avoid replying to clients */
980c43e99fdSEd Maste 	tt_assert(regress_dnsserver(inactive_base, &portnum, search_table));
981c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
982c43e99fdSEd Maste 
983c43e99fdSEd Maste 	dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
984c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
985c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns, "timeout:", "0.1"));
986c43e99fdSEd Maste 
987c43e99fdSEd Maste 	evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r);
988c43e99fdSEd Maste 	n_replies_left = 1;
989c43e99fdSEd Maste 	exit_base = base;
990c43e99fdSEd Maste 
991c43e99fdSEd Maste 	event_base_dispatch(base);
992c43e99fdSEd Maste 
993c43e99fdSEd Maste 	tt_int_op(n_replies_left, ==, 0);
994c43e99fdSEd Maste 
995c43e99fdSEd Maste 	tt_int_op(r.result, ==, DNS_ERR_TIMEOUT);
996c43e99fdSEd Maste 	tt_int_op(r.count, ==, 0);
997c43e99fdSEd Maste 	tt_ptr_op(r.addrs, ==, NULL);
998c43e99fdSEd Maste 
999c43e99fdSEd Maste end:
1000c43e99fdSEd Maste 	if (dns)
1001c43e99fdSEd Maste 		evdns_base_free(dns, 0);
1002c43e99fdSEd Maste 	regress_clean_dnsserver();
1003c43e99fdSEd Maste 	if (inactive_base)
1004c43e99fdSEd Maste 		event_base_free(inactive_base);
1005c43e99fdSEd Maste }
1006c43e99fdSEd Maste 
1007*b50261e2SCy Schubert static void
dns_initialize_nameservers_test(void * arg)1008*b50261e2SCy Schubert dns_initialize_nameservers_test(void *arg)
1009*b50261e2SCy Schubert {
1010*b50261e2SCy Schubert 	struct basic_test_data *data = arg;
1011*b50261e2SCy Schubert 	struct event_base *base = data->base;
1012*b50261e2SCy Schubert 	struct evdns_base *dns = NULL;
1013*b50261e2SCy Schubert 
1014*b50261e2SCy Schubert 	dns = evdns_base_new(base, 0);
1015*b50261e2SCy Schubert 	tt_assert(dns);
1016*b50261e2SCy Schubert 	tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
1017*b50261e2SCy Schubert 	evdns_base_free(dns, 0);
1018*b50261e2SCy Schubert 
1019*b50261e2SCy Schubert 	dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS);
1020*b50261e2SCy Schubert 	tt_assert(dns);
1021*b50261e2SCy Schubert 	tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr));
1022*b50261e2SCy Schubert 
1023*b50261e2SCy Schubert end:
1024*b50261e2SCy Schubert 	if (dns)
1025*b50261e2SCy Schubert 		evdns_base_free(dns, 0);
1026*b50261e2SCy Schubert }
1027*b50261e2SCy Schubert #ifndef _WIN32
1028*b50261e2SCy Schubert #define RESOLV_FILE "empty-resolv.conf"
1029*b50261e2SCy Schubert static void
dns_nameservers_no_default_test(void * arg)1030*b50261e2SCy Schubert dns_nameservers_no_default_test(void *arg)
1031*b50261e2SCy Schubert {
1032*b50261e2SCy Schubert 	struct basic_test_data *data = arg;
1033*b50261e2SCy Schubert 	struct event_base *base = data->base;
1034*b50261e2SCy Schubert 	struct evdns_base *dns = NULL;
1035*b50261e2SCy Schubert 	int ok = access(RESOLV_FILE, R_OK);
1036*b50261e2SCy Schubert 
1037*b50261e2SCy Schubert 	tt_assert(ok);
1038*b50261e2SCy Schubert 
1039*b50261e2SCy Schubert 	dns = evdns_base_new(base, 0);
1040*b50261e2SCy Schubert 	tt_assert(dns);
1041*b50261e2SCy Schubert 	tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
1042*b50261e2SCy Schubert 
1043*b50261e2SCy Schubert 	/* We cannot test
1044*b50261e2SCy Schubert 	 * EVDNS_BASE_INITIALIZE_NAMESERVERS|EVDNS_BASE_NAMESERVERS_NO_DEFAULT
1045*b50261e2SCy Schubert 	 * because we cannot mock "/etc/resolv.conf" (yet). */
1046*b50261e2SCy Schubert 
1047*b50261e2SCy Schubert 	evdns_base_resolv_conf_parse(dns,
1048*b50261e2SCy Schubert 		DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT, RESOLV_FILE);
1049*b50261e2SCy Schubert 	tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1);
1050*b50261e2SCy Schubert 
1051*b50261e2SCy Schubert 	evdns_base_resolv_conf_parse(dns, DNS_OPTIONS_ALL, RESOLV_FILE);
1052*b50261e2SCy Schubert 	tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr));
1053*b50261e2SCy Schubert 
1054*b50261e2SCy Schubert end:
1055*b50261e2SCy Schubert 	if (dns)
1056*b50261e2SCy Schubert 		evdns_base_free(dns, 0);
1057*b50261e2SCy Schubert }
1058*b50261e2SCy Schubert #endif
1059*b50261e2SCy Schubert 
1060c43e99fdSEd Maste /* === Test for bufferevent_socket_connect_hostname */
1061c43e99fdSEd Maste 
1062c43e99fdSEd Maste static int total_connected_or_failed = 0;
1063c43e99fdSEd Maste static int total_n_accepted = 0;
1064c43e99fdSEd Maste static struct event_base *be_connect_hostname_base = NULL;
1065c43e99fdSEd Maste 
1066c43e99fdSEd Maste /* Implements a DNS server for the connect_hostname test and the
1067c43e99fdSEd Maste  * getaddrinfo_async test */
1068c43e99fdSEd Maste static void
be_getaddrinfo_server_cb(struct evdns_server_request * req,void * data)1069c43e99fdSEd Maste be_getaddrinfo_server_cb(struct evdns_server_request *req, void *data)
1070c43e99fdSEd Maste {
1071c43e99fdSEd Maste 	int i;
1072c43e99fdSEd Maste 	int *n_got_p=data;
1073c43e99fdSEd Maste 	int added_any=0;
1074c43e99fdSEd Maste 	++*n_got_p;
1075c43e99fdSEd Maste 
1076c43e99fdSEd Maste 	for (i = 0; i < req->nquestions; ++i) {
1077c43e99fdSEd Maste 		const int qtype = req->questions[i]->type;
1078c43e99fdSEd Maste 		const int qclass = req->questions[i]->dns_question_class;
1079c43e99fdSEd Maste 		const char *qname = req->questions[i]->name;
1080c43e99fdSEd Maste 		struct in_addr ans;
1081c43e99fdSEd Maste 		struct in6_addr ans6;
1082c43e99fdSEd Maste 		memset(&ans6, 0, sizeof(ans6));
1083c43e99fdSEd Maste 
1084c43e99fdSEd Maste 		TT_BLATHER(("Got question about %s, type=%d", qname, qtype));
1085c43e99fdSEd Maste 
1086c43e99fdSEd Maste 		if (qtype == EVDNS_TYPE_A &&
1087c43e99fdSEd Maste 		    qclass == EVDNS_CLASS_INET &&
1088c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "nobodaddy.example.com")) {
1089c43e99fdSEd Maste 			ans.s_addr = htonl(0x7f000001);
1090c43e99fdSEd Maste 			evdns_server_request_add_a_reply(req, qname,
1091c43e99fdSEd Maste 			    1, &ans.s_addr, 2000);
1092c43e99fdSEd Maste 			added_any = 1;
1093c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1094c43e99fdSEd Maste 			"nosuchplace.example.com")) {
1095c43e99fdSEd Maste 			/* ok, just say notfound. */
1096c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1097c43e99fdSEd Maste 			"both.example.com")) {
1098c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_A) {
1099c43e99fdSEd Maste 				ans.s_addr = htonl(0x50502020);
1100c43e99fdSEd Maste 				evdns_server_request_add_a_reply(req, qname,
1101c43e99fdSEd Maste 				    1, &ans.s_addr, 2000);
1102c43e99fdSEd Maste 				added_any = 1;
1103c43e99fdSEd Maste 			} else if (qtype == EVDNS_TYPE_AAAA) {
1104c43e99fdSEd Maste 				ans6.s6_addr[0] = 0x80;
1105c43e99fdSEd Maste 				ans6.s6_addr[1] = 0xff;
1106c43e99fdSEd Maste 				ans6.s6_addr[14] = 0xbb;
1107c43e99fdSEd Maste 				ans6.s6_addr[15] = 0xbb;
1108c43e99fdSEd Maste 				evdns_server_request_add_aaaa_reply(req, qname,
1109c43e99fdSEd Maste 				    1, &ans6.s6_addr, 2000);
1110c43e99fdSEd Maste 				added_any = 1;
1111c43e99fdSEd Maste 			}
1112c43e99fdSEd Maste 			evdns_server_request_add_cname_reply(req, qname,
1113c43e99fdSEd Maste 			    "both-canonical.example.com", 1000);
1114c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1115c43e99fdSEd Maste 			"v4only.example.com") ||
1116c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "v4assert.example.com")) {
1117c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_A) {
1118c43e99fdSEd Maste 				ans.s_addr = htonl(0x12345678);
1119c43e99fdSEd Maste 				evdns_server_request_add_a_reply(req, qname,
1120c43e99fdSEd Maste 				    1, &ans.s_addr, 2000);
1121c43e99fdSEd Maste 				added_any = 1;
1122c43e99fdSEd Maste 			} else if (!evutil_ascii_strcasecmp(qname,
1123c43e99fdSEd Maste 				"v4assert.example.com")) {
1124c43e99fdSEd Maste 				TT_FAIL(("Got an AAAA request for v4assert"));
1125c43e99fdSEd Maste 			}
1126c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1127c43e99fdSEd Maste 			"v6only.example.com") ||
1128c43e99fdSEd Maste 		    !evutil_ascii_strcasecmp(qname, "v6assert.example.com")) {
1129c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_AAAA) {
1130c43e99fdSEd Maste 				ans6.s6_addr[0] = 0x0b;
1131c43e99fdSEd Maste 				ans6.s6_addr[1] = 0x0b;
1132c43e99fdSEd Maste 				ans6.s6_addr[14] = 0xf0;
1133c43e99fdSEd Maste 				ans6.s6_addr[15] = 0x0d;
1134c43e99fdSEd Maste 				evdns_server_request_add_aaaa_reply(req, qname,
1135c43e99fdSEd Maste 				    1, &ans6.s6_addr, 2000);
1136c43e99fdSEd Maste 				added_any = 1;
1137c43e99fdSEd Maste 			}  else if (!evutil_ascii_strcasecmp(qname,
1138c43e99fdSEd Maste 				"v6assert.example.com")) {
1139c43e99fdSEd Maste 				TT_FAIL(("Got a A request for v6assert"));
1140c43e99fdSEd Maste 			}
1141c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1142c43e99fdSEd Maste 			"v6timeout.example.com")) {
1143c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_A) {
1144c43e99fdSEd Maste 				ans.s_addr = htonl(0xabcdef01);
1145c43e99fdSEd Maste 				evdns_server_request_add_a_reply(req, qname,
1146c43e99fdSEd Maste 				    1, &ans.s_addr, 2000);
1147c43e99fdSEd Maste 				added_any = 1;
1148c43e99fdSEd Maste 			} else if (qtype == EVDNS_TYPE_AAAA) {
1149c43e99fdSEd Maste 				/* Let the v6 request time out.*/
1150c43e99fdSEd Maste 				evdns_server_request_drop(req);
1151c43e99fdSEd Maste 				return;
1152c43e99fdSEd Maste 			}
1153c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1154c43e99fdSEd Maste 			"v4timeout.example.com")) {
1155c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_AAAA) {
1156c43e99fdSEd Maste 				ans6.s6_addr[0] = 0x0a;
1157c43e99fdSEd Maste 				ans6.s6_addr[1] = 0x0a;
1158c43e99fdSEd Maste 				ans6.s6_addr[14] = 0xff;
1159c43e99fdSEd Maste 				ans6.s6_addr[15] = 0x01;
1160c43e99fdSEd Maste 				evdns_server_request_add_aaaa_reply(req, qname,
1161c43e99fdSEd Maste 				    1, &ans6.s6_addr, 2000);
1162c43e99fdSEd Maste 				added_any = 1;
1163c43e99fdSEd Maste 			} else if (qtype == EVDNS_TYPE_A) {
1164c43e99fdSEd Maste 				/* Let the v4 request time out.*/
1165c43e99fdSEd Maste 				evdns_server_request_drop(req);
1166c43e99fdSEd Maste 				return;
1167c43e99fdSEd Maste 			}
1168c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1169c43e99fdSEd Maste 			"v6timeout-nonexist.example.com")) {
1170c43e99fdSEd Maste 			if (qtype == EVDNS_TYPE_A) {
1171c43e99fdSEd Maste 				/* Fall through, give an nexist. */
1172c43e99fdSEd Maste 			} else if (qtype == EVDNS_TYPE_AAAA) {
1173c43e99fdSEd Maste 				/* Let the v6 request time out.*/
1174c43e99fdSEd Maste 				evdns_server_request_drop(req);
1175c43e99fdSEd Maste 				return;
1176c43e99fdSEd Maste 			}
1177c43e99fdSEd Maste 		} else if (!evutil_ascii_strcasecmp(qname,
1178c43e99fdSEd Maste 			"all-timeout.example.com")) {
1179c43e99fdSEd Maste 			/* drop all requests */
1180c43e99fdSEd Maste 			evdns_server_request_drop(req);
1181c43e99fdSEd Maste 			return;
1182c43e99fdSEd Maste 		} else {
1183c43e99fdSEd Maste 			TT_GRIPE(("Got weird request for %s",qname));
1184c43e99fdSEd Maste 		}
1185c43e99fdSEd Maste 	}
1186c43e99fdSEd Maste 	if (added_any) {
1187c43e99fdSEd Maste 		TT_BLATHER(("answering"));
1188c43e99fdSEd Maste 		evdns_server_request_respond(req, 0);
1189c43e99fdSEd Maste 	} else {
1190c43e99fdSEd Maste 		TT_BLATHER(("saying nexist."));
1191c43e99fdSEd Maste 		evdns_server_request_respond(req, 3);
1192c43e99fdSEd Maste 	}
1193c43e99fdSEd Maste }
1194c43e99fdSEd Maste 
1195c43e99fdSEd Maste /* Implements a listener for connect_hostname test. */
1196c43e99fdSEd Maste static void
nil_accept_cb(struct evconnlistener * l,evutil_socket_t fd,struct sockaddr * s,int socklen,void * arg)1197c43e99fdSEd Maste nil_accept_cb(struct evconnlistener *l, evutil_socket_t fd, struct sockaddr *s,
1198c43e99fdSEd Maste     int socklen, void *arg)
1199c43e99fdSEd Maste {
1200c43e99fdSEd Maste 	int *p = arg;
1201c43e99fdSEd Maste 	(*p)++;
1202c43e99fdSEd Maste 	++total_n_accepted;
1203c43e99fdSEd Maste 	/* don't do anything with the socket; let it close when we exit() */
1204c43e99fdSEd Maste 	if (total_n_accepted >= 3 && total_connected_or_failed >= 5)
1205c43e99fdSEd Maste 		event_base_loopexit(be_connect_hostname_base,
1206c43e99fdSEd Maste 		    NULL);
1207c43e99fdSEd Maste }
1208c43e99fdSEd Maste 
1209c43e99fdSEd Maste struct be_conn_hostname_result {
1210c43e99fdSEd Maste 	int dnserr;
1211c43e99fdSEd Maste 	int what;
1212c43e99fdSEd Maste };
1213c43e99fdSEd Maste 
1214c43e99fdSEd Maste /* Bufferevent event callback for the connect_hostname test: remembers what
1215c43e99fdSEd Maste  * event we got. */
1216c43e99fdSEd Maste static void
be_connect_hostname_event_cb(struct bufferevent * bev,short what,void * ctx)1217c43e99fdSEd Maste be_connect_hostname_event_cb(struct bufferevent *bev, short what, void *ctx)
1218c43e99fdSEd Maste {
1219c43e99fdSEd Maste 	struct be_conn_hostname_result *got = ctx;
1220*b50261e2SCy Schubert 
1221*b50261e2SCy Schubert 	if (got->what) {
1222*b50261e2SCy Schubert 		TT_FAIL(("Two events on one bufferevent. %d,%d",
1223*b50261e2SCy Schubert 			got->what, (int)what));
1224*b50261e2SCy Schubert 	}
1225*b50261e2SCy Schubert 
1226c43e99fdSEd Maste 	TT_BLATHER(("Got a bufferevent event %d", what));
1227c43e99fdSEd Maste 	got->what = what;
1228c43e99fdSEd Maste 
1229c43e99fdSEd Maste 	if ((what & BEV_EVENT_CONNECTED) || (what & BEV_EVENT_ERROR)) {
1230*b50261e2SCy Schubert 		int expected = 3;
1231*b50261e2SCy Schubert 		int r = bufferevent_socket_get_dns_error(bev);
1232*b50261e2SCy Schubert 
1233*b50261e2SCy Schubert 		if (r) {
1234c43e99fdSEd Maste 			got->dnserr = r;
1235c43e99fdSEd Maste 			TT_BLATHER(("DNS error %d: %s", r,
1236c43e99fdSEd Maste 				   evutil_gai_strerror(r)));
1237*b50261e2SCy Schubert 		}
1238*b50261e2SCy Schubert 		++total_connected_or_failed;
1239c43e99fdSEd Maste 		TT_BLATHER(("Got %d connections or errors.", total_connected_or_failed));
1240c43e99fdSEd Maste 
1241*b50261e2SCy Schubert 		/** emfile test */
1242*b50261e2SCy Schubert 		if (errno == EMFILE) {
1243*b50261e2SCy Schubert 			expected = 0;
1244*b50261e2SCy Schubert 		}
1245*b50261e2SCy Schubert 
1246*b50261e2SCy Schubert 		if (total_n_accepted >= expected && total_connected_or_failed >= 5)
1247c43e99fdSEd Maste 			event_base_loopexit(be_connect_hostname_base,
1248c43e99fdSEd Maste 			    NULL);
1249c43e99fdSEd Maste 	}
1250c43e99fdSEd Maste }
1251c43e99fdSEd Maste 
1252c43e99fdSEd Maste static void
test_bufferevent_connect_hostname(void * arg)1253c43e99fdSEd Maste test_bufferevent_connect_hostname(void *arg)
1254c43e99fdSEd Maste {
1255c43e99fdSEd Maste 	struct basic_test_data *data = arg;
1256c43e99fdSEd Maste 	struct evconnlistener *listener = NULL;
1257*b50261e2SCy Schubert 	struct bufferevent *be[5];
1258*b50261e2SCy Schubert 	struct be_conn_hostname_result be_outcome[ARRAY_SIZE(be)];
1259*b50261e2SCy Schubert 	int expect_err;
1260c43e99fdSEd Maste 	struct evdns_base *dns=NULL;
1261c43e99fdSEd Maste 	struct evdns_server_port *port=NULL;
1262c43e99fdSEd Maste 	struct sockaddr_in sin;
1263c43e99fdSEd Maste 	int listener_port=-1;
1264c43e99fdSEd Maste 	ev_uint16_t dns_port=0;
1265c43e99fdSEd Maste 	int n_accept=0, n_dns=0;
1266c43e99fdSEd Maste 	char buf[128];
1267*b50261e2SCy Schubert 	int emfile = data->setup_data && !strcmp(data->setup_data, "emfile");
1268*b50261e2SCy Schubert 	unsigned i;
1269*b50261e2SCy Schubert 	int ret;
1270c43e99fdSEd Maste 
1271c43e99fdSEd Maste 	be_connect_hostname_base = data->base;
1272c43e99fdSEd Maste 
1273c43e99fdSEd Maste 	/* Bind an address and figure out what port it's on. */
1274c43e99fdSEd Maste 	memset(&sin, 0, sizeof(sin));
1275c43e99fdSEd Maste 	sin.sin_family = AF_INET;
1276c43e99fdSEd Maste 	sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */
1277c43e99fdSEd Maste 	sin.sin_port = 0;
1278c43e99fdSEd Maste 	listener = evconnlistener_new_bind(data->base, nil_accept_cb,
1279c43e99fdSEd Maste 	    &n_accept,
1280c43e99fdSEd Maste 	    LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,
1281c43e99fdSEd Maste 	    -1, (struct sockaddr *)&sin, sizeof(sin));
1282c43e99fdSEd Maste 	tt_assert(listener);
1283c43e99fdSEd Maste 	listener_port = regress_get_socket_port(
1284c43e99fdSEd Maste 		evconnlistener_get_fd(listener));
1285c43e99fdSEd Maste 
1286c43e99fdSEd Maste 	port = regress_get_dnsserver(data->base, &dns_port, NULL,
1287c43e99fdSEd Maste 	    be_getaddrinfo_server_cb, &n_dns);
1288c43e99fdSEd Maste 	tt_assert(port);
1289c43e99fdSEd Maste 	tt_int_op(dns_port, >=, 0);
1290c43e99fdSEd Maste 
1291c43e99fdSEd Maste 	/* Start an evdns_base that uses the server as its resolver. */
1292c43e99fdSEd Maste 	dns = evdns_base_new(data->base, 0);
1293c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)dns_port);
1294c43e99fdSEd Maste 	evdns_base_nameserver_ip_add(dns, buf);
1295c43e99fdSEd Maste 
1296*b50261e2SCy Schubert #ifdef EVENT__HAVE_SETRLIMIT
1297*b50261e2SCy Schubert 	if (emfile) {
1298*b50261e2SCy Schubert 		int fd = socket(AF_INET, SOCK_STREAM, 0);
1299*b50261e2SCy Schubert 		struct rlimit file = { fd, fd };
1300*b50261e2SCy Schubert 
1301*b50261e2SCy Schubert 		tt_int_op(fd, >=, 0);
1302*b50261e2SCy Schubert 		tt_assert(!close(fd));
1303*b50261e2SCy Schubert 
1304*b50261e2SCy Schubert 		tt_assert(!setrlimit(RLIMIT_NOFILE, &file));
1305*b50261e2SCy Schubert 	}
1306*b50261e2SCy Schubert #endif
1307*b50261e2SCy Schubert 
1308c43e99fdSEd Maste 	/* Now, finally, at long last, launch the bufferevents.	 One should do
1309c43e99fdSEd Maste 	 * a failing lookup IP, one should do a successful lookup by IP,
1310c43e99fdSEd Maste 	 * and one should do a successful lookup by hostname. */
1311*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(be); ++i) {
1312*b50261e2SCy Schubert 		memset(&be_outcome[i], 0, sizeof(be_outcome[i]));
1313*b50261e2SCy Schubert 		be[i] = bufferevent_socket_new(data->base, -1, BEV_OPT_CLOSE_ON_FREE);
1314*b50261e2SCy Schubert 		bufferevent_setcb(be[i], NULL, NULL, be_connect_hostname_event_cb,
1315*b50261e2SCy Schubert 			&be_outcome[i]);
1316*b50261e2SCy Schubert 	}
1317c43e99fdSEd Maste 
1318c43e99fdSEd Maste 	/* Use the blocking resolver.  This one will fail if your resolver
1319c43e99fdSEd Maste 	 * can't resolve localhost to 127.0.0.1 */
1320*b50261e2SCy Schubert 	tt_assert(!bufferevent_socket_connect_hostname(be[3], NULL, AF_INET,
1321c43e99fdSEd Maste 		"localhost", listener_port));
1322c43e99fdSEd Maste 	/* Use the blocking resolver with a nonexistent hostname. */
1323*b50261e2SCy Schubert 	tt_assert(!bufferevent_socket_connect_hostname(be[4], NULL, AF_INET,
1324c43e99fdSEd Maste 		"nonesuch.nowhere.example.com", 80));
1325c43e99fdSEd Maste 	{
1326c43e99fdSEd Maste 		/* The blocking resolver will use the system nameserver, which
1327c43e99fdSEd Maste 		 * might tell us anything.  (Yes, some twits even pretend that
1328c43e99fdSEd Maste 		 * example.com is real.) Let's see what answer to expect. */
1329c43e99fdSEd Maste 		struct evutil_addrinfo hints, *ai = NULL;
1330c43e99fdSEd Maste 		memset(&hints, 0, sizeof(hints));
1331c43e99fdSEd Maste 		hints.ai_family = AF_INET;
1332c43e99fdSEd Maste 		hints.ai_socktype = SOCK_STREAM;
1333c43e99fdSEd Maste 		hints.ai_protocol = IPPROTO_TCP;
1334*b50261e2SCy Schubert 		expect_err = evutil_getaddrinfo(
1335c43e99fdSEd Maste 			"nonesuch.nowhere.example.com", "80", &hints, &ai);
1336c43e99fdSEd Maste 	}
1337c43e99fdSEd Maste 	/* Launch an async resolve that will fail. */
1338*b50261e2SCy Schubert 	tt_assert(!bufferevent_socket_connect_hostname(be[0], dns, AF_INET,
1339c43e99fdSEd Maste 		"nosuchplace.example.com", listener_port));
1340c43e99fdSEd Maste 	/* Connect to the IP without resolving. */
1341*b50261e2SCy Schubert 	tt_assert(!bufferevent_socket_connect_hostname(be[1], dns, AF_INET,
1342c43e99fdSEd Maste 		"127.0.0.1", listener_port));
1343c43e99fdSEd Maste 	/* Launch an async resolve that will succeed. */
1344*b50261e2SCy Schubert 	tt_assert(!bufferevent_socket_connect_hostname(be[2], dns, AF_INET,
1345c43e99fdSEd Maste 		"nobodaddy.example.com", listener_port));
1346c43e99fdSEd Maste 
1347*b50261e2SCy Schubert 	ret = event_base_dispatch(data->base);
1348*b50261e2SCy Schubert #ifdef __sun__
1349*b50261e2SCy Schubert 	if (emfile && !strcmp(event_base_get_method(data->base), "devpoll")) {
1350*b50261e2SCy Schubert 		tt_int_op(ret, ==, -1);
1351*b50261e2SCy Schubert 		/** DP_POLL failed */
1352*b50261e2SCy Schubert 		tt_skip();
1353*b50261e2SCy Schubert 	} else
1354*b50261e2SCy Schubert #endif
1355*b50261e2SCy Schubert 	{
1356*b50261e2SCy Schubert 		tt_int_op(ret, ==, 0);
1357c43e99fdSEd Maste 	}
1358c43e99fdSEd Maste 
1359*b50261e2SCy Schubert 	tt_int_op(be_outcome[0].what, ==, BEV_EVENT_ERROR);
1360*b50261e2SCy Schubert 	tt_int_op(be_outcome[0].dnserr, ==, EVUTIL_EAI_NONAME);
1361*b50261e2SCy Schubert 	tt_int_op(be_outcome[1].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
1362*b50261e2SCy Schubert 	tt_int_op(be_outcome[1].dnserr, ==, 0);
1363*b50261e2SCy Schubert 	tt_int_op(be_outcome[2].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
1364*b50261e2SCy Schubert 	tt_int_op(be_outcome[2].dnserr, ==, 0);
1365*b50261e2SCy Schubert 	tt_int_op(be_outcome[3].what, ==, !emfile ? BEV_EVENT_CONNECTED : BEV_EVENT_ERROR);
1366*b50261e2SCy Schubert 	if (!emfile) {
1367*b50261e2SCy Schubert 		tt_int_op(be_outcome[3].dnserr, ==, 0);
1368*b50261e2SCy Schubert 	} else {
1369*b50261e2SCy Schubert 		tt_int_op(be_outcome[3].dnserr, !=, 0);
1370*b50261e2SCy Schubert 	}
1371*b50261e2SCy Schubert 	if (expect_err) {
1372*b50261e2SCy Schubert 		tt_int_op(be_outcome[4].what, ==, BEV_EVENT_ERROR);
1373*b50261e2SCy Schubert 		tt_int_op(be_outcome[4].dnserr, ==, expect_err);
1374*b50261e2SCy Schubert 	}
1375*b50261e2SCy Schubert 
1376*b50261e2SCy Schubert 	if (emfile) {
1377*b50261e2SCy Schubert 		tt_int_op(n_accept, ==, 0);
1378*b50261e2SCy Schubert 	} else {
1379c43e99fdSEd Maste 		tt_int_op(n_accept, ==, 3);
1380*b50261e2SCy Schubert 	}
1381c43e99fdSEd Maste 	tt_int_op(n_dns, ==, 2);
1382c43e99fdSEd Maste 
1383c43e99fdSEd Maste end:
1384c43e99fdSEd Maste 	if (listener)
1385c43e99fdSEd Maste 		evconnlistener_free(listener);
1386c43e99fdSEd Maste 	if (port)
1387c43e99fdSEd Maste 		evdns_close_server_port(port);
1388c43e99fdSEd Maste 	if (dns)
1389c43e99fdSEd Maste 		evdns_base_free(dns, 0);
1390*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(be); ++i) {
1391*b50261e2SCy Schubert 		if (be[i])
1392*b50261e2SCy Schubert 			bufferevent_free(be[i]);
1393*b50261e2SCy Schubert 	}
1394c43e99fdSEd Maste }
1395c43e99fdSEd Maste 
1396c43e99fdSEd Maste 
1397c43e99fdSEd Maste struct gai_outcome {
1398c43e99fdSEd Maste 	int err;
1399c43e99fdSEd Maste 	struct evutil_addrinfo *ai;
1400c43e99fdSEd Maste };
1401c43e99fdSEd Maste 
1402c43e99fdSEd Maste static int n_gai_results_pending = 0;
1403c43e99fdSEd Maste static struct event_base *exit_base_on_no_pending_results = NULL;
1404c43e99fdSEd Maste 
1405c43e99fdSEd Maste static void
gai_cb(int err,struct evutil_addrinfo * res,void * ptr)1406c43e99fdSEd Maste gai_cb(int err, struct evutil_addrinfo *res, void *ptr)
1407c43e99fdSEd Maste {
1408c43e99fdSEd Maste 	struct gai_outcome *go = ptr;
1409c43e99fdSEd Maste 	go->err = err;
1410c43e99fdSEd Maste 	go->ai = res;
1411c43e99fdSEd Maste 	if (--n_gai_results_pending <= 0 && exit_base_on_no_pending_results)
1412c43e99fdSEd Maste 		event_base_loopexit(exit_base_on_no_pending_results, NULL);
1413c43e99fdSEd Maste 	if (n_gai_results_pending < 900)
1414c43e99fdSEd Maste 		TT_BLATHER(("Got an answer; expecting %d more.",
1415c43e99fdSEd Maste 			n_gai_results_pending));
1416c43e99fdSEd Maste }
1417c43e99fdSEd Maste 
1418c43e99fdSEd Maste static void
cancel_gai_cb(evutil_socket_t fd,short what,void * ptr)1419c43e99fdSEd Maste cancel_gai_cb(evutil_socket_t fd, short what, void *ptr)
1420c43e99fdSEd Maste {
1421c43e99fdSEd Maste 	struct evdns_getaddrinfo_request *r = ptr;
1422c43e99fdSEd Maste 	evdns_getaddrinfo_cancel(r);
1423c43e99fdSEd Maste }
1424c43e99fdSEd Maste 
1425c43e99fdSEd Maste static void
test_getaddrinfo_async(void * arg)1426c43e99fdSEd Maste test_getaddrinfo_async(void *arg)
1427c43e99fdSEd Maste {
1428c43e99fdSEd Maste 	struct basic_test_data *data = arg;
1429c43e99fdSEd Maste 	struct evutil_addrinfo hints, *a;
1430c43e99fdSEd Maste 	struct gai_outcome local_outcome;
1431c43e99fdSEd Maste 	struct gai_outcome a_out[12];
1432*b50261e2SCy Schubert 	unsigned i;
1433c43e99fdSEd Maste 	struct evdns_getaddrinfo_request *r;
1434c43e99fdSEd Maste 	char buf[128];
1435c43e99fdSEd Maste 	struct evdns_server_port *port = NULL;
1436c43e99fdSEd Maste 	ev_uint16_t dns_port = 0;
1437c43e99fdSEd Maste 	int n_dns_questions = 0;
1438c43e99fdSEd Maste 	struct evdns_base *dns_base;
1439c43e99fdSEd Maste 
1440c43e99fdSEd Maste 	memset(a_out, 0, sizeof(a_out));
1441c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1442c43e99fdSEd Maste 
1443c43e99fdSEd Maste 	dns_base = evdns_base_new(data->base, 0);
1444c43e99fdSEd Maste 	tt_assert(dns_base);
1445c43e99fdSEd Maste 
1446c43e99fdSEd Maste 	/* for localhost */
1447c43e99fdSEd Maste 	evdns_base_load_hosts(dns_base, NULL);
1448c43e99fdSEd Maste 
1449c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns_base, "timeout", "0.3"));
1450c43e99fdSEd Maste 	tt_assert(! evdns_base_set_option(dns_base, "getaddrinfo-allow-skew", "0.2"));
1451c43e99fdSEd Maste 
1452c43e99fdSEd Maste 	n_gai_results_pending = 10000; /* don't think about exiting yet. */
1453c43e99fdSEd Maste 
1454c43e99fdSEd Maste 	/* 1. Try some cases that will never hit the asynchronous resolver. */
1455c43e99fdSEd Maste 	/* 1a. Simple case with a symbolic service name */
1456c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1457c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1458c43e99fdSEd Maste 	hints.ai_socktype = SOCK_STREAM;
1459c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1460c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "1.2.3.4", "http",
1461c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1462c43e99fdSEd Maste 	tt_assert(! r);
1463c43e99fdSEd Maste 	if (!local_outcome.err) {
1464c43e99fdSEd Maste 		tt_ptr_op(local_outcome.ai,!=,NULL);
1465c43e99fdSEd Maste 		test_ai_eq(local_outcome.ai, "1.2.3.4:80", SOCK_STREAM, IPPROTO_TCP);
1466c43e99fdSEd Maste 		evutil_freeaddrinfo(local_outcome.ai);
1467c43e99fdSEd Maste 		local_outcome.ai = NULL;
1468c43e99fdSEd Maste 	} else {
1469c43e99fdSEd Maste 		TT_BLATHER(("Apparently we have no getservbyname."));
1470c43e99fdSEd Maste 	}
1471c43e99fdSEd Maste 
1472c43e99fdSEd Maste 	/* 1b. EVUTIL_AI_NUMERICHOST is set */
1473c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1474c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1475c43e99fdSEd Maste 	hints.ai_flags = EVUTIL_AI_NUMERICHOST;
1476c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1477c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "www.google.com", "80",
1478c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1479c43e99fdSEd Maste 	tt_ptr_op(r,==,NULL);
1480c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,EVUTIL_EAI_NONAME);
1481c43e99fdSEd Maste 	tt_ptr_op(local_outcome.ai,==,NULL);
1482c43e99fdSEd Maste 
1483c43e99fdSEd Maste 	/* 1c. We give a numeric address (ipv6) */
1484c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1485c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1486c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1487c43e99fdSEd Maste 	hints.ai_protocol = IPPROTO_TCP;
1488c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "f::f", "8008",
1489c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1490c43e99fdSEd Maste 	tt_assert(!r);
1491c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1492c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1493c43e99fdSEd Maste 	tt_ptr_op(local_outcome.ai->ai_next,==,NULL);
1494c43e99fdSEd Maste 	test_ai_eq(local_outcome.ai, "[f::f]:8008", SOCK_STREAM, IPPROTO_TCP);
1495c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1496c43e99fdSEd Maste 	local_outcome.ai = NULL;
1497c43e99fdSEd Maste 
1498c43e99fdSEd Maste 	/* 1d. We give a numeric address (ipv4) */
1499c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1500c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1501c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1502c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "5.6.7.8", NULL,
1503c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1504c43e99fdSEd Maste 	tt_assert(!r);
1505c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1506c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1507c43e99fdSEd Maste 	a = ai_find_by_protocol(local_outcome.ai, IPPROTO_TCP);
1508c43e99fdSEd Maste 	tt_assert(a);
1509c43e99fdSEd Maste 	test_ai_eq(a, "5.6.7.8", SOCK_STREAM, IPPROTO_TCP);
1510c43e99fdSEd Maste 	a = ai_find_by_protocol(local_outcome.ai, IPPROTO_UDP);
1511c43e99fdSEd Maste 	tt_assert(a);
1512c43e99fdSEd Maste 	test_ai_eq(a, "5.6.7.8", SOCK_DGRAM, IPPROTO_UDP);
1513c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1514c43e99fdSEd Maste 	local_outcome.ai = NULL;
1515c43e99fdSEd Maste 
1516c43e99fdSEd Maste 	/* 1e. nodename is NULL (bind) */
1517c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1518c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1519c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1520c43e99fdSEd Maste 	hints.ai_socktype = SOCK_DGRAM;
1521c43e99fdSEd Maste 	hints.ai_flags = EVUTIL_AI_PASSIVE;
1522c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, NULL, "9090",
1523c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1524c43e99fdSEd Maste 	tt_assert(!r);
1525c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1526c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1527c43e99fdSEd Maste 	/* we should get a v4 address of 0.0.0.0... */
1528c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET);
1529c43e99fdSEd Maste 	tt_assert(a);
1530c43e99fdSEd Maste 	test_ai_eq(a, "0.0.0.0:9090", SOCK_DGRAM, IPPROTO_UDP);
1531c43e99fdSEd Maste 	/* ... and a v6 address of ::0 */
1532c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
1533c43e99fdSEd Maste 	tt_assert(a);
1534c43e99fdSEd Maste 	test_ai_eq(a, "[::]:9090", SOCK_DGRAM, IPPROTO_UDP);
1535c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1536c43e99fdSEd Maste 	local_outcome.ai = NULL;
1537c43e99fdSEd Maste 
1538c43e99fdSEd Maste 	/* 1f. nodename is NULL (connect) */
1539c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1540c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1541c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1542c43e99fdSEd Maste 	hints.ai_socktype = SOCK_STREAM;
1543c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, NULL, "2",
1544c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1545c43e99fdSEd Maste 	tt_assert(!r);
1546c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1547c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1548c43e99fdSEd Maste 	/* we should get a v4 address of 127.0.0.1 .... */
1549c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET);
1550c43e99fdSEd Maste 	tt_assert(a);
1551c43e99fdSEd Maste 	test_ai_eq(a, "127.0.0.1:2", SOCK_STREAM, IPPROTO_TCP);
1552c43e99fdSEd Maste 	/* ... and a v6 address of ::1 */
1553c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
1554c43e99fdSEd Maste 	tt_assert(a);
1555c43e99fdSEd Maste 	test_ai_eq(a, "[::1]:2", SOCK_STREAM, IPPROTO_TCP);
1556c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1557c43e99fdSEd Maste 	local_outcome.ai = NULL;
1558c43e99fdSEd Maste 
1559c43e99fdSEd Maste 	/* 1g. We find localhost immediately. (pf_unspec) */
1560c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1561c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1562c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1563c43e99fdSEd Maste 	hints.ai_socktype = SOCK_STREAM;
1564c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "LOCALHOST", "80",
1565c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1566c43e99fdSEd Maste 	tt_assert(!r);
1567c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1568c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1569c43e99fdSEd Maste 	/* we should get a v4 address of 127.0.0.1 .... */
1570c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET);
1571c43e99fdSEd Maste 	tt_assert(a);
1572c43e99fdSEd Maste 	test_ai_eq(a, "127.0.0.1:80", SOCK_STREAM, IPPROTO_TCP);
1573c43e99fdSEd Maste 	/* ... and a v6 address of ::1 */
1574c43e99fdSEd Maste 	a = ai_find_by_family(local_outcome.ai, PF_INET6);
1575c43e99fdSEd Maste 	tt_assert(a);
1576c43e99fdSEd Maste 	test_ai_eq(a, "[::1]:80", SOCK_STREAM, IPPROTO_TCP);
1577c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1578c43e99fdSEd Maste 	local_outcome.ai = NULL;
1579c43e99fdSEd Maste 
1580c43e99fdSEd Maste 	/* 1g. We find localhost immediately. (pf_inet6) */
1581c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1582c43e99fdSEd Maste 	memset(&local_outcome, 0, sizeof(local_outcome));
1583c43e99fdSEd Maste 	hints.ai_family = PF_INET6;
1584c43e99fdSEd Maste 	hints.ai_socktype = SOCK_STREAM;
1585c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "LOCALHOST", "9999",
1586c43e99fdSEd Maste 	    &hints, gai_cb, &local_outcome);
1587c43e99fdSEd Maste 	tt_assert(! r);
1588c43e99fdSEd Maste 	tt_int_op(local_outcome.err,==,0);
1589c43e99fdSEd Maste 	tt_assert(local_outcome.ai);
1590c43e99fdSEd Maste 	a = local_outcome.ai;
1591c43e99fdSEd Maste 	test_ai_eq(a, "[::1]:9999", SOCK_STREAM, IPPROTO_TCP);
1592c43e99fdSEd Maste 	tt_ptr_op(a->ai_next, ==, NULL);
1593c43e99fdSEd Maste 	evutil_freeaddrinfo(local_outcome.ai);
1594c43e99fdSEd Maste 	local_outcome.ai = NULL;
1595c43e99fdSEd Maste 
1596c43e99fdSEd Maste 	/* 2. Okay, now we can actually test the asynchronous resolver. */
1597c43e99fdSEd Maste 	/* Start a dummy local dns server... */
1598c43e99fdSEd Maste 	port = regress_get_dnsserver(data->base, &dns_port, NULL,
1599c43e99fdSEd Maste 	    be_getaddrinfo_server_cb, &n_dns_questions);
1600c43e99fdSEd Maste 	tt_assert(port);
1601c43e99fdSEd Maste 	tt_int_op(dns_port, >=, 0);
1602c43e99fdSEd Maste 	/* ... and tell the evdns_base about it. */
1603c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", dns_port);
1604c43e99fdSEd Maste 	evdns_base_nameserver_ip_add(dns_base, buf);
1605c43e99fdSEd Maste 
1606c43e99fdSEd Maste 	memset(&hints, 0, sizeof(hints));
1607c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1608c43e99fdSEd Maste 	hints.ai_socktype = SOCK_STREAM;
1609c43e99fdSEd Maste 	hints.ai_flags = EVUTIL_AI_CANONNAME;
1610c43e99fdSEd Maste 	/* 0: Request for both.example.com should return both addresses. */
1611c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "both.example.com", "8000",
1612c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[0]);
1613c43e99fdSEd Maste 	tt_assert(r);
1614c43e99fdSEd Maste 
1615c43e99fdSEd Maste 	/* 1: Request for v4only.example.com should return one address. */
1616c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v4only.example.com", "8001",
1617c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[1]);
1618c43e99fdSEd Maste 	tt_assert(r);
1619c43e99fdSEd Maste 
1620c43e99fdSEd Maste 	/* 2: Request for v6only.example.com should return one address. */
1621c43e99fdSEd Maste 	hints.ai_flags = 0;
1622c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v6only.example.com", "8002",
1623c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[2]);
1624c43e99fdSEd Maste 	tt_assert(r);
1625c43e99fdSEd Maste 
1626c43e99fdSEd Maste 	/* 3: PF_INET request for v4assert.example.com should not generate a
1627c43e99fdSEd Maste 	 * v6 request.	The server will fail the test if it does. */
1628c43e99fdSEd Maste 	hints.ai_family = PF_INET;
1629c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v4assert.example.com", "8003",
1630c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[3]);
1631c43e99fdSEd Maste 	tt_assert(r);
1632c43e99fdSEd Maste 
1633c43e99fdSEd Maste 	/* 4: PF_INET6 request for v6assert.example.com should not generate a
1634c43e99fdSEd Maste 	 * v4 request.	The server will fail the test if it does. */
1635c43e99fdSEd Maste 	hints.ai_family = PF_INET6;
1636c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v6assert.example.com", "8004",
1637c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[4]);
1638c43e99fdSEd Maste 	tt_assert(r);
1639c43e99fdSEd Maste 
1640c43e99fdSEd Maste 	/* 5: PF_INET request for nosuchplace.example.com should give NEXIST. */
1641c43e99fdSEd Maste 	hints.ai_family = PF_INET;
1642c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8005",
1643c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[5]);
1644c43e99fdSEd Maste 	tt_assert(r);
1645c43e99fdSEd Maste 
1646c43e99fdSEd Maste 	/* 6: PF_UNSPEC request for nosuchplace.example.com should give NEXIST.
1647c43e99fdSEd Maste 	 */
1648c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1649c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "nosuchplace.example.com", "8006",
1650c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[6]);
1651c43e99fdSEd Maste 	tt_assert(r);
1652c43e99fdSEd Maste 
1653c43e99fdSEd Maste 	/* 7: PF_UNSPEC request for v6timeout.example.com should give an ipv4
1654c43e99fdSEd Maste 	 * address only. */
1655c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1656c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v6timeout.example.com", "8007",
1657c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[7]);
1658c43e99fdSEd Maste 	tt_assert(r);
1659c43e99fdSEd Maste 
1660c43e99fdSEd Maste 	/* 8: PF_UNSPEC request for v6timeout-nonexist.example.com should give
1661c43e99fdSEd Maste 	 * a NEXIST */
1662c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1663c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v6timeout-nonexist.example.com",
1664c43e99fdSEd Maste 	    "8008", &hints, gai_cb, &a_out[8]);
1665c43e99fdSEd Maste 	tt_assert(r);
1666c43e99fdSEd Maste 
1667c43e99fdSEd Maste 	/* 9: AI_ADDRCONFIG should at least not crash.	Can't test it more
1668c43e99fdSEd Maste 	 * without knowing what kind of internet we have. */
1669c43e99fdSEd Maste 	hints.ai_flags |= EVUTIL_AI_ADDRCONFIG;
1670c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "both.example.com",
1671c43e99fdSEd Maste 	    "8009", &hints, gai_cb, &a_out[9]);
1672c43e99fdSEd Maste 	tt_assert(r);
1673c43e99fdSEd Maste 
1674c43e99fdSEd Maste 	/* 10: PF_UNSPEC for v4timeout.example.com should give an ipv6 address
1675c43e99fdSEd Maste 	 * only. */
1676c43e99fdSEd Maste 	hints.ai_family = PF_UNSPEC;
1677c43e99fdSEd Maste 	hints.ai_flags = 0;
1678c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "v4timeout.example.com", "8010",
1679c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[10]);
1680c43e99fdSEd Maste 	tt_assert(r);
1681c43e99fdSEd Maste 
1682c43e99fdSEd Maste 	/* 11: timeout.example.com: cancel it after 100 msec. */
1683c43e99fdSEd Maste 	r = evdns_getaddrinfo(dns_base, "all-timeout.example.com", "8011",
1684c43e99fdSEd Maste 	    &hints, gai_cb, &a_out[11]);
1685c43e99fdSEd Maste 	tt_assert(r);
1686c43e99fdSEd Maste 	{
1687c43e99fdSEd Maste 		struct timeval tv;
1688c43e99fdSEd Maste 		tv.tv_sec = 0;
1689c43e99fdSEd Maste 		tv.tv_usec = 100*1000; /* 100 msec */
1690c43e99fdSEd Maste 		event_base_once(data->base, -1, EV_TIMEOUT, cancel_gai_cb,
1691c43e99fdSEd Maste 		    r, &tv);
1692c43e99fdSEd Maste 	}
1693c43e99fdSEd Maste 
1694c43e99fdSEd Maste 	/* XXXXX There are more tests we could do, including:
1695c43e99fdSEd Maste 
1696c43e99fdSEd Maste 	   - A test to elicit NODATA.
1697c43e99fdSEd Maste 
1698c43e99fdSEd Maste 	 */
1699c43e99fdSEd Maste 
1700c43e99fdSEd Maste 	n_gai_results_pending = 12;
1701c43e99fdSEd Maste 	exit_base_on_no_pending_results = data->base;
1702c43e99fdSEd Maste 
1703c43e99fdSEd Maste 	event_base_dispatch(data->base);
1704c43e99fdSEd Maste 
1705c43e99fdSEd Maste 	/* 0: both.example.com */
1706c43e99fdSEd Maste 	tt_int_op(a_out[0].err, ==, 0);
1707c43e99fdSEd Maste 	tt_assert(a_out[0].ai);
1708c43e99fdSEd Maste 	tt_assert(a_out[0].ai->ai_next);
1709c43e99fdSEd Maste 	tt_assert(!a_out[0].ai->ai_next->ai_next);
1710c43e99fdSEd Maste 	a = ai_find_by_family(a_out[0].ai, PF_INET);
1711c43e99fdSEd Maste 	tt_assert(a);
1712c43e99fdSEd Maste 	test_ai_eq(a, "80.80.32.32:8000", SOCK_STREAM, IPPROTO_TCP);
1713c43e99fdSEd Maste 	a = ai_find_by_family(a_out[0].ai, PF_INET6);
1714c43e99fdSEd Maste 	tt_assert(a);
1715c43e99fdSEd Maste 	test_ai_eq(a, "[80ff::bbbb]:8000", SOCK_STREAM, IPPROTO_TCP);
1716c43e99fdSEd Maste 	tt_assert(a_out[0].ai->ai_canonname);
1717c43e99fdSEd Maste 	tt_str_op(a_out[0].ai->ai_canonname, ==, "both-canonical.example.com");
1718c43e99fdSEd Maste 
1719c43e99fdSEd Maste 	/* 1: v4only.example.com */
1720c43e99fdSEd Maste 	tt_int_op(a_out[1].err, ==, 0);
1721c43e99fdSEd Maste 	tt_assert(a_out[1].ai);
1722c43e99fdSEd Maste 	tt_assert(! a_out[1].ai->ai_next);
1723c43e99fdSEd Maste 	test_ai_eq(a_out[1].ai, "18.52.86.120:8001", SOCK_STREAM, IPPROTO_TCP);
1724c43e99fdSEd Maste 	tt_assert(a_out[1].ai->ai_canonname == NULL);
1725c43e99fdSEd Maste 
1726c43e99fdSEd Maste 
1727c43e99fdSEd Maste 	/* 2: v6only.example.com */
1728c43e99fdSEd Maste 	tt_int_op(a_out[2].err, ==, 0);
1729c43e99fdSEd Maste 	tt_assert(a_out[2].ai);
1730c43e99fdSEd Maste 	tt_assert(! a_out[2].ai->ai_next);
1731c43e99fdSEd Maste 	test_ai_eq(a_out[2].ai, "[b0b::f00d]:8002", SOCK_STREAM, IPPROTO_TCP);
1732c43e99fdSEd Maste 
1733c43e99fdSEd Maste 	/* 3: v4assert.example.com */
1734c43e99fdSEd Maste 	tt_int_op(a_out[3].err, ==, 0);
1735c43e99fdSEd Maste 	tt_assert(a_out[3].ai);
1736c43e99fdSEd Maste 	tt_assert(! a_out[3].ai->ai_next);
1737c43e99fdSEd Maste 	test_ai_eq(a_out[3].ai, "18.52.86.120:8003", SOCK_STREAM, IPPROTO_TCP);
1738c43e99fdSEd Maste 
1739c43e99fdSEd Maste 	/* 4: v6assert.example.com */
1740c43e99fdSEd Maste 	tt_int_op(a_out[4].err, ==, 0);
1741c43e99fdSEd Maste 	tt_assert(a_out[4].ai);
1742c43e99fdSEd Maste 	tt_assert(! a_out[4].ai->ai_next);
1743c43e99fdSEd Maste 	test_ai_eq(a_out[4].ai, "[b0b::f00d]:8004", SOCK_STREAM, IPPROTO_TCP);
1744c43e99fdSEd Maste 
1745c43e99fdSEd Maste 	/* 5: nosuchplace.example.com (inet) */
1746c43e99fdSEd Maste 	tt_int_op(a_out[5].err, ==, EVUTIL_EAI_NONAME);
1747c43e99fdSEd Maste 	tt_assert(! a_out[5].ai);
1748c43e99fdSEd Maste 
1749c43e99fdSEd Maste 	/* 6: nosuchplace.example.com (unspec) */
1750c43e99fdSEd Maste 	tt_int_op(a_out[6].err, ==, EVUTIL_EAI_NONAME);
1751c43e99fdSEd Maste 	tt_assert(! a_out[6].ai);
1752c43e99fdSEd Maste 
1753c43e99fdSEd Maste 	/* 7: v6timeout.example.com */
1754c43e99fdSEd Maste 	tt_int_op(a_out[7].err, ==, 0);
1755c43e99fdSEd Maste 	tt_assert(a_out[7].ai);
1756c43e99fdSEd Maste 	tt_assert(! a_out[7].ai->ai_next);
1757c43e99fdSEd Maste 	test_ai_eq(a_out[7].ai, "171.205.239.1:8007", SOCK_STREAM, IPPROTO_TCP);
1758c43e99fdSEd Maste 
1759c43e99fdSEd Maste 	/* 8: v6timeout-nonexist.example.com */
1760c43e99fdSEd Maste 	tt_int_op(a_out[8].err, ==, EVUTIL_EAI_NONAME);
1761c43e99fdSEd Maste 	tt_assert(! a_out[8].ai);
1762c43e99fdSEd Maste 
1763c43e99fdSEd Maste 	/* 9: both (ADDRCONFIG) */
1764c43e99fdSEd Maste 	tt_int_op(a_out[9].err, ==, 0);
1765c43e99fdSEd Maste 	tt_assert(a_out[9].ai);
1766c43e99fdSEd Maste 	a = ai_find_by_family(a_out[9].ai, PF_INET);
1767c43e99fdSEd Maste 	if (a)
1768c43e99fdSEd Maste 		test_ai_eq(a, "80.80.32.32:8009", SOCK_STREAM, IPPROTO_TCP);
1769c43e99fdSEd Maste 	else
1770c43e99fdSEd Maste 		tt_assert(ai_find_by_family(a_out[9].ai, PF_INET6));
1771c43e99fdSEd Maste 	a = ai_find_by_family(a_out[9].ai, PF_INET6);
1772c43e99fdSEd Maste 	if (a)
1773c43e99fdSEd Maste 		test_ai_eq(a, "[80ff::bbbb]:8009", SOCK_STREAM, IPPROTO_TCP);
1774c43e99fdSEd Maste 	else
1775c43e99fdSEd Maste 		tt_assert(ai_find_by_family(a_out[9].ai, PF_INET));
1776c43e99fdSEd Maste 
1777c43e99fdSEd Maste 	/* 10: v4timeout.example.com */
1778c43e99fdSEd Maste 	tt_int_op(a_out[10].err, ==, 0);
1779c43e99fdSEd Maste 	tt_assert(a_out[10].ai);
1780c43e99fdSEd Maste 	tt_assert(! a_out[10].ai->ai_next);
1781c43e99fdSEd Maste 	test_ai_eq(a_out[10].ai, "[a0a::ff01]:8010", SOCK_STREAM, IPPROTO_TCP);
1782c43e99fdSEd Maste 
1783c43e99fdSEd Maste 	/* 11: cancelled request. */
1784c43e99fdSEd Maste 	tt_int_op(a_out[11].err, ==, EVUTIL_EAI_CANCEL);
1785c43e99fdSEd Maste 	tt_assert(a_out[11].ai == NULL);
1786c43e99fdSEd Maste 
1787c43e99fdSEd Maste end:
1788c43e99fdSEd Maste 	if (local_outcome.ai)
1789c43e99fdSEd Maste 		evutil_freeaddrinfo(local_outcome.ai);
1790*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(a_out); ++i) {
1791c43e99fdSEd Maste 		if (a_out[i].ai)
1792c43e99fdSEd Maste 			evutil_freeaddrinfo(a_out[i].ai);
1793c43e99fdSEd Maste 	}
1794c43e99fdSEd Maste 	if (port)
1795c43e99fdSEd Maste 		evdns_close_server_port(port);
1796c43e99fdSEd Maste 	if (dns_base)
1797c43e99fdSEd Maste 		evdns_base_free(dns_base, 0);
1798c43e99fdSEd Maste }
1799c43e99fdSEd Maste 
1800c43e99fdSEd Maste struct gaic_request_status {
1801c43e99fdSEd Maste 	int magic;
1802c43e99fdSEd Maste 	struct event_base *base;
1803c43e99fdSEd Maste 	struct evdns_base *dns_base;
1804c43e99fdSEd Maste 	struct evdns_getaddrinfo_request *request;
1805c43e99fdSEd Maste 	struct event cancel_event;
1806c43e99fdSEd Maste 	int canceled;
1807c43e99fdSEd Maste };
1808c43e99fdSEd Maste 
1809c43e99fdSEd Maste #define GAIC_MAGIC 0x1234abcd
1810c43e99fdSEd Maste 
1811*b50261e2SCy Schubert static int gaic_pending = 0;
1812*b50261e2SCy Schubert static int gaic_freed = 0;
1813c43e99fdSEd Maste 
1814c43e99fdSEd Maste static void
gaic_cancel_request_cb(evutil_socket_t fd,short what,void * arg)1815c43e99fdSEd Maste gaic_cancel_request_cb(evutil_socket_t fd, short what, void *arg)
1816c43e99fdSEd Maste {
1817c43e99fdSEd Maste 	struct gaic_request_status *status = arg;
1818c43e99fdSEd Maste 
1819c43e99fdSEd Maste 	tt_assert(status->magic == GAIC_MAGIC);
1820c43e99fdSEd Maste 	status->canceled = 1;
1821c43e99fdSEd Maste 	evdns_getaddrinfo_cancel(status->request);
1822c43e99fdSEd Maste 	return;
1823c43e99fdSEd Maste end:
1824c43e99fdSEd Maste 	event_base_loopexit(status->base, NULL);
1825c43e99fdSEd Maste }
1826c43e99fdSEd Maste 
1827c43e99fdSEd Maste static void
gaic_server_cb(struct evdns_server_request * req,void * arg)1828c43e99fdSEd Maste gaic_server_cb(struct evdns_server_request *req, void *arg)
1829c43e99fdSEd Maste {
1830c43e99fdSEd Maste 	ev_uint32_t answer = 0x7f000001;
1831c43e99fdSEd Maste 	tt_assert(req->nquestions);
1832c43e99fdSEd Maste 	evdns_server_request_add_a_reply(req, req->questions[0]->name, 1,
1833c43e99fdSEd Maste 	    &answer, 100);
1834c43e99fdSEd Maste 	evdns_server_request_respond(req, 0);
1835c43e99fdSEd Maste 	return;
1836c43e99fdSEd Maste end:
1837c43e99fdSEd Maste 	evdns_server_request_respond(req, DNS_ERR_REFUSED);
1838c43e99fdSEd Maste }
1839c43e99fdSEd Maste 
1840c43e99fdSEd Maste 
1841c43e99fdSEd Maste static void
gaic_getaddrinfo_cb(int result,struct evutil_addrinfo * res,void * arg)1842c43e99fdSEd Maste gaic_getaddrinfo_cb(int result, struct evutil_addrinfo *res, void *arg)
1843c43e99fdSEd Maste {
1844c43e99fdSEd Maste 	struct gaic_request_status *status = arg;
1845c43e99fdSEd Maste 	struct event_base *base = status->base;
1846c43e99fdSEd Maste 	tt_assert(status->magic == GAIC_MAGIC);
1847c43e99fdSEd Maste 
1848c43e99fdSEd Maste 	if (result == EVUTIL_EAI_CANCEL) {
1849c43e99fdSEd Maste 		tt_assert(status->canceled);
1850c43e99fdSEd Maste 	}
1851c43e99fdSEd Maste 	event_del(&status->cancel_event);
1852c43e99fdSEd Maste 
1853c43e99fdSEd Maste 	memset(status, 0xf0, sizeof(*status));
1854c43e99fdSEd Maste 	free(status);
1855c43e99fdSEd Maste 
1856c43e99fdSEd Maste end:
1857*b50261e2SCy Schubert 	if (res)
1858*b50261e2SCy Schubert 	{
1859*b50261e2SCy Schubert 		TT_BLATHER(("evutil_freeaddrinfo(%p)", res));
1860*b50261e2SCy Schubert 		evutil_freeaddrinfo(res);
1861*b50261e2SCy Schubert 		++gaic_freed;
1862*b50261e2SCy Schubert 	}
1863*b50261e2SCy Schubert 	if (--gaic_pending <= 0)
1864c43e99fdSEd Maste 		event_base_loopexit(base, NULL);
1865c43e99fdSEd Maste }
1866c43e99fdSEd Maste 
1867c43e99fdSEd Maste static void
gaic_launch(struct event_base * base,struct evdns_base * dns_base)1868c43e99fdSEd Maste gaic_launch(struct event_base *base, struct evdns_base *dns_base)
1869c43e99fdSEd Maste {
1870c43e99fdSEd Maste 	struct gaic_request_status *status = calloc(1,sizeof(*status));
1871c43e99fdSEd Maste 	struct timeval tv = { 0, 10000 };
1872c43e99fdSEd Maste 	status->magic = GAIC_MAGIC;
1873c43e99fdSEd Maste 	status->base = base;
1874c43e99fdSEd Maste 	status->dns_base = dns_base;
1875c43e99fdSEd Maste 	event_assign(&status->cancel_event, base, -1, 0, gaic_cancel_request_cb,
1876c43e99fdSEd Maste 	    status);
1877c43e99fdSEd Maste 	status->request = evdns_getaddrinfo(dns_base,
1878c43e99fdSEd Maste 	    "foobar.bazquux.example.com", "80", NULL, gaic_getaddrinfo_cb,
1879c43e99fdSEd Maste 	    status);
1880c43e99fdSEd Maste 	event_add(&status->cancel_event, &tv);
1881*b50261e2SCy Schubert 	++gaic_pending;
1882c43e99fdSEd Maste }
1883c43e99fdSEd Maste 
1884c43e99fdSEd Maste #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
1885c43e99fdSEd Maste /* FIXME: We should move this to regress_main.c if anything else needs it.*/
1886c43e99fdSEd Maste 
1887c43e99fdSEd Maste /* Trivial replacements for malloc/free/realloc to check for memory leaks.
1888c43e99fdSEd Maste  * Not threadsafe. */
1889c43e99fdSEd Maste static int allocated_chunks = 0;
1890c43e99fdSEd Maste 
1891c43e99fdSEd Maste static void *
cnt_malloc(size_t sz)1892c43e99fdSEd Maste cnt_malloc(size_t sz)
1893c43e99fdSEd Maste {
1894c43e99fdSEd Maste 	allocated_chunks += 1;
1895c43e99fdSEd Maste 	return malloc(sz);
1896c43e99fdSEd Maste }
1897c43e99fdSEd Maste 
1898c43e99fdSEd Maste static void *
cnt_realloc(void * old,size_t sz)1899c43e99fdSEd Maste cnt_realloc(void *old, size_t sz)
1900c43e99fdSEd Maste {
1901c43e99fdSEd Maste 	if (!old)
1902c43e99fdSEd Maste 		allocated_chunks += 1;
1903c43e99fdSEd Maste 	if (!sz)
1904c43e99fdSEd Maste 		allocated_chunks -= 1;
1905c43e99fdSEd Maste 	return realloc(old, sz);
1906c43e99fdSEd Maste }
1907c43e99fdSEd Maste 
1908c43e99fdSEd Maste static void
cnt_free(void * ptr)1909c43e99fdSEd Maste cnt_free(void *ptr)
1910c43e99fdSEd Maste {
1911c43e99fdSEd Maste 	allocated_chunks -= 1;
1912c43e99fdSEd Maste 	free(ptr);
1913c43e99fdSEd Maste }
1914c43e99fdSEd Maste 
1915c43e99fdSEd Maste struct testleak_env_t {
1916c43e99fdSEd Maste 	struct event_base *base;
1917c43e99fdSEd Maste 	struct evdns_base *dns_base;
1918c43e99fdSEd Maste 	struct evdns_request *req;
1919c43e99fdSEd Maste 	struct generic_dns_callback_result r;
1920c43e99fdSEd Maste };
1921c43e99fdSEd Maste 
1922c43e99fdSEd Maste static void *
testleak_setup(const struct testcase_t * testcase)1923c43e99fdSEd Maste testleak_setup(const struct testcase_t *testcase)
1924c43e99fdSEd Maste {
1925c43e99fdSEd Maste 	struct testleak_env_t *env;
1926c43e99fdSEd Maste 
1927c43e99fdSEd Maste 	allocated_chunks = 0;
1928c43e99fdSEd Maste 
1929c43e99fdSEd Maste 	/* Reset allocation counter, to start allocations from the very beginning.
1930c43e99fdSEd Maste 	 * (this will avoid false-positive negative numbers for allocated_chunks)
1931c43e99fdSEd Maste 	 */
1932c43e99fdSEd Maste 	libevent_global_shutdown();
1933c43e99fdSEd Maste 
1934c43e99fdSEd Maste 	event_set_mem_functions(cnt_malloc, cnt_realloc, cnt_free);
1935c43e99fdSEd Maste 
1936c43e99fdSEd Maste 	event_enable_debug_mode();
1937c43e99fdSEd Maste 
1938c43e99fdSEd Maste 	/* not mm_calloc: we don't want to mess with the count. */
1939c43e99fdSEd Maste 	env = calloc(1, sizeof(struct testleak_env_t));
1940c43e99fdSEd Maste 	env->base = event_base_new();
1941c43e99fdSEd Maste 	env->dns_base = evdns_base_new(env->base, 0);
1942c43e99fdSEd Maste 	env->req = evdns_base_resolve_ipv4(
1943c43e99fdSEd Maste 		env->dns_base, "example.com", DNS_QUERY_NO_SEARCH,
1944c43e99fdSEd Maste 		generic_dns_callback, &env->r);
1945c43e99fdSEd Maste 	return env;
1946c43e99fdSEd Maste }
1947c43e99fdSEd Maste 
1948c43e99fdSEd Maste static int
testleak_cleanup(const struct testcase_t * testcase,void * env_)1949c43e99fdSEd Maste testleak_cleanup(const struct testcase_t *testcase, void *env_)
1950c43e99fdSEd Maste {
1951c43e99fdSEd Maste 	int ok = 0;
1952c43e99fdSEd Maste 	struct testleak_env_t *env = env_;
1953c43e99fdSEd Maste 	tt_assert(env);
1954c43e99fdSEd Maste #ifdef EVENT__DISABLE_DEBUG_MODE
1955c43e99fdSEd Maste 	tt_int_op(allocated_chunks, ==, 0);
1956c43e99fdSEd Maste #else
1957c43e99fdSEd Maste 	libevent_global_shutdown();
1958c43e99fdSEd Maste 	tt_int_op(allocated_chunks, ==, 0);
1959c43e99fdSEd Maste #endif
1960c43e99fdSEd Maste 	ok = 1;
1961c43e99fdSEd Maste end:
1962c43e99fdSEd Maste 	if (env) {
1963c43e99fdSEd Maste 		if (env->dns_base)
1964c43e99fdSEd Maste 			evdns_base_free(env->dns_base, 0);
1965c43e99fdSEd Maste 		if (env->base)
1966c43e99fdSEd Maste 			event_base_free(env->base);
1967c43e99fdSEd Maste 		free(env);
1968c43e99fdSEd Maste 	}
1969c43e99fdSEd Maste 	return ok;
1970c43e99fdSEd Maste }
1971c43e99fdSEd Maste 
1972c43e99fdSEd Maste static struct testcase_setup_t testleak_funcs = {
1973c43e99fdSEd Maste 	testleak_setup, testleak_cleanup
1974c43e99fdSEd Maste };
1975c43e99fdSEd Maste 
1976c43e99fdSEd Maste static void
test_dbg_leak_cancel(void * env_)1977c43e99fdSEd Maste test_dbg_leak_cancel(void *env_)
1978c43e99fdSEd Maste {
1979c43e99fdSEd Maste 	/* cancel, loop, free/dns, free/base */
1980c43e99fdSEd Maste 	struct testleak_env_t *env = env_;
1981c43e99fdSEd Maste 	int send_err_shutdown = 1;
1982c43e99fdSEd Maste 	evdns_cancel_request(env->dns_base, env->req);
1983c43e99fdSEd Maste 	env->req = 0;
1984c43e99fdSEd Maste 
1985c43e99fdSEd Maste 	/* `req` is freed in callback, that's why one loop is required. */
1986c43e99fdSEd Maste 	event_base_loop(env->base, EVLOOP_NONBLOCK);
1987c43e99fdSEd Maste 
1988c43e99fdSEd Maste 	/* send_err_shutdown means nothing as soon as our request is
1989c43e99fdSEd Maste 	 * already canceled */
1990c43e99fdSEd Maste 	evdns_base_free(env->dns_base, send_err_shutdown);
1991c43e99fdSEd Maste 	env->dns_base = 0;
1992c43e99fdSEd Maste 	event_base_free(env->base);
1993c43e99fdSEd Maste 	env->base = 0;
1994c43e99fdSEd Maste }
1995c43e99fdSEd Maste 
1996c43e99fdSEd Maste static void
dbg_leak_resume(void * env_,int cancel,int send_err_shutdown)1997c43e99fdSEd Maste dbg_leak_resume(void *env_, int cancel, int send_err_shutdown)
1998c43e99fdSEd Maste {
1999c43e99fdSEd Maste 	/* cancel, loop, free/dns, free/base */
2000c43e99fdSEd Maste 	struct testleak_env_t *env = env_;
2001c43e99fdSEd Maste 	if (cancel) {
2002c43e99fdSEd Maste 		evdns_cancel_request(env->dns_base, env->req);
2003c43e99fdSEd Maste 		tt_assert(!evdns_base_resume(env->dns_base));
2004c43e99fdSEd Maste 	} else {
2005c43e99fdSEd Maste 		/* TODO: No nameservers, request can't be processed, must be errored */
2006c43e99fdSEd Maste 		tt_assert(!evdns_base_resume(env->dns_base));
2007c43e99fdSEd Maste 	}
2008c43e99fdSEd Maste 
2009c43e99fdSEd Maste 	event_base_loop(env->base, EVLOOP_NONBLOCK);
2010c43e99fdSEd Maste 	/**
2011c43e99fdSEd Maste 	 * Because we don't cancel request, and want our callback to recieve
2012c43e99fdSEd Maste 	 * DNS_ERR_SHUTDOWN, we use deferred callback, and there was:
2013c43e99fdSEd Maste 	 * - one extra malloc(),
2014c43e99fdSEd Maste 	 *   @see reply_schedule_callback()
2015c43e99fdSEd Maste 	 * - and one missing free
2016c43e99fdSEd Maste 	 *   @see request_finished() (req->handle->pending_cb = 1)
2017c43e99fdSEd Maste 	 * than we don't need to count in testleak_cleanup(), but we can clean them
2018c43e99fdSEd Maste 	 * if we will run loop once again, but *after* evdns base freed.
2019c43e99fdSEd Maste 	 */
2020c43e99fdSEd Maste 	evdns_base_free(env->dns_base, send_err_shutdown);
2021c43e99fdSEd Maste 	env->dns_base = 0;
2022c43e99fdSEd Maste 	event_base_loop(env->base, EVLOOP_NONBLOCK);
2023c43e99fdSEd Maste 
2024c43e99fdSEd Maste end:
2025c43e99fdSEd Maste 	event_base_free(env->base);
2026c43e99fdSEd Maste 	env->base = 0;
2027c43e99fdSEd Maste }
2028c43e99fdSEd Maste 
2029c43e99fdSEd Maste #define IMPL_DBG_LEAK_RESUME(name, cancel, send_err_shutdown)      \
2030c43e99fdSEd Maste 	static void                                                    \
2031c43e99fdSEd Maste 	test_dbg_leak_##name##_(void *env_)                            \
2032c43e99fdSEd Maste 	{                                                              \
2033c43e99fdSEd Maste 		dbg_leak_resume(env_, cancel, send_err_shutdown);          \
2034c43e99fdSEd Maste 	}
2035c43e99fdSEd Maste IMPL_DBG_LEAK_RESUME(resume, 0, 0)
2036c43e99fdSEd Maste IMPL_DBG_LEAK_RESUME(cancel_and_resume, 1, 0)
2037c43e99fdSEd Maste IMPL_DBG_LEAK_RESUME(resume_send_err, 0, 1)
2038c43e99fdSEd Maste IMPL_DBG_LEAK_RESUME(cancel_and_resume_send_err, 1, 1)
2039c43e99fdSEd Maste 
2040c43e99fdSEd Maste static void
test_dbg_leak_shutdown(void * env_)2041c43e99fdSEd Maste test_dbg_leak_shutdown(void *env_)
2042c43e99fdSEd Maste {
2043c43e99fdSEd Maste 	/* free/dns, loop, free/base */
2044c43e99fdSEd Maste 	struct testleak_env_t *env = env_;
2045c43e99fdSEd Maste 	int send_err_shutdown = 1;
2046c43e99fdSEd Maste 
2047c43e99fdSEd Maste 	/* `req` is freed both with `send_err_shutdown` and without it,
2048c43e99fdSEd Maste 	 * the only difference is `evdns_callback` call */
2049c43e99fdSEd Maste 	env->req = 0;
2050c43e99fdSEd Maste 
2051c43e99fdSEd Maste 	evdns_base_free(env->dns_base, send_err_shutdown);
2052c43e99fdSEd Maste 	env->dns_base = 0;
2053c43e99fdSEd Maste 
2054c43e99fdSEd Maste 	/* `req` is freed in callback, that's why one loop is required */
2055c43e99fdSEd Maste 	event_base_loop(env->base, EVLOOP_NONBLOCK);
2056c43e99fdSEd Maste 	event_base_free(env->base);
2057c43e99fdSEd Maste 	env->base = 0;
2058c43e99fdSEd Maste }
2059c43e99fdSEd Maste #endif
2060c43e99fdSEd Maste 
2061c43e99fdSEd Maste static void
test_getaddrinfo_async_cancel_stress(void * ptr)2062c43e99fdSEd Maste test_getaddrinfo_async_cancel_stress(void *ptr)
2063c43e99fdSEd Maste {
2064c43e99fdSEd Maste 	struct event_base *base;
2065c43e99fdSEd Maste 	struct evdns_base *dns_base = NULL;
2066c43e99fdSEd Maste 	struct evdns_server_port *server = NULL;
2067c43e99fdSEd Maste 	evutil_socket_t fd = -1;
2068c43e99fdSEd Maste 	struct sockaddr_in sin;
2069c43e99fdSEd Maste 	struct sockaddr_storage ss;
2070c43e99fdSEd Maste 	ev_socklen_t slen;
2071*b50261e2SCy Schubert 	unsigned i;
2072c43e99fdSEd Maste 
2073c43e99fdSEd Maste 	base = event_base_new();
2074c43e99fdSEd Maste 	dns_base = evdns_base_new(base, 0);
2075c43e99fdSEd Maste 
2076c43e99fdSEd Maste 	memset(&sin, 0, sizeof(sin));
2077c43e99fdSEd Maste 	sin.sin_family = AF_INET;
2078c43e99fdSEd Maste 	sin.sin_port = 0;
2079c43e99fdSEd Maste 	sin.sin_addr.s_addr = htonl(0x7f000001);
2080c43e99fdSEd Maste 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
2081c43e99fdSEd Maste 		tt_abort_perror("socket");
2082c43e99fdSEd Maste 	}
2083c43e99fdSEd Maste 	evutil_make_socket_nonblocking(fd);
2084c43e99fdSEd Maste 	if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
2085c43e99fdSEd Maste 		tt_abort_perror("bind");
2086c43e99fdSEd Maste 	}
2087c43e99fdSEd Maste 	server = evdns_add_server_port_with_base(base, fd, 0, gaic_server_cb,
2088c43e99fdSEd Maste 	    base);
2089c43e99fdSEd Maste 
2090c43e99fdSEd Maste 	memset(&ss, 0, sizeof(ss));
2091c43e99fdSEd Maste 	slen = sizeof(ss);
2092c43e99fdSEd Maste 	if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) {
2093c43e99fdSEd Maste 		tt_abort_perror("getsockname");
2094c43e99fdSEd Maste 	}
2095c43e99fdSEd Maste 	evdns_base_nameserver_sockaddr_add(dns_base,
2096c43e99fdSEd Maste 	    (struct sockaddr*)&ss, slen, 0);
2097c43e99fdSEd Maste 
2098c43e99fdSEd Maste 	for (i = 0; i < 1000; ++i) {
2099c43e99fdSEd Maste 		gaic_launch(base, dns_base);
2100c43e99fdSEd Maste 	}
2101c43e99fdSEd Maste 
2102c43e99fdSEd Maste 	event_base_dispatch(base);
2103c43e99fdSEd Maste 
2104*b50261e2SCy Schubert 	// at least some was canceled via external event
2105*b50261e2SCy Schubert 	tt_int_op(gaic_freed, !=, 1000);
2106*b50261e2SCy Schubert 
2107c43e99fdSEd Maste end:
2108c43e99fdSEd Maste 	if (dns_base)
2109c43e99fdSEd Maste 		evdns_base_free(dns_base, 1);
2110c43e99fdSEd Maste 	if (server)
2111c43e99fdSEd Maste 		evdns_close_server_port(server);
2112c43e99fdSEd Maste 	if (base)
2113c43e99fdSEd Maste 		event_base_free(base);
2114c43e99fdSEd Maste 	if (fd >= 0)
2115c43e99fdSEd Maste 		evutil_closesocket(fd);
2116c43e99fdSEd Maste }
2117c43e99fdSEd Maste 
2118c43e99fdSEd Maste static void
dns_client_fail_requests_test(void * arg)2119c43e99fdSEd Maste dns_client_fail_requests_test(void *arg)
2120c43e99fdSEd Maste {
2121c43e99fdSEd Maste 	struct basic_test_data *data = arg;
2122c43e99fdSEd Maste 	struct event_base *base = data->base;
2123*b50261e2SCy Schubert 	int limit_inflight = data->setup_data && !strcmp(data->setup_data, "limit-inflight");
2124c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
2125c43e99fdSEd Maste 	struct evdns_server_port *dns_port = NULL;
2126c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
2127c43e99fdSEd Maste 	char buf[64];
2128c43e99fdSEd Maste 
2129c43e99fdSEd Maste 	struct generic_dns_callback_result r[20];
2130*b50261e2SCy Schubert 	unsigned i;
2131c43e99fdSEd Maste 
2132c43e99fdSEd Maste 	dns_port = regress_get_dnsserver(base, &portnum, NULL,
2133c43e99fdSEd Maste 		regress_dns_server_cb, reissue_table);
2134c43e99fdSEd Maste 	tt_assert(dns_port);
2135c43e99fdSEd Maste 
2136c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
2137c43e99fdSEd Maste 
2138c43e99fdSEd Maste 	dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
2139c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
2140c43e99fdSEd Maste 
2141*b50261e2SCy Schubert 	if (limit_inflight)
2142*b50261e2SCy Schubert 		tt_assert(!evdns_base_set_option(dns, "max-inflight:", "11"));
2143*b50261e2SCy Schubert 
2144c43e99fdSEd Maste 	for (i = 0; i < 20; ++i)
2145c43e99fdSEd Maste 		evdns_base_resolve_ipv4(dns, "foof.example.com", 0, generic_dns_callback, &r[i]);
2146c43e99fdSEd Maste 
2147c43e99fdSEd Maste 	n_replies_left = 20;
2148c43e99fdSEd Maste 	exit_base = base;
2149c43e99fdSEd Maste 
2150c43e99fdSEd Maste 	evdns_base_free(dns, 1 /** fail requests */);
2151c43e99fdSEd Maste 	/** run defered callbacks, to trigger UAF */
2152c43e99fdSEd Maste 	event_base_dispatch(base);
2153c43e99fdSEd Maste 
2154c43e99fdSEd Maste 	tt_int_op(n_replies_left, ==, 0);
2155c43e99fdSEd Maste 	for (i = 0; i < 20; ++i)
2156c43e99fdSEd Maste 		tt_int_op(r[i].result, ==, DNS_ERR_SHUTDOWN);
2157c43e99fdSEd Maste 
2158c43e99fdSEd Maste end:
2159c43e99fdSEd Maste 	evdns_close_server_port(dns_port);
2160c43e99fdSEd Maste }
2161c43e99fdSEd Maste 
2162c43e99fdSEd Maste static void
getaddrinfo_cb(int err,struct evutil_addrinfo * res,void * ptr)2163c43e99fdSEd Maste getaddrinfo_cb(int err, struct evutil_addrinfo *res, void *ptr)
2164c43e99fdSEd Maste {
2165c43e99fdSEd Maste 	generic_dns_callback(err, 0, 0, 0, NULL, ptr);
2166c43e99fdSEd Maste }
2167c43e99fdSEd Maste static void
dns_client_fail_requests_getaddrinfo_test(void * arg)2168c43e99fdSEd Maste dns_client_fail_requests_getaddrinfo_test(void *arg)
2169c43e99fdSEd Maste {
2170c43e99fdSEd Maste 	struct basic_test_data *data = arg;
2171c43e99fdSEd Maste 	struct event_base *base = data->base;
2172c43e99fdSEd Maste 	struct evdns_base *dns = NULL;
2173c43e99fdSEd Maste 	struct evdns_server_port *dns_port = NULL;
2174c43e99fdSEd Maste 	ev_uint16_t portnum = 0;
2175c43e99fdSEd Maste 	char buf[64];
2176c43e99fdSEd Maste 
2177c43e99fdSEd Maste 	struct generic_dns_callback_result r[20];
2178c43e99fdSEd Maste 	int i;
2179c43e99fdSEd Maste 
2180c43e99fdSEd Maste 	dns_port = regress_get_dnsserver(base, &portnum, NULL,
2181c43e99fdSEd Maste 		regress_dns_server_cb, reissue_table);
2182c43e99fdSEd Maste 	tt_assert(dns_port);
2183c43e99fdSEd Maste 
2184c43e99fdSEd Maste 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
2185c43e99fdSEd Maste 
2186c43e99fdSEd Maste 	dns = evdns_base_new(base, EVDNS_BASE_DISABLE_WHEN_INACTIVE);
2187c43e99fdSEd Maste 	tt_assert(!evdns_base_nameserver_ip_add(dns, buf));
2188c43e99fdSEd Maste 
2189c43e99fdSEd Maste 	for (i = 0; i < 20; ++i)
2190*b50261e2SCy Schubert 		tt_assert(evdns_getaddrinfo(dns, "foof.example.com", "80", NULL, getaddrinfo_cb, &r[i]));
2191c43e99fdSEd Maste 
2192c43e99fdSEd Maste 	n_replies_left = 20;
2193c43e99fdSEd Maste 	exit_base = base;
2194c43e99fdSEd Maste 
2195c43e99fdSEd Maste 	evdns_base_free(dns, 1 /** fail requests */);
2196c43e99fdSEd Maste 	/** run defered callbacks, to trigger UAF */
2197c43e99fdSEd Maste 	event_base_dispatch(base);
2198c43e99fdSEd Maste 
2199c43e99fdSEd Maste 	tt_int_op(n_replies_left, ==, 0);
2200c43e99fdSEd Maste 	for (i = 0; i < 20; ++i)
2201c43e99fdSEd Maste 		tt_int_op(r[i].result, ==, EVUTIL_EAI_FAIL);
2202c43e99fdSEd Maste 
2203c43e99fdSEd Maste end:
2204c43e99fdSEd Maste 	evdns_close_server_port(dns_port);
2205c43e99fdSEd Maste }
2206c43e99fdSEd Maste 
2207*b50261e2SCy Schubert #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
2208*b50261e2SCy Schubert struct race_param
2209*b50261e2SCy Schubert {
2210*b50261e2SCy Schubert 	void *lock;
2211*b50261e2SCy Schubert 	void *reqs_cmpl_cond;
2212*b50261e2SCy Schubert 	int bw_threads;
2213*b50261e2SCy Schubert 	void *bw_threads_exited_cond;
2214*b50261e2SCy Schubert 	volatile int stopping;
2215*b50261e2SCy Schubert 	void *base;
2216*b50261e2SCy Schubert 	void *dns;
2217*b50261e2SCy Schubert 
2218*b50261e2SCy Schubert 	int locked;
2219*b50261e2SCy Schubert };
2220*b50261e2SCy Schubert static void *
race_base_run(void * arg)2221*b50261e2SCy Schubert race_base_run(void *arg)
2222*b50261e2SCy Schubert {
2223*b50261e2SCy Schubert 	struct race_param *rp = (struct race_param *)arg;
2224*b50261e2SCy Schubert 	event_base_loop(rp->base, EVLOOP_NO_EXIT_ON_EMPTY);
2225*b50261e2SCy Schubert 	THREAD_RETURN();
2226*b50261e2SCy Schubert }
2227*b50261e2SCy Schubert static void *
race_busywait_run(void * arg)2228*b50261e2SCy Schubert race_busywait_run(void *arg)
2229*b50261e2SCy Schubert {
2230*b50261e2SCy Schubert 	struct race_param *rp = (struct race_param *)arg;
2231*b50261e2SCy Schubert 	struct sockaddr_storage ss;
2232*b50261e2SCy Schubert 	while (!rp->stopping)
2233*b50261e2SCy Schubert 		evdns_base_get_nameserver_addr(rp->dns, 0, (struct sockaddr *)&ss, sizeof(ss));
2234*b50261e2SCy Schubert 	EVLOCK_LOCK(rp->lock, 0);
2235*b50261e2SCy Schubert 	if (--rp->bw_threads == 0)
2236*b50261e2SCy Schubert 		EVTHREAD_COND_SIGNAL(rp->bw_threads_exited_cond);
2237*b50261e2SCy Schubert 	EVLOCK_UNLOCK(rp->lock, 0);
2238*b50261e2SCy Schubert 	THREAD_RETURN();
2239*b50261e2SCy Schubert }
2240*b50261e2SCy Schubert static void
race_gai_cb(int result,struct evutil_addrinfo * res,void * arg)2241*b50261e2SCy Schubert race_gai_cb(int result, struct evutil_addrinfo *res, void *arg)
2242*b50261e2SCy Schubert {
2243*b50261e2SCy Schubert 	struct race_param *rp = arg;
2244*b50261e2SCy Schubert 	(void)result;
2245*b50261e2SCy Schubert 	(void)res;
2246*b50261e2SCy Schubert 
2247*b50261e2SCy Schubert 	--n_replies_left;
2248*b50261e2SCy Schubert 	if (n_replies_left == 0) {
2249*b50261e2SCy Schubert 		EVLOCK_LOCK(rp->lock, 0);
2250*b50261e2SCy Schubert 		EVTHREAD_COND_SIGNAL(rp->reqs_cmpl_cond);
2251*b50261e2SCy Schubert 		EVLOCK_UNLOCK(rp->lock, 0);
2252*b50261e2SCy Schubert 	}
2253*b50261e2SCy Schubert }
2254*b50261e2SCy Schubert static void
getaddrinfo_race_gotresolve_test(void * arg)2255*b50261e2SCy Schubert getaddrinfo_race_gotresolve_test(void *arg)
2256*b50261e2SCy Schubert {
2257*b50261e2SCy Schubert 	struct race_param rp;
2258*b50261e2SCy Schubert 	struct evdns_server_port *dns_port = NULL;
2259*b50261e2SCy Schubert 	ev_uint16_t portnum = 0;
2260*b50261e2SCy Schubert 	char buf[64];
2261*b50261e2SCy Schubert 	int i;
2262*b50261e2SCy Schubert 
2263*b50261e2SCy Schubert 	// Some stress is needed to yield inside getaddrinfo between resolve_ipv4 and resolve_ipv6
2264*b50261e2SCy Schubert 	int n_reqs = 16384;
2265*b50261e2SCy Schubert #ifdef _SC_NPROCESSORS_ONLN
2266*b50261e2SCy Schubert 	int n_threads = sysconf(_SC_NPROCESSORS_ONLN) + 1;
2267*b50261e2SCy Schubert #else
2268*b50261e2SCy Schubert 	int n_threads = 17;
2269*b50261e2SCy Schubert #endif
2270*b50261e2SCy Schubert 	THREAD_T thread[n_threads];
2271*b50261e2SCy Schubert 	struct timeval tv;
2272*b50261e2SCy Schubert 
2273*b50261e2SCy Schubert 	(void)arg;
2274*b50261e2SCy Schubert 
2275*b50261e2SCy Schubert 	evthread_use_pthreads();
2276*b50261e2SCy Schubert 
2277*b50261e2SCy Schubert 	rp.base = event_base_new();
2278*b50261e2SCy Schubert 	tt_assert(rp.base);
2279*b50261e2SCy Schubert 	if (evthread_make_base_notifiable(rp.base) < 0)
2280*b50261e2SCy Schubert 		tt_abort_msg("Couldn't make base notifiable!");
2281*b50261e2SCy Schubert 
2282*b50261e2SCy Schubert 	dns_port = regress_get_dnsserver(rp.base, &portnum, NULL,
2283*b50261e2SCy Schubert 									 regress_dns_server_cb, reissue_table);
2284*b50261e2SCy Schubert 	tt_assert(dns_port);
2285*b50261e2SCy Schubert 
2286*b50261e2SCy Schubert 	evutil_snprintf(buf, sizeof(buf), "127.0.0.1:%d", (int)portnum);
2287*b50261e2SCy Schubert 
2288*b50261e2SCy Schubert 	rp.dns = evdns_base_new(rp.base, 0);
2289*b50261e2SCy Schubert 	tt_assert(!evdns_base_nameserver_ip_add(rp.dns, buf));
2290*b50261e2SCy Schubert 
2291*b50261e2SCy Schubert 	n_replies_left = n_reqs;
2292*b50261e2SCy Schubert 
2293*b50261e2SCy Schubert 	EVTHREAD_ALLOC_LOCK(rp.lock, 0);
2294*b50261e2SCy Schubert 	EVTHREAD_ALLOC_COND(rp.reqs_cmpl_cond);
2295*b50261e2SCy Schubert 	EVTHREAD_ALLOC_COND(rp.bw_threads_exited_cond);
2296*b50261e2SCy Schubert 	tt_assert(rp.lock);
2297*b50261e2SCy Schubert 	tt_assert(rp.reqs_cmpl_cond);
2298*b50261e2SCy Schubert 	tt_assert(rp.bw_threads_exited_cond);
2299*b50261e2SCy Schubert 	rp.bw_threads = 0;
2300*b50261e2SCy Schubert 	rp.stopping = 0;
2301*b50261e2SCy Schubert 
2302*b50261e2SCy Schubert 	// Run resolver thread
2303*b50261e2SCy Schubert 	THREAD_START(thread[0], race_base_run, &rp);
2304*b50261e2SCy Schubert 	// Run busy-wait threads used to force yield this thread
2305*b50261e2SCy Schubert 	for (i = 1; i < n_threads; i++) {
2306*b50261e2SCy Schubert 		rp.bw_threads++;
2307*b50261e2SCy Schubert 		THREAD_START(thread[i], race_busywait_run, &rp);
2308*b50261e2SCy Schubert 	}
2309*b50261e2SCy Schubert 
2310*b50261e2SCy Schubert 	EVLOCK_LOCK(rp.lock, 0);
2311*b50261e2SCy Schubert 	rp.locked = 1;
2312*b50261e2SCy Schubert 
2313*b50261e2SCy Schubert 	for (i = 0; i < n_reqs; ++i) {
2314*b50261e2SCy Schubert 		tt_assert(evdns_getaddrinfo(rp.dns, "foof.example.com", "80", NULL, race_gai_cb, &rp));
2315*b50261e2SCy Schubert 		// This magic along with busy-wait threads make this thread yield frequently
2316*b50261e2SCy Schubert 		if (i % 100 == 0) {
2317*b50261e2SCy Schubert 			tv.tv_sec = 0;
2318*b50261e2SCy Schubert 			tv.tv_usec = 10000;
2319*b50261e2SCy Schubert 			evutil_usleep_(&tv);
2320*b50261e2SCy Schubert 		}
2321*b50261e2SCy Schubert 	}
2322*b50261e2SCy Schubert 
2323*b50261e2SCy Schubert 	exit_base = rp.base;
2324*b50261e2SCy Schubert 
2325*b50261e2SCy Schubert 	// Wait for some time
2326*b50261e2SCy Schubert 	tv.tv_sec = 5;
2327*b50261e2SCy Schubert 	tv.tv_usec = 0;
2328*b50261e2SCy Schubert 	EVTHREAD_COND_WAIT_TIMED(rp.reqs_cmpl_cond, rp.lock, &tv);
2329*b50261e2SCy Schubert 
2330*b50261e2SCy Schubert 	// Stop busy-wait threads
2331*b50261e2SCy Schubert 	tv.tv_sec = 1;
2332*b50261e2SCy Schubert 	tv.tv_usec = 0;
2333*b50261e2SCy Schubert 	rp.stopping = 1;
2334*b50261e2SCy Schubert 	tt_assert(EVTHREAD_COND_WAIT_TIMED(rp.bw_threads_exited_cond, rp.lock, &tv) == 0);
2335*b50261e2SCy Schubert 
2336*b50261e2SCy Schubert 	EVLOCK_UNLOCK(rp.lock, 0);
2337*b50261e2SCy Schubert 	rp.locked = 0;
2338*b50261e2SCy Schubert 
2339*b50261e2SCy Schubert 	evdns_base_free(rp.dns, 1 /** fail requests */);
2340*b50261e2SCy Schubert 
2341*b50261e2SCy Schubert 	tt_int_op(n_replies_left, ==, 0);
2342*b50261e2SCy Schubert 
2343*b50261e2SCy Schubert end:
2344*b50261e2SCy Schubert 	if (rp.locked)
2345*b50261e2SCy Schubert 		EVLOCK_UNLOCK(rp.lock, 0);
2346*b50261e2SCy Schubert 	EVTHREAD_FREE_LOCK(rp.lock, 0);
2347*b50261e2SCy Schubert 	EVTHREAD_FREE_COND(rp.reqs_cmpl_cond);
2348*b50261e2SCy Schubert 	EVTHREAD_FREE_COND(rp.bw_threads_exited_cond);
2349*b50261e2SCy Schubert 	evdns_close_server_port(dns_port);
2350*b50261e2SCy Schubert 	event_base_loopbreak(rp.base);
2351*b50261e2SCy Schubert 	event_base_free(rp.base);
2352*b50261e2SCy Schubert }
2353*b50261e2SCy Schubert #endif
2354*b50261e2SCy Schubert 
2355*b50261e2SCy Schubert static void
test_set_so_rcvbuf_so_sndbuf(void * arg)2356*b50261e2SCy Schubert test_set_so_rcvbuf_so_sndbuf(void *arg)
2357*b50261e2SCy Schubert {
2358*b50261e2SCy Schubert 	struct basic_test_data *data = arg;
2359*b50261e2SCy Schubert 	struct evdns_base *dns_base;
2360*b50261e2SCy Schubert 
2361*b50261e2SCy Schubert 	dns_base = evdns_base_new(data->base, 0);
2362*b50261e2SCy Schubert 	tt_assert(dns_base);
2363*b50261e2SCy Schubert 
2364*b50261e2SCy Schubert 	tt_assert(!evdns_base_set_option(dns_base, "so-rcvbuf", "10240"));
2365*b50261e2SCy Schubert 	tt_assert(!evdns_base_set_option(dns_base, "so-sndbuf", "10240"));
2366*b50261e2SCy Schubert 
2367*b50261e2SCy Schubert 	/* actually check SO_RCVBUF/SO_SNDBUF not fails */
2368*b50261e2SCy Schubert 	tt_assert(!evdns_base_nameserver_ip_add(dns_base, "127.0.0.1"));
2369*b50261e2SCy Schubert 
2370*b50261e2SCy Schubert end:
2371*b50261e2SCy Schubert 	if (dns_base)
2372*b50261e2SCy Schubert 		evdns_base_free(dns_base, 0);
2373*b50261e2SCy Schubert }
2374*b50261e2SCy Schubert 
2375*b50261e2SCy Schubert static void
test_set_option(void * arg)2376*b50261e2SCy Schubert test_set_option(void *arg)
2377*b50261e2SCy Schubert {
2378*b50261e2SCy Schubert #define SUCCESS 0
2379*b50261e2SCy Schubert #define FAIL -1
2380*b50261e2SCy Schubert 	struct basic_test_data *data = arg;
2381*b50261e2SCy Schubert 	struct evdns_base *dns_base;
2382*b50261e2SCy Schubert 	size_t i;
2383*b50261e2SCy Schubert 	/* Option names are allowed to have ':' at the end.
2384*b50261e2SCy Schubert 	 * So all test option names come in pairs.
2385*b50261e2SCy Schubert 	 */
2386*b50261e2SCy Schubert 	const char *int_options[] = {
2387*b50261e2SCy Schubert 		"ndots", "ndots:",
2388*b50261e2SCy Schubert 		"max-timeouts", "max-timeouts:",
2389*b50261e2SCy Schubert 		"max-inflight", "max-inflight:",
2390*b50261e2SCy Schubert 		"attempts", "attempts:",
2391*b50261e2SCy Schubert 		"randomize-case", "randomize-case:",
2392*b50261e2SCy Schubert 		"so-rcvbuf", "so-rcvbuf:",
2393*b50261e2SCy Schubert 		"so-sndbuf", "so-sndbuf:",
2394*b50261e2SCy Schubert 	};
2395*b50261e2SCy Schubert 	const char *timeval_options[] = {
2396*b50261e2SCy Schubert 		"timeout", "timeout:",
2397*b50261e2SCy Schubert 		"getaddrinfo-allow-skew", "getaddrinfo-allow-skew:",
2398*b50261e2SCy Schubert 		"initial-probe-timeout", "initial-probe-timeout:",
2399*b50261e2SCy Schubert 	};
2400*b50261e2SCy Schubert 	const char *addr_port_options[] = {
2401*b50261e2SCy Schubert 		"bind-to", "bind-to:",
2402*b50261e2SCy Schubert 	};
2403*b50261e2SCy Schubert 
2404*b50261e2SCy Schubert 	dns_base = evdns_base_new(data->base, 0);
2405*b50261e2SCy Schubert 	tt_assert(dns_base);
2406*b50261e2SCy Schubert 
2407*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(int_options); ++i) {
2408*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "0"));
2409*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "1"));
2410*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, int_options[i], "10000"));
2411*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "foo"));
2412*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, int_options[i], "3.14"));
2413*b50261e2SCy Schubert 	}
2414*b50261e2SCy Schubert 
2415*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(timeval_options); ++i) {
2416*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "1"));
2417*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "0.001"));
2418*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "3.14"));
2419*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, timeval_options[i], "10000"));
2420*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "0"));
2421*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, timeval_options[i], "foo"));
2422*b50261e2SCy Schubert 	}
2423*b50261e2SCy Schubert 
2424*b50261e2SCy Schubert 	for (i = 0; i < ARRAY_SIZE(addr_port_options); ++i) {
2425*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "8.8.8.8:80"));
2426*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "1.2.3.4"));
2427*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "::1:82"));
2428*b50261e2SCy Schubert 		tt_assert(SUCCESS == evdns_base_set_option(dns_base, addr_port_options[i], "3::4"));
2429*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "3.14"));
2430*b50261e2SCy Schubert 		tt_assert(FAIL == evdns_base_set_option(dns_base, addr_port_options[i], "foo"));
2431*b50261e2SCy Schubert 	}
2432*b50261e2SCy Schubert 
2433*b50261e2SCy Schubert #undef SUCCESS
2434*b50261e2SCy Schubert #undef FAIL
2435*b50261e2SCy Schubert end:
2436*b50261e2SCy Schubert 	if (dns_base)
2437*b50261e2SCy Schubert 		evdns_base_free(dns_base, 0);
2438*b50261e2SCy Schubert }
2439c43e99fdSEd Maste 
2440c43e99fdSEd Maste #define DNS_LEGACY(name, flags)					       \
2441c43e99fdSEd Maste 	{ #name, run_legacy_test_fn, flags|TT_LEGACY, &legacy_setup,   \
2442c43e99fdSEd Maste 		    dns_##name }
2443c43e99fdSEd Maste 
2444c43e99fdSEd Maste struct testcase_t dns_testcases[] = {
2445c43e99fdSEd Maste 	DNS_LEGACY(server, TT_FORK|TT_NEED_BASE),
2446c43e99fdSEd Maste 	DNS_LEGACY(gethostbyname, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
2447c43e99fdSEd Maste 	DNS_LEGACY(gethostbyname6, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
2448c43e99fdSEd Maste 	DNS_LEGACY(gethostbyaddr, TT_FORK|TT_NEED_BASE|TT_NEED_DNS|TT_OFF_BY_DEFAULT),
2449c43e99fdSEd Maste 	{ "resolve_reverse", dns_resolve_reverse, TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
2450c43e99fdSEd Maste 	{ "search_empty", dns_search_empty_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2451c43e99fdSEd Maste 	{ "search", dns_search_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2452c43e99fdSEd Maste 	{ "search_lower", dns_search_lower_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2453c43e99fdSEd Maste 	{ "search_cancel", dns_search_cancel_test,
2454c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2455c43e99fdSEd Maste 	{ "retry", dns_retry_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2456c43e99fdSEd Maste 	{ "retry_disable_when_inactive", dns_retry_disable_when_inactive_test,
2457c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2458c43e99fdSEd Maste 	{ "reissue", dns_reissue_test, TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2459c43e99fdSEd Maste 	{ "reissue_disable_when_inactive", dns_reissue_disable_when_inactive_test,
2460c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2461c43e99fdSEd Maste 	{ "inflight", dns_inflight_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2462c43e99fdSEd Maste 	{ "bufferevent_connect_hostname", test_bufferevent_connect_hostname,
2463c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2464*b50261e2SCy Schubert #ifdef EVENT__HAVE_SETRLIMIT
2465*b50261e2SCy Schubert 	{ "bufferevent_connect_hostname_emfile", test_bufferevent_connect_hostname,
2466*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"emfile" },
2467*b50261e2SCy Schubert #endif
2468c43e99fdSEd Maste 	{ "disable_when_inactive", dns_disable_when_inactive_test,
2469c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2470c43e99fdSEd Maste 	{ "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test,
2471*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2472*b50261e2SCy Schubert 
2473*b50261e2SCy Schubert 	{ "initialize_nameservers", dns_initialize_nameservers_test,
2474c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2475*b50261e2SCy Schubert #ifndef _WIN32
2476*b50261e2SCy Schubert 	{ "nameservers_no_default", dns_nameservers_no_default_test,
2477*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2478*b50261e2SCy Schubert #endif
2479c43e99fdSEd Maste 
2480c43e99fdSEd Maste 	{ "getaddrinfo_async", test_getaddrinfo_async,
2481c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" },
2482c43e99fdSEd Maste 	{ "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,
2483c43e99fdSEd Maste 	  TT_FORK, NULL, NULL },
2484c43e99fdSEd Maste 
2485c43e99fdSEd Maste #ifdef EVENT_SET_MEM_FUNCTIONS_IMPLEMENTED
2486c43e99fdSEd Maste 	{ "leak_shutdown", test_dbg_leak_shutdown, TT_FORK, &testleak_funcs, NULL },
2487c43e99fdSEd Maste 	{ "leak_cancel", test_dbg_leak_cancel, TT_FORK, &testleak_funcs, NULL },
2488c43e99fdSEd Maste 
2489c43e99fdSEd Maste 	{ "leak_resume", test_dbg_leak_resume_, TT_FORK, &testleak_funcs, NULL },
2490c43e99fdSEd Maste 	{ "leak_cancel_and_resume", test_dbg_leak_cancel_and_resume_,
2491c43e99fdSEd Maste 	  TT_FORK, &testleak_funcs, NULL },
2492c43e99fdSEd Maste 	{ "leak_resume_send_err", test_dbg_leak_resume_send_err_,
2493c43e99fdSEd Maste 	  TT_FORK, &testleak_funcs, NULL },
2494c43e99fdSEd Maste 	{ "leak_cancel_and_resume_send_err", test_dbg_leak_cancel_and_resume_send_err_,
2495c43e99fdSEd Maste 	  TT_FORK, &testleak_funcs, NULL },
2496c43e99fdSEd Maste #endif
2497c43e99fdSEd Maste 
2498c43e99fdSEd Maste 	{ "client_fail_requests", dns_client_fail_requests_test,
2499*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2500*b50261e2SCy Schubert 	{ "client_fail_waiting_requests", dns_client_fail_requests_test,
2501*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, (char*)"limit-inflight" },
2502c43e99fdSEd Maste 	{ "client_fail_requests_getaddrinfo",
2503c43e99fdSEd Maste 	  dns_client_fail_requests_getaddrinfo_test,
2504*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE|TT_NO_LOGS, &basic_setup, NULL },
2505*b50261e2SCy Schubert #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED
2506*b50261e2SCy Schubert 	{ "getaddrinfo_race_gotresolve",
2507*b50261e2SCy Schubert 	  getaddrinfo_race_gotresolve_test,
2508*b50261e2SCy Schubert 	  TT_FORK|TT_OFF_BY_DEFAULT, NULL, NULL },
2509*b50261e2SCy Schubert #endif
2510*b50261e2SCy Schubert 
2511*b50261e2SCy Schubert 	{ "set_SO_RCVBUF_SO_SNDBUF", test_set_so_rcvbuf_so_sndbuf,
2512*b50261e2SCy Schubert 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2513*b50261e2SCy Schubert 	{ "set_options", test_set_option,
2514c43e99fdSEd Maste 	  TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
2515c43e99fdSEd Maste 
2516c43e99fdSEd Maste 	END_OF_TESTCASES
2517c43e99fdSEd Maste };
2518c43e99fdSEd Maste 
2519