From 786e8755e7f8142c90a82351a11ad51acf5e1460 Mon Sep 17 00:00:00 2001
From: Berend-Jan Lange <berendjanlange@Berend-Jans-MBP.home>
Date: Fri, 22 Apr 2022 21:39:09 +0200
Subject: [PATCH] created tcpstream quickack trait for linux and android

---
 library/std/src/net/mod.rs        |  2 +-
 library/std/src/os/android/mod.rs |  1 +
 library/std/src/os/android/net.rs |  4 ++
 library/std/src/os/linux/mod.rs   |  1 +
 library/std/src/os/linux/net.rs   |  4 ++
 library/std/src/os/mod.rs         |  3 ++
 library/std/src/os/net/mod.rs     |  7 ++++
 library/std/src/os/net/tcp.rs     | 70 +++++++++++++++++++++++++++++++
 library/std/src/os/net/tests.rs   | 29 +++++++++++++
 library/std/src/sys/unix/net.rs   | 11 +++++
 library/std/src/sys_common/net.rs |  8 +++-
 11 files changed, 138 insertions(+), 2 deletions(-)
 create mode 100644 library/std/src/os/android/net.rs
 create mode 100644 library/std/src/os/linux/net.rs
 create mode 100644 library/std/src/os/net/mod.rs
 create mode 100644 library/std/src/os/net/tcp.rs
 create mode 100644 library/std/src/os/net/tests.rs

diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs
index e7a40bdaf8e..6f9743f3a0e 100644
--- a/library/std/src/net/mod.rs
+++ b/library/std/src/net/mod.rs
@@ -41,7 +41,7 @@ mod ip;
 mod parser;
 mod tcp;
 #[cfg(test)]
-mod test;
+pub(crate) mod test;
 mod udp;
 
 /// Possible values which can be passed to the [`TcpStream::shutdown`] method.
diff --git a/library/std/src/os/android/mod.rs b/library/std/src/os/android/mod.rs
index dbb0127f369..5adcb82b6a4 100644
--- a/library/std/src/os/android/mod.rs
+++ b/library/std/src/os/android/mod.rs
@@ -3,4 +3,5 @@
 #![stable(feature = "raw_ext", since = "1.1.0")]
 
 pub mod fs;
+pub mod net;
 pub mod raw;
diff --git a/library/std/src/os/android/net.rs b/library/std/src/os/android/net.rs
new file mode 100644
index 00000000000..ff96125c37b
--- /dev/null
+++ b/library/std/src/os/android/net.rs
@@ -0,0 +1,4 @@
+//! Linux and Android-specific definitions for socket options.
+
+#![unstable(feature = "tcp_quickack", issue = "96256")]
+pub use crate::os::net::tcp::TcpStreamExt;
diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs
index 8e7776f6646..c17053011ad 100644
--- a/library/std/src/os/linux/mod.rs
+++ b/library/std/src/os/linux/mod.rs
@@ -4,5 +4,6 @@
 #![doc(cfg(target_os = "linux"))]
 
 pub mod fs;
+pub mod net;
 pub mod process;
 pub mod raw;
diff --git a/library/std/src/os/linux/net.rs b/library/std/src/os/linux/net.rs
new file mode 100644
index 00000000000..ff96125c37b
--- /dev/null
+++ b/library/std/src/os/linux/net.rs
@@ -0,0 +1,4 @@
+//! Linux and Android-specific definitions for socket options.
+
+#![unstable(feature = "tcp_quickack", issue = "96256")]
+pub use crate::os::net::tcp::TcpStreamExt;
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 6fbaa42c768..18c64b51007 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -148,3 +148,6 @@ pub mod vxworks;
 
 #[cfg(any(unix, target_os = "wasi", doc))]
 mod fd;
