From 5cda414795be49eb7f4b5e7c4a34f21f4a493f65 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 26 Mar 2024 22:39:12 +0000 Subject: [PATCH] std::net: adding tcp_syncnt feature for Linux/Android. to control the number of client's attempts to establish a connection. --- library/std/src/os/net/linux_ext/tcp.rs | 49 +++++++++++++++++++++++++ library/std/src/sys/pal/unix/net.rs | 11 ++++++ 2 files changed, 60 insertions(+) diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index ff29afe7ed311..ccbaf3e0f93da 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -98,6 +98,47 @@ pub trait TcpStreamExt: Sealed { #[unstable(feature = "tcp_deferaccept", issue = "119639")] #[cfg(target_os = "linux")] fn deferaccept(&self) -> io::Result; + + /// Set the number of `SYN` packets to send before giving up establishing a connection. + /// + /// In case the server does not repond, a `SYN` packet is sent by the client. + /// This option controls the number of attempts, the default system value + /// can be seen via the `net.ipv4.tcp_syn_retries` sysctl's OID (usually 5 or 6). + /// The maximum valid value is 255. + /// + /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_syncnt)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_syncnt(3).expect("set_setcnt call failed"); + #[unstable(feature = "tcp_syncnt", issue = "123112")] + fn set_syncnt(&self, count: u8) -> io::Result<()>; + + /// Get the number of `SYN` packets to send before giving up establishing a connection. + /// + /// For more information about this option, see [`TcpStreamExt::set_syncnt`]. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(tcp_syncnt)] + /// use std::net::TcpStream; + /// use std::os::linux::net::TcpStreamExt; + /// + /// let stream = TcpStream::connect("127.0.0.1:8080") + /// .expect("Couldn't connect to the server..."); + /// stream.set_syncnt(3).expect("set_syncnt call failed"); + /// assert_eq!(stream.syncnt().unwrap_or(0), 3); + /// ``` + #[unstable(feature = "tcp_syncnt", issue = "123112")] + fn syncnt(&self) -> io::Result; } #[unstable(feature = "tcp_quickack", issue = "96256")] @@ -122,4 +163,12 @@ impl TcpStreamExt for net::TcpStream { fn deferaccept(&self) -> io::Result { self.as_inner().as_inner().deferaccept() } + + fn set_syncnt(&self, count: u8) -> io::Result<()> { + self.as_inner().as_inner().set_syncnt(count) + } + + fn syncnt(&self) -> io::Result { + self.as_inner().as_inner().syncnt() + } } diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 9a0a1b18aee0d..c21e6e8f647ea 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -453,6 +453,17 @@ impl Socket { Ok(raw as u32) } + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn set_syncnt(&self, count: u8) -> io::Result<()> { + setsockopt(self, libc::IPPROTO_TCP, libc::TCP_SYNCNT, count as c_int) + } + + #[cfg(any(target_os = "android", target_os = "linux",))] + pub fn syncnt(&self) -> io::Result { + let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_SYNCNT)?; + Ok(raw as u8) + } + #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] pub fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> { if !name.to_bytes().is_empty() {