udp: add flag to enable recvmmsg(2) explicitly

Instead of implicitly enabling it by checking the supplied buffer size
to alloc_cb, have a dedicated flag that must be set on `uv_udp_init_ex`.

Fixes: https://github.com/libuv/libuv/issues/2791
Closes: https://github.com/libuv/libuv/pull/2792
PR-URL: https://github.com/libuv/libuv/pull/2799
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Saúl Ibarra Corretgé 2020-04-18 13:58:19 +02:00 committed by cjihrig
parent 0fd993195f
commit 5736658bee
No known key found for this signature in database
GPG Key ID: 7434390BDBE9B9C5
4 changed files with 35 additions and 13 deletions

View File

@ -41,12 +41,16 @@ Data types
* (provided they all set the flag) but only the last one to bind will receive
* any traffic, in effect "stealing" the port from the previous listener.
*/
UV_UDP_REUSEADDR = 4
UV_UDP_REUSEADDR = 4,
/*
* Indicates that the message was received by recvmmsg, so the buffer provided
* must not be freed by the recv_cb callback.
*/
UV_UDP_MMSG_CHUNK = 8
UV_UDP_MMSG_CHUNK = 8,
/*
* Indicates that recvmmsg should be used, if available.
*/
UV_UDP_RECVMMSG = 256
};
.. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
@ -125,12 +129,17 @@ API
.. c:function:: int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
Initialize the handle with the specified flags. At the moment the lower 8 bits
of the `flags` parameter are used as the socket domain. A socket will be created
for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
just like :c:func:`uv_udp_init`.
Initialize the handle with the specified flags. The lower 8 bits of the `flags`
parameter are used as the socket domain. A socket will be created for the given domain.
If the specified domain is ``AF_UNSPEC`` no socket is created, just like :c:func:`uv_udp_init`.
The remaining bits can be used to set one of these flags:
* `UV_UDP_RECVMMSG`: if set, and the platform supports it, :man:`recvmmsg(2)` will
be used.
.. versionadded:: 1.7.0
.. versionchanged:: 1.37.0 added the `UV_UDP_RECVMMSG` flag.
.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
@ -379,6 +388,9 @@ API
.. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms).
The use of this feature requires a buffer larger than
2 * 64KB to be passed to `alloc_cb`.
.. versionchanged:: 1.37.0 :man:`recvmmsg(2)` support is no longer enabled implicitly,
it must be explicitly requested by passing the `UV_UDP_RECVMMSG` flag to
:c:func:`uv_udp_init_ex`.
.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)

View File

@ -610,7 +610,12 @@ enum uv_udp_flags {
* Indicates that the message was received by recvmmsg, so the buffer provided
* must not be freed by the recv_cb callback.
*/
UV_UDP_MMSG_CHUNK = 8
UV_UDP_MMSG_CHUNK = 8,
/*
* Indicates that recvmmsg should be used, if available.
*/
UV_UDP_RECVMMSG = 256
};
typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);

View File

@ -262,11 +262,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
assert(buf.base != NULL);
#if HAVE_MMSG
if (handle->flags & UV_HANDLE_UDP_RECVMMSG) {
uv_once(&once, uv__udp_mmsg_init);
if (uv__recvmmsg_avail) {
/* Returned space for more than 1 datagram, use it to receive
* multiple datagrams. */
if (buf.len >= 2 * UV__UDP_DGRAM_MAXSIZE) {
nread = uv__udp_recvmmsg(handle, &buf);
if (nread > 0)
count -= nread;
@ -949,6 +947,7 @@ static int uv__udp_set_source_membership6(uv_udp_t* handle,
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
int domain;
int err;
int extra_flags;
int fd;
/* Use the lower 8 bits for the domain */
@ -956,7 +955,9 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
return UV_EINVAL;
if (flags & ~0xFF)
/* Use the higher bits for extra flags */
extra_flags = flags & ~0xFF;
if (extra_flags & ~UV_UDP_RECVMMSG)
return UV_EINVAL;
if (domain != AF_UNSPEC) {
@ -977,6 +978,9 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
QUEUE_INIT(&handle->write_queue);
QUEUE_INIT(&handle->write_completed_queue);
if (extra_flags & UV_UDP_RECVMMSG)
handle->flags |= UV_HANDLE_UDP_RECVMMSG;
return 0;
}

View File

@ -104,6 +104,7 @@ enum {
/* Only used by uv_udp_t handles. */
UV_HANDLE_UDP_PROCESSING = 0x01000000,
UV_HANDLE_UDP_CONNECTED = 0x02000000,
UV_HANDLE_UDP_RECVMMSG = 0x04000000,
/* Only used by uv_pipe_t handles. */
UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,