Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit bea6f37

Browse files
committedOct 25, 2023
Convert Unix{Datagram,Stream}::{set_}passcred() to per-OS traits
These methods are the pre-stabilized API for obtaining peer credentials from an `AF_UNIX` socket, part of the `unix_socket_ancillary_data` feature. Their current behavior is to get/set one of the `SO_PASSCRED` (Linux), `LOCAL_CREDS_PERSISTENT` (FreeBSD), or `LOCAL_CREDS` (NetBSD) socket options. On other targets the `{set_}passcred()` methods do not exist. There are two problems with this approach: 1. Having public methods only exist for certain targets isn't permitted in a stable `std` API. 2. These options have generally similar purposes, but they are non-POSIX and their details can differ in subtle and surprising ways (such as whether they continue to be set after the next call to `recvmsg()`). Splitting into OS-specific extension traits is the preferred solution to both problems.
1 parent d3d145e commit bea6f37

File tree

11 files changed

+244
-136
lines changed

11 files changed

+244
-136
lines changed
 

‎library/std/src/os/freebsd/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
#![stable(feature = "raw_ext", since = "1.1.0")]
44

55
pub mod fs;
6+
pub mod net;
67
pub mod raw;

‎library/std/src/os/freebsd/net.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! FreeBSD-specific networking functionality.
2+
3+
#![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
4+
5+
use crate::io;
6+
use crate::os::unix::net;
7+
use crate::sealed::Sealed;
8+
use crate::sys_common::AsInner;
9+
10+
/// FreeBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
11+
/// and [`UnixStream`].
12+
///
13+
/// [`UnixDatagram`]: net::UnixDatagram
14+
/// [`UnixStream`]: net::UnixStream
15+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
16+
pub trait UnixSocketExt: Sealed {
17+
/// Query the current setting of socket option `LOCAL_CREDS_PERSISTENT`.
18+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
19+
fn local_creds_persistent(&self) -> io::Result<bool>;
20+
21+
/// Enable or disable socket option `LOCAL_CREDS_PERSISTENT`.
22+
///
23+
/// This option enables the credentials of the sending process to be
24+
/// received as a control message in [`AncillaryData`].
25+
///
26+
/// [`AncillaryData`]: net::AncillaryData
27+
///
28+
/// # Examples
29+
///
30+
/// ```no_run
31+
/// #![feature(unix_socket_ancillary_data)]
32+
/// use std::os::freebsd::net::UnixSocketExt;
33+
/// use std::os::unix::net::UnixDatagram;
34+
///
35+
/// fn main() -> std::io::Result<()> {
36+
/// let sock = UnixDatagram::unbound()?;
37+
/// sock.set_local_creds_persistent(true).expect("set_local_creds_persistent failed");
38+
/// Ok(())
39+
/// }
40+
/// ```
41+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
42+
fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()>;
43+
}
44+
45+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
46+
impl UnixSocketExt for net::UnixDatagram {
47+
fn local_creds_persistent(&self) -> io::Result<bool> {
48+
self.as_inner().local_creds_persistent()
49+
}
50+
51+
fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
52+
self.as_inner().set_local_creds_persistent(local_creds_persistent)
53+
}
54+
}
55+
56+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
57+
impl UnixSocketExt for net::UnixStream {
58+
fn local_creds_persistent(&self) -> io::Result<bool> {
59+
self.as_inner().local_creds_persistent()
60+
}
61+
62+
fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
63+
self.as_inner().set_local_creds_persistent(local_creds_persistent)
64+
}
65+
}

‎library/std/src/os/linux/net.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
66
pub use crate::os::net::linux_ext::addr::SocketAddrExt;
77

8+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
9+
pub use crate::os::net::linux_ext::socket::UnixSocketExt;
10+
811
#[unstable(feature = "tcp_quickack", issue = "96256")]
912
pub use crate::os::net::linux_ext::tcp::TcpStreamExt;

‎library/std/src/os/net/linux_ext/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#[stable(feature = "unix_socket_abstract", since = "1.70.0")]
66
pub(crate) mod addr;
77

