diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-11-03 01:39:54 +0100 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-11-03 01:39:54 +0100 |
| commit | 4304d2704a57c22d5b3f8576b5acebc57a6a7eef (patch) | |
| tree | 70384aa84d71d3e7060ec758d3b199dcf2a22229 /src/core/internal_network | |
| parent | e9211374ad3728cad12e6520dbaa8f90c3cce280 (diff) | |
network: close each bsd fd once and drop unwanted or malformed room packets
Two threads closing the same fd both copied the descriptor and both called
Close(), so a host socket could be closed twice, and the second closesocket
could hit an unrelated socket that had reused the host fd. CloseImpl now
frees the slot under file_descriptors_mutex first and only that thread closes
the socket; the other gets EBADF.
OnProxyPacketReceived decompressed every room packet when any fd had a
socket, including native sockets and proxy sockets on other ports. Sockets
now report through AcceptsProxyPacket whether they want a packet, and only
those are collected, so an unwanted packet is not decompressed.
DecompressDataZSTD passed the frame's declared size straight to the vector
constructor, so a malformed or unsized frame from a room member threw on the
room thread. The new TryDecompressDataZSTD rejects invalid, unsized and
oversized frames, and bsd drops such packets with a warning.
DecompressDataZSTD now returns an empty vector for them instead of throwing.
Assisted-by: Claude Opus 5.5 (investigation and implementation)
Diffstat (limited to 'src/core/internal_network')
| -rw-r--r-- | src/core/internal_network/network.cpp | 4 | ||||
| -rw-r--r-- | src/core/internal_network/socket_proxy.cpp | 28 | ||||
| -rw-r--r-- | src/core/internal_network/socket_proxy.h | 5 | ||||
| -rw-r--r-- | src/core/internal_network/sockets.h | 5 |
4 files changed, 34 insertions, 8 deletions
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index d1c436aa08..806562076d 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -1095,6 +1095,10 @@ bool Socket::IsOpened() const { return fd != INVALID_SOCKET; } +bool Socket::AcceptsProxyPacket(const ProxyPacket& packet) { + return false; +} + void Socket::HandleProxyPacket(const ProxyPacket& packet) { LOG_WARNING(Network, "ProxyPacket received, but not in Proxy mode!"); } diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 95f64b9bd0..f12891e8f5 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -30,17 +30,29 @@ ProxySocket::~ProxySocket() { fd = INVALID_SOCKET; } +bool ProxySocket::MatchesPacket(const ProxyPacket& packet) const { + if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno || + closed) { + return false; + } + if (!broadcast && packet.broadcast) { + LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode"); + return false; + } + return true; +} + +bool ProxySocket::AcceptsProxyPacket(const ProxyPacket& packet) { + std::lock_guard guard(packets_mutex); + return MatchesPacket(packet); +} + void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { { - // Runs on the room thread, while the game thread may bind, close or reconfigure the socket + // Runs on the room thread, while the game thread may bind, close or reconfigure the socket. + // Check again: the socket may have changed since AcceptsProxyPacket. std::lock_guard guard(packets_mutex); - if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno || - closed) { - return; - } - - if (!broadcast && packet.broadcast) { - LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode"); + if (!MatchesPacket(packet)) { return; } received_packets.push(packet); diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h index 5d6e35693c..078baa7806 100644 --- a/src/core/internal_network/socket_proxy.h +++ b/src/core/internal_network/socket_proxy.h @@ -22,6 +22,8 @@ public: explicit ProxySocket() noexcept; ~ProxySocket() override; + bool AcceptsProxyPacket(const ProxyPacket& packet) override; + void HandleProxyPacket(const ProxyPacket& packet) override; Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override; @@ -82,6 +84,9 @@ public: bool IsOpened() const override; private: + /// Expects packets_mutex to be held + bool MatchesPacket(const ProxyPacket& packet) const; + bool broadcast = false; bool closed = false; u32 send_timeout = 0; diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h index 37cffd4651..29b5b0f18a 100644 --- a/src/core/internal_network/sockets.h +++ b/src/core/internal_network/sockets.h @@ -89,6 +89,9 @@ public: virtual bool IsOpened() const = 0; + /// Whether HandleProxyPacket would queue the packet; checked before decompressing it + virtual bool AcceptsProxyPacket(const ProxyPacket& packet) = 0; + /// Queues a room packet whose data is already decompressed virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; @@ -164,6 +167,8 @@ public: bool IsOpened() const override; + bool AcceptsProxyPacket(const ProxyPacket& packet) override; + void HandleProxyPacket(const ProxyPacket& packet) override; private: |
