/*
** 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 .
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Commando/gamespyauthmgr.cpp $*
* *
* $Author:: Tom_s $*
* *
* $Modtime:: 2/22/02 5:41p $*
* *
* $Revision:: 3 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "gamespyauthmgr.h"
#include "gamespyscchallengeevent.h"
#include "playermanager.h"
#include "cnetwork.h"
#include "gamespyadmin.h"
#include "cdkeyauth.h"
#include "sctextobj.h"
#include "translatedb.h"
#include "string_ids.h"
//
// Class statics
//
//-----------------------------------------------------------------------------
void
cGameSpyAuthMgr::Think
(
void
)
{
WWASSERT(cNetwork::I_Am_Server());
WWASSERT(cGameSpyAdmin::Is_Gamespy_Game());
//
// Process all the players
//
WWASSERT(cPlayerManager::Get_Player_Object_List() != NULL);
for (
SLNode * player_node = cPlayerManager::Get_Player_Object_List()->Head();
player_node != NULL;
player_node = player_node->Next())
{
cPlayer * p_player = player_node->Data();
WWASSERT(p_player != NULL);
if (!p_player->Is_Alive_And_Kicking())
{
continue;
}
switch (p_player->Get_GameSpy_Auth_State())
{
case GAMESPY_AUTH_STATE_INITIAL:
{
if (cNetwork::I_Am_Client() && p_player->Get_Id() == cNetwork::Get_My_Id())
{
//
// Do not bother authenticating the server's local client.
//
p_player->Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_ACCEPTED);
}
else
{
//
// Challenge this player
//
StringClass challenge_string;
challenge_string.Format("%s", CCDKeyAuth::GenChallenge(8));
p_player->Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_CHALLENGED);
p_player->Set_GameSpy_Challenge_String(challenge_string);
cGameSpyScChallengeEvent * p_event = new cGameSpyScChallengeEvent;
p_event->Init(p_player->Get_Id(), challenge_string);
}
break;
}
case GAMESPY_AUTH_STATE_CHALLENGED:
{
DWORD time_now_ms = TIMEGETTIME();
if (time_now_ms - p_player->Get_GameSpy_Auth_State_Entry_Time_Ms() >
CHALLENGE_RESPONSE_TIMEOUT_MS)
{
//
// We challenged this guy and he hasn't responded in the required
// time. We are going to have to boot him out.
//
int player_id = p_player->Get_Id();
WWDEBUG_SAY(("cGameSpyAuthMgr::Think: player %d timed out on challenge response.\n",
player_id));
//p_player->Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_REJECTING);
//Evict_Player(player_id);
cGameSpyAuthMgr::Initiate_Auth_Rejection(player_id);
}
break;
}
case GAMESPY_AUTH_STATE_VALIDATING:
{
//
// At this stage I am not implementing any timeout for GameSpy to
// authenticate this user.
//
break;
}
case GAMESPY_AUTH_STATE_ACCEPTED:
{
//
// The only peaceful, harmonious state.
//
break;
}
case GAMESPY_AUTH_STATE_REJECTING:
{
DWORD time_now_ms = TIMEGETTIME();
if (time_now_ms - p_player->Get_GameSpy_Auth_State_Entry_Time_Ms() >
REJECTION_DELAY_MS)
{
p_player->Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_REJECTED);
Evict_Player(p_player->Get_Id());
}
break;
}
case GAMESPY_AUTH_STATE_REJECTED:
{
//
// Do nothing
//
break;
}
default:
DIE;
}
}
}
//-----------------------------------------------------------------------------
void
cGameSpyAuthMgr::Initiate_Auth_Rejection
(
int player_id
)
{
WWDEBUG_SAY(("cGameSpyAuthMgr::Initiate_Auth_Rejection(%d)\n", player_id));
WWASSERT(cNetwork::I_Am_Server());
WWASSERT(cGameSpyAdmin::Is_Gamespy_Game());
cPlayer * p_player = cPlayerManager::Find_Player(player_id);
if (p_player != NULL)
{
cScTextObj * p_message = new cScTextObj;
//p_message->Init(L"CD Authentication failed. Please quit.", TEXT_MESSAGE_PRIVATE, true, HOST_TEXT_SENDER, player_id);
p_message->Init(TRANSLATE(IDS_MP_CD_AUTH_FAILED), TEXT_MESSAGE_PRIVATE, true, HOST_TEXT_SENDER, player_id);
p_player->Set_GameSpy_Auth_State(GAMESPY_AUTH_STATE_REJECTING);
}
}
//-----------------------------------------------------------------------------
void
cGameSpyAuthMgr::Evict_Player
(
int player_id
)
{
WWDEBUG_SAY(("cGameSpyAuthMgr::Evict_Player(%d)\n", player_id));
WWASSERT(cNetwork::I_Am_Server());
WWASSERT(cGameSpyAdmin::Is_Gamespy_Game());
//
// The behaviour presently is fairly brutal - no feedback to evicted player.
// This is fine if he is a cracker, but other cases exist. TODO_AUTH.
//
cNetwork::Server_Kill_Connection(player_id);
cNetwork::Cleanup_After_Client(player_id);
}
//-----------------------------------------------------------------------------
LPCSTR
cGameSpyAuthMgr::Describe_Auth_State
(
GAMESPY_AUTH_STATE_ENUM state
)
{
switch (state)
{
case GAMESPY_AUTH_STATE_INITIAL: return "INITIAL";
case GAMESPY_AUTH_STATE_CHALLENGED: return "CHALLENGED";
case GAMESPY_AUTH_STATE_VALIDATING: return "VALIDATING";
case GAMESPY_AUTH_STATE_ACCEPTED: return "ACCEPTED";
case GAMESPY_AUTH_STATE_REJECTING: return "REJECTING";
case GAMESPY_AUTH_STATE_REJECTED: return "REJECTED";
default: DIE; return "bollocks"; // avoid compiler warning;
}
}