netcode-revival: receive timeout on the relay transport socket
Some checks are pending
Lint & Format Check / Format Check (push) Waiting to run
Some checks are pending
Lint & Format Check / Format Check (push) Waiting to run
The Run thread blocked in recvfrom with no SO_RCVTIMEO, so when there was no inbound game traffic the 4s heartbeat never fired (the relay swept the silent transport client after ~8s) AND StopLocked()'s join() deadlocked SetRelay on a room change (hanging the ghost network loop). A 200ms receive timeout wakes the loop regularly: the heartbeat keeps the transport alive and shutdown/room-change joins complete promptly.
This commit is contained in:
parent
01fe706c13
commit
3ec27d115b
1 changed files with 19 additions and 0 deletions
|
|
@ -60,6 +60,23 @@ void SocketClose(int64_t s) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The receive loop must wake regularly so the heartbeat fires even with no
|
||||||
|
// inbound traffic (otherwise the relay sweeps a silent transport client
|
||||||
|
// after ~8s) and so StopLocked()'s join completes promptly instead of
|
||||||
|
// deadlocking SetRelay on a room change.
|
||||||
|
void SocketSetRecvTimeout(int64_t s, int timeout_ms) {
|
||||||
|
#if REX_PLATFORM_WIN32
|
||||||
|
DWORD tv = DWORD(timeout_ms);
|
||||||
|
::setsockopt(SOCKET(s), SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
reinterpret_cast<const char*>(&tv), sizeof(tv));
|
||||||
|
#else
|
||||||
|
timeval tv = {};
|
||||||
|
tv.tv_sec = timeout_ms / 1000;
|
||||||
|
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||||
|
::setsockopt(int(s), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool SocketSendTo(int64_t s, const sockaddr_in* to, const void* buf, int size) {
|
bool SocketSendTo(int64_t s, const sockaddr_in* to, const void* buf, int size) {
|
||||||
#if REX_PLATFORM_WIN32
|
#if REX_PLATFORM_WIN32
|
||||||
const int n = ::sendto(SOCKET(s), reinterpret_cast<const char*>(buf), size, 0,
|
const int n = ::sendto(SOCKET(s), reinterpret_cast<const char*>(buf), size, 0,
|
||||||
|
|
@ -176,6 +193,8 @@ void XNetTransport::Reconnect() {
|
||||||
REXLOG_WARN("xnet transport: cannot open relay socket");
|
REXLOG_WARN("xnet transport: cannot open relay socket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Wake the receive loop every 200ms (heartbeat + prompt shutdown).
|
||||||
|
SocketSetRecvTimeout(sock_, 200);
|
||||||
REXLOG_INFO("xnet transport: connecting to relay '{}:{}' room '{}' (vip {}.{}.{}.{})", host_,
|
REXLOG_INFO("xnet transport: connecting to relay '{}:{}' room '{}' (vip {}.{}.{}.{})", host_,
|
||||||
port_, room_.c_str(), (LocalVirtualIp() >> 24) & 0xFF, (LocalVirtualIp() >> 16) & 0xFF,
|
port_, room_.c_str(), (LocalVirtualIp() >> 24) & 0xFF, (LocalVirtualIp() >> 16) & 0xFF,
|
||||||
(LocalVirtualIp() >> 8) & 0xFF, LocalVirtualIp() & 0xFF);
|
(LocalVirtualIp() >> 8) & 0xFF, LocalVirtualIp() & 0xFF);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue