2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2011-07-31 11:17:38 +00:00
# include <base/math.h>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
2011-02-27 14:03:57 +00:00
# include <engine/config.h>
# include <engine/console.h>
# include <engine/engine.h>
# include <engine/map.h>
# include <engine/masterserver.h>
# include <engine/server.h>
# include <engine/storage.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/compression.h>
# include <engine/shared/config.h>
# include <engine/shared/datafile.h>
2010-09-12 10:16:51 +00:00
# include <engine/shared/demo.h>
2011-07-30 11:40:01 +00:00
# include <engine/shared/econ.h>
2011-07-30 16:29:40 +00:00
# include <engine/shared/filecollection.h>
2011-03-31 13:13:49 +00:00
# include <engine/shared/mapchecker.h>
2011-12-29 22:36:53 +00:00
# include <engine/shared/netban.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/network.h>
# include <engine/shared/packer.h>
# include <engine/shared/protocol.h>
# include <engine/shared/snapshot.h>
2014-08-29 14:52:08 +00:00
# include <engine/shared/fifoconsole.h>
2010-05-29 07:25:38 +00:00
# include <mastersrv/mastersrv.h>
2011-04-26 09:51:02 +00:00
// DDRace
# include <string.h>
# include <vector>
# include <engine/shared/linereader.h>
2014-01-30 15:49:15 +00:00
# include <game/server/gamecontext.h>
2011-04-26 09:51:02 +00:00
2010-05-29 07:25:38 +00:00
# include "register.h"
# include "server.h"
2011-04-13 18:37:12 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2011-02-27 14:03:57 +00:00
# define _WIN32_WINNT 0x0501
# define WIN32_LEAN_AND_MEAN
2010-05-29 07:25:38 +00:00
# include <windows.h>
# endif
2012-07-08 09:40:23 +00:00
static const char * StrLtrim ( const char * pStr )
2010-05-29 07:25:38 +00:00
{
2011-12-29 12:34:13 +00:00
while ( * pStr )
2010-05-29 07:25:38 +00:00
{
2011-12-29 12:34:13 +00:00
const char * pStrOld = pStr ;
int Code = str_utf8_decode ( & pStr ) ;
2015-07-09 00:08:14 +00:00
2011-12-29 12:34:13 +00:00
// check if unicode is not empty
2014-11-08 19:14:12 +00:00
if ( str_utf8_isspace ( Code ) )
2011-12-29 12:34:13 +00:00
{
return pStrOld ;
}
2010-05-29 07:25:38 +00:00
}
return pStr ;
}
2012-07-08 09:40:23 +00:00
static void StrRtrim ( char * pStr )
2010-05-29 07:25:38 +00:00
{
2011-12-29 12:34:13 +00:00
const char * p = pStr ;
const char * pEnd = 0 ;
while ( * p )
2010-05-29 07:25:38 +00:00
{
2011-12-29 12:34:13 +00:00
const char * pStrOld = p ;
int Code = str_utf8_decode ( & p ) ;
2015-07-09 00:08:14 +00:00
2011-12-29 12:34:13 +00:00
// check if unicode is not empty
2014-11-08 19:14:12 +00:00
if ( str_utf8_isspace ( Code ) )
2011-12-29 12:34:13 +00:00
{
pEnd = 0 ;
}
else if ( pEnd = = 0 )
pEnd = pStrOld ;
2010-05-29 07:25:38 +00:00
}
2011-12-29 12:34:13 +00:00
if ( pEnd ! = 0 )
* ( const_cast < char * > ( pEnd ) ) = 0 ;
2010-05-29 07:25:38 +00:00
}
CSnapIDPool : : CSnapIDPool ( )
{
Reset ( ) ;
}
void CSnapIDPool : : Reset ( )
{
for ( int i = 0 ; i < MAX_IDS ; i + + )
{
m_aIDs [ i ] . m_Next = i + 1 ;
m_aIDs [ i ] . m_State = 0 ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_aIDs [ MAX_IDS - 1 ] . m_Next = - 1 ;
m_FirstFree = 0 ;
m_FirstTimed = - 1 ;
m_LastTimed = - 1 ;
m_Usage = 0 ;
m_InUsage = 0 ;
}
void CSnapIDPool : : RemoveFirstTimeout ( )
{
int NextTimed = m_aIDs [ m_FirstTimed ] . m_Next ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// add it to the free list
m_aIDs [ m_FirstTimed ] . m_Next = m_FirstFree ;
m_aIDs [ m_FirstTimed ] . m_State = 0 ;
m_FirstFree = m_FirstTimed ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// remove it from the timed list
m_FirstTimed = NextTimed ;
if ( m_FirstTimed = = - 1 )
m_LastTimed = - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_Usage - - ;
}
int CSnapIDPool : : NewID ( )
{
int64 Now = time_get ( ) ;
// process timed ids
while ( m_FirstTimed ! = - 1 & & m_aIDs [ m_FirstTimed ] . m_Timeout < Now )
RemoveFirstTimeout ( ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
int ID = m_FirstFree ;
dbg_assert ( ID ! = - 1 , " id error " ) ;
if ( ID = = - 1 )
return ID ;
2010-05-29 07:25:38 +00:00
m_FirstFree = m_aIDs [ m_FirstFree ] . m_Next ;
2011-02-12 10:40:36 +00:00
m_aIDs [ ID ] . m_State = 1 ;
2010-05-29 07:25:38 +00:00
m_Usage + + ;
m_InUsage + + ;
2011-02-12 10:40:36 +00:00
return ID ;
2010-05-29 07:25:38 +00:00
}
void CSnapIDPool : : TimeoutIDs ( )
{
// process timed ids
while ( m_FirstTimed ! = - 1 )
RemoveFirstTimeout ( ) ;
}
2011-02-12 10:40:36 +00:00
void CSnapIDPool : : FreeID ( int ID )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
if ( ID < 0 )
2010-12-16 02:29:08 +00:00
return ;
2011-02-12 10:40:36 +00:00
dbg_assert ( m_aIDs [ ID ] . m_State = = 1 , " id is not alloced " ) ;
2010-05-29 07:25:38 +00:00
m_InUsage - - ;
2011-02-12 10:40:36 +00:00
m_aIDs [ ID ] . m_State = 2 ;
m_aIDs [ ID ] . m_Timeout = time_get ( ) + time_freq ( ) * 5 ;
m_aIDs [ ID ] . m_Next = - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( m_LastTimed ! = - 1 )
{
2011-02-12 10:40:36 +00:00
m_aIDs [ m_LastTimed ] . m_Next = ID ;
m_LastTimed = ID ;
2010-05-29 07:25:38 +00:00
}
else
{
2011-02-12 10:40:36 +00:00
m_FirstTimed = ID ;
m_LastTimed = ID ;
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2011-12-29 22:36:53 +00:00
2012-08-16 22:03:53 +00:00
void CServerBan : : InitServerBan ( IConsole * pConsole , IStorage * pStorage , CServer * pServer )
2011-12-29 22:36:53 +00:00
{
CNetBan : : Init ( pConsole , pStorage ) ;
m_pServer = pServer ;
// overwrites base command, todo: improve this
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " ban " , " s[ip|id] ?i[minutes] r[reason] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConBanExt , this , " Ban player with ip/client id for x minutes for any reason " ) ;
2011-12-29 22:36:53 +00:00
}
template < class T >
int CServerBan : : BanExt ( T * pBanPool , const typename T : : CDataType * pData , int Seconds , const char * pReason )
{
// validate address
if ( Server ( ) - > m_RconClientID > = 0 & & Server ( ) - > m_RconClientID < MAX_CLIENTS & &
Server ( ) - > m_aClients [ Server ( ) - > m_RconClientID ] . m_State ! = CServer : : CClient : : STATE_EMPTY )
{
if ( NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( Server ( ) - > m_RconClientID ) ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (you can't ban yourself) " ) ;
return - 1 ;
}
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( i = = Server ( ) - > m_RconClientID | | Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( Server ( ) - > m_aClients [ i ] . m_Authed > = Server ( ) - > m_RconAuthLevel & & NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (command denied) " ) ;
return - 1 ;
}
}
}
2011-12-31 11:11:48 +00:00
else if ( Server ( ) - > m_RconClientID = = IServer : : RCON_CID_VOTE )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( Server ( ) - > m_aClients [ i ] . m_Authed ! = CServer : : AUTHED_NO & & NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (command denied) " ) ;
return - 1 ;
}
}
}
2011-12-29 22:36:53 +00:00
int Result = Ban ( pBanPool , pData , Seconds , pReason ) ;
if ( Result ! = 0 )
return Result ;
// drop banned clients
2011-12-30 18:35:57 +00:00
typename T : : CDataType Data = * pData ;
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( NetMatch ( & Data , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
{
CNetHash NetHash ( & Data ) ;
char aBuf [ 256 ] ;
MakeBanInfo ( pBanPool - > Find ( & Data , & NetHash ) , aBuf , sizeof ( aBuf ) , MSGTYPE_PLAYER ) ;
Server ( ) - > m_NetServer . Drop ( i , aBuf ) ;
}
}
return Result ;
}
int CServerBan : : BanAddr ( const NETADDR * pAddr , int Seconds , const char * pReason )
{
return BanExt ( & m_BanAddrPool , pAddr , Seconds , pReason ) ;
}
int CServerBan : : BanRange ( const CNetRange * pRange , int Seconds , const char * pReason )
{
if ( pRange - > IsValid ( ) )
return BanExt ( & m_BanRangePool , pRange , Seconds , pReason ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban failed (invalid range) " ) ;
return - 1 ;
}
void CServerBan : : ConBanExt ( IConsole : : IResult * pResult , void * pUser )
{
CServerBan * pThis = static_cast < CServerBan * > ( pUser ) ;
const char * pStr = pResult - > GetString ( 0 ) ;
int Minutes = pResult - > NumArguments ( ) > 1 ? clamp ( pResult - > GetInteger ( 1 ) , 0 , 44640 ) : 30 ;
const char * pReason = pResult - > NumArguments ( ) > 2 ? pResult - > GetString ( 2 ) : " No reason given " ;
if ( StrAllnum ( pStr ) )
{
int ClientID = str_toint ( pStr ) ;
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | pThis - > Server ( ) - > m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (invalid client id) " ) ;
else
pThis - > BanAddr ( pThis - > Server ( ) - > m_NetServer . ClientAddr ( ClientID ) , Minutes * 60 , pReason ) ;
}
else
ConBan ( pResult , pUser ) ;
}
2010-05-29 07:25:38 +00:00
void CServer : : CClient : : Reset ( )
{
// reset input
for ( int i = 0 ; i < 200 ; i + + )
m_aInputs [ i ] . m_GameTick = - 1 ;
m_CurrentInput = 0 ;
mem_zero ( & m_LatestInput , sizeof ( m_LatestInput ) ) ;
m_Snapshots . PurgeAll ( ) ;
m_LastAckedSnapshot = - 1 ;
m_LastInputTick = - 1 ;
m_SnapRate = CClient : : SNAPRATE_INIT ;
m_Score = 0 ;
}
2014-09-26 00:05:22 +00:00
CServer : : CServer ( )
2010-05-29 07:25:38 +00:00
{
2014-12-02 14:44:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
m_aDemoRecorder [ i ] = CDemoRecorder ( & m_SnapshotDelta , true ) ;
m_aDemoRecorder [ MAX_CLIENTS ] = CDemoRecorder ( & m_SnapshotDelta , false ) ;
2014-09-26 00:05:22 +00:00
2010-05-29 07:25:38 +00:00
m_TickSpeed = SERVER_TICK_SPEED ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_pGameServer = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_CurrentGameTick = 0 ;
m_RunServer = 1 ;
m_pCurrentMapData = 0 ;
m_CurrentMapSize = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-30 12:01:11 +00:00
m_MapReload = 0 ;
2015-10-22 15:27:30 +00:00
m_ReloadedWhenEmpty = false ;
2010-05-29 07:25:38 +00:00
2011-12-31 11:11:48 +00:00
m_RconClientID = IServer : : RCON_CID_SERV ;
2011-07-05 19:54:10 +00:00
m_RconAuthLevel = AUTHED_ADMIN ;
2010-09-12 11:52:25 +00:00
2013-07-30 23:31:53 +00:00
m_RconRestrict = - 1 ;
2015-06-21 17:46:55 +00:00
m_GeneratedRconPassword = 0 ;
2013-07-30 23:31:53 +00:00
2016-01-22 15:02:40 +00:00
m_ServerInfoFirstRequest = 0 ;
m_ServerInfoNumRequests = 0 ;
m_ServerInfoHighLoad = false ;
2010-05-29 07:25:38 +00:00
Init ( ) ;
}
int CServer : : TrySetClientName ( int ClientID , const char * pName )
{
char aTrimmedName [ 64 ] ;
// trim the name
2012-07-08 09:40:23 +00:00
str_copy ( aTrimmedName , StrLtrim ( pName ) , sizeof ( aTrimmedName ) ) ;
StrRtrim ( aTrimmedName ) ;
// check for empty names
if ( ! aTrimmedName [ 0 ] )
return - 1 ;
2011-03-15 10:23:49 +00:00
2015-12-16 19:15:43 +00:00
// make sure that two clients don't have the same name
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2015-12-18 12:17:45 +00:00
{
2010-05-29 07:25:38 +00:00
if ( i ! = ClientID & & m_aClients [ i ] . m_State > = CClient : : STATE_READY )
{
2015-12-17 15:27:35 +00:00
if ( str_utf8_comp_names ( aTrimmedName , m_aClients [ i ] . m_aName ) = = 0 )
2010-05-29 07:25:38 +00:00
return - 1 ;
}
2015-12-18 12:17:45 +00:00
}
2010-05-29 07:25:38 +00:00
2015-12-18 12:17:45 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " '%s' -> '%s' " , pName , aTrimmedName ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
pName = aTrimmedName ;
2015-12-17 15:27:35 +00:00
2010-05-29 07:25:38 +00:00
// set the client name
str_copy ( m_aClients [ ClientID ] . m_aName , pName , MAX_NAME_LENGTH ) ;
return 0 ;
}
2016-01-27 00:48:19 +00:00
2010-05-29 07:25:38 +00:00
void CServer : : SetClientName ( int ClientID , const char * pName )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( ! pName )
return ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
char aNameTry [ MAX_NAME_LENGTH ] ;
2013-12-26 17:02:22 +00:00
str_copy ( aNameTry , pName , sizeof ( aNameTry ) ) ;
2010-05-29 07:25:38 +00:00
if ( TrySetClientName ( ClientID , aNameTry ) )
{
// auto rename
for ( int i = 1 ; ; i + + )
{
2013-12-26 17:02:22 +00:00
str_format ( aNameTry , sizeof ( aNameTry ) , " (%d)%s " , i , pName ) ;
2010-05-29 07:25:38 +00:00
if ( TrySetClientName ( ClientID , aNameTry ) = = 0 )
break ;
}
}
}
2011-03-15 10:23:49 +00:00
void CServer : : SetClientClan ( int ClientID , const char * pClan )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY | | ! pClan )
return ;
2011-04-13 18:37:12 +00:00
2011-03-15 10:23:49 +00:00
str_copy ( m_aClients [ ClientID ] . m_aClan , pClan , MAX_CLAN_LENGTH ) ;
}
void CServer : : SetClientCountry ( int ClientID , int Country )
2010-05-29 07:25:38 +00:00
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
2011-04-13 18:37:12 +00:00
2011-03-15 10:23:49 +00:00
m_aClients [ ClientID ] . m_Country = Country ;
2010-05-29 07:25:38 +00:00
}
void CServer : : SetClientScore ( int ClientID , int Score )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
m_aClients [ ClientID ] . m_Score = Score ;
}
void CServer : : Kick ( int ClientID , const char * pReason )
{
2010-09-12 10:07:10 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CClient : : STATE_EMPTY )
2010-09-12 11:52:25 +00:00
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " invalid client id to kick " ) ;
2010-05-29 07:25:38 +00:00
return ;
2010-09-12 11:52:25 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( m_RconClientID = = ClientID )
2010-09-12 11:52:25 +00:00
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " you can't kick yourself " ) ;
2015-07-09 00:08:14 +00:00
return ;
2010-09-12 10:07:10 +00:00
}
2011-07-05 19:54:10 +00:00
else if ( m_aClients [ ClientID ] . m_Authed > m_RconAuthLevel )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " kick command denied " ) ;
2015-07-09 00:08:14 +00:00
return ;
2011-07-05 19:54:10 +00:00
}
2011-04-13 18:37:12 +00:00
2010-09-12 10:07:10 +00:00
m_NetServer . Drop ( ClientID , pReason ) ;
2010-05-29 07:25:38 +00:00
}
/*int CServer::Tick()
{
return m_CurrentGameTick ;
} */
int64 CServer : : TickStartTime ( int Tick )
{
return m_GameStartTime + ( time_freq ( ) * Tick ) / SERVER_TICK_SPEED ;
}
/*int CServer::TickSpeed()
{
return SERVER_TICK_SPEED ;
} */
int CServer : : Init ( )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
m_aClients [ i ] . m_State = CClient : : STATE_EMPTY ;
m_aClients [ i ] . m_aName [ 0 ] = 0 ;
m_aClients [ i ] . m_aClan [ 0 ] = 0 ;
2011-03-15 10:23:49 +00:00
m_aClients [ i ] . m_Country = - 1 ;
2010-05-29 07:25:38 +00:00
m_aClients [ i ] . m_Snapshots . Init ( ) ;
2013-08-04 02:24:03 +00:00
m_aClients [ i ] . m_Traffic = 0 ;
m_aClients [ i ] . m_TrafficSince = 0 ;
2010-05-29 07:25:38 +00:00
}
m_CurrentGameTick = 0 ;
2010-12-06 02:27:35 +00:00
m_AnnouncementLastLine = 0 ;
2011-04-09 06:41:31 +00:00
memset ( m_aPrevStates , CClient : : STATE_EMPTY , MAX_CLIENTS * sizeof ( int ) ) ;
2010-05-29 07:25:38 +00:00
return 0 ;
}
2011-12-31 11:11:48 +00:00
void CServer : : SetRconCID ( int ClientID )
{
m_RconClientID = ClientID ;
}
2011-08-13 00:11:06 +00:00
bool CServer : : IsAuthed ( int ClientID )
2010-06-02 02:42:17 +00:00
{
2010-10-10 13:36:58 +00:00
return m_aClients [ ClientID ] . m_Authed ;
2010-06-02 02:42:17 +00:00
}
2010-05-29 07:25:38 +00:00
int CServer : : GetClientInfo ( int ClientID , CClientInfo * pInfo )
{
dbg_assert ( ClientID > = 0 & & ClientID < MAX_CLIENTS , " client_id is not valid " ) ;
dbg_assert ( pInfo ! = 0 , " info can not be null " ) ;
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
{
pInfo - > m_pName = m_aClients [ ClientID ] . m_aName ;
pInfo - > m_Latency = m_aClients [ ClientID ] . m_Latency ;
2014-01-30 15:49:15 +00:00
CGameContext * GameServer = ( CGameContext * ) m_pGameServer ;
2014-01-30 15:54:58 +00:00
if ( GameServer - > m_apPlayers [ ClientID ] )
pInfo - > m_ClientVersion = GameServer - > m_apPlayers [ ClientID ] - > m_ClientVersion ;
2010-05-29 07:25:38 +00:00
return 1 ;
}
return 0 ;
}
2011-03-28 18:11:28 +00:00
void CServer : : GetClientAddr ( int ClientID , char * pAddrStr , int Size )
2010-05-29 07:25:38 +00:00
{
if ( ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , pAddrStr , Size , false ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
2011-02-12 10:40:36 +00:00
const char * CServer : : ClientName ( int ClientID )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
2011-04-16 16:41:44 +00:00
return " (invalid) " ;
2011-03-15 10:23:49 +00:00
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_aName ;
else
2011-04-16 16:41:44 +00:00
return " (connecting) " ;
2011-04-13 18:37:12 +00:00
2011-03-15 10:23:49 +00:00
}
const char * CServer : : ClientClan ( int ClientID )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
return " " ;
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_aClan ;
else
return " " ;
}
int CServer : : ClientCountry ( int ClientID )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
return - 1 ;
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_Country ;
else
return - 1 ;
}
2010-05-29 07:25:38 +00:00
bool CServer : : ClientIngame ( int ClientID )
{
return ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME ;
}
2011-12-04 15:51:33 +00:00
int CServer : : MaxClients ( ) const
{
return m_NetServer . MaxClients ( ) ;
}
2015-06-21 17:46:55 +00:00
void CServer : : InitRconPasswordIfEmpty ( )
{
if ( g_Config . m_SvRconPassword [ 0 ] )
{
return ;
}
static const char VALUES [ ] = " ABCDEFGHKLMNPRSTUVWXYZabcdefghjkmnopqt23456789 " ;
static const size_t NUM_VALUES = sizeof ( VALUES ) - 1 ; // Disregard the '\0'.
static const size_t PASSWORD_LENGTH = 6 ;
dbg_assert ( NUM_VALUES * NUM_VALUES > = 2048 , " need at least 2048 possibilities for 2-character sequences " ) ;
// With 6 characters, we get a password entropy of log(2048) * 6/2 = 33bit.
dbg_assert ( PASSWORD_LENGTH % 2 = = 0 , " need an even password length " ) ;
unsigned short aRandom [ PASSWORD_LENGTH / 2 ] ;
char aRandomPassword [ PASSWORD_LENGTH + 1 ] ;
aRandomPassword [ PASSWORD_LENGTH ] = 0 ;
secure_random_fill ( aRandom , sizeof ( aRandom ) ) ;
for ( size_t i = 0 ; i < PASSWORD_LENGTH / 2 ; i + + )
{
unsigned short RandomNumber = aRandom [ i ] % 2048 ;
aRandomPassword [ 2 * i + 0 ] = VALUES [ RandomNumber / NUM_VALUES ] ;
aRandomPassword [ 2 * i + 1 ] = VALUES [ RandomNumber % NUM_VALUES ] ;
}
str_copy ( g_Config . m_SvRconPassword , aRandomPassword , sizeof ( g_Config . m_SvRconPassword ) ) ;
m_GeneratedRconPassword = 1 ;
}
2011-02-12 10:40:36 +00:00
int CServer : : SendMsg ( CMsgPacker * pMsg , int Flags , int ClientID )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
return SendMsgEx ( pMsg , Flags , ClientID , false ) ;
2010-05-29 07:25:38 +00:00
}
int CServer : : SendMsgEx ( CMsgPacker * pMsg , int Flags , int ClientID , bool System )
{
CNetChunk Packet ;
if ( ! pMsg )
return - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
mem_zero ( & Packet , sizeof ( CNetChunk ) ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
Packet . m_ClientID = ClientID ;
Packet . m_pData = pMsg - > Data ( ) ;
Packet . m_DataSize = pMsg - > Size ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// HACK: modify the message id in the packet and store the system flag
* ( ( unsigned char * ) Packet . m_pData ) < < = 1 ;
if ( System )
* ( ( unsigned char * ) Packet . m_pData ) | = 1 ;
if ( Flags & MSGFLAG_VITAL )
Packet . m_Flags | = NETSENDFLAG_VITAL ;
if ( Flags & MSGFLAG_FLUSH )
Packet . m_Flags | = NETSENDFLAG_FLUSH ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// write message to demo recorder
2014-09-26 00:05:22 +00:00
if ( ! ( Flags & MSGFLAG_NORECORD ) )
{
if ( ClientID > - 1 )
m_aDemoRecorder [ ClientID ] . RecordMessage ( pMsg - > Data ( ) , pMsg - > Size ( ) ) ;
m_aDemoRecorder [ MAX_CLIENTS ] . RecordMessage ( pMsg - > Data ( ) , pMsg - > Size ( ) ) ;
}
2010-05-29 07:25:38 +00:00
if ( ! ( Flags & MSGFLAG_NOSEND ) )
{
if ( ClientID = = - 1 )
{
// broadcast
int i ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_aClients [ i ] . m_State = = CClient : : STATE_INGAME )
{
Packet . m_ClientID = i ;
m_NetServer . Send ( & Packet ) ;
}
}
else
m_NetServer . Send ( & Packet ) ;
}
return 0 ;
}
void CServer : : DoSnapshot ( )
{
GameServer ( ) - > OnPreSnap ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// create snapshot for demo recording
2014-09-26 00:05:22 +00:00
if ( m_aDemoRecorder [ MAX_CLIENTS ] . IsRecording ( ) )
2010-05-29 07:25:38 +00:00
{
char aData [ CSnapshot : : MAX_SIZE ] ;
int SnapshotSize ;
// build snap and possibly add some messages
m_SnapshotBuilder . Init ( ) ;
GameServer ( ) - > OnSnap ( - 1 ) ;
SnapshotSize = m_SnapshotBuilder . Finish ( aData ) ;
2011-04-13 18:37:12 +00:00
2014-12-02 01:32:07 +00:00
// for antiping: if the projectile netobjects contains extra data, this is removed and the original content restored before recording demo
unsigned char aExtraInfoRemoved [ CSnapshot : : MAX_SIZE ] ;
mem_copy ( aExtraInfoRemoved , aData , SnapshotSize ) ;
SnapshotRemoveExtraInfo ( aExtraInfoRemoved ) ;
2010-05-29 07:25:38 +00:00
// write snapshot
2014-12-02 01:32:07 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . RecordSnapshot ( Tick ( ) , aExtraInfoRemoved , SnapshotSize ) ;
2010-05-29 07:25:38 +00:00
}
// create snapshots for all clients
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
// client must be ingame to recive snapshots
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_INGAME )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// this client is trying to recover, don't spam snapshots
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_RECOVER & & ( Tick ( ) % 50 ) ! = 0 )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// this client is trying to recover, don't spam snapshots
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_INIT & & ( Tick ( ) % 10 ) ! = 0 )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
{
char aData [ CSnapshot : : MAX_SIZE ] ;
2010-06-09 16:24:38 +00:00
CSnapshot * pData = ( CSnapshot * ) aData ; // Fix compiler warning for strict-aliasing
2010-05-29 07:25:38 +00:00
char aDeltaData [ CSnapshot : : MAX_SIZE ] ;
char aCompData [ CSnapshot : : MAX_SIZE ] ;
int SnapshotSize ;
int Crc ;
static CSnapshot EmptySnap ;
CSnapshot * pDeltashot = & EmptySnap ;
int DeltashotSize ;
int DeltaTick = - 1 ;
int DeltaSize ;
m_SnapshotBuilder . Init ( ) ;
GameServer ( ) - > OnSnap ( i ) ;
// finish snapshot
2010-06-09 16:24:38 +00:00
SnapshotSize = m_SnapshotBuilder . Finish ( pData ) ;
2014-09-26 00:05:22 +00:00
if ( m_aDemoRecorder [ i ] . IsRecording ( ) )
2014-12-02 01:32:07 +00:00
{
// for antiping: if the projectile netobjects contains extra data, this is removed and the original content restored before recording demo
unsigned char aExtraInfoRemoved [ CSnapshot : : MAX_SIZE ] ;
mem_copy ( aExtraInfoRemoved , aData , SnapshotSize ) ;
SnapshotRemoveExtraInfo ( aExtraInfoRemoved ) ;
// write snapshot
m_aDemoRecorder [ i ] . RecordSnapshot ( Tick ( ) , aExtraInfoRemoved , SnapshotSize ) ;
}
2014-09-26 00:05:22 +00:00
2010-06-09 16:24:38 +00:00
Crc = pData - > Crc ( ) ;
2010-05-29 07:25:38 +00:00
// remove old snapshos
// keep 3 seconds worth of snapshots
m_aClients [ i ] . m_Snapshots . PurgeUntil ( m_CurrentGameTick - SERVER_TICK_SPEED * 3 ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// save it the snapshot
2010-06-09 16:24:38 +00:00
m_aClients [ i ] . m_Snapshots . Add ( m_CurrentGameTick , time_get ( ) , SnapshotSize , pData , 0 ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// find snapshot that we can preform delta against
EmptySnap . Clear ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
{
DeltashotSize = m_aClients [ i ] . m_Snapshots . Get ( m_aClients [ i ] . m_LastAckedSnapshot , 0 , & pDeltashot , 0 ) ;
if ( DeltashotSize > = 0 )
DeltaTick = m_aClients [ i ] . m_LastAckedSnapshot ;
else
{
// no acked package found, force client to recover rate
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_FULL )
m_aClients [ i ] . m_SnapRate = CClient : : SNAPRATE_RECOVER ;
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// create delta
2010-06-09 16:24:38 +00:00
DeltaSize = m_SnapshotDelta . CreateDelta ( pDeltashot , pData , aDeltaData ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( DeltaSize )
{
// compress it
int SnapshotSize ;
const int MaxSize = MAX_SNAPSHOT_PACKSIZE ;
int NumPackets ;
SnapshotSize = CVariableInt : : Compress ( aDeltaData , DeltaSize , aCompData ) ;
NumPackets = ( SnapshotSize + MaxSize - 1 ) / MaxSize ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int n = 0 , Left = SnapshotSize ; Left ; n + + )
{
int Chunk = Left < MaxSize ? Left : MaxSize ;
Left - = Chunk ;
if ( NumPackets = = 1 )
{
CMsgPacker Msg ( NETMSG_SNAPSINGLE ) ;
Msg . AddInt ( m_CurrentGameTick ) ;
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
Msg . AddInt ( Crc ) ;
Msg . AddInt ( Chunk ) ;
Msg . AddRaw ( & aCompData [ n * MaxSize ] , Chunk ) ;
SendMsgEx ( & Msg , MSGFLAG_FLUSH , i , true ) ;
}
else
{
CMsgPacker Msg ( NETMSG_SNAP ) ;
Msg . AddInt ( m_CurrentGameTick ) ;
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
Msg . AddInt ( NumPackets ) ;
2011-04-13 18:37:12 +00:00
Msg . AddInt ( n ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( Crc ) ;
Msg . AddInt ( Chunk ) ;
Msg . AddRaw ( & aCompData [ n * MaxSize ] , Chunk ) ;
SendMsgEx ( & Msg , MSGFLAG_FLUSH , i , true ) ;
}
}
}
else
{
CMsgPacker Msg ( NETMSG_SNAPEMPTY ) ;
Msg . AddInt ( m_CurrentGameTick ) ;
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
SendMsgEx ( & Msg , MSGFLAG_FLUSH , i , true ) ;
}
}
}
GameServer ( ) - > OnPostSnap ( ) ;
}
2015-08-23 15:51:28 +00:00
int CServer : : ClientRejoinCallback ( int ClientID , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
pThis - > SendMap ( ClientID ) ;
return 0 ;
}
2015-08-23 15:01:01 +00:00
int CServer : : NewClientNoAuthCallback ( int ClientID , bool Reset , void * pUser )
2015-08-13 08:58:47 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2015-08-23 15:01:01 +00:00
if ( Reset )
{
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
}
2015-08-13 08:58:47 +00:00
pThis - > SendMap ( ClientID ) ;
return 0 ;
}
2010-05-29 07:25:38 +00:00
2011-02-12 10:40:36 +00:00
int CServer : : NewClientCallback ( int ClientID , void * pUser )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_AUTH ;
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
2011-03-15 10:23:49 +00:00
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
2011-07-05 19:54:10 +00:00
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
2011-07-14 20:07:21 +00:00
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2013-08-04 16:09:28 +00:00
pThis - > m_aClients [ ClientID ] . m_Traffic = 0 ;
pThis - > m_aClients [ ClientID ] . m_TrafficSince = 0 ;
2013-12-31 05:13:57 +00:00
memset ( & pThis - > m_aClients [ ClientID ] . m_Addr , 0 , sizeof ( NETADDR ) ) ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
2010-05-29 07:25:38 +00:00
return 0 ;
}
2011-02-12 10:40:36 +00:00
int CServer : : DelClientCallback ( int ClientID , const char * pReason , void * pUser )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2011-04-13 18:37:12 +00:00
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( pThis - > m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-03-28 18:11:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " client dropped. cid=%d addr=%s reason='%s' " , ClientID , aAddrStr , pReason ) ;
2010-08-17 22:06:00 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
// notify the mod about the drop
2011-02-12 10:40:36 +00:00
if ( pThis - > m_aClients [ ClientID ] . m_State > = CClient : : STATE_READY )
2011-02-14 18:41:32 +00:00
pThis - > GameServer ( ) - > OnClientDrop ( ClientID , pReason ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_EMPTY ;
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
2011-03-15 10:23:49 +00:00
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
2011-07-05 19:54:10 +00:00
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
2011-08-13 00:11:06 +00:00
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2013-08-04 16:09:28 +00:00
pThis - > m_aClients [ ClientID ] . m_Traffic = 0 ;
pThis - > m_aClients [ ClientID ] . m_TrafficSince = 0 ;
2011-02-13 05:35:13 +00:00
pThis - > m_aPrevStates [ ClientID ] = CClient : : STATE_EMPTY ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_Snapshots . PurgeAll ( ) ;
2010-05-29 07:25:38 +00:00
return 0 ;
}
2012-04-13 23:30:18 +00:00
static int lastsent [ MAX_CLIENTS ] ;
static int lastask [ MAX_CLIENTS ] ;
2012-12-23 17:10:31 +00:00
static int lastasktick [ MAX_CLIENTS ] ;
2012-04-13 23:30:18 +00:00
2011-02-12 10:40:36 +00:00
void CServer : : SendMap ( int ClientID )
2010-05-29 07:25:38 +00:00
{
2012-04-13 23:30:18 +00:00
lastsent [ ClientID ] = 0 ;
lastask [ ClientID ] = 0 ;
2012-12-23 17:10:31 +00:00
lastasktick [ ClientID ] = Tick ( ) ;
2010-05-29 07:25:38 +00:00
CMsgPacker Msg ( NETMSG_MAP_CHANGE ) ;
2010-10-10 13:36:58 +00:00
Msg . AddString ( GetMapName ( ) , 0 ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( m_CurrentMapCrc ) ;
2011-02-16 11:07:54 +00:00
Msg . AddInt ( m_CurrentMapSize ) ;
2011-02-12 10:40:36 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID , true ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
void CServer : : SendConnectionReady ( int ClientID )
{
CMsgPacker Msg ( NETMSG_CON_READY ) ;
2011-02-12 10:40:36 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID , true ) ;
2010-05-29 07:25:38 +00:00
}
2011-02-12 10:40:36 +00:00
void CServer : : SendRconLine ( int ClientID , const char * pLine )
2010-05-29 07:25:38 +00:00
{
CMsgPacker Msg ( NETMSG_RCON_LINE ) ;
Msg . AddString ( pLine , 512 ) ;
2011-02-12 10:40:36 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
2010-05-29 07:25:38 +00:00
}
2014-12-20 15:35:47 +00:00
void CServer : : SendRconLineAuthed ( const char * pLine , void * pUser , bool Highlighted )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
static volatile int ReentryGuard = 0 ;
int i ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( ReentryGuard ) return ;
ReentryGuard + + ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2013-07-30 23:31:53 +00:00
if ( pThis - > m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY & & pThis - > m_aClients [ i ] . m_Authed > = pThis - > m_RconAuthLevel & & ( pThis - > m_RconRestrict = = - 1 | | pThis - > m_RconRestrict = = i ) )
2010-05-29 07:25:38 +00:00
pThis - > SendRconLine ( i , pLine ) ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
ReentryGuard - - ;
}
2011-07-14 20:07:21 +00:00
void CServer : : SendRconCmdAdd ( const IConsole : : CCommandInfo * pCommandInfo , int ClientID )
{
CMsgPacker Msg ( NETMSG_RCON_CMD_ADD ) ;
2011-07-30 16:19:15 +00:00
Msg . AddString ( pCommandInfo - > m_pName , IConsole : : TEMPCMD_NAME_LENGTH ) ;
Msg . AddString ( pCommandInfo - > m_pHelp , IConsole : : TEMPCMD_HELP_LENGTH ) ;
2015-12-28 15:14:52 +00:00
Msg . AddString ( pCommandInfo - > m_pParams , IConsole : : TEMPCMD_PARAMS_LENGTH ) ;
2011-07-14 20:07:21 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
}
void CServer : : SendRconCmdRem ( const IConsole : : CCommandInfo * pCommandInfo , int ClientID )
{
CMsgPacker Msg ( NETMSG_RCON_CMD_REM ) ;
Msg . AddString ( pCommandInfo - > m_pName , 256 ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
}
void CServer : : UpdateClientRconCommands ( )
{
int ClientID = Tick ( ) % MAX_CLIENTS ;
2011-08-11 08:59:14 +00:00
2011-07-14 20:07:21 +00:00
if ( m_aClients [ ClientID ] . m_State ! = CClient : : STATE_EMPTY & & m_aClients [ ClientID ] . m_Authed )
{
2015-10-23 00:33:10 +00:00
int ConsoleAccessLevel = m_aClients [ ClientID ] . m_Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : m_aClients [ ClientID ] . m_Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : IConsole : : ACCESS_LEVEL_HELPER ;
2011-07-14 20:07:21 +00:00
for ( int i = 0 ; i < MAX_RCONCMD_SEND & & m_aClients [ ClientID ] . m_pRconCmdToSend ; + + i )
{
SendRconCmdAdd ( m_aClients [ ClientID ] . m_pRconCmdToSend , ClientID ) ;
m_aClients [ ClientID ] . m_pRconCmdToSend = m_aClients [ ClientID ] . m_pRconCmdToSend - > NextCommandInfo ( ConsoleAccessLevel , CFGFLAG_SERVER ) ;
}
}
}
2010-05-29 07:25:38 +00:00
void CServer : : ProcessClientPacket ( CNetChunk * pPacket )
{
2011-02-12 10:40:36 +00:00
int ClientID = pPacket - > m_ClientID ;
2010-05-29 07:25:38 +00:00
CUnpacker Unpacker ;
Unpacker . Reset ( pPacket - > m_pData , pPacket - > m_DataSize ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// unpack msgid and system flag
int Msg = Unpacker . GetInt ( ) ;
int Sys = Msg & 1 ;
Msg > > = 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( Unpacker . Error ( ) )
return ;
2011-04-13 18:37:12 +00:00
2013-08-04 02:37:15 +00:00
if ( g_Config . m_SvNetlimit & & Msg ! = NETMSG_REQUEST_MAP_DATA )
2013-08-04 02:24:03 +00:00
{
2013-08-04 02:37:15 +00:00
int64 Now = time_get ( ) ;
2013-08-04 15:50:12 +00:00
int64 Diff = Now - m_aClients [ ClientID ] . m_TrafficSince ;
float Alpha = g_Config . m_SvNetlimitAlpha / 100.0 ;
float Limit = ( float ) g_Config . m_SvNetlimit * 1024 / time_freq ( ) ;
2013-08-04 02:37:15 +00:00
2013-08-04 15:50:12 +00:00
if ( m_aClients [ ClientID ] . m_Traffic > Limit )
2013-08-04 02:24:03 +00:00
{
2013-11-23 19:19:30 +00:00
m_NetServer . NetBan ( ) - > BanAddr ( & pPacket - > m_Address , 600 , " Stressing network " ) ;
2013-08-04 15:50:12 +00:00
return ;
2013-08-04 02:24:03 +00:00
}
2013-08-04 15:50:12 +00:00
if ( Diff > 100 )
2013-08-04 02:24:03 +00:00
{
2013-08-04 15:50:12 +00:00
m_aClients [ ClientID ] . m_Traffic = ( Alpha * ( ( float ) pPacket - > m_DataSize / Diff ) ) + ( 1.0 - Alpha ) * m_aClients [ ClientID ] . m_Traffic ;
m_aClients [ ClientID ] . m_TrafficSince = Now ;
2013-08-04 02:24:03 +00:00
}
}
2011-03-15 08:58:57 +00:00
if ( Sys )
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
// system message
if ( Msg = = NETMSG_INFO )
2010-05-29 07:25:38 +00:00
{
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_AUTH )
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
const char * pVersion = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pVersion ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2011-03-15 08:58:57 +00:00
if ( str_comp ( pVersion , GameServer ( ) - > NetVersion ( ) ) ! = 0 )
{
// wrong version
char aReason [ 256 ] ;
str_format ( aReason , sizeof ( aReason ) , " Wrong version. Server is running '%s' and client '%s' " , GameServer ( ) - > NetVersion ( ) , pVersion ) ;
m_NetServer . Drop ( ClientID , aReason ) ;
return ;
}
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
const char * pPassword = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pPassword ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2011-03-15 08:58:57 +00:00
if ( g_Config . m_Password [ 0 ] ! = 0 & & str_comp ( g_Config . m_Password , pPassword ) ! = 0 )
{
// wrong password
m_NetServer . Drop ( ClientID , " Wrong password " ) ;
return ;
}
2011-04-09 06:41:31 +00:00
// reserved slot
if ( ClientID > = ( g_Config . m_SvMaxClients - g_Config . m_SvReservedSlots ) & & g_Config . m_SvReservedSlotsPass [ 0 ] ! = 0 & & strcmp ( g_Config . m_SvReservedSlotsPass , pPassword ) ! = 0 )
{
m_NetServer . Drop ( ClientID , " This server is full " ) ;
return ;
}
2011-04-13 23:27:49 +00:00
2015-01-27 22:13:47 +00:00
m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
SendMap ( ClientID ) ;
2010-10-11 01:50:43 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else if ( Msg = = NETMSG_REQUEST_MAP_DATA )
2010-05-29 07:25:38 +00:00
{
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) = = 0 | | m_aClients [ ClientID ] . m_State < CClient : : STATE_CONNECTING )
return ;
2013-02-08 12:12:50 +00:00
2011-03-15 08:58:57 +00:00
int Chunk = Unpacker . GetInt ( ) ;
2014-11-22 12:17:55 +00:00
unsigned int ChunkSize = 1024 - 128 ;
unsigned int Offset = Chunk * ChunkSize ;
2011-03-15 08:58:57 +00:00
int Last = 0 ;
2011-04-13 18:37:12 +00:00
2012-04-13 23:30:18 +00:00
lastask [ ClientID ] = Chunk ;
2012-12-23 17:10:31 +00:00
lastasktick [ ClientID ] = Tick ( ) ;
2012-04-13 23:30:18 +00:00
if ( Chunk = = 0 )
{
lastsent [ ClientID ] = 0 ;
}
2011-03-15 08:58:57 +00:00
// drop faulty map data requests
2014-11-22 12:17:55 +00:00
if ( Chunk < 0 | | Offset > m_CurrentMapSize )
2011-03-15 08:58:57 +00:00
return ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( Offset + ChunkSize > = m_CurrentMapSize )
{
ChunkSize = m_CurrentMapSize - Offset ;
Last = 1 ;
}
2011-04-13 18:37:12 +00:00
2012-12-23 17:10:31 +00:00
if ( lastsent [ ClientID ] < Chunk + g_Config . m_SvMapWindow & & g_Config . m_SvFastDownload )
2012-04-13 23:30:18 +00:00
return ;
2011-03-15 08:58:57 +00:00
CMsgPacker Msg ( NETMSG_MAP_DATA ) ;
Msg . AddInt ( Last ) ;
Msg . AddInt ( m_CurrentMapCrc ) ;
Msg . AddInt ( Chunk ) ;
Msg . AddInt ( ChunkSize ) ;
Msg . AddRaw ( & m_pCurrentMapData [ Offset ] , ChunkSize ) ;
2015-09-17 07:55:09 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID , true ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( g_Config . m_Debug )
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " sending chunk %d with size %d " , Chunk , ChunkSize ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
2010-07-29 19:55:33 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_READY )
{
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_CONNECTING )
2010-05-29 07:25:38 +00:00
{
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
char aBuf [ 256 ] ;
2016-01-20 15:33:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " player is ready. ClientID=%d addr=%s secure=%s " , ClientID , aAddrStr , m_NetServer . HasSecurityToken ( ClientID ) ? " yes " : " no " ) ;
2011-03-15 08:58:57 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
m_aClients [ ClientID ] . m_State = CClient : : STATE_READY ;
GameServer ( ) - > OnClientConnected ( ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2015-08-23 15:01:01 +00:00
SendConnectionReady ( ClientID ) ;
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_ENTERGAME )
{
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_READY & & GameServer ( ) - > IsClientReady ( ClientID ) )
2010-05-29 07:25:38 +00:00
{
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
char aBuf [ 256 ] ;
2016-01-20 15:33:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " player has entered the game. ClientID=%d addr=%s " , ClientID , aAddrStr ) ;
2011-03-15 08:58:57 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
m_aClients [ ClientID ] . m_State = CClient : : STATE_INGAME ;
GameServer ( ) - > OnClientEnter ( ClientID ) ;
2010-09-06 02:59:02 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_INPUT )
{
CClient : : CInput * pInput ;
int64 TagTime ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_LastAckedSnapshot = Unpacker . GetInt ( ) ;
int IntendedTick = Unpacker . GetInt ( ) ;
int Size = Unpacker . GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
// check for errors
if ( Unpacker . Error ( ) | | Size / 4 > MAX_INPUT_SIZE )
return ;
2010-08-22 16:06:20 +00:00
2011-03-15 08:58:57 +00:00
if ( m_aClients [ ClientID ] . m_LastAckedSnapshot > 0 )
m_aClients [ ClientID ] . m_SnapRate = CClient : : SNAPRATE_FULL ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( m_aClients [ ClientID ] . m_Snapshots . Get ( m_aClients [ ClientID ] . m_LastAckedSnapshot , & TagTime , 0 , 0 ) > = 0 )
m_aClients [ ClientID ] . m_Latency = ( int ) ( ( ( time_get ( ) - TagTime ) * 1000 ) / time_freq ( ) ) ;
2010-08-22 16:06:20 +00:00
2011-03-15 08:58:57 +00:00
// add message to report the input timing
// skip packets that are old
if ( IntendedTick > m_aClients [ ClientID ] . m_LastInputTick )
{
int TimeLeft = ( ( TickStartTime ( IntendedTick ) - time_get ( ) ) * 1000 ) / time_freq ( ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
CMsgPacker Msg ( NETMSG_INPUTTIMING ) ;
Msg . AddInt ( IntendedTick ) ;
Msg . AddInt ( TimeLeft ) ;
SendMsgEx ( & Msg , 0 , ClientID , true ) ;
}
2010-09-06 02:59:02 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_LastInputTick = IntendedTick ;
2010-10-10 13:36:58 +00:00
2011-03-15 08:58:57 +00:00
pInput = & m_aClients [ ClientID ] . m_aInputs [ m_aClients [ ClientID ] . m_CurrentInput ] ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( IntendedTick < = Tick ( ) )
IntendedTick = Tick ( ) + 1 ;
2010-10-10 13:36:58 +00:00
2011-03-15 08:58:57 +00:00
pInput - > m_GameTick = IntendedTick ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
for ( int i = 0 ; i < Size / 4 ; i + + )
pInput - > m_aData [ i ] = Unpacker . GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
mem_copy ( m_aClients [ ClientID ] . m_LatestInput . m_aData , pInput - > m_aData , MAX_INPUT_SIZE * sizeof ( int ) ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_CurrentInput + + ;
m_aClients [ ClientID ] . m_CurrentInput % = 200 ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
// call the mod with the fresh input data
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
GameServer ( ) - > OnClientDirectInput ( ClientID , m_aClients [ ClientID ] . m_LatestInput . m_aData ) ;
}
else if ( Msg = = NETMSG_RCON_CMD )
{
const char * pCmd = Unpacker . GetString ( ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pCmd ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2013-12-31 05:13:57 +00:00
if ( Unpacker . Error ( ) = = 0 & & ! str_comp ( pCmd , " crashmeplx " ) )
{
2014-01-30 15:49:15 +00:00
CGameContext * GameServer = ( CGameContext * ) m_pGameServer ;
2014-01-30 16:28:30 +00:00
if ( GameServer - > m_apPlayers [ ClientID ] & & GameServer - > m_apPlayers [ ClientID ] - > m_ClientVersion < VERSION_DDNET_OLD )
2014-01-30 15:54:58 +00:00
GameServer - > m_apPlayers [ ClientID ] - > m_ClientVersion = VERSION_DDNET_OLD ;
2013-12-31 05:13:57 +00:00
} else
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & Unpacker . Error ( ) = = 0 & & m_aClients [ ClientID ] . m_Authed )
2010-05-29 07:25:38 +00:00
{
2014-08-22 11:54:13 +00:00
CGameContext * GameServer = ( CGameContext * ) m_pGameServer ;
2016-02-22 18:54:45 +00:00
if ( GameServer - > m_apPlayers [ ClientID ] )
2014-08-22 11:54:13 +00:00
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d rcon='%s' " , ClientID , pCmd ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
m_RconClientID = ClientID ;
m_RconAuthLevel = m_aClients [ ClientID ] . m_Authed ;
2015-10-23 00:33:10 +00:00
Console ( ) - > SetAccessLevel ( m_aClients [ ClientID ] . m_Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : m_aClients [ ClientID ] . m_Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : m_aClients [ ClientID ] . m_Authed = = AUTHED_HELPER ? IConsole : : ACCESS_LEVEL_HELPER : IConsole : : ACCESS_LEVEL_USER ) ;
2014-08-22 11:54:13 +00:00
Console ( ) - > ExecuteLineFlag ( pCmd , CFGFLAG_SERVER , ClientID ) ;
Console ( ) - > SetAccessLevel ( IConsole : : ACCESS_LEVEL_ADMIN ) ;
m_RconClientID = IServer : : RCON_CID_SERV ;
m_RconAuthLevel = AUTHED_ADMIN ;
}
2010-10-10 13:36:58 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_RCON_AUTH )
{
const char * pPw ;
Unpacker . GetString ( ) ; // login name, not used
pPw = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pPw ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2010-10-12 07:31:47 +00:00
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & Unpacker . Error ( ) = = 0 )
2011-03-15 08:58:57 +00:00
{
2015-10-26 23:33:26 +00:00
int AuthLevel = - 1 ;
2015-10-23 00:33:10 +00:00
if ( g_Config . m_SvRconPassword [ 0 ] = = 0 & & g_Config . m_SvRconModPassword [ 0 ] = = 0 & & g_Config . m_SvRconHelperPassword [ 0 ] = = 0 )
2010-10-10 13:36:58 +00:00
{
2011-07-05 19:54:10 +00:00
SendRconLine ( ClientID , " No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console. " ) ;
2010-05-29 07:25:38 +00:00
}
2011-07-07 22:00:38 +00:00
else if ( g_Config . m_SvRconPassword [ 0 ] & & str_comp ( pPw , g_Config . m_SvRconPassword ) = = 0 )
2015-10-26 23:33:26 +00:00
AuthLevel = AUTHED_ADMIN ;
2011-07-07 22:00:38 +00:00
else if ( g_Config . m_SvRconModPassword [ 0 ] & & str_comp ( pPw , g_Config . m_SvRconModPassword ) = = 0 )
2015-10-26 23:33:26 +00:00
AuthLevel = AUTHED_MOD ;
2015-10-23 00:33:10 +00:00
else if ( g_Config . m_SvRconHelperPassword [ 0 ] & & str_comp ( pPw , g_Config . m_SvRconHelperPassword ) = = 0 )
2015-10-26 23:33:26 +00:00
AuthLevel = AUTHED_HELPER ;
if ( AuthLevel ! = - 1 )
2011-07-05 19:54:10 +00:00
{
2015-10-26 23:33:26 +00:00
if ( m_aClients [ ClientID ] . m_Authed ! = AuthLevel )
2014-08-22 11:54:13 +00:00
{
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS ) ;
Msg . AddInt ( 1 ) ; //authed
Msg . AddInt ( 1 ) ; //cmdlist
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
2015-10-26 23:33:26 +00:00
m_aClients [ ClientID ] . m_Authed = AuthLevel ;
2014-08-22 11:54:13 +00:00
int SendRconCmds = Unpacker . GetInt ( ) ;
if ( Unpacker . Error ( ) = = 0 & & SendRconCmds )
2015-10-26 23:33:26 +00:00
// AUTHED_ADMIN - AuthLevel gets the proper IConsole::ACCESS_LEVEL_<x>
m_aClients [ ClientID ] . m_pRconCmdToSend = Console ( ) - > FirstCommandInfo ( AUTHED_ADMIN - AuthLevel , CFGFLAG_SERVER ) ;
2014-08-22 11:54:13 +00:00
char aBuf [ 256 ] ;
2015-10-26 23:33:26 +00:00
switch ( AuthLevel )
{
case AUTHED_ADMIN :
{
SendRconLine ( ClientID , " Admin authentication successful. Full remote console access granted. " ) ;
2015-10-27 01:00:15 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed (admin) " , ClientID ) ;
2015-10-26 23:33:26 +00:00
break ;
}
case AUTHED_MOD :
{
SendRconLine ( ClientID , " Moderator authentication successful. Limited remote console access granted. " ) ;
2015-10-27 01:00:15 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed (moderator) " , ClientID ) ;
2015-10-26 23:33:26 +00:00
break ;
}
case AUTHED_HELPER :
{
SendRconLine ( ClientID , " Helper authentication successful. Limited remote console access granted. " ) ;
2015-10-27 01:00:15 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed (helper) " , ClientID ) ;
2015-10-26 23:33:26 +00:00
break ;
}
}
2014-08-22 11:54:13 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
// DDRace
2015-10-27 01:00:15 +00:00
GameServer ( ) - > OnSetAuthed ( ClientID , AuthLevel ) ;
2014-08-22 11:54:13 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( g_Config . m_SvRconMaxTries )
{
m_aClients [ ClientID ] . m_AuthTries + + ;
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Wrong password %d/%d. " , m_aClients [ ClientID ] . m_AuthTries , g_Config . m_SvRconMaxTries ) ;
SendRconLine ( ClientID , aBuf ) ;
if ( m_aClients [ ClientID ] . m_AuthTries > = g_Config . m_SvRconMaxTries )
2010-10-11 01:50:43 +00:00
{
2011-03-15 08:58:57 +00:00
if ( ! g_Config . m_SvRconBantime )
m_NetServer . Drop ( ClientID , " Too many remote console authentication tries " ) ;
else
2011-12-29 22:36:53 +00:00
m_ServerBan . BanAddr ( m_NetServer . ClientAddr ( ClientID ) , g_Config . m_SvRconBantime * 60 , " Too many remote console authentication tries " ) ;
2010-10-11 01:50:43 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
SendRconLine ( ClientID , " Wrong password. " ) ;
2011-01-19 14:39:04 +00:00
}
2011-08-13 00:11:06 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else if ( Msg = = NETMSG_PING )
{
CMsgPacker Msg ( NETMSG_PING_REPLY ) ;
SendMsgEx ( & Msg , 0 , ClientID , true ) ;
2010-05-29 07:25:38 +00:00
}
else
{
2011-03-15 08:58:57 +00:00
if ( g_Config . m_Debug )
{
char aHex [ ] = " 0123456789ABCDEF " ;
char aBuf [ 512 ] ;
for ( int b = 0 ; b < pPacket - > m_DataSize & & b < 32 ; b + + )
{
aBuf [ b * 3 ] = aHex [ ( ( const unsigned char * ) pPacket - > m_pData ) [ b ] > > 4 ] ;
aBuf [ b * 3 + 1 ] = aHex [ ( ( const unsigned char * ) pPacket - > m_pData ) [ b ] & 0xf ] ;
aBuf [ b * 3 + 2 ] = ' ' ;
aBuf [ b * 3 + 3 ] = 0 ;
}
char aBufMsg [ 256 ] ;
str_format ( aBufMsg , sizeof ( aBufMsg ) , " strange message ClientID=%d msg=%d data_size=%d " , ClientID , Msg , pPacket - > m_DataSize ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBufMsg ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
}
2010-09-06 02:59:02 +00:00
}
2011-03-15 08:58:57 +00:00
else
{
// game message
2015-03-19 08:57:47 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State > = CClient : : STATE_READY )
2011-03-15 08:58:57 +00:00
GameServer ( ) - > OnMessage ( Msg , & Unpacker , ClientID ) ;
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2016-01-22 15:02:40 +00:00
void CServer : : SendServerInfoConnless ( const NETADDR * pAddr , int Token , bool Extended )
{
2016-01-22 15:42:54 +00:00
const int MaxRequests = g_Config . m_SvServerInfoPerSecond ;
2016-01-22 15:02:40 +00:00
int64 Now = Tick ( ) ;
if ( Now < = m_ServerInfoFirstRequest + TickSpeed ( ) )
{
m_ServerInfoNumRequests + + ;
}
else
{
2016-01-22 15:42:54 +00:00
m_ServerInfoHighLoad = m_ServerInfoNumRequests > MaxRequests ;
2016-01-22 15:02:40 +00:00
m_ServerInfoNumRequests = 1 ;
m_ServerInfoFirstRequest = Now ;
}
2016-01-22 15:42:54 +00:00
bool Short = m_ServerInfoNumRequests > MaxRequests | | m_ServerInfoHighLoad ;
2016-01-22 15:02:40 +00:00
SendServerInfo ( pAddr , Token , Extended , 0 , Short ) ;
}
void CServer : : SendServerInfo ( const NETADDR * pAddr , int Token , bool Extended , int Offset , bool Short )
2010-05-29 07:25:38 +00:00
{
CNetChunk Packet ;
CPacker p ;
char aBuf [ 128 ] ;
2016-01-22 15:02:40 +00:00
Packet . m_ClientID = - 1 ;
Packet . m_Address = * pAddr ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
2010-05-29 07:25:38 +00:00
// count the players
2011-03-20 14:33:49 +00:00
int PlayerCount = 0 , ClientCount = 0 ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2011-03-20 14:33:49 +00:00
{
if ( GameServer ( ) - > IsClientPlayer ( i ) )
PlayerCount + + ;
2011-04-13 18:37:12 +00:00
2011-03-20 14:33:49 +00:00
ClientCount + + ;
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
p . Reset ( ) ;
2014-01-01 13:58:39 +00:00
if ( Extended )
p . AddRaw ( SERVERBROWSE_INFO64 , sizeof ( SERVERBROWSE_INFO64 ) ) ;
else
p . AddRaw ( SERVERBROWSE_INFO , sizeof ( SERVERBROWSE_INFO ) ) ;
2011-03-04 17:14:08 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , Token ) ;
p . AddString ( aBuf , 6 ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
p . AddString ( GameServer ( ) - > Version ( ) , 32 ) ;
2013-12-31 05:13:57 +00:00
if ( Extended )
{
p . AddString ( g_Config . m_SvName , 256 ) ;
}
else
{
2014-01-01 22:36:53 +00:00
if ( m_NetServer . MaxClients ( ) < = VANILLA_MAX_CLIENTS )
2013-12-31 05:13:57 +00:00
p . AddString ( g_Config . m_SvName , 64 ) ;
else
{
2014-01-01 13:58:39 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s [%d/%d] " , g_Config . m_SvName , ClientCount , m_NetServer . MaxClients ( ) ) ;
2013-12-31 05:13:57 +00:00
p . AddString ( aBuf , 64 ) ;
}
}
2010-10-10 13:36:58 +00:00
p . AddString ( GetMapName ( ) , 32 ) ;
2010-05-29 07:25:38 +00:00
// gametype
2011-02-16 11:31:47 +00:00
p . AddString ( GameServer ( ) - > GameType ( ) , 16 ) ;
2010-05-29 07:25:38 +00:00
// flags
int i = 0 ;
2011-04-13 18:37:12 +00:00
if ( g_Config . m_Password [ 0 ] ) // password set
2010-05-29 07:25:38 +00:00
i | = SERVER_FLAG_PASSWORD ;
str_format ( aBuf , sizeof ( aBuf ) , " %d " , i ) ;
p . AddString ( aBuf , 2 ) ;
2013-12-31 05:13:57 +00:00
int MaxClients = m_NetServer . MaxClients ( ) ;
if ( ! Extended )
{
if ( ClientCount > = VANILLA_MAX_CLIENTS )
{
if ( ClientCount < MaxClients )
ClientCount = VANILLA_MAX_CLIENTS - 1 ;
else
ClientCount = VANILLA_MAX_CLIENTS ;
}
if ( MaxClients > VANILLA_MAX_CLIENTS ) MaxClients = VANILLA_MAX_CLIENTS ;
}
if ( PlayerCount > ClientCount )
PlayerCount = ClientCount ;
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , PlayerCount ) ; p . AddString ( aBuf , 3 ) ; // num players
2013-12-31 05:13:57 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , MaxClients - g_Config . m_SvSpectatorSlots ) ; p . AddString ( aBuf , 3 ) ; // max players
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , ClientCount ) ; p . AddString ( aBuf , 3 ) ; // num clients
2013-12-31 05:13:57 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , MaxClients ) ; p . AddString ( aBuf , 3 ) ; // max clients
if ( Extended )
p . AddInt ( Offset ) ;
2016-01-22 15:02:40 +00:00
if ( Short )
{
Packet . m_DataSize = p . Size ( ) ;
Packet . m_pData = p . Data ( ) ;
m_NetServer . Send ( & Packet ) ;
return ;
}
2013-12-31 05:13:57 +00:00
int ClientsPerPacket = Extended ? 24 : VANILLA_MAX_CLIENTS ;
int Skip = Offset ;
int Take = ClientsPerPacket ;
2010-05-29 07:25:38 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2014-01-09 20:08:50 +00:00
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2010-05-29 07:25:38 +00:00
{
2013-12-31 05:13:57 +00:00
if ( Skip - - > 0 )
continue ;
if ( - - Take < 0 )
break ;
2011-04-13 18:37:12 +00:00
p . AddString ( ClientName ( i ) , MAX_NAME_LENGTH ) ; // client name
p . AddString ( ClientClan ( i ) , MAX_CLAN_LENGTH ) ; // client clan
2013-12-31 05:13:57 +00:00
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d " , m_aClients [ i ] . m_Country ) ; p . AddString ( aBuf , 6 ) ; // client country
str_format ( aBuf , sizeof ( aBuf ) , " %d " , m_aClients [ i ] . m_Score ) ; p . AddString ( aBuf , 6 ) ; // client score
str_format ( aBuf , sizeof ( aBuf ) , " %d " , GameServer ( ) - > IsClientPlayer ( i ) ? 1 : 0 ) ; p . AddString ( aBuf , 2 ) ; // is player?
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
Packet . m_DataSize = p . Size ( ) ;
Packet . m_pData = p . Data ( ) ;
m_NetServer . Send ( & Packet ) ;
2013-12-31 05:13:57 +00:00
if ( Extended & & Take < 0 )
SendServerInfo ( pAddr , Token , Extended , Offset + ClientsPerPacket ) ;
2010-05-29 07:25:38 +00:00
}
void CServer : : UpdateServerInfo ( )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2014-01-14 19:40:29 +00:00
{
2014-02-03 14:21:13 +00:00
SendServerInfo ( m_NetServer . ClientAddr ( i ) , - 1 , true ) ;
SendServerInfo ( m_NetServer . ClientAddr ( i ) , - 1 , false ) ;
2014-01-14 19:40:29 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
void CServer : : PumpNetwork ( )
{
CNetChunk Packet ;
m_NetServer . Update ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// process packets
while ( m_NetServer . Recv ( & Packet ) )
{
if ( Packet . m_ClientID = = - 1 )
{
// stateless
if ( ! m_Register . RegisterProcessPacket ( & Packet ) )
{
2016-01-22 15:02:40 +00:00
bool ServerInfo = false ;
bool Extended = false ;
2010-05-29 07:25:38 +00:00
if ( Packet . m_DataSize = = sizeof ( SERVERBROWSE_GETINFO ) + 1 & &
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO , sizeof ( SERVERBROWSE_GETINFO ) ) = = 0 )
{
2016-01-22 15:02:40 +00:00
ServerInfo = true ;
Extended = false ;
2010-05-29 07:25:38 +00:00
}
2013-12-31 05:13:57 +00:00
else if ( Packet . m_DataSize = = sizeof ( SERVERBROWSE_GETINFO64 ) + 1 & &
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO64 , sizeof ( SERVERBROWSE_GETINFO64 ) ) = = 0 )
{
2016-01-22 15:02:40 +00:00
ServerInfo = true ;
Extended = true ;
}
if ( ServerInfo )
{
int Token = ( ( unsigned char * ) Packet . m_pData ) [ sizeof ( SERVERBROWSE_GETINFO ) ] ;
SendServerInfoConnless ( & Packet . m_Address , Token , Extended ) ;
2013-12-31 05:13:57 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
else
ProcessClientPacket ( & Packet ) ;
}
2012-11-14 18:34:23 +00:00
if ( g_Config . m_SvFastDownload )
2012-04-13 23:30:18 +00:00
{
2012-11-14 18:34:23 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2012-04-13 23:30:18 +00:00
{
2012-11-14 18:34:23 +00:00
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_CONNECTING )
continue ;
2012-12-23 17:10:31 +00:00
if ( lastasktick [ i ] < Tick ( ) - TickSpeed ( ) )
{
lastsent [ i ] = lastask [ i ] ;
lastasktick [ i ] = Tick ( ) ;
}
2012-11-14 18:34:23 +00:00
if ( lastask [ i ] < lastsent [ i ] - g_Config . m_SvMapWindow )
continue ;
2015-07-09 00:08:14 +00:00
2012-11-14 18:34:23 +00:00
int Chunk = lastsent [ i ] + + ;
2014-11-22 12:17:55 +00:00
unsigned int ChunkSize = 1024 - 128 ;
unsigned int Offset = Chunk * ChunkSize ;
2012-11-14 18:34:23 +00:00
int Last = 0 ;
2015-07-09 00:08:14 +00:00
2012-11-14 18:34:23 +00:00
// drop faulty map data requests
2014-11-22 12:17:55 +00:00
if ( Chunk < 0 | | Offset > m_CurrentMapSize )
2012-11-14 18:34:23 +00:00
continue ;
if ( Offset + ChunkSize > = m_CurrentMapSize )
{
ChunkSize = m_CurrentMapSize - Offset ;
Last = 1 ;
}
2015-07-09 00:08:14 +00:00
2012-11-14 18:34:23 +00:00
CMsgPacker Msg ( NETMSG_MAP_DATA ) ;
Msg . AddInt ( Last ) ;
Msg . AddInt ( m_CurrentMapCrc ) ;
Msg . AddInt ( Chunk ) ;
Msg . AddInt ( ChunkSize ) ;
Msg . AddRaw ( & m_pCurrentMapData [ Offset ] , ChunkSize ) ;
2016-04-27 17:54:43 +00:00
SendMsgEx ( & Msg , MSGFLAG_FLUSH , i , true ) ;
2015-07-09 00:08:14 +00:00
2012-11-14 18:34:23 +00:00
if ( g_Config . m_Debug )
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " sending chunk %d with size %d " , Chunk , ChunkSize ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
}
2012-04-13 23:30:18 +00:00
}
}
2011-12-29 22:36:53 +00:00
m_ServerBan . Update ( ) ;
2011-07-30 11:40:01 +00:00
m_Econ . Update ( ) ;
2010-05-29 07:25:38 +00:00
}
2010-10-10 13:36:58 +00:00
char * CServer : : GetMapName ( )
{
// get the name of the map without his path
char * pMapShortName = & g_Config . m_SvMap [ 0 ] ;
for ( int i = 0 ; i < str_length ( g_Config . m_SvMap ) - 1 ; i + + )
{
if ( g_Config . m_SvMap [ i ] = = ' / ' | | g_Config . m_SvMap [ i ] = = ' \\ ' )
pMapShortName = & g_Config . m_SvMap [ i + 1 ] ;
}
return pMapShortName ;
}
2010-05-29 07:25:38 +00:00
int CServer : : LoadMap ( const char * pMapName )
{
//DATAFILE *df;
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " maps/%s.map " , pMapName ) ;
2015-07-14 20:08:29 +00:00
GameServer ( ) - > OnMapChange ( aBuf , sizeof ( aBuf ) ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
/*df = datafile_load(buf);
if ( ! df )
return 0 ; */
2011-03-31 13:13:49 +00:00
// check for valid standard map
if ( ! m_MapChecker . ReadAndValidateMap ( Storage ( ) , aBuf , IStorage : : TYPE_ALL ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " mapchecker " , " invalid standard map " ) ;
return 0 ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( ! m_pMap - > Load ( aBuf ) )
return 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// stop recording when we change map
2014-09-26 00:05:22 +00:00
for ( int i = 0 ; i < MAX_CLIENTS + 1 ; i + + )
{
m_aDemoRecorder [ i ] . Stop ( ) ;
// remove tmp demos
if ( i < MAX_CLIENTS )
{
char aPath [ 256 ] ;
str_format ( aPath , sizeof ( aPath ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , g_Config . m_SvPort , i ) ;
Storage ( ) - > RemoveFile ( aPath , IStorage : : TYPE_SAVE ) ;
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// reinit snapshot ids
m_IDPool . TimeoutIDs ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// get the crc of the map
m_CurrentMapCrc = m_pMap - > Crc ( ) ;
2010-08-17 22:06:00 +00:00
char aBufMsg [ 256 ] ;
str_format ( aBufMsg , sizeof ( aBufMsg ) , " %s crc is %08x " , aBuf , m_CurrentMapCrc ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBufMsg ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
str_copy ( m_aCurrentMap , pMapName , sizeof ( m_aCurrentMap ) ) ;
//map_set(df);
2011-04-13 18:37:12 +00:00
2011-08-02 10:14:11 +00:00
// load complete map into memory for download
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
IOHANDLE File = Storage ( ) - > OpenFile ( aBuf , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
2014-11-23 20:24:20 +00:00
m_CurrentMapSize = ( unsigned int ) io_length ( File ) ;
2010-05-29 07:25:38 +00:00
if ( m_pCurrentMapData )
mem_free ( m_pCurrentMapData ) ;
m_pCurrentMapData = ( unsigned char * ) mem_alloc ( m_CurrentMapSize , 1 ) ;
io_read ( File , m_pCurrentMapData , m_CurrentMapSize ) ;
io_close ( File ) ;
}
2011-01-20 20:25:09 +00:00
2011-04-09 06:41:31 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2011-01-20 20:25:09 +00:00
m_aPrevStates [ i ] = m_aClients [ i ] . m_State ;
2010-05-29 07:25:38 +00:00
return 1 ;
}
2010-08-17 22:06:00 +00:00
void CServer : : InitRegister ( CNetServer * pNetServer , IEngineMasterServer * pMasterServer , IConsole * pConsole )
2010-05-29 07:25:38 +00:00
{
2010-08-17 22:06:00 +00:00
m_Register . Init ( pNetServer , pMasterServer , pConsole ) ;
2010-05-29 07:25:38 +00:00
}
int CServer : : Run ( )
{
//
2011-07-30 11:40:01 +00:00
m_PrintCBIndex = Console ( ) - > RegisterPrintCallback ( g_Config . m_ConsoleOutputLevel , SendRconLineAuthed , this ) ;
2010-05-29 07:25:38 +00:00
// load map
if ( ! LoadMap ( g_Config . m_SvMap ) )
{
dbg_msg ( " server " , " failed to load map. mapname='%s' " , g_Config . m_SvMap ) ;
return - 1 ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// start server
NETADDR BindAddr ;
2012-01-06 18:17:14 +00:00
if ( g_Config . m_Bindaddr [ 0 ] & & net_host_lookup ( g_Config . m_Bindaddr , & BindAddr , NETTYPE_ALL ) = = 0 )
2010-05-29 07:25:38 +00:00
{
// sweet!
2012-03-04 11:47:16 +00:00
BindAddr . type = NETTYPE_ALL ;
2010-05-29 07:25:38 +00:00
BindAddr . port = g_Config . m_SvPort ;
}
else
{
mem_zero ( & BindAddr , sizeof ( BindAddr ) ) ;
2011-03-28 18:11:28 +00:00
BindAddr . type = NETTYPE_ALL ;
2010-05-29 07:25:38 +00:00
BindAddr . port = g_Config . m_SvPort ;
}
2011-04-13 18:37:12 +00:00
2011-12-29 22:36:53 +00:00
if ( ! m_NetServer . Open ( BindAddr , & m_ServerBan , g_Config . m_SvMaxClients , g_Config . m_SvMaxClientsPerIP , 0 ) )
2010-05-29 07:25:38 +00:00
{
2012-01-28 22:54:04 +00:00
dbg_msg ( " server " , " couldn't open socket. port %d might already be in use " , g_Config . m_SvPort ) ;
2010-05-29 07:25:38 +00:00
return - 1 ;
}
2015-08-23 15:51:28 +00:00
m_NetServer . SetCallbacks ( NewClientCallback , NewClientNoAuthCallback , ClientRejoinCallback , DelClientCallback , this ) ;
2011-04-13 18:37:12 +00:00
2011-12-29 22:36:53 +00:00
m_Econ . Init ( Console ( ) , & m_ServerBan ) ;
2011-07-02 06:36:14 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " server name is '%s' " , g_Config . m_SvName ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
GameServer ( ) - > OnInit ( ) ;
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " version %s " , GameServer ( ) - > NetVersion ( ) ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
2010-08-07 18:22:25 +00:00
// process pending commands
2011-08-13 00:11:06 +00:00
m_pConsole - > StoreCommands ( false ) ;
2010-08-07 18:22:25 +00:00
2015-06-21 17:46:55 +00:00
if ( m_GeneratedRconPassword )
{
dbg_msg ( " server " , " +-------------------------+ " ) ;
dbg_msg ( " server " , " | rcon password: '%s' | " , g_Config . m_SvRconPassword ) ;
dbg_msg ( " server " , " +-------------------------+ " ) ;
}
2010-05-29 07:25:38 +00:00
// start game
{
2014-11-24 21:31:13 +00:00
bool NonActive = false ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_Lastheartbeat = 0 ;
m_GameStartTime = time_get ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( g_Config . m_Debug )
2010-08-17 22:06:00 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " baseline memory usage %dk " , mem_stats ( ) - > allocated / 1024 ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
while ( m_RunServer )
{
2014-11-24 21:31:13 +00:00
if ( NonActive )
PumpNetwork ( ) ;
2014-11-09 23:08:50 +00:00
set_new_tick ( ) ;
2014-11-24 21:31:13 +00:00
2010-05-29 07:25:38 +00:00
int64 t = time_get ( ) ;
int NewTicks = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// load new map TODO: don't poll this
2010-05-30 12:01:11 +00:00
if ( str_comp ( g_Config . m_SvMap , m_aCurrentMap ) ! = 0 | | m_MapReload )
2010-05-29 07:25:38 +00:00
{
2010-05-30 12:01:11 +00:00
m_MapReload = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// load map
if ( LoadMap ( g_Config . m_SvMap ) )
{
// new map loaded
GameServer ( ) - > OnShutdown ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int c = 0 ; c < MAX_CLIENTS ; c + + )
{
2010-06-26 15:59:59 +00:00
if ( m_aClients [ c ] . m_State < = CClient : : STATE_AUTH )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
SendMap ( c ) ;
m_aClients [ c ] . Reset ( ) ;
m_aClients [ c ] . m_State = CClient : : STATE_CONNECTING ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_GameStartTime = time_get ( ) ;
m_CurrentGameTick = 0 ;
2016-01-22 16:53:46 +00:00
m_ServerInfoFirstRequest = 0 ;
2010-05-29 07:25:38 +00:00
Kernel ( ) - > ReregisterInterface ( GameServer ( ) ) ;
GameServer ( ) - > OnInit ( ) ;
2010-06-07 11:34:47 +00:00
UpdateServerInfo ( ) ;
2010-05-29 07:25:38 +00:00
}
else
{
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " failed to load map. mapname='%s' " , g_Config . m_SvMap ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
str_copy ( g_Config . m_SvMap , m_aCurrentMap , sizeof ( g_Config . m_SvMap ) ) ;
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
while ( t > TickStartTime ( m_CurrentGameTick + 1 ) )
{
m_CurrentGameTick + + ;
NewTicks + + ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// apply new input
for ( int c = 0 ; c < MAX_CLIENTS ; c + + )
{
2014-01-15 15:52:22 +00:00
if ( m_aClients [ c ] . m_State ! = CClient : : STATE_INGAME )
2010-05-29 07:25:38 +00:00
continue ;
for ( int i = 0 ; i < 200 ; i + + )
{
if ( m_aClients [ c ] . m_aInputs [ i ] . m_GameTick = = Tick ( ) )
{
2014-01-15 15:52:22 +00:00
GameServer ( ) - > OnClientPredictedInput ( c , m_aClients [ c ] . m_aInputs [ i ] . m_aData ) ;
2010-05-29 07:25:38 +00:00
break ;
}
}
}
GameServer ( ) - > OnTick ( ) ;
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// snap game
if ( NewTicks )
{
if ( g_Config . m_SvHighBandwidth | | ( m_CurrentGameTick % 2 ) = = 0 )
DoSnapshot ( ) ;
2011-07-14 20:07:21 +00:00
UpdateClientRconCommands ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// master server stuff
2011-07-06 23:48:00 +00:00
m_Register . RegisterUpdate ( m_NetServer . NetType ( ) ) ;
2011-04-13 18:37:12 +00:00
2014-11-24 21:31:13 +00:00
if ( ! NonActive )
PumpNetwork ( ) ;
2011-04-13 18:37:12 +00:00
2014-11-24 21:31:13 +00:00
NonActive = true ;
2014-01-15 15:52:22 +00:00
for ( int c = 0 ; c < MAX_CLIENTS ; c + + )
if ( m_aClients [ c ] . m_State ! = CClient : : STATE_EMPTY )
NonActive = false ;
2014-01-14 23:02:19 +00:00
// wait for incoming data
2014-01-15 15:52:22 +00:00
if ( NonActive )
2014-08-15 12:32:21 +00:00
{
2015-10-22 15:51:02 +00:00
if ( g_Config . m_SvReloadWhenEmpty = = 1 )
{
2015-10-22 15:27:30 +00:00
m_MapReload = true ;
g_Config . m_SvReloadWhenEmpty = 0 ;
2015-10-22 15:51:02 +00:00
}
else if ( g_Config . m_SvReloadWhenEmpty = = 2 & & ! m_ReloadedWhenEmpty )
{
2015-10-22 15:27:30 +00:00
m_MapReload = true ;
m_ReloadedWhenEmpty = true ;
}
2014-08-15 12:32:21 +00:00
if ( g_Config . m_SvShutdownWhenEmpty )
m_RunServer = false ;
else
2014-12-26 11:12:28 +00:00
net_socket_read_wait ( m_NetServer . Socket ( ) , 1000000 ) ;
2014-08-15 12:32:21 +00:00
}
2014-01-15 15:52:22 +00:00
else
2014-11-11 12:00:02 +00:00
{
2015-10-22 15:27:30 +00:00
m_ReloadedWhenEmpty = false ;
2014-11-11 12:00:02 +00:00
set_new_tick ( ) ;
int64 t = time_get ( ) ;
2014-11-15 17:14:20 +00:00
int x = ( TickStartTime ( m_CurrentGameTick + 1 ) - t ) * 1000000 / time_freq ( ) + 1 ;
2014-11-11 12:00:02 +00:00
if ( x > 0 )
2014-11-15 17:14:20 +00:00
{
2014-11-11 12:00:02 +00:00
net_socket_read_wait ( m_NetServer . Socket ( ) , x ) ;
2014-11-15 17:14:20 +00:00
}
2014-11-11 12:00:02 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
// disconnect all clients on shutdown
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2010-10-09 18:19:58 +00:00
m_NetServer . Drop ( i , " Server shutdown " ) ;
2011-07-31 00:20:46 +00:00
m_Econ . Shutdown ( ) ;
2010-05-29 07:25:38 +00:00
}
GameServer ( ) - > OnShutdown ( ) ;
m_pMap - > Unload ( ) ;
if ( m_pCurrentMapData )
mem_free ( m_pCurrentMapData ) ;
return 0 ;
}
2013-07-22 22:15:50 +00:00
void CServer : : ConTestingCommands ( CConsole : : IResult * pResult , void * pUser )
{
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Value: %d " , g_Config . m_SvTestingCommands ) ;
2014-09-06 21:22:35 +00:00
( ( CConsole * ) pUser ) - > Print ( CConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
2013-07-22 22:15:50 +00:00
}
2015-06-30 16:46:36 +00:00
void CServer : : ConRescue ( CConsole : : IResult * pResult , void * pUser )
2015-04-17 09:24:28 +00:00
{
char aBuf [ 128 ] ;
2015-06-30 16:46:36 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Value: %d " , g_Config . m_SvRescue ) ;
2015-04-17 09:24:28 +00:00
( ( CConsole * ) pUser ) - > Print ( CConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
}
2011-08-13 00:11:06 +00:00
void CServer : : ConKick ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
2011-08-13 00:11:06 +00:00
if ( pResult - > NumArguments ( ) > 1 )
2010-10-09 18:19:58 +00:00
{
char aBuf [ 128 ] ;
2011-08-13 00:11:06 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Kicked (%s) " , pResult - > GetString ( 1 ) ) ;
( ( CServer * ) pUser ) - > Kick ( pResult - > GetInteger ( 0 ) , aBuf ) ;
2010-10-09 18:19:58 +00:00
}
else
2011-08-13 00:11:06 +00:00
( ( CServer * ) pUser ) - > Kick ( pResult - > GetInteger ( 0 ) , " Kicked by console " ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConStatus ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
char aBuf [ 1024 ] ;
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
CServer * pThis = static_cast < CServer * > ( pUser ) ;
2010-05-29 07:25:38 +00:00
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2010-05-29 07:25:38 +00:00
{
2011-12-29 22:36:53 +00:00
if ( pThis - > m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2010-05-29 07:25:38 +00:00
{
2011-12-29 22:36:53 +00:00
net_addr_str ( pThis - > m_NetServer . ClientAddr ( i ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
if ( pThis - > m_aClients [ i ] . m_State = = CClient : : STATE_INGAME )
2012-07-29 10:17:16 +00:00
{
const char * pAuthStr = pThis - > m_aClients [ i ] . m_Authed = = CServer : : AUTHED_ADMIN ? " (Admin) " :
2015-10-23 00:33:10 +00:00
pThis - > m_aClients [ i ] . m_Authed = = CServer : : AUTHED_MOD ? " (Mod) " :
pThis - > m_aClients [ i ] . m_Authed = = CServer : : AUTHED_HELPER ? " (Helper) " : " " ;
2015-08-14 14:46:01 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=%s name='%s' score=%d client=%d secure=%s %s " , i , aAddrStr ,
pThis - > m_aClients [ i ] . m_aName , pThis - > m_aClients [ i ] . m_Score , ( ( CGameContext * ) ( pThis - > GameServer ( ) ) ) - > m_apPlayers [ i ] - > m_ClientVersion , pThis - > m_NetServer . HasSecurityToken ( i ) ? " yes " : " no " , pAuthStr ) ;
2012-07-29 10:17:16 +00:00
}
2010-06-03 12:48:32 +00:00
else
2011-03-28 18:11:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=%s connecting " , i , aAddrStr ) ;
2011-12-29 22:36:53 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " Server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
}
2011-08-13 00:11:06 +00:00
void CServer : : ConShutdown ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
( ( CServer * ) pUser ) - > m_RunServer = 0 ;
}
2011-07-22 21:17:16 +00:00
void CServer : : DemoRecorder_HandleAutoStart ( )
{
if ( g_Config . m_SvAutoDemoRecord )
{
2014-09-26 00:05:22 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . Stop ( ) ;
2011-07-22 21:17:16 +00:00
char aFilename [ 128 ] ;
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%s.demo " , " auto/autorecord " , aDate ) ;
2014-09-26 00:05:22 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . Start ( Storage ( ) , m_pConsole , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " server " ) ;
2011-07-22 21:17:16 +00:00
if ( g_Config . m_SvAutoDemoMax )
{
// clean up auto recorded demos
CFileCollection AutoDemos ;
AutoDemos . Init ( Storage ( ) , " demos/server " , " autorecord " , " .demo " , g_Config . m_SvAutoDemoMax ) ;
}
}
}
2012-01-08 23:49:20 +00:00
bool CServer : : DemoRecorder_IsRecording ( )
{
2014-09-26 00:05:22 +00:00
return m_aDemoRecorder [ MAX_CLIENTS ] . IsRecording ( ) ;
}
void CServer : : SaveDemo ( int ClientID , float Time )
{
if ( IsRecording ( ClientID ) )
{
2014-12-02 14:44:54 +00:00
m_aDemoRecorder [ ClientID ] . Stop ( true ) ;
2014-09-26 00:05:22 +00:00
// rename the demo
char aOldFilename [ 256 ] ;
char aNewFilename [ 256 ] ;
str_format ( aOldFilename , sizeof ( aOldFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , g_Config . m_SvPort , ClientID ) ;
str_format ( aNewFilename , sizeof ( aNewFilename ) , " demos/%s_%s_%5.2f.demo " , m_aCurrentMap , m_aClients [ ClientID ] . m_aName , Time ) ;
Storage ( ) - > RenameFile ( aOldFilename , aNewFilename , IStorage : : TYPE_SAVE ) ;
}
}
void CServer : : StartRecord ( int ClientID )
{
if ( g_Config . m_SvPlayerDemoRecord )
{
char aFilename [ 128 ] ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , g_Config . m_SvPort , ClientID ) ;
2014-12-02 14:44:54 +00:00
m_aDemoRecorder [ ClientID ] . Start ( Storage ( ) , Console ( ) , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " client " , m_CurrentMapSize , m_pCurrentMapData ) ;
2014-09-26 00:05:22 +00:00
}
}
void CServer : : StopRecord ( int ClientID )
{
if ( IsRecording ( ClientID ) )
{
m_aDemoRecorder [ ClientID ] . Stop ( ) ;
char aFilename [ 128 ] ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , g_Config . m_SvPort , ClientID ) ;
Storage ( ) - > RemoveFile ( aFilename , IStorage : : TYPE_SAVE ) ;
}
}
bool CServer : : IsRecording ( int ClientID )
{
return m_aDemoRecorder [ ClientID ] . IsRecording ( ) ;
2012-01-08 23:49:20 +00:00
}
2010-05-29 07:25:38 +00:00
void CServer : : ConRecord ( IConsole : : IResult * pResult , void * pUser )
{
2010-12-07 23:42:32 +00:00
CServer * pServer = ( CServer * ) pUser ;
char aFilename [ 128 ] ;
if ( pResult - > NumArguments ( ) )
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s.demo " , pResult - > GetString ( 0 ) ) ;
else
{
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/demo_%s.demo " , aDate ) ;
}
2014-09-26 00:05:22 +00:00
pServer - > m_aDemoRecorder [ MAX_CLIENTS ] . Start ( pServer - > Storage ( ) , pServer - > Console ( ) , aFilename , pServer - > GameServer ( ) - > NetVersion ( ) , pServer - > m_aCurrentMap , pServer - > m_CurrentMapCrc , " server " ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConStopRecord ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
2014-09-26 00:05:22 +00:00
( ( CServer * ) pUser ) - > m_aDemoRecorder [ MAX_CLIENTS ] . Stop ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConMapReload ( IConsole : : IResult * pResult , void * pUser )
2010-05-30 12:01:11 +00:00
{
( ( CServer * ) pUser ) - > m_MapReload = 1 ;
}
2011-12-26 21:07:57 +00:00
void CServer : : ConLogout ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pServer = ( CServer * ) pUser ;
2011-12-29 23:07:17 +00:00
if ( pServer - > m_RconClientID > = 0 & & pServer - > m_RconClientID < MAX_CLIENTS & &
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_State ! = CServer : : CClient : : STATE_EMPTY )
{
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS ) ;
Msg . AddInt ( 0 ) ; //authed
Msg . AddInt ( 0 ) ; //cmdlist
pServer - > SendMsgEx ( & Msg , MSGFLAG_VITAL , pServer - > m_RconClientID , true ) ;
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_Authed = AUTHED_NO ;
2012-03-04 11:47:02 +00:00
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_AuthTries = 0 ;
2011-12-29 23:07:17 +00:00
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_pRconCmdToSend = 0 ;
pServer - > SendRconLine ( pServer - > m_RconClientID , " Logout successful. " ) ;
char aBuf [ 32 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d logged out " , pServer - > m_RconClientID ) ;
pServer - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
2011-12-26 21:07:57 +00:00
}
2010-05-29 07:25:38 +00:00
void CServer : : ConchainSpecialInfoupdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2010-05-29 07:25:38 +00:00
if ( pResult - > NumArguments ( ) )
( ( CServer * ) pUserData ) - > UpdateServerInfo ( ) ;
}
2010-06-03 12:48:32 +00:00
void CServer : : ConchainMaxclientsperipUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2010-06-03 12:48:32 +00:00
if ( pResult - > NumArguments ( ) )
( ( CServer * ) pUserData ) - > m_NetServer . SetMaxClientsPerIP ( pResult - > GetInteger ( 0 ) ) ;
}
2015-10-23 00:33:10 +00:00
void CServer : : ConchainCommandAccessUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2011-07-14 20:07:21 +00:00
{
if ( pResult - > NumArguments ( ) = = 2 )
{
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
const IConsole : : CCommandInfo * pInfo = pThis - > Console ( ) - > GetCommandInfo ( pResult - > GetString ( 0 ) , CFGFLAG_SERVER , false ) ;
2011-08-01 10:11:10 +00:00
int OldAccessLevel = 0 ;
2011-07-14 20:07:21 +00:00
if ( pInfo )
OldAccessLevel = pInfo - > GetAccessLevel ( ) ;
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pInfo & & OldAccessLevel ! = pInfo - > GetAccessLevel ( ) )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
2015-10-23 00:33:10 +00:00
if ( pThis - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY | |
( pInfo - > GetAccessLevel ( ) > AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed & & AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed < OldAccessLevel ) | |
( pInfo - > GetAccessLevel ( ) < AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed & & AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed > OldAccessLevel ) | |
( pThis - > m_aClients [ i ] . m_pRconCmdToSend & & str_comp ( pResult - > GetString ( 0 ) , pThis - > m_aClients [ i ] . m_pRconCmdToSend - > m_pName ) > = 0 ) )
2011-07-14 20:07:21 +00:00
continue ;
2015-10-23 00:33:10 +00:00
if ( OldAccessLevel < pInfo - > GetAccessLevel ( ) )
2011-07-14 20:07:21 +00:00
pThis - > SendRconCmdAdd ( pInfo , i ) ;
else
pThis - > SendRconCmdRem ( pInfo , i ) ;
}
}
}
else
pfnCallback ( pResult , pCallbackUserData ) ;
}
2011-07-30 11:40:01 +00:00
void CServer : : ConchainConsoleOutputLevelUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > Console ( ) - > SetPrintOutputLevel ( pThis - > m_PrintCBIndex , pResult - > GetInteger ( 0 ) ) ;
}
}
2015-10-26 23:33:26 +00:00
void CServer : : LogoutByAuthLevel ( int AuthLevel ) // AUTHED_<x>
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( m_aClients [ i ] . m_Authed = = AuthLevel )
{
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS ) ;
Msg . AddInt ( 0 ) ; //authed
Msg . AddInt ( 0 ) ; //cmdlist
SendMsgEx ( & Msg , MSGFLAG_VITAL , i , true ) ;
m_aClients [ i ] . m_Authed = AUTHED_NO ;
m_aClients [ i ] . m_AuthTries = 0 ;
m_aClients [ i ] . m_pRconCmdToSend = 0 ;
SendRconLine ( i , " Logged out by password change. " ) ;
char aBuf [ 64 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d logged out by password change " , i ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
}
}
2014-09-16 19:14:31 +00:00
void CServer : : ConchainRconPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pServer = ( CServer * ) pUserData ;
2015-10-26 23:33:26 +00:00
pServer - > LogoutByAuthLevel ( AUTHED_ADMIN ) ;
2014-09-16 19:14:31 +00:00
}
}
void CServer : : ConchainRconModPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pServer = ( CServer * ) pUserData ;
2015-10-26 23:33:26 +00:00
pServer - > LogoutByAuthLevel ( AUTHED_MOD ) ;
2014-09-16 19:14:31 +00:00
}
}
2015-10-23 00:33:10 +00:00
void CServer : : ConchainRconHelperPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pServer = ( CServer * ) pUserData ;
2015-10-26 23:33:26 +00:00
pServer - > LogoutByAuthLevel ( AUTHED_HELPER ) ;
2014-09-16 19:14:31 +00:00
}
}
2010-05-29 07:25:38 +00:00
void CServer : : RegisterCommands ( )
{
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
2012-03-04 11:47:09 +00:00
m_pGameServer = Kernel ( ) - > RequestInterface < IGameServer > ( ) ;
m_pMap = Kernel ( ) - > RequestInterface < IEngineMap > ( ) ;
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2011-04-13 18:37:12 +00:00
2012-03-04 11:47:09 +00:00
// register console commands
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " kick " , " i[id] ?r[reason] " , CFGFLAG_SERVER , ConKick , this , " Kick player with specified id for any reason " ) ;
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " status " , " " , CFGFLAG_SERVER , ConStatus , this , " List players " ) ;
Console ( ) - > Register ( " shutdown " , " " , CFGFLAG_SERVER , ConShutdown , this , " Shut down " ) ;
2011-12-29 23:07:17 +00:00
Console ( ) - > Register ( " logout " , " " , CFGFLAG_SERVER , ConLogout , this , " Logout of rcon " ) ;
2010-05-29 07:25:38 +00:00
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " record " , " ?s[file] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConRecord , this , " Record to a file " ) ;
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " stoprecord " , " " , CFGFLAG_SERVER , ConStopRecord , this , " Stop recording " ) ;
2011-04-13 18:37:12 +00:00
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " reload " , " " , CFGFLAG_SERVER , ConMapReload , this , " Reload the map " ) ;
2011-08-13 00:11:06 +00:00
2010-05-29 07:25:38 +00:00
Console ( ) - > Chain ( " sv_name " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " password " , ConchainSpecialInfoupdate , this ) ;
2010-06-03 12:48:32 +00:00
Console ( ) - > Chain ( " sv_max_clients_per_ip " , ConchainMaxclientsperipUpdate , this ) ;
2015-10-23 00:33:10 +00:00
Console ( ) - > Chain ( " access_level " , ConchainCommandAccessUpdate , this ) ;
2011-07-30 11:40:01 +00:00
Console ( ) - > Chain ( " console_output_level " , ConchainConsoleOutputLevelUpdate , this ) ;
2015-07-09 00:08:14 +00:00
2014-09-16 19:14:31 +00:00
Console ( ) - > Chain ( " sv_rcon_password " , ConchainRconPasswordChange , this ) ;
Console ( ) - > Chain ( " sv_rcon_mod_password " , ConchainRconModPasswordChange , this ) ;
2015-10-23 00:33:10 +00:00
Console ( ) - > Chain ( " sv_rcon_helper_password " , ConchainRconHelperPasswordChange , this ) ;
2012-03-04 11:47:09 +00:00
// register console commands in sub parts
2012-08-16 22:03:53 +00:00
m_ServerBan . InitServerBan ( Console ( ) , Storage ( ) , this ) ;
2012-03-04 11:47:09 +00:00
m_pGameServer - > OnConsoleInit ( ) ;
2011-04-13 18:37:12 +00:00
}
2010-05-29 07:25:38 +00:00
int CServer : : SnapNewID ( )
{
return m_IDPool . NewID ( ) ;
}
void CServer : : SnapFreeID ( int ID )
{
m_IDPool . FreeID ( ID ) ;
}
2011-02-12 10:40:36 +00:00
void * CServer : : SnapNewItem ( int Type , int ID , int Size )
2010-05-29 07:25:38 +00:00
{
dbg_assert ( Type > = 0 & & Type < = 0xffff , " incorrect type " ) ;
2011-02-12 10:40:36 +00:00
dbg_assert ( ID > = 0 & & ID < = 0xffff , " incorrect id " ) ;
2011-04-13 18:37:12 +00:00
return ID < 0 ? 0 : m_SnapshotBuilder . NewItem ( Type , ID , Size ) ;
2010-05-29 07:25:38 +00:00
}
void CServer : : SnapSetStaticsize ( int ItemType , int Size )
{
m_SnapshotDelta . SetStaticsize ( ItemType , Size ) ;
}
static CServer * CreateServer ( ) { return new CServer ( ) ; }
int main ( int argc , const char * * argv ) // ignore_convention
{
2014-12-06 18:45:52 +00:00
# if !defined(CONF_PLATFORM_MACOSX) && !defined(FUZZING)
2014-09-09 21:02:05 +00:00
dbg_enable_threaded ( ) ;
2014-09-11 19:38:23 +00:00
# endif
2010-05-29 07:25:38 +00:00
# if defined(CONF_FAMILY_WINDOWS)
for ( int i = 1 ; i < argc ; i + + ) // ignore_convention
{
if ( str_comp ( " -s " , argv [ i ] ) = = 0 | | str_comp ( " --silent " , argv [ i ] ) = = 0 ) // ignore_convention
{
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
break ;
}
}
# endif
2010-11-17 23:32:54 +00:00
2015-06-21 17:46:55 +00:00
if ( secure_random_init ( ) ! = 0 )
{
dbg_msg ( " secure " , " could not initialize secure RNG " ) ;
return - 1 ;
}
2010-05-29 07:25:38 +00:00
CServer * pServer = CreateServer ( ) ;
IKernel * pKernel = IKernel : : Create ( ) ;
// create the components
2011-02-27 14:03:57 +00:00
IEngine * pEngine = CreateEngine ( " Teeworlds " ) ;
2010-05-29 07:25:38 +00:00
IEngineMap * pEngineMap = CreateEngineMap ( ) ;
IGameServer * pGameServer = CreateGameServer ( ) ;
2011-12-30 18:12:31 +00:00
IConsole * pConsole = CreateConsole ( CFGFLAG_SERVER | CFGFLAG_ECON ) ;
2010-05-29 07:25:38 +00:00
IEngineMasterServer * pEngineMasterServer = CreateEngineMasterServer ( ) ;
2012-01-09 00:38:45 +00:00
IStorage * pStorage = CreateStorage ( " Teeworlds " , IStorage : : STORAGETYPE_SERVER , argc , argv ) ; // ignore_convention
2010-05-29 07:25:38 +00:00
IConfig * pConfig = CreateConfig ( ) ;
2011-04-13 18:37:12 +00:00
2010-08-17 22:06:00 +00:00
pServer - > InitRegister ( & pServer - > m_NetServer , pEngineMasterServer , pConsole ) ;
2010-05-29 07:25:38 +00:00
{
bool RegisterFail = false ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pServer ) ; // register as both
2011-02-27 14:03:57 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngine ) ;
2010-05-29 07:25:38 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineMap * > ( pEngineMap ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMap * > ( pEngineMap ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pGameServer ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConsole ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pStorage ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConfig ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineMasterServer * > ( pEngineMasterServer ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMasterServer * > ( pEngineMasterServer ) ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( RegisterFail )
return - 1 ;
}
2011-04-13 18:37:12 +00:00
2011-03-05 10:46:24 +00:00
pEngine - > Init ( ) ;
2010-05-29 07:25:38 +00:00
pConfig - > Init ( ) ;
2011-02-27 14:03:57 +00:00
pEngineMasterServer - > Init ( ) ;
2010-05-29 07:25:38 +00:00
pEngineMasterServer - > Load ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// register all console commands
pServer - > RegisterCommands ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// execute autoexec file
2015-08-12 11:49:16 +00:00
IOHANDLE file = pStorage - > OpenFile ( AUTOEXEC_SERVER_FILE , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
if ( file )
{
io_close ( file ) ;
pConsole - > ExecuteFile ( AUTOEXEC_SERVER_FILE ) ;
}
else // fallback
{
pConsole - > ExecuteFile ( AUTOEXEC_FILE ) ;
}
2010-05-29 07:25:38 +00:00
// parse the command line arguments
if ( argc > 1 ) // ignore_convention
pConsole - > ParseArguments ( argc - 1 , & argv [ 1 ] ) ; // ignore_convention
2010-08-10 22:31:42 +00:00
2015-04-17 09:24:28 +00:00
pConsole - > Register ( " sv_test_cmds " , " " , CFGFLAG_SERVER , CServer : : ConTestingCommands , pConsole , " Turns testing commands aka cheats on/off " ) ;
2015-08-10 11:34:56 +00:00
pConsole - > Register ( " sv_rescue " , " " , CFGFLAG_SERVER , CServer : : ConRescue , pConsole , " Allow /rescue command so players can teleport themselves out of freeze " ) ;
2013-07-22 22:15:50 +00:00
2011-02-27 14:03:57 +00:00
pEngine - > InitLogfile ( ) ;
2010-08-22 16:06:20 +00:00
2013-08-06 04:44:53 +00:00
# if defined(CONF_FAMILY_UNIX)
2014-08-29 17:42:34 +00:00
FifoConsole * fifoConsole = new FifoConsole ( pConsole , g_Config . m_SvInputFifo , CFGFLAG_SERVER ) ;
2013-08-06 04:44:53 +00:00
# endif
2015-06-21 17:46:55 +00:00
pServer - > InitRconPasswordIfEmpty ( ) ;
2013-07-29 19:03:59 +00:00
2010-05-29 07:25:38 +00:00
// run the server
2011-02-27 14:03:57 +00:00
dbg_msg ( " server " , " starting... " ) ;
2010-05-29 07:25:38 +00:00
pServer - > Run ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// free
2013-08-06 04:44:53 +00:00
# if defined(CONF_FAMILY_UNIX)
2013-07-29 19:03:59 +00:00
delete fifoConsole ;
2013-08-06 04:44:53 +00:00
# endif
2010-05-29 07:25:38 +00:00
delete pServer ;
delete pKernel ;
delete pEngineMap ;
delete pGameServer ;
delete pConsole ;
delete pEngineMasterServer ;
delete pStorage ;
delete pConfig ;
return 0 ;
}
2011-04-09 06:41:31 +00:00
// DDRace
void CServer : : GetClientAddr ( int ClientID , NETADDR * pAddr )
{
2011-12-31 22:00:00 +00:00
if ( ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME ) {
2012-02-02 23:16:22 +00:00
* pAddr = * m_NetServer . ClientAddr ( ClientID ) ;
2011-12-31 22:00:00 +00:00
}
2011-04-09 06:41:31 +00:00
}
2011-03-16 14:27:30 +00:00
char * CServer : : GetAnnouncementLine ( char const * pFileName )
2010-11-22 10:59:25 +00:00
{
2011-03-16 14:27:30 +00:00
IOHANDLE File = m_pStorage - > OpenFile ( pFileName , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
2010-11-22 10:59:25 +00:00
if ( File )
{
std : : vector < char * > v ;
char * pLine ;
CLineReader * lr = new CLineReader ( ) ;
lr - > Init ( File ) ;
2010-12-07 17:44:23 +00:00
while ( ( pLine = lr - > Get ( ) ) )
2010-11-22 10:59:25 +00:00
if ( str_length ( pLine ) )
2010-12-05 22:38:29 +00:00
if ( pLine [ 0 ] ! = ' # ' )
2010-11-29 04:21:04 +00:00
v . push_back ( pLine ) ;
2010-12-06 02:27:35 +00:00
if ( v . size ( ) = = 1 )
{
m_AnnouncementLastLine = 0 ;
}
else if ( ! g_Config . m_SvAnnouncementRandom )
{
if ( m_AnnouncementLastLine > = v . size ( ) )
m_AnnouncementLastLine % = v . size ( ) ;
}
else
{
2010-12-07 17:44:23 +00:00
unsigned Rand ;
2010-12-06 02:27:35 +00:00
do
Rand = rand ( ) % v . size ( ) ;
while ( Rand = = m_AnnouncementLastLine ) ;
2011-04-09 06:41:31 +00:00
2010-12-06 02:27:35 +00:00
m_AnnouncementLastLine = Rand ;
}
return v [ m_AnnouncementLastLine ] ;
2010-11-22 10:59:25 +00:00
}
return 0 ;
}
2010-12-19 05:25:01 +00:00
2013-12-31 05:13:57 +00:00
int * CServer : : GetIdMap ( int ClientID )
{
return ( int * ) ( IdMap + VANILLA_MAX_CLIENTS * ClientID ) ;
}