mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 14:07:59 +00:00
Merge branch '3545-prevent-unexpected-client-read-callbacks' into 'main'
Prevent unexpected UDP client read callbacks Closes #3545 See merge request isc-projects/bind9!6777
This commit is contained in:
commit
88f6f30c3d
3
CHANGES
3
CHANGES
@ -1,3 +1,6 @@
|
||||
5974. [bug] Fix an assertion failure in dispatch caused by
|
||||
extra read callback call. [GL #3545]
|
||||
|
||||
5973. [bug] Fixed a possible invalid detach in UPDATE
|
||||
processing. [GL #3522]
|
||||
|
||||
|
@ -297,7 +297,6 @@ typedef enum isc__netievent_type {
|
||||
|
||||
netievent_udplisten,
|
||||
netievent_udpstop,
|
||||
netievent_udpread,
|
||||
|
||||
netievent_tcplisten,
|
||||
netievent_tcpstop,
|
||||
@ -1313,8 +1312,6 @@ void
|
||||
isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_udpcancel(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
void
|
||||
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0);
|
||||
/*%<
|
||||
* Callback handlers for asynchronous UDP events (listen, stoplisten, send).
|
||||
*/
|
||||
@ -1834,7 +1831,6 @@ NETIEVENT_SOCKET_TYPE(tlsstartread);
|
||||
NETIEVENT_SOCKET_HANDLE_TYPE(tlscancel);
|
||||
NETIEVENT_SOCKET_TYPE(udplisten);
|
||||
NETIEVENT_SOCKET_TYPE(udpstop);
|
||||
NETIEVENT_SOCKET_TYPE(udpread);
|
||||
|
||||
NETIEVENT_SOCKET_TYPE(tcpdnsclose);
|
||||
NETIEVENT_SOCKET_TYPE(tcpdnsread);
|
||||
@ -1893,7 +1889,6 @@ NETIEVENT_SOCKET_DECL(tlsstartread);
|
||||
NETIEVENT_SOCKET_HANDLE_DECL(tlscancel);
|
||||
NETIEVENT_SOCKET_DECL(udplisten);
|
||||
NETIEVENT_SOCKET_DECL(udpstop);
|
||||
NETIEVENT_SOCKET_DECL(udpread);
|
||||
|
||||
NETIEVENT_SOCKET_DECL(tcpdnsclose);
|
||||
NETIEVENT_SOCKET_DECL(tcpdnsread);
|
||||
|
@ -449,7 +449,6 @@ process_netievent(void *arg) {
|
||||
NETIEVENT_CASE(udplisten);
|
||||
NETIEVENT_CASE(udpstop);
|
||||
NETIEVENT_CASE(udpcancel);
|
||||
NETIEVENT_CASE(udpread);
|
||||
|
||||
NETIEVENT_CASE(tcpaccept);
|
||||
NETIEVENT_CASE(tcpconnect);
|
||||
@ -536,7 +535,6 @@ NETIEVENT_SOCKET_HANDLE_DEF(tlscancel);
|
||||
NETIEVENT_SOCKET_DEF(udplisten);
|
||||
NETIEVENT_SOCKET_DEF(udpstop);
|
||||
NETIEVENT_SOCKET_HANDLE_DEF(udpcancel);
|
||||
NETIEVENT_SOCKET_DEF(udpread);
|
||||
|
||||
NETIEVENT_SOCKET_DEF(tcpdnsclose);
|
||||
NETIEVENT_SOCKET_DEF(tcpdnsread);
|
||||
|
@ -59,10 +59,6 @@
|
||||
#endif /* if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) \
|
||||
*/
|
||||
|
||||
static void
|
||||
udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
const struct sockaddr *addr, unsigned flags);
|
||||
|
||||
static void
|
||||
udp_send_cb(uv_udp_send_t *req, int status);
|
||||
|
||||
@ -413,7 +409,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__nm_set_network_buffers(mgr, &sock->uv_handle.handle);
|
||||
|
||||
r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
|
||||
udp_recv_cb);
|
||||
isc__nm_udp_read_cb);
|
||||
if (r != 0) {
|
||||
isc__nm_incstats(sock, STATID_BINDFAIL);
|
||||
goto done;
|
||||
@ -511,9 +507,9 @@ isc__nm_async_udpstop(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
* reused for a series of packets, so we need to allocate a new one.
|
||||
* This new one can be reused to send the response then.
|
||||
*/
|
||||
static void
|
||||
udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
const struct sockaddr *addr, unsigned flags) {
|
||||
void
|
||||
isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
const struct sockaddr *addr, unsigned flags) {
|
||||
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
|
||||
isc__nm_uvreq_t *req = NULL;
|
||||
uint32_t maxudp;
|
||||
@ -562,15 +558,6 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
goto free;
|
||||
}
|
||||
|
||||
/*
|
||||
* - If addr == NULL, in which case it's the end of stream;
|
||||
* we can free the buffer and bail.
|
||||
*/
|
||||
if (addr == NULL) {
|
||||
isc__nm_failed_read_cb(sock, ISC_R_EOF, false);
|
||||
goto free;
|
||||
}
|
||||
|
||||
/*
|
||||
* - If the network manager is shutting down
|
||||
*/
|
||||
@ -587,6 +574,23 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
goto free;
|
||||
}
|
||||
|
||||
/*
|
||||
* End of the current (iteration) datagram stream, just free the buffer.
|
||||
* The callback with nrecv == 0 and addr == NULL is called for both
|
||||
* normal UDP sockets and recvmmsg sockets at the end of every event
|
||||
* loop iteration.
|
||||
*/
|
||||
if (nrecv == 0 && addr == NULL) {
|
||||
INSIST(flags == 0);
|
||||
goto free;
|
||||
}
|
||||
|
||||
/*
|
||||
* We could receive an empty datagram in which case:
|
||||
* nrecv == 0 and addr != NULL
|
||||
*/
|
||||
INSIST(addr != NULL);
|
||||
|
||||
if (!sock->route_sock) {
|
||||
result = isc_sockaddr_fromsockaddr(&sockaddr, addr);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
@ -604,6 +608,16 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
|
||||
sock->recv_read = false;
|
||||
|
||||
/*
|
||||
* The client isc_nm_read() expects just a single message, so we need to
|
||||
* stop reading now. The reading could be restarted in the read
|
||||
* callback with another isc_nm_read() call.
|
||||
*/
|
||||
if (atomic_load(&sock->client)) {
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
isc__nm_stop_reading(sock);
|
||||
}
|
||||
|
||||
REQUIRE(!sock->processing);
|
||||
sock->processing = true;
|
||||
isc__nm_readcb(sock, req, ISC_R_SUCCESS);
|
||||
@ -870,31 +884,6 @@ isc_nm_udpconnect(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *peer,
|
||||
isc__nmsocket_detach(&sock);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
const struct sockaddr *addr, unsigned flags) {
|
||||
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(atomic_load(&sock->client));
|
||||
REQUIRE(sock->parent == NULL);
|
||||
|
||||
/*
|
||||
* This function can only be reached when calling isc_nm_read() on
|
||||
* a UDP client socket. There's no point calling isc_nm_read() on
|
||||
* a UDP listener socket; those are always reading.
|
||||
*
|
||||
* The reason why we stop the timer and the reading after calling the
|
||||
* callback is because there's a time window where a second UDP packet
|
||||
* might be received between isc__nm_stop_reading() call and
|
||||
* isc_nm_read() call from the callback and such UDP datagram would be
|
||||
* lost like tears in the rain.
|
||||
*/
|
||||
udp_recv_cb(handle, nrecv, buf, addr, flags);
|
||||
|
||||
isc__nmsocket_timer_stop(sock);
|
||||
isc__nm_stop_reading(sock);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
@ -940,23 +929,30 @@ isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Asynchronous 'udpread' call handler: start or resume reading on a
|
||||
* socket; pause reading and call the 'recv' callback after each
|
||||
* datagram.
|
||||
*/
|
||||
void
|
||||
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0;
|
||||
isc_nmsocket_t *sock = ievent->sock;
|
||||
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
UNUSED(worker);
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_udpsocket);
|
||||
REQUIRE(sock->statichandle == handle);
|
||||
REQUIRE(!sock->recv_read);
|
||||
REQUIRE(sock->tid == isc_tid());
|
||||
|
||||
if (isc__nm_closing(worker)) {
|
||||
/*
|
||||
* We need to initialize the callback before checking for shutdown
|
||||
* conditions, so the callback is always called even on error condition.
|
||||
*/
|
||||
sock->recv_cb = cb;
|
||||
sock->recv_cbarg = cbarg;
|
||||
sock->recv_read = true;
|
||||
|
||||
if (isc__nm_closing(sock->worker)) {
|
||||
result = ISC_R_SHUTTINGDOWN;
|
||||
goto fail;
|
||||
}
|
||||
@ -971,7 +967,7 @@ isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
isc__nmsocket_timer_start(sock);
|
||||
isc__nmsocket_timer_restart(sock);
|
||||
return;
|
||||
|
||||
fail:
|
||||
@ -979,35 +975,6 @@ fail:
|
||||
isc__nm_failed_read_cb(sock, result, false);
|
||||
}
|
||||
|
||||
void
|
||||
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
|
||||
isc_nmsocket_t *sock = NULL;
|
||||
|
||||
REQUIRE(VALID_NMHANDLE(handle));
|
||||
|
||||
sock = handle->sock;
|
||||
|
||||
REQUIRE(VALID_NMSOCK(sock));
|
||||
REQUIRE(sock->type == isc_nm_udpsocket);
|
||||
REQUIRE(sock->statichandle == handle);
|
||||
REQUIRE(!sock->recv_read);
|
||||
|
||||
sock->recv_cb = cb;
|
||||
sock->recv_cbarg = cbarg;
|
||||
sock->recv_read = true;
|
||||
|
||||
if (!atomic_load(&sock->reading) && sock->tid == isc_tid()) {
|
||||
isc__netievent_udpread_t ievent = { .sock = sock };
|
||||
isc__nm_async_udpread(sock->worker,
|
||||
(isc__netievent_t *)&ievent);
|
||||
} else {
|
||||
isc__netievent_udpread_t *ievent =
|
||||
isc__nm_get_netievent_udpread(sock->worker, sock);
|
||||
isc__nm_enqueue_ievent(sock->worker,
|
||||
(isc__netievent_t *)ievent);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
udp_close_cb(uv_handle_t *handle) {
|
||||
isc_nmsocket_t *sock = uv_handle_get_data(handle);
|
||||
|
@ -100,6 +100,8 @@ setup_test(void **state) {
|
||||
|
||||
isc_nonce_buf(&send_magic, sizeof(send_magic));
|
||||
|
||||
connect_readcb = connect_read_cb;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -304,7 +306,6 @@ udp_noresponse_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
static void
|
||||
udp_noresponse_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_region_t *region, void *cbarg) {
|
||||
UNUSED(handle);
|
||||
UNUSED(region);
|
||||
UNUSED(cbarg);
|
||||
|
||||
@ -337,9 +338,6 @@ udp_noresponse_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_nmhandle_t *readhandle = NULL;
|
||||
isc_nmhandle_t *sendhandle = NULL;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(cbarg);
|
||||
|
||||
isc_refcount_decrement(&active_cconnects);
|
||||
|
||||
assert_int_equal(eresult, ISC_R_SUCCESS);
|
||||
@ -461,8 +459,6 @@ udp_timeout_recovery_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_nmhandle_t *readhandle = NULL;
|
||||
isc_nmhandle_t *sendhandle = NULL;
|
||||
|
||||
UNUSED(cbarg);
|
||||
|
||||
F();
|
||||
|
||||
isc_refcount_decrement(&active_cconnects);
|
||||
@ -555,14 +551,50 @@ ISC_LOOP_TEST_IMPL(udp_shutdown_connect) {
|
||||
isc_job_run(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(handle);
|
||||
UNUSED(region);
|
||||
UNUSED(cbarg);
|
||||
|
||||
assert_int_equal(eresult, ISC_R_SHUTTINGDOWN);
|
||||
assert_true(eresult == ISC_R_SHUTTINGDOWN || eresult == ISC_R_TIMEDOUT);
|
||||
|
||||
isc_refcount_decrement(&active_creads);
|
||||
|
||||
@ -575,21 +607,25 @@ static void
|
||||
udp_shutdown_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
void *cbarg) {
|
||||
isc_nmhandle_t *readhandle = NULL;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(cbarg);
|
||||
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);
|
||||
|
||||
atomic_fetch_add(&cconnects, 1);
|
||||
/* 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);
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
atomic_fetch_add(&cconnects, 1);
|
||||
}
|
||||
|
||||
ISC_SETUP_TEST_IMPL(udp_shutdown_read) {
|
||||
@ -607,6 +643,8 @@ ISC_TEARDOWN_TEST_IMPL(udp_shutdown_read) {
|
||||
}
|
||||
|
||||
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);
|
||||
@ -616,7 +654,8 @@ 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;
|
||||
isc_nmhandle_t *sendhandle = NULL;
|
||||
|
||||
UNUSED(cbarg);
|
||||
|
||||
assert_non_null(handle);
|
||||
|
||||
@ -628,38 +667,6 @@ udp_cancel_read_recv_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
|
||||
memmove(&magic, region->base, sizeof(magic));
|
||||
assert_true(magic == send_magic);
|
||||
|
||||
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, listen_send_cb,
|
||||
cbarg);
|
||||
}
|
||||
|
||||
static void
|
||||
udp_cancel_read_read_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_region_t *region, void *cbarg) {
|
||||
UNUSED(handle);
|
||||
UNUSED(region);
|
||||
UNUSED(cbarg);
|
||||
|
||||
F();
|
||||
|
||||
switch (eresult) {
|
||||
case ISC_R_TIMEDOUT:
|
||||
case ISC_R_EOF:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
isc_refcount_decrement(&active_creads);
|
||||
|
||||
atomic_fetch_add(&creads, 1);
|
||||
|
||||
isc_nmhandle_detach(&handle);
|
||||
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -674,18 +681,56 @@ udp_cancel_read_send_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
|
||||
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 */
|
||||
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_cancel_read_send_cb, cbarg);
|
||||
break;
|
||||
case ISC_R_EOF:
|
||||
/* The read has been canceled */
|
||||
isc_loopmgr_shutdown(loopmgr);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
isc_refcount_decrement(&active_creads);
|
||||
|
||||
atomic_fetch_add(&creads, 1);
|
||||
|
||||
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_nmhandle_t *sendhandle = NULL;
|
||||
|
||||
UNUSED(handle);
|
||||
UNUSED(cbarg);
|
||||
|
||||
isc_refcount_decrement(&active_cconnects);
|
||||
|
||||
@ -695,22 +740,13 @@ udp_cancel_read_connect_cb(isc_nmhandle_t *handle, isc_result_t eresult,
|
||||
isc_nmhandle_attach(handle, &readhandle);
|
||||
isc_nm_read(handle, udp_cancel_read_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_cancel_read_send_cb, readhandle);
|
||||
|
||||
isc_nm_cancelread(readhandle);
|
||||
|
||||
atomic_fetch_add(&cconnects, 1);
|
||||
}
|
||||
|
||||
ISC_SETUP_TEST_IMPL(udp_cancel_read) {
|
||||
setup_test(state);
|
||||
expected_cconnects = 1;
|
||||
expected_creads = 1;
|
||||
expected_creads = 2;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -733,8 +769,6 @@ static void
|
||||
udp__send_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
|
||||
isc_nmhandle_t *sendhandle = handle;
|
||||
|
||||
UNUSED(cbarg);
|
||||
|
||||
assert_non_null(sendhandle);
|
||||
|
||||
F();
|
||||
@ -780,8 +814,6 @@ udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
|
||||
isc_nmhandle_t *readhandle = NULL;
|
||||
isc_nmhandle_t *sendhandle = NULL;
|
||||
|
||||
UNUSED(cbarg);
|
||||
|
||||
F();
|
||||
|
||||
isc_refcount_decrement(&active_cconnects);
|
||||
@ -797,7 +829,7 @@ udp__connect_cb(isc_nmhandle_t *handle, isc_result_t eresult, void *cbarg) {
|
||||
|
||||
isc_refcount_increment0(&active_creads);
|
||||
isc_nmhandle_attach(handle, &readhandle);
|
||||
isc_nm_read(handle, connect_read_cb, cbarg);
|
||||
isc_nm_read(handle, connect_readcb, cbarg);
|
||||
|
||||
isc_refcount_increment0(&active_csends);
|
||||
isc_nmhandle_attach(handle, &sendhandle);
|
||||
@ -931,6 +963,166 @@ ISC_LOOP_TEST_IMPL(udp_recv_send) {
|
||||
}
|
||||
}
|
||||
|
||||
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_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_TIMEDOUT:
|
||||
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_TEST_LIST_START
|
||||
|
||||
/* Mock tests are unreliable on OpenBSD */
|
||||
@ -956,6 +1148,7 @@ 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user