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
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg and that it's not at
|
||||
* the beginning of the buffer allocated by alloc_cb - so the buffer provided
|
||||
* 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
|
||||
@ -72,9 +71,13 @@ Data types
|
||||
|
||||
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)
|
||||
on error. Don't free the buffer when the UV_UDP_MMSG_CHUNK flag is set.
|
||||
The final callback receives the whole buffer (containing the first chunk)
|
||||
with the UV_UDP_MMSG_CHUNK flag cleared.
|
||||
on error.
|
||||
|
||||
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::
|
||||
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.
|
||||
|
||||
.. 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)
|
||||
|
||||
Stop listening for incoming datagrams.
|
||||
|
||||
@ -607,8 +607,7 @@ enum uv_udp_flags {
|
||||
*/
|
||||
UV_UDP_REUSEADDR = 4,
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg and that it's not at
|
||||
* the beginning of the buffer allocated by alloc_cb - so the buffer provided
|
||||
* 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
|
||||
|
||||
@ -214,14 +214,11 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
else
|
||||
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
|
||||
} else {
|
||||
/* count to zero, so the buffer base comes last */
|
||||
for (k = nread; k > 0 && handle->recv_cb != NULL;) {
|
||||
k--;
|
||||
flags = 0;
|
||||
/* pass each chunk to the application */
|
||||
for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
|
||||
flags = UV_UDP_MMSG_CHUNK;
|
||||
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
|
||||
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);
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user