diff --git a/docs/src/udp.rst b/docs/src/udp.rst index aed7ce22..706d011b 100644 --- a/docs/src/udp.rst +++ b/docs/src/udp.rst @@ -47,6 +47,12 @@ Data types * must not be freed by the recv_cb callback. */ UV_UDP_MMSG_CHUNK = 8, + /* + * Indicates that the buffer provided has been fully utilized by recvmmsg and + * that it should now be freed by the recv_cb callback. When this flag is set + * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. + */ + UV_UDP_MMSG_FREE = 16, /* * Indicates that recvmmsg should be used, if available. */ @@ -80,8 +86,10 @@ Data types When using :man:`recvmmsg(2)`, chunks will have the `UV_UDP_MMSG_CHUNK` flag set, those must not be freed. There will be a final callback with `nread` set to 0, `addr` set to NULL and the buffer pointing at the initially allocated data with - the `UV_UDP_MMSG_CHUNK` flag cleared. This is a good chance for the callee to - free the provided buffer. + the `UV_UDP_MMSG_CHUNK` flag cleared and the `UV_UDP_MMSG_FREE` flag set. + The callee can now safely free the provided buffer. + + .. versionchanged:: 1.39.0 added the `UV_UDP_MMSG_FREE` flag. .. note:: The receive callback will be called with `nread` == 0 and `addr` == NULL when there is diff --git a/include/uv.h b/include/uv.h index 06b6d001..d481eeb8 100644 --- a/include/uv.h +++ b/include/uv.h @@ -614,6 +614,12 @@ enum uv_udp_flags { * must not be freed by the recv_cb callback. */ UV_UDP_MMSG_CHUNK = 8, + /* + * Indicates that the buffer provided has been fully utilized by recvmmsg and + * that it should now be freed by the recv_cb callback. When this flag is set + * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. + */ + UV_UDP_MMSG_FREE = 16, /* * Indicates that recvmmsg should be used, if available. diff --git a/src/unix/udp.c b/src/unix/udp.c index 16c7f38a..587c3475 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -238,7 +238,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { /* one last callback so the original buffer is freed */ if (handle->recv_cb != NULL) - handle->recv_cb(handle, 0, buf, NULL, 0); + handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); } return nread; } diff --git a/test/test-udp-mmsg.c b/test/test-udp-mmsg.c index 94e8d5b8..08628a50 100644 --- a/test/test-udp-mmsg.c +++ b/test/test-udp-mmsg.c @@ -74,16 +74,22 @@ static void recv_cb(uv_udp_t* handle, unsigned flags) { ASSERT_GE(nread, 0); - if (nread > 0) { - ASSERT_EQ(nread, 4); - ASSERT(addr != NULL); - ASSERT_MEM_EQ("PING", rcvbuf->base, nread); + /* free and return if this is a mmsg free-only callback invocation */ + if (flags & UV_UDP_MMSG_FREE) { + ASSERT_EQ(nread, 0); + ASSERT(addr == NULL); + free(rcvbuf->base); + return; + } - recv_cb_called++; - if (recv_cb_called == NUM_SENDS) { - uv_close((uv_handle_t*)handle, close_cb); - uv_close((uv_handle_t*)&sender, close_cb); - } + ASSERT_EQ(nread, 4); + ASSERT(addr != NULL); + ASSERT_MEM_EQ("PING", rcvbuf->base, nread); + + recv_cb_called++; + if (recv_cb_called == NUM_SENDS) { + uv_close((uv_handle_t*)handle, close_cb); + uv_close((uv_handle_t*)&sender, close_cb); } /* Don't free if the buffer could be reused via mmsg */