diff --git a/library/std/src/os/net/linux_ext/tcp.rs b/library/std/src/os/net/linux_ext/tcp.rs index 2fc6b2769568e..3e77546bad265 100644 --- a/library/std/src/os/net/linux_ext/tcp.rs +++ b/library/std/src/os/net/linux_ext/tcp.rs @@ -72,21 +72,26 @@ pub impl(self) trait TcpStreamExt { #[stable(feature = "tcp_quickack", since = "1.89.0")] fn quickack(&self) -> io::Result; - /// A socket listener will be awakened solely when data arrives. + /// Configures the `TCP_DEFER_ACCEPT` option on the socket. /// - /// The `accept` argument set the maximum delay until the - /// data is available to read, reducing the number of short lived - /// connections without data to process. - /// Contrary to other platforms `SO_ACCEPTFILTER` feature equivalent, there is - /// no necessity to set it after the `listen` call. - /// Note that the delay is expressed as Duration from user's perspective - /// the call rounds it down to the nearest second expressible as a `c_int`. + /// This defers accepting an incoming connection that has not yet received data. + /// The `accept` argument specifies an approximate delay. /// - /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) + /// Currently, the standard library rounds the duration down to whole seconds, + /// capped at `c_int::MAX` seconds. This may change if the underlying API becomes + /// more expressive. Passing [`Duration::ZERO`] disables this option. + /// + /// This option can also limit the number of attempts TCP makes to complete a + /// connection, so connections may be dropped if more retransmissions are needed. + /// + /// Unlike the equivalent `SO_ACCEPTFILTER` option on other platforms, this option + /// can be set before calling `listen`. + /// + /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) for more information. /// /// # Examples /// - /// ```no run + /// ```no_run /// #![feature(tcp_deferaccept)] /// use std::net::TcpStream; /// use std::os::linux::net::TcpStreamExt; @@ -94,15 +99,19 @@ pub impl(self) trait TcpStreamExt { /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); - /// stream.set_deferaccept(Duration::from_secs(1u64)).expect("set_deferaccept call failed"); + /// stream.set_defer_accept(Duration::from_secs(1u64)).expect("set_defer_accept call failed"); /// ``` #[unstable(feature = "tcp_deferaccept", issue = "119639")] #[cfg(target_os = "linux")] - fn set_deferaccept(&self, accept: Duration) -> io::Result<()>; + fn set_defer_accept(&self, accept: Duration) -> io::Result<()>; /// Gets the accept delay value of the `TCP_DEFER_ACCEPT` option. /// - /// For more information about this option, see [`TcpStreamExt::set_deferaccept`]. + /// Returns [`None`] if this option is disabled, or [`Some`] containing the delay + /// otherwise. The returned duration may differ from the requested duration due + /// to rounding. + /// + /// For more information about this option, see [`TcpStreamExt::set_defer_accept`]. /// /// # Examples /// @@ -121,12 +130,14 @@ pub impl(self) trait TcpStreamExt { /// /// let stream = TcpStream::connect("127.0.0.1:8080") /// .expect("Couldn't connect to the server..."); - /// stream.set_deferaccept(Duration::from_secs(1u64)).expect("set_deferaccept call failed"); - /// assert_eq!(stream.deferaccept().unwrap(), Duration::from_secs(1u64)); + /// stream.set_defer_accept(Duration::from_secs(1u64)).expect("set_defer_accept call failed"); + /// assert_eq!(stream.defer_accept().unwrap(), Some(Duration::from_secs(1u64))); + /// stream.set_defer_accept(Duration::ZERO).expect("set_defer_accept call failed"); + /// assert_eq!(stream.defer_accept().unwrap(), None); /// ``` #[unstable(feature = "tcp_deferaccept", issue = "119639")] #[cfg(target_os = "linux")] - fn deferaccept(&self) -> io::Result; + fn defer_accept(&self) -> io::Result>; } #[stable(feature = "tcp_quickack", since = "1.89.0")] @@ -140,12 +151,12 @@ impl TcpStreamExt for net::TcpStream { } #[cfg(target_os = "linux")] - fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { - self.as_inner().as_inner().set_deferaccept(accept) + fn set_defer_accept(&self, accept: Duration) -> io::Result<()> { + self.as_inner().as_inner().set_defer_accept(accept) } #[cfg(target_os = "linux")] - fn deferaccept(&self) -> io::Result { - self.as_inner().as_inner().deferaccept() + fn defer_accept(&self) -> io::Result> { + self.as_inner().as_inner().defer_accept() } } diff --git a/library/std/src/os/net/linux_ext/tests.rs b/library/std/src/os/net/linux_ext/tests.rs index a63524e63b6d8..daa2f36f1af7f 100644 --- a/library/std/src/os/net/linux_ext/tests.rs +++ b/library/std/src/os/net/linux_ext/tests.rs @@ -28,7 +28,7 @@ fn quickack() { #[test] #[cfg(target_os = "linux")] -fn deferaccept() { +fn defer_accept() { use crate::net::tests::LOCALHOST_IP4; use crate::net::{TcpListener, TcpStream}; use crate::os::net::linux_ext::tcp::TcpStreamExt; @@ -44,13 +44,13 @@ fn deferaccept() { } let one = Duration::from_secs(1u64); - let zero = Duration::from_secs(0u64); + let zero = Duration::ZERO; let listener = t!(TcpListener::bind(LOCALHOST_IP4)); let addr = t!(listener.local_addr()); let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - stream.set_deferaccept(one).expect("set_deferaccept failed"); - assert_eq!(stream.deferaccept().unwrap(), one); - stream.set_deferaccept(zero).expect("set_deferaccept failed"); - assert_eq!(stream.deferaccept().unwrap(), zero); + stream.set_defer_accept(one).expect("set_defer_accept failed"); + assert_eq!(stream.defer_accept().unwrap(), Some(one)); + stream.set_defer_accept(zero).expect("set_defer_accept failed"); + assert_eq!(stream.defer_accept().unwrap(), None); } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 15e9dc2c7cc9d..1b4985edf92ee 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -490,15 +490,15 @@ impl Socket { // bionic libc makes no use of this flag #[cfg(target_os = "linux")] - pub fn set_deferaccept(&self, accept: Duration) -> io::Result<()> { + pub fn set_defer_accept(&self, accept: Duration) -> io::Result<()> { let val = cmp::min(accept.as_secs(), c_int::MAX as u64) as c_int; unsafe { setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, val) } } #[cfg(target_os = "linux")] - pub fn deferaccept(&self) -> io::Result { + pub fn defer_accept(&self) -> io::Result> { let raw: c_int = unsafe { getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)? }; - Ok(Duration::from_secs(raw as _)) + Ok((raw != 0).then(|| Duration::from_secs(raw as u64))) } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]