udp: return recvmmsg-ed datagrams in order
When recvmmsg support was added it returned the datagrams in reverse received order, which may impact some applications. To restore the previous behavior, we call recv_cb one last time with nread == 0 and addr == NULL so applications can free the buffer. PR-URL: https://github.com/libuv/libuv/pull/2736 Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
055e89f637
commit
d9cd7d437d
@ -43,8 +43,7 @@ Data types
|
|||||||
*/
|
*/
|
||||||
UV_UDP_REUSEADDR = 4
|
UV_UDP_REUSEADDR = 4
|
||||||
/*
|
/*
|
||||||
* Indicates that the message was received by recvmmsg and that it's not at
|
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||||
* the beginning of the buffer allocated by alloc_cb - so the buffer provided
|
|
||||||
* must not be freed by the recv_cb callback.
|
* must not be freed by the recv_cb callback.
|
||||||
*/
|
*/
|
||||||
UV_UDP_MMSG_CHUNK = 8
|
UV_UDP_MMSG_CHUNK = 8
|
||||||
@ -72,9 +71,13 @@ Data types
|
|||||||
|
|
||||||
The callee is responsible for freeing the buffer, libuv does not reuse it.
|
The callee is responsible for freeing the buffer, libuv does not reuse it.
|
||||||
The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0)
|
The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0)
|
||||||
on error. Don't free the buffer when the UV_UDP_MMSG_CHUNK flag is set.
|
on error.
|
||||||
The final callback receives the whole buffer (containing the first chunk)
|
|
||||||
with the UV_UDP_MMSG_CHUNK flag cleared.
|
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.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
|
The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
|
||||||
@ -373,6 +376,10 @@ API
|
|||||||
|
|
||||||
:returns: 0 on success, or an error code < 0 on failure.
|
:returns: 0 on success, or an error code < 0 on failure.
|
||||||
|
|
||||||
|
.. 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`.
|
||||||
|
|
||||||
.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
|
.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
|
||||||
|
|
||||||
Stop listening for incoming datagrams.
|
Stop listening for incoming datagrams.
|
||||||
|
|||||||
@ -607,8 +607,7 @@ enum uv_udp_flags {
|
|||||||
*/
|
*/
|
||||||
UV_UDP_REUSEADDR = 4,
|
UV_UDP_REUSEADDR = 4,
|
||||||
/*
|
/*
|
||||||
* Indicates that the message was received by recvmmsg and that it's not at
|
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||||
* the beginning of the buffer allocated by alloc_cb - so the buffer provided
|
|
||||||
* must not be freed by the recv_cb callback.
|
* must not be freed by the recv_cb callback.
|
||||||
*/
|
*/
|
||||||
UV_UDP_MMSG_CHUNK = 8
|
UV_UDP_MMSG_CHUNK = 8
|
||||||
|
|||||||
@ -214,14 +214,11 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
|||||||
else
|
else
|
||||||
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
|
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
/* count to zero, so the buffer base comes last */
|
/* pass each chunk to the application */
|
||||||
for (k = nread; k > 0 && handle->recv_cb != NULL;) {
|
for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
|
||||||
k--;
|
flags = UV_UDP_MMSG_CHUNK;
|
||||||
flags = 0;
|
|
||||||
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
|
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
|
||||||
flags |= UV_UDP_PARTIAL;
|
flags |= UV_UDP_PARTIAL;
|
||||||
if (k != 0)
|
|
||||||
flags |= UV_UDP_MMSG_CHUNK;
|
|
||||||
|
|
||||||
chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
|
chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
|
||||||
handle->recv_cb(handle,
|
handle->recv_cb(handle,
|
||||||
@ -230,6 +227,10 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
|||||||
msgs[k].msg_hdr.msg_name,
|
msgs[k].msg_hdr.msg_name,
|
||||||
flags);
|
flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* one last callback so the original buffer is freed */
|
||||||
|
if (handle->recv_cb != NULL)
|
||||||
|
handle->recv_cb(handle, 0, buf, NULL, 0);
|
||||||
}
|
}
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user