netcode-revival: fix SetRelay deadlock + grant multiplayer privileges
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
- Deadlock: SetRelay held the transport mutex while join()ing the receive thread, which needs the mutex to observe running_ and exit. With the 200ms recv timeout the thread woke and hit the lock -> a room/server change froze the game (every room keystroke reconnects the transport). StopThread now detaches the thread under the lock and joins WITHOUT it. - XamUserCheckPrivilege denied everything, which is the gate the game's 'create a party' flow checks (multiplayer sessions); grant requested privileges so the P2P session flow opens, and log the mask.
This commit is contained in:
parent
3229aa3632
commit
6fcc96de18
3 changed files with 37 additions and 15 deletions
|
|
@ -138,7 +138,10 @@ class XNetTransport {
|
||||||
XNetTransport& operator=(const XNetTransport&) = delete;
|
XNetTransport& operator=(const XNetTransport&) = delete;
|
||||||
|
|
||||||
void Reconnect();
|
void Reconnect();
|
||||||
void StopLocked();
|
// Stop the receive thread and join it WITHOUT holding mu_ (the Run thread
|
||||||
|
// needs mu_ to observe running_ and exit; joining under the lock deadlocks
|
||||||
|
// once recvfrom times out and the thread tries to lock mu_).
|
||||||
|
void StopThread();
|
||||||
void Run();
|
void Run();
|
||||||
void HandlePacket(const uint8_t* data, int size);
|
void HandlePacket(const uint8_t* data, int size);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,8 +430,13 @@ u32 XamUserCheckPrivilege_entry(u32 user_index, u32 mask, mapped_u32 out_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we deny everything, games should hopefully not try to do stuff.
|
// netcode-revival: the game gates its party/session flow on
|
||||||
*out_value = 0;
|
// XamUserCheckPrivilege (e.g. MULTIPLAYER_SESSIONS); denying everything
|
||||||
|
// (the old default) made "create a party" refuse. Grant requested online
|
||||||
|
// privileges so the P2P session flow opens.
|
||||||
|
*out_value = 1;
|
||||||
|
REXLOG_INFO("xam: XamUserCheckPrivilege(user={}, mask=0x{:08X}) -> granted",
|
||||||
|
user_index, mask);
|
||||||
return X_ERROR_SUCCESS;
|
return X_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,16 @@ XNetTransport& XNetTransport::Instance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
XNetTransport::~XNetTransport() {
|
XNetTransport::~XNetTransport() {
|
||||||
|
StopThread(); // join outside the lock (see StopThread)
|
||||||
std::lock_guard<std::mutex> lock(mu_);
|
std::lock_guard<std::mutex> lock(mu_);
|
||||||
StopLocked();
|
if (sock_ != -1) {
|
||||||
|
SocketClose(sock_);
|
||||||
|
sock_ = -1;
|
||||||
|
}
|
||||||
|
active_ = false;
|
||||||
|
joined_ = false;
|
||||||
|
sessions_.clear();
|
||||||
|
sockets_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t XNetTransport::LocalVirtualIp() {
|
uint32_t XNetTransport::LocalVirtualIp() {
|
||||||
|
|
@ -156,17 +164,29 @@ void XNetTransport::SetRelay(const char* host, uint16_t port, const char* room)
|
||||||
host_ = h;
|
host_ = h;
|
||||||
port_ = port;
|
port_ = port;
|
||||||
room_ = r;
|
room_ = r;
|
||||||
StopLocked();
|
|
||||||
}
|
}
|
||||||
|
StopThread(); // join the old thread OUTSIDE the lock
|
||||||
Reconnect();
|
Reconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XNetTransport::StopLocked() {
|
void XNetTransport::StopThread() {
|
||||||
if (thread_.joinable()) {
|
std::thread old;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mu_);
|
||||||
running_ = false;
|
running_ = false;
|
||||||
thread_.join();
|
old = std::move(thread_);
|
||||||
thread_ = {};
|
thread_ = {};
|
||||||
}
|
}
|
||||||
|
if (old.joinable()) {
|
||||||
|
old.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XNetTransport::Reconnect() {
|
||||||
|
std::lock_guard<std::mutex> lock(mu_);
|
||||||
|
if (host_.empty() || port_ == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (sock_ != -1) {
|
if (sock_ != -1) {
|
||||||
SocketClose(sock_);
|
SocketClose(sock_);
|
||||||
sock_ = -1;
|
sock_ = -1;
|
||||||
|
|
@ -174,13 +194,7 @@ void XNetTransport::StopLocked() {
|
||||||
active_ = false;
|
active_ = false;
|
||||||
joined_ = false;
|
joined_ = false;
|
||||||
sessions_.clear();
|
sessions_.clear();
|
||||||
}
|
relay_resolved_ = false;
|
||||||
|
|
||||||
void XNetTransport::Reconnect() {
|
|
||||||
std::lock_guard<std::mutex> lock(mu_);
|
|
||||||
if (host_.empty() || port_ == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sockaddr_in relay_addr = {};
|
sockaddr_in relay_addr = {};
|
||||||
if (!Resolve(host_, port_, &relay_addr)) {
|
if (!Resolve(host_, port_, &relay_addr)) {
|
||||||
REXLOG_WARN("xnet transport: cannot resolve relay '{}:{}'", host_, port_);
|
REXLOG_WARN("xnet transport: cannot resolve relay '{}:{}'", host_, port_);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue