netcode-revival: pack the relay wire structs + heartbeat + transport logging
- #pragma pack(push,1) on the wire structs (the relay's proto is packed; the transport's were not, which would inflate sizes and corrupt every datagram) plus static_asserts pinning sizes to 7/31/1410/25/801. - Heartbeat re-JOIN every 4s so the relay never times the transport out. - REXLOG info for connect/join/session-reply so the flow is observable.
This commit is contained in:
parent
bf3635d7ad
commit
01fe706c13
3 changed files with 43 additions and 1 deletions
|
|
@ -32,6 +32,10 @@ namespace system {
|
|||
|
||||
class XSocket;
|
||||
|
||||
// The wire structs below must match the relay's byte-for-byte (the main repo
|
||||
// packs them with #pragma pack(1); leaving padding here would inflate the
|
||||
// sizes and silently corrupt every datagram).
|
||||
#pragma pack(push, 1)
|
||||
// Header of every relay datagram ("GHST" magic, little-endian type + size).
|
||||
// Must match kGhostMagic / PacketHeader in skate3_native_ghost_proto.h.
|
||||
struct XNetRelayHeader {
|
||||
|
|
@ -69,6 +73,7 @@ struct XNetRelaySessionReply {
|
|||
uint8_t count;
|
||||
XNetRelaySessionEntry list[32];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// One discovered session (a member of our room).
|
||||
struct XNetSession {
|
||||
|
|
@ -143,6 +148,9 @@ class XNetTransport {
|
|||
// header stays platform-independent.
|
||||
uint8_t relay_addr_[16] = {};
|
||||
bool relay_resolved_ = false;
|
||||
uint8_t join_pkt_[7 + sizeof(XNetRelayJoin)] = {};
|
||||
uint16_t join_pkt_size_ = 0;
|
||||
double last_join_ = 0.0; // monotonic seconds (heartbeat to beat the timeout)
|
||||
std::thread thread_;
|
||||
bool running_ = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <thread>
|
||||
|
||||
#include <rex/platform.h>
|
||||
#include <rex/logging.h>
|
||||
#include <rex/system/kernel_state.h>
|
||||
#include <rex/system/xsocket.h>
|
||||
#include <rex/system/xam/user_profile.h>
|
||||
|
|
@ -29,6 +30,15 @@
|
|||
namespace rex {
|
||||
namespace system {
|
||||
|
||||
// Pin the packed wire sizes to the values the relay expects (the game-side
|
||||
// proto packs them identically). Catches accidental un-packing or member
|
||||
// edits before they corrupt the wire.
|
||||
static_assert(sizeof(XNetRelayHeader) == 7, "relay header must be 7 bytes");
|
||||
static_assert(sizeof(XNetRelayJoin) == 31, "relay join must be 31 bytes");
|
||||
static_assert(sizeof(XNetRelayGame) == 1410, "relay game payload must be 1410 bytes");
|
||||
static_assert(sizeof(XNetRelaySessionEntry) == 25, "session entry must be 25 bytes");
|
||||
static_assert(sizeof(XNetRelaySessionReply) == 801, "session reply must be 801 bytes");
|
||||
|
||||
namespace {
|
||||
|
||||
// Virtual address range: 10.80.0.0/16 (host order prefix 0x0A500000).
|
||||
|
|
@ -156,14 +166,19 @@ void XNetTransport::Reconnect() {
|
|||
}
|
||||
sockaddr_in relay_addr = {};
|
||||
if (!Resolve(host_, port_, &relay_addr)) {
|
||||
REXLOG_WARN("xnet transport: cannot resolve relay '{}:{}'", host_, port_);
|
||||
return;
|
||||
}
|
||||
std::memcpy(relay_addr_, &relay_addr, sizeof(relay_addr));
|
||||
relay_resolved_ = true;
|
||||
sock_ = SocketCreate();
|
||||
if (sock_ == -1) {
|
||||
REXLOG_WARN("xnet transport: cannot open relay socket");
|
||||
return;
|
||||
}
|
||||
REXLOG_INFO("xnet transport: connecting to relay '{}:{}' room '{}' (vip {}.{}.{}.{})", host_,
|
||||
port_, room_.c_str(), (LocalVirtualIp() >> 24) & 0xFF, (LocalVirtualIp() >> 16) & 0xFF,
|
||||
(LocalVirtualIp() >> 8) & 0xFF, LocalVirtualIp() & 0xFF);
|
||||
// Join the room so the relay routes our game traffic among its members.
|
||||
XNetRelayJoin jp = {};
|
||||
jp.version = kVersion;
|
||||
|
|
@ -184,6 +199,12 @@ void XNetTransport::Reconnect() {
|
|||
std::memcpy(pkt + 7, &jp, sizeof(jp));
|
||||
SocketSendTo(sock_, &relay_addr, pkt, sizeof(pkt));
|
||||
|
||||
// Keep the JOIN around for the heartbeat (the relay drops silent clients
|
||||
// after ~8s).
|
||||
std::memcpy(join_pkt_, pkt, sizeof(pkt));
|
||||
join_pkt_size_ = uint16_t(sizeof(pkt));
|
||||
last_join_ = 0.0;
|
||||
|
||||
running_ = true;
|
||||
thread_ = std::thread(&XNetTransport::Run, this);
|
||||
}
|
||||
|
|
@ -271,6 +292,14 @@ void XNetTransport::Run() {
|
|||
if (!running_) {
|
||||
return;
|
||||
}
|
||||
// Heartbeat: re-JOIN every ~4s so the relay never times us out.
|
||||
const double now =
|
||||
double(std::chrono::steady_clock::now().time_since_epoch().count()) / 1e9;
|
||||
if (join_pkt_size_ != 0 && now - last_join_ >= 4.0) {
|
||||
SocketSendTo(sock_, reinterpret_cast<const sockaddr_in*>(relay_addr_), join_pkt_,
|
||||
join_pkt_size_);
|
||||
last_join_ = now;
|
||||
}
|
||||
}
|
||||
uint8_t buf[7 + sizeof(XNetRelayGame)];
|
||||
sockaddr_in from = {};
|
||||
|
|
@ -307,6 +336,9 @@ void XNetTransport::HandlePacket(const uint8_t* data, int size) {
|
|||
// session_id != 0 means accepted (0 = refused).
|
||||
active_ = payload[0] != 0;
|
||||
joined_ = true;
|
||||
REXLOG_INFO("xnet transport: relay {} (vip {}.{}.{}.{})", active_ ? "joined" : "refused",
|
||||
(LocalVirtualIp() >> 24) & 0xFF, (LocalVirtualIp() >> 16) & 0xFF,
|
||||
(LocalVirtualIp() >> 8) & 0xFF, LocalVirtualIp() & 0xFF);
|
||||
break;
|
||||
}
|
||||
case kGame: {
|
||||
|
|
@ -350,6 +382,8 @@ void XNetTransport::HandlePacket(const uint8_t* data, int size) {
|
|||
std::lock_guard<std::mutex> lock(mu_);
|
||||
sessions_ = std::move(fresh);
|
||||
++reply_seq_;
|
||||
REXLOG_INFO("xnet transport: session reply with {} session(s) in room '{}'", count,
|
||||
room_.c_str());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
2
thirdparty/imgui
vendored
2
thirdparty/imgui
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit cdda62349d6068e906c2e0ee340d6ec31eedbb9c
|
||||
Subproject commit 0af8f475d1cf8b98d603702059c0c73deeb81ac2
|
||||
Loading…
Add table
Reference in a new issue