+
+#[cfg(any(target_os = "linux", target_os = "android", doc))]
+mod net;
diff --git a/library/std/src/os/net/mod.rs b/library/std/src/os/net/mod.rs
new file mode 100644
index 00000000000..d6d84d24ec4
--- /dev/null
+++ b/library/std/src/os/net/mod.rs
@@ -0,0 +1,7 @@
+//! Linux and Android-specific definitions for socket options.
+
+#![unstable(feature = "tcp_quickack", issue = "96256")]
+#![doc(cfg(any(target_os = "linux", target_os = "android",)))]
+pub mod tcp;
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/os/net/tcp.rs b/library/std/src/os/net/tcp.rs
new file mode 100644
index 00000000000..5e9ee65a415
--- /dev/null
+++ b/library/std/src/os/net/tcp.rs
@@ -0,0 +1,70 @@
+//! Linux and Android-specific tcp extensions to primitives in the [`std::net`] module.
+//!
+//! [`std::net`]: crate::net
+
+use crate::io;
+use crate::net;
+use crate::sealed::Sealed;
+use crate::sys_common::AsInner;
+
+/// Os-specific extensions for [`TcpStream`]
+///
+/// [`TcpStream`]: net::TcpStream
+#[unstable(feature = "tcp_quickack", issue = "96256")]
+pub trait TcpStreamExt: Sealed {
+    /// Enable or disable `TCP_QUICKACK`.
+    ///
+    /// This flag causes Linux to eagerly send ACKs rather than delaying them.
+    /// Linux may reset this flag after further operations on the socket.
+    ///
+    /// See [`man 7 tcp`](https://man7.org/linux/man-pages/man7/tcp.7.html) and
+    /// [TCP delayed acknowledgement](https://en.wikipedia.org/wiki/TCP_delayed_acknowledgment)
+    /// for more information.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(tcp_quickack)]
+    /// 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_quickack(true).expect("set_quickack call failed");
+    /// ```
+    #[unstable(feature = "tcp_quickack", issue = "96256")]
+    fn set_quickack(&self, quickack: bool) -> io::Result<()>;
+
+    /// Gets the value of the `TCP_QUICKACK` option on this socket.
+    ///
+    /// For more information about this option, see [`TcpStreamExt::set_quickack`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(tcp_quickack)]
+    /// 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_quickack(true).expect("set_quickack call failed");
+    /// assert_eq!(stream.quickack().unwrap_or(false), true);
+    /// ```
+    #[unstable(feature = "tcp_quickack", issue = "96256")]
+    fn quickack(&self) -> io::Result<bool>;
+}
+
+#[unstable(feature = "tcp_quickack", issue = "96256")]
+impl Sealed for net::TcpStream {}
+
+#[unstable(feature = "tcp_quickack", issue = "96256")]
+impl TcpStreamExt for net::TcpStream {
+    fn set_quickack(&self, quickack: bool) -> io::Result<()> {
+        self.as_inner().as_inner().set_quickack(quickack)
+    }
+
+    fn quickack(&self) -> io::Result<bool> {
+        self.as_inner().as_inner().quickack()
+    }
+}
diff --git a/library/std/src/os/net/tests.rs b/library/std/src/os/net/tests.rs
new file mode 100644
index 00000000000..4704e315691
--- /dev/null
+++ b/library/std/src/os/net/tests.rs
@@ -0,0 +1,29 @@
+#[cfg(any(target_os = "android", target_os = "linux",))]
+#[test]
+fn quickack() {
+    use crate::{
+        net::{test::next_test_ip4, TcpListener, TcpStream},
+        os::net::tcp::TcpStreamExt,
+    };
+
+    macro_rules! t {
+        ($e:expr) => {
+            match $e {
+                Ok(t) => t,
+                Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+            }
+        };
+    }
+
+    let addr = next_test_ip4();
+    let _listener = t!(TcpListener::bind(&addr));
+
+    let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+    t!(stream.set_quickack(false));
+    assert_eq!(false, t!(stream.quickack()));
+    t!(stream.set_quickack(true));
+    assert_eq!(true, t!(stream.quickack()));
+    t!(stream.set_quickack(false));
+    assert_eq!(false, t!(stream.quickack()));
+}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 462a45b01ab..85dcfc747af 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -392,6 +392,17 @@ impl Socket {
         Ok(raw != 0)
     }
 
+    #[cfg(any(target_os = "android", target_os = "linux",))]
+    pub fn set_quickack(&self, quickack: bool) -> io::Result<()> {
+        setsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK, quickack as c_int)
+    }
+
+    #[cfg(any(target_os = "android", target_os = "linux",))]
+    pub fn quickack(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_QUICKACK)?;
+        Ok(raw != 0)
+    }
+
     #[cfg(any(target_os = "android", target_os = "linux",))]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 33d336c4317..3ad802afa8f 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -10,7 +10,7 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::ptr;
 use crate::sys::net::netc as c;
 use crate::sys::net::{cvt, cvt_gai, cvt_r, init, wrlen_t, Socket};
-use crate::sys_common::{FromInner, IntoInner};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
 use libc::{c_int, c_void};
@@ -345,6 +345,12 @@ impl TcpStream {
     }
 }
 
+impl AsInner<Socket> for TcpStream {
+    fn as_inner(&self) -> &Socket {
+        &self.inner
+    }
+}
+
 impl FromInner<Socket> for TcpStream {
     fn from_inner(socket: Socket) -> TcpStream {
         TcpStream { inner: socket }