Skip to content

Commit f1d312f

Browse files
committed
add opts for enabling keep-alive. and enabled by default
- ref #490
1 parent 86336c4 commit f1d312f

File tree

3 files changed

+104
-15
lines changed

3 files changed

+104
-15
lines changed

crates/shadowsocks/src/net/option.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ pub struct TcpSocketOpts {
1616

1717
/// `TCP_FASTOPEN`, enables TFO
1818
pub fastopen: bool,
19+
20+
/// `TCP_KEEPALIVE`, enables keep-alive messages on connection-oriented sockets
21+
pub keepalive: bool,
1922
}
2023

2124
impl Default for TcpSocketOpts {
@@ -25,6 +28,7 @@ impl Default for TcpSocketOpts {
2528
recv_buffer_size: None,
2629
nodelay: false,
2730
fastopen: false,
31+
keepalive: true,
2832
}
2933
}
3034
}

crates/shadowsocks/src/net/sys/mod.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,66 @@ fn set_common_sockopt_for_connect(addr: SocketAddr, socket: &TcpSocket, opts: &C
4646
}
4747

4848
fn set_common_sockopt_after_connect(stream: &tokio::net::TcpStream, opts: &ConnectOpts) -> io::Result<()> {
49-
if opts.tcp.nodelay {
50-
stream.set_nodelay(true)?;
51-
}
49+
stream.set_nodelay(opts.tcp.nodelay)?;
50+
set_common_sockopt_after_connect_sys(stream, opts)?;
51+
52+
Ok(())
53+
}
54+
55+
#[cfg(unix)]
56+
#[inline]
57+
fn set_common_sockopt_after_connect_sys(stream: &tokio::net::TcpStream, opts: &ConnectOpts) -> io::Result<()> {
58+
use socket2::Socket;
59+
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
60+
61+
let socket = unsafe { Socket::from_raw_fd(stream.as_raw_fd()) };
62+
63+
macro_rules! try_sockopt {
64+
($socket:ident . $func:ident ($($arg:expr),*)) => {
65+
match $socket . $func ($($arg),*) {
66+
Ok(e) => e,
67+
Err(err) => {
68+
let _ = socket.into_raw_fd();
69+
return Err(err);
70+
}
71+
}
72+
};
73+
}
74+
75+
try_sockopt!(socket.set_keepalive(opts.tcp.keepalive));
76+
77+
let _ = socket.into_raw_fd();
78+
Ok(())
79+
}
80+
81+
#[cfg(windows)]
82+
#[inline]
83+
fn set_common_sockopt_after_connect_sys(stream: &tokio::net::TcpStream, opts: &ConnectOpts) -> io::Result<()> {
84+
use socket2::Socket;
85+
use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket};
86+
87+
let socket = unsafe { Socket::from_raw_socket(stream.as_raw_socket()) };
88+
89+
macro_rules! try_sockopt {
90+
($socket:ident . $func:ident ($($arg:expr),*)) => {
91+
match $socket . $func ($($arg),*) {
92+
Ok(e) => e,
93+
Err(err) => {
94+
let _ = socket.into_raw_socket();
95+
return Err(err);
96+
}
97+
}
98+
};
99+
}
100+
101+
try_sockopt!(socket.set_keepalive(opts.tcp.keepalive));
102+
103+
let _ = socket.into_raw_socket();
104+
Ok(())
105+
}
52106

107+
#[cfg(all(not(windows), not(unix)))]
108+
#[inline]
109+
fn set_common_sockopt_after_connect_sys(_: &tokio::net::TcpStream, _: &ConnectOpts) -> io::Result<()> {
53110
Ok(())
54111
}

crates/shadowsocks/src/net/tcp.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,41 +241,69 @@ impl From<TcpListener> for TokioTcpListener {
241241
}
242242

243243
#[cfg(unix)]
244-
fn setsockopt_with_opt<F: AsRawFd>(f: &F, opts: &AcceptOpts) -> io::Result<()> {
244+
fn setsockopt_with_opt(f: &tokio::net::TcpStream, opts: &AcceptOpts) -> io::Result<()> {
245245
let socket = unsafe { Socket::from_raw_fd(f.as_raw_fd()) };
246246

247+
macro_rules! try_sockopt {
248+
($socket:ident . $func:ident ($($arg:expr),*)) => {
249+
match $socket . $func ($($arg),*) {
250+
Ok(e) => e,
251+
Err(err) => {
252+
let _ = socket.into_raw_fd();
253+
return Err(err);
254+
}
255+
}
256+
};
257+
}
258+
247259
if let Some(buf_size) = opts.tcp.send_buffer_size {
248-
socket.set_send_buffer_size(buf_size as usize)?;
260+
try_sockopt!(socket.set_send_buffer_size(buf_size as usize));
249261
}
250262

251263
if let Some(buf_size) = opts.tcp.recv_buffer_size {
252-
socket.set_recv_buffer_size(buf_size as usize)?;
264+
try_sockopt!(socket.set_recv_buffer_size(buf_size as usize));
253265
}
254266

255-
if opts.tcp.nodelay {
256-
socket.set_nodelay(true)?;
257-
}
267+
try_sockopt!(socket.set_nodelay(opts.tcp.nodelay));
268+
try_sockopt!(socket.set_keepalive(opts.tcp.keepalive));
258269

259270
let _ = socket.into_raw_fd();
260271
Ok(())
261272
}
262273

263274
#[cfg(windows)]
264-
fn setsockopt_with_opt<F: AsRawSocket>(f: &F, opts: &AcceptOpts) -> io::Result<()> {
275+
fn setsockopt_with_opt(f: &tokio::net::TcpStream, opts: &AcceptOpts) -> io::Result<()> {
265276
let socket = unsafe { Socket::from_raw_socket(f.as_raw_socket()) };
266277

278+
macro_rules! try_sockopt {
279+
($socket:ident . $func:ident ($($arg:expr),*)) => {
280+
match $socket . $func ($($arg),*) {
281+
Ok(e) => e,
282+
Err(err) => {
283+
let _ = socket.into_raw_socket();
284+
return Err(err);
285+
}
286+
}
287+
};
288+
}
289+
267290
if let Some(buf_size) = opts.tcp.send_buffer_size {
268-
socket.set_send_buffer_size(buf_size as usize)?;
291+
try_sockopt!(socket.set_send_buffer_size(buf_size as usize));
269292
}
270293

271294
if let Some(buf_size) = opts.tcp.recv_buffer_size {
272-
socket.set_recv_buffer_size(buf_size as usize)?;
295+
try_sockopt!(socket.set_recv_buffer_size(buf_size as usize));
273296
}
274297

275-
if opts.tcp.nodelay {
276-
socket.set_nodelay(true)?;
277-
}
298+
try_sockopt!(socket.set_nodelay(opts.tcp.nodelay));
299+
try_sockopt!(socket.set_keepalive(opts.tcp.keepalive));
278300

279301
let _ = socket.into_raw_socket();
280302
Ok(())
281303
}
304+
305+
#[cfg(all(not(windows), not(unix)))]
306+
fn setsockopt_with_opt(f: &tokio::net::TcpStream, opts: &AcceptOpts) -> io::Result<()> {
307+
f.set_nodelay(opts.tcp.nodelay)?;
308+
Ok(())
309+
}

0 commit comments

Comments
 (0)