mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 19:12:50 +00:00
Rollup merge of #88495 - ibraheemdev:tcp-linger, r=joshtriplett
Add `TcpStream::set_linger` and `TcpStream::linger` Adds methods for getting/setting the `SO_LINGER` option on TCP sockets. Behavior is consistent across Unix and Windows. r? `@joshtriplett` (I noticed you've been reviewing net related PRs)
This commit is contained in:
commit
c5a34d802d
@ -401,6 +401,53 @@ impl TcpStream {
|
||||
self.0.peek(buf)
|
||||
}
|
||||
|
||||
/// Sets the value of the `SO_LINGER` option on this socket.
|
||||
///
|
||||
/// This value controls how the socket is closed when data remains
|
||||
/// to be sent. If `SO_LINGER` is set, the socket will remain open
|
||||
/// for the specified duration as the system attempts to send pending data.
|
||||
/// Otherwise, the system may close the socket immediately, or wait for a
|
||||
/// default timeout.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(tcp_linger)]
|
||||
///
|
||||
/// use std::net::TcpStream;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let stream = TcpStream::connect("127.0.0.1:8080")
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed");
|
||||
/// ```
|
||||
#[unstable(feature = "tcp_linger", issue = "88494")]
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
self.0.set_linger(linger)
|
||||
}
|
||||
|
||||
/// Gets the value of the `SO_LINGER` option on this socket.
|
||||
///
|
||||
/// For more information about this option, see [`TcpStream::set_linger`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(tcp_linger)]
|
||||
///
|
||||
/// use std::net::TcpStream;
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let stream = TcpStream::connect("127.0.0.1:8080")
|
||||
/// .expect("Couldn't connect to the server...");
|
||||
/// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed");
|
||||
/// assert_eq!(stream.linger().unwrap(), Some(Duration::from_secs(0)));
|
||||
/// ```
|
||||
#[unstable(feature = "tcp_linger", issue = "88494")]
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
self.0.linger()
|
||||
}
|
||||
|
||||
/// Sets the value of the `TCP_NODELAY` option on this socket.
|
||||
///
|
||||
/// If set, this option disables the Nagle algorithm. This means that
|
||||
|
@ -767,6 +767,21 @@ fn test_timeout_zero_duration() {
|
||||
drop(listener);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "sgx", ignore)]
|
||||
fn linger() {
|
||||
let addr = next_test_ip4();
|
||||
let _listener = t!(TcpListener::bind(&addr));
|
||||
|
||||
let stream = t!(TcpStream::connect(&("localhost", addr.port())));
|
||||
|
||||
assert_eq!(None, t!(stream.linger()));
|
||||
t!(stream.set_linger(Some(Duration::from_secs(1))));
|
||||
assert_eq!(Some(Duration::from_secs(1)), t!(stream.linger()));
|
||||
t!(stream.set_linger(None));
|
||||
assert_eq!(None, t!(stream.linger()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_env = "sgx", ignore)]
|
||||
fn nodelay() {
|
||||
|
@ -182,6 +182,14 @@ impl TcpStream {
|
||||
Ok(self.clone())
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
|
||||
abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
|
||||
.map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
|
||||
|
@ -183,6 +183,14 @@ impl TcpStream {
|
||||
Ok(self.clone())
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
sgx_ineffective(())
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
sgx_ineffective(None)
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
sgx_ineffective(())
|
||||
}
|
||||
|
@ -98,6 +98,14 @@ pub mod net {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
@ -214,6 +222,14 @@ pub mod net {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
unimpl!();
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
unimpl!();
|
||||
}
|
||||
|
@ -12,6 +12,14 @@ use crate::time::{Duration, Instant};
|
||||
|
||||
use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_vendor = "apple")] {
|
||||
use libc::SO_LINGER_SEC as SO_LINGER;
|
||||
} else {
|
||||
use libc::SO_LINGER;
|
||||
}
|
||||
}
|
||||
|
||||
pub use crate::sys::{cvt, cvt_r};
|
||||
|
||||
#[allow(unused_extern_crates)]
|
||||
@ -376,6 +384,21 @@ impl Socket {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
let linger = libc::linger {
|
||||
l_onoff: linger.is_some() as libc::c_int,
|
||||
l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
|
||||
};
|
||||
|
||||
setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger)
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?;
|
||||
|
||||
Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
|
||||
}
|
||||
|
@ -76,6 +76,14 @@ impl TcpStream {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
self.0
|
||||
}
|
||||
|
@ -127,6 +127,14 @@ impl TcpStream {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
@ -197,6 +197,7 @@ pub const SOCK_DGRAM: c_int = 2;
|
||||
pub const SOCK_STREAM: c_int = 1;
|
||||
pub const SOCKET_ERROR: c_int = -1;
|
||||
pub const SOL_SOCKET: c_int = 0xffff;
|
||||
pub const SO_LINGER: c_int = 0x0080;
|
||||
pub const SO_RCVTIMEO: c_int = 0x1006;
|
||||
pub const SO_SNDTIMEO: c_int = 0x1005;
|
||||
pub const IPPROTO_IP: c_int = 0;
|
||||
@ -216,6 +217,13 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
|
||||
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
|
||||
pub const MSG_PEEK: c_int = 0x2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct linger {
|
||||
pub l_onoff: c_ushort,
|
||||
pub l_linger: c_ushort,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ip_mreq {
|
||||
pub imr_multiaddr: in_addr,
|
||||
|
@ -15,7 +15,7 @@ use crate::sys_common::net;
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
use crate::time::Duration;
|
||||
|
||||
use libc::{c_int, c_long, c_ulong};
|
||||
use libc::{c_int, c_long, c_ulong, c_ushort};
|
||||
|
||||
pub type wrlen_t = i32;
|
||||
|
||||
@ -446,6 +446,21 @@ impl Socket {
|
||||
cvt(result).map(drop)
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
let linger = c::linger {
|
||||
l_onoff: linger.is_some() as c_ushort,
|
||||
l_linger: linger.unwrap_or_default().as_secs() as c_ushort,
|
||||
};
|
||||
|
||||
net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger)
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
|
||||
|
||||
Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE)
|
||||
}
|
||||
|
@ -297,6 +297,14 @@ impl TcpStream {
|
||||
self.inner.duplicate().map(|s| TcpStream { inner: s })
|
||||
}
|
||||
|
||||
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
|
||||
self.inner.set_linger(linger)
|
||||
}
|
||||
|
||||
pub fn linger(&self) -> io::Result<Option<Duration>> {
|
||||
self.inner.linger()
|
||||
}
|
||||
|
||||
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
|
||||
self.inner.set_nodelay(nodelay)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user