about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichał Łowicki <mlowicki@gmail.com>2025-04-18 10:38:17 +0200
committerMichał Łowicki <michal.lowicki@datadoghq.com>2025-06-16 09:15:17 +0200
commit426ab142507fca8704d934da556f1c96b0fd61b2 (patch)
tree971db0ea8dc6503539410cda2de05189570c6264
parented44c0e3b3a4f90c464361ec6892c1d42c15ea8f (diff)
downloadrust-426ab142507fca8704d934da556f1c96b0fd61b2.tar.gz
rust-426ab142507fca8704d934da556f1c96b0fd61b2.zip
Set MSG_NOSIGNAL for UnixSteam
https://github.com/rust-lang/rust/issues/139956

fix
-rw-r--r--library/std/src/net/tcp.rs6
-rw-r--r--library/std/src/os/unix/net/stream.rs23
-rw-r--r--library/std/src/sys/net/connection/socket/unix.rs8
3 files changed, 36 insertions, 1 deletions
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 6a951426407..10685b49319 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -53,6 +53,12 @@ use crate::time::Duration;
 ///     Ok(())
 /// } // the stream is closed here
 /// ```
+///
+/// # Platform-specific Behavior
+///
+/// On Unix, writes to the underlying socket in `SOCK_STREAM` mode are made with
+/// `MSG_NOSIGNAL` flag. This suppresses the emission of the  `SIGPIPE` signal when writing
+/// to disconnected socket. In some cases, getting a `SIGPIPE` would trigger process termination.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct TcpStream(net_imp::TcpStream);
 
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 1bd3bab5e37..035768a6fab 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -1,3 +1,18 @@
+cfg_if::cfg_if! {
+    if #[cfg(any(
+        target_os = "linux", target_os = "android",
+        target_os = "hurd",
+        target_os = "dragonfly", target_os = "freebsd",
+        target_os = "openbsd", target_os = "netbsd",
+        target_os = "solaris", target_os = "illumos",
+        target_os = "haiku", target_os = "nto",
+        target_os = "cygwin"))] {
+        use libc::MSG_NOSIGNAL;
+    } else {
+        const MSG_NOSIGNAL: core::ffi::c_int = 0x0;
+    }
+}
+
 use super::{SocketAddr, sockaddr_un};
 #[cfg(any(doc, target_os = "android", target_os = "linux"))]
 use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to};
@@ -41,6 +56,12 @@ use crate::time::Duration;
 ///     Ok(())
 /// }
 /// ```
+///
+/// # `SIGPIPE`
+///
+/// Writes to the underlying socket in `SOCK_STREAM` mode are made with `MSG_NOSIGNAL` flag.
+/// This suppresses the emission of the  `SIGPIPE` signal when writing to disconnected socket.
+/// In some cases getting a `SIGPIPE` would trigger process termination.
 #[stable(feature = "unix_socket", since = "1.10.0")]
 pub struct UnixStream(pub(super) Socket);
 
@@ -633,7 +654,7 @@ impl io::Write for UnixStream {
 #[stable(feature = "unix_socket", since = "1.10.0")]
 impl<'a> io::Write for &'a UnixStream {
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
+        self.0.send_with_flags(buf, MSG_NOSIGNAL)
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index b35d5d2aa84..b2a4961c3c5 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -281,6 +281,14 @@ impl Socket {
         self.0.duplicate().map(Socket)
     }
 
+    pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
+        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let ret = cvt(unsafe {
+            libc::send(self.as_raw_fd(), buf.as_ptr() as *const c_void, len, flags)
+        })?;
+        Ok(ret as usize)
+    }
+
     fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
         let ret = cvt(unsafe {
             libc::recv(