8+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
9+
pub(crate) mod socket;
10+
811
#[unstable(feature = "tcp_quickack", issue = "96256")]
912
pub(crate) mod tcp;
1013

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//! Linux and Android-specific socket functionality.
2+
3+
use crate::io;
4+
use crate::os::unix::net;
5+
use crate::sealed::Sealed;
6+
use crate::sys_common::AsInner;
7+
8+
/// Linux-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
9+
/// and [`UnixStream`].
10+
///
11+
/// [`UnixDatagram`]: net::UnixDatagram
12+
/// [`UnixStream`]: net::UnixStream
13+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
14+
pub trait UnixSocketExt: Sealed {
15+
/// Query the current setting of socket option `SO_PASSCRED`.
16+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
17+
fn passcred(&self) -> io::Result<bool>;
18+
19+
/// Enable or disable socket option `SO_PASSCRED`.
20+
///
21+
/// This option enables the credentials of the sending process to be
22+
/// received as a control message in [`AncillaryData`].
23+
///
24+
/// [`AncillaryData`]: net::AncillaryData
25+
///
26+
/// # Examples
27+
///
28+
/// ```no_run
29+
/// #![feature(unix_socket_ancillary_data)]
30+
/// use std::os::linux::net::UnixSocketExt;
31+
/// use std::os::unix::net::UnixDatagram;
32+
///
33+
/// fn main() -> std::io::Result<()> {
34+
/// let sock = UnixDatagram::unbound()?;
35+
/// sock.set_passcred(true).expect("set_passcred failed");
36+
/// Ok(())
37+
/// }
38+
/// ```
39+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
40+
fn set_passcred(&self, passcred: bool) -> io::Result<()>;
41+
}
42+
43+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
44+
impl UnixSocketExt for net::UnixDatagram {
45+
fn passcred(&self) -> io::Result<bool> {
46+
self.as_inner().passcred()
47+
}
48+
49+
fn set_passcred(&self, passcred: bool) -> io::Result<()> {
50+
self.as_inner().set_passcred(passcred)
51+
}
52+
}
53+
54+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
55+
impl UnixSocketExt for net::UnixStream {
56+
fn passcred(&self) -> io::Result<bool> {
57+
self.as_inner().passcred()
58+
}
59+
60+
fn set_passcred(&self, passcred: bool) -> io::Result<()> {
61+
self.as_inner().set_passcred(passcred)
62+
}
63+
}

‎library/std/src/os/netbsd/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
#![stable(feature = "raw_ext", since = "1.1.0")]
44

55
pub mod fs;
6+
pub mod net;
67
pub mod raw;

‎library/std/src/os/netbsd/net.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! NetBSD-specific networking functionality.
2+
3+
#![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
4+
5+
use crate::io;
6+
use crate::os::unix::net;
7+
use crate::sealed::Sealed;
8+
use crate::sys_common::AsInner;
9+
10+
/// NetBSD-specific functionality for `AF_UNIX` sockets [`UnixDatagram`]
11+
/// and [`UnixStream`].
12+
///
13+
/// [`UnixDatagram`]: net::UnixDatagram
14+
/// [`UnixStream`]: net::UnixStream
15+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
16+
pub trait UnixSocketExt: Sealed {
17+
/// Query the current setting of socket option `LOCAL_CREDS`.
18+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
19+
fn local_creds(&self) -> io::Result<bool>;
20+
21+
/// Enable or disable socket option `LOCAL_CREDS`.
22+
///
23+
/// This option enables the credentials of the sending process to be
24+
/// received as a control message in [`AncillaryData`].
25+
///
26+
/// [`AncillaryData`]: net::AncillaryData
27+
///
28+
/// # Examples
29+
///
30+
/// ```no_run
31+
/// #![feature(unix_socket_ancillary_data)]
32+
/// use std::os::netbsd::net::UnixSocketExt;
33+
/// use std::os::unix::net::UnixDatagram;
34+
///
35+
/// fn main() -> std::io::Result<()> {
36+
/// let sock = UnixDatagram::unbound()?;
37+
/// sock.set_local_creds(true).expect("set_local_creds failed");
38+
/// Ok(())
39+
/// }
40+
/// ```
41+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
42+
fn set_local_creds(&self, local_creds: bool) -> io::Result<()>;
43+
}
44+
45+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
46+
impl UnixSocketExt for net::UnixDatagram {
47+
fn local_creds(&self) -> io::Result<bool> {
48+
self.as_inner().local_creds()
49+
}
50+
51+
fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
52+
self.as_inner().set_local_creds(local_creds)
53+
}
54+
}
55+
56+
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
57+
impl UnixSocketExt for net::UnixStream {
58+
fn local_creds(&self) -> io::Result<bool> {
59+
self.as_inner().local_creds()
60+
}
61+
62+
fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
63+
self.as_inner().set_local_creds(local_creds)
64+
}
65+
}

