From 148cfb17d5ae1ed22936c994ee77b084a3e7d6e2 Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Wed, 11 Oct 2023 22:18:54 +0300 Subject: [PATCH] Refactor UDP tests This commit mostly moves the code around to make the parts of the UDP unit test suite reusable. That changes the unit test suite structure to resemble that of stream based unit tests. The motivation behind this is to reuse most of the code for the new PROXY over UDP uni tests suite. --- tests/isc/netmgr_common.c | 1051 +++++++++++++++++++++++++++++++++++ tests/isc/netmgr_common.h | 111 ++++ tests/isc/udp_test.c | 1095 ++----------------------------------- 3 files changed, 1213 insertions(+), 1044 deletions(-) diff --git a/tests/isc/netmgr_common.c b/tests/isc/netmgr_common.c index 35375ebda5..fadbb6a036 100644 --- a/tests/isc/netmgr_common.c +++ b/tests/isc/netmgr_common.c @@ -53,6 +53,9 @@ isc_tlsctx_t *tcp_listen_tlsctx = NULL; isc_tlsctx_t *tcp_connect_tlsctx = NULL; isc_tlsctx_client_session_cache_t *tcp_tlsctx_client_sess_cache = NULL; +isc_sockaddr_t udp_listen_addr; +isc_sockaddr_t udp_connect_addr; + uint64_t send_magic = 0; isc_region_t send_msg = { .base = (unsigned char *)&send_magic, @@ -104,6 +107,7 @@ bool noanswer = false; bool stream_use_TLS = false; bool stream_use_PROXY = false; bool stream_PROXY_over_TLS = false; +bool udp_use_PROXY = false; bool stream = false; in_port_t stream_port = 0; @@ -1184,3 +1188,1050 @@ stream_recv_send_teardown(void **state ISC_ATTR_UNUSED) { return (teardown_netmgr_test(state)); } + +int +setup_udp_test(void **state) { + setup_loopmgr(state); + setup_netmgr(state); + + udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); + + udp_listen_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&udp_listen_addr, &in6addr_loopback, + UDP_TEST_PORT); + + atomic_store(&sreads, 0); + atomic_store(&ssends, 0); + + atomic_store(&cconnects, 0); + atomic_store(&csends, 0); + atomic_store(&creads, 0); + atomic_store(&ctimeouts, 0); + + isc_refcount_init(&active_cconnects, 0); + isc_refcount_init(&active_csends, 0); + isc_refcount_init(&active_creads, 0); + isc_refcount_init(&active_ssends, 0); + isc_refcount_init(&active_sreads, 0); + + expected_cconnects = -1; + expected_csends = -1; + expected_creads = -1; + expected_sreads = -1; + expected_ssends = -1; + expected_ctimeouts = -1; + + ssends_shutdown = true; + sreads_shutdown = true; + csends_shutdown = true; + cconnects_shutdown = true; + creads_shutdown = true; + + isc_nonce_buf(&send_magic, sizeof(send_magic)); + + connect_readcb = connect_read_cb; + + return (0); +} + +int +teardown_udp_test(void **state) { + UNUSED(state); + + isc_refcount_destroy(&active_cconnects); + isc_refcount_destroy(&active_csends); + isc_refcount_destroy(&active_creads); + isc_refcount_destroy(&active_ssends); + isc_refcount_destroy(&active_sreads); + + teardown_netmgr(state); + teardown_loopmgr(state); + + return (0); +} + +static void +udp_connect(isc_nm_cb_t cb, void *cbarg, unsigned int timeout) { + isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, cb, + cbarg, timeout); +} + +static void +udp_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + if (eresult != ISC_R_SUCCESS) { + isc_refcount_increment0(&active_sreads); + } + listen_read_cb(handle, eresult, region, cbarg); +} + +static void +udp_start_listening(uint32_t nworkers, isc_nm_recv_cb_t cb) { + isc_result_t result = isc_nm_listenudp( + netmgr, nworkers, &udp_listen_addr, cb, NULL, &listen_sock); + assert_int_equal(result, ISC_R_SUCCESS); + + isc_loop_teardown(mainloop, stop_listening, listen_sock); +} + +static void +udp__send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + isc_nmhandle_t *sendhandle = handle; + + assert_non_null(sendhandle); + + F(); + + switch (eresult) { + case ISC_R_SUCCESS: + if (have_expected_csends(atomic_fetch_add(&csends, 1) + 1)) { + if (csends_shutdown) { + isc_nm_cancelread(handle); + isc_loopmgr_shutdown(loopmgr); + } + } + break; + case ISC_R_SHUTTINGDOWN: + case ISC_R_CANCELED: + break; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } + + isc_nmhandle_detach(&sendhandle); + isc_refcount_decrement(&active_csends); +} + +static void +udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg); + +static void +udp_enqueue_connect(void *arg ISC_ATTR_UNUSED) { + isc_sockaddr_t connect_addr; + + connect_addr = (isc_sockaddr_t){ .length = 0 }; + isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0); + + isc_refcount_increment0(&active_cconnects); + + udp_connect(udp__connect_cb, NULL, T_CONNECT); +} + +static void +udp__connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + + assert_non_null(handle); + + F(); + + switch (eresult) { + case ISC_R_TIMEDOUT: + /* + * We are operating on the localhost, UDP cannot get lost, but + * it could be delayed, so we read again until we get the + * answer. + */ + isc_nm_read(handle, connect_readcb, cbarg); + return; + case ISC_R_SUCCESS: + assert_true(region->length >= sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + + assert_true(magic == send_magic); + + if (have_expected_creads(atomic_fetch_add(&creads, 1) + 1)) { + do_creads_shutdown(loopmgr); + } + + if (magic == send_magic && allow_send_back) { + connect_send(handle); + return; + } + + break; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } + + isc_refcount_decrement(&active_creads); + + isc_nmhandle_detach(&handle); +} + +static void +udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { + isc_nmhandle_t *readhandle = NULL; + isc_nmhandle_t *sendhandle = NULL; + + F(); + + isc_refcount_decrement(&active_cconnects); + + switch (eresult) { + case ISC_R_SUCCESS: + if (have_expected_cconnects(atomic_fetch_add(&cconnects, 1) + + 1)) + { + do_cconnects_shutdown(loopmgr); + } else if (do_send) { + isc_async_current(loopmgr, udp_enqueue_connect, cbarg); + } + + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, connect_readcb, cbarg); + + isc_refcount_increment0(&active_csends); + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(handle, T_IDLE); + + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, udp__send_cb, + cbarg); + + break; + case ISC_R_ADDRINUSE: + /* Try again */ + udp_enqueue_connect(NULL); + break; + case ISC_R_SHUTTINGDOWN: + case ISC_R_CANCELED: + break; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } +} + +int +udp_noop_setup(void **state) { + setup_udp_test(state); + expected_cconnects = 1; + cconnects_shutdown = true; + return (0); +} + +int +udp_noop_teardown(void **state) { + atomic_assert_int_eq(cconnects, 1); + teardown_udp_test(state); + return (0); +} + +void +udp_noop(void **arg ISC_ATTR_UNUSED) { + /* isc_result_t result = ISC_R_SUCCESS; */ + + /* result = isc_nm_listenudp(netmgr, ISC_NM_LISTEN_ALL, + * &udp_listen_addr, */ + /* mock_recv_cb, NULL, &listen_sock); */ + /* assert_int_equal(result, ISC_R_SUCCESS); */ + + /* isc_nm_stoplistening(listen_sock); */ + /* isc_nmsocket_close(&listen_sock); */ + /* assert_null(listen_sock); */ + + isc_refcount_increment0(&active_cconnects); + udp_connect(connect_success_cb, NULL, UDP_T_CONNECT); +} + +static void +udp_noresponse_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(handle); + UNUSED(eresult); + UNUSED(region); + UNUSED(cbarg); +} + +static void +udp_noresponse_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(region); + UNUSED(cbarg); + + assert_int_equal(eresult, ISC_R_TIMEDOUT); + + isc_refcount_decrement(&active_creads); + + atomic_fetch_add(&creads, 1); + + isc_nmhandle_detach(&handle); + + isc_loopmgr_shutdown(loopmgr); +} + +static void +udp_noresponse_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(cbarg); + + assert_non_null(handle); + assert_int_equal(eresult, ISC_R_SUCCESS); + atomic_fetch_add(&csends, 1); + isc_nmhandle_detach(&handle); + isc_refcount_decrement(&active_csends); +} + +static void +udp_noresponse_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + isc_nmhandle_t *readhandle = NULL; + isc_nmhandle_t *sendhandle = NULL; + + isc_refcount_decrement(&active_cconnects); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + /* Read */ + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, udp_noresponse_read_cb, cbarg); + + /* Send */ + isc_refcount_increment0(&active_csends); + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(handle, T_IDLE); + + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, + udp_noresponse_send_cb, cbarg); + + atomic_fetch_add(&cconnects, 1); +} + +int +udp_noresponse_setup(void **state) { + setup_udp_test(state); + expected_csends = 1; + return (0); +} + +int +udp_noresponse_teardown(void **state) { + atomic_assert_int_eq(csends, expected_csends); + teardown_udp_test(state); + return (0); +} + +void +udp_noresponse(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ONE, udp_noresponse_recv_cb); + + isc_refcount_increment0(&active_cconnects); + udp_connect(udp_noresponse_connect_cb, listen_sock, UDP_T_SOFT); +} + +static void +udp_timeout_recovery_ssend_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(cbarg); + + isc_refcount_decrement(&active_ssends); + assert_non_null(handle); + assert_int_equal(eresult, ISC_R_SUCCESS); + atomic_fetch_add(&ssends, 1); + isc_nmhandle_detach(&handle); +} + +static void +udp_timeout_recovery_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + isc_nmhandle_t *sendhandle = NULL; + int _creads = atomic_fetch_add(&creads, 1) + 1; + + assert_non_null(handle); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + assert_true(region->length == sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + assert_true(magic == send_magic); + assert_true(_creads < 6); + + if (_creads == 5) { + isc_nmhandle_attach(handle, &sendhandle); + isc_refcount_increment0(&active_ssends); + isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, + udp_timeout_recovery_ssend_cb, cbarg); + } +} + +static void +udp_timeout_recovery_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(region); + UNUSED(cbarg); + + assert_non_null(handle); + + F(); + + if (eresult == ISC_R_TIMEDOUT && + atomic_fetch_add(&ctimeouts, 1) + 1 < expected_ctimeouts) + { + isc_nmhandle_settimeout(handle, T_SOFT); + return; + } + + isc_refcount_decrement(&active_creads); + isc_nmhandle_detach(&handle); + + atomic_fetch_add(&creads, 1); + isc_loopmgr_shutdown(loopmgr); +} + +static void +udp_timeout_recovery_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(cbarg); + + assert_non_null(handle); + assert_int_equal(eresult, ISC_R_SUCCESS); + atomic_fetch_add(&csends, 1); + + isc_nmhandle_detach(&handle); + isc_refcount_decrement(&active_csends); +} + +static void +udp_timeout_recovery_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + isc_nmhandle_t *readhandle = NULL; + isc_nmhandle_t *sendhandle = NULL; + + F(); + + isc_refcount_decrement(&active_cconnects); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + /* Read */ + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, udp_timeout_recovery_read_cb, cbarg); + + /* Send */ + isc_refcount_increment0(&active_csends); + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(handle, T_IDLE); + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, + udp_timeout_recovery_send_cb, cbarg); + + atomic_fetch_add(&cconnects, 1); +} + +int +udp_timeout_recovery_setup(void **state) { + setup_udp_test(state); + expected_cconnects = 1; + expected_csends = 1; + expected_creads = 1; + expected_ctimeouts = 4; + return (0); +} + +int +udp_timeout_recovery_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + atomic_assert_int_eq(csends, expected_csends); + atomic_assert_int_eq(csends, expected_creads); + atomic_assert_int_eq(ctimeouts, expected_ctimeouts); + teardown_udp_test(state); + return (0); +} + +void +udp_timeout_recovery(void **arg ISC_ATTR_UNUSED) { + /* + * Listen using the noop callback so that client reads will time out. + */ + udp_start_listening(ISC_NM_LISTEN_ONE, udp_timeout_recovery_recv_cb); + + /* + * Connect with client timeout set to 0.05 seconds, then sleep for at + * least a second for each 'tick'. timeout_retry_cb() will give up + * after five timeouts. + */ + isc_refcount_increment0(&active_cconnects); + udp_connect(udp_timeout_recovery_connect_cb, listen_sock, UDP_T_SOFT); +} + +static void +udp_shutdown_connect_async_cb(void *arg ISC_ATTR_UNUSED); + +static void +udp_shutdown_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(handle); + UNUSED(cbarg); + + isc_refcount_decrement(&active_cconnects); + + /* + * The first UDP connect is faster than asynchronous shutdown procedure, + * restart the UDP connect again and expect the failure only in the + * second loop. + */ + if (atomic_fetch_add(&cconnects, 1) == 0) { + assert_int_equal(eresult, ISC_R_SUCCESS); + isc_async_current(loopmgr, udp_shutdown_connect_async_cb, + netmgr); + } else { + assert_int_equal(eresult, ISC_R_SHUTTINGDOWN); + } +} + +static void +udp_shutdown_connect_async_cb(void *arg ISC_ATTR_UNUSED) { + isc_refcount_increment0(&active_cconnects); + udp_connect(udp_shutdown_connect_connect_cb, NULL, T_SOFT); +} + +int +udp_shutdown_connect_setup(void **state) { + setup_udp_test(state); + expected_cconnects = 2; + return (0); +} + +int +udp_shutdown_connect_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + teardown_udp_test(state); + return (0); +} + +void +udp_shutdown_connect(void **arg ISC_ATTR_UNUSED) { + isc_loopmgr_shutdown(loopmgr); + /* + * isc_nm_udpconnect() is synchronous, so we need to launch this on the + * async loop. + */ + isc_async_current(loopmgr, udp_shutdown_connect_async_cb, netmgr); +} + +static void +udp_shutdown_read_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + + UNUSED(cbarg); + + assert_non_null(handle); + + F(); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + assert_true(region->length == sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + assert_true(magic == send_magic); +} + +static void +udp_shutdown_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(cbarg); + + F(); + + assert_non_null(handle); + assert_int_equal(eresult, ISC_R_SUCCESS); + + atomic_fetch_add(&csends, 1); + + isc_loopmgr_shutdown(loopmgr); + + isc_nmhandle_detach(&handle); + isc_refcount_decrement(&active_csends); +} + +static void +udp_shutdown_read_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + UNUSED(region); + UNUSED(cbarg); + + assert_true(eresult == ISC_R_SHUTTINGDOWN || eresult == ISC_R_TIMEDOUT); + + isc_refcount_decrement(&active_creads); + + atomic_fetch_add(&creads, 1); + + isc_nmhandle_detach(&handle); +} + +static void +udp_shutdown_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + isc_nmhandle_t *readhandle = NULL; + isc_nmhandle_t *sendhandle = NULL; + + isc_refcount_decrement(&active_cconnects); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + /* Read */ + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, udp_shutdown_read_read_cb, cbarg); + assert_true(handle->sock->reading); + + /* Send */ + isc_refcount_increment0(&active_csends); + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(handle, T_IDLE); + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, + udp_shutdown_read_send_cb, cbarg); + + atomic_fetch_add(&cconnects, 1); +} + +int +udp_shutdown_read_setup(void **state) { + setup_udp_test(state); + expected_cconnects = 1; + expected_creads = 1; + return (0); +} + +int +udp_shutdown_read_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + atomic_assert_int_eq(creads, expected_creads); + teardown_udp_test(state); + return (0); +} + +void +udp_shutdown_read(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ONE, udp_shutdown_read_recv_cb); + + isc_refcount_increment0(&active_cconnects); + udp_connect(udp_shutdown_read_connect_cb, NULL, UDP_T_SOFT); +} + +static void +udp_cancel_read_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + + UNUSED(cbarg); + + assert_non_null(handle); + + F(); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + assert_true(region->length == sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + assert_true(magic == send_magic); +} + +static void +udp_cancel_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + UNUSED(cbarg); + + F(); + + assert_non_null(handle); + assert_int_equal(eresult, ISC_R_SUCCESS); + + atomic_fetch_add(&csends, 1); + + isc_nm_cancelread(handle); + + isc_nmhandle_detach(&handle); + isc_refcount_decrement(&active_csends); +} + +static void +udp_cancel_read_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + isc_nmhandle_t *sendhandle = NULL; + isc_nmhandle_t *readhandle = NULL; + + UNUSED(region); + + F(); + + switch (eresult) { + case ISC_R_TIMEDOUT: + + /* Read again */ + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, udp_cancel_read_read_cb, cbarg); + + /* Send only once */ + if (isc_refcount_increment0(&active_csends) == 0) { + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(handle, T_IDLE); + isc_nm_send(sendhandle, (isc_region_t *)&send_msg, + udp_cancel_read_send_cb, cbarg); + } + break; + case ISC_R_CANCELED: + /* The read has been canceled */ + atomic_fetch_add(&creads, 1); + isc_loopmgr_shutdown(loopmgr); + break; + default: + UNREACHABLE(); + } + + isc_refcount_decrement(&active_creads); + + isc_nmhandle_detach(&handle); +} + +static void +udp_cancel_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + isc_nmhandle_t *readhandle = NULL; + + isc_refcount_decrement(&active_cconnects); + + assert_int_equal(eresult, ISC_R_SUCCESS); + + isc_refcount_increment0(&active_creads); + isc_nmhandle_attach(handle, &readhandle); + isc_nm_read(handle, udp_cancel_read_read_cb, cbarg); + + atomic_fetch_add(&cconnects, 1); +} + +int +udp_cancel_read_setup(void **state) { + setup_udp_test(state); + expected_cconnects = 1; + expected_creads = 1; + return (0); +} + +int +udp_cancel_read_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + atomic_assert_int_eq(creads, expected_creads); + teardown_udp_test(state); + return (0); +} + +void +udp_cancel_read(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ONE, udp_cancel_read_recv_cb); + + isc_refcount_increment0(&active_cconnects); + udp_connect(udp_cancel_read_connect_cb, NULL, UDP_T_SOFT); +} + +int +udp_recv_one_setup(void **state) { + setup_udp_test(state); + + connect_readcb = udp__connect_read_cb; + + expected_cconnects = 1; + cconnects_shutdown = false; + + expected_csends = 1; + csends_shutdown = false; + + expected_sreads = 1; + sreads_shutdown = false; + + expected_ssends = 1; + ssends_shutdown = false; + + expected_creads = 1; + creads_shutdown = true; + + return (0); +} + +int +udp_recv_one_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + atomic_assert_int_eq(csends, expected_csends); + atomic_assert_int_eq(sreads, expected_sreads); + atomic_assert_int_eq(ssends, expected_ssends); + atomic_assert_int_eq(creads, expected_creads); + + teardown_udp_test(state); + + return (0); +} + +void +udp_recv_one(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ONE, udp_listen_read_cb); + + udp_enqueue_connect(NULL); +} + +int +udp_recv_two_setup(void **state) { + setup_udp_test(state); + + connect_readcb = udp__connect_read_cb; + + expected_cconnects = 2; + cconnects_shutdown = false; + + expected_csends = 2; + csends_shutdown = false; + + expected_sreads = 2; + sreads_shutdown = false; + + expected_ssends = 2; + ssends_shutdown = false; + + expected_creads = 2; + creads_shutdown = true; + + return (0); +} + +int +udp_recv_two_teardown(void **state) { + atomic_assert_int_eq(cconnects, expected_cconnects); + atomic_assert_int_eq(csends, expected_csends); + atomic_assert_int_eq(sreads, expected_sreads); + atomic_assert_int_eq(ssends, expected_ssends); + atomic_assert_int_eq(creads, expected_creads); + + teardown_udp_test(state); + return (0); +} + +void +udp_recv_two(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ONE, udp_listen_read_cb); + + udp_enqueue_connect(NULL); + udp_enqueue_connect(NULL); +} + +int +udp_recv_send_setup(void **state) { + setup_udp_test(state); + + /* Allow some leeway (+1) as datagram service is unreliable */ + expected_cconnects = (workers + 1) * NSENDS; + cconnects_shutdown = false; + + expected_creads = workers * NSENDS; + do_send = true; + + return (0); +} + +int +udp_recv_send_teardown(void **state) { + atomic_assert_int_ge(cconnects, expected_creads); + atomic_assert_int_ge(csends, expected_creads); + atomic_assert_int_ge(sreads, expected_creads); + atomic_assert_int_ge(ssends, expected_creads); + atomic_assert_int_ge(creads, expected_creads); + + teardown_udp_test(state); + return (0); +} + +void +udp_recv_send(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ALL, udp_listen_read_cb); + + for (size_t i = 0; i < workers; i++) { + isc_async_run(isc_loop_get(loopmgr, i), udp_enqueue_connect, + NULL); + } +} + +static void +udp_double_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { + assert_non_null(handle); + + F(); + + isc_refcount_decrement(&active_ssends); + + switch (eresult) { + case ISC_R_SUCCESS: + if (have_expected_ssends(atomic_fetch_add(&ssends, 1) + 1)) { + do_ssends_shutdown(loopmgr); + } else { + isc_nmhandle_t *sendhandle = NULL; + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); + isc_refcount_increment0(&active_ssends); + isc_nm_send(sendhandle, &send_msg, + udp_double_read_send_cb, cbarg); + break; + } + break; + case ISC_R_CANCELED: + break; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } + + isc_nmhandle_detach(&handle); +} + +static void +udp_double_read_listen_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + + assert_non_null(handle); + + F(); + + switch (eresult) { + case ISC_R_EOF: + case ISC_R_SHUTTINGDOWN: + case ISC_R_CANCELED: + break; + case ISC_R_SUCCESS: + memmove(&magic, region->base, sizeof(magic)); + assert_true(magic == send_magic); + + assert_true(region->length >= sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + assert_true(magic == send_magic); + + isc_nmhandle_t *sendhandle = NULL; + isc_nmhandle_attach(handle, &sendhandle); + isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); + isc_refcount_increment0(&active_ssends); + isc_nm_send(sendhandle, &send_msg, udp_double_read_send_cb, + cbarg); + return; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } + + isc_refcount_decrement(&active_sreads); + + isc_nmhandle_detach(&handle); +} + +static void +udp_double_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, + isc_region_t *region, void *cbarg) { + uint64_t magic = 0; + bool detach = false; + + assert_non_null(handle); + + F(); + + switch (eresult) { + case ISC_R_TIMEDOUT: + /* + * We are operating on the localhost, UDP cannot get lost, but + * it could be delayed, so we read again until we get the + * answer. + */ + detach = false; + break; + case ISC_R_SUCCESS: + assert_true(region->length >= sizeof(magic)); + + memmove(&magic, region->base, sizeof(magic)); + + assert_true(magic == send_magic); + + if (have_expected_creads(atomic_fetch_add(&creads, 1) + 1)) { + do_creads_shutdown(loopmgr); + detach = true; + } + + if (magic == send_magic && allow_send_back) { + connect_send(handle); + return; + } + + break; + case ISC_R_EOF: + case ISC_R_SHUTTINGDOWN: + case ISC_R_CANCELED: + case ISC_R_CONNECTIONRESET: + detach = true; + break; + default: + fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, + isc_result_totext(eresult), cbarg); + assert_int_equal(eresult, ISC_R_SUCCESS); + } + + if (detach) { + isc_refcount_decrement(&active_creads); + isc_nmhandle_detach(&handle); + } else { + isc_nm_read(handle, connect_readcb, cbarg); + } +} + +int +udp_double_read_setup(void **state) { + setup_udp_test(state); + + expected_cconnects = 1; + cconnects_shutdown = false; + + expected_csends = 1; + csends_shutdown = false; + + expected_sreads = 1; + sreads_shutdown = false; + + expected_ssends = 2; + ssends_shutdown = false; + expected_creads = 2; + creads_shutdown = true; + + connect_readcb = udp_double_read_cb; + + return (0); +} + +int +udp_double_read_teardown(void **state) { + atomic_assert_int_eq(creads, expected_creads); + + teardown_udp_test(state); + + return (0); +} + +void +udp_double_read(void **arg ISC_ATTR_UNUSED) { + udp_start_listening(ISC_NM_LISTEN_ALL, udp_double_read_listen_cb); + + udp_enqueue_connect(NULL); +} diff --git a/tests/isc/netmgr_common.h b/tests/isc/netmgr_common.h index 4e3d2be0a2..3df02c883b 100644 --- a/tests/isc/netmgr_common.h +++ b/tests/isc/netmgr_common.h @@ -42,6 +42,9 @@ extern isc_tlsctx_t *tcp_listen_tlsctx; extern isc_tlsctx_t *tcp_connect_tlsctx; extern isc_tlsctx_client_session_cache_t *tcp_tlsctx_client_sess_cache; +extern isc_sockaddr_t udp_listen_addr; +extern isc_sockaddr_t udp_connect_addr; + extern uint64_t send_magic; extern uint64_t stop_magic; @@ -432,3 +435,111 @@ proxystreamtls_shutdownread_teardown(void **state); void stop_listening(void *arg ISC_ATTR_UNUSED); + +/* UDP */ + +/* Timeout for soft-timeout tests (0.05 seconds) */ +#define UDP_T_SOFT 50 + +/* Timeouts in miliseconds */ +#define UDP_T_INIT 120 * 1000 +#define UDP_T_IDLE 120 * 1000 +#define UDP_T_KEEPALIVE 120 * 1000 +#define UDP_T_ADVERTISED 120 * 1000 +#define UDP_T_CONNECT 30 * 1000 + +int +setup_udp_test(void **state); + +int +teardown_udp_test(void **state); + +int +udp_noop_setup(void **state); + +int +udp_noop_teardown(void **state); + +void +udp_noop(void **arg ISC_ATTR_UNUSED); + +int +udp_noresponse_setup(void **state); + +int +udp_noresponse_teardown(void **state); + +void +udp_noresponse(void **arg ISC_ATTR_UNUSED); + +int +udp_timeout_recovery_setup(void **state); + +int +udp_timeout_recovery_teardown(void **state); + +void +udp_timeout_recovery(void **arg ISC_ATTR_UNUSED); + +int +udp_shutdown_connect_setup(void **state); + +int +udp_shutdown_connect_teardown(void **state); + +void +udp_shutdown_connect(void **arg ISC_ATTR_UNUSED); + +int +udp_shutdown_read_setup(void **state); + +int +udp_shutdown_read_teardown(void **state); + +void +udp_shutdown_read(void **arg ISC_ATTR_UNUSED); + +int +udp_cancel_read_setup(void **state); + +int +udp_cancel_read_teardown(void **state); + +void +udp_cancel_read(void **arg ISC_ATTR_UNUSED); + +int +udp_recv_one_setup(void **state); + +int +udp_recv_one_teardown(void **state); + +void +udp_recv_one(void **arg ISC_ATTR_UNUSED); + +int +udp_recv_two_setup(void **state); + +int +udp_recv_two_teardown(void **state); + +void +udp_recv_two(void **arg ISC_ATTR_UNUSED); + +int +udp_recv_send_setup(void **state); + +int +udp_recv_send_teardown(void **state); + +void +udp_recv_send(void **arg ISC_ATTR_UNUSED); + +int +udp_double_read_setup(void **state); + +int +udp_double_read_teardown(void **state); + +void +udp_double_read(void **arg ISC_ATTR_UNUSED); diff --git a/tests/isc/udp_test.c b/tests/isc/udp_test.c index 3ede5a29f1..610139b96a 100644 --- a/tests/isc/udp_test.c +++ b/tests/isc/udp_test.c @@ -49,81 +49,6 @@ #include -static isc_sockaddr_t udp_listen_addr; -static isc_sockaddr_t udp_connect_addr; - -/* Timeout for soft-timeout tests (0.05 seconds) */ -#define T_SOFT 50 - -/* Timeouts in miliseconds */ -#define T_INIT 120 * 1000 -#define T_IDLE 120 * 1000 -#define T_KEEPALIVE 120 * 1000 -#define T_ADVERTISED 120 * 1000 -#define T_CONNECT 30 * 1000 - -static int -setup_test(void **state) { - setup_loopmgr(state); - setup_netmgr(state); - - udp_connect_addr = (isc_sockaddr_t){ .length = 0 }; - isc_sockaddr_fromin6(&udp_connect_addr, &in6addr_loopback, 0); - - udp_listen_addr = (isc_sockaddr_t){ .length = 0 }; - isc_sockaddr_fromin6(&udp_listen_addr, &in6addr_loopback, - UDP_TEST_PORT); - - atomic_store(&sreads, 0); - atomic_store(&ssends, 0); - - atomic_store(&cconnects, 0); - atomic_store(&csends, 0); - atomic_store(&creads, 0); - atomic_store(&ctimeouts, 0); - - isc_refcount_init(&active_cconnects, 0); - isc_refcount_init(&active_csends, 0); - isc_refcount_init(&active_creads, 0); - isc_refcount_init(&active_ssends, 0); - isc_refcount_init(&active_sreads, 0); - - expected_cconnects = -1; - expected_csends = -1; - expected_creads = -1; - expected_sreads = -1; - expected_ssends = -1; - expected_ctimeouts = -1; - - ssends_shutdown = true; - sreads_shutdown = true; - csends_shutdown = true; - cconnects_shutdown = true; - creads_shutdown = true; - - isc_nonce_buf(&send_magic, sizeof(send_magic)); - - connect_readcb = connect_read_cb; - - return (0); -} - -static int -teardown_test(void **state) { - UNUSED(state); - - isc_refcount_destroy(&active_cconnects); - isc_refcount_destroy(&active_csends); - isc_refcount_destroy(&active_creads); - isc_refcount_destroy(&active_ssends); - isc_refcount_destroy(&active_sreads); - - teardown_netmgr(state); - teardown_loopmgr(state); - - return (0); -} - /* Callbacks */ static void @@ -136,16 +61,8 @@ mock_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region, } static void -udp_listen_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - if (eresult != ISC_R_SUCCESS) { - isc_refcount_increment0(&active_sreads); - } - listen_read_cb(handle, eresult, region, cbarg); -} - -static void -connect_nomemory_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { +udp_connect_nomemory_cb(isc_nmhandle_t *handle, isc_result_t eresult, + void *cbarg) { UNUSED(handle); UNUSED(cbarg); @@ -155,15 +72,6 @@ connect_nomemory_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { isc_loopmgr_shutdown(loopmgr); } -static void -start_listening(uint32_t nworkers, isc_nm_recv_cb_t cb) { - isc_result_t result = isc_nm_listenudp( - netmgr, nworkers, &udp_listen_addr, cb, NULL, &listen_sock); - assert_int_equal(result, ISC_R_SUCCESS); - - isc_loop_teardown(mainloop, stop_listening, listen_sock); -} - /* UDP */ ISC_LOOP_TEST_IMPL(mock_listenudp_uv_udp_open) { @@ -216,7 +124,7 @@ ISC_LOOP_TEST_IMPL(mock_udpconnect_uv_udp_open) { isc_refcount_increment0(&active_cconnects); isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_nomemory_cb, NULL, T_CONNECT); + udp_connect_nomemory_cb, NULL, UDP_T_CONNECT); isc_loopmgr_shutdown(loopmgr); RESET_RETURN; @@ -227,7 +135,7 @@ ISC_LOOP_TEST_IMPL(mock_udpconnect_uv_udp_bind) { isc_refcount_increment0(&active_cconnects); isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_nomemory_cb, NULL, T_CONNECT); + udp_connect_nomemory_cb, NULL, UDP_T_CONNECT); isc_loopmgr_shutdown(loopmgr); RESET_RETURN; @@ -238,7 +146,7 @@ ISC_LOOP_TEST_IMPL(mock_udpconnect_uv_udp_connect) { isc_refcount_increment0(&active_cconnects); isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_nomemory_cb, NULL, T_CONNECT); + udp_connect_nomemory_cb, NULL, UDP_T_CONNECT); isc_loopmgr_shutdown(loopmgr); RESET_RETURN; @@ -249,7 +157,7 @@ ISC_LOOP_TEST_IMPL(mock_udpconnect_uv_recv_buffer_size) { isc_refcount_increment0(&active_cconnects); isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_success_cb, NULL, T_CONNECT); + connect_success_cb, NULL, UDP_T_CONNECT); isc_loopmgr_shutdown(loopmgr); RESET_RETURN; @@ -260,969 +168,68 @@ ISC_LOOP_TEST_IMPL(mock_udpconnect_uv_send_buffer_size) { isc_refcount_increment0(&active_cconnects); isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_success_cb, NULL, T_CONNECT); + connect_success_cb, NULL, UDP_T_CONNECT); isc_loopmgr_shutdown(loopmgr); RESET_RETURN; } -ISC_SETUP_TEST_IMPL(udp_noop) { - setup_test(state); - expected_cconnects = 1; - cconnects_shutdown = true; - return (0); -} +ISC_LOOP_TEST_IMPL(udp_noop) { udp_noop(arg); } -ISC_TEARDOWN_TEST_IMPL(udp_noop) { - atomic_assert_int_eq(cconnects, 1); - teardown_test(state); - return (0); -} +ISC_LOOP_TEST_IMPL(udp_noresponse) { udp_noresponse(arg); } -ISC_LOOP_TEST_IMPL(udp_noop) { - /* isc_result_t result = ISC_R_SUCCESS; */ +ISC_LOOP_TEST_IMPL(udp_timeout_recovery) { udp_timeout_recovery(arg); } - /* result = isc_nm_listenudp(netmgr, ISC_NM_LISTEN_ALL, - * &udp_listen_addr, */ - /* mock_recv_cb, NULL, &listen_sock); */ - /* assert_int_equal(result, ISC_R_SUCCESS); */ +ISC_LOOP_TEST_IMPL(udp_shutdown_connect) { udp_shutdown_connect(arg); } - /* isc_nm_stoplistening(listen_sock); */ - /* isc_nmsocket_close(&listen_sock); */ - /* assert_null(listen_sock); */ +ISC_LOOP_TEST_IMPL(udp_shutdown_read) { udp_shutdown_read(arg); } - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - connect_success_cb, NULL, T_CONNECT); -} +ISC_LOOP_TEST_IMPL(udp_cancel_read) { udp_cancel_read(arg); } -static void -udp_noresponse_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - UNUSED(handle); - UNUSED(eresult); - UNUSED(region); - UNUSED(cbarg); -} +ISC_LOOP_TEST_IMPL(udp_recv_one) { udp_recv_one(arg); } -static void -udp_noresponse_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - UNUSED(region); - UNUSED(cbarg); +ISC_LOOP_TEST_IMPL(udp_recv_two) { udp_recv_two(arg); } - assert_int_equal(eresult, ISC_R_TIMEDOUT); +ISC_LOOP_TEST_IMPL(udp_recv_send) { udp_recv_send(arg); } - isc_refcount_decrement(&active_creads); - - atomic_fetch_add(&creads, 1); - - isc_nmhandle_detach(&handle); - - isc_loopmgr_shutdown(loopmgr); -} - -static void -udp_noresponse_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(cbarg); - - assert_non_null(handle); - assert_int_equal(eresult, ISC_R_SUCCESS); - atomic_fetch_add(&csends, 1); - isc_nmhandle_detach(&handle); - isc_refcount_decrement(&active_csends); -} - -static void -udp_noresponse_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - isc_nmhandle_t *readhandle = NULL; - isc_nmhandle_t *sendhandle = NULL; - - isc_refcount_decrement(&active_cconnects); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - /* Read */ - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, udp_noresponse_read_cb, cbarg); - - /* Send */ - isc_refcount_increment0(&active_csends); - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(handle, T_IDLE); - - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, - udp_noresponse_send_cb, cbarg); - - atomic_fetch_add(&cconnects, 1); -} - -ISC_SETUP_TEST_IMPL(udp_noresponse) { - setup_test(state); - expected_csends = 1; - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_noresponse) { - atomic_assert_int_eq(csends, expected_csends); - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_noresponse) { - start_listening(ISC_NM_LISTEN_ONE, udp_noresponse_recv_cb); - - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp_noresponse_connect_cb, listen_sock, T_SOFT); -} - -static void -udp_timeout_recovery_ssend_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(cbarg); - - isc_refcount_decrement(&active_ssends); - assert_non_null(handle); - assert_int_equal(eresult, ISC_R_SUCCESS); - atomic_fetch_add(&ssends, 1); - isc_nmhandle_detach(&handle); -} - -static void -udp_timeout_recovery_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - isc_nmhandle_t *sendhandle = NULL; - int _creads = atomic_fetch_add(&creads, 1) + 1; - - assert_non_null(handle); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - assert_true(region->length == sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - assert_true(magic == send_magic); - assert_true(_creads < 6); - - if (_creads == 5) { - isc_nmhandle_attach(handle, &sendhandle); - isc_refcount_increment0(&active_ssends); - isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, - udp_timeout_recovery_ssend_cb, cbarg); - } -} - -static void -udp_timeout_recovery_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - UNUSED(region); - UNUSED(cbarg); - - assert_non_null(handle); - - F(); - - if (eresult == ISC_R_TIMEDOUT && - atomic_fetch_add(&ctimeouts, 1) + 1 < expected_ctimeouts) - { - isc_nmhandle_settimeout(handle, T_SOFT); - return; - } - - isc_refcount_decrement(&active_creads); - isc_nmhandle_detach(&handle); - - atomic_fetch_add(&creads, 1); - isc_loopmgr_shutdown(loopmgr); -} - -static void -udp_timeout_recovery_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(cbarg); - - assert_non_null(handle); - assert_int_equal(eresult, ISC_R_SUCCESS); - atomic_fetch_add(&csends, 1); - - isc_nmhandle_detach(&handle); - isc_refcount_decrement(&active_csends); -} - -static void -udp_timeout_recovery_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - isc_nmhandle_t *readhandle = NULL; - isc_nmhandle_t *sendhandle = NULL; - - F(); - - isc_refcount_decrement(&active_cconnects); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - /* Read */ - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, udp_timeout_recovery_read_cb, cbarg); - - /* Send */ - isc_refcount_increment0(&active_csends); - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(handle, T_IDLE); - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, - udp_timeout_recovery_send_cb, cbarg); - - atomic_fetch_add(&cconnects, 1); -} - -ISC_SETUP_TEST_IMPL(udp_timeout_recovery) { - setup_test(state); - expected_cconnects = 1; - expected_csends = 1; - expected_creads = 1; - expected_ctimeouts = 4; - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_timeout_recovery) { - atomic_assert_int_eq(cconnects, expected_cconnects); - atomic_assert_int_eq(csends, expected_csends); - atomic_assert_int_eq(csends, expected_creads); - atomic_assert_int_eq(ctimeouts, expected_ctimeouts); - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_timeout_recovery) { - /* - * Listen using the noop callback so that client reads will time out. - */ - start_listening(ISC_NM_LISTEN_ONE, udp_timeout_recovery_recv_cb); - - /* - * Connect with client timeout set to 0.05 seconds, then sleep for at - * least a second for each 'tick'. timeout_retry_cb() will give up - * after five timeouts. - */ - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp_timeout_recovery_connect_cb, listen_sock, T_SOFT); -} - -static void -udp_connect_udpconnect(void *arg ISC_ATTR_UNUSED); - -static void -udp_shutdown_connect_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(handle); - UNUSED(cbarg); - - isc_refcount_decrement(&active_cconnects); - - /* - * The first UDP connect is faster than asynchronous shutdown procedure, - * restart the UDP connect again and expect the failure only in the - * second loop. - */ - if (atomic_fetch_add(&cconnects, 1) == 0) { - assert_int_equal(eresult, ISC_R_SUCCESS); - isc_async_current(loopmgr, udp_connect_udpconnect, netmgr); - } else { - assert_int_equal(eresult, ISC_R_SHUTTINGDOWN); - } -} - -static void -udp_connect_udpconnect(void *arg ISC_ATTR_UNUSED) { - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp_shutdown_connect_connect_cb, NULL, T_SOFT); -} - -ISC_SETUP_TEST_IMPL(udp_shutdown_connect) { - setup_test(state); - expected_cconnects = 2; - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_shutdown_connect) { - atomic_assert_int_eq(cconnects, expected_cconnects); - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_shutdown_connect) { - isc_loopmgr_shutdown(loopmgr); - /* - * isc_nm_udpconnect() is synchronous, so we need to launch this on the - * async loop. - */ - isc_async_current(loopmgr, udp_connect_udpconnect, netmgr); -} - -static void -udp_shutdown_read_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - - UNUSED(cbarg); - - assert_non_null(handle); - - F(); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - assert_true(region->length == sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - assert_true(magic == send_magic); -} - -static void -udp_shutdown_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(cbarg); - - F(); - - assert_non_null(handle); - assert_int_equal(eresult, ISC_R_SUCCESS); - - atomic_fetch_add(&csends, 1); - - isc_loopmgr_shutdown(loopmgr); - - isc_nmhandle_detach(&handle); - isc_refcount_decrement(&active_csends); -} - -static void -udp_shutdown_read_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - UNUSED(region); - UNUSED(cbarg); - - assert_true(eresult == ISC_R_SHUTTINGDOWN || eresult == ISC_R_TIMEDOUT); - - isc_refcount_decrement(&active_creads); - - atomic_fetch_add(&creads, 1); - - isc_nmhandle_detach(&handle); -} - -static void -udp_shutdown_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - isc_nmhandle_t *readhandle = NULL; - isc_nmhandle_t *sendhandle = NULL; - - isc_refcount_decrement(&active_cconnects); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - /* Read */ - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, udp_shutdown_read_read_cb, cbarg); - assert_true(handle->sock->reading); - - /* Send */ - isc_refcount_increment0(&active_csends); - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(handle, T_IDLE); - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, - udp_shutdown_read_send_cb, cbarg); - - atomic_fetch_add(&cconnects, 1); -} - -ISC_SETUP_TEST_IMPL(udp_shutdown_read) { - setup_test(state); - expected_cconnects = 1; - expected_creads = 1; - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_shutdown_read) { - atomic_assert_int_eq(cconnects, expected_cconnects); - atomic_assert_int_eq(creads, expected_creads); - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_shutdown_read) { - start_listening(ISC_NM_LISTEN_ONE, udp_shutdown_read_recv_cb); - - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp_shutdown_read_connect_cb, NULL, T_SOFT); -} - -static void -udp_cancel_read_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - - UNUSED(cbarg); - - assert_non_null(handle); - - F(); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - assert_true(region->length == sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - assert_true(magic == send_magic); -} - -static void -udp_cancel_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - UNUSED(cbarg); - - F(); - - assert_non_null(handle); - assert_int_equal(eresult, ISC_R_SUCCESS); - - atomic_fetch_add(&csends, 1); - - isc_nm_cancelread(handle); - - isc_nmhandle_detach(&handle); - isc_refcount_decrement(&active_csends); -} - -static void -udp_cancel_read_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - isc_nmhandle_t *sendhandle = NULL; - isc_nmhandle_t *readhandle = NULL; - - UNUSED(region); - - F(); - - switch (eresult) { - case ISC_R_TIMEDOUT: - - /* Read again */ - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, udp_cancel_read_read_cb, cbarg); - - /* Send only once */ - if (isc_refcount_increment0(&active_csends) == 0) { - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(handle, T_IDLE); - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, - udp_cancel_read_send_cb, cbarg); - } - break; - case ISC_R_CANCELED: - /* The read has been canceled */ - atomic_fetch_add(&creads, 1); - isc_loopmgr_shutdown(loopmgr); - break; - default: - UNREACHABLE(); - } - - isc_refcount_decrement(&active_creads); - - isc_nmhandle_detach(&handle); -} - -static void -udp_cancel_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, - void *cbarg) { - isc_nmhandle_t *readhandle = NULL; - - isc_refcount_decrement(&active_cconnects); - - assert_int_equal(eresult, ISC_R_SUCCESS); - - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, udp_cancel_read_read_cb, cbarg); - - atomic_fetch_add(&cconnects, 1); -} - -ISC_SETUP_TEST_IMPL(udp_cancel_read) { - setup_test(state); - expected_cconnects = 1; - expected_creads = 1; - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_cancel_read) { - atomic_assert_int_eq(cconnects, expected_cconnects); - atomic_assert_int_eq(creads, expected_creads); - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_cancel_read) { - start_listening(ISC_NM_LISTEN_ONE, udp_cancel_read_recv_cb); - - isc_refcount_increment0(&active_cconnects); - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp_cancel_read_connect_cb, NULL, T_SOFT); -} - -static void -udp__send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { - isc_nmhandle_t *sendhandle = handle; - - assert_non_null(sendhandle); - - F(); - - switch (eresult) { - case ISC_R_SUCCESS: - if (have_expected_csends(atomic_fetch_add(&csends, 1) + 1)) { - if (csends_shutdown) { - isc_nm_cancelread(handle); - isc_loopmgr_shutdown(loopmgr); - } - } - break; - case ISC_R_SHUTTINGDOWN: - case ISC_R_CANCELED: - break; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } - - isc_nmhandle_detach(&sendhandle); - isc_refcount_decrement(&active_csends); -} - -static void -udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg); -static void -udp__connect(void *arg ISC_ATTR_UNUSED) { - isc_sockaddr_t connect_addr; - - connect_addr = (isc_sockaddr_t){ .length = 0 }; - isc_sockaddr_fromin6(&connect_addr, &in6addr_loopback, 0); - - isc_refcount_increment0(&active_cconnects); - - isc_nm_udpconnect(netmgr, &udp_connect_addr, &udp_listen_addr, - udp__connect_cb, NULL, T_CONNECT); -} - -static void -udp__connect_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - - assert_non_null(handle); - - F(); - - switch (eresult) { - case ISC_R_TIMEDOUT: - /* - * We are operating on the localhost, UDP cannot get lost, but - * it could be delayed, so we read again until we get the - * answer. - */ - isc_nm_read(handle, connect_readcb, cbarg); - return; - case ISC_R_SUCCESS: - assert_true(region->length >= sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - - assert_true(magic == send_magic); - - if (have_expected_creads(atomic_fetch_add(&creads, 1) + 1)) { - do_creads_shutdown(loopmgr); - } - - if (magic == send_magic && allow_send_back) { - connect_send(handle); - return; - } - - break; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } - - isc_refcount_decrement(&active_creads); - - isc_nmhandle_detach(&handle); -} - -static void -udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { - isc_nmhandle_t *readhandle = NULL; - isc_nmhandle_t *sendhandle = NULL; - - F(); - - isc_refcount_decrement(&active_cconnects); - - switch (eresult) { - case ISC_R_SUCCESS: - if (have_expected_cconnects(atomic_fetch_add(&cconnects, 1) + - 1)) - { - do_cconnects_shutdown(loopmgr); - } else if (do_send) { - isc_async_current(loopmgr, udp__connect, cbarg); - } - - isc_refcount_increment0(&active_creads); - isc_nmhandle_attach(handle, &readhandle); - isc_nm_read(handle, connect_readcb, cbarg); - - isc_refcount_increment0(&active_csends); - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(handle, T_IDLE); - - isc_nm_send(sendhandle, (isc_region_t *)&send_msg, udp__send_cb, - cbarg); - - break; - case ISC_R_ADDRINUSE: - /* Try again */ - udp__connect(NULL); - break; - case ISC_R_SHUTTINGDOWN: - case ISC_R_CANCELED: - break; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } -} - -ISC_SETUP_TEST_IMPL(udp_recv_one) { - setup_test(state); - - connect_readcb = udp__connect_read_cb; - - expected_cconnects = 1; - cconnects_shutdown = false; - - expected_csends = 1; - csends_shutdown = false; - - expected_sreads = 1; - sreads_shutdown = false; - - expected_ssends = 1; - ssends_shutdown = false; - - expected_creads = 1; - creads_shutdown = true; - - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_recv_one) { - atomic_assert_int_eq(cconnects, expected_cconnects); - atomic_assert_int_eq(csends, expected_csends); - atomic_assert_int_eq(sreads, expected_sreads); - atomic_assert_int_eq(ssends, expected_ssends); - atomic_assert_int_eq(creads, expected_creads); - - teardown_test(state); - - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_recv_one) { - start_listening(ISC_NM_LISTEN_ONE, udp_listen_read_cb); - - udp__connect(NULL); -} - -ISC_SETUP_TEST_IMPL(udp_recv_two) { - setup_test(state); - - connect_readcb = udp__connect_read_cb; - - expected_cconnects = 2; - cconnects_shutdown = false; - - expected_csends = 2; - csends_shutdown = false; - - expected_sreads = 2; - sreads_shutdown = false; - - expected_ssends = 2; - ssends_shutdown = false; - - expected_creads = 2; - creads_shutdown = true; - - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_recv_two) { - atomic_assert_int_eq(cconnects, expected_cconnects); - atomic_assert_int_eq(csends, expected_csends); - atomic_assert_int_eq(sreads, expected_sreads); - atomic_assert_int_eq(ssends, expected_ssends); - atomic_assert_int_eq(creads, expected_creads); - - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_recv_two) { - start_listening(ISC_NM_LISTEN_ONE, udp_listen_read_cb); - - udp__connect(NULL); - udp__connect(NULL); -} - -ISC_SETUP_TEST_IMPL(udp_recv_send) { - setup_test(state); - - /* Allow some leeway (+1) as datagram service is unreliable */ - expected_cconnects = (workers + 1) * NSENDS; - cconnects_shutdown = false; - - expected_creads = workers * NSENDS; - do_send = true; - - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_recv_send) { - atomic_assert_int_ge(cconnects, expected_creads); - atomic_assert_int_ge(csends, expected_creads); - atomic_assert_int_ge(sreads, expected_creads); - atomic_assert_int_ge(ssends, expected_creads); - atomic_assert_int_ge(creads, expected_creads); - - teardown_test(state); - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_recv_send) { - start_listening(ISC_NM_LISTEN_ALL, udp_listen_read_cb); - - for (size_t i = 0; i < workers; i++) { - isc_async_run(isc_loop_get(loopmgr, i), udp__connect, NULL); - } -} - -static void -double_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) { - assert_non_null(handle); - - F(); - - isc_refcount_decrement(&active_ssends); - - switch (eresult) { - case ISC_R_SUCCESS: - if (have_expected_ssends(atomic_fetch_add(&ssends, 1) + 1)) { - do_ssends_shutdown(loopmgr); - } else { - isc_nmhandle_t *sendhandle = NULL; - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); - isc_refcount_increment0(&active_ssends); - isc_nm_send(sendhandle, &send_msg, double_read_send_cb, - cbarg); - break; - } - break; - case ISC_R_CANCELED: - break; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } - - isc_nmhandle_detach(&handle); -} - -static void -double_read_listen_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - - assert_non_null(handle); - - F(); - - switch (eresult) { - case ISC_R_EOF: - case ISC_R_SHUTTINGDOWN: - case ISC_R_CANCELED: - break; - case ISC_R_SUCCESS: - memmove(&magic, region->base, sizeof(magic)); - assert_true(magic == send_magic); - - assert_true(region->length >= sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - assert_true(magic == send_magic); - - isc_nmhandle_t *sendhandle = NULL; - isc_nmhandle_attach(handle, &sendhandle); - isc_nmhandle_setwritetimeout(sendhandle, T_IDLE); - isc_refcount_increment0(&active_ssends); - isc_nm_send(sendhandle, &send_msg, double_read_send_cb, cbarg); - return; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } - - isc_refcount_decrement(&active_sreads); - - isc_nmhandle_detach(&handle); -} - -static void -double_read_cb(isc_nmhandle_t *handle, isc_result_t eresult, - isc_region_t *region, void *cbarg) { - uint64_t magic = 0; - bool detach = false; - - assert_non_null(handle); - - F(); - - switch (eresult) { - case ISC_R_TIMEDOUT: - /* - * We are operating on the localhost, UDP cannot get lost, but - * it could be delayed, so we read again until we get the - * answer. - */ - detach = false; - break; - case ISC_R_SUCCESS: - assert_true(region->length >= sizeof(magic)); - - memmove(&magic, region->base, sizeof(magic)); - - assert_true(magic == send_magic); - - if (have_expected_creads(atomic_fetch_add(&creads, 1) + 1)) { - do_creads_shutdown(loopmgr); - detach = true; - } - - if (magic == send_magic && allow_send_back) { - connect_send(handle); - return; - } - - break; - case ISC_R_EOF: - case ISC_R_SHUTTINGDOWN: - case ISC_R_CANCELED: - case ISC_R_CONNECTIONRESET: - detach = true; - break; - default: - fprintf(stderr, "%s(%p, %s, %p)\n", __func__, handle, - isc_result_totext(eresult), cbarg); - assert_int_equal(eresult, ISC_R_SUCCESS); - } - - if (detach) { - isc_refcount_decrement(&active_creads); - isc_nmhandle_detach(&handle); - } else { - isc_nm_read(handle, connect_readcb, cbarg); - } -} - -ISC_SETUP_TEST_IMPL(udp_double_read) { - setup_test(state); - - expected_cconnects = 1; - cconnects_shutdown = false; - - expected_csends = 1; - csends_shutdown = false; - - expected_sreads = 1; - sreads_shutdown = false; - - expected_ssends = 2; - ssends_shutdown = false; - - expected_creads = 2; - creads_shutdown = true; - - connect_readcb = double_read_cb; - - return (0); -} - -ISC_TEARDOWN_TEST_IMPL(udp_double_read) { - atomic_assert_int_eq(creads, expected_creads); - - teardown_test(state); - - return (0); -} - -ISC_LOOP_TEST_IMPL(udp_double_read) { - start_listening(ISC_NM_LISTEN_ALL, double_read_listen_cb); - - udp__connect(NULL); -} +ISC_LOOP_TEST_IMPL(udp_double_read) { udp_double_read(arg); } ISC_TEST_LIST_START -ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_open, setup_test, teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_bind, setup_test, teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_recv_start, setup_test, - teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_open, setup_test, teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_bind, setup_test, teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_connect, setup_test, teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_recv_buffer_size, setup_test, - teardown_test) -ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_send_buffer_size, setup_test, - teardown_test) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_noop) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_noresponse) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_shutdown_connect) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_shutdown_read) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_cancel_read) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_timeout_recovery) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_double_read) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_recv_one) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_recv_two) -ISC_TEST_ENTRY_SETUP_TEARDOWN(udp_recv_send) +ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_open, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_bind, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_listenudp_uv_udp_recv_start, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_open, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_bind, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_udp_connect, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_recv_buffer_size, setup_udp_test, + teardown_udp_test) +ISC_TEST_ENTRY_CUSTOM(mock_udpconnect_uv_send_buffer_size, setup_udp_test, + teardown_udp_test) + +ISC_TEST_ENTRY_CUSTOM(udp_noop, udp_noop_setup, udp_noop_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_noresponse, udp_noresponse_setup, + udp_noresponse_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_timeout_recovery, udp_timeout_recovery_setup, + udp_timeout_recovery_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_shutdown_read, udp_shutdown_read_setup, + udp_shutdown_read_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_cancel_read, udp_cancel_read_setup, + udp_cancel_read_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_shutdown_connect, udp_shutdown_connect_setup, + udp_shutdown_connect_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_double_read, udp_double_read_setup, + udp_double_read_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_recv_one, udp_recv_one_setup, udp_recv_one_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_recv_two, udp_recv_two_setup, udp_recv_two_teardown) +ISC_TEST_ENTRY_CUSTOM(udp_recv_send, udp_recv_send_setup, + udp_recv_send_teardown) ISC_TEST_LIST_END