Home | History | Annotate | Line # | Download | only in dns
dispatch_test.c revision 1.2.2.2
      1 /*	$NetBSD: dispatch_test.c,v 1.2.2.2 2024/02/25 15:47:39 martin Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #include <inttypes.h>
     17 #include <sched.h> /* IWYU pragma: keep */
     18 #include <setjmp.h>
     19 #include <stdarg.h>
     20 #include <stdbool.h>
     21 #include <stddef.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <unistd.h>
     25 #include <uv.h>
     26 
     27 #define UNIT_TESTING
     28 #include <cmocka.h>
     29 
     30 #include <isc/buffer.h>
     31 #include <isc/managers.h>
     32 #include <isc/refcount.h>
     33 #include <isc/task.h>
     34 #include <isc/util.h>
     35 
     36 #include <dns/dispatch.h>
     37 #include <dns/name.h>
     38 #include <dns/view.h>
     39 
     40 #include <tests/dns.h>
     41 
     42 uv_sem_t sem;
     43 
     44 /* Timeouts in miliseconds */
     45 #define T_SERVER_INIT	    5000
     46 #define T_SERVER_IDLE	    5000
     47 #define T_SERVER_KEEPALIVE  5000
     48 #define T_SERVER_ADVERTISED 5000
     49 
     50 #define T_CLIENT_INIT	    2000
     51 #define T_CLIENT_IDLE	    2000
     52 #define T_CLIENT_KEEPALIVE  2000
     53 #define T_CLIENT_ADVERTISED 2000
     54 
     55 #define T_CLIENT_CONNECT 1000
     56 
     57 dns_dispatchmgr_t *dispatchmgr = NULL;
     58 dns_dispatchset_t *dset = NULL;
     59 isc_nm_t *connect_nm = NULL;
     60 static isc_sockaddr_t udp_server_addr;
     61 static isc_sockaddr_t udp_connect_addr;
     62 static isc_sockaddr_t tcp_server_addr;
     63 static isc_sockaddr_t tcp_connect_addr;
     64 
     65 const struct in6_addr in6addr_blackhole = { { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     66 						0, 0, 0, 0, 1 } } };
     67 
     68 static int
     69 setup_ephemeral_port(isc_sockaddr_t *addr, sa_family_t family) {
     70 	socklen_t addrlen = sizeof(*addr);
     71 	uv_os_sock_t fd;
     72 	int r;
     73 
     74 	isc_sockaddr_fromin6(addr, &in6addr_loopback, 0);
     75 
     76 	fd = socket(AF_INET6, family, 0);
     77 	if (fd < 0) {
     78 		perror("setup_ephemeral_port: socket()");
     79 		return (-1);
     80 	}
     81 
     82 	r = bind(fd, (const struct sockaddr *)&addr->type.sa,
     83 		 sizeof(addr->type.sin6));
     84 	if (r != 0) {
     85 		perror("setup_ephemeral_port: bind()");
     86 		close(fd);
     87 		return (r);
     88 	}
     89 
     90 	r = getsockname(fd, (struct sockaddr *)&addr->type.sa, &addrlen);
     91 	if (r != 0) {
     92 		perror("setup_ephemeral_port: getsockname()");
     93 		close(fd);
     94 		return (r);
     95 	}
     96 
     97 #if IPV6_RECVERR
     98 #define setsockopt_on(socket, level, name) \
     99 	setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
    100 
    101 	r = setsockopt_on(fd, IPPROTO_IPV6, IPV6_RECVERR);
    102 	if (r != 0) {
    103 		perror("setup_ephemeral_port");
    104 		close(fd);
    105 		return (r);
    106 	}
    107 #endif
    108 
    109 	return (fd);
    110 }
    111 
    112 static void
    113 reset_testdata(void);
    114 
    115 static int
    116 _setup(void **state) {
    117 	uv_os_sock_t sock = -1;
    118 	int r;
    119 
    120 	udp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    121 	isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0);
    122 
    123 	tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    124 	isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
    125 
    126 	udp_server_addr = (isc_sockaddr_t){ .length = 0 };
    127 	sock = setup_ephemeral_port(&udp_server_addr, SOCK_DGRAM);
    128 	if (sock < 0) {
    129 		return (-1);
    130 	}
    131 	close(sock);
    132 
    133 	tcp_server_addr = (isc_sockaddr_t){ .length = 0 };
    134 	sock = setup_ephemeral_port(&tcp_server_addr, SOCK_STREAM);
    135 	if (sock < 0) {
    136 		return (-1);
    137 	}
    138 	close(sock);
    139 
    140 	setup_managers(state);
    141 
    142 	/* Create a secondary network manager */
    143 	isc_managers_create(mctx, workers, 0, &connect_nm, NULL, NULL);
    144 
    145 	isc_nm_settimeouts(netmgr, T_SERVER_INIT, T_SERVER_IDLE,
    146 			   T_SERVER_KEEPALIVE, T_SERVER_ADVERTISED);
    147 
    148 	/*
    149 	 * Use shorter client-side timeouts, to ensure that clients
    150 	 * time out before the server.
    151 	 */
    152 	isc_nm_settimeouts(connect_nm, T_CLIENT_INIT, T_CLIENT_IDLE,
    153 			   T_CLIENT_KEEPALIVE, T_CLIENT_ADVERTISED);
    154 
    155 	r = uv_sem_init(&sem, 0);
    156 	assert_int_equal(r, 0);
    157 
    158 	reset_testdata();
    159 
    160 	return (0);
    161 }
    162 
    163 static int
    164 _teardown(void **state) {
    165 	uv_sem_destroy(&sem);
    166 
    167 	isc_managers_destroy(&connect_nm, NULL, NULL);
    168 	assert_null(connect_nm);
    169 
    170 	teardown_managers(state);
    171 
    172 	return (0);
    173 }
    174 
    175 static isc_result_t
    176 make_dispatchset(unsigned int ndisps) {
    177 	isc_result_t result;
    178 	isc_sockaddr_t any;
    179 	dns_dispatch_t *disp = NULL;
    180 
    181 	result = dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr);
    182 	if (result != ISC_R_SUCCESS) {
    183 		return (result);
    184 	}
    185 
    186 	isc_sockaddr_any(&any);
    187 	result = dns_dispatch_createudp(dispatchmgr, &any, &disp);
    188 	if (result != ISC_R_SUCCESS) {
    189 		return (result);
    190 	}
    191 
    192 	result = dns_dispatchset_create(mctx, disp, &dset, ndisps);
    193 	dns_dispatch_detach(&disp);
    194 
    195 	return (result);
    196 }
    197 
    198 static void
    199 reset(void) {
    200 	if (dset != NULL) {
    201 		dns_dispatchset_destroy(&dset);
    202 	}
    203 	if (dispatchmgr != NULL) {
    204 		dns_dispatchmgr_detach(&dispatchmgr);
    205 	}
    206 }
    207 
    208 /* create dispatch set */
    209 ISC_RUN_TEST_IMPL(dispatchset_create) {
    210 	isc_result_t result;
    211 
    212 	UNUSED(state);
    213 
    214 	result = make_dispatchset(1);
    215 	assert_int_equal(result, ISC_R_SUCCESS);
    216 	reset();
    217 
    218 	result = make_dispatchset(10);
    219 	assert_int_equal(result, ISC_R_SUCCESS);
    220 	reset();
    221 }
    222 
    223 /* test dispatch set round-robin */
    224 ISC_RUN_TEST_IMPL(dispatchset_get) {
    225 	isc_result_t result;
    226 	dns_dispatch_t *d1, *d2, *d3, *d4, *d5;
    227 
    228 	UNUSED(state);
    229 
    230 	result = make_dispatchset(1);
    231 	assert_int_equal(result, ISC_R_SUCCESS);
    232 
    233 	d1 = dns_dispatchset_get(dset);
    234 	d2 = dns_dispatchset_get(dset);
    235 	d3 = dns_dispatchset_get(dset);
    236 	d4 = dns_dispatchset_get(dset);
    237 	d5 = dns_dispatchset_get(dset);
    238 
    239 	assert_ptr_equal(d1, d2);
    240 	assert_ptr_equal(d2, d3);
    241 	assert_ptr_equal(d3, d4);
    242 	assert_ptr_equal(d4, d5);
    243 
    244 	reset();
    245 
    246 	result = make_dispatchset(4);
    247 	assert_int_equal(result, ISC_R_SUCCESS);
    248 
    249 	d1 = dns_dispatchset_get(dset);
    250 	d2 = dns_dispatchset_get(dset);
    251 	d3 = dns_dispatchset_get(dset);
    252 	d4 = dns_dispatchset_get(dset);
    253 	d5 = dns_dispatchset_get(dset);
    254 
    255 	assert_ptr_equal(d1, d5);
    256 	assert_ptr_not_equal(d1, d2);
    257 	assert_ptr_not_equal(d2, d3);
    258 	assert_ptr_not_equal(d3, d4);
    259 	assert_ptr_not_equal(d4, d5);
    260 
    261 	reset();
    262 }
    263 
    264 struct {
    265 	atomic_uint_fast32_t responses;
    266 	atomic_uint_fast32_t result;
    267 } testdata;
    268 
    269 static dns_dispatch_t *dispatch = NULL;
    270 static dns_dispentry_t *dispentry = NULL;
    271 static atomic_bool first = true;
    272 
    273 static void
    274 reset_testdata(void) {
    275 	atomic_init(&testdata.responses, 0);
    276 	atomic_init(&testdata.result, ISC_R_UNSET);
    277 }
    278 
    279 static void
    280 server_senddone(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
    281 	UNUSED(handle);
    282 	UNUSED(eresult);
    283 	UNUSED(cbarg);
    284 
    285 	return;
    286 }
    287 
    288 static void
    289 nameserver(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
    290 	   void *cbarg) {
    291 	isc_region_t response;
    292 	static unsigned char buf1[16];
    293 	static unsigned char buf2[16];
    294 
    295 	UNUSED(eresult);
    296 	UNUSED(cbarg);
    297 
    298 	memmove(buf1, region->base, 12);
    299 	memset(buf1 + 12, 0, 4);
    300 	buf1[2] |= 0x80; /* qr=1 */
    301 
    302 	memmove(buf2, region->base, 12);
    303 	memset(buf2 + 12, 1, 4);
    304 	buf2[2] |= 0x80; /* qr=1 */
    305 
    306 	/*
    307 	 * send message to be discarded.
    308 	 */
    309 	response.base = buf1;
    310 	response.length = sizeof(buf1);
    311 	isc_nm_send(handle, &response, server_senddone, NULL);
    312 
    313 	/*
    314 	 * send nextitem message.
    315 	 */
    316 	response.base = buf2;
    317 	response.length = sizeof(buf2);
    318 	isc_nm_send(handle, &response, server_senddone, NULL);
    319 }
    320 
    321 static isc_result_t
    322 accept_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
    323 	UNUSED(handle);
    324 	UNUSED(cbarg);
    325 
    326 	return (eresult);
    327 }
    328 
    329 static void
    330 noop_nameserver(isc_nmhandle_t *handle, isc_result_t eresult,
    331 		isc_region_t *region, void *cbarg) {
    332 	UNUSED(handle);
    333 	UNUSED(eresult);
    334 	UNUSED(region);
    335 	UNUSED(cbarg);
    336 }
    337 
    338 static void
    339 response_getnext(isc_result_t result, isc_region_t *region, void *arg) {
    340 	UNUSED(region);
    341 	UNUSED(arg);
    342 
    343 	atomic_fetch_add_relaxed(&testdata.responses, 1);
    344 
    345 	if (atomic_compare_exchange_strong(&first, &(bool){ true }, false)) {
    346 		result = dns_dispatch_getnext(dispentry);
    347 		assert_int_equal(result, ISC_R_SUCCESS);
    348 	} else {
    349 		uv_sem_post(&sem);
    350 	}
    351 }
    352 
    353 static void
    354 response(isc_result_t eresult, isc_region_t *region, void *arg) {
    355 	UNUSED(region);
    356 	UNUSED(arg);
    357 
    358 	switch (eresult) {
    359 	case ISC_R_EOF:
    360 	case ISC_R_CANCELED:
    361 	case ISC_R_SHUTTINGDOWN:
    362 		break;
    363 	default:
    364 		atomic_fetch_add_relaxed(&testdata.responses, 1);
    365 		atomic_store_relaxed(&testdata.result, eresult);
    366 	}
    367 
    368 	uv_sem_post(&sem);
    369 }
    370 
    371 static void
    372 response_timeout(isc_result_t eresult, isc_region_t *region, void *arg) {
    373 	UNUSED(region);
    374 	UNUSED(arg);
    375 
    376 	atomic_store_relaxed(&testdata.result, eresult);
    377 
    378 	uv_sem_post(&sem);
    379 }
    380 
    381 static void
    382 connected(isc_result_t eresult, isc_region_t *region, void *cbarg) {
    383 	isc_region_t *r = (isc_region_t *)cbarg;
    384 
    385 	UNUSED(eresult);
    386 	UNUSED(region);
    387 
    388 	dns_dispatch_send(dispentry, r);
    389 }
    390 
    391 static void
    392 client_senddone(isc_result_t eresult, isc_region_t *region, void *cbarg) {
    393 	UNUSED(eresult);
    394 	UNUSED(region);
    395 	UNUSED(cbarg);
    396 
    397 	return;
    398 }
    399 
    400 static void
    401 timeout_connected(isc_result_t eresult, isc_region_t *region, void *cbarg) {
    402 	UNUSED(region);
    403 	UNUSED(cbarg);
    404 
    405 	atomic_store_relaxed(&testdata.result, eresult);
    406 
    407 	uv_sem_post(&sem);
    408 }
    409 
    410 ISC_RUN_TEST_IMPL(dispatch_timeout_tcp_connect) {
    411 	isc_result_t result;
    412 	isc_region_t region;
    413 	unsigned char rbuf[12] = { 0 };
    414 	unsigned char message[12] = { 0 };
    415 	uint16_t id;
    416 
    417 	UNUSED(state);
    418 
    419 	tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    420 	isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_blackhole, 0);
    421 
    422 	result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
    423 	assert_int_equal(result, ISC_R_SUCCESS);
    424 
    425 	result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
    426 					&tcp_server_addr, &dispatch);
    427 	assert_int_equal(result, ISC_R_SUCCESS);
    428 
    429 	region.base = rbuf;
    430 	region.length = sizeof(rbuf);
    431 
    432 	result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
    433 				  &tcp_server_addr, timeout_connected,
    434 				  client_senddone, response, &region, &id,
    435 				  &dispentry);
    436 	assert_int_equal(result, ISC_R_SUCCESS);
    437 
    438 	memset(message, 0, sizeof(message));
    439 	message[0] = (id >> 8) & 0xff;
    440 	message[1] = id & 0xff;
    441 
    442 	region.base = message;
    443 	region.length = sizeof(message);
    444 
    445 	dns_dispatch_connect(dispentry);
    446 
    447 	uv_sem_wait(&sem);
    448 
    449 	dns_dispatch_done(&dispentry);
    450 
    451 	dns_dispatch_detach(&dispatch);
    452 	dns_dispatchmgr_detach(&dispatchmgr);
    453 
    454 	/* Skip if the IPv6 is not available or not blackholed */
    455 
    456 	result = atomic_load_acquire(&testdata.result);
    457 	if (result == ISC_R_ADDRNOTAVAIL || result == ISC_R_CONNREFUSED) {
    458 		skip();
    459 		return;
    460 	}
    461 
    462 	assert_int_equal(result, ISC_R_TIMEDOUT);
    463 }
    464 
    465 ISC_RUN_TEST_IMPL(dispatch_timeout_tcp_response) {
    466 	isc_result_t result;
    467 	isc_region_t region;
    468 	unsigned char rbuf[12] = { 0 };
    469 	unsigned char message[12] = { 0 };
    470 	uint16_t id;
    471 	isc_nmsocket_t *sock = NULL;
    472 
    473 	UNUSED(state);
    474 
    475 	tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    476 	isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
    477 
    478 	result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
    479 	assert_int_equal(result, ISC_R_SUCCESS);
    480 
    481 	result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
    482 					&tcp_server_addr, &dispatch);
    483 	assert_int_equal(result, ISC_R_SUCCESS);
    484 
    485 	result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, noop_nameserver,
    486 				     NULL, accept_cb, NULL, 0, 0, NULL, &sock);
    487 	assert_int_equal(result, ISC_R_SUCCESS);
    488 
    489 	region.base = rbuf;
    490 	region.length = sizeof(rbuf);
    491 
    492 	result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
    493 				  &tcp_server_addr, connected, client_senddone,
    494 				  response_timeout, &region, &id, &dispentry);
    495 	assert_int_equal(result, ISC_R_SUCCESS);
    496 
    497 	memset(message, 0, sizeof(message));
    498 	message[0] = (id >> 8) & 0xff;
    499 	message[1] = id & 0xff;
    500 
    501 	region.base = message;
    502 	region.length = sizeof(message);
    503 
    504 	dns_dispatch_connect(dispentry);
    505 
    506 	uv_sem_wait(&sem);
    507 
    508 	assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT);
    509 
    510 	isc_nm_stoplistening(sock);
    511 	isc_nmsocket_close(&sock);
    512 	assert_null(sock);
    513 
    514 	dns_dispatch_done(&dispentry);
    515 
    516 	dns_dispatch_detach(&dispatch);
    517 	dns_dispatchmgr_detach(&dispatchmgr);
    518 }
    519 
    520 ISC_RUN_TEST_IMPL(dispatch_tcp_response) {
    521 	isc_result_t result;
    522 	isc_region_t region;
    523 	unsigned char rbuf[12] = { 0 };
    524 	unsigned char message[12] = { 0 };
    525 	uint16_t id;
    526 	isc_nmsocket_t *sock = NULL;
    527 
    528 	UNUSED(state);
    529 
    530 	tcp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    531 	isc_sockaddr_fromin6(&tcp_connect_addr, &in6addr_loopback, 0);
    532 
    533 	result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
    534 	assert_int_equal(result, ISC_R_SUCCESS);
    535 
    536 	result = dns_dispatch_createtcp(dispatchmgr, &tcp_connect_addr,
    537 					&tcp_server_addr, &dispatch);
    538 	assert_int_equal(result, ISC_R_SUCCESS);
    539 
    540 	result = isc_nm_listentcpdns(netmgr, &tcp_server_addr, nameserver, NULL,
    541 				     accept_cb, NULL, 0, 0, NULL, &sock);
    542 	assert_int_equal(result, ISC_R_SUCCESS);
    543 
    544 	region.base = rbuf;
    545 	region.length = sizeof(rbuf);
    546 
    547 	result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
    548 				  &tcp_server_addr, connected, client_senddone,
    549 				  response, &region, &id, &dispentry);
    550 	assert_int_equal(result, ISC_R_SUCCESS);
    551 
    552 	memset(message, 0, sizeof(message));
    553 	message[0] = (id >> 8) & 0xff;
    554 	message[1] = id & 0xff;
    555 
    556 	region.base = message;
    557 	region.length = sizeof(message);
    558 
    559 	dns_dispatch_connect(dispentry);
    560 
    561 	uv_sem_wait(&sem);
    562 
    563 	assert_in_range(atomic_load_acquire(&testdata.responses), 1, 2);
    564 	assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_SUCCESS);
    565 
    566 	/* Cleanup */
    567 
    568 	isc_nm_stoplistening(sock);
    569 	isc_nmsocket_close(&sock);
    570 	assert_null(sock);
    571 
    572 	dns_dispatch_done(&dispentry);
    573 
    574 	dns_dispatch_detach(&dispatch);
    575 	dns_dispatchmgr_detach(&dispatchmgr);
    576 }
    577 
    578 ISC_RUN_TEST_IMPL(dispatch_timeout_udp_response) {
    579 	isc_result_t result;
    580 	isc_region_t region;
    581 	unsigned char rbuf[12] = { 0 };
    582 	unsigned char message[12] = { 0 };
    583 	uint16_t id;
    584 	isc_nmsocket_t *sock = NULL;
    585 
    586 	UNUSED(state);
    587 
    588 	udp_connect_addr = (isc_sockaddr_t){ .length = 0 };
    589 	isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0);
    590 
    591 	result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
    592 	assert_int_equal(result, ISC_R_SUCCESS);
    593 
    594 	result = dns_dispatch_createudp(dispatchmgr, &tcp_connect_addr,
    595 					&dispatch);
    596 	assert_int_equal(result, ISC_R_SUCCESS);
    597 
    598 	result = isc_nm_listenudp(netmgr, &udp_server_addr, noop_nameserver,
    599 				  NULL, 0, &sock);
    600 	assert_int_equal(result, ISC_R_SUCCESS);
    601 
    602 	region.base = rbuf;
    603 	region.length = sizeof(rbuf);
    604 
    605 	result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
    606 				  &udp_server_addr, connected, client_senddone,
    607 				  response_timeout, &region, &id, &dispentry);
    608 	assert_int_equal(result, ISC_R_SUCCESS);
    609 
    610 	memset(message, 0, sizeof(message));
    611 	message[0] = (id >> 8) & 0xff;
    612 	message[1] = id & 0xff;
    613 
    614 	region.base = message;
    615 	region.length = sizeof(message);
    616 
    617 	dns_dispatch_connect(dispentry);
    618 
    619 	uv_sem_wait(&sem);
    620 
    621 	assert_int_equal(atomic_load_acquire(&testdata.result), ISC_R_TIMEDOUT);
    622 
    623 	isc_nm_stoplistening(sock);
    624 	isc_nmsocket_close(&sock);
    625 	assert_null(sock);
    626 
    627 	dns_dispatch_done(&dispentry);
    628 
    629 	dns_dispatch_detach(&dispatch);
    630 	dns_dispatchmgr_detach(&dispatchmgr);
    631 }
    632 
    633 /* test dispatch getnext */
    634 ISC_RUN_TEST_IMPL(dispatch_getnext) {
    635 	isc_result_t result;
    636 	isc_region_t region;
    637 	isc_nmsocket_t *sock = NULL;
    638 	unsigned char message[12] = { 0 };
    639 	unsigned char rbuf[12] = { 0 };
    640 	uint16_t id;
    641 
    642 	UNUSED(state);
    643 
    644 	result = dns_dispatchmgr_create(mctx, connect_nm, &dispatchmgr);
    645 	assert_int_equal(result, ISC_R_SUCCESS);
    646 
    647 	result = dns_dispatch_createudp(dispatchmgr, &udp_connect_addr,
    648 					&dispatch);
    649 	assert_int_equal(result, ISC_R_SUCCESS);
    650 
    651 	/*
    652 	 * Create a local udp nameserver on the loopback.
    653 	 */
    654 	result = isc_nm_listenudp(netmgr, &udp_server_addr, nameserver, NULL, 0,
    655 				  &sock);
    656 	assert_int_equal(result, ISC_R_SUCCESS);
    657 
    658 	region.base = rbuf;
    659 	region.length = sizeof(rbuf);
    660 	result = dns_dispatch_add(dispatch, 0, T_CLIENT_CONNECT,
    661 				  &udp_server_addr, connected, client_senddone,
    662 				  response_getnext, &region, &id, &dispentry);
    663 	assert_int_equal(result, ISC_R_SUCCESS);
    664 
    665 	memset(message, 0, sizeof(message));
    666 	message[0] = (id >> 8) & 0xff;
    667 	message[1] = id & 0xff;
    668 
    669 	region.base = message;
    670 	region.length = sizeof(message);
    671 
    672 	dns_dispatch_connect(dispentry);
    673 
    674 	uv_sem_wait(&sem);
    675 
    676 	assert_int_equal(atomic_load_acquire(&testdata.responses), 2);
    677 
    678 	/* Cleanup */
    679 	isc_nm_stoplistening(sock);
    680 	isc_nmsocket_close(&sock);
    681 	assert_null(sock);
    682 
    683 	dns_dispatch_done(&dispentry);
    684 	dns_dispatch_detach(&dispatch);
    685 	dns_dispatchmgr_detach(&dispatchmgr);
    686 }
    687 
    688 ISC_TEST_LIST_START
    689 
    690 ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_tcp_connect, _setup, _teardown)
    691 ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_tcp_response, _setup, _teardown)
    692 ISC_TEST_ENTRY_CUSTOM(dispatch_tcp_response, _setup, _teardown)
    693 ISC_TEST_ENTRY_CUSTOM(dispatch_timeout_udp_response, _setup, _teardown)
    694 ISC_TEST_ENTRY_CUSTOM(dispatchset_create, _setup, _teardown)
    695 ISC_TEST_ENTRY_CUSTOM(dispatchset_get, _setup, _teardown)
    696 ISC_TEST_ENTRY_CUSTOM(dispatch_getnext, _setup, _teardown)
    697 
    698 ISC_TEST_LIST_END
    699 
    700 ISC_TEST_MAIN
    701