summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZeki Sherif <9832640+zekisherif@users.noreply.github.com>2020-11-17 11:58:00 -0600
committerGitHub <noreply@github.com>2020-11-17 09:58:00 -0800
commit7d11aa866837eea50a6f1e0ef7e24846a653cbf1 (patch)
treeca0d5edc04a29bbe6e2906c760a22908e032a4c9
parent0ea23076503c5151d68a781a3d91823396c82949 (diff)
net: add SO_LINGER get/set to TcpStream (#3143)
-rw-r--r--tokio/src/net/tcp/stream.rs70
-rw-r--r--tokio/tests/tcp_stream.rs16
2 files changed, 86 insertions, 0 deletions
diff --git a/tokio/src/net/tcp/stream.rs b/tokio/src/net/tcp/stream.rs
index 7427ba54..de7b4213 100644
--- a/tokio/src/net/tcp/stream.rs
+++ b/tokio/src/net/tcp/stream.rs
@@ -8,8 +8,14 @@ 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;
cfg_net! {
/// A TCP stream between a local and a remote socket.
@@ -663,6 +669,70 @@ 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<dyn std::error::Error>> {
+ /// let stream = TcpStream::connect("127.0.0.1:8080").await?;
+ ///
+ /// println!("{:?}", stream.linger()?);
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ let mio_socket = std::mem::ManuallyDrop::new(self.to_mio());
+
+ mio_socket.get_linger()
+ }
+
+ /// 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<dyn std::error::Error>> {
+ /// let stream = TcpStream::connect("127.0.0.1:8080").await?;
+ ///
+ /// stream.set_linger(None)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
+ let mio_socket = std::mem::ManuallyDrop::new(self.to_mio());
+
+ mio_socket.set_linger(dur)
+ }
+
+ fn to_mio(&self) -> mio::net::TcpSocket {
+ #[cfg(windows)]
+ {
+ unsafe { mio::net::TcpSocket::from_raw_socket(self.as_raw_socket()) }
+ }
+
+ #[cfg(unix)]
+ {
+ 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`].
diff --git a/tokio/tests/tcp_stream.rs b/tokio/tests/tcp_stream.rs
index 84d58dc5..58b06ee3 100644
--- a/tokio/tests/tcp_stream.rs
+++ b/tokio/tests/tcp_stream.rs
@@ -9,10 +9,26 @@ 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";