From af835e10e1765849c53d2f959e4403010f896b83 Mon Sep 17 00:00:00 2001 From: Zeki Sherif Date: Fri, 6 Nov 2020 09:33:10 -0800 Subject: [PATCH 1/5] net: reintroduce getter/setter for SO_LINGER to tokio::net::tcp::stream --- tokio/Cargo.toml | 2 +- tokio/src/net/tcp/stream.rs | 72 +++++++++++++++++++++++++++++++++++++ tokio/tests/tcp_stream.rs | 16 +++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/tokio/Cargo.toml b/tokio/Cargo.toml index 1c454b9afb2..1af88fe0467 100644 --- a/tokio/Cargo.toml +++ b/tokio/Cargo.toml @@ -98,7 +98,7 @@ bytes = { version = "0.6.0", optional = true } futures-core = { version = "0.3.0", optional = true } lazy_static = { version = "1.4.0", optional = true } memchr = { version = "2.2", optional = true } -mio = { version = "0.7.5", optional = true } +mio = { version = "0.7.6", optional = true } num_cpus = { version = "1.8.0", optional = true } parking_lot = { version = "0.11.0", optional = true } slab = { version = "0.4.1", optional = true } diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs index 8a157e1c29d..cbe94105aec 100644 --- a/tokio/src/net/tcp/stream.rs +++ b/tokio/src/net/tcp/stream.rs @@ -10,6 +10,7 @@ use std::io; use std::net::{Shutdown, SocketAddr}; use std::pin::Pin; use std::task::{Context, Poll}; +use std::time::Duration; cfg_net! { /// A TCP stream between a local and a remote socket. @@ -664,6 +665,65 @@ impl TcpStream { self.io.set_nodelay(nodelay) } + /// Reads the linger duration for this socket by getting the `SO_LINGER` + /// option. + /// + /// For more information about this option, see [`set_linger`]. + /// + /// [`set_linger`]: TcpStream::set_linger + /// + /// # Examples + /// + /// ```no_run + /// use tokio::net::TcpStream; + /// + /// # async fn dox() -> Result<(), Box> { + /// let stream = TcpStream::connect("127.0.0.1:8080").await?; + /// + /// println!("{:?}", stream.linger()?); + /// # Ok(()) + /// # } + /// ``` + pub fn linger(&self) -> io::Result> { + let mio_socket = mio::net::TcpSocket::from(self); + + let result = mio_socket.get_linger(); + + std::mem::forget(mio_socket); + + result + } + + /// Sets the linger duration of this socket by setting the SO_LINGER option. + /// + /// This option controls the action taken when a stream has unsent messages and the stream is + /// closed. If SO_LINGER is set, the system shall block the process until it can transmit the + /// data or until the time expires. + /// + /// If SO_LINGER is not specified, and the stream is closed, the system handles the call in a + /// way that allows the process to continue as quickly as possible. + /// + /// # Examples + /// + /// ```no_run + /// use tokio::net::TcpStream; + /// + /// # async fn dox() -> Result<(), Box> { + /// let stream = TcpStream::connect("127.0.0.1:8080").await?; + /// + /// stream.set_linger(None)?; + /// # Ok(()) + /// # } + /// ``` + pub fn set_linger(&self, dur: Option) -> io::Result<()> { + let mio_socket = mio::net::TcpSocket::from(self); + + let result = mio_socket.set_linger(dur); + + std::mem::forget(mio_socket); + result + } + /// Gets the value of the `IP_TTL` option for this socket. /// /// For more information about this option, see [`set_ttl`]. @@ -826,6 +886,12 @@ mod sys { self.io.as_raw_fd() } } + + impl From<&TcpStream> for mio::net::TcpSocket { + fn from(stream: &TcpStream) -> Self { + unsafe { mio::net::TcpSocket::from_raw_fd(stream.as_raw_fd()) } + } + } } #[cfg(windows)] @@ -838,4 +904,10 @@ mod sys { self.io.as_raw_socket() } } + + impl From<&TcpStream> for mio::net::TcpSocket { + fn from(stream: &TcpStream) -> Self { + unsafe { mio::net::TcpSocket::from_raw_socket(stream.as_raw_socket()) } + } + } } diff --git a/tokio/tests/tcp_stream.rs b/tokio/tests/tcp_stream.rs index 84d58dc511b..58b06ee3233 100644 --- a/tokio/tests/tcp_stream.rs +++ b/tokio/tests/tcp_stream.rs @@ -9,9 +9,25 @@ use tokio_test::{assert_ok, assert_pending, assert_ready_ok}; use std::io; use std::task::Poll; +use std::time::Duration; use futures::future::poll_fn; +#[tokio::test] +async fn set_linger() { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + + let stream = TcpStream::connect(listener.local_addr().unwrap()) + .await + .unwrap(); + + assert_ok!(stream.set_linger(Some(Duration::from_secs(1)))); + assert_eq!(stream.linger().unwrap().unwrap().as_secs(), 1); + + assert_ok!(stream.set_linger(None)); + assert!(stream.linger().unwrap().is_none()); +} + #[tokio::test] async fn try_read_write() { const DATA: &[u8] = b"this is some data to write to the socket"; From 56cff9258b5c1893716aa9c36b710ec7a37d9e4a Mon Sep 17 00:00:00 2001 From: Zeki Sherif Date: Mon, 16 Nov 2020 14:48:23 -0800 Subject: [PATCH 2/5] add to_mio(&self) private fn --- tokio/src/net/tcp/stream.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs index cbe94105aec..64f30991038 100644 --- a/tokio/src/net/tcp/stream.rs +++ b/tokio/src/net/tcp/stream.rs @@ -8,6 +8,11 @@ use std::convert::TryFrom; use std::fmt; use std::io; use std::net::{Shutdown, SocketAddr}; +#[cfg(windows)] +use std::os::windows::io::{AsRawSocket, FromRawSocket}; + +#[cfg(unix)] +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; @@ -685,7 +690,7 @@ impl TcpStream { /// # } /// ``` pub fn linger(&self) -> io::Result> { - let mio_socket = mio::net::TcpSocket::from(self); + let mio_socket = self.to_mio(); let result = mio_socket.get_linger(); @@ -716,7 +721,7 @@ impl TcpStream { /// # } /// ``` pub fn set_linger(&self, dur: Option) -> io::Result<()> { - let mio_socket = mio::net::TcpSocket::from(self); + let mio_socket = self.to_mio(); let result = mio_socket.set_linger(dur); @@ -724,6 +729,18 @@ impl TcpStream { result } + fn to_mio(&self) -> mio::net::TcpSocket { + #[cfg(windows)] + { + return unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) }; + } + + #[cfg(unix)] + { + return unsafe { mio::net::TcpSocket::from_raw_fd(self.as_raw_fd()) }; + } + } + /// Gets the value of the `IP_TTL` option for this socket. /// /// For more information about this option, see [`set_ttl`]. @@ -886,12 +903,6 @@ mod sys { self.io.as_raw_fd() } } - - impl From<&TcpStream> for mio::net::TcpSocket { - fn from(stream: &TcpStream) -> Self { - unsafe { mio::net::TcpSocket::from_raw_fd(stream.as_raw_fd()) } - } - } } #[cfg(windows)] @@ -904,10 +915,4 @@ mod sys { self.io.as_raw_socket() } } - - impl From<&TcpStream> for mio::net::TcpSocket { - fn from(stream: &TcpStream) -> Self { - unsafe { mio::net::TcpSocket::from_raw_socket(stream.as_raw_socket()) } - } - } } From 824390aa0042f958d52acd41fc735ff52cc87dd0 Mon Sep 17 00:00:00 2001 From: Zeki Sherif Date: Mon, 16 Nov 2020 14:53:16 -0800 Subject: [PATCH 3/5] clippy --- tokio/src/net/tcp/stream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs index 64f30991038..c2a551a126d 100644 --- a/tokio/src/net/tcp/stream.rs +++ b/tokio/src/net/tcp/stream.rs @@ -732,12 +732,12 @@ impl TcpStream { fn to_mio(&self) -> mio::net::TcpSocket { #[cfg(windows)] { - return unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) }; + unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) } } #[cfg(unix)] { - return unsafe { mio::net::TcpSocket::from_raw_fd(self.as_raw_fd()) }; + unsafe { mio::net::TcpSocket::from_raw_fd(self.as_raw_fd()) } } } From 91f82072da854447a18f79a2f4aa60524252498a Mon Sep 17 00:00:00 2001 From: Zeki Sherif Date: Mon, 16 Nov 2020 14:56:24 -0800 Subject: [PATCH 4/5] fmt --- tokio/src/net/tcp/stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs index c2a551a126d..20fddffcddf 100644 --- a/tokio/src/net/tcp/stream.rs +++ b/tokio/src/net/tcp/stream.rs @@ -732,7 +732,7 @@ impl TcpStream { fn to_mio(&self) -> mio::net::TcpSocket { #[cfg(windows)] { - unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) } + unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) } } #[cfg(unix)] From 6b7e1bce73ff3d144abd4315d304ea8c4c0940b4 Mon Sep 17 00:00:00 2001 From: Zeki Sherif Date: Mon, 16 Nov 2020 16:01:07 -0800 Subject: [PATCH 5/5] use ManuallyDrop --- tokio/src/net/tcp/stream.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs index 20fddffcddf..f6b6b8ffd96 100644 --- a/tokio/src/net/tcp/stream.rs +++ b/tokio/src/net/tcp/stream.rs @@ -690,13 +690,9 @@ impl TcpStream { /// # } /// ``` pub fn linger(&self) -> io::Result> { - let mio_socket = self.to_mio(); + let mio_socket = std::mem::ManuallyDrop::new(self.to_mio()); - let result = mio_socket.get_linger(); - - std::mem::forget(mio_socket); - - result + mio_socket.get_linger() } /// Sets the linger duration of this socket by setting the SO_LINGER option. @@ -721,12 +717,9 @@ impl TcpStream { /// # } /// ``` pub fn set_linger(&self, dur: Option) -> io::Result<()> { - let mio_socket = self.to_mio(); - - let result = mio_socket.set_linger(dur); + let mio_socket = std::mem::ManuallyDrop::new(self.to_mio()); - std::mem::forget(mio_socket); - result + mio_socket.set_linger(dur) } fn to_mio(&self) -> mio::net::TcpSocket {