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