Skip to content

Commit 3d6bd87

Browse files
committed
unix: Fix feature(unix_socket_ancillary_data) on macos and other BSDs
This adds support for CMSG handling on macOS and fixes it on OpenBSD and other BSDs. When traversing the CMSG list, the previous code had an exception for Android where the next element after the last pointer could point to the first pointer instead of NULL. This is actually not specific to Android: the `libc::CMSG_NXTHDR` implementation for Linux and emscripten have a special case to return NULL when the length of the previous element is zero; most other implementations simply return the previous element plus a zero offset in this case. This MR additionally adds `SocketAncillary::is_empty` because clippy is right that it should be added.
1 parent b8719c5 commit 3d6bd87

File tree

1 file changed

+34
-23
lines changed

1 file changed

+34
-23
lines changed

library/std/src/sys/unix/ext/net/ancillary.rs

+34-23
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ use crate::marker::PhantomData;
55
use crate::mem::{size_of, zeroed};
66
use crate::os::unix::io::RawFd;
77
use crate::path::Path;
8-
#[cfg(target_os = "android")]
9-
use crate::ptr::eq;
10-
use crate::ptr::read_unaligned;
8+
use crate::ptr::{eq, read_unaligned};
119
use crate::slice::from_raw_parts;
1210
use crate::sys::net::Socket;
1311

@@ -30,12 +28,10 @@ pub(super) fn recv_vectored_with_ancillary_from(
3028
) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
3129
unsafe {
3230
let mut msg_name: libc::sockaddr_un = zeroed();
33-
3431
let mut msg: libc::msghdr = zeroed();
3532
msg.msg_name = &mut msg_name as *mut _ as *mut _;
3633
msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
3734
msg.msg_iov = bufs.as_mut_ptr().cast();
38-
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
3935
cfg_if::cfg_if! {
4036
if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
4137
msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -45,13 +41,18 @@ pub(super) fn recv_vectored_with_ancillary_from(
4541
target_os = "emscripten",
4642
target_os = "freebsd",
4743
all(target_os = "linux", target_env = "musl",),
44+
target_os = "macos",
4845
target_os = "netbsd",
4946
target_os = "openbsd",
5047
))] {
5148
msg.msg_iovlen = bufs.len() as libc::c_int;
5249
msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
5350
}
5451
}
52+
// macos requires that the control pointer is NULL when the len is 0.
53+
if msg.msg_controllen > 0 {
54+
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
55+
}
5556

5657
let count = socket.recv_msg(&mut msg)?;
5758

@@ -79,7 +80,6 @@ pub(super) fn send_vectored_with_ancillary_to(
7980
msg.msg_name = &mut msg_name as *mut _ as *mut _;
8081
msg.msg_namelen = msg_namelen;
8182
msg.msg_iov = bufs.as_ptr() as *mut _;
82-
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
8383
cfg_if::cfg_if! {
8484
if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
8585
msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -89,13 +89,18 @@ pub(super) fn send_vectored_with_ancillary_to(
8989
target_os = "emscripten",
9090
target_os = "freebsd",
9191
all(target_os = "linux", target_env = "musl",),
92+
target_os = "macos",
9293
target_os = "netbsd",
9394
target_os = "openbsd",
9495
))] {
9596
msg.msg_iovlen = bufs.len() as libc::c_int;
9697
msg.msg_controllen = ancillary.length as libc::socklen_t;
9798
}
9899
}
100+
// macos requires that the control pointer is NULL when the len is 0.
101+
if msg.msg_controllen > 0 {
102+
msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
103+
}
99104

100105
ancillary.truncated = false;
101106

@@ -147,6 +152,7 @@ fn add_to_ancillary_data<T>(
147152
target_os = "emscripten",
148153
target_os = "freebsd",
149154
all(target_os = "linux", target_env = "musl",),
155+
target_os = "macos",
150156
target_os = "netbsd",
151157
target_os = "openbsd",
152158
))] {
@@ -159,14 +165,12 @@ fn add_to_ancillary_data<T>(
159165
while !cmsg.is_null() {
160166
previous_cmsg = cmsg;
161167
cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
162-
cfg_if::cfg_if! {
163-
// Android return the same pointer if it is the last cmsg.
164-
// Therefore, check it if the previous pointer is the same as the current one.
165-
if #[cfg(target_os = "android")] {
166-
if cmsg == previous_cmsg {
167-
break;
168-
}
169-
}
168+
169+
// Most operating systems, but not Linux or emscripten, return the previous pointer
170+
// when its length is zero. Therefore, check if the previous pointer is the same as
171+
// the current one.
172+
if eq(cmsg, previous_cmsg) {
173+
break;
170174
}
171175
}
172176

@@ -184,6 +188,7 @@ fn add_to_ancillary_data<T>(
184188
target_os = "emscripten",
185189
target_os = "freebsd",
186190
all(target_os = "linux", target_env = "musl",),
191+
target_os = "macos",
187192
target_os = "netbsd",
188193
target_os = "openbsd",
189194
))] {
@@ -371,6 +376,7 @@ impl<'a> AncillaryData<'a> {
371376
target_os = "emscripten",
372377
target_os = "freebsd",
373378
all(target_os = "linux", target_env = "musl",),
379+
target_os = "macos",
374380
target_os = "netbsd",
375381
target_os = "openbsd",
376382
))] {
@@ -421,6 +427,7 @@ impl<'a> Iterator for Messages<'a> {
421427
target_os = "emscripten",
422428
target_os = "freebsd",
423429
all(target_os = "linux", target_env = "musl",),
430+
target_os = "macos",
424431
target_os = "netbsd",
425432
target_os = "openbsd",
426433
))] {
@@ -435,15 +442,13 @@ impl<'a> Iterator for Messages<'a> {
435442
};
436443

437444
let cmsg = cmsg.as_ref()?;
438-
cfg_if::cfg_if! {
439-
// Android return the same pointer if it is the last cmsg.
440-
// Therefore, check it if the previous pointer is the same as the current one.
441-
if #[cfg(target_os = "android")] {
442-
if let Some(current) = self.current {
443-
if eq(current, cmsg) {
444-
return None;
445-
}
446-
}
445+
446+
// Most operating systems, but not Linux or emscripten, return the previous pointer
447+
// when its length is zero. Therefore, check if the previous pointer is the same as
448+
// the current one.
449+
if let Some(current) = self.current {
450+
if eq(current, cmsg) {
451+
return None;
447452
}
448453
}
449454

@@ -514,6 +519,12 @@ impl<'a> SocketAncillary<'a> {
514519
self.buffer.len()
515520
}
516521

522+
/// Returns `true` if the ancillary data is empty.
523+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
524+
pub fn is_empty(&self) -> bool {
525+
self.length == 0
526+
}
527+
517528
/// Returns the number of used bytes.
518529
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
519530
pub fn len(&self) -> usize {

0 commit comments

Comments
 (0)