mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-12 18:35:16 -10:00
Server: the game thread is the keep-alive timeout's only judge; kick, then close a second later
The writer thread's own check raced it and logged "Disconnected" instead of vanilla's "Timed out". Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
5fb90b440c
commit
c3601b74f3
2 files changed
+18
-21
No files matched your search
@@ -1337,22 +1337,16 @@ fn write_loop(
|
||||
Err(RecvTimeoutError::Timeout) => {}
|
||||
}
|
||||
let now = Instant::now();
|
||||
if let Some((id, at)) = sent_at {
|
||||
if alive.load(Ordering::Relaxed) == id {
|
||||
let ms = i32::try_from(at.elapsed().as_millis()).unwrap_or(i32::MAX);
|
||||
let old = latency.load(Ordering::Relaxed);
|
||||
latency.store((old * 3 + ms) / 4, Ordering::Relaxed);
|
||||
sent_at = None;
|
||||
} else if at.elapsed() >= KEEP_ALIVE_EVERY {
|
||||
let _ = writer.send(
|
||||
&play::Clientbound::Disconnect(cfg::Disconnect {
|
||||
reason: translatable("disconnect.timeout", &[]),
|
||||
})
|
||||
.encode(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
if let Some((id, at)) = sent_at
|
||||
&& alive.load(Ordering::Relaxed) == id
|
||||
{
|
||||
let ms = i32::try_from(at.elapsed().as_millis()).unwrap_or(i32::MAX);
|
||||
let old = latency.load(Ordering::Relaxed);
|
||||
latency.store((old * 3 + ms) / 4, Ordering::Relaxed);
|
||||
sent_at = None;
|
||||
}
|
||||
// The game thread times a client out ([`PlayerSender::timed_out`]):
|
||||
// this thread may be blocked on a client that stopped reading.
|
||||
if sent_at.is_none() && now >= next {
|
||||
let id = i64::try_from(start.elapsed().as_millis()).unwrap_or(0);
|
||||
if writer
|
||||
|
||||
@@ -1192,10 +1192,16 @@ impl Hub {
|
||||
}
|
||||
}
|
||||
}
|
||||
// keepConnectionAlive's timeout, checked once a second here as well:
|
||||
// a client that stops reading blocks its writer thread, which sends
|
||||
// the keep-alives and checks them, and would hold its slot forever.
|
||||
// keepConnectionAlive's timeout, checked once a second here, not on
|
||||
// the writer thread: a client that stops reading blocks that thread
|
||||
// and would hold its slot forever. Kicked, it gets the reason; still
|
||||
// here a second later, its connection is closed under the writer.
|
||||
if self.ticks.is_multiple_of(20) {
|
||||
for g in &self.guests {
|
||||
if !g.left_reason.is_empty() && g.sender.timed_out() {
|
||||
g.sender.close();
|
||||
}
|
||||
}
|
||||
let silent: Vec<u32> = self
|
||||
.guests
|
||||
.iter()
|
||||
@@ -1204,9 +1210,6 @@ impl Hub {
|
||||
.collect();
|
||||
for conn in silent {
|
||||
self.kick(conn, translatable("disconnect.timeout", &[]));
|
||||
if let Some(g) = self.guest(conn) {
|
||||
g.sender.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
events
|
||||
|
||||
Reference in new issue
Block a user