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. */
2017-03-12 13:49:18 +00:00
# define _WIN32_WINNT 0x0501
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>
2017-05-21 23:07:13 +00:00
# include <engine/shared/protocol_ex.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/snapshot.h>
2016-05-02 21:36:21 +00:00
# include <engine/shared/fifo.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>
2017-06-06 05:31:56 +00:00
# include <game/extrainfo.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_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
2017-03-21 10:24:44 +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 ;
2016-11-18 14:00:42 +00:00
m_NextMapChunk = 0 ;
2010-05-29 07:25:38 +00:00
}
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 ;
2016-01-22 15:02:40 +00:00
m_ServerInfoFirstRequest = 0 ;
m_ServerInfoNumRequests = 0 ;
m_ServerInfoHighLoad = false ;
2015-11-23 21:49:18 +00:00
# if defined (CONF_SQL)
2015-12-17 21:04:38 +00:00
for ( int i = 0 ; i < MAX_SQLSERVERS ; i + + )
{
m_apSqlReadServers [ i ] = 0 ;
m_apSqlWriteServers [ i ] = 0 ;
}
CSqlConnector : : SetReadServers ( m_apSqlReadServers ) ;
CSqlConnector : : SetWriteServers ( m_apSqlWriteServers ) ;
2015-11-23 21:49:18 +00:00
# endif
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
2016-07-08 14:38:05 +00:00
// check for names starting with /, as they can be abused to make people
// write chat commands
if ( aTrimmedName [ 0 ] = = ' / ' )
return - 1 ;
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 )
{
2016-10-30 11:25:49 +00:00
if ( str_utf8_comp_confusable ( 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 ;
2017-03-02 15:16:29 +00:00
m_aClients [ i ] . m_AuthKey = - 1 ;
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 ;
}
2017-06-08 19:58:41 +00:00
int CServer : : GetAuthedState ( 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 ;
2017-06-06 05:31:56 +00:00
pInfo - > m_ClientVersion = GameServer ( ) - > GetClientVersion ( ClientID ) ;
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 ( ) ;
}
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 ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2015-08-23 15:51:28 +00:00
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 ;
2016-09-05 09:38:11 +00:00
pThis - > m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_NONE ;
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 ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2015-08-23 15:01:01 +00:00
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 ;
2016-09-05 09:38:11 +00:00
pThis - > m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_NONE ;
2011-02-12 10:40:36 +00:00
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 ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
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 ;
}
2016-09-05 09:38:11 +00:00
void CServer : : InitDnsbl ( int ClientID )
{
NETADDR Addr = * m_NetServer . ClientAddr ( ClientID ) ;
//TODO: support ipv6
if ( Addr . type ! = NETTYPE_IPV4 )
return ;
// build dnsbl host lookup
char aBuf [ 256 ] ;
if ( g_Config . m_SvDnsblKey [ 0 ] = = ' \0 ' )
// without key
str_format ( aBuf , sizeof ( aBuf ) , " %d.%d.%d.%d.%s " , Addr . ip [ 3 ] , Addr . ip [ 2 ] , Addr . ip [ 1 ] , Addr . ip [ 0 ] , g_Config . m_SvDnsblHost ) ;
else
// with key
str_format ( aBuf , sizeof ( aBuf ) , " %s.%d.%d.%d.%d.%s " , g_Config . m_SvDnsblKey , Addr . ip [ 3 ] , Addr . ip [ 2 ] , Addr . ip [ 1 ] , Addr . ip [ 0 ] , g_Config . m_SvDnsblHost ) ;
IEngine * pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
pEngine - > HostLookup ( & m_aClients [ ClientID ] . m_DnsblLookup , aBuf , NETTYPE_IPV4 ) ;
}
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 ) ;
2017-04-17 10:13:58 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2017-04-17 10:13:58 +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 ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
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 ;
}
2017-07-24 19:43:55 +00:00
void CServer : : SendRconType ( int ClientID , bool UsernameReq )
{
CMsgPacker Msg ( NETMSG_RCONTYPE ) ;
Msg . AddInt ( UsernameReq ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
}
2011-02-12 10:40:36 +00:00
void CServer : : SendMap ( int ClientID )
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 ) ;
2016-11-18 14:00:42 +00:00
m_aClients [ ClientID ] . m_NextMapChunk = 0 ;
}
void CServer : : SendMapData ( int ClientID , int Chunk )
{
unsigned int ChunkSize = 1024 - 128 ;
unsigned int Offset = Chunk * ChunkSize ;
int Last = 0 ;
// drop faulty map data requests
if ( Chunk < 0 | | Offset > m_CurrentMapSize )
return ;
if ( Offset + ChunkSize > = m_CurrentMapSize )
{
ChunkSize = m_CurrentMapSize - Offset ;
Last = 1 ;
}
CMsgPacker Msg ( NETMSG_MAP_DATA ) ;
Msg . AddInt ( Last ) ;
Msg . AddInt ( m_CurrentMapCrc ) ;
Msg . AddInt ( Chunk ) ;
Msg . AddInt ( ChunkSize ) ;
Msg . AddRaw ( & m_pCurrentMapData [ Offset ] , ChunkSize ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID , true ) ;
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-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 ) ;
2017-05-21 23:07:13 +00:00
CMsgPacker Packer ( NETMSG_EX ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// unpack msgid and system flag
2017-05-21 23:07:13 +00:00
int Msg ;
bool Sys ;
CUuid Uuid ;
2011-04-13 18:37:12 +00:00
2017-05-21 23:07:13 +00:00
int Result = UnpackMessageID ( & Msg , & Sys , & Uuid , & Unpacker , & Packer ) ;
if ( Result = = UNPACKMESSAGE_ERROR )
{
2010-05-29 07:25:38 +00:00
return ;
2017-05-21 23:07:13 +00:00
}
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 ;
2017-03-21 10:24:44 +00:00
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
{
2017-03-21 10:24:44 +00:00
m_aClients [ ClientID ] . m_Traffic = ( Alpha * ( ( float ) pPacket - > m_DataSize / Diff ) ) + ( 1.0 - Alpha ) * m_aClients [ ClientID ] . m_Traffic ;
2013-08-04 15:50:12 +00:00
m_aClients [ ClientID ] . m_TrafficSince = Now ;
2013-08-04 02:24:03 +00:00
}
}
2017-05-21 23:07:13 +00:00
if ( Result = = UNPACKMESSAGE_ANSWER )
{
SendMsgEx ( & Packer , MSGFLAG_VITAL , ClientID , true ) ;
}
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 ;
2017-07-24 19:43:55 +00:00
SendRconType ( ClientID , m_AuthManager . NumNonDefaultKeys ( ) > 0 ) ;
2015-01-27 22:13:47 +00:00
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 ( ) ;
2016-11-18 14:00:42 +00:00
if ( Chunk ! = m_aClients [ ClientID ] . m_NextMapChunk | | ! g_Config . m_SvFastDownload )
2012-04-13 23:30:18 +00:00
{
2016-11-18 14:00:42 +00:00
SendMapData ( ClientID , Chunk ) ;
2011-03-15 08:58:57 +00:00
return ;
}
2011-04-13 18:37:12 +00:00
2016-11-18 14:00:42 +00:00
if ( Chunk = = 0 )
2011-03-15 08:58:57 +00:00
{
2016-11-18 14:00:42 +00:00
for ( int i = 0 ; i < g_Config . m_SvMapWindow ; i + + )
{
SendMapData ( ClientID , i ) ;
}
2010-07-29 19:55:33 +00:00
}
2016-11-18 14:00:42 +00:00
SendMapData ( ClientID , g_Config . m_SvMapWindow + m_aClients [ ClientID ] . m_NextMapChunk ) ;
m_aClients [ ClientID ] . m_NextMapChunk + + ;
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 " ) )
{
2017-06-06 05:31:56 +00:00
int version = GameServer ( ) - > GetClientVersion ( ClientID ) ;
if ( GameServer ( ) - > PlayerExists ( ClientID ) & & version < VERSION_DDNET_OLD )
GameServer ( ) - > SetClientVersion ( ClientID , 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
{
2017-06-06 05:31:56 +00:00
if ( GameServer ( ) - > PlayerExists ( 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 )
{
2017-03-02 15:16:29 +00:00
const char * pName = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ; // login name, now used
const char * pPw = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2017-03-04 20:06:22 +00:00
if ( ! str_utf8_check ( pPw ) | | ! str_utf8_check ( pName ) )
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 ;
2017-03-02 15:16:29 +00:00
int KeySlot = - 1 ;
2015-10-26 23:33:26 +00:00
2017-03-02 15:16:29 +00:00
if ( ! pName [ 0 ] )
2010-10-10 13:36:58 +00:00
{
2017-03-02 15:16:29 +00:00
if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_ADMIN ) ) , pPw ) )
AuthLevel = AUTHED_ADMIN ;
else if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_MOD ) ) , pPw ) )
AuthLevel = AUTHED_MOD ;
else if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_HELPER ) ) , pPw ) )
AuthLevel = AUTHED_HELPER ;
}
else
{
KeySlot = m_AuthManager . FindKey ( pName ) ;
if ( m_AuthManager . CheckKey ( KeySlot , pPw ) )
AuthLevel = m_AuthManager . KeyLevel ( KeySlot ) ;
2010-05-29 07:25:38 +00:00
}
2015-10-26 23:33:26 +00:00
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 ) ;
2017-03-06 19:11:23 +00:00
m_aClients [ ClientID ] . m_Authed = AuthLevel ; // Keeping m_Authed around is unwise...
2017-03-02 15:16:29 +00:00
m_aClients [ ClientID ] . m_AuthKey = KeySlot ;
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 ] ;
2017-03-02 15:16:29 +00:00
const char * pIdent = m_AuthManager . KeyIdent ( KeySlot ) ;
2015-10-26 23:33:26 +00:00
switch ( AuthLevel )
{
case AUTHED_ADMIN :
{
SendRconLine ( ClientID , " Admin authentication successful. Full remote console access granted. " ) ;
2017-03-02 15:16:29 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (admin) " , ClientID , pIdent ) ;
2015-10-26 23:33:26 +00:00
break ;
}
case AUTHED_MOD :
{
SendRconLine ( ClientID , " Moderator authentication successful. Limited remote console access granted. " ) ;
2017-03-02 15:16:29 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (moderator) " , ClientID , pIdent ) ;
2015-10-26 23:33:26 +00:00
break ;
}
case AUTHED_HELPER :
{
SendRconLine ( ClientID , " Helper authentication successful. Limited remote console access granted. " ) ;
2017-03-02 15:16:29 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (helper) " , ClientID , pIdent ) ;
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
2017-03-29 10:56:13 +00:00
void CServer : : SendServerInfoConnless ( const NETADDR * pAddr , int Token , int Type )
2016-01-22 15:02:40 +00:00
{
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 ;
}
2017-03-29 10:56:13 +00:00
bool SendClients = m_ServerInfoNumRequests < = MaxRequests & & ! m_ServerInfoHighLoad ;
SendServerInfo ( pAddr , Token , Type , SendClients ) ;
2016-01-22 15:02:40 +00:00
}
2017-03-29 10:56:13 +00:00
void CServer : : SendServerInfo ( const NETADDR * pAddr , int Token , int Type , bool SendClients )
2010-05-29 07:25:38 +00:00
{
2017-03-29 10:56:13 +00:00
// One chance to improve the protocol!
2010-05-29 07:25:38 +00:00
CPacker p ;
char aBuf [ 128 ] ;
// 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 ( ) ;
2017-03-29 10:56:13 +00:00
# define ADD_RAW(p, x) (p).AddRaw(x, sizeof(x))
# define ADD_INT(p, x) do { str_format(aBuf, sizeof(aBuf), "%d", x); (p).AddString(aBuf, 0); } while(0)
2014-01-01 13:58:39 +00:00
2017-03-29 10:56:13 +00:00
switch ( Type )
{
case SERVERINFO_EXTENDED : ADD_RAW ( p , SERVERBROWSE_INFO_EXTENDED ) ; break ;
case SERVERINFO_64_LEGACY : ADD_RAW ( p , SERVERBROWSE_INFO_64_LEGACY ) ; break ;
case SERVERINFO_VANILLA : ADD_RAW ( p , SERVERBROWSE_INFO ) ; break ;
case SERVERINFO_INGAME : ADD_RAW ( p , SERVERBROWSE_INFO ) ; break ;
default : dbg_assert ( false , " unknown serverinfo type " ) ;
}
ADD_INT ( p , Token ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
p . AddString ( GameServer ( ) - > Version ( ) , 32 ) ;
2017-03-29 10:56:13 +00:00
if ( Type ! = SERVERINFO_VANILLA )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
p . AddString ( g_Config . m_SvName , 256 ) ;
2013-12-31 05:13:57 +00:00
}
else
{
2017-03-29 10:56:13 +00:00
if ( m_NetServer . MaxClients ( ) < = VANILLA_MAX_CLIENTS )
{
2013-12-31 05:13:57 +00:00
p . AddString ( g_Config . m_SvName , 64 ) ;
2017-03-29 10:56:13 +00:00
}
2013-12-31 05:13:57 +00:00
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
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
ADD_INT ( p , m_CurrentMapCrc ) ;
ADD_INT ( p , m_CurrentMapSize ) ;
}
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
2017-03-29 10:56:13 +00:00
ADD_INT ( p , g_Config . m_Password [ 0 ] ? SERVER_FLAG_PASSWORD : 0 ) ;
2010-05-29 07:25:38 +00:00
2013-12-31 05:13:57 +00:00
int MaxClients = m_NetServer . MaxClients ( ) ;
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_VANILLA | | Type = = SERVERINFO_INGAME )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
if ( ClientCount > = VANILLA_MAX_CLIENTS )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
if ( ClientCount < MaxClients )
2013-12-31 05:13:57 +00:00
ClientCount = VANILLA_MAX_CLIENTS - 1 ;
else
ClientCount = VANILLA_MAX_CLIENTS ;
}
2017-03-29 10:56:13 +00:00
if ( MaxClients > VANILLA_MAX_CLIENTS )
MaxClients = VANILLA_MAX_CLIENTS ;
if ( PlayerCount > ClientCount )
PlayerCount = ClientCount ;
2013-12-31 05:13:57 +00:00
}
2017-03-29 10:56:13 +00:00
ADD_INT ( p , PlayerCount ) ; // num players
ADD_INT ( p , MaxClients - g_Config . m_SvSpectatorSlots ) ; // max players
ADD_INT ( p , ClientCount ) ; // num clients
ADD_INT ( p , MaxClients ) ; // max clients
if ( Type = = SERVERINFO_EXTENDED )
p . AddString ( " " , 0 ) ; // extra info, reserved
const void * pPrefix = p . Data ( ) ;
int PrefixSize = p . Size ( ) ;
CPacker pp ;
CNetChunk Packet ;
int PacketsSent = 0 ;
int PlayersSent = 0 ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = * pAddr ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
# define SEND(size) \
do \
{ \
Packet . m_pData = pp . Data ( ) ; \
Packet . m_DataSize = size ; \
m_NetServer . Send ( & Packet ) ; \
PacketsSent + + ; \
} while ( 0 )
# define RESET() \
do \
{ \
pp . Reset ( ) ; \
pp . AddRaw ( pPrefix , PrefixSize ) ; \
} while ( 0 )
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
RESET ( ) ;
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_64_LEGACY )
pp . AddInt ( PlayersSent ) ; // offset
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( ! SendClients )
2016-01-22 15:02:40 +00:00
{
2017-03-29 10:56:13 +00:00
SEND ( pp . Size ( ) ) ;
2016-01-22 15:02:40 +00:00
return ;
}
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
pPrefix = SERVERBROWSE_INFO_EXTENDED_MORE ;
PrefixSize = sizeof ( SERVERBROWSE_INFO_EXTENDED_MORE ) ;
}
int Remaining ;
switch ( Type )
{
case SERVERINFO_EXTENDED : Remaining = - 1 ; break ;
case SERVERINFO_64_LEGACY : Remaining = 24 ; break ;
case SERVERINFO_VANILLA : Remaining = VANILLA_MAX_CLIENTS ; break ;
case SERVERINFO_INGAME : Remaining = VANILLA_MAX_CLIENTS ; break ;
default : dbg_assert ( 0 , " caught earlier, unreachable " ) ; return ;
}
// Use the following strategy for sending:
// For vanilla, send the first 16 players.
// For legacy 64p, send 24 players per packet.
// For extended, send as much players as possible.
2010-05-29 07:25:38 +00:00
2017-03-29 10:56:13 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2010-05-29 07:25:38 +00:00
{
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
{
2017-03-29 10:56:13 +00:00
if ( Remaining = = 0 )
{
if ( Type = = SERVERINFO_VANILLA | | Type = = SERVERINFO_INGAME )
break ;
// Otherwise we're SERVERINFO_64_LEGACY.
SEND ( pp . Size ( ) ) ;
RESET ( ) ;
pp . AddInt ( PlayersSent ) ; // offset
Remaining = 24 ;
}
if ( Remaining > 0 )
{
Remaining - - ;
}
int PreviousSize = pp . Size ( ) ;
pp . AddString ( ClientName ( i ) , MAX_NAME_LENGTH ) ; // client name
pp . AddString ( ClientClan ( i ) , MAX_CLAN_LENGTH ) ; // client clan
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
ADD_INT ( pp , m_aClients [ i ] . m_Country ) ; // client country
ADD_INT ( pp , m_aClients [ i ] . m_Score ) ; // client score
ADD_INT ( pp , GameServer ( ) - > IsClientPlayer ( i ) ? 1 : 0 ) ; // is player?
if ( Type = = SERVERINFO_EXTENDED )
pp . AddString ( " " , 0 ) ; // extra info, reserved
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
if ( pp . Size ( ) > = NET_MAX_PAYLOAD )
{
// Retry current player.
i - - ;
SEND ( PreviousSize ) ;
RESET ( ) ;
ADD_INT ( pp , Token ) ;
ADD_INT ( pp , PacketsSent ) ;
pp . AddString ( " " , 0 ) ; // extra info, reserved
continue ;
}
}
PlayersSent + + ;
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2017-03-29 10:56:13 +00:00
SEND ( pp . Size ( ) ) ;
# undef SEND
# undef RESET
# undef ADD_RAW
# undef ADD_INT
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
{
2017-03-29 10:56:13 +00:00
SendServerInfo ( m_NetServer . ClientAddr ( i ) , - 1 , SERVERINFO_INGAME , 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 ) )
{
2017-03-29 10:56:13 +00:00
int ExtraToken = 0 ;
int Type = - 1 ;
if ( Packet . m_DataSize > = ( int ) sizeof ( SERVERBROWSE_GETINFO ) + 1 & &
2010-05-29 07:25:38 +00:00
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO , sizeof ( SERVERBROWSE_GETINFO ) ) = = 0 )
{
2017-03-29 10:56:13 +00:00
if ( Packet . m_Flags & NETSENDFLAG_EXTENDED )
{
Type = SERVERINFO_EXTENDED ;
ExtraToken = ( Packet . m_aExtraData [ 0 ] < < 8 ) | Packet . m_aExtraData [ 1 ] ;
}
else
Type = SERVERINFO_VANILLA ;
2010-05-29 07:25:38 +00:00
}
2017-03-29 10:56:13 +00:00
else if ( Packet . m_DataSize > = ( int ) sizeof ( SERVERBROWSE_GETINFO_64_LEGACY ) + 1 & &
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO_64_LEGACY , sizeof ( SERVERBROWSE_GETINFO_64_LEGACY ) ) = = 0 )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
Type = SERVERINFO_64_LEGACY ;
2016-01-22 15:02:40 +00:00
}
2017-03-29 10:56:13 +00:00
if ( Type ! = - 1 )
2016-01-22 15:02:40 +00:00
{
int Token = ( ( unsigned char * ) Packet . m_pData ) [ sizeof ( SERVERBROWSE_GETINFO ) ] ;
2017-03-29 10:56:13 +00:00
Token | = ExtraToken < < 8 ;
SendServerInfoConnless ( & Packet . m_Address , Token , Type ) ;
2013-12-31 05:13:57 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
else
ProcessClientPacket ( & Packet ) ;
}
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 ( ) ;
2016-05-02 21:36:21 +00:00
# if defined(CONF_FAMILY_UNIX)
m_Fifo . Update ( ) ;
# endif
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 ( )
{
2017-03-02 15:16:29 +00:00
m_AuthManager . Init ( ) ;
2017-05-21 23:07:13 +00:00
if ( g_Config . m_Debug )
{
g_UuidManager . DebugDump ( ) ;
}
2010-05-29 07:25:38 +00:00
//
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
2016-05-02 21:36:21 +00:00
# if defined(CONF_FAMILY_UNIX)
m_Fifo . Init ( Console ( ) , g_Config . m_SvInputFifo , CFGFLAG_SERVER ) ;
# endif
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
2017-03-04 20:16:02 +00:00
if ( m_AuthManager . IsGenerated ( ) )
2015-06-21 17:46:55 +00:00
{
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
2017-04-17 10:13:58 +00:00
for ( int ClientID = 0 ; ClientID < MAX_CLIENTS ; ClientID + + )
2010-05-29 07:25:38 +00:00
{
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_State < = CClient : : STATE_AUTH )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2017-04-17 10:13:58 +00:00
SendMap ( ClientID ) ;
m_aClients [ ClientID ] . Reset ( ) ;
m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
2010-05-29 07:25:38 +00:00
}
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
2016-09-05 09:38:11 +00:00
// handle dnsbl
if ( g_Config . m_SvDnsbl )
{
2017-04-17 10:13:58 +00:00
for ( int ClientID = 0 ; ClientID < MAX_CLIENTS ; ClientID + + )
2016-09-05 09:38:11 +00:00
{
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_EMPTY )
2016-09-05 09:38:11 +00:00
continue ;
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_NONE )
2016-09-05 09:38:11 +00:00
{
// initiate dnsbl lookup
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_PENDING ;
InitDnsbl ( ClientID ) ;
2016-09-05 09:38:11 +00:00
}
2017-04-17 10:13:58 +00:00
else if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_PENDING & &
m_aClients [ ClientID ] . m_DnsblLookup . m_Job . Status ( ) = = CJob : : STATE_DONE )
2016-09-05 09:38:11 +00:00
{
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_DnsblLookup . m_Job . Result ( ) ! = 0 )
2016-09-05 09:38:11 +00:00
{
// entry not found -> whitelisted
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_WHITELISTED ;
2016-09-05 09:38:11 +00:00
}
else
{
// entry found -> blacklisted
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_BLACKLISTED ;
2016-09-05 09:38:11 +00:00
// console output
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2017-04-17 10:13:58 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2016-09-05 09:38:11 +00:00
char aBuf [ 256 ] ;
2017-04-17 10:13:58 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d addr=%s secure=%s blacklisted " , ClientID , aAddrStr , m_NetServer . HasSecurityToken ( ClientID ) ? " yes " : " no " ) ;
2016-09-05 09:38:11 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " dnsbl " , aBuf ) ;
}
}
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_BLACKLISTED & &
2016-09-05 09:38:11 +00:00
g_Config . m_SvDnsblBan )
2017-04-17 10:13:58 +00:00
m_NetServer . NetBan ( ) - > BanAddr ( m_NetServer . ClientAddr ( ClientID ) , 60 * 10 , " Blacklisted by DNSBL " ) ;
2016-09-05 09:38:11 +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 " ) ;
2010-05-29 07:25:38 +00:00
}
2016-05-02 21:36:21 +00:00
m_Econ . Shutdown ( ) ;
# if defined(CONF_FAMILY_UNIX)
m_Fifo . Shutdown ( ) ;
# endif
2016-05-04 13:32:24 +00:00
GameServer ( ) - > OnShutdown ( true ) ;
2010-05-29 07:25:38 +00:00
m_pMap - > Unload ( ) ;
if ( m_pCurrentMapData )
mem_free ( m_pCurrentMapData ) ;
2015-11-23 21:49:18 +00:00
# if defined (CONF_SQL)
2015-12-17 21:04:38 +00:00
for ( int i = 0 ; i < MAX_SQLSERVERS ; i + + )
{
if ( m_apSqlReadServers [ i ] )
delete m_apSqlReadServers [ i ] ;
2015-11-23 21:49:18 +00:00
2015-12-17 21:04:38 +00:00
if ( m_apSqlWriteServers [ i ] )
delete m_apSqlWriteServers [ i ] ;
}
2015-11-23 21:49:18 +00:00
# endif
2010-05-29 07:25:38 +00:00
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
}
2017-06-07 02:45:42 +00:00
void CServer : : StatusImpl ( IConsole : : IResult * pResult , void * pUser , bool DnsblBlacklistedOnly )
2010-05-29 07:25:38 +00:00
{
char aBuf [ 1024 ] ;
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2017-03-21 10:24:44 +00:00
CServer * pThis = static_cast < CServer * > ( pUser ) ;
2010-05-29 07:25:38 +00:00
2017-04-17 10:13:58 +00:00
bool CanSeeAddress = pThis - > m_aClients [ pResult - > m_ClientID ] . m_Authed > CServer : : AUTHED_MOD ;
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2010-05-29 07:25:38 +00:00
{
2017-06-07 02:45:42 +00:00
if (
pThis - > m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY
& & ( ! DnsblBlacklistedOnly | | pThis - > m_aClients [ i ] . m_DnsblState = = CClient : : DNSBL_STATE_BLACKLISTED )
)
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) " : " " ;
2017-03-02 16:02:57 +00:00
char aAuthStr [ 128 ] ;
2017-03-06 11:35:37 +00:00
aAuthStr [ 0 ] = ' \0 ' ;
2017-03-06 19:11:23 +00:00
if ( pThis - > m_aClients [ i ] . m_AuthKey > = 0 )
str_format ( aAuthStr , sizeof ( aAuthStr ) , " key=%s %s " , pThis - > m_AuthManager . KeyIdent ( pThis - > m_aClients [ i ] . m_AuthKey ) , pAuthStr ) ;
2017-03-06 11:35:37 +00:00
2017-04-17 10:13:58 +00:00
if ( CanSeeAddress )
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=%s name='%s' score=%d client=%d secure=%s %s " , i , aAddrStr ,
2017-06-06 05:31:56 +00:00
pThis - > m_aClients [ i ] . m_aName , pThis - > m_aClients [ i ] . m_Score , pThis - > GameServer ( ) - > GetClientVersion ( i ) , pThis - > m_NetServer . HasSecurityToken ( i ) ? " yes " : " no " , aAuthStr ) ;
2017-04-17 10:13:58 +00:00
else
str_format ( aBuf , sizeof ( aBuf ) , " id=%d name='%s' score=%d client=%d secure=%s %s " , i ,
2017-06-06 05:31:56 +00:00
pThis - > m_aClients [ i ] . m_aName , pThis - > m_aClients [ i ] . m_Score , pThis - > GameServer ( ) - > GetClientVersion ( i ) , pThis - > m_NetServer . HasSecurityToken ( i ) ? " yes " : " no " , aAuthStr ) ;
2012-07-29 10:17:16 +00:00
}
2010-06-03 12:48:32 +00:00
else
2017-04-17 10:13:58 +00:00
{
if ( CanSeeAddress )
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=%s connecting " , i , aAddrStr ) ;
else
str_format ( aBuf , sizeof ( aBuf ) , " id=%d connecting " , i ) ;
}
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
}
}
}
2017-06-07 02:45:42 +00:00
void CServer : : ConStatus ( IConsole : : IResult * pResult , void * pUser )
2016-09-05 12:05:07 +00:00
{
2017-06-07 02:45:42 +00:00
StatusImpl ( pResult , pUser , false ) ;
}
2017-03-06 11:35:37 +00:00
2017-06-07 02:45:42 +00:00
void CServer : : ConDnsblStatus ( IConsole : : IResult * pResult , void * pUser )
{
StatusImpl ( pResult , pUser , true ) ;
2016-09-05 12:05:07 +00:00
}
2017-03-02 15:16:29 +00:00
static int GetAuthLevel ( const char * pLevel )
{
int Level = - 1 ;
if ( ! str_comp_nocase ( pLevel , " admin " ) )
Level = CServer : : AUTHED_ADMIN ;
else if ( ! str_comp_nocase_num ( pLevel , " mod " , 3 ) )
Level = CServer : : AUTHED_MOD ;
else if ( ! str_comp_nocase ( pLevel , " helper " ) )
Level = CServer : : AUTHED_HELPER ;
return Level ;
}
2017-03-06 17:02:19 +00:00
void CServer : : AuthRemoveKey ( int KeySlot )
{
int NewKeySlot = KeySlot ;
int OldKeySlot = m_AuthManager . RemoveKey ( KeySlot ) ;
LogoutKey ( KeySlot , " key removal " ) ;
// Update indices.
if ( OldKeySlot ! = NewKeySlot )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_aClients [ i ] . m_AuthKey = = OldKeySlot )
m_aClients [ i ] . m_AuthKey = NewKeySlot ;
}
}
2017-03-02 15:16:29 +00:00
void CServer : : ConAuthAdd ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
2017-07-24 19:43:55 +00:00
bool NeedUpdate = ! pManager - > NumNonDefaultKeys ( ) ;
2017-03-04 20:16:02 +00:00
if ( pManager - > AddKey ( pIdent , pPw , Level ) < 0 )
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident already exists " ) ;
else
2017-07-24 19:43:55 +00:00
{
if ( NeedUpdate )
pThis - > SendRconType ( - 1 , true ) ;
2017-03-04 20:16:02 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key added " ) ;
2017-07-24 19:43:55 +00:00
}
2017-03-02 15:16:29 +00:00
}
void CServer : : ConAuthAddHashed ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
const char * pSalt = pResult - > GetString ( 3 ) ;
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
unsigned char aHash [ MD5_BYTES ] ;
unsigned char aSalt [ SALT_BYTES ] ;
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aHash , sizeof ( aHash ) , pPw ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed password hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aSalt , sizeof ( aSalt ) , pSalt ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed salt hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-02 15:16:29 +00:00
2017-07-24 19:43:55 +00:00
bool NeedUpdate = ! pManager - > NumNonDefaultKeys ( ) ;
2017-03-04 20:16:02 +00:00
if ( pManager - > AddKeyHash ( pIdent , aHash , aSalt , Level ) < 0 )
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident already exists " ) ;
else
2017-07-24 19:43:55 +00:00
{
if ( NeedUpdate )
pThis - > SendRconType ( - 1 , true ) ;
2017-03-04 20:16:02 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key added " ) ;
2017-07-24 19:43:55 +00:00
}
2017-03-02 15:16:29 +00:00
}
void CServer : : ConAuthUpdate ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
pManager - > UpdateKey ( KeySlot , pPw , Level ) ;
2017-07-24 19:43:55 +00:00
pThis - > LogoutKey ( KeySlot , " key update " ) ;
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key updated " ) ;
}
void CServer : : ConAuthUpdateHashed ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
const char * pSalt = pResult - > GetString ( 3 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
unsigned char aHash [ MD5_BYTES ] ;
unsigned char aSalt [ SALT_BYTES ] ;
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aHash , sizeof ( aHash ) , pPw ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed password hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aSalt , sizeof ( aSalt ) , pSalt ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed salt hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-02 15:16:29 +00:00
pManager - > UpdateKeyHash ( KeySlot , aHash , aSalt , Level ) ;
pThis - > LogoutKey ( KeySlot , " key update " ) ;
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key updated " ) ;
}
void CServer : : ConAuthRemove ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
2017-03-06 17:02:19 +00:00
pThis - > AuthRemoveKey ( KeySlot ) ;
2017-07-24 19:43:55 +00:00
if ( ! pManager - > NumNonDefaultKeys ( ) )
pThis - > SendRconType ( - 1 , false ) ;
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key removed, all users logged out " ) ;
}
static void ListKeysCallback ( const char * pIdent , int Level , void * pUser )
{
2017-03-06 19:11:23 +00:00
static const char LSTRING [ ] [ 10 ] = { " helper " , " moderator " , " admin " } ;
2017-03-02 15:16:29 +00:00
char aBuf [ 256 ] ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s %s " , pIdent , LSTRING [ Level - 1 ] ) ;
2017-03-02 15:16:29 +00:00
( ( CServer * ) pUser ) - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , aBuf ) ;
}
void CServer : : ConAuthList ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
pManager - > ListKeys ( ListKeysCallback , pThis ) ;
}
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 ) ;
2017-07-08 11:38:27 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . Start ( Storage ( ) , m_pConsole , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " server " , m_CurrentMapSize , m_pCurrentMapData ) ;
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 ) )
{
2017-07-08 11:38:27 +00:00
m_aDemoRecorder [ ClientID ] . Stop ( ) ;
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 ) ;
2017-07-08 11:38:27 +00:00
m_aDemoRecorder [ ClientID ] . Start ( Storage ( ) , Console ( ) , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " server " , 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 )
{
2017-03-21 10:24:44 +00:00
CServer * pServer = ( CServer * ) pUser ;
2010-12-07 23:42:32 +00:00
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 ) ;
}
2017-07-08 11:38:27 +00:00
pServer - > m_aDemoRecorder [ MAX_CLIENTS ] . Start ( pServer - > Storage ( ) , pServer - > Console ( ) , aFilename , pServer - > GameServer ( ) - > NetVersion ( ) , pServer - > m_aCurrentMap , pServer - > m_CurrentMapCrc , " server " , pServer - > m_CurrentMapSize , pServer - > m_pCurrentMapData ) ;
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 )
{
2017-03-02 15:16:29 +00:00
pServer - > LogoutClient ( pServer - > m_RconClientID , " " ) ;
2011-12-29 23:07:17 +00:00
}
2011-12-26 21:07:57 +00:00
}
2015-11-23 21:49:18 +00:00
# if defined (CONF_SQL)
2015-12-17 21:04:38 +00:00
void CServer : : ConAddSqlServer ( IConsole : : IResult * pResult , void * pUserData )
2015-11-23 21:49:18 +00:00
{
CServer * pSelf = ( CServer * ) pUserData ;
2015-12-20 15:07:32 +00:00
if ( pResult - > NumArguments ( ) ! = 7 & & pResult - > NumArguments ( ) ! = 8 )
2015-11-23 21:49:18 +00:00
{
2015-12-20 15:07:32 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " 7 or 8 arguments are required " ) ;
2015-11-23 21:49:18 +00:00
return ;
}
2015-12-19 17:26:09 +00:00
bool ReadOnly ;
if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " w " ) = = 0 )
ReadOnly = false ;
else if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " r " ) = = 0 )
ReadOnly = true ;
else
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " choose either 'r' for SqlReadServer or 'w' for SqlWriteServer " ) ;
return ;
}
2015-12-17 21:04:38 +00:00
2015-12-20 15:07:32 +00:00
bool SetUpDb = pResult - > NumArguments ( ) = = 8 ? pResult - > GetInteger ( 7 ) : false ;
2015-12-17 21:04:38 +00:00
CSqlServer * * apSqlServers = ReadOnly ? pSelf - > m_apSqlReadServers : pSelf - > m_apSqlWriteServers ;
for ( int i = 0 ; i < MAX_SQLSERVERS ; i + + )
2015-11-23 21:49:18 +00:00
{
2015-12-17 21:04:38 +00:00
if ( ! apSqlServers [ i ] )
2015-11-23 21:49:18 +00:00
{
2016-01-28 16:46:51 +00:00
apSqlServers [ i ] = new CSqlServer ( pResult - > GetString ( 1 ) , pResult - > GetString ( 2 ) , pResult - > GetString ( 3 ) , pResult - > GetString ( 4 ) , pResult - > GetString ( 5 ) , pResult - > GetInteger ( 6 ) , ReadOnly , SetUpDb ) ;
2015-11-23 21:49:18 +00:00
2015-12-20 15:07:32 +00:00
if ( SetUpDb )
2015-11-25 17:23:23 +00:00
{
2015-12-17 21:04:38 +00:00
void * TablesThread = thread_init ( CreateTablesThread , apSqlServers [ i ] ) ;
2015-11-25 17:23:23 +00:00
thread_detach ( TablesThread ) ;
}
2015-11-23 21:49:18 +00:00
char aBuf [ 512 ] ;
2016-05-16 13:41:52 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Added new Sql%sServer: %d: DB: '%s' Prefix: '%s' User: '%s' IP: '%s' Port: %d " , ReadOnly ? " Read " : " Write " , i , apSqlServers [ i ] - > GetDatabase ( ) , apSqlServers [ i ] - > GetPrefix ( ) , apSqlServers [ i ] - > GetUser ( ) , apSqlServers [ i ] - > GetIP ( ) , apSqlServers [ i ] - > GetPort ( ) ) ;
2015-11-23 21:49:18 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
return ;
}
}
2016-01-28 16:46:51 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " failed to add new sqlserver: limit of sqlservers reached " ) ;
2015-11-23 21:49:18 +00:00
}
2015-12-17 21:04:38 +00:00
void CServer : : ConDumpSqlServers ( IConsole : : IResult * pResult , void * pUserData )
2015-11-23 21:49:18 +00:00
{
CServer * pSelf = ( CServer * ) pUserData ;
2015-12-19 17:26:09 +00:00
bool ReadOnly ;
if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " w " ) = = 0 )
ReadOnly = false ;
else if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " r " ) = = 0 )
ReadOnly = true ;
else
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " choose either 'r' for SqlReadServer or 'w' for SqlWriteServer " ) ;
return ;
}
2015-12-17 21:04:38 +00:00
CSqlServer * * apSqlServers = ReadOnly ? pSelf - > m_apSqlReadServers : pSelf - > m_apSqlWriteServers ;
for ( int i = 0 ; i < MAX_SQLSERVERS ; i + + )
if ( apSqlServers [ i ] )
2015-11-23 21:49:18 +00:00
{
char aBuf [ 512 ] ;
2015-12-17 21:04:38 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " SQL-%s %d: DB: '%s' Prefix: '%s' User: '%s' Pass: '%s' IP: '%s' Port: %d " , ReadOnly ? " Read " : " Write " , i , apSqlServers [ i ] - > GetDatabase ( ) , apSqlServers [ i ] - > GetPrefix ( ) , apSqlServers [ i ] - > GetUser ( ) , apSqlServers [ i ] - > GetPass ( ) , apSqlServers [ i ] - > GetIP ( ) , apSqlServers [ i ] - > GetPort ( ) ) ;
2015-11-23 21:49:18 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
}
2015-11-25 17:23:23 +00:00
void CServer : : CreateTablesThread ( void * pData )
{
( ( CSqlServer * ) pData ) - > CreateTables ( ) ;
}
2015-11-23 21:49:18 +00:00
# endif
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 ) ) ;
}
}
2017-03-02 15:16:29 +00:00
void CServer : : LogoutClient ( int ClientID , const char * pReason )
2015-10-26 23:33:26 +00:00
{
2017-03-02 15:16:29 +00:00
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS ) ;
Msg . AddInt ( 0 ) ; //authed
Msg . AddInt ( 0 ) ; //cmdlist
SendMsgEx ( & Msg , MSGFLAG_VITAL , ClientID , true ) ;
m_aClients [ ClientID ] . m_AuthTries = 0 ;
m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
char aBuf [ 64 ] ;
2017-03-06 19:11:23 +00:00
if ( * pReason )
{
str_format ( aBuf , sizeof ( aBuf ) , " Logged out by %s. " , pReason ) ;
2017-03-02 15:16:29 +00:00
SendRconLine ( ClientID , aBuf ) ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d with key=%s logged out by %s " , ClientID , m_AuthManager . KeyIdent ( m_aClients [ ClientID ] . m_AuthKey ) , pReason ) ;
2015-10-26 23:33:26 +00:00
}
2017-03-06 19:11:23 +00:00
else
{
2017-03-02 15:16:29 +00:00
SendRconLine ( ClientID , " Logout successful. " ) ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d with key=%s logged out " , ClientID , m_AuthManager . KeyIdent ( m_aClients [ ClientID ] . m_AuthKey ) ) ;
2017-03-02 15:16:29 +00:00
}
m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
m_aClients [ ClientID ] . m_AuthKey = - 1 ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
void CServer : : LogoutKey ( int Key , const char * pReason )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_aClients [ i ] . m_AuthKey = = Key )
LogoutClient ( i , pReason ) ;
2015-10-26 23:33:26 +00:00
}
2017-03-06 17:02:19 +00:00
void CServer : : ConchainRconPasswordChangeGeneric ( int Level , IConsole : : IResult * pResult )
2014-09-16 19:14:31 +00:00
{
if ( pResult - > NumArguments ( ) = = 1 )
{
2017-03-06 17:02:19 +00:00
int KeySlot = m_AuthManager . DefaultKey ( Level ) ;
2017-03-06 12:46:02 +00:00
if ( KeySlot = = - 1 & & pResult - > GetString ( 0 ) [ 0 ] )
2017-03-04 07:58:02 +00:00
{
2017-03-06 17:02:19 +00:00
m_AuthManager . AddDefaultKey ( Level , pResult - > GetString ( 0 ) ) ;
2017-03-04 07:58:02 +00:00
}
2017-03-06 19:11:23 +00:00
else if ( KeySlot > = 0 )
2017-03-04 07:58:02 +00:00
{
2017-03-04 20:06:22 +00:00
if ( ! pResult - > GetString ( 0 ) [ 0 ] )
2017-03-06 17:02:19 +00:00
{
AuthRemoveKey ( KeySlot ) ;
// Already logs users out.
}
2017-03-04 20:06:22 +00:00
else
2017-03-06 17:02:19 +00:00
{
m_AuthManager . UpdateKey ( KeySlot , pResult - > GetString ( 0 ) , Level ) ;
LogoutKey ( KeySlot , " key update " ) ;
}
2017-03-04 07:58:02 +00:00
}
2014-09-16 19:14:31 +00:00
}
}
2017-03-06 17:02:19 +00:00
void CServer : : ConchainRconPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2014-09-16 19:14:31 +00:00
{
pfnCallback ( pResult , pCallbackUserData ) ;
2017-03-06 17:02:19 +00:00
( ( CServer * ) pUserData ) - > ConchainRconPasswordChangeGeneric ( AUTHED_ADMIN , pResult ) ;
}
2017-03-02 15:16:29 +00:00
2017-03-06 17:02:19 +00:00
void CServer : : ConchainRconModPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
( ( CServer * ) pUserData ) - > ConchainRconPasswordChangeGeneric ( AUTHED_MOD , pResult ) ;
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 ) ;
2017-03-06 17:02:19 +00:00
( ( CServer * ) pUserData ) - > ConchainRconPasswordChangeGeneric ( AUTHED_HELPER , pResult ) ;
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
2015-11-23 21:49:18 +00:00
# if defined (CONF_SQL)
2016-01-17 16:57:38 +00:00
Console ( ) - > Register ( " add_sqlserver " , " s['r'|'w'] s[Database] s[Prefix] s[User] s[Password] s[IP] i[Port] ?i[SetUpDatabase ?] " , CFGFLAG_SERVER , ConAddSqlServer , this , " add a sqlserver " ) ;
Console ( ) - > Register ( " dump_sqlservers " , " s['r'|'w'] " , CFGFLAG_SERVER , ConDumpSqlServers , this , " dumps all sqlservers readservers = r, writeservers = w " ) ;
2015-11-23 21:49:18 +00:00
# endif
2016-09-05 12:05:07 +00:00
Console ( ) - > Register ( " dnsbl_status " , " " , CFGFLAG_SERVER , ConDnsblStatus , this , " List blacklisted players " ) ;
2017-03-06 19:11:23 +00:00
Console ( ) - > Register ( " auth_add " , " s[ident] s[level] s[pw] " , CFGFLAG_SERVER , ConAuthAdd , this , " Add a rcon key " ) ;
Console ( ) - > Register ( " auth_add_p " , " s[ident] s[level] s[hash] s[salt] " , CFGFLAG_SERVER , ConAuthAddHashed , this , " Add a prehashed rcon key " ) ;
Console ( ) - > Register ( " auth_change " , " s[ident] s[level] s[pw] " , CFGFLAG_SERVER , ConAuthUpdate , this , " Update a rcon key " ) ;
Console ( ) - > Register ( " auth_change_p " , " s[ident] s[level] s[hash] s[salt] " , CFGFLAG_SERVER , ConAuthUpdateHashed , this , " Update a rcon key with prehashed data " ) ;
Console ( ) - > Register ( " auth_remove " , " s[ident] " , CFGFLAG_SERVER , ConAuthRemove , this , " Remove a rcon key " ) ;
Console ( ) - > Register ( " auth_list " , " " , CFGFLAG_SERVER , ConAuthList , this , " List all rcon keys " ) ;
2017-03-02 15:16:29 +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
{
2017-05-21 23:07:13 +00:00
if ( ! ( Type > = 0 & & Type < = 0xffff ) )
{
g_UuidManager . GetUuid ( Type ) ;
}
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 ;
2017-07-21 17:46:31 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pServer ) ;
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
2017-07-21 17:46:31 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMap * > ( pEngineMap ) , false ) ;
2010-05-29 07:25:38 +00:00
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
2017-07-21 17:46:31 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMasterServer * > ( pEngineMasterServer ) , false ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( RegisterFail )
2017-07-21 17:46:31 +00:00
{
delete pKernel ;
2010-05-29 07:25:38 +00:00
return - 1 ;
2017-07-21 17:46:31 +00:00
}
2010-05-29 07:25:38 +00:00
}
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
2017-07-08 11:38:27 +00:00
IOHANDLE File = pStorage - > OpenFile ( AUTOEXEC_SERVER_FILE , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
if ( File )
2015-08-12 11:49:16 +00:00
{
2017-07-08 11:38:27 +00:00
io_close ( File ) ;
2015-08-12 11:49:16 +00:00
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 ( ) ;
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
delete pKernel ;
return 0 ;
}
2011-04-09 06:41:31 +00:00
// DDRace
void CServer : : GetClientAddr ( int ClientID , NETADDR * pAddr )
{
2017-03-06 19:11:23 +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
}
2017-06-06 03:51:12 +00:00
const 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 ) ;
2017-07-08 11:38:27 +00:00
if ( ! File )
return 0 ;
std : : vector < char * > v ;
char * pLine ;
CLineReader * lr = new CLineReader ( ) ;
lr - > Init ( File ) ;
while ( ( pLine = lr - > Get ( ) ) )
if ( str_length ( pLine ) )
if ( pLine [ 0 ] ! = ' # ' )
v . push_back ( pLine ) ;
if ( v . size ( ) = = 1 )
2010-11-22 10:59:25 +00:00
{
2017-07-08 11:38:27 +00:00
m_AnnouncementLastLine = 0 ;
}
else if ( ! g_Config . m_SvAnnouncementRandom )
{
if ( m_AnnouncementLastLine > = v . size ( ) )
m_AnnouncementLastLine % = v . size ( ) ;
}
else
{
unsigned Rand ;
do
Rand = rand ( ) % v . size ( ) ;
while ( Rand = = m_AnnouncementLastLine ) ;
2011-04-09 06:41:31 +00:00
2017-07-08 11:38:27 +00:00
m_AnnouncementLastLine = Rand ;
2010-11-22 10:59:25 +00:00
}
2017-07-08 11:38:27 +00:00
io_close ( File ) ;
return v [ m_AnnouncementLastLine ] ;
2010-11-22 10:59:25 +00:00
}
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 ) ;
}
2017-06-06 03:51:12 +00:00
bool CServer : : SetTimedOut ( int ClientID , int OrigID ) {
if ( ! m_NetServer . SetTimedOut ( ClientID , OrigID ) )
{
return false ;
}
DelClientCallback ( OrigID , " Timeout Protection used " , this ) ;
m_aClients [ ClientID ] . m_Authed = IServer : : AUTHED_NO ;
return true ;
}