From d24a0d3c2052cedefb67b10f21afd28c6ae8f82b Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 2 Jan 2026 13:12:58 +0100 Subject: [PATCH 1/4] Don't set SO_NOSIGPIPE when accepting sockets This is inherited from the parent socket. Furthermore when attempting to set it on a Unix socket domain it will result in an error. --- src/socket.rs | 32 +++++++++++++++++++++++++++++--- tests/socket.rs | 26 +++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 22fe858b..5d865239 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -285,7 +285,7 @@ impl Socket { )))] { let (socket, addr) = self.accept_raw()?; - let socket = set_common_flags(socket)?; + let socket = set_common_accept_flags(socket)?; // `set_common_flags` does not disable inheritance on Windows because `Socket::new` // unlike `accept` is able to create the socket with inheritance disabled. #[cfg(windows)] @@ -762,8 +762,6 @@ const fn set_common_type(ty: Type) -> Type { } /// Set `FD_CLOEXEC` and `NOSIGPIPE` on the `socket` for platforms that need it. -#[inline(always)] -#[allow(clippy::unnecessary_wraps)] fn set_common_flags(socket: Socket) -> io::Result { // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`. #[cfg(all( @@ -798,6 +796,34 @@ fn set_common_flags(socket: Socket) -> io::Result { Ok(socket) } +/// Set `FD_CLOEXEC` on the `socket` for platforms that need it. +/// +/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited. +/// Furthermore attempts to set it on a unix socket domain results in an error. +fn set_common_accept_flags(socket: Socket) -> io::Result { + // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`. + #[cfg(all( + unix, + not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "espidf", + target_os = "vita", + target_os = "cygwin", + )) + ))] + socket._set_cloexec(true)?; + + Ok(socket) +} + /// A local interface specified by its index or an address assigned to it. /// /// `Index(0)` and `Address(Ipv4Addr::UNSPECIFIED)` are equivalent and indicate diff --git a/tests/socket.rs b/tests/socket.rs index d34083cc..b553fcda 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -511,7 +511,7 @@ where panic!("unexpected error: {}", io::Error::last_os_error()); } assert_eq!(length as usize, size_of::()); - assert_eq!(flags, want as _, "non-blocking option"); + assert_eq!(flags, want as _); } const DATA: &[u8] = b"hello world"; @@ -631,6 +631,30 @@ fn unix() { assert_eq!(&buf[..n], DATA); } +#[test] +fn unix_accept() { + if !unix_sockets_supported() { + return; + } + let mut path = env::temp_dir(); + path.push("socket2"); + let _ = fs::remove_dir_all(&path); + fs::create_dir_all(&path).unwrap(); + path.push("unix_accept"); + + let listener = Socket::new(Domain::UNIX, Type::STREAM, None).unwrap(); + listener.bind(&SockAddr::unix(&path).unwrap()).unwrap(); + listener.listen(1).unwrap(); + + Socket::new(Domain::UNIX, Type::STREAM, None) + .unwrap() + .connect(&SockAddr::unix(path).unwrap()) + .unwrap(); + + let (socket, _) = listener.accept().unwrap(); + assert_common_flags(&socket, true); +} + #[test] #[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))] #[ignore = "using VSOCK family requires optional kernel support (works when enabled)"] From ac349595a7078fddee5fcf392acad47e4b00fe47 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 2 Jan 2026 13:20:51 +0100 Subject: [PATCH 2/4] Add approriate cfg attributes to set_common_accept_flags --- src/socket.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/socket.rs b/src/socket.rs index 5d865239..469b3140 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -800,6 +800,17 @@ fn set_common_flags(socket: Socket) -> io::Result { /// /// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited. /// Furthermore attempts to set it on a unix socket domain results in an error. +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", +)))] fn set_common_accept_flags(socket: Socket) -> io::Result { // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`. #[cfg(all( From 00e848531cc29a94937b4548c4e4fd8c212ea667 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 2 Jan 2026 13:26:21 +0100 Subject: [PATCH 3/4] Make test directories unique The directory are removed at the start of the test (the line after the change), which means on test can remove the other tests' created files. --- tests/socket.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/socket.rs b/tests/socket.rs index b553fcda..86dc8059 100644 --- a/tests/socket.rs +++ b/tests/socket.rs @@ -605,7 +605,7 @@ fn unix() { return; } let mut path = env::temp_dir(); - path.push("socket2"); + path.push("socket2.unix"); let _ = fs::remove_dir_all(&path); fs::create_dir_all(&path).unwrap(); path.push("unix"); @@ -637,7 +637,7 @@ fn unix_accept() { return; } let mut path = env::temp_dir(); - path.push("socket2"); + path.push("socket2.unix_accept"); let _ = fs::remove_dir_all(&path); fs::create_dir_all(&path).unwrap(); path.push("unix_accept"); From 7ff8d7da11ce76f127df6dee74ce6a49ef334128 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Fri, 2 Jan 2026 13:27:57 +0100 Subject: [PATCH 4/4] Documentation improvements As suggested by Alice. --- src/socket.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 469b3140..7a6832a3 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -762,6 +762,8 @@ const fn set_common_type(ty: Type) -> Type { } /// Set `FD_CLOEXEC` and `NOSIGPIPE` on the `socket` for platforms that need it. +/// +/// Sockets created via `accept` should use `set_common_accept_flags` instead. fn set_common_flags(socket: Socket) -> io::Result { // On platforms that don't have `SOCK_CLOEXEC` use `FD_CLOEXEC`. #[cfg(all( @@ -798,8 +800,9 @@ fn set_common_flags(socket: Socket) -> io::Result { /// Set `FD_CLOEXEC` on the `socket` for platforms that need it. /// -/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited. -/// Furthermore attempts to set it on a unix socket domain results in an error. +/// Unlike `set_common_flags` we don't set `NOSIGPIPE` as that is inherited from +/// the listener. Furthermore, attempts to set it on a unix socket domain +/// results in an error. #[cfg(not(any( target_os = "android", target_os = "dragonfly",