Skip to content

Commit 183bbe4

Browse files
authored
Add SO_REUSEPORT support for TCP socket (#1375)
1 parent 2b7c096 commit 183bbe4

5 files changed

Lines changed: 111 additions & 1 deletion

File tree

src/net/tcp/socket.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,25 @@ impl TcpSocket {
8282
sys::tcp::set_reuseaddr(self.sys, reuseaddr)
8383
}
8484

85+
/// Get the value of `SO_REUSEADDR` set on this socket.
86+
pub fn get_reuseaddr(&self) -> io::Result<bool> {
87+
sys::tcp::get_reuseaddr(self.sys)
88+
}
89+
90+
/// Sets the value of `SO_REUSEPORT` on this socket.
91+
/// Only supported available in unix
92+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
93+
pub fn set_reuseport(&self, reuseport: bool) -> io::Result<()> {
94+
sys::tcp::set_reuseport(self.sys, reuseport)
95+
}
96+
97+
/// Get the value of `SO_REUSEPORT` set on this socket.
98+
/// Only supported available in unix
99+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
100+
pub fn get_reuseport(&self) -> io::Result<bool> {
101+
sys::tcp::get_reuseport(self.sys)
102+
}
103+
85104
/// Sets the value of `SO_LINGER` on this socket.
86105
pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> {
87106
sys::tcp::set_linger(self.sys, dur)

src/sys/shell/tcp.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ pub(crate) fn set_reuseaddr(_: TcpSocket, _: bool) -> io::Result<()> {
3232
os_required!();
3333
}
3434

35+
pub(crate) fn get_reuseaddr(_: TcpSocket) -> io::Result<bool> {
36+
os_required!();
37+
}
38+
39+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
40+
pub(crate) fn set_reuseport(_: TcpSocket, _: bool) -> io::Result<()> {
41+
os_required!();
42+
}
43+
44+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
45+
pub(crate) fn get_reuseport(_: TcpSocket) -> io::Result<bool> {
46+
os_required!();
47+
}
48+
3549
pub(crate) fn set_linger(_: TcpSocket, _: Option<Duration>) -> io::Result<()> {
3650
os_required!();
3751
}

src/sys/unix/tcp.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::io;
2+
use std::mem;
23
use std::mem::{size_of, MaybeUninit};
34
use std::net::{self, SocketAddr};
45
use std::time::Duration;
@@ -58,6 +59,50 @@ pub(crate) fn set_reuseaddr(socket: TcpSocket, reuseaddr: bool) -> io::Result<()
5859
)).map(|_| ())
5960
}
6061

62+
pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
63+
let mut optval: libc::c_int = 0;
64+
let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
65+
66+
syscall!(getsockopt(
67+
socket,
68+
libc::SOL_SOCKET,
69+
libc::SO_REUSEADDR,
70+
&mut optval as *mut _ as *mut _,
71+
&mut optlen,
72+
))?;
73+
74+
Ok(optval != 0)
75+
}
76+
77+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
78+
pub(crate) fn set_reuseport(socket: TcpSocket, reuseport: bool) -> io::Result<()> {
79+
let val: libc::c_int = if reuseport { 1 } else { 0 };
80+
81+
syscall!(setsockopt(
82+
socket,
83+
libc::SOL_SOCKET,
84+
libc::SO_REUSEPORT,
85+
&val as *const libc::c_int as *const libc::c_void,
86+
size_of::<libc::c_int>() as libc::socklen_t,
87+
)).map(|_| ())
88+
}
89+
90+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
91+
pub(crate) fn get_reuseport(socket: TcpSocket) -> io::Result<bool> {
92+
let mut optval: libc::c_int = 0;
93+
let mut optlen = mem::size_of::<libc::c_int>() as libc::socklen_t;
94+
95+
syscall!(getsockopt(
96+
socket,
97+
libc::SOL_SOCKET,
98+
libc::SO_REUSEPORT,
99+
&mut optval as *mut _ as *mut _,
100+
&mut optlen,
101+
))?;
102+
103+
Ok(optval != 0)
104+
}
105+
61106
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
62107
let val: libc::linger = libc::linger {
63108
l_onoff: if dur.is_some() { 1 } else { 0 },

src/sys/windows/tcp.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib use
88
use winapi::ctypes::{c_char, c_int, c_ushort};
99
use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
1010
use winapi::um::winsock2::{
11-
self, closesocket, linger, setsockopt, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
11+
self, closesocket, linger, setsockopt, getsockopt, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
1212
SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
1313
};
1414

@@ -87,6 +87,22 @@ pub(crate) fn set_reuseaddr(socket: TcpSocket, reuseaddr: bool) -> io::Result<()
8787
}
8888
}
8989

90+
pub(crate) fn get_reuseaddr(socket: TcpSocket) -> io::Result<bool> {
91+
let mut optval: c_char = 0;
92+
let mut optlen = size_of::<BOOL>() as c_int;
93+
94+
match unsafe { getsockopt(
95+
socket,
96+
SOL_SOCKET,
97+
SO_REUSEADDR,
98+
&mut optval as *mut _ as *mut _,
99+
&mut optlen,
100+
) } {
101+
SOCKET_ERROR => Err(io::Error::last_os_error()),
102+
_ => Ok(optval != 0),
103+
}
104+
}
105+
90106
pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
91107
let val: linger = linger {
92108
l_onoff: if dur.is_some() { 1 } else { 0 },

tests/tcp_socket.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ fn set_reuseaddr() {
1717

1818
let socket = TcpSocket::new_v4().unwrap();
1919
socket.set_reuseaddr(true).unwrap();
20+
assert!(socket.get_reuseaddr().unwrap());
21+
22+
socket.bind(addr).unwrap();
23+
24+
let _ = socket.listen(128).unwrap();
25+
}
26+
27+
#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))]
28+
#[test]
29+
fn set_reuseport() {
30+
let addr = "127.0.0.1:0".parse().unwrap();
31+
32+
let socket = TcpSocket::new_v4().unwrap();
33+
socket.set_reuseport(true).unwrap();
34+
assert!(socket.get_reuseport().unwrap());
35+
2036
socket.bind(addr).unwrap();
2137

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

0 commit comments

Comments
 (0)