From 8113c093e63ff3d4bef4bbdc8229d93723701fac Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Thu, 23 Jul 2026 23:41:54 +0200 Subject: [PATCH 1/6] refactor(network): Remove obsolete Refresh NAT button and INI state ### What this code did: The `ButtonFirewallRefresh` button in `OptionsMenu.cpp` and `FirewallNeedToRefresh` in `FirewallHelper.cpp` / `OptionPreferences.cpp`: 1. Saved/read `FirewallNeedToRefresh` and `LastFirewallIP` boolean flags to/from `Options.ini`. 2. Required players to manually click a "Refresh NAT" button in the Options GUI when changing network interfaces or encountering P2P negotiation failures. 3. Contaminated `GlobalData` (`TheWritableGlobalData->m_firewallBehavior`) with disk-persisted firewall state across process restarts. ### How the new code works: 1. **Automated In-Engine RAM Lifecycle**: NAT state classification (`m_behavior`) is managed 100% in memory within `FirewallHelperClass`. 2. **Transparent Background Probing**: Non-blocking STUN probing runs in the background during online lobby entry (`WOLWelcomeMenu`), caching the classified result in RAM for the remainder of the game session. 3. **Self-Healing Re-Detection**: If a peer connection times out (`NAT.cpp`) or the user selects a new IP address in Options (`OptionPreferences.cpp`), `TheFirewallHelper->flagNeedToRefresh(TRUE)` resets `m_behavior = FIREWALL_TYPE_UNKNOWN` in RAM to seamlessly trigger a fresh background probe. 4. **Clean GUI Deprecation**: Hides `OptionsMenu.wnd:ButtonFirewallRefresh` via `winHide(TRUE)` in C++ without breaking custom or legacy `.wnd` layout files. ### Background & Reason for Removal: - **Obsolete Manual Workaround**: Manual NAT refresh buttons are a legacy 2003 workaround; modern network stacks handle NAT re-detection automatically in-engine. - **Elimination of Disk I/O**: Completely removes `FirewallNeedToRefresh` and `LastFirewallIP` from `Options.ini`, preventing stale or corrupted flags from persisting across game crashes or process restarts. - **Architectural Decoupling**: Fully encapsulates STUN probing state inside `FirewallHelperClass` in memory, removing direct mutations to `TheWritableGlobalData->m_firewallBehavior`. --- .../Include/Common/OptionPreferences.h | 1 - .../Include/GameNetwork/FirewallHelper.h | 4 +-- .../Source/Common/OptionPreferences.cpp | 34 ++++++++----------- .../Source/GameNetwork/FirewallHelper.cpp | 30 ++++++---------- .../GameEngine/Source/Common/GlobalData.cpp | 1 - .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 19 ++--------- .../GUICallbacks/Menus/WOLGameSetupMenu.cpp | 6 ++-- .../GUICallbacks/Menus/WOLQuickMatchMenu.cpp | 3 +- .../GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp | 7 ---- .../GameEngine/Source/GameNetwork/GameSpy.cpp | 10 ------ .../GameEngine/Source/Common/GlobalData.cpp | 1 - .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 19 ++--------- .../GUICallbacks/Menus/WOLGameSetupMenu.cpp | 6 ++-- .../GUICallbacks/Menus/WOLQuickMatchMenu.cpp | 3 +- .../GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp | 7 ---- 15 files changed, 42 insertions(+), 109 deletions(-) diff --git a/Core/GameEngine/Include/Common/OptionPreferences.h b/Core/GameEngine/Include/Common/OptionPreferences.h index 1f45873191a..5da2955eb27 100644 --- a/Core/GameEngine/Include/Common/OptionPreferences.h +++ b/Core/GameEngine/Include/Common/OptionPreferences.h @@ -88,7 +88,6 @@ class OptionPreferences : public UserPreferences Int getFirewallBehavior(); Short getFirewallPortAllocationDelta(); UnsignedShort getFirewallPortOverride(); - Bool getFirewallNeedToRefresh(); Bool usesSystemMapDir(); AsciiString getPreferred3DProvider(); AsciiString getSpeakerType(); diff --git a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h index 352b1a040bc..056b64abba5 100644 --- a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h +++ b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h @@ -175,6 +175,7 @@ class FirewallHelperClass { FirewallHelperClass(); virtual ~FirewallHelperClass(); Bool detectFirewall(); + void detectFirewallBehavior(/*Bool &canRecord*/); UnsignedShort getRawFirewallBehavior() {return((UnsignedShort)m_behavior);} Short getSourcePortAllocationDelta(); Int getFirewallHardness(FirewallBehaviorType behavior); @@ -239,12 +240,9 @@ class FirewallHelperClass { return(FALSE); }; - - private: Int getNATPortAllocationScheme(Int numPorts, UnsignedShort *originalPorts, UnsignedShort *mangledPorts, Bool &relativeDelta, Bool &looksGood); - void detectFirewallBehavior(/*Bool &canRecord*/); Bool getReferencePort(); SpareSocketStruct * findSpareSocketByPort(UnsignedShort port); diff --git a/Core/GameEngine/Source/Common/OptionPreferences.cpp b/Core/GameEngine/Source/Common/OptionPreferences.cpp index af61c4c84fe..7573be64182 100644 --- a/Core/GameEngine/Source/Common/OptionPreferences.cpp +++ b/Core/GameEngine/Source/Common/OptionPreferences.cpp @@ -45,6 +45,7 @@ #include "GameLogic/ScriptEngine.h" #include "GameNetwork/IPEnumeration.h" +#include "GameNetwork/FirewallHelper.h" OptionPreferences::OptionPreferences() { @@ -142,14 +143,19 @@ UnsignedInt OptionPreferences::getLANIPAddress() void OptionPreferences::setLANIPAddress(AsciiString IP) { - (*this)["IPAddress"] = IP; + if ((*this)["IPAddress"].compareNoCase(IP) != 0) + { + (*this)["IPAddress"] = IP; + if (TheFirewallHelper != nullptr) + TheFirewallHelper->flagNeedToRefresh(TRUE); + } } void OptionPreferences::setLANIPAddress(UnsignedInt IP) { AsciiString tmp; tmp.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); - (*this)["IPAddress"] = tmp; + setLANIPAddress(tmp); } UnsignedInt OptionPreferences::getOnlineIPAddress() @@ -170,14 +176,19 @@ UnsignedInt OptionPreferences::getOnlineIPAddress() void OptionPreferences::setOnlineIPAddress(AsciiString IP) { - (*this)["GameSpyIPAddress"] = IP; + if ((*this)["GameSpyIPAddress"].compareNoCase(IP) != 0) + { + (*this)["GameSpyIPAddress"] = IP; + if (TheFirewallHelper != nullptr) + TheFirewallHelper->flagNeedToRefresh(TRUE); + } } void OptionPreferences::setOnlineIPAddress(UnsignedInt IP) { AsciiString tmp; tmp.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); - (*this)["GameSpyIPAddress"] = tmp; + setOnlineIPAddress(tmp); } Bool OptionPreferences::getArchiveReplaysEnabled() const @@ -501,21 +512,6 @@ UnsignedShort OptionPreferences::getFirewallPortOverride() return portOverride; } -Bool OptionPreferences::getFirewallNeedToRefresh() -{ - OptionPreferences::const_iterator it = find("FirewallNeedToRefresh"); - if (it == end()) { - return FALSE; - } - - Bool retval = FALSE; - AsciiString str = it->second; - if (str.compareNoCase("TRUE") == 0) { - retval = TRUE; - } - return retval; -} - AsciiString OptionPreferences::getPreferred3DProvider() { OptionPreferences::const_iterator it = find("3DAudioProvider"); diff --git a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp index 04e5f7166b0..5655796ee5c 100644 --- a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp @@ -54,6 +54,7 @@ #include "GameNetwork/NAT.h" #include "GameNetwork/udp.h" #include "GameNetwork/NetworkDefs.h" +#include "GameNetwork/IPEnumeration.h" #include "GameNetwork/GameSpy/GSConfig.h" @@ -61,7 +62,9 @@ FirewallHelperClass *TheFirewallHelper = nullptr; FirewallHelperClass * createFirewallHelper() { - return NEW FirewallHelperClass(); + FirewallHelperClass *helper = NEW FirewallHelperClass(); + helper->detectFirewallBehavior(); + return helper; } @@ -176,22 +179,12 @@ void FirewallHelperClass::reset() *=============================================================================================*/ Bool FirewallHelperClass::detectFirewall() { - OptionPreferences pref; - - OptionPreferences::const_iterator it = pref.find("FirewallNeedToRefresh"); - if (it != pref.end()) { - AsciiString str = it->second; - if (str.compareNoCase("TRUE") == 0) { - TheWritableGlobalData->m_firewallBehavior = FIREWALL_TYPE_UNKNOWN; - } - } - - if (TheWritableGlobalData->m_firewallBehavior == FIREWALL_TYPE_UNKNOWN) { + if (m_behavior == FIREWALL_TYPE_UNKNOWN) { detectFirewallBehavior(); return FALSE; } else { - DEBUG_LOG(("FirewallHelperClass::detectFirewall - firewall behavior already specified as %d, port allocation delta is %d, skipping detection.", TheWritableGlobalData->m_firewallBehavior, TheWritableGlobalData->m_firewallPortAllocationDelta)); + DEBUG_LOG(("FirewallHelperClass::detectFirewall - firewall behavior already specified as %d, port allocation delta is %d, skipping detection.", m_behavior, m_sourcePortAllocationDelta)); } return TRUE; @@ -535,11 +528,9 @@ void FirewallHelperClass::writeFirewallBehavior() *=============================================================================================*/ void FirewallHelperClass::flagNeedToRefresh(Bool flag) { - OptionPreferences pref; - - (pref)["FirewallNeedToRefresh"] = flag ? "TRUE" : "FALSE"; - - pref.write(); + if (flag) { + detectFirewallBehavior(); + } } @@ -583,13 +574,12 @@ void FirewallHelperClass::readFirewallBehavior() *=============================================================================================*/ void FirewallHelperClass::detectFirewallBehavior(/*Bool &canRecord*/) { - m_behavior = FIREWALL_TYPE_SIMPLE; + m_behavior = FIREWALL_TYPE_UNKNOWN; m_currentState = DETECTIONSTATE_BEGIN; } FirewallHelperClass::FirewallBehaviorType FirewallHelperClass::getFirewallBehavior() { - m_currentState = DETECTIONSTATE_IDLE; return m_behavior; } diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index 25d5432c51f..425394d7298 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -1206,7 +1206,6 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_moveScrollAnchor = optionPref.getMoveScrollAnchor(); TheWritableGlobalData->m_defaultIP = optionPref.getLANIPAddress(); TheWritableGlobalData->m_firewallSendDelay = optionPref.getSendDelay(); - TheWritableGlobalData->m_firewallBehavior = optionPref.getFirewallBehavior(); TheWritableGlobalData->m_firewallPortAllocationDelta = optionPref.getFirewallPortAllocationDelta(); TheWritableGlobalData->m_firewallPortOverride = optionPref.getFirewallPortOverride(); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 91b7f80af92..0180e78804e 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -121,8 +121,6 @@ static GameWindow * checkDrawAnchor = nullptr; static NameKeyType checkMoveAnchorID = NAMEKEY_INVALID; static GameWindow * checkMoveAnchor = nullptr; -static NameKeyType buttonFirewallRefreshID = NAMEKEY_INVALID; -static GameWindow * buttonFirewallRefresh = nullptr; // //static NameKeyType checkAudioHardwareID = NAMEKEY_INVALID; //static GameWindow * checkAudioHardware = nullptr; @@ -970,8 +968,9 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); - buttonFirewallRefreshID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:ButtonFirewallRefresh" ); - buttonFirewallRefresh = TheWindowManager->winGetWindowFromId( nullptr, buttonFirewallRefreshID); + GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); + if (buttonFirewallRefresh) + buttonFirewallRefresh->winHide(TRUE); checkDrawAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxDrawAnchor" ); checkDrawAnchor = TheWindowManager->winGetWindowFromId( nullptr, checkDrawAnchorID); checkMoveAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxMoveAnchor" ); @@ -1696,18 +1695,6 @@ WindowMsgHandledType OptionsMenuSystem( GameWindow *window, UnsignedInt msg, (*pref)["UseCameraInReplays"] = "no"; } } - else if (controlID == buttonFirewallRefreshID) - { - // setting the behavior to unknown will force the firewall helper to detect the firewall behavior - // the next time we log into gamespy/WOL/whatever. - char num[16]; - num[0] = 0; - TheWritableGlobalData->m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - itoa(TheGlobalData->m_firewallBehavior, num, 10); - AsciiString numstr; - numstr = num; - (*pref)["FirewallBehavior"] = numstr; - } break; } diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp index f0f4b8df4a5..07c9fddd4cd 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp @@ -1212,7 +1212,8 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) CustomMatchPreferences customPref; hostSlot->setColor( customPref.getPreferredColor() ); hostSlot->setPlayerTemplate( customPref.getPreferredFaction() ); - hostSlot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)natPref.getFirewallBehavior()); + FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + hostSlot->setNATBehavior(natBehavior); hostSlot->setPingString(TheGameSpyInfo->getPingString()); game->setMap(customPref.getPreferredMap()); @@ -1260,7 +1261,8 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) options.format("Color=%d", customPref.getPreferredColor()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); - options.format("NAT=%d", natPref.getFirewallBehavior()); + FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + options.format("NAT=%d", natBehavior); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); options.format("Ping=%s", TheGameSpyInfo->getPingString().str()); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp index 1f8cbb310d5..9579344373b 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp @@ -1691,8 +1691,7 @@ WindowMsgHandledType WOLQuickMatchMenuSystem( GameWindow *window, UnsignedInt ms index = (Int)GadgetComboBoxGetItemData( comboBoxColor, selected ); req.QM.color = index; - OptionPreferences natPref; - req.QM.NAT = natPref.getFirewallBehavior(); + req.QM.NAT = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; if (ladderIndex) { diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp index 403d17c9bea..ae26870b4b2 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp @@ -489,11 +489,6 @@ void WOLWelcomeMenuInit( WindowLayout *layout, void *userData ) if (TheFirewallHelper == nullptr) { TheFirewallHelper = createFirewallHelper(); } - if (TheFirewallHelper->detectFirewall() == TRUE) { - // don't need to detect firewall, already been done. - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } /* if (TheGameSpyChat && TheGameSpyChat->isConnected()) @@ -592,8 +587,6 @@ void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData) { if (TheFirewallHelper->behaviorDetectionUpdate()) { - TheWritableGlobalData->m_firewallBehavior = TheFirewallHelper->getFirewallBehavior(); - TheFirewallHelper->writeFirewallBehavior(); TheFirewallHelper->flagNeedToRefresh(FALSE); // 2/19/03 BGC, we're done, so we don't need to refresh the NAT anymore. diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp index 8fd4ed5c6b4..bf464cf4bef 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp @@ -284,16 +284,6 @@ void GameSpyChat::update() if (TheFirewallHelper != nullptr) { if (TheFirewallHelper->behaviorDetectionUpdate()) { - TheGlobalData->m_firewallBehavior = TheFirewallHelper->getFirewallBehavior(); - OptionPreferences *pref = NEW OptionPreferences; - char num[16]; - num[0] = 0; - itoa(TheGlobalData->m_firewallBehavior, num, 10); - AsciiString numstr; - numstr = num; - (*pref)["FirewallBehavior"] = numstr; - pref->write(); - // we are now done with the firewall helper delete TheFirewallHelper; TheFirewallHelper = nullptr; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index 131d20513ff..3878f20b684 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -1213,7 +1213,6 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_moveScrollAnchor = optionPref.getMoveScrollAnchor(); TheWritableGlobalData->m_defaultIP = optionPref.getLANIPAddress(); TheWritableGlobalData->m_firewallSendDelay = optionPref.getSendDelay(); - TheWritableGlobalData->m_firewallBehavior = optionPref.getFirewallBehavior(); TheWritableGlobalData->m_firewallPortAllocationDelta = optionPref.getFirewallPortAllocationDelta(); TheWritableGlobalData->m_firewallPortOverride = optionPref.getFirewallPortOverride(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index ee99e20c452..7b4826a764f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -127,8 +127,6 @@ static GameWindow * checkDrawAnchor = nullptr; static NameKeyType checkMoveAnchorID = NAMEKEY_INVALID; static GameWindow * checkMoveAnchor = nullptr; -static NameKeyType buttonFirewallRefreshID = NAMEKEY_INVALID; -static GameWindow * buttonFirewallRefresh = nullptr; // //static NameKeyType checkAudioHardwareID = NAMEKEY_INVALID; //static GameWindow * checkAudioHardware = nullptr; @@ -999,8 +997,9 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); - buttonFirewallRefreshID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:ButtonFirewallRefresh" ); - buttonFirewallRefresh = TheWindowManager->winGetWindowFromId( nullptr, buttonFirewallRefreshID); + GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); + if (buttonFirewallRefresh) + buttonFirewallRefresh->winHide(TRUE); checkDrawAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxDrawAnchor" ); checkDrawAnchor = TheWindowManager->winGetWindowFromId( nullptr, checkDrawAnchorID); checkMoveAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxMoveAnchor" ); @@ -1732,18 +1731,6 @@ WindowMsgHandledType OptionsMenuSystem( GameWindow *window, UnsignedInt msg, (*pref)["UseCameraInReplays"] = "no"; } } - else if (controlID == buttonFirewallRefreshID) - { - // setting the behavior to unknown will force the firewall helper to detect the firewall behavior - // the next time we log into gamespy/WOL/whatever. - char num[16]; - num[0] = 0; - TheWritableGlobalData->m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - itoa(TheGlobalData->m_firewallBehavior, num, 10); - AsciiString numstr; - numstr = num; - (*pref)["FirewallBehavior"] = numstr; - } break; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp index f360ba9423b..c0e255923a9 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp @@ -1369,7 +1369,8 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) CustomMatchPreferences customPref; hostSlot->setColor( customPref.getPreferredColor() ); hostSlot->setPlayerTemplate( customPref.getPreferredFaction() ); - hostSlot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)natPref.getFirewallBehavior()); + FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + hostSlot->setNATBehavior(natBehavior); hostSlot->setPingString(TheGameSpyInfo->getPingString()); game->setMap(customPref.getPreferredMap()); @@ -1437,7 +1438,8 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) options.format("Color=%d", customPref.getPreferredColor()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); - options.format("NAT=%d", natPref.getFirewallBehavior()); + FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + options.format("NAT=%d", natBehavior); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); options.format("Ping=%s", TheGameSpyInfo->getPingString().str()); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp index 977f72e5a87..19d78c20424 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp @@ -1756,8 +1756,7 @@ WindowMsgHandledType WOLQuickMatchMenuSystem( GameWindow *window, UnsignedInt ms index = (Int)GadgetComboBoxGetItemData( comboBoxColor, selected ); req.QM.color = index; - OptionPreferences natPref; - req.QM.NAT = natPref.getFirewallBehavior(); + req.QM.NAT = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; if (ladderIndex) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp index c84a8fd559e..19e877cdbfc 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp @@ -506,11 +506,6 @@ void WOLWelcomeMenuInit( WindowLayout *layout, void *userData ) if (TheFirewallHelper == nullptr) { TheFirewallHelper = createFirewallHelper(); } - if (TheFirewallHelper->detectFirewall() == TRUE) { - // don't need to detect firewall, already been done. - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } /* if (TheGameSpyChat && TheGameSpyChat->isConnected()) @@ -609,8 +604,6 @@ void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData) { if (TheFirewallHelper->behaviorDetectionUpdate()) { - TheWritableGlobalData->m_firewallBehavior = TheFirewallHelper->getFirewallBehavior(); - TheFirewallHelper->writeFirewallBehavior(); TheFirewallHelper->flagNeedToRefresh(FALSE); // 2/19/03 BGC, we're done, so we don't need to refresh the NAT anymore. From 0a4ada6c29b26b2c7dbce20cb2b55d9c85a7086f Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Fri, 24 Jul 2026 00:25:20 +0200 Subject: [PATCH 2/6] fix(network): Reset probe state and close spare sockets on firewall re-detection --- Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp index 5655796ee5c..387bc604c97 100644 --- a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp @@ -574,8 +574,15 @@ void FirewallHelperClass::readFirewallBehavior() *=============================================================================================*/ void FirewallHelperClass::detectFirewallBehavior(/*Bool &canRecord*/) { + reset(); + m_currentTry = 0; + m_numManglers = 0; + m_numResponses = 0; + m_packetID = 0; + m_timeoutLength = 0; + m_timeoutStart = 0; + m_sourcePortAllocationDelta = 0; m_behavior = FIREWALL_TYPE_UNKNOWN; - m_currentState = DETECTIONSTATE_BEGIN; } From fd146ae0635d276e87a1a78232856cf28c6e2263 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Fri, 24 Jul 2026 00:32:28 +0200 Subject: [PATCH 3/6] fix(network): Preserve FirewallHelper lifetime across online menus and matchmaking --- .../Source/GameNetwork/FirewallHelper.cpp | 5 +++++ Core/GameEngine/Source/GameNetwork/NAT.cpp | 14 -------------- .../GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp | 14 +------------- .../Code/GameEngine/Source/GameNetwork/GameSpy.cpp | 6 +----- .../GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp | 14 +------------- 5 files changed, 8 insertions(+), 45 deletions(-) diff --git a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp index 387bc604c97..2ca00dfa35a 100644 --- a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp @@ -62,6 +62,11 @@ FirewallHelperClass *TheFirewallHelper = nullptr; FirewallHelperClass * createFirewallHelper() { + if (TheFirewallHelper) + { + delete TheFirewallHelper; + TheFirewallHelper = nullptr; + } FirewallHelperClass *helper = NEW FirewallHelperClass(); helper->detectFirewallBehavior(); return helper; diff --git a/Core/GameEngine/Source/GameNetwork/NAT.cpp b/Core/GameEngine/Source/GameNetwork/NAT.cpp index 159d8532cfa..d624ec478d7 100644 --- a/Core/GameEngine/Source/GameNetwork/NAT.cpp +++ b/Core/GameEngine/Source/GameNetwork/NAT.cpp @@ -210,9 +210,6 @@ NATStateType NAT::update() { { m_NATState = NATSTATE_DONE; TheEstablishConnectionsMenu->endMenu(); - - delete TheFirewallHelper; - TheFirewallHelper = nullptr; } } else if (m_NATState == NATSTATE_DOCONNECTIONPATHS) { if (allConnectionsDoneThisRound() == TRUE) { @@ -257,18 +254,7 @@ NATStateType NAT::update() { m_NATState = NATSTATE_FAILED; TheEstablishConnectionsMenu->endMenu(); if (TheFirewallHelper != nullptr) { - // we failed NAT negotiation, perhaps we need to redetect our firewall settings. - // We don't trust the user to do it for themselves so we force them to do it next time - // the log in. - // 2/19/03 - ok, we don't want to do this right away, if the user tries to play in another game - // before they log out and log back in the game won't have a chance at working. - // so we need to simply flag it so that when they log out the firewall behavior gets blown away. TheFirewallHelper->flagNeedToRefresh(TRUE); -// TheWritableGlobalData->m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; -// TheFirewallHelper->writeFirewallBehavior(); - - delete TheFirewallHelper; - TheFirewallHelper = nullptr; } // we failed to connect, so we don't have to pass on the transport to the network. delete m_transport; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp index ae26870b4b2..8b950d2382a 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp @@ -545,9 +545,6 @@ void WOLWelcomeMenuShutdown( WindowLayout *layout, void *userData ) { listboxInfo = nullptr; - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - isShuttingDown = TRUE; // if we are shutting down for an immediate pop, skip the animations @@ -585,16 +582,7 @@ void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData) if (TheFirewallHelper != nullptr) { - if (TheFirewallHelper->behaviorDetectionUpdate()) - { - TheFirewallHelper->writeFirewallBehavior(); - - TheFirewallHelper->flagNeedToRefresh(FALSE); // 2/19/03 BGC, we're done, so we don't need to refresh the NAT anymore. - - // we are now done with the firewall helper - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } + TheFirewallHelper->behaviorDetectionUpdate(); } if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue) diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp index bf464cf4bef..ab3b1558f63 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp @@ -283,11 +283,7 @@ void GameSpyChat::update() } if (TheFirewallHelper != nullptr) { - if (TheFirewallHelper->behaviorDetectionUpdate()) { - // we are now done with the firewall helper - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } + TheFirewallHelper->behaviorDetectionUpdate(); } UnsignedInt now = timeGetTime(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp index 19e877cdbfc..ed18907163b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLWelcomeMenu.cpp @@ -562,9 +562,6 @@ void WOLWelcomeMenuShutdown( WindowLayout *layout, void *userData ) { listboxInfo = nullptr; - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - isShuttingDown = TRUE; // if we are shutting down for an immediate pop, skip the animations @@ -602,16 +599,7 @@ void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData) if (TheFirewallHelper != nullptr) { - if (TheFirewallHelper->behaviorDetectionUpdate()) - { - TheFirewallHelper->writeFirewallBehavior(); - - TheFirewallHelper->flagNeedToRefresh(FALSE); // 2/19/03 BGC, we're done, so we don't need to refresh the NAT anymore. - - // we are now done with the firewall helper - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } + TheFirewallHelper->behaviorDetectionUpdate(); } if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue) From 6c507459e402e1d85c6b2ac417b36579e2f2dd5a Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Sat, 25 Jul 2026 23:00:48 +0200 Subject: [PATCH 4/6] Updated after review feedback --- .../Include/Common/OptionPreferences.h | 4 ++ .../Include/GameNetwork/FirewallHelper.h | 2 +- .../Source/Common/OptionPreferences.cpp | 37 ++++++++++--------- .../Source/GameNetwork/FirewallHelper.cpp | 7 +--- .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 1 + .../GUI/GUICallbacks/Menus/OptionsMenu.cpp | 1 + 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/Core/GameEngine/Include/Common/OptionPreferences.h b/Core/GameEngine/Include/Common/OptionPreferences.h index 5da2955eb27..87773fa4532 100644 --- a/Core/GameEngine/Include/Common/OptionPreferences.h +++ b/Core/GameEngine/Include/Common/OptionPreferences.h @@ -131,4 +131,8 @@ class OptionPreferences : public UserPreferences Bool getShowMoneyPerMinute() const; Real getGameWindowTransitionSpeedMultiplier() const; + +private: + + void setIPAddress(AsciiString key, AsciiString IP); }; diff --git a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h index 056b64abba5..39ef7526bc3 100644 --- a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h +++ b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h @@ -175,7 +175,7 @@ class FirewallHelperClass { FirewallHelperClass(); virtual ~FirewallHelperClass(); Bool detectFirewall(); - void detectFirewallBehavior(/*Bool &canRecord*/); + void detectFirewallBehavior(); UnsignedShort getRawFirewallBehavior() {return((UnsignedShort)m_behavior);} Short getSourcePortAllocationDelta(); Int getFirewallHardness(FirewallBehaviorType behavior); diff --git a/Core/GameEngine/Source/Common/OptionPreferences.cpp b/Core/GameEngine/Source/Common/OptionPreferences.cpp index 7573be64182..bc4ee83c7bf 100644 --- a/Core/GameEngine/Source/Common/OptionPreferences.cpp +++ b/Core/GameEngine/Source/Common/OptionPreferences.cpp @@ -141,21 +141,27 @@ UnsignedInt OptionPreferences::getLANIPAddress() return TheGlobalData->m_defaultIP; } +void OptionPreferences::setIPAddress(AsciiString key, AsciiString IP) +{ + if ((*this)[key].compareNoCase(IP) == 0) + return; + + (*this)[key] = IP; + + if (TheFirewallHelper != nullptr) + TheFirewallHelper->flagNeedToRefresh(TRUE); +} + void OptionPreferences::setLANIPAddress(AsciiString IP) { - if ((*this)["IPAddress"].compareNoCase(IP) != 0) - { - (*this)["IPAddress"] = IP; - if (TheFirewallHelper != nullptr) - TheFirewallHelper->flagNeedToRefresh(TRUE); - } + setIPAddress("IPAddress", IP); } void OptionPreferences::setLANIPAddress(UnsignedInt IP) { - AsciiString tmp; - tmp.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); - setLANIPAddress(tmp); + AsciiString ipString; + ipString.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); + setLANIPAddress(ipString); } UnsignedInt OptionPreferences::getOnlineIPAddress() @@ -176,19 +182,14 @@ UnsignedInt OptionPreferences::getOnlineIPAddress() void OptionPreferences::setOnlineIPAddress(AsciiString IP) { - if ((*this)["GameSpyIPAddress"].compareNoCase(IP) != 0) - { - (*this)["GameSpyIPAddress"] = IP; - if (TheFirewallHelper != nullptr) - TheFirewallHelper->flagNeedToRefresh(TRUE); - } + setIPAddress("GameSpyIPAddress", IP); } void OptionPreferences::setOnlineIPAddress(UnsignedInt IP) { - AsciiString tmp; - tmp.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); - setOnlineIPAddress(tmp); + AsciiString ipString; + ipString.format("%d.%d.%d.%d", PRINTF_IP_AS_4_INTS(IP)); + setOnlineIPAddress(ipString); } Bool OptionPreferences::getArchiveReplaysEnabled() const diff --git a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp index 2ca00dfa35a..4c1c4e69438 100644 --- a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp @@ -62,11 +62,6 @@ FirewallHelperClass *TheFirewallHelper = nullptr; FirewallHelperClass * createFirewallHelper() { - if (TheFirewallHelper) - { - delete TheFirewallHelper; - TheFirewallHelper = nullptr; - } FirewallHelperClass *helper = NEW FirewallHelperClass(); helper->detectFirewallBehavior(); return helper; @@ -577,7 +572,7 @@ void FirewallHelperClass::readFirewallBehavior() * HISTORY: * * 3/15/01 12:30PM ST : Created * *=============================================================================================*/ -void FirewallHelperClass::detectFirewallBehavior(/*Bool &canRecord*/) +void FirewallHelperClass::detectFirewallBehavior() { reset(); m_currentTry = 0; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 0180e78804e..ddde5e17fba 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -968,6 +968,7 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); + // TheSuperHackers @info 25/07/2026 Refresh button has been hidden, we have migrated this to self-healing NAT GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); if (buttonFirewallRefresh) buttonFirewallRefresh->winHide(TRUE); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 7b4826a764f..a8eebcbcd92 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -997,6 +997,7 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); + // TheSuperHackers @info 25/07/2026 Refresh button has been hidden, we have migrated this to self-healing GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); if (buttonFirewallRefresh) buttonFirewallRefresh->winHide(TRUE); From 67eef47bb80a43f66ca3dcba710b0012cea40033 Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Sun, 26 Jul 2026 01:31:51 +0200 Subject: [PATCH 5/6] update after greptile feedback placed nat detection earlier in the online Code some more cleanup --- .../Include/Common/OptionPreferences.h | 2 - .../Include/GameNetwork/FirewallHelper.h | 9 +- .../Source/Common/OptionPreferences.cpp | 25 ---- .../Source/GameNetwork/FirewallHelper.cpp | 114 ++++++++---------- .../Source/GameNetwork/GameSpy/PeerDefs.cpp | 9 ++ Core/GameEngine/Source/GameNetwork/NAT.cpp | 2 +- .../GameEngine/Include/Common/GlobalData.h | 2 - .../GameEngine/Source/Common/GlobalData.cpp | 5 - .../GUICallbacks/Menus/WOLGameSetupMenu.cpp | 8 +- .../GUI/GUICallbacks/Menus/WOLLoginMenu.cpp | 6 + .../GUICallbacks/Menus/WOLQuickMatchMenu.cpp | 2 +- .../GameEngine/Source/GameNetwork/GameSpy.cpp | 2 +- .../GameEngine/Include/Common/GlobalData.h | 2 - .../GameEngine/Source/Common/GlobalData.cpp | 5 - .../GUICallbacks/Menus/WOLGameSetupMenu.cpp | 8 +- .../GUI/GUICallbacks/Menus/WOLLoginMenu.cpp | 6 + .../GUICallbacks/Menus/WOLQuickMatchMenu.cpp | 2 +- 17 files changed, 87 insertions(+), 122 deletions(-) diff --git a/Core/GameEngine/Include/Common/OptionPreferences.h b/Core/GameEngine/Include/Common/OptionPreferences.h index 87773fa4532..037b0375f43 100644 --- a/Core/GameEngine/Include/Common/OptionPreferences.h +++ b/Core/GameEngine/Include/Common/OptionPreferences.h @@ -85,8 +85,6 @@ class OptionPreferences : public UserPreferences Bool getScreenEdgeScrollEnabledInFullscreenApp() const; ScreenEdgeScrollMode getScreenEdgeScrollMode() const; Bool getSendDelay(); - Int getFirewallBehavior(); - Short getFirewallPortAllocationDelta(); UnsignedShort getFirewallPortOverride(); Bool usesSystemMapDir(); AsciiString getPreferred3DProvider(); diff --git a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h index 39ef7526bc3..23e707b5043 100644 --- a/Core/GameEngine/Include/GameNetwork/FirewallHelper.h +++ b/Core/GameEngine/Include/GameNetwork/FirewallHelper.h @@ -182,15 +182,17 @@ class FirewallHelperClass { Int getFirewallRetries(FirewallBehaviorType behavior); void setSourcePortPoolStart(Int port) {m_sourcePortPool = port;}; Int getSourcePortPool() {return(m_sourcePortPool);}; - void readFirewallBehavior(); void reset(); Bool behaviorDetectionUpdate(); FirewallBehaviorType getFirewallBehavior(); - void writeFirewallBehavior(); void flagNeedToRefresh(Bool flag); + Bool isBehaviorDetectionComplete() {return(m_currentState == DETECTIONSTATE_DONE);} + FirewallBehaviorType getLastFirewallBehavior() {return(m_lastBehavior);} + Short getLastSourcePortAllocationDelta() {return((Short)m_lastSourcePortAllocationDelta);} + static void getManglerName(Int manglerIndex, Char *nameBuf); Bool sendToManglerFromPort(UnsignedInt address, UnsignedShort port, UnsignedShort packetID, Bool blitzme = FALSE); UnsignedShort getManglerResponse(UnsignedShort packetID, Int time = 0); @@ -303,3 +305,6 @@ class FirewallHelperClass { extern FirewallHelperClass *TheFirewallHelper; FirewallHelperClass * createFirewallHelper(); + +FirewallHelperClass::FirewallBehaviorType getBestKnownFirewallBehavior(); +Short getBestKnownSourcePortAllocationDelta(); diff --git a/Core/GameEngine/Source/Common/OptionPreferences.cpp b/Core/GameEngine/Source/Common/OptionPreferences.cpp index bc4ee83c7bf..8d26448aa4e 100644 --- a/Core/GameEngine/Source/Common/OptionPreferences.cpp +++ b/Core/GameEngine/Source/Common/OptionPreferences.cpp @@ -475,31 +475,6 @@ Bool OptionPreferences::getSendDelay() return FALSE; } -Int OptionPreferences::getFirewallBehavior() -{ - OptionPreferences::const_iterator it = find("FirewallBehavior"); - if (it == end()) - return TheGlobalData->m_firewallBehavior; - - Int behavior = atoi(it->second.str()); - if (behavior < 0) - { - behavior = 0; - } - return behavior; -} - -Short OptionPreferences::getFirewallPortAllocationDelta() -{ - OptionPreferences::const_iterator it = find("FirewallPortAllocationDelta"); - if (it == end()) { - return TheGlobalData->m_firewallPortAllocationDelta; - } - - Short delta = atoi(it->second.str()); - return delta; -} - UnsignedShort OptionPreferences::getFirewallPortOverride() { OptionPreferences::const_iterator it = find("FirewallPortOverride"); diff --git a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp index 4c1c4e69438..1bd56307921 100644 --- a/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp +++ b/Core/GameEngine/Source/GameNetwork/FirewallHelper.cpp @@ -67,6 +67,44 @@ FirewallHelperClass * createFirewallHelper() return helper; } +FirewallHelperClass::FirewallBehaviorType getBestKnownFirewallBehavior() +{ + if (TheFirewallHelper != nullptr) + { + if (TheFirewallHelper->isBehaviorDetectionComplete() + && TheFirewallHelper->getFirewallBehavior() != FirewallHelperClass::FIREWALL_TYPE_UNKNOWN) + { + return TheFirewallHelper->getFirewallBehavior(); + } + + if (TheFirewallHelper->getLastFirewallBehavior() != FirewallHelperClass::FIREWALL_TYPE_UNKNOWN) + { + return TheFirewallHelper->getLastFirewallBehavior(); + } + } + + return FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; +} + +Short getBestKnownSourcePortAllocationDelta() +{ + if (TheFirewallHelper != nullptr) + { + if (TheFirewallHelper->isBehaviorDetectionComplete() + && TheFirewallHelper->getFirewallBehavior() != FirewallHelperClass::FIREWALL_TYPE_UNKNOWN) + { + return TheFirewallHelper->getSourcePortAllocationDelta(); + } + + if (TheFirewallHelper->getLastFirewallBehavior() != FirewallHelperClass::FIREWALL_TYPE_UNKNOWN) + { + return TheFirewallHelper->getLastSourcePortAllocationDelta(); + } + } + + return 0; +} + /*********************************************************************************************** * FirewallHelperClass::FirewallHelperClass -- Constructor * @@ -473,44 +511,6 @@ UnsignedShort FirewallHelperClass::getManglerResponse(UnsignedShort packetID, In return mangled_port; } - - - -/*********************************************************************************************** - * FirewallHelperClass::Write_Firewall_Settings -- Save out firewall settings. * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/22/01 10:23PM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::writeFirewallBehavior() -{ - OptionPreferences pref; - - char num[16]; - num[0] = 0; - itoa(TheGlobalData->m_firewallBehavior, num, 10); - AsciiString numstr; - numstr = num; - (pref)["FirewallBehavior"] = numstr; - - TheWritableGlobalData->m_firewallPortAllocationDelta = getSourcePortAllocationDelta(); - num[0] = 0; - itoa(TheGlobalData->m_firewallPortAllocationDelta, num, 10); - numstr = num; - (pref)["FirewallPortAllocationDelta"] = numstr; - - pref.write(); -} - - /*********************************************************************************************** * FirewallHelperClass::flagNeedToRefresh -- Flag that the next time we log in we need to * * refresh our firewall settings. * @@ -533,31 +533,6 @@ void FirewallHelperClass::flagNeedToRefresh(Bool flag) } } - -/*********************************************************************************************** - * FirewallHelperClass::Read_Firewall_Behavior -- Read in old firewall settings * - * * - * * - * * - * INPUT: Nothing * - * * - * OUTPUT: Nothing * - * * - * WARNINGS: None * - * * - * HISTORY: * - * 3/22/01 10:25PM ST : Created * - *=============================================================================================*/ -void FirewallHelperClass::readFirewallBehavior() -{ -#if (0) - m_lastBehavior = (FirewallBehaviorType) ConfigINI.Get_Int("MultiPlayer", "FirewallSettings", FIREWALL_UNKNOWN); - m_lastSourcePortAllocationDelta = ConfigINI.Get_Int("MultiPlayer", "FirewallDelta", 1); -#endif //(0) -} - - - /*********************************************************************************************** * FHC::detectFirewallBehavior -- What is that wacky firewall doing to our packet headers? * * * @@ -581,6 +556,13 @@ void FirewallHelperClass::detectFirewallBehavior() m_packetID = 0; m_timeoutLength = 0; m_timeoutStart = 0; + + if (m_behavior != FIREWALL_TYPE_UNKNOWN) + { + m_lastBehavior = m_behavior; + m_lastSourcePortAllocationDelta = m_sourcePortAllocationDelta; + } + m_sourcePortAllocationDelta = 0; m_behavior = FIREWALL_TYPE_UNKNOWN; m_currentState = DETECTIONSTATE_BEGIN; @@ -605,6 +587,12 @@ Short FirewallHelperClass::getSourcePortAllocationDelta() { Bool FirewallHelperClass::detectionBeginUpdate() { // UnsignedShort mangler_port = MANGLER_PORT; m_packetID = 0x7f00; + + if (TheGameSpyConfig == nullptr) { + DEBUG_LOG(("FirewallHelperClass::detectionBeginUpdate - no GameSpy config, skipping detection.")); + m_currentState = DETECTIONSTATE_DONE; + return TRUE; + } //int current_mangler = 0; /* diff --git a/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp b/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp index 60d4be33148..28609a79681 100644 --- a/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp +++ b/Core/GameEngine/Source/GameNetwork/GameSpy/PeerDefs.cpp @@ -43,6 +43,7 @@ #include "GameNetwork/GameSpy/PersistentStorageThread.h" #include "GameNetwork/GameSpy/GSConfig.h" #include "GameNetwork/GameSpyOverlay.h" +#include "GameNetwork/FirewallHelper.h" #include "GameNetwork/RankPointValue.h" #include "GameLogic/GameLogic.h" @@ -633,6 +634,11 @@ void SetUpGameSpy( const char *motdBuffer, const char *configBuffer ) TheGameSpyConfig = GameSpyConfigInterface::create(configBuffer); + if (TheFirewallHelper == nullptr) + { + TheFirewallHelper = createFirewallHelper(); + } + TheLadderList = NEW LadderList; ThePinger = PingerInterface::createNewPingerInterface(); @@ -697,6 +703,9 @@ void TearDownGameSpy() delete TheLadderList; TheLadderList = nullptr; + delete TheFirewallHelper; + TheFirewallHelper = nullptr; + delete TheGameSpyConfig; TheGameSpyConfig = nullptr; diff --git a/Core/GameEngine/Source/GameNetwork/NAT.cpp b/Core/GameEngine/Source/GameNetwork/NAT.cpp index d624ec478d7..279051444dc 100644 --- a/Core/GameEngine/Source/GameNetwork/NAT.cpp +++ b/Core/GameEngine/Source/GameNetwork/NAT.cpp @@ -831,7 +831,7 @@ void NAT::processManglerResponse(UnsignedShort mangledPort) { return; } - Short delta = TheGlobalData->m_firewallPortAllocationDelta; + Short delta = getBestKnownSourcePortAllocationDelta(); UnsignedShort sourcePort = getSlotPort(m_connectionNodes[m_localNodeNumber].m_slotIndex); UnsignedShort returnPort = 0; diff --git a/Generals/Code/GameEngine/Include/Common/GlobalData.h b/Generals/Code/GameEngine/Include/Common/GlobalData.h index 26023c229db..ee8b029142e 100644 --- a/Generals/Code/GameEngine/Include/Common/GlobalData.h +++ b/Generals/Code/GameEngine/Include/Common/GlobalData.h @@ -323,10 +323,8 @@ class GlobalData : public SubsystemInterface Int m_netMinPlayers; ///< Min players needed to start a net game UnsignedInt m_defaultIP; ///< preferred IP address for LAN - UnsignedInt m_firewallBehavior; ///< Last detected firewall behavior Bool m_firewallSendDelay; ///< Use send delay for firewall connection negotiations UnsignedInt m_firewallPortOverride; ///< User-specified port to be used - Short m_firewallPortAllocationDelta; ///< the port allocation delta last detected. Int m_baseValuePerSupplyBox; Real m_BuildSpeed; diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index 425394d7298..cd57f922ade 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -434,9 +434,7 @@ GlobalData* GlobalData::m_theOriginal = nullptr; { "ShellMapOn", INI::parseBool, nullptr, offsetof( GlobalData, m_shellMapOn ) }, { "PlayIntro", INI::parseBool, nullptr, offsetof( GlobalData, m_playIntro ) }, - { "FirewallBehavior", INI::parseInt, nullptr, offsetof( GlobalData, m_firewallBehavior ) }, { "FirewallPortOverride", INI::parseInt, nullptr, offsetof( GlobalData, m_firewallPortOverride ) }, - { "FirewallPortAllocationDelta",INI::parseInt, nullptr, offsetof( GlobalData, m_firewallPortAllocationDelta) }, { "GroupSelectMinSelectSize", INI::parseInt, nullptr, offsetof( GlobalData, m_groupSelectMinSelectSize ) }, { "GroupSelectVolumeBase", INI::parseReal, nullptr, offsetof( GlobalData, m_groupSelectVolumeBase ) }, @@ -938,10 +936,8 @@ GlobalData::GlobalData() // m_languageFilterPref = false; m_languageFilterPref = true; - m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; m_firewallSendDelay = FALSE; m_firewallPortOverride = 0; - m_firewallPortAllocationDelta = 0; m_loadScreenDemo = FALSE; m_disableRender = false; @@ -1206,7 +1202,6 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_moveScrollAnchor = optionPref.getMoveScrollAnchor(); TheWritableGlobalData->m_defaultIP = optionPref.getLANIPAddress(); TheWritableGlobalData->m_firewallSendDelay = optionPref.getSendDelay(); - TheWritableGlobalData->m_firewallPortAllocationDelta = optionPref.getFirewallPortAllocationDelta(); TheWritableGlobalData->m_firewallPortOverride = optionPref.getFirewallPortOverride(); TheWritableGlobalData->m_saveCameraInReplay = optionPref.saveCameraInReplays(); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp index 07c9fddd4cd..992de08732b 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp @@ -1208,12 +1208,10 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) hostSlot->setAccept(); if (TheGameSpyInfo->amIHost()) { - OptionPreferences natPref; CustomMatchPreferences customPref; hostSlot->setColor( customPref.getPreferredColor() ); hostSlot->setPlayerTemplate( customPref.getPreferredFaction() ); - FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - hostSlot->setNATBehavior(natBehavior); + hostSlot->setNATBehavior(getBestKnownFirewallBehavior()); hostSlot->setPingString(TheGameSpyInfo->getPingString()); game->setMap(customPref.getPreferredMap()); @@ -1244,7 +1242,6 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) } else { - OptionPreferences natPref; CustomMatchPreferences customPref; AsciiString options; PeerRequest req; @@ -1261,8 +1258,7 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) options.format("Color=%d", customPref.getPreferredColor()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); - FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - options.format("NAT=%d", natBehavior); + options.format("NAT=%d", getBestKnownFirewallBehavior()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); options.format("Ping=%s", TheGameSpyInfo->getPingString().str()); diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index 6edaba07101..5fc6c8a4029 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -66,6 +66,7 @@ #include "GameNetwork/GameSpy/PersistentStorageThread.h" #include "GameNetwork/GameSpyOverlay.h" +#include "GameNetwork/FirewallHelper.h" #include "GameNetwork/WOLBrowser/WebBrowser.h" @@ -811,6 +812,11 @@ void WOLLoginMenuUpdate( WindowLayout * layout, void *userData) if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished()) shutdownComplete(layout); + if (TheFirewallHelper != nullptr) + { + TheFirewallHelper->behaviorDetectionUpdate(); + } + if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue) { PingResponse pingResp; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp index 9579344373b..5283bc2ec02 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp @@ -1691,7 +1691,7 @@ WindowMsgHandledType WOLQuickMatchMenuSystem( GameWindow *window, UnsignedInt ms index = (Int)GadgetComboBoxGetItemData( comboBoxColor, selected ); req.QM.color = index; - req.QM.NAT = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + req.QM.NAT = getBestKnownFirewallBehavior(); if (ladderIndex) { diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp index ab3b1558f63..5b3f780e386 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy.cpp @@ -951,7 +951,7 @@ void JoinRoomCallback(PEER peer, PEERBool success, PEERJoinResult result, RoomTy localIP = ntohl(localIP); // The IP returned from GetLocalChatConnectionAddress is in network byte order. options.format("IP=%d", localIP); peerUTMPlayer(TheGameSpyChat->getPeer(), hostName.str(), "REQ/", options.str(), PEERFalse); - options.format("NAT=%d", TheFirewallHelper->getFirewallBehavior()); + options.format("NAT=%d", getBestKnownFirewallBehavior()); peerUTMPlayer(TheGameSpyChat->getPeer(), hostName.str(), "REQ/", options.str(), PEERFalse); // refresh the map cache diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h index 5235b763fd1..2ed3d340cc0 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h @@ -324,10 +324,8 @@ class GlobalData : public SubsystemInterface Int m_netMinPlayers; ///< Min players needed to start a net game UnsignedInt m_defaultIP; ///< preferred IP address for LAN - UnsignedInt m_firewallBehavior; ///< Last detected firewall behavior Bool m_firewallSendDelay; ///< Use send delay for firewall connection negotiations UnsignedInt m_firewallPortOverride; ///< User-specified port to be used - Short m_firewallPortAllocationDelta; ///< the port allocation delta last detected. Int m_baseValuePerSupplyBox; Real m_BuildSpeed; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index 3878f20b684..e63611447f0 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -434,9 +434,7 @@ GlobalData* GlobalData::m_theOriginal = nullptr; { "ShellMapOn", INI::parseBool, nullptr, offsetof( GlobalData, m_shellMapOn ) }, { "PlayIntro", INI::parseBool, nullptr, offsetof( GlobalData, m_playIntro ) }, - { "FirewallBehavior", INI::parseInt, nullptr, offsetof( GlobalData, m_firewallBehavior ) }, { "FirewallPortOverride", INI::parseInt, nullptr, offsetof( GlobalData, m_firewallPortOverride ) }, - { "FirewallPortAllocationDelta",INI::parseInt, nullptr, offsetof( GlobalData, m_firewallPortAllocationDelta) }, { "GroupSelectMinSelectSize", INI::parseInt, nullptr, offsetof( GlobalData, m_groupSelectMinSelectSize ) }, { "GroupSelectVolumeBase", INI::parseReal, nullptr, offsetof( GlobalData, m_groupSelectVolumeBase ) }, @@ -945,10 +943,8 @@ GlobalData::GlobalData() // m_languageFilterPref = false; m_languageFilterPref = true; - m_firewallBehavior = FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; m_firewallSendDelay = FALSE; m_firewallPortOverride = 0; - m_firewallPortAllocationDelta = 0; m_loadScreenDemo = FALSE; m_disableRender = false; @@ -1213,7 +1209,6 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_moveScrollAnchor = optionPref.getMoveScrollAnchor(); TheWritableGlobalData->m_defaultIP = optionPref.getLANIPAddress(); TheWritableGlobalData->m_firewallSendDelay = optionPref.getSendDelay(); - TheWritableGlobalData->m_firewallPortAllocationDelta = optionPref.getFirewallPortAllocationDelta(); TheWritableGlobalData->m_firewallPortOverride = optionPref.getFirewallPortOverride(); TheWritableGlobalData->m_saveCameraInReplay = optionPref.saveCameraInReplays(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp index c0e255923a9..46aa6479b92 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp @@ -1365,12 +1365,10 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) hostSlot->setAccept(); if (TheGameSpyInfo->amIHost()) { - OptionPreferences natPref; CustomMatchPreferences customPref; hostSlot->setColor( customPref.getPreferredColor() ); hostSlot->setPlayerTemplate( customPref.getPreferredFaction() ); - FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - hostSlot->setNATBehavior(natBehavior); + hostSlot->setNATBehavior(getBestKnownFirewallBehavior()); hostSlot->setPingString(TheGameSpyInfo->getPingString()); game->setMap(customPref.getPreferredMap()); @@ -1421,7 +1419,6 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) } else { - OptionPreferences natPref; CustomMatchPreferences customPref; AsciiString options; PeerRequest req; @@ -1438,8 +1435,7 @@ void WOLGameSetupMenuInit( WindowLayout *layout, void *userData ) options.format("Color=%d", customPref.getPreferredColor()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); - FirewallHelperClass::FirewallBehaviorType natBehavior = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; - options.format("NAT=%d", natBehavior); + options.format("NAT=%d", getBestKnownFirewallBehavior()); req.options = options.str(); TheGameSpyPeerMessageQueue->addRequest(req); options.format("Ping=%s", TheGameSpyInfo->getPingString().str()); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index 25d49d2daa2..0cf9d06be13 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -66,6 +66,7 @@ #include "GameNetwork/GameSpy/PersistentStorageThread.h" #include "GameNetwork/GameSpyOverlay.h" +#include "GameNetwork/FirewallHelper.h" #include "GameNetwork/WOLBrowser/WebBrowser.h" @@ -811,6 +812,11 @@ void WOLLoginMenuUpdate( WindowLayout * layout, void *userData) if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished()) shutdownComplete(layout); + if (TheFirewallHelper != nullptr) + { + TheFirewallHelper->behaviorDetectionUpdate(); + } + if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue) { PingResponse pingResp; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp index 19d78c20424..c57936351cc 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLQuickMatchMenu.cpp @@ -1756,7 +1756,7 @@ WindowMsgHandledType WOLQuickMatchMenuSystem( GameWindow *window, UnsignedInt ms index = (Int)GadgetComboBoxGetItemData( comboBoxColor, selected ); req.QM.color = index; - req.QM.NAT = TheFirewallHelper ? TheFirewallHelper->getFirewallBehavior() : FirewallHelperClass::FIREWALL_TYPE_UNKNOWN; + req.QM.NAT = getBestKnownFirewallBehavior(); if (ladderIndex) { From 802dd307e382dfd6d2df423e6989e1d97459ebdb Mon Sep 17 00:00:00 2001 From: githubawn <115191165+githubawn@users.noreply.github.com> Date: Sun, 26 Jul 2026 18:26:35 +0200 Subject: [PATCH 6/6] refactor(network): Put Refresh NAT button hiding behind ENABLE_GUI_HACKS --- .../GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp | 6 +++--- .../GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index ddde5e17fba..cdeb55d983e 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -968,10 +968,12 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); - // TheSuperHackers @info 25/07/2026 Refresh button has been hidden, we have migrated this to self-healing NAT +#if ENABLE_GUI_HACKS + // TheSuperHackers @tweak 25/07/2026 Hide the obsolete Refresh NAT button, because NAT detection is now self-healing GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); if (buttonFirewallRefresh) buttonFirewallRefresh->winHide(TRUE); +#endif checkDrawAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxDrawAnchor" ); checkDrawAnchor = TheWindowManager->winGetWindowFromId( nullptr, checkDrawAnchorID); checkMoveAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxMoveAnchor" ); @@ -1391,8 +1393,6 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkSendDelay->winEnable(FALSE); - buttonFirewallRefresh->winEnable(FALSE); - if (comboBoxDetail) comboBoxDetail->winEnable(FALSE); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index a8eebcbcd92..7baad300dac 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -997,10 +997,12 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkLanguageFilter = TheWindowManager->winGetWindowFromId( nullptr, checkLanguageFilterID ); checkSendDelayID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckSendDelay" ); checkSendDelay = TheWindowManager->winGetWindowFromId( nullptr, checkSendDelayID); - // TheSuperHackers @info 25/07/2026 Refresh button has been hidden, we have migrated this to self-healing +#if ENABLE_GUI_HACKS + // TheSuperHackers @tweak 25/07/2026 Hide the obsolete Refresh NAT button, because NAT detection is now self-healing GameWindow *buttonFirewallRefresh = TheWindowManager->winGetWindowFromId(nullptr, NAMEKEY("OptionsMenu.wnd:ButtonFirewallRefresh")); if (buttonFirewallRefresh) buttonFirewallRefresh->winHide(TRUE); +#endif checkDrawAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxDrawAnchor" ); checkDrawAnchor = TheWindowManager->winGetWindowFromId( nullptr, checkDrawAnchorID); checkMoveAnchorID = TheNameKeyGenerator->nameToKey( "OptionsMenu.wnd:CheckBoxMoveAnchor" ); @@ -1427,8 +1429,6 @@ void OptionsMenuInit( WindowLayout *layout, void *userData ) checkSendDelay->winEnable(FALSE); - buttonFirewallRefresh->winEnable(FALSE); - if (comboBoxDetail) comboBoxDetail->winEnable(FALSE);