Skip to content

Commit e231b42

Browse files
authored
Report the number of received bytes in recv_uninit and recvfrom_uninit. (#1278)
As discussed in #1159, add a length to the return value of `recv_uninit` and `recvfrom_uninit` to report the original received length, which with `RecvFlags::TRUNC` may differ from the returned buffer length.
1 parent 253582d commit e231b42

2 files changed

Lines changed: 27 additions & 21 deletions

File tree

src/net/send_recv/mod.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,26 +70,23 @@ pub fn recv<Fd: AsFd>(fd: Fd, buf: &mut [u8], flags: RecvFlags) -> io::Result<us
7070
/// `recv(fd, buf, flags)`—Reads data from a socket.
7171
///
7272
/// This is equivalent to [`recv`], except that it can read into uninitialized
73-
/// memory. It returns the slice that was initialized by this function and the
74-
/// slice that remains uninitialized.
75-
///
76-
/// Because this interface returns the length via the returned slice, it's
77-
/// unsable to return the untruncated length that would be returned when the
78-
/// `RecvFlags::TRUNC` flag is used. If you need the untruncated length, use
79-
/// [`recv`].
73+
/// memory. It returns the slice that was initialized by this function, the
74+
/// slice that remains uninitialized, and the number of bytes received before
75+
/// any truncation due to the `RecvFlags::TRUNC` flag.
8076
#[inline]
8177
pub fn recv_uninit<Fd: AsFd>(
8278
fd: Fd,
8379
buf: &mut [MaybeUninit<u8>],
8480
flags: RecvFlags,
85-
) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
81+
) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>], usize)> {
8682
let length = unsafe {
8783
backend::net::syscalls::recv(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len(), flags)?
8884
};
8985

9086
// If the `TRUNC` flag is set, the returned `length` may be longer than the
9187
// buffer length.
92-
Ok(unsafe { split_init(buf, min(length, buf.len())) })
88+
let (init, uninit) = unsafe { split_init(buf, min(length, buf.len())) };
89+
Ok((init, uninit, length))
9390
}
9491

9592
/// `send(fd, buf, flags)`—Writes data to a socket.
@@ -167,19 +164,21 @@ pub fn recvfrom<Fd: AsFd>(
167164
///
168165
/// This is equivalent to [`recvfrom`], except that it can read into
169166
/// uninitialized memory. It returns the slice that was initialized by this
170-
/// function and the slice that remains uninitialized.
171-
///
172-
/// Because this interface returns the length via the returned slice, it's
173-
/// unsable to return the untruncated length that would be returned when the
174-
/// `RecvFlags::TRUNC` flag is used. If you need the untruncated length, use
175-
/// [`recvfrom`].
167+
/// function, the slice that remains uninitialized, the number of bytes
168+
/// received before any truncation due to the `RecvFlags::TRUNC` flag, and
169+
/// the address of the sender if known.
176170
#[allow(clippy::type_complexity)]
177171
#[inline]
178172
pub fn recvfrom_uninit<Fd: AsFd>(
179173
fd: Fd,
180174
buf: &mut [MaybeUninit<u8>],
181175
flags: RecvFlags,
182-
) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>], Option<SocketAddrAny>)> {
176+
) -> io::Result<(
177+
&mut [u8],
178+
&mut [MaybeUninit<u8>],
179+
usize,
180+
Option<SocketAddrAny>,
181+
)> {
183182
let (length, addr) = unsafe {
184183
backend::net::syscalls::recvfrom(
185184
fd.as_fd(),
@@ -192,7 +191,7 @@ pub fn recvfrom_uninit<Fd: AsFd>(
192191
// If the `TRUNC` flag is set, the returned `length` may be longer than the
193192
// buffer length.
194193
let (init, uninit) = unsafe { split_init(buf, min(length, buf.len())) };
195-
Ok((init, uninit, addr))
194+
Ok((init, uninit, length, addr))
196195
}
197196

198197
/// `sendto(fd, buf, flags, addr)`—Writes data to a socket to a specific IP

tests/net/recv_trunc.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ fn net_recv_uninit_trunc() {
2323
#[cfg(not(any(apple, solarish, target_os = "netbsd")))]
2424
{
2525
let mut response = [MaybeUninit::<u8>::zeroed(); 5];
26-
let (init, uninit) = rustix::net::recv_uninit(&receiver, &mut response, RecvFlags::TRUNC)
27-
.expect("recv_uninit");
26+
let (init, uninit, length) =
27+
rustix::net::recv_uninit(&receiver, &mut response, RecvFlags::TRUNC)
28+
.expect("recv_uninit");
2829

2930
// We used the `TRUNC` flag, so we should have only gotten 5 bytes.
3031
assert_eq!(init, b"Hello");
@@ -34,17 +35,23 @@ fn net_recv_uninit_trunc() {
3435
let n =
3536
rustix::net::sendto_unix(&sender, request, SendFlags::empty(), &name).expect("send");
3637
assert_eq!(n, request.len());
38+
39+
// Check the `length`.
40+
assert_eq!(length, 15);
3741
}
3842

3943
// This time receive it without `TRUNC`. This should fail.
4044
let mut response = [MaybeUninit::<u8>::zeroed(); 5];
41-
let (init, uninit) = rustix::net::recv_uninit(&receiver, &mut response, RecvFlags::empty())
42-
.expect("recv_uninit");
45+
let (init, uninit, length) =
46+
rustix::net::recv_uninit(&receiver, &mut response, RecvFlags::empty())
47+
.expect("recv_uninit");
4348

4449
// We didn't use the `TRUNC` flag, so we should have received 15 bytes,
4550
// truncated to 5 bytes.
4651
assert_eq!(init, b"Hello");
4752
assert!(uninit.is_empty());
53+
54+
assert_eq!(length, 5);
4855
}
4956

5057
/// Test `recvmsg` with the `RecvFlags::Trunc` flag.

0 commit comments

Comments
 (0)