‎library/std/src/os/unix/net/datagram.rs

Lines changed: 12 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::io::{IoSlice, IoSliceMut};
66
use crate::net::Shutdown;
77
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
88
use crate::path::Path;
9+
use crate::sealed::Sealed;
910
use crate::sys::cvt;
1011
use crate::sys::net::Socket;
1112
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -54,6 +55,10 @@ const MSG_NOSIGNAL: libc::c_int = 0x0;
5455
#[stable(feature = "unix_socket", since = "1.10.0")]
5556
pub struct UnixDatagram(Socket);
5657

58+
/// Allows extension traits within `std`.
59+
#[unstable(feature = "sealed", issue = "none")]
60+
impl Sealed for UnixDatagram {}
61+
5762
#[stable(feature = "unix_socket", since = "1.10.0")]
5863
impl fmt::Debug for UnixDatagram {
5964
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -802,69 +807,6 @@ impl UnixDatagram {
802807
self.0.set_nonblocking(nonblocking)
803808
}
804809

805-
/// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
806-
///
807-
/// Set the socket option `SO_PASSCRED`.
808-
///
809-
/// # Examples
810-
///
811-
#[cfg_attr(
812-
any(
813-
target_os = "android",
814-
target_os = "linux",
815-
target_os = "netbsd",
816-
target_os = "freebsd",
817-
),
818-
doc = "```no_run"
819-
)]
820-
#[cfg_attr(
821-
not(any(
822-
target_os = "android",
823-
target_os = "linux",
824-
target_os = "netbsd",
825-
target_os = "freebsd"
826-
)),
827-
doc = "```ignore"
828-
)]
829-
/// #![feature(unix_socket_ancillary_data)]
830-
/// use std::os::unix::net::UnixDatagram;
831-
///
832-
/// fn main() -> std::io::Result<()> {
833-
/// let sock = UnixDatagram::unbound()?;
834-
/// sock.set_passcred(true).expect("set_passcred function failed");
835-
/// Ok(())
836-
/// }
837-
/// ```
838-
#[cfg(any(
839-
doc,
840-
target_os = "android",
841-
target_os = "linux",
842-
target_os = "netbsd",
843-
target_os = "freebsd"
844-
))]
845-
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
846-
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
847-
self.0.set_passcred(passcred)
848-
}
849-
850-
/// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
851-
/// This value can be change by [`set_passcred`].
852-
///
853-
/// Get the socket option `SO_PASSCRED`.
854-
///
855-
/// [`set_passcred`]: UnixDatagram::set_passcred
856-
#[cfg(any(
857-
doc,
858-
target_os = "android",
859-
target_os = "linux",
860-
target_os = "netbsd",
861-
target_os = "freebsd"
862-
))]
863-
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
864-
pub fn passcred(&self) -> io::Result<bool> {
865-
self.0.passcred()
866-
}
867-
868810
/// Set the id of the socket for network filtering purpose
869811
///
870812
#[cfg_attr(
@@ -1038,3 +980,10 @@ impl From<OwnedFd> for UnixDatagram {
1038980
unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
1039981
}
1040982
}
983+
984+
impl AsInner<Socket> for UnixDatagram {
985+
#[inline]
986+
fn as_inner(&self) -> &Socket {
987+
&self.0
988+
}
989+
}

‎library/std/src/os/unix/net/stream.rs

Lines changed: 12 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, Owned
1919
))]
2020
use crate::os::unix::ucred;
2121
use crate::path::Path;
22+
use crate::sealed::Sealed;
2223
use crate::sys::cvt;
2324
use crate::sys::net::Socket;
2425
use crate::sys_common::{AsInner, FromInner};
@@ -59,6 +60,10 @@ pub use ucred::UCred;
5960
#[stable(feature = "unix_socket", since = "1.10.0")]
6061
pub struct UnixStream(pub(super) Socket);
6162

