This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Commando/FirewallWait.cpp

317 lines
No EOL
7.2 KiB
C++

/*
** 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 <http://www.gnu.org/licenses/>.
*/
/******************************************************************************
*
* 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 <WWOnline\WOLSession.h>
#include <WWDebug\WWDebug.h>
#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> 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> 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);
}