Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ class NetworkMesh
void SendACPacket(uint32_t userID, const void* pData, uint32_t dataLen);

void StartConnectionSignalling(const char* szMiddlewareID, int64_t remoteUserID, uint16_t preferredPort);

// A joiner gets its TURN credentials after its mesh exists; signalling waits for them
void AwaitTurnCredentials();
void SetTurnCredentials(const std::string& strUsername, const std::string& strToken);

void DisconnectUser(int64_t remoteUserID);
void Disconnect();

Expand Down Expand Up @@ -272,6 +277,15 @@ class NetworkMesh
std::string m_strTurnTokenString;
std::string m_strTurnServerList;

struct PendingSignalling
{
std::string strMiddlewareID;
int64_t remoteUserID;
uint16_t preferredPort;
};
bool m_bAwaitingTurnCredentials = false;
std::vector<PendingSignalling> m_vecSignallingAwaitingTurn;

// k_nSteamNetworkingConfig_P2P_Transport_ICE_Enable_* for this lobby's connections.
int m_iceEnable = 0;
int m_iceImplementation = 2;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <atomic>

enum class EConnectionState : uint8_t
{
NOT_CONNECTED,
Expand Down Expand Up @@ -55,7 +57,8 @@ enum class EAnticheatActionReason : int32_t
class AnticheatPlugInterface
{
public:
static bool g_bPendingExitLobby;
// set from plugin threads
static std::atomic<bool> g_bPendingExitLobby;

static void AC_NetworkMessageArrived(uint32_t goUserID, void* pData, uint32_t dataLen);

Expand Down Expand Up @@ -207,7 +210,8 @@ extern HWND ApplicationHWnd;
class AnticheatPlugInterface
{
public:
static bool g_bPendingExitLobby;
// set from plugin threads
static std::atomic<bool> g_bPendingExitLobby;

static void AC_NetworkMessageArrived(uint32_t goUserID, void* pData, uint32_t dataLen)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
NGMP_OnlineServices_LobbyInterface* pJoinOrderLobby = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
const bool bWeJoinedLater = pJoinOrderLobby == nullptr || !pJoinOrderLobby->IsJoinOrderKnown() || pJoinOrderLobby->JoinedAfter(userID);
const bool bPeerLeft = pJoinOrderLobby != nullptr && pJoinOrderLobby->IsJoinOrderKnown() && !pJoinOrderLobby->IsLobbyMember(userID);
bool bShouldRetry = serviceConf.retry_signalling && ((!bWeJoinedLater && !bPeerLeft) || signallingAttemptsBeforeDisconnect < numSignallingAttempts);
// a match can't leave its lobby, so keep repairing the link until the game drops the player
const bool bInMatch = TheGameLogic != nullptr && TheGameLogic->isInInternetGame();
bool bShouldRetry = serviceConf.retry_signalling && (bInMatch || (!bWeJoinedLater && !bPeerLeft) || signallingAttemptsBeforeDisconnect < numSignallingAttempts);

bool bWasError = pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally || pInfo->m_info.m_eEndReason != k_ESteamNetConnectionEnd_App_Generic;
plrConnection.SetDisconnected(bWasError, pMesh, bShouldRetry && bWasError);
Expand Down Expand Up @@ -173,7 +175,12 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
NetworkLog(ELogVerbosity::LOG_RELEASE, "[STEAM NETWORKING][DISCONNECT HANDLER] Not retrying, handling disconnect as failure...");

NGMP_OnlineServices_LobbyInterface* pLobbyInterface = NGMP_OnlineServicesManager::GetInterface<NGMP_OnlineServices_LobbyInterface>();
if (pLobbyInterface != nullptr)
if (pLobbyInterface != nullptr && pLobbyInterface->IsHost())
{
// the host keeps its lobby; the peer that can't connect is the one to go
NetworkLog(ELogVerbosity::LOG_RELEASE, "[STEAM NETWORKING][DISCONNECT HANDLER] Not leaving, we host this lobby; dropping user %lld only", userID);
}
else if (pLobbyInterface != nullptr)
{
NetworkLog(ELogVerbosity::LOG_RELEASE, "[STEAM NETWORKING][DISCONNECT HANDLER] Performing local removal for user %lld from lobby due to failure to connect\n", userID);

Expand Down Expand Up @@ -871,6 +878,14 @@ void NetworkMesh::StartConnectionSignalling(const char* szMiddlewareID, int64_t
}
else
{
// no relay without our TURN credentials
if (m_bAwaitingTurnCredentials)
{
NetworkLog(ELogVerbosity::LOG_RELEASE, "[SIGNAL] Holding signalling with %lld until our TURN credentials arrive", remoteUserID);
m_vecSignallingAwaitingTurn.push_back({ szMiddlewareID != nullptr ? szMiddlewareID : "", remoteUserID, preferredPort });
return;
}

// if we already have a connection to this use, drop it, having a single-direction connection will break signalling
int previousAttempts = 0;
auto it = m_mapConnections.find(remoteUserID);
Expand Down Expand Up @@ -992,7 +1007,44 @@ void NetworkMesh::StartConnectionSignalling(const char* szMiddlewareID, int64_t
m_mapConnections[remoteUserID].m_SignallingAttempts = previousAttempts + 1;
}
}


}

void NetworkMesh::AwaitTurnCredentials()
{
std::lock_guard<std::recursive_mutex> lock(m_mapConnectionsMutex);
m_bAwaitingTurnCredentials = true;
}

void NetworkMesh::SetTurnCredentials(const std::string& strUsername, const std::string& strToken)
{
std::vector<PendingSignalling> vecPending;
{
std::lock_guard<std::recursive_mutex> lock(m_mapConnectionsMutex);

m_strTurnUsername = strUsername;
m_strTurnToken = strToken;
m_strTurnUsernameString = std::format("{},{}", m_strTurnUsername.c_str(), m_strTurnUsername.c_str());
m_strTurnTokenString = std::format("{},{}", m_strTurnToken.c_str(), m_strTurnToken.c_str());

// incoming connections use the listen socket's TURN settings
if (m_hListenSock != k_HSteamListenSocket_Invalid)
{
SteamNetworkingUtils()->SetConfigValue(k_ESteamNetworkingConfig_P2P_TURN_UserList, k_ESteamNetworkingConfig_ListenSocket,
(intptr_t)m_hListenSock, k_ESteamNetworkingConfig_String, m_strTurnUsernameString.c_str());
SteamNetworkingUtils()->SetConfigValue(k_ESteamNetworkingConfig_P2P_TURN_PassList, k_ESteamNetworkingConfig_ListenSocket,
(intptr_t)m_hListenSock, k_ESteamNetworkingConfig_String, m_strTurnTokenString.c_str());
}

m_bAwaitingTurnCredentials = false;
vecPending.swap(m_vecSignallingAwaitingTurn);
}

NetworkLog(ELogVerbosity::LOG_RELEASE, "[SIGNAL] Got TURN credentials, starting %d held signalling request(s)", (int)vecPending.size());
for (const PendingSignalling& pending : vecPending)
{
StartConnectionSignalling(pending.strMiddlewareID.c_str(), pending.remoteUserID, pending.preferredPort);
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,14 @@ void NGMP_OnlineServicesManager::GetAndParseServiceConfig(std::function<void(voi
}
else
{
// It's OK to fail, we'll just use the sensible defaults
NetworkLog(ELogVerbosity::LOG_RELEASE, "[NGMP] Failed to get service config, using defaults. Status code: %d", statusCode);
pMgr->m_ServiceConfig = ServiceConfig();
// keep the last good config (defaults if there never was one); resetting would turn off retry_signalling
NetworkLog(ELogVerbosity::LOG_RELEASE, "[NGMP] Failed to get service config, keeping the current one. Status code: %d", statusCode);
}

}
catch (...)
{
// It's OK to fail, we'll just use the sensible defaults
NetworkLog(ELogVerbosity::LOG_RELEASE, "[NGMP] Failed to get service config, using defaults. Exception.");
NGMP_OnlineServicesManager* pMgr = NGMP_OnlineServicesManager::GetInstance();
if (pMgr != nullptr)
{
pMgr->m_ServiceConfig = ServiceConfig();
}
NetworkLog(ELogVerbosity::LOG_RELEASE, "[NGMP] Failed to parse service config, keeping the current one.");
}

if (cbOnDone != nullptr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,13 @@ void NGMP_OnlineServices_LobbyInterface::UpdateRoomDataCache(std::function<void(
fnCallback(false);
}

// the match runs on this lobby's mesh
if (TheNGMPGame != nullptr && TheNGMPGame->isGameInProgress())
{
NetworkLog(ELogVerbosity::LOG_RELEASE, "[NGMP] Lobby lookup returned 404 during a match, keeping the match running");
return;
}

LeaveCurrentLobby();
return;
}
Expand Down Expand Up @@ -1191,6 +1198,9 @@ void NGMP_OnlineServices_LobbyInterface::JoinLobby(LobbyEntry lobbyInfo, std::st
m_pLobbyMesh = pNewMesh;
}

// TURN credentials arrive with the join response
m_pLobbyMesh->AwaitTurnCredentials();

// convert
NGMP_OnlineServicesManager::GetInstance()->GetHTTPManager()->SendPUTRequest(strURI.c_str(), EIPProtocolVersion::DONT_CARE, mapHeaders, strPostData.c_str(), [=](bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)
{
Expand Down Expand Up @@ -1252,6 +1262,11 @@ void NGMP_OnlineServices_LobbyInterface::JoinLobby(LobbyEntry lobbyInfo, std::st

}

if (m_pLobbyMesh != nullptr)
{
m_pLobbyMesh->SetTurnCredentials(m_strTURNUsername, m_strTURNToken);
}

// for safety
if (TheNGMPGame != nullptr)
{
Expand Down Expand Up @@ -1548,6 +1563,11 @@ void NGMP_OnlineServices_LobbyInterface::CreateLobby(UnicodeString strLobbyName,
m_strTURNToken = resp.turn_token;
NetworkLog(ELogVerbosity::LOG_DEBUG, "Got TURN username: %s, token: %s", m_strTURNUsername.c_str(), m_strTURNToken.c_str());

// a mesh kept from a failed join has stale credentials
if (m_pLobbyMesh != nullptr)
{
m_pLobbyMesh->SetTurnCredentials(m_strTURNUsername, m_strTURNToken);
}

if (resp.result == ECreateLobbyResponseResult::SUCCEEDED)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "../OnlineServices_Auth.h"
#include "../OnlineServices_LobbyInterface.h"

bool AnticheatPlugInterface::g_bPendingExitLobby = false;
std::atomic<bool> AnticheatPlugInterface::g_bPendingExitLobby = false;

#if defined(GENERALS_ONLINE_USE_PLUGINS_INTERFACE)

Expand Down Expand Up @@ -475,6 +475,9 @@ void AnticheatPlugInterface::BeginSession()

void AnticheatPlugInterface::EndSession()
{
// a stale exit request would eject us from the next lobby
g_bPendingExitLobby = false;

#if defined(AC_ENABLED)
if (IsPluginLoaded() && Functions.fnEndSession != nullptr)
{
Expand Down
Loading