fix(lib): keep the server connection alive with TCP keepalive
A NAT that drops an idle mapping leaves the server socket looking connected while the server can no longer reach us, and nothing errors: peers stop finding us and searches go unanswered until a restart. The server socket now carries TCP keepalive (idle 10s, interval 2s, ten probes), which keeps the mapping alive and turns a dead path into a read error within about half a minute, as Nicotine+ does. The server stopped answering ServerPing (code 32) long ago, so an application ping is no substitute. Windows gets a no-op until the daemon ships there.
This commit is contained in:
@@ -350,6 +350,9 @@ impl ServerActor {
|
||||
return false;
|
||||
}
|
||||
stream.set_nodelay(true).ok();
|
||||
if let Err(e) = crate::utils::keepalive::set_keepalive(&stream) {
|
||||
warn!("[server] keepalive not set: {}", e);
|
||||
}
|
||||
|
||||
self.stream = Some(stream);
|
||||
self.connection_state = ConnectionState::Connecting {
|
||||
@@ -1020,6 +1023,22 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn the_server_socket_keeps_itself_alive() {
|
||||
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let mut actor = parked_actor(listener.local_addr().unwrap().port());
|
||||
|
||||
assert!(actor.initiate_connection());
|
||||
|
||||
assert!(
|
||||
crate::utils::keepalive::keepalive_enabled(
|
||||
actor.stream.as_ref().unwrap()
|
||||
),
|
||||
"an idle NAT mapping must be kept alive and a dead path noticed"
|
||||
);
|
||||
}
|
||||
|
||||
fn parked_actor(port: u16) -> ServerActor {
|
||||
let (tx, _rx) = std::sync::mpsc::channel();
|
||||
ServerActor::new(
|
||||
|
||||
Reference in New Issue
Block a user