mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
Fix the UDP recvmmsg support
Previously, the netmgr/udp.c tried to detect the recvmmsg detection in libuv with #ifdef UV_UDP_<foo> preprocessor macros. However, because the UV_UDP_<foo> are not preprocessor macros, but enum members, the detection didn't work. Because the detection didn't work, the code didn't have access to the information when we received the final chunk of the recvmmsg and tried to free the uvbuf every time. Fortunately, the isc__nm_free_uvbuf() had a kludge that detected attempt to free in the middle of the receive buffer, so the code worked. However, libuv 1.37.0 changed the way the recvmmsg was enabled from implicit to explicit, and we checked for yet another enum member presence with preprocessor macro, so in fact libuv recvmmsg support was never enabled with libuv >= 1.37.0. This commit changes to the preprocessor macros to autoconf checks for declaration, so the detection now works again. On top of that, it's now possible to cleanup the alloc_cb and free_uvbuf functions because now, the information whether we can or cannot free the buffer is available to us.
This commit is contained in:
@@ -431,7 +431,7 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||||
REQUIRE(sock->parent != NULL);
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
|
||||
#ifdef UV_UDP_RECVMMSG
|
||||
#if HAVE_DECL_UV_UDP_RECVMMSG
|
||||
uv_init_flags |= UV_UDP_RECVMMSG;
|
||||
#endif
|
||||
r = uv_udp_init_ex(&worker->loop, &sock->uv_handle.udp, uv_init_flags);
|
||||
@@ -556,7 +556,6 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
|
||||
isc__nm_uvreq_t *req = NULL;
|
||||
uint32_t maxudp;
|
||||
bool free_buf;
|
||||
isc_result_t result;
|
||||
isc_sockaddr_t sockaddr, *sa = NULL;
|
||||
|
||||
@@ -564,19 +563,22 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
REQUIRE(sock->tid == isc_nm_tid());
|
||||
REQUIRE(atomic_load(&sock->reading));
|
||||
|
||||
#ifdef UV_UDP_MMSG_FREE
|
||||
free_buf = ((flags & UV_UDP_MMSG_FREE) == UV_UDP_MMSG_FREE);
|
||||
#elif UV_UDP_MMSG_CHUNK
|
||||
free_buf = ((flags & UV_UDP_MMSG_CHUNK) == 0);
|
||||
/*
|
||||
* When using recvmmsg(2), if no errors occur, there will be a final
|
||||
* callback with nrecv set to 0, addr set to NULL and the buffer
|
||||
* pointing at the initially allocated data with the UV_UDP_MMSG_CHUNK
|
||||
* flag cleared and the UV_UDP_MMSG_FREE flag set.
|
||||
*/
|
||||
#if HAVE_DECL_UV_UDP_MMSG_FREE
|
||||
if ((flags & UV_UDP_MMSG_FREE) == UV_UDP_MMSG_FREE) {
|
||||
INSIST(nrecv == 0);
|
||||
INSIST(addr == NULL);
|
||||
goto free;
|
||||
}
|
||||
#else
|
||||
free_buf = true;
|
||||
UNUSED(flags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Four possible reasons to return now without processing:
|
||||
*/
|
||||
|
||||
/*
|
||||
* - If we're simulating a firewall blocking UDP packets
|
||||
* bigger than 'maxudp' bytes for testing purposes.
|
||||
@@ -640,9 +642,31 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
|
||||
sock->processing = false;
|
||||
|
||||
free:
|
||||
if (free_buf) {
|
||||
isc__nm_free_uvbuf(sock, buf);
|
||||
#if HAVE_DECL_UV_UDP_MMSG_CHUNK
|
||||
/*
|
||||
* When using recvmmsg(2), chunks will have the UV_UDP_MMSG_CHUNK flag
|
||||
* set, those must not be freed.
|
||||
*/
|
||||
if ((flags & UV_UDP_MMSG_CHUNK) == UV_UDP_MMSG_CHUNK) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When using recvmmsg(2), if a UDP socket error occurs, nrecv will be <
|
||||
* 0. In either scenario, the callee can now safely free the provided
|
||||
* buffer.
|
||||
*/
|
||||
if (nrecv < 0) {
|
||||
/*
|
||||
* The buffer may be a null buffer on error.
|
||||
*/
|
||||
if (buf->base == NULL && buf->len == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
isc__nm_free_uvbuf(sock, buf);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user