From 7c5df8abed92b6c7f88cb41f450a217f9f1ae8bc Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Tue, 14 Jul 2026 11:58:04 -0400 Subject: [PATCH] add possible protective controls around RPTL/RPTK/RPTC/RPT_DISC to mitigate multi-threaded race condition from rapid disconnect/connection scenarios; --- src/fne/network/TrafficNetwork.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/fne/network/TrafficNetwork.cpp b/src/fne/network/TrafficNetwork.cpp index a369c83b..d0e91bb8 100644 --- a/src/fne/network/TrafficNetwork.cpp +++ b/src/fne/network/TrafficNetwork.cpp @@ -36,6 +36,7 @@ using namespace compress; #include #include #include +#include // --------------------------------------------------------------------------- // Constants @@ -51,6 +52,8 @@ const uint64_t PACKET_LATE_TIME = 250U; // 250ms const uint32_t FIXED_HA_UPDATE_INTERVAL = 30U; // 30s +const size_t PEER_STATE_LOCK_STRIPES = 256U; + // --------------------------------------------------------------------------- // Static Class Members // --------------------------------------------------------------------------- @@ -58,6 +61,22 @@ const uint32_t FIXED_HA_UPDATE_INTERVAL = 30U; // 30s std::timed_mutex TrafficNetwork::s_keyQueueMutex; std::timed_mutex TrafficNetwork::s_llaKeyQueueMutex; +std::array s_peerStateLocks; + +// --------------------------------------------------------------------------- +// Global Functions +// --------------------------------------------------------------------------- + +/** + * @brief Gets the mutex for a specific peer ID. + * @param peerId The ID of the peer. + * @return A reference to the mutex associated with the peer ID. + */ +inline std::mutex& getPeerStateLock(uint32_t peerId) +{ + return s_peerStateLocks[peerId % PEER_STATE_LOCK_STRIPES]; +} + // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- @@ -1197,6 +1216,8 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) case NET_FUNC::RPTL: // Repeater/Peer Login { + std::lock_guard peerGuard(getPeerStateLock(peerId)); + if (peerId > 0 && (network->m_peers.find(peerId) == network->m_peers.end())) { if (network->m_peers.size() >= MAX_HARD_CONN_CAP) { LogError(LOG_MASTER, "PEER %u attempted to connect with no more connections available, currConnections = %u", peerId, network->m_peers.size()); @@ -1289,6 +1310,8 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) case NET_FUNC::RPTK: // Repeater/Peer Authentication { if (peerId > 0 && (network->m_peers.find(peerId) != network->m_peers.end())) { + std::lock_guard peerGuard(getPeerStateLock(peerId)); + FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { connection->lastPing(now); @@ -1397,6 +1420,8 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) case NET_FUNC::RPTC: // Repeater/Peer Configuration { if (peerId > 0 && (network->m_peers.find(peerId) != network->m_peers.end())) { + std::lock_guard peerGuard(getPeerStateLock(peerId)); + FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { connection->lastPing(now); @@ -1647,6 +1672,8 @@ void TrafficNetwork::taskNetworkRx(NetPacketRequest* req) case NET_FUNC::RPT_DISC: // Repeater/Peer Disconnect { if (peerId > 0 && (network->m_peers.find(peerId) != network->m_peers.end())) { + std::lock_guard peerGuard(getPeerStateLock(peerId)); + FNEPeerConnection* connection = network->m_peers[peerId]; if (connection != nullptr) { std::string ip = udp::Socket::address(req->address);