/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /****************************************************************************** * * FILE * $Archive: /Commando/Code/Commando/FirewallWait.cpp $ * * DESCRIPTION * Firewall negotiation wait condition. * * PROGRAMMER * $Author: Tom_s $ * * VERSION INFO * $Revision: 16 $ * $Modtime: 3/04/02 11:45a $ * ******************************************************************************/ #include "always.h" #include "FirewallWait.h" #include "nat.h" #include "string_ids.h" #include "translatedb.h" #include "natter.h" #include #include #ifdef _MSC_VER #pragma warning (push,3) #endif #include "systimer.h" #ifdef _MSC_VER #pragma warning (pop) #endif /* ** Wait code for firewall/NAT detection. ** ** ** */ RefPtr FirewallDetectWait::Create(void) { return new FirewallDetectWait(); } FirewallDetectWait::FirewallDetectWait(void) : SingleWait(TRANSLATION(IDS_FIREWALL_NEGOTIATING_FIREWALL), 60000), mEvent(NULL), mPingsRemaining(UINT_MAX) { mWOLSession = WWOnline::Session::GetInstance(false); assert(mWOLSession.IsValid()); } FirewallDetectWait::~FirewallDetectWait() { WWDEBUG_SAY(("FirewallDetectWait: End - %S\n", mEndText)); mWOLSession->EnablePinging(true); if (mEvent) { CloseHandle(mEvent); } } void FirewallDetectWait::WaitBeginning(void) { WWDEBUG_SAY(("FirewallDetectWait: Beginning\n")); mEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (mEvent == NULL) { WWDEBUG_SAY(("FirewallDetectWait: Can't create event\n")); EndWait(Error, TRANSLATION(IDS_FIREWALL_CREATE_EVENT_FAILED)); } else { mWOLSession->EnablePinging(false); mTimeout = 15000; } } WaitCondition::WaitResult FirewallDetectWait::GetResult(void) { if (mEndResult == Waiting) { // Wait for pending pings to finish first unsigned int pingsWaiting = mWOLSession->GetPendingPingCount(); if (mPingsRemaining != pingsWaiting) { mPingsRemaining = pingsWaiting; mTimeout = 60000; FirewallHelper.Detect_Firewall(mEvent); } if (mPingsRemaining == 0) { DWORD result = WaitForSingleObject(mEvent, 0); if (result == WAIT_OBJECT_0) { WWDEBUG_SAY(("FirewallDetectWait: ConditionMet\n")); WOLNATInterface.Save_Firewall_Info_To_Registry(); EndWait(ConditionMet, TRANSLATION(IDS_FIREWALL_NEGOTIATION_COMPLETE)); } else if (result == WAIT_FAILED) { WWDEBUG_SAY(("FirewallDetectWait: WAIT_FAILED\n")); EndWait(Error, TRANSLATION(IDS_FIREWALL_NEGOTIATION_FAILED)); } } } if (mEndResult != Waiting) { mWOLSession->EnablePinging(true); } return mEndResult; } /* ** Wait code for clients when trying to open up a firewall for a server connection. ** */ RefPtr FirewallConnectWait::Create(void) { return new FirewallConnectWait; } FirewallConnectWait::FirewallConnectWait(void) : SingleWait(TRANSLATION(IDS_FIREWALL_NEGOTIATING_WITH_SERVER)), mEvent(NULL), mCancelEvent(NULL), mSuccessFlag(FirewallHelperClass::FW_RESULT_UNKNOWN), mQueueCount(0), mLastQueueCount(0), mPingsRemaining(UINT_MAX) { mWOLSession = WWOnline::Session::GetInstance(false); assert(mWOLSession.IsValid()); } FirewallConnectWait::~FirewallConnectWait() { WWDEBUG_SAY(("FirewallConnectWait: End - %S\n", mEndText)); mWOLSession->EnablePinging(true); if (mEvent) { CloseHandle(mEvent); } if (mCancelEvent) { CloseHandle(mCancelEvent); } } void FirewallConnectWait::WaitBeginning(void) { WWDEBUG_SAY(("FirewallConnectWait: Beginning\n")); mEvent = CreateEvent(NULL, TRUE, FALSE, NULL); mCancelEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (mEvent == NULL) { WWDEBUG_SAY(("FirewallConnectWait: Can't create event\n")); EndWait(Error, TRANSLATION(IDS_FIREWALL_CREATE_EVENT_FAILED)); } else { mWOLSession->EnablePinging(false); WOLNATInterface.Tell_Server_That_Client_Is_In_Channel(); mTimeout = 15000; mStartTime = TIMEGETTIME(); } } WaitCondition::WaitResult FirewallConnectWait::GetResult(void) { if (mEndResult == Waiting) { // Wait for pending pings to finish first unsigned int pingsWaiting = mWOLSession->GetPendingPingCount(); if (mPingsRemaining != pingsWaiting) { mPingsRemaining = pingsWaiting; if (mPingsRemaining == 0) { FirewallHelper.Set_Client_Connect_Event(mEvent, mCancelEvent, &mSuccessFlag, (int*)&mQueueCount); mTimeout = 32000; mStartTime = TIMEGETTIME(); } } if (mPingsRemaining == 0) { if ((TIMEGETTIME() - mStartTime) > mTimeout) { EndWait(TimeOut, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_TIMEOUT)); } else { // Maybe change the wait text if there are players queued in front of us. if (mQueueCount != mLastQueueCount) { wchar_t temp[256]; swprintf(temp, TRANSLATION(IDS_FIREWALL_QUEUE_NOTIFICATION), mQueueCount); WideStringClass text(temp, true); SetWaitText(text); mLastQueueCount = mQueueCount; mTimeout = max((unsigned)32000, ((mQueueCount * 32000) + 32000)); mStartTime = TIMEGETTIME(); } DWORD result = WaitForSingleObject(mEvent, 0); if (result == WAIT_OBJECT_0) { if (mSuccessFlag == FirewallHelperClass::FW_RESULT_SUCCEEDED) { WWDEBUG_SAY(("FirewallConnectWait: ConditionMet\n")); EndWait(ConditionMet, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_COMPLETE)); } else { assert(mSuccessFlag == FirewallHelperClass::FW_RESULT_FAILED); WWDEBUG_SAY(("FirewallConnectWait: ConditionMet\n")); EndWait(Error, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_FAILED)); } } else if (result == WAIT_FAILED) { WWDEBUG_SAY(("FirewallConnectWait: WAIT_FAILED\n")); EndWait(Error, TRANSLATION(IDS_FIREWALL_PORT_NEGOTIATION_FAILED)); } } } } if (mEndResult != Waiting) { mWOLSession->EnablePinging(true); } return mEndResult; } // // Override base class end wait to check for cancel being pressed. // void FirewallConnectWait::EndWait(WaitResult result, const wchar_t* endText) { WWDEBUG_SAY(("FirewallConnectWait: EndWait\n")); if (result == UserCancel || result == TimeOut) { // Tell the firewall negotiation code to give up. SetEvent(mCancelEvent); } // Give the firewall code a little time to respond then remove it's cancel event anyway. It'll figure it out. for (int i=0 ; i<100 ; i++) { if (mSuccessFlag == FirewallHelperClass::FW_RESULT_CANCELLED) { break; } Sleep(1); } FirewallHelper.Set_Client_Connect_Event(NULL, NULL, NULL, NULL); SingleWait::EndWait(result, endText); }