Skip to content

Commit 8790c3c

Browse files
committed
Auto merge of #119636 - devnexen:linux_tcp_defer_accept, r=m-ou-se
os::net: expanding TcpStreamExt for Linux with `tcp_deferaccept`. allows for socket to process only when there is data to process, the option sets a number of seconds until the data is ready.
2 parents b6e4299 + 85bf443 commit 8790c3c

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

library/std/src/os/net/linux_ext/tcp.rs

+55
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,51 @@ pub trait TcpStreamExt: Sealed {
5353
/// ```
5454
#[unstable(feature = "tcp_quickack", issue = "96256")]
5555
fn quickack(&self) -> io::Result<bool>;
56+
57+
/// A socket listener will be awakened solely when data arrives.
58+
///
59+
/// The `accept` argument set the delay in seconds until the
60+
/// data is available to read, reducing the number of short lived
61+
/// connections without data to process.
62+
/// Contrary to other platforms `SO_ACCEPTFILTER` feature equivalent, there is
63+
/// no necessity to set it after the `listen` call.
64+
///
65+
/// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html)
66+
///
67+
/// # Examples
68+
///
69+
/// ```no run
70+
/// #![feature(tcp_deferaccept)]
71+
/// use std::net::TcpStream;
72+
/// use std::os::linux::net::TcpStreamExt;
73+
///
74+
/// let stream = TcpStream::connect("127.0.0.1:8080")
75+
/// .expect("Couldn't connect to the server...");
76+
/// stream.set_deferaccept(1).expect("set_deferaccept call failed");
77+
/// ```
78+
#[unstable(feature = "tcp_deferaccept", issue = "119639")]
79+
#[cfg(target_os = "linux")]
80+
fn set_deferaccept(&self, accept: u32) -> io::Result<()>;
81+
82+
/// Gets the accept delay value (in seconds) of the `TCP_DEFER_ACCEPT` option.
83+
///
84+
/// For more information about this option, see [`TcpStreamExt::set_deferaccept`].
85+
///
86+
/// # Examples
87+
///
88+
/// ```no_run
89+
/// #![feature(tcp_deferaccept)]
90+
/// use std::net::TcpStream;
91+
/// use std::os::linux::net::TcpStreamExt;
92+
///
93+
/// let stream = TcpStream::connect("127.0.0.1:8080")
94+
/// .expect("Couldn't connect to the server...");
95+
/// stream.set_deferaccept(1).expect("set_deferaccept call failed");
96+
/// assert_eq!(stream.deferaccept().unwrap_or(0), 1);
97+
/// ```
98+
#[unstable(feature = "tcp_deferaccept", issue = "119639")]
99+
#[cfg(target_os = "linux")]
100+
fn deferaccept(&self) -> io::Result<u32>;
56101
}
57102

58103
#[unstable(feature = "tcp_quickack", issue = "96256")]
@@ -67,4 +112,14 @@ impl TcpStreamExt for net::TcpStream {
67112
fn quickack(&self) -> io::Result<bool> {
68113
self.as_inner().as_inner().quickack()
69114
}
115+
116+
#[cfg(target_os = "linux")]
117+
fn set_deferaccept(&self, accept: u32) -> io::Result<()> {
118+
self.as_inner().as_inner().set_deferaccept(accept)
119+
}
120+
121+
#[cfg(target_os = "linux")]
122+
fn deferaccept(&self) -> io::Result<u32> {
123+
self.as_inner().as_inner().deferaccept()
124+
}
70125
}

library/std/src/os/net/linux_ext/tests.rs

+26
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,29 @@ fn quickack() {
2626
t!(stream.set_quickack(false));
2727
assert_eq!(false, t!(stream.quickack()));
2828
}
29+
30+
#[test]
31+
#[cfg(target_os = "linux")]
32+
fn deferaccept() {
33+
use crate::{
34+
net::{test::next_test_ip4, TcpListener, TcpStream},
35+
os::net::linux_ext::tcp::TcpStreamExt,
36+
};
37+
38+
macro_rules! t {
39+
($e:expr) => {
40+
match $e {
41+
Ok(t) => t,
42+
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
43+
}
44+
};
45+
}
46+
47+
let addr = next_test_ip4();
48+
let _listener = t!(TcpListener::bind(&addr));
49+
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
50+
stream.set_deferaccept(1).expect("set_deferaccept failed");
51+
assert_eq!(stream.deferaccept().unwrap(), 1);
52+
stream.set_deferaccept(0).expect("set_deferaccept failed");
53+
assert_eq!(stream.deferaccept().unwrap(), 0);
54+
}

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

+12
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,18 @@ impl Socket {
441441
Ok(raw != 0)
442442
}
443443

444+
// bionic libc makes no use of this flag
445+
#[cfg(target_os = "linux")]
446+
pub fn set_deferaccept(&self, accept: u32) -> io::Result<()> {
447+
setsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT, accept as c_int)
448+
}
449+
450+
#[cfg(target_os = "linux")]
451+
pub fn deferaccept(&self) -> io::Result<u32> {
452+
let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_DEFER_ACCEPT)?;
453+
Ok(raw as u32)
454+
}
455+
444456
#[cfg(any(target_os = "android", target_os = "linux",))]
445457
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
446458
setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)

0 commit comments

Comments
 (0)