Skip to content

Commit

Permalink
Support setting SO_LINGER
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeki Sherif committed Nov 6, 2020
1 parent f5017fa commit ffb1366
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/net/tcp/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ impl TcpSocket {
sys::tcp::set_linger(self.sys, dur)
}

/// Gets the value of `SO_LINGER` on this socket
pub fn get_linger(&self) -> io::Result<Option<Duration>> {
sys::tcp::get_linger(self.sys)
}

/// Sets the value of `SO_RCVBUF` on this socket.
pub fn set_recv_buffer_size(&self, size: u32) -> io::Result<()> {
sys::tcp::set_recv_buffer_size(self.sys, size)
Expand Down
4 changes: 4 additions & 0 deletions src/sys/shell/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ pub(crate) fn set_linger(_: TcpSocket, _: Option<Duration>) -> io::Result<()> {
os_required!();
}

pub(crate) fn get_linger(_: TcpSocket) -> io::Result<Option<Duration>> {
os_required!();
}

pub(crate) fn set_recv_buffer_size(_: TcpSocket, _: u32) -> io::Result<()> {
os_required!();
}
Expand Down
19 changes: 19 additions & 0 deletions src/sys/unix/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,25 @@ pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result
)).map(|_| ())
}

pub(crate) fn get_linger(socket: TcpSocket) -> io::Result<Option<Duration>> {
let mut val: libc::linger = unsafe { std::mem::zeroed() };
let mut len = mem::size_of::<libc::linger>() as libc::socklen_t;

syscall!(getsockopt(
socket,
libc::SOL_SOCKET,
libc::SO_LINGER,
&mut val as *mut _ as *mut _,
&mut len,
))?;

if val.l_onoff == 0 {
Ok(None)
} else {
Ok(Some(Duration::from_secs(val.l_linger as u64)))
}
}

pub(crate) fn set_recv_buffer_size(socket: TcpSocket, size: u32) -> io::Result<()> {
let size = size.try_into().ok().unwrap_or_else(i32::max_value);
syscall!(setsockopt(
Expand Down
24 changes: 22 additions & 2 deletions src/sys/windows/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ pub(crate) fn get_localaddr(socket: TcpSocket) -> io::Result<SocketAddr> {
}
},
}


}

pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
Expand All @@ -150,6 +148,28 @@ pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result
}
}

pub(crate) fn get_linger(socket: TcpSocket) -> io::Result<Option<Duration>> {
let mut val: linger = unsafe { std::mem::zeroed() };
let mut len = size_of::<linger>() as c_int;

match unsafe { getsockopt(
socket,
SOL_SOCKET,
SO_LINGER,
&mut val as *mut _ as *mut _,
&mut len,
) } {
SOCKET_ERROR => Err(io::Error::last_os_error()),
_ => {
if val.l_onoff == 0 {
Ok(None)
} else {
Ok(Some(Duration::from_secs(val.l_linger as u64)))
}
},
}
}


pub(crate) fn set_recv_buffer_size(socket: TcpSocket, size: u32) -> io::Result<()> {
let size = size.try_into().ok().unwrap_or_else(i32::max_value);
Expand Down
18 changes: 17 additions & 1 deletion tests/tcp_socket.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(all(feature = "os-poll", feature = "tcp"))]

use mio::net::TcpSocket;
use std::io;
use std::time::Duration;

#[test]
fn is_send_and_sync() {
Expand Down Expand Up @@ -58,6 +58,22 @@ fn get_localaddr() {
let _ = socket.listen(128).unwrap();
}

#[test]
fn set_linger() {
let addr = "127.0.0.1:0".parse().unwrap();

let socket = TcpSocket::new_v4().unwrap();
socket.set_linger(Some(Duration::from_secs(1))).unwrap();
assert_eq!(socket.get_linger().unwrap().unwrap().as_secs(), 1);

let _ = socket.set_linger(None);
assert_eq!(socket.get_linger().unwrap(), None);

socket.bind(addr).unwrap();

let _ = socket.listen(128).unwrap();
}

#[test]
fn send_buffer_size_roundtrips() {
test_buffer_sizes(
Expand Down

0 comments on commit ffb1366

Please sign in to comment.