63+
/// Allows extension traits within `std`.
64+
#[unstable(feature = "sealed", issue = "none")]
65+
impl Sealed for UnixStream {}
66+
6267
#[stable(feature = "unix_socket", since = "1.10.0")]
6368
impl fmt::Debug for UnixStream {
6469
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -394,69 +399,6 @@ impl UnixStream {
394399
self.0.set_nonblocking(nonblocking)
395400
}
396401

397-
/// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
398-
///
399-
/// Set the socket option `SO_PASSCRED`.
400-
///
401-
/// # Examples
402-
///
403-
#[cfg_attr(
404-
any(
405-
target_os = "android",
406-
target_os = "linux",
407-
target_os = "netbsd",
408-
target_os = "freebsd"
409-
),
410-
doc = "```no_run"
411-
)]
412-
#[cfg_attr(
413-
not(any(
414-
target_os = "android",
415-
target_os = "linux",
416-
target_os = "netbsd",
417-
target_os = "freebsd"
418-
)),
419-
doc = "```ignore"
420-
)]
421-
/// #![feature(unix_socket_ancillary_data)]
422-
/// use std::os::unix::net::UnixStream;
423-
///
424-
/// fn main() -> std::io::Result<()> {
425-
/// let socket = UnixStream::connect("/tmp/sock")?;
426-
/// socket.set_passcred(true).expect("Couldn't set passcred");
427-
/// Ok(())
428-
/// }
429-
/// ```
430-
#[cfg(any(
431-
doc,
432-
target_os = "android",
433-
target_os = "linux",
434-
target_os = "netbsd",
435-
target_os = "freebsd"
436-
))]
437-
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
438-
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
439-
self.0.set_passcred(passcred)
440-
}
441-
442-
/// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
443-
/// This value can be change by [`set_passcred`].
444-
///
445-
/// Get the socket option `SO_PASSCRED`.
446-
///
447-
/// [`set_passcred`]: UnixStream::set_passcred
448-
#[cfg(any(
449-
doc,
450-
target_os = "android",
451-
target_os = "linux",
452-
target_os = "netbsd",
453-
target_os = "freebsd"
454-
))]
455-
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
456-
pub fn passcred(&self) -> io::Result<bool> {
457-
self.0.passcred()
458-
}
459-
460402
/// Set the id of the socket for network filtering purpose
461403
///
462404
#[cfg_attr(
@@ -766,3 +708,10 @@ impl From<OwnedFd> for UnixStream {
766708
unsafe { Self::from_raw_fd(owned.into_raw_fd()) }
767709
}
768710
}
711+
712+
impl AsInner<Socket> for UnixStream {
713+
#[inline]
714+
fn as_inner(&self) -> &Socket {
715+
&self.0
716+
}
717+
}

‎library/std/src/os/unix/net/tests.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ use crate::os::android::net::SocketAddrExt;
1313
#[cfg(target_os = "linux")]
1414
use crate::os::linux::net::SocketAddrExt;
1515

16+
#[cfg(any(target_os = "android", target_os = "linux"))]
17+
use crate::os::linux::net::UnixSocketExt;
18+
1619
macro_rules! or_panic {
1720
($e:expr) => {
1821
match $e {

‎library/std/src/sys/pal/unix/net.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -465,25 +465,31 @@ impl Socket {
465465
}
466466

467467
#[cfg(target_os = "netbsd")]
468-
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
469-
setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, passcred as libc::c_int)
468+
pub fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
469+
setsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS, local_creds as libc::c_int)
470470
}
471471

472472
#[cfg(target_os = "netbsd")]
473-
pub fn passcred(&self) -> io::Result<bool> {
474-
let passcred: libc::c_int = getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)?;
475-
Ok(passcred != 0)
473+
pub fn local_creds(&self) -> io::Result<bool> {
474+
let local_creds: libc::c_int = getsockopt(self, 0 as libc::c_int, libc::LOCAL_CREDS)?;
475+
Ok(local_creds != 0)
476476
}
477477

478478
#[cfg(target_os = "freebsd")]
479-
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
480-
setsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT, passcred as libc::c_int)
479+
pub fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
480+
setsockopt(
481+
self,
482+
libc::AF_LOCAL,
483+
libc::LOCAL_CREDS_PERSISTENT,
484+
local_creds_persistent as libc::c_int,
485+
)
481486
}
482487

483488
#[cfg(target_os = "freebsd")]
484-
pub fn passcred(&self) -> io::Result<bool> {
485-
let passcred: libc::c_int = getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?;
486-
Ok(passcred != 0)
489+
pub fn local_creds_persistent(&self) -> io::Result<bool> {
490+
let local_creds_persistent: libc::c_int =
491+
getsockopt(self, libc::AF_LOCAL, libc::LOCAL_CREDS_PERSISTENT)?;
492+
Ok(local_creds_persistent != 0)
487493
}
488494

489495
#[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "vita")))]

0 commit comments

Comments
 (0)
Please sign in to comment.