Skip to content

Commit 253582d

Browse files
authored
Add a new ReturnFlags type for flags returned from recvmsg (#1288)
* Add a new `ReturnFlags` type for flags returned from `recvmsg` `RecvMsgReturn`'s `flags` field was previously `RecvFlags`, however `recvmsg` returns a different set of flags than that. To address that, add a new type, `ReturnFlags`, which contains the flags that are returned from `recvmsg`. Fixes #1287. * Make `RecvMsgReturn`'s `Debug` impl not break no_std. * Fix copypasta to avoid a unix domain socket collision. * Windows lacks `MSG_EOR`. * Fix VMIN/VEOF on AIX. * Workaround limitations on Apple. - Disable `RecvFlags::TRUNC` on Apple. - Check for `AF_UNIX` socket addresses with no paths on Apple. * Disable `RecvFlags::TRUNC` on illumos too. * Disable `RecvFlags::TRUNC` on NetBSD too.
1 parent bb1478d commit 253582d

14 files changed

Lines changed: 329 additions & 80 deletions

File tree

src/backend/libc/net/read_sockaddr.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ unsafe fn read_ss_family(storage: *const c::sockaddr_storage) -> u16 {
9393
(*storage.cast::<sockaddr_header>()).ss_family.into()
9494
}
9595

96+
/// Read the first byte of the `sun_path` field, assuming we have an `AF_UNIX`
97+
/// socket address.
98+
#[cfg(apple)]
99+
#[inline]
100+
unsafe fn read_sun_path0(storage: *const c::sockaddr_storage) -> u8 {
101+
// In `read_ss_family` we assert that we know the layout of `sockaddr`.
102+
storage
103+
.cast::<u8>()
104+
.add(super::addr::offsetof_sun_path())
105+
.read()
106+
}
107+
96108
/// Set the `ss_family` field of a socket address to `AF_UNSPEC`, so that we
97109
/// can test for `AF_UNSPEC` to test whether it was stored to.
98110
pub(crate) unsafe fn initialize_family_to_unspec(storage: *mut c::sockaddr_storage) {
@@ -233,10 +245,17 @@ pub(crate) unsafe fn maybe_read_sockaddr_os(
233245
assert!(len >= size_of::<c::sa_family_t>());
234246
let family = read_ss_family(storage).into();
235247
if family == c::AF_UNSPEC {
236-
None
237-
} else {
238-
Some(inner_read_sockaddr_os(family, storage, len))
248+
return None;
239249
}
250+
251+
// On macOS, if we get an `AF_UNIX` with an empty path, treat it as
252+
// an absent address.
253+
#[cfg(apple)]
254+
if family == c::AF_UNIX && read_sun_path0(storage) == 0 {
255+
return None;
256+
}
257+
258+
Some(inner_read_sockaddr_os(family, storage, len))
240259
}
241260

242261
/// Read a socket address returned from the OS.

src/backend/libc/net/send_recv.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ bitflags! {
6363
#[repr(transparent)]
6464
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
6565
pub struct RecvFlags: u32 {
66+
/// `MSG_CMSG_CLOEXEC`
6667
#[cfg(not(any(
6768
apple,
6869
solarish,
@@ -73,7 +74,6 @@ bitflags! {
7374
target_os = "nto",
7475
target_os = "vita",
7576
)))]
76-
/// `MSG_CMSG_CLOEXEC`
7777
const CMSG_CLOEXEC = bitcast!(c::MSG_CMSG_CLOEXEC);
7878
/// `MSG_DONTWAIT`
7979
#[cfg(not(windows))]
@@ -96,6 +96,10 @@ bitflags! {
9696
/// `MSG_PEEK`
9797
const PEEK = bitcast!(c::MSG_PEEK);
9898
/// `MSG_TRUNC`
99+
// Apple, illumos, and NetBSD have `MSG_TRUNC` but it's not documented
100+
// for use with `recv` and friends, and in practice appears to be
101+
// ignored.
102+
#[cfg(not(any(apple, solarish, target_os = "netbsd")))]
99103
const TRUNC = bitcast!(c::MSG_TRUNC);
100104
/// `MSG_WAITALL`
101105
const WAITALL = bitcast!(c::MSG_WAITALL);
@@ -104,3 +108,34 @@ bitflags! {
104108
const _ = !0;
105109
}
106110
}
111+
112+
bitflags! {
113+
/// `MSG_*` flags returned from [`recvmsg`], in the `flags` field of
114+
/// [`RecvMsgReturn`]
115+
///
116+
/// [`recvmsg`]: crate::net::recvmsg
117+
/// [`RecvMsgReturn`]: crate::net::RecvMsgReturn
118+
#[repr(transparent)]
119+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
120+
pub struct ReturnFlags: u32 {
121+
/// `MSG_OOB`
122+
const OOB = bitcast!(c::MSG_OOB);
123+
/// `MSG_EOR`
124+
#[cfg(not(windows))]
125+
const EOR = bitcast!(c::MSG_EOR);
126+
/// `MSG_TRUNC`
127+
const TRUNC = bitcast!(c::MSG_TRUNC);
128+
/// `MSG_CTRUNC`
129+
const CTRUNC = bitcast!(c::MSG_CTRUNC);
130+
131+
/// `MSG_CMSG_CLOEXEC`
132+
#[cfg(linux_kernel)]
133+
const CMSG_CLOEXEC = bitcast!(c::MSG_CMSG_CLOEXEC);
134+
/// `MSG_ERRQUEUE`
135+
#[cfg(linux_kernel)]
136+
const ERRQUEUE = bitcast!(c::MSG_ERRQUEUE);
137+
138+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
139+
const _ = !0;
140+
}
141+
}

src/backend/libc/net/syscalls.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use {
3030
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
3131
use {
3232
super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os},
33-
super::send_recv::{RecvFlags, SendFlags},
33+
super::send_recv::{RecvFlags, ReturnFlags, SendFlags},
3434
super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6},
3535
crate::net::{AddressFamily, Protocol, Shutdown, SocketFlags, SocketType},
3636
core::ptr::null_mut,
@@ -344,7 +344,7 @@ pub(crate) fn recvmsg(
344344
RecvMsgReturn {
345345
bytes,
346346
address: addr,
347-
flags: RecvFlags::from_bits_retain(bitcast!(msghdr.msg_flags)),
347+
flags: ReturnFlags::from_bits_retain(bitcast!(msghdr.msg_flags)),
348348
}
349349
})
350350
})

src/backend/linux_raw/c.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ pub(crate) use linux_raw_sys::{
7171
IPV6_MULTICAST_LOOP, IPV6_RECVTCLASS, IPV6_TCLASS, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
7272
IP_ADD_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_DROP_SOURCE_MEMBERSHIP,
7373
IP_FREEBIND, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_RECVTOS, IP_TOS, IP_TTL,
74-
MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR, MSG_ERRQUEUE,
75-
MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL, SCM_CREDENTIALS,
76-
SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET,
77-
SOCK_STREAM, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE, SO_DOMAIN,
78-
SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE, SO_ORIGINAL_DST,
79-
SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVTIMEO_NEW,
74+
MSG_CMSG_CLOEXEC, MSG_CONFIRM, MSG_CTRUNC, MSG_DONTROUTE, MSG_DONTWAIT, MSG_EOR,
75+
MSG_ERRQUEUE, MSG_MORE, MSG_NOSIGNAL, MSG_OOB, MSG_PEEK, MSG_TRUNC, MSG_WAITALL,
76+
SCM_CREDENTIALS, SCM_RIGHTS, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_DGRAM, SOCK_RAW, SOCK_RDM,
77+
SOCK_SEQPACKET, SOCK_STREAM, SOL_SOCKET, SOL_XDP, SO_ACCEPTCONN, SO_BROADCAST, SO_COOKIE,
78+
SO_DOMAIN, SO_ERROR, SO_INCOMING_CPU, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
79+
SO_ORIGINAL_DST, SO_PASSCRED, SO_PROTOCOL, SO_RCVBUF, SO_RCVBUFFORCE, SO_RCVTIMEO_NEW,
8080
SO_RCVTIMEO_NEW as SO_RCVTIMEO, SO_RCVTIMEO_OLD, SO_REUSEADDR, SO_REUSEPORT, SO_SNDBUF,
8181
SO_SNDTIMEO_NEW, SO_SNDTIMEO_NEW as SO_SNDTIMEO, SO_SNDTIMEO_OLD, SO_TYPE, TCP_CONGESTION,
8282
TCP_CORK, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_NODELAY, TCP_QUICKACK,

src/backend/linux_raw/net/send_recv.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,30 @@ bitflags! {
5858
const _ = !0;
5959
}
6060
}
61+
62+
bitflags! {
63+
/// `MSG_*` flags returned from [`recvmsg`], in the `flags` field of
64+
/// [`RecvMsgReturn`]
65+
///
66+
/// [`recvmsg`]: crate::net::recvmsg
67+
/// [`RecvMsgReturn`]: crate::net::RecvMsgReturn
68+
#[repr(transparent)]
69+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
70+
pub struct ReturnFlags: u32 {
71+
/// `MSG_OOB`
72+
const OOB = c::MSG_OOB;
73+
/// `MSG_EOR`
74+
const EOR = c::MSG_EOR;
75+
/// `MSG_TRUNC`
76+
const TRUNC = c::MSG_TRUNC;
77+
/// `MSG_CTRUNC`
78+
const CTRUNC = c::MSG_CTRUNC;
79+
/// `MSG_ERRQUEUE`
80+
const ERRQUEUE = c::MSG_ERRQUEUE;
81+
/// `MSG_CMSG_CLOEXEC`
82+
const CMSG_CLOEXEC = c::MSG_CMSG_CLOEXEC;
83+
84+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
85+
const _ = !0;
86+
}
87+
}

src/backend/linux_raw/net/syscalls.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::msghdr::{
1111
with_noaddr_msghdr, with_recv_msghdr, with_unix_msghdr, with_v4_msghdr, with_v6_msghdr,
1212
};
1313
use super::read_sockaddr::{initialize_family_to_unspec, maybe_read_sockaddr_os, read_sockaddr_os};
14-
use super::send_recv::{RecvFlags, SendFlags};
14+
use super::send_recv::{RecvFlags, ReturnFlags, SendFlags};
1515
#[cfg(target_os = "linux")]
1616
use super::write_sockaddr::encode_sockaddr_xdp;
1717
use super::write_sockaddr::{encode_sockaddr_v4, encode_sockaddr_v6};
@@ -293,7 +293,7 @@ pub(crate) fn recvmsg(
293293
RecvMsgReturn {
294294
bytes,
295295
address: addr,
296-
flags: RecvFlags::from_bits_retain(msghdr.msg_flags),
296+
flags: ReturnFlags::from_bits_retain(msghdr.msg_flags),
297297
}
298298
})
299299
})

src/net/send_recv/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use backend::fd::{AsFd, BorrowedFd};
1313
use core::cmp::min;
1414
use core::mem::MaybeUninit;
1515

16-
pub use backend::net::send_recv::{RecvFlags, SendFlags};
16+
pub use backend::net::send_recv::{RecvFlags, ReturnFlags, SendFlags};
1717

1818
#[cfg(not(any(
1919
windows,

src/net/send_recv/msg.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ use crate::fd::{AsFd, BorrowedFd, OwnedFd};
77
use crate::io::{self, IoSlice, IoSliceMut};
88
#[cfg(linux_kernel)]
99
use crate::net::UCred;
10-
10+
#[cfg(feature = "std")]
11+
use core::fmt;
1112
use core::iter::FusedIterator;
1213
use core::marker::PhantomData;
1314
use core::mem::{align_of, size_of, size_of_val, take};
1415
#[cfg(linux_kernel)]
1516
use core::ptr::addr_of;
1617
use core::{ptr, slice};
1718

18-
use super::{RecvFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6};
19+
use super::{RecvFlags, ReturnFlags, SendFlags, SocketAddrAny, SocketAddrV4, SocketAddrV6};
1920

2021
/// Macro for defining the amount of space to allocate in a buffer for use with
2122
/// [`RecvAncillaryBuffer::new`] and [`SendAncillaryBuffer::new`].
@@ -819,15 +820,30 @@ pub fn recvmsg<Fd: AsFd>(
819820
/// The result of a successful [`recvmsg`] call.
820821
pub struct RecvMsgReturn {
821822
/// The number of bytes received.
823+
///
824+
/// When `RecvFlags::TRUNC` is in use, this may be greater than the
825+
/// length of the buffer, as it reflects the number of bytes received
826+
/// before truncation into the buffer.
822827
pub bytes: usize,
823828

824829
/// The flags received.
825-
pub flags: RecvFlags,
830+
pub flags: ReturnFlags,
826831

827832
/// The address of the socket we received from, if any.
828833
pub address: Option<SocketAddrAny>,
829834
}
830835

836+
#[cfg(feature = "std")]
837+
impl fmt::Debug for RecvMsgReturn {
838+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
839+
f.debug_struct("RecvMsgReturn")
840+
.field("bytes", &self.bytes)
841+
.field("flags", &self.flags)
842+
.field("address", &self.address)
843+
.finish()
844+
}
845+
}
846+
831847
/// An iterator over data in an ancillary buffer.
832848
pub struct AncillaryIter<'data, T> {
833849
/// The data we're iterating over.

src/termios/types.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1211,24 +1211,28 @@ impl core::fmt::Debug for SpecialCodeIndex {
12111211
Self::VKILL => write!(f, "VKILL"),
12121212
#[cfg(not(any(
12131213
solarish,
1214+
target_os = "aix",
12141215
all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
12151216
)))]
12161217
Self::VEOF => write!(f, "VEOF"),
12171218
#[cfg(not(any(
12181219
solarish,
1220+
target_os = "aix",
12191221
all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
12201222
)))]
12211223
Self::VTIME => write!(f, "VTIME"),
12221224
#[cfg(not(any(
12231225
solarish,
1226+
target_os = "aix",
12241227
all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
12251228
)))]
12261229
Self::VMIN => write!(f, "VMIN"),
12271230

1228-
// On Solarish platforms, and Linux on SPARC, `VMIN` and `VTIME`
1231+
// On Solarish platforms, Linux on SPARC, and AIX, `VMIN` and `VTIME`
12291232
// have the same value as `VEOF` and `VEOL`.
12301233
#[cfg(any(
12311234
solarish,
1235+
target_os = "aix",
12321236
all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64"))
12331237
))]
12341238
Self::VMIN => write!(f, "VMIN/VEOF"),

0 commit comments

Comments
 (0)