Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2552 lines
64 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // baseserver.cpp: implementation of the CBaseServer class.
  9. //
  10. //////////////////////////////////////////////////////////////////////
  11. #if defined(_WIN32) && !defined(_X360)
  12. #include "winlite.h" // FILETIME
  13. #elif defined(POSIX)
  14. #include <time.h>
  15. /*
  16. #include <sys/sysinfo.h>
  17. #include <asm/param.h> // for HZ
  18. */
  19. #include <sys/resource.h>
  20. #include <netinet/in.h>
  21. #elif defined(_X360)
  22. #else
  23. #error "Includes for CPU usage calcs here"
  24. #endif
  25. #include "filesystem_engine.h"
  26. #include "baseserver.h"
  27. #include "sysexternal.h"
  28. #include "quakedef.h"
  29. #include "host.h"
  30. #include "netmessages.h"
  31. #include "sys.h"
  32. #include "framesnapshot.h"
  33. #include "sv_packedentities.h"
  34. #include "dt_send_eng.h"
  35. #include "dt_recv_eng.h"
  36. #include "networkstringtable.h"
  37. #include "sys_dll.h"
  38. #include "host_cmd.h"
  39. #include "sv_steamauth.h"
  40. #include <proto_oob.h>
  41. #include <vstdlib/random.h>
  42. #include <irecipientfilter.h>
  43. #include <KeyValues.h>
  44. #include <tier0/vprof.h>
  45. #include <cdll_int.h>
  46. #include <eiface.h>
  47. #include <client_class.h>
  48. #include "tier0/icommandline.h"
  49. #include "sv_steamauth.h"
  50. #include "tier0/vcrmode.h"
  51. #include "sv_ipratelimit.h"
  52. #include "cl_steamauth.h"
  53. #include "sv_filter.h"
  54. #if defined( _X360 )
  55. #include "xbox/xbox_win32stubs.h"
  56. #endif
  57. // memdbgon must be the last include file in a .cpp file!!!
  58. #include "tier0/memdbgon.h"
  59. CThreadFastMutex g_svInstanceBaselineMutex;
  60. extern CGlobalVars g_ServerGlobalVariables;
  61. static ConVar sv_max_queries_sec( "sv_max_queries_sec", "3.0", 0, "Maximum queries per second to respond to from a single IP address." );
  62. static ConVar sv_max_queries_window( "sv_max_queries_window", "30", 0, "Window over which to average queries per second averages." );
  63. static ConVar sv_max_queries_sec_global( "sv_max_queries_sec_global", "3000", 0, "Maximum queries per second to respond to from anywhere." );
  64. static ConVar sv_max_connects_sec( "sv_max_connects_sec", "2.0", 0, "Maximum connections per second to respond to from a single IP address." );
  65. static ConVar sv_max_connects_window( "sv_max_connects_window", "4", 0, "Window over which to average connections per second averages." );
  66. // This defaults to zero so that somebody spamming the server with packets cannot lock out other clients.
  67. static ConVar sv_max_connects_sec_global( "sv_max_connects_sec_global", "0", 0, "Maximum connections per second to respond to from anywhere." );
  68. static CIPRateLimit s_queryRateChecker( &sv_max_queries_sec, &sv_max_queries_window, &sv_max_queries_sec_global );
  69. static CIPRateLimit s_connectRateChecker( &sv_max_connects_sec, &sv_max_connects_window, &sv_max_connects_sec_global );
  70. // Give new data to Steam's master server updater every N seconds.
  71. // This is NOT how often packets are sent to master servers, only how often the
  72. // game server talks to Steam's master server updater (which is on the game server's
  73. // machine, not the Steam servers).
  74. #define MASTER_SERVER_UPDATE_INTERVAL 2.0
  75. // Steam has a matching one in matchmakingtypes.h
  76. #define MAX_TAG_STRING_LENGTH 128
  77. int SortServerTags( char* const *p1, char* const *p2 )
  78. {
  79. return ( Q_strcmp( *p1, *p2 ) > 0 );
  80. }
  81. static void ServerTagsCleanUp( void )
  82. {
  83. CUtlVector<char*> TagList;
  84. ConVarRef sv_tags( "sv_tags" );
  85. if ( sv_tags.IsValid() )
  86. {
  87. int i;
  88. char tmptags[MAX_TAG_STRING_LENGTH];
  89. tmptags[0] = '\0';
  90. V_SplitString( sv_tags.GetString(), ",", TagList );
  91. // make a pass on the tags to eliminate preceding whitespace and empty tags
  92. for ( i = 0; i < TagList.Count(); i++ )
  93. {
  94. if ( i > 0 )
  95. {
  96. Q_strncat( tmptags, ",", MAX_TAG_STRING_LENGTH );
  97. }
  98. char *pChar = TagList[i];
  99. while ( *pChar && *pChar == ' ' )
  100. {
  101. pChar++;
  102. }
  103. // make sure we don't have an empty string (all spaces or ,,)
  104. if ( *pChar )
  105. {
  106. Q_strncat( tmptags, pChar, MAX_TAG_STRING_LENGTH );
  107. }
  108. }
  109. // reset our lists and sort the tags
  110. TagList.PurgeAndDeleteElements();
  111. V_SplitString( tmptags, ",", TagList );
  112. TagList.Sort( SortServerTags );
  113. tmptags[0] = '\0';
  114. // create our new, sorted list of tags
  115. for ( i = 0; i < TagList.Count(); i++ )
  116. {
  117. if ( i > 0 )
  118. {
  119. Q_strncat( tmptags, ",", MAX_TAG_STRING_LENGTH );
  120. }
  121. Q_strncat( tmptags, TagList[i], MAX_TAG_STRING_LENGTH );
  122. }
  123. // set our convar and purge our list
  124. sv_tags.SetValue( tmptags );
  125. TagList.PurgeAndDeleteElements();
  126. }
  127. }
  128. static void SvTagsChangeCallback( IConVar *pConVar, const char *pOldValue, float flOldValue )
  129. {
  130. // We're going to modify the sv_tags convar here, which will cause this to be called again. Prevent recursion.
  131. static bool bTagsChangeCallback = false;
  132. if ( bTagsChangeCallback )
  133. return;
  134. bTagsChangeCallback = true;
  135. ServerTagsCleanUp();
  136. ConVarRef var( pConVar );
  137. if ( Steam3Server().SteamGameServer() )
  138. {
  139. Steam3Server().SteamGameServer()->SetGameTags( var.GetString() );
  140. }
  141. bTagsChangeCallback = false;
  142. }
  143. ConVar sv_region( "sv_region","-1", FCVAR_NONE, "The region of the world to report this server in." );
  144. static ConVar sv_instancebaselines( "sv_instancebaselines", "1", FCVAR_DEVELOPMENTONLY, "Enable instanced baselines. Saves network overhead." );
  145. static ConVar sv_stats( "sv_stats", "1", 0, "Collect CPU usage stats" );
  146. static ConVar sv_enableoldqueries( "sv_enableoldqueries", "0", 0, "Enable support for old style (HL1) server queries" );
  147. static ConVar sv_password( "sv_password", "", FCVAR_NOTIFY | FCVAR_PROTECTED | FCVAR_DONTRECORD, "Server password for entry into multiplayer games" );
  148. ConVar sv_tags( "sv_tags", "", FCVAR_NOTIFY, "Server tags. Used to provide extra information to clients when they're browsing for servers. Separate tags with a comma.", SvTagsChangeCallback );
  149. ConVar sv_visiblemaxplayers( "sv_visiblemaxplayers", "-1", 0, "Overrides the max players reported to prospective clients" );
  150. ConVar sv_alternateticks( "sv_alternateticks", ( IsX360() ) ? "1" : "0", FCVAR_SPONLY, "If set, server only simulates entities on even numbered ticks.\n" );
  151. ConVar sv_allow_wait_command( "sv_allow_wait_command", "1", FCVAR_REPLICATED, "Allow or disallow the wait command on clients connected to this server." );
  152. ConVar sv_allow_color_correction( "sv_allow_color_correction", "1", FCVAR_REPLICATED, "Allow or disallow clients to use color correction on this server." );
  153. extern CNetworkStringTableContainer *networkStringTableContainerServer;
  154. extern ConVar sv_stressbots;
  155. int g_CurGameServerID = 1;
  156. // #define ALLOW_DEBUG_DEDICATED_SERVER_OUTSIDE_STEAM
  157. bool AllowDebugDedicatedServerOutsideSteam()
  158. {
  159. #if defined( ALLOW_DEBUG_DEDICATED_SERVER_OUTSIDE_STEAM )
  160. return true;
  161. #else
  162. return false;
  163. #endif
  164. }
  165. static void SetMasterServerKeyValue( ISteamGameServer *pUpdater, IConVar *pConVar )
  166. {
  167. ConVarRef var( pConVar );
  168. // For protected cvars, don't send the string
  169. if ( var.IsFlagSet( FCVAR_PROTECTED ) )
  170. {
  171. // If it has a value string and the string is not "none"
  172. if ( ( strlen( var.GetString() ) > 0 ) &&
  173. stricmp( var.GetString(), "none" ) )
  174. {
  175. pUpdater->SetKeyValue( var.GetName(), "1" );
  176. }
  177. else
  178. {
  179. pUpdater->SetKeyValue( var.GetName(), "0" );
  180. }
  181. }
  182. else
  183. {
  184. pUpdater->SetKeyValue( var.GetName(), var.GetString() );
  185. }
  186. if ( Steam3Server().BIsActive() )
  187. {
  188. sv.RecalculateTags();
  189. }
  190. }
  191. static void ServerNotifyVarChangeCallback( IConVar *pConVar, const char *pOldValue, float flOldValue )
  192. {
  193. if ( !pConVar->IsFlagSet( FCVAR_NOTIFY ) )
  194. return;
  195. ISteamGameServer *pUpdater = Steam3Server().SteamGameServer();
  196. if ( !pUpdater )
  197. {
  198. // This will force it to send all the rules whenever the master server updater is there.
  199. sv.SetMasterServerRulesDirty();
  200. return;
  201. }
  202. SetMasterServerKeyValue( pUpdater, pConVar );
  203. }
  204. //////////////////////////////////////////////////////////////////////
  205. // Construction/Destruction
  206. //////////////////////////////////////////////////////////////////////
  207. CBaseServer::CBaseServer()
  208. {
  209. // Just get a unique ID to talk to the steam master server updater.
  210. m_bRestartOnLevelChange = false;
  211. m_StringTables = NULL;
  212. m_pInstanceBaselineTable = NULL;
  213. m_pLightStyleTable = NULL;
  214. m_pUserInfoTable = NULL;
  215. m_pServerStartupTable = NULL;
  216. m_pDownloadableFileTable = NULL;
  217. m_fLastCPUCheckTime = 0;
  218. m_fStartTime = 0;
  219. m_fCPUPercent = 0;
  220. m_Socket = NS_SERVER;
  221. m_nTickCount = 0;
  222. m_szMapname[0] = 0;
  223. m_szSkyname[0] = 0;
  224. m_Password[0] = 0;
  225. V_memset( worldmapMD5.bits, 0, MD5_DIGEST_LENGTH );
  226. serverclasses = serverclassbits = 0;
  227. m_nMaxclients = m_nSpawnCount = 0;
  228. m_flTickInterval = 0.03;
  229. m_nUserid = 0;
  230. m_nNumConnections = 0;
  231. m_bIsDedicated = false;
  232. m_fCPUPercent = 0;
  233. m_fStartTime = 0;
  234. m_fLastCPUCheckTime = 0;
  235. m_bMasterServerRulesDirty = true;
  236. m_flLastMasterServerUpdateTime = 0;
  237. m_CurrentRandomNonce = 0;
  238. m_LastRandomNonce = 0;
  239. m_flLastRandomNumberGenerationTime = -3.0f; // force it to calc first frame
  240. m_bReportNewFakeClients = true;
  241. m_flPausedTimeEnd = -1.f;
  242. }
  243. CBaseServer::~CBaseServer()
  244. {
  245. }
  246. /*
  247. ================
  248. SV_CheckChallenge
  249. Make sure connecting client is not spoofing
  250. ================
  251. */
  252. bool CBaseServer::CheckChallengeNr( netadr_t &adr, int nChallengeValue )
  253. {
  254. // See if the challenge is valid
  255. // Don't care if it is a local address.
  256. if ( adr.IsLoopback() )
  257. return true;
  258. // X360TBD: network
  259. if ( IsX360() )
  260. return true;
  261. uint64 challenge = ((uint64)adr.GetIPNetworkByteOrder() << 32) + m_CurrentRandomNonce;
  262. CRC32_t hash;
  263. CRC32_Init( &hash );
  264. CRC32_ProcessBuffer( &hash, &challenge, sizeof(challenge) );
  265. CRC32_Final( &hash );
  266. if ( (int)hash == nChallengeValue )
  267. return true;
  268. // try with the old random nonce
  269. challenge &= 0xffffffff00000000ull;
  270. challenge += m_LastRandomNonce;
  271. hash = 0;
  272. CRC32_Init( &hash );
  273. CRC32_ProcessBuffer( &hash, &challenge, sizeof(challenge) );
  274. CRC32_Final( &hash );
  275. if ( (int)hash == nChallengeValue )
  276. return true;
  277. return false;
  278. }
  279. const char *CBaseServer::GetPassword() const
  280. {
  281. const char *password = sv_password.GetString();
  282. // if password is empty or "none", return NULL
  283. if ( !password[0] || !Q_stricmp(password, "none" ) )
  284. {
  285. return NULL;
  286. }
  287. return password;
  288. }
  289. void CBaseServer::SetPassword(const char *password)
  290. {
  291. if ( password != NULL )
  292. {
  293. Q_strncpy( m_Password, password, sizeof(m_Password) );
  294. }
  295. else
  296. {
  297. m_Password[0] = 0; // clear password
  298. }
  299. }
  300. #define MAX_REUSE_PER_IP 5 // 5 outstanding connect request within timeout window, to account for NATs
  301. /*
  302. ================
  303. CheckIPConnectionReuse
  304. Determine if this IP requesting the connect is connecting too often
  305. ================
  306. */
  307. bool CBaseServer::CheckIPConnectionReuse( netadr_t &adr )
  308. {
  309. int nSimultaneouslyConnections = 0;
  310. for ( int slot = 0 ; slot < m_Clients.Count() ; slot++ )
  311. {
  312. CBaseClient *client = m_Clients[slot];
  313. // if the user is connected but not fully in AND the addr's match
  314. if ( client->IsConnected() &&
  315. !client->IsActive() &&
  316. !client->IsFakeClient() &&
  317. adr.CompareAdr ( client->m_NetChannel->GetRemoteAddress(), true ) )
  318. {
  319. nSimultaneouslyConnections++;
  320. }
  321. }
  322. if ( nSimultaneouslyConnections > MAX_REUSE_PER_IP )
  323. {
  324. Msg ("Too many connect packets from %s\n", adr.ToString( true ) );
  325. return false; // too many connect packets!!!!
  326. }
  327. return true; // this IP is okay
  328. }
  329. int CBaseServer::GetNextUserID()
  330. {
  331. // Note: we'll usually exit on the first pass of this loop..
  332. for ( int i=0; i < m_Clients.Count()+1; i++ )
  333. {
  334. int nTestID = (m_nUserid + i + 1) % SHRT_MAX;
  335. // Make sure no client has this user ID.
  336. int iClient;
  337. for ( iClient=0; iClient < m_Clients.Count(); iClient++ )
  338. {
  339. if ( m_Clients[iClient]->GetUserID() == nTestID )
  340. break;
  341. }
  342. // Ok, no client has this ID, so return it.
  343. if ( iClient == m_Clients.Count() )
  344. return nTestID;
  345. }
  346. Assert( !"GetNextUserID: can't find a unique ID." );
  347. return m_nUserid + 1;
  348. }
  349. /*
  350. ================
  351. SV_ConnectClient
  352. Initializes a CSVClient for a new net connection. This will only be called
  353. once for a player each game, not once for each level change.
  354. ================
  355. */
  356. IClient *CBaseServer::ConnectClient ( netadr_t &adr, int protocol, int challenge, int clientChallenge, int authProtocol,
  357. const char *name, const char *password, const char *hashedCDkey, int cdKeyLen )
  358. {
  359. COM_TimestampedLog( "CBaseServer::ConnectClient" );
  360. if ( !IsActive() )
  361. {
  362. return NULL;
  363. }
  364. if ( !name || !password || !hashedCDkey )
  365. {
  366. return NULL;
  367. }
  368. // Make sure protocols match up
  369. if ( !CheckProtocol( adr, protocol, clientChallenge ) )
  370. {
  371. return NULL;
  372. }
  373. if ( !CheckChallengeNr( adr, challenge ) )
  374. {
  375. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectBadChallenge" );
  376. return NULL;
  377. }
  378. // SourceTV checks password & restrictions later once we know
  379. // if its a normal spectator client or a relay proxy
  380. if ( !IsHLTV() && !IsReplay() )
  381. {
  382. #ifndef NO_STEAM
  383. // LAN servers restrict to class b IP addresses
  384. if ( !CheckIPRestrictions( adr, authProtocol ) )
  385. {
  386. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectLANRestrict");
  387. return NULL;
  388. }
  389. #endif
  390. if ( !CheckPassword( adr, password, name ) )
  391. {
  392. // failed
  393. ConMsg ( "%s: password failed.\n", adr.ToString() );
  394. // Special rejection handler.
  395. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectBadPassword" );
  396. return NULL;
  397. }
  398. }
  399. COM_TimestampedLog( "CBaseServer::ConnectClient: GetFreeClient" );
  400. CBaseClient *client = GetFreeClient( adr );
  401. if ( !client )
  402. {
  403. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectServerFull" );
  404. return NULL; // no free slot found
  405. }
  406. int nNextUserID = GetNextUserID();
  407. if ( !CheckChallengeType( client, nNextUserID, adr, authProtocol, hashedCDkey, cdKeyLen, clientChallenge ) ) // we use the client pointer to track steam requests
  408. {
  409. return NULL;
  410. }
  411. ISteamGameServer *pSteamGameServer = Steam3Server().SteamGameServer();
  412. if ( !pSteamGameServer && authProtocol == PROTOCOL_STEAM )
  413. {
  414. Warning("NULL ISteamGameServer in ConnectClient. Steam authentication may fail.\n");
  415. }
  416. if ( Filter_IsUserBanned( client->GetNetworkID() ) )
  417. {
  418. // Need to make sure the master server is updated with the rejected connection because
  419. // we called Steam3Server().NotifyClientConnect() in CheckChallengeType() above.
  420. if ( pSteamGameServer && authProtocol == PROTOCOL_STEAM )
  421. pSteamGameServer->SendUserDisconnect( client->m_SteamID );
  422. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectBanned" );
  423. return NULL;
  424. }
  425. #if !defined( _HLTVTEST ) && !defined( _REPLAYTEST )
  426. if ( !FinishCertificateCheck( adr, authProtocol, hashedCDkey, clientChallenge ) )
  427. {
  428. // Need to make sure the master server is updated with the rejected connection because
  429. // we called Steam3Server().NotifyClientConnect() in CheckChallengeType() above.
  430. if ( pSteamGameServer && authProtocol == PROTOCOL_STEAM )
  431. pSteamGameServer->SendUserDisconnect( client->m_SteamID );
  432. return NULL;
  433. }
  434. #endif
  435. COM_TimestampedLog( "CBaseServer::ConnectClient: NET_CreateNetChannel" );
  436. // create network channel
  437. INetChannel * netchan = NET_CreateNetChannel( m_Socket, &adr, adr.ToString(), client );
  438. if ( !netchan )
  439. {
  440. // Need to make sure the master server is updated with the rejected connection because
  441. // we called Steam3Server().NotifyClientConnect() in CheckChallengeType() above.
  442. if ( pSteamGameServer && authProtocol == PROTOCOL_STEAM )
  443. pSteamGameServer->SendUserDisconnect( client->m_SteamID );
  444. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectFailedChannel" );
  445. return NULL;
  446. }
  447. // setup netchannl settings
  448. netchan->SetChallengeNr( challenge );
  449. COM_TimestampedLog( "CBaseServer::ConnectClient: client->Connect" );
  450. // make sure client is reset and clear
  451. client->Connect( name, nNextUserID, netchan, false, clientChallenge );
  452. m_nUserid = nNextUserID;
  453. m_nNumConnections++;
  454. // Will get reset from userinfo, but this value comes from sv_updaterate ( the default )
  455. client->m_fSnapshotInterval = 1.0f/20.0f;
  456. client->m_fNextMessageTime = net_time + client->m_fSnapshotInterval;
  457. // Force a full delta update on first packet.
  458. client->m_nDeltaTick = -1;
  459. client->m_nSignonTick = 0;
  460. client->m_nStringTableAckTick = 0;
  461. client->m_pLastSnapshot = NULL;
  462. // Tell client connection worked, now use netchannels
  463. {
  464. ALIGN4 char msg_buffer[MAX_ROUTABLE_PAYLOAD] ALIGN4_POST;
  465. bf_write msg( msg_buffer, sizeof(msg_buffer) );
  466. msg.WriteLong( CONNECTIONLESS_HEADER );
  467. msg.WriteByte( S2C_CONNECTION );
  468. msg.WriteLong( clientChallenge );
  469. msg.WriteString( "0000000000" ); // pad out
  470. NET_SendPacket ( NULL, m_Socket, adr, msg.GetData(), msg.GetNumBytesWritten() );
  471. }
  472. // Set up client structure.
  473. if ( authProtocol == PROTOCOL_HASHEDCDKEY )
  474. {
  475. // use hased CD key as player GUID
  476. Q_strncpy ( client->m_GUID, hashedCDkey, SIGNED_GUID_LEN );
  477. client->m_GUID[SIGNED_GUID_LEN] = '\0';
  478. }
  479. else if ( authProtocol == PROTOCOL_STEAM )
  480. {
  481. // StartSteamValidation() above initialized the clients networkid
  482. }
  483. if ( netchan && !netchan->IsLoopback() )
  484. ConMsg("Client \"%s\" connected (%s).\n", client->GetClientName(), netchan->GetAddress() );
  485. return client;
  486. }
  487. /*
  488. ================
  489. RequireValidChallenge
  490. Return true if this server query must provide a valid challenge number
  491. ================
  492. */
  493. bool CBaseServer::RequireValidChallenge( netadr_t &adr )
  494. {
  495. if ( sv_enableoldqueries.GetBool() == true )
  496. {
  497. return false; // don't enforce challenge numbers
  498. }
  499. return true;
  500. }
  501. /*
  502. ================
  503. ValidChallenge
  504. Return true if this challenge number is correct for this host (for server queries)
  505. ================
  506. */
  507. bool CBaseServer::ValidChallenge( netadr_t & adr, int challengeNr )
  508. {
  509. if ( !IsActive() ) // Must be running a server.
  510. return false ;
  511. if ( !IsMultiplayer() ) // ignore in single player
  512. return false ;
  513. if ( RequireValidChallenge( adr) )
  514. {
  515. if ( !CheckChallengeNr( adr, challengeNr ) )
  516. {
  517. ReplyServerChallenge( adr );
  518. return false;
  519. }
  520. }
  521. return true;
  522. }
  523. bool CBaseServer::ValidInfoChallenge( netadr_t & adr, const char *nugget )
  524. {
  525. if ( !IsActive() ) // Must be running a server.
  526. return false ;
  527. if ( !IsMultiplayer() ) // ignore in single player
  528. return false ;
  529. if ( IsReplay() )
  530. return false;
  531. if ( RequireValidChallenge( adr) )
  532. {
  533. if ( Q_stricmp( nugget, A2S_KEY_STRING ) ) // if the string isn't equal then fail out
  534. {
  535. return false;
  536. }
  537. }
  538. return true;
  539. }
  540. bool CBaseServer::ProcessConnectionlessPacket(netpacket_t * packet)
  541. {
  542. bf_read msg = packet->message; // handy shortcut
  543. char c = msg.ReadChar();
  544. if ( c== 0 )
  545. {
  546. return false;
  547. }
  548. switch ( c )
  549. {
  550. case A2S_GETCHALLENGE :
  551. {
  552. int clientChallenge = msg.ReadLong();
  553. ReplyChallenge( packet->from, clientChallenge );
  554. }
  555. break;
  556. case A2S_SERVERQUERY_GETCHALLENGE:
  557. ReplyServerChallenge( packet->from );
  558. break;
  559. case C2S_CONNECT :
  560. {
  561. char cdkey[STEAM_KEYSIZE];
  562. char name[256];
  563. char password[256];
  564. char productVersion[32];
  565. int protocol = msg.ReadLong();
  566. int authProtocol = msg.ReadLong();
  567. int challengeNr = msg.ReadLong();
  568. int clientChallenge = msg.ReadLong();
  569. // pull the challenge number check early before we do any expensive processing on the connect
  570. if ( !CheckChallengeNr( packet->from, challengeNr ) )
  571. {
  572. RejectConnection( packet->from, clientChallenge, "#GameUI_ServerRejectBadChallenge" );
  573. break;
  574. }
  575. // rate limit the connections
  576. if ( !s_connectRateChecker.CheckIP( packet->from ) )
  577. return false;
  578. msg.ReadString( name, sizeof(name) );
  579. msg.ReadString( password, sizeof(password) );
  580. msg.ReadString( productVersion, sizeof(productVersion) );
  581. // bool bClientPlugins = ( msg.ReadByte() > 0 );
  582. // There's a magic number we use in the steam.inf in P4 that we don't update.
  583. // We can use this to detect if they are running out of P4, and if so, don't do any version
  584. // checking.
  585. const char *pszVersionInP4 = "2000";
  586. const char *pszVersionString = GetSteamInfIDVersionInfo().szVersionString;
  587. if ( V_strcmp( pszVersionString, pszVersionInP4 ) && V_strcmp( productVersion, pszVersionInP4 ) )
  588. {
  589. int nVersionCheck = Q_strncmp( pszVersionString, productVersion, V_strlen( pszVersionString ) );
  590. if ( nVersionCheck < 0 )
  591. {
  592. RejectConnection( packet->from, clientChallenge, "#GameUI_ServerRejectOldVersion" );
  593. break;
  594. }
  595. if ( nVersionCheck > 0 )
  596. {
  597. RejectConnection( packet->from, clientChallenge, "#GameUI_ServerRejectNewVersion" );
  598. break;
  599. }
  600. }
  601. // if ( Steam3Server().BSecure() && bClientPlugins )
  602. // {
  603. // RejectConnection( packet->from, "Cannot connect to a secure server while plug-ins are\nloaded on your client\n" );
  604. // break;
  605. // }
  606. if ( authProtocol == PROTOCOL_STEAM )
  607. {
  608. int keyLen = msg.ReadShort();
  609. if ( keyLen < 0 || keyLen > sizeof(cdkey) )
  610. {
  611. RejectConnection( packet->from, clientChallenge, "#GameUI_ServerRejectBadSteamKey" );
  612. break;
  613. }
  614. msg.ReadBytes( cdkey, keyLen );
  615. ConnectClient( packet->from, protocol, challengeNr, clientChallenge, authProtocol, name, password, cdkey, keyLen ); // cd key is actually a raw encrypted key
  616. }
  617. else
  618. {
  619. msg.ReadString( cdkey, sizeof(cdkey) );
  620. ConnectClient( packet->from, protocol, challengeNr, clientChallenge, authProtocol, name, password, cdkey, strlen(cdkey) );
  621. }
  622. }
  623. break;
  624. default:
  625. {
  626. // rate limit the more expensive server query packets
  627. if ( !s_queryRateChecker.CheckIP( packet->from ) )
  628. return false;
  629. // We don't understand it, let the master server updater at it.
  630. if ( Steam3Server().SteamGameServer() && Steam3Server().IsMasterServerUpdaterSharingGameSocket() )
  631. {
  632. Steam3Server().SteamGameServer()->HandleIncomingPacket(
  633. packet->message.GetBasePointer(),
  634. packet->message.TotalBytesAvailable(),
  635. packet->from.GetIPHostByteOrder(),
  636. packet->from.GetPort()
  637. );
  638. // This is where it will usually want to respond to something immediately by sending some
  639. // packets, so check for that immediately.
  640. ForwardPacketsFromMasterServerUpdater();
  641. }
  642. }
  643. break;
  644. }
  645. return true;
  646. }
  647. int CBaseServer::GetNumFakeClients() const
  648. {
  649. int count = 0;
  650. for ( int i = 0; i < m_Clients.Count(); i++ )
  651. {
  652. if ( m_Clients[i]->IsFakeClient() )
  653. {
  654. count++;
  655. }
  656. }
  657. return count;
  658. }
  659. /*
  660. ==================
  661. void SV_CountPlayers
  662. Counts number of connections. Clients includes regular connections
  663. ==================
  664. */
  665. int CBaseServer::GetNumClients( void ) const
  666. {
  667. int count = 0;
  668. for (int i=0 ; i < m_Clients.Count() ; i++ )
  669. {
  670. if ( m_Clients[ i ]->IsConnected() )
  671. {
  672. count++;
  673. }
  674. }
  675. return count;
  676. }
  677. /*
  678. ==================
  679. void SV_CountPlayers
  680. Counts number of HLTV and Replay connections. Clients includes regular connections
  681. ==================
  682. */
  683. int CBaseServer::GetNumProxies( void ) const
  684. {
  685. int count = 0;
  686. for (int i=0 ; i < m_Clients.Count() ; i++ )
  687. {
  688. #if defined( REPLAY_ENABLED )
  689. if ( m_Clients[ i ]->IsConnected() && (m_Clients[ i ]->IsHLTV() || m_Clients[ i ]->IsReplay() ) )
  690. #else
  691. if ( m_Clients[ i ]->IsConnected() && m_Clients[ i ]->IsHLTV() )
  692. #endif
  693. {
  694. count++;
  695. }
  696. }
  697. return count;
  698. }
  699. int CBaseServer::GetNumPlayers()
  700. {
  701. int count = 0;
  702. if ( !GetUserInfoTable())
  703. {
  704. return 0;
  705. }
  706. const int maxPlayers = GetUserInfoTable()->GetNumStrings();
  707. for ( int i=0; i < maxPlayers; i++ )
  708. {
  709. const player_info_t *pi = (const player_info_t *) m_pUserInfoTable->GetStringUserData( i, NULL );
  710. if ( !pi )
  711. continue;
  712. if ( pi->fakeplayer )
  713. continue; // don't count bots
  714. count++;
  715. }
  716. return count;
  717. }
  718. bool CBaseServer::GetPlayerInfo( int nClientIndex, player_info_t *pinfo )
  719. {
  720. if ( !pinfo )
  721. return false;
  722. if ( nClientIndex < 0 || !GetUserInfoTable() || nClientIndex >= GetUserInfoTable()->GetNumStrings() )
  723. {
  724. Q_memset( pinfo, 0, sizeof( player_info_t ) );
  725. return false;
  726. }
  727. player_info_t *pi = (player_info_t*) GetUserInfoTable()->GetStringUserData( nClientIndex, NULL );
  728. if ( !pi )
  729. {
  730. Q_memset( pinfo, 0, sizeof( player_info_t ) );
  731. return false;
  732. }
  733. Q_memcpy( pinfo, pi, sizeof( player_info_t ) );
  734. // Fixup from network order (little endian)
  735. CByteswap byteswap;
  736. byteswap.SetTargetBigEndian( false );
  737. byteswap.SwapFieldsToTargetEndian( pinfo );
  738. return true;
  739. }
  740. void CBaseServer::UserInfoChanged( int nClientIndex )
  741. {
  742. player_info_t pi;
  743. bool oldlock = networkStringTableContainerServer->Lock( false );
  744. if ( m_Clients[ nClientIndex ]->FillUserInfo( pi ) )
  745. {
  746. // Fixup to little endian for networking
  747. CByteswap byteswap;
  748. byteswap.SetTargetBigEndian( false );
  749. byteswap.SwapFieldsToTargetEndian( &pi );
  750. // update user info settings
  751. m_pUserInfoTable->SetStringUserData( nClientIndex, sizeof(pi), &pi );
  752. }
  753. else
  754. {
  755. // delete user data settings
  756. m_pUserInfoTable->SetStringUserData( nClientIndex, 0, NULL );
  757. }
  758. networkStringTableContainerServer->Lock( oldlock );
  759. }
  760. void CBaseServer::FillServerInfo(SVC_ServerInfo &serverinfo)
  761. {
  762. static char gamedir[MAX_OSPATH];
  763. Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
  764. serverinfo.m_nProtocol = PROTOCOL_VERSION;
  765. serverinfo.m_nServerCount = GetSpawnCount();
  766. V_memcpy( serverinfo.m_nMapMD5.bits, worldmapMD5.bits, MD5_DIGEST_LENGTH );
  767. serverinfo.m_nMaxClients = GetMaxClients();
  768. serverinfo.m_nMaxClasses = serverclasses;
  769. serverinfo.m_bIsDedicated = IsDedicated();
  770. #ifdef _WIN32
  771. serverinfo.m_cOS = 'W';
  772. #else
  773. serverinfo.m_cOS = 'L';
  774. #endif
  775. // HACK to signal that the server is "new"
  776. serverinfo.m_cOS = tolower( serverinfo.m_cOS );
  777. serverinfo.m_fTickInterval = GetTickInterval();
  778. serverinfo.m_szGameDir = gamedir;
  779. serverinfo.m_szMapName = GetMapName();
  780. serverinfo.m_szSkyName = m_szSkyname;
  781. serverinfo.m_szHostName = GetName();
  782. serverinfo.m_bIsHLTV = IsHLTV();
  783. #if defined( REPLAY_ENABLED )
  784. serverinfo.m_bIsReplay = IsReplay();
  785. #endif
  786. }
  787. /*
  788. =================
  789. SVC_GetChallenge
  790. Returns a challenge number that can be used
  791. in a subsequent client_connect command.
  792. We do this to prevent denial of service attacks that
  793. flood the server with invalid connection IPs. With a
  794. challenge, they must give a valid IP address.
  795. =================
  796. */
  797. void CBaseServer::ReplyChallenge(netadr_t &adr, int clientChallenge )
  798. {
  799. ALIGN4 char buffer[STEAM_KEYSIZE+32] ALIGN4_POST;
  800. bf_write msg(buffer,sizeof(buffer));
  801. // get a free challenge number
  802. int challengeNr = GetChallengeNr( adr );
  803. int authprotocol = GetChallengeType( adr );
  804. msg.WriteLong( CONNECTIONLESS_HEADER );
  805. msg.WriteByte( S2C_CHALLENGE );
  806. msg.WriteLong( S2C_MAGICVERSION ); // This makes it so we can detect that this server is correct
  807. msg.WriteLong( challengeNr ); // Server to client challenge
  808. msg.WriteLong( clientChallenge ); // Client to server challenge to ensure our reply is what they asked
  809. msg.WriteLong( authprotocol );
  810. #if !defined( NO_STEAM ) //#ifndef _XBOX
  811. if ( authprotocol == PROTOCOL_STEAM )
  812. {
  813. msg.WriteShort( 0 ); // steam2 encryption key not there anymore
  814. CSteamID steamID = Steam3Server().GetGSSteamID();
  815. uint64 unSteamID = steamID.ConvertToUint64();
  816. msg.WriteBytes( &unSteamID, sizeof(unSteamID) );
  817. msg.WriteByte( Steam3Server().BSecure() );
  818. }
  819. #else
  820. msg.WriteShort( 1 );
  821. msg.WriteByte( 0 );
  822. uint64 unSteamID = 0;
  823. msg.WriteBytes( &unSteamID, sizeof(unSteamID) );
  824. msg.WriteByte( 0 );
  825. #endif
  826. msg.WriteString( "000000" ); // padding bytes
  827. NET_SendPacket( NULL, m_Socket, adr, msg.GetData(), msg.GetNumBytesWritten() );
  828. }
  829. /*
  830. =================
  831. ReplyServerChallenge
  832. Returns a challenge number that can be used
  833. in a subsequent server query commands.
  834. We do this to prevent DDoS attacks via bandwidth
  835. amplification.
  836. =================
  837. */
  838. void CBaseServer::ReplyServerChallenge(netadr_t &adr)
  839. {
  840. ALIGN4 char buffer[16] ALIGN4_POST;
  841. bf_write msg(buffer,sizeof(buffer));
  842. // get a free challenge number
  843. int challengeNr = GetChallengeNr( adr );
  844. msg.WriteLong( CONNECTIONLESS_HEADER );
  845. msg.WriteByte( S2C_CHALLENGE );
  846. msg.WriteLong( challengeNr );
  847. NET_SendPacket( NULL, m_Socket, adr, msg.GetData(), msg.GetNumBytesWritten() );
  848. }
  849. const char *CBaseServer::GetName( void ) const
  850. {
  851. return host_name.GetString();
  852. }
  853. int CBaseServer::GetChallengeType(netadr_t &adr)
  854. {
  855. if ( AllowDebugDedicatedServerOutsideSteam() )
  856. return PROTOCOL_HASHEDCDKEY;
  857. #ifndef SWDS
  858. // don't auth SP games or local mp games if steam isn't running
  859. if ( Host_IsSinglePlayerGame() || ( !Steam3Client().SteamUser() && !IsDedicated() ))
  860. {
  861. return PROTOCOL_HASHEDCDKEY;
  862. }
  863. else
  864. #endif
  865. {
  866. return PROTOCOL_STEAM;
  867. }
  868. }
  869. int CBaseServer::GetChallengeNr (netadr_t &adr)
  870. {
  871. uint64 challenge = ((uint64)adr.GetIPNetworkByteOrder() << 32) + m_CurrentRandomNonce;
  872. CRC32_t hash;
  873. CRC32_Init( &hash );
  874. CRC32_ProcessBuffer( &hash, &challenge, sizeof(challenge) );
  875. CRC32_Final( &hash );
  876. return (int)hash;
  877. }
  878. void CBaseServer::GetNetStats( float &avgIn, float &avgOut )
  879. {
  880. avgIn = avgOut = 0.0f;
  881. for (int i = 0; i < m_Clients.Count(); i++ )
  882. {
  883. CBaseClient *cl = m_Clients[ i ];
  884. // Fake clients get killed in here.
  885. if ( cl->IsFakeClient() )
  886. continue;
  887. if ( !cl->IsConnected() )
  888. continue;
  889. INetChannel *netchan = cl->GetNetChannel();
  890. avgIn += netchan->GetAvgData(FLOW_INCOMING);
  891. avgOut += netchan->GetAvgData(FLOW_OUTGOING);
  892. }
  893. }
  894. void CBaseServer::CalculateCPUUsage( void )
  895. {
  896. if ( !sv_stats.GetBool() )
  897. {
  898. return;
  899. }
  900. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  901. float curtime = Sys_FloatTime();
  902. if ( m_fStartTime == 0 )
  903. // record when we started
  904. {
  905. m_fStartTime = curtime;
  906. }
  907. if( curtime > m_fLastCPUCheckTime + 1 )
  908. // only do this every 1 second
  909. {
  910. #if defined ( _WIN32 )
  911. static float lastAvg=0;
  912. static __int64 lastTotalTime=0,lastNow=0;
  913. HANDLE handle;
  914. FILETIME creationTime, exitTime, kernelTime, userTime, nowTime;
  915. __int64 totalTime,now;
  916. handle = GetCurrentProcess();
  917. // get CPU time
  918. GetProcessTimes (handle, &creationTime, &exitTime,
  919. &kernelTime, &userTime);
  920. GetSystemTimeAsFileTime(&nowTime);
  921. if ( lastNow == 0 )
  922. {
  923. memcpy(&lastNow, &creationTime, sizeof(__int64));
  924. }
  925. memcpy(&totalTime, &userTime, sizeof(__int64));
  926. memcpy(&now, &kernelTime, sizeof(__int64));
  927. totalTime+=now;
  928. memcpy(&now, &nowTime, sizeof(__int64));
  929. m_fCPUPercent = (double)(totalTime-lastTotalTime)/(double)(now-lastNow);
  930. // now save this away for next time
  931. if ( curtime > lastAvg+5 )
  932. // only do it every 5 seconds, so we keep a moving average
  933. {
  934. memcpy(&lastNow,&nowTime,sizeof(__int64));
  935. memcpy(&lastTotalTime,&totalTime,sizeof(__int64));
  936. lastAvg=m_fLastCPUCheckTime;
  937. }
  938. #elif defined ( POSIX )
  939. static struct rusage s_lastUsage;
  940. static float s_lastAvg = 0;
  941. struct rusage currentUsage;
  942. if ( getrusage( RUSAGE_SELF, &currentUsage ) == 0 )
  943. {
  944. double flTimeDiff = (double)( currentUsage.ru_utime.tv_sec - s_lastUsage.ru_utime.tv_sec ) +
  945. (double)(( currentUsage.ru_utime.tv_usec - s_lastUsage.ru_utime.tv_usec ) / 1000000);
  946. m_fCPUPercent = flTimeDiff / ( m_fLastCPUCheckTime - s_lastAvg );
  947. // now save this away for next time
  948. if( m_fLastCPUCheckTime > s_lastAvg + 5)
  949. {
  950. s_lastUsage = currentUsage;
  951. s_lastAvg = m_fLastCPUCheckTime;
  952. }
  953. }
  954. // limit checking :)
  955. if( m_fCPUPercent > 0.9999 )
  956. m_fCPUPercent = 0.9999;
  957. if( m_fCPUPercent < 0 )
  958. m_fCPUPercent = 0;
  959. #else
  960. #error
  961. #endif
  962. m_fLastCPUCheckTime = curtime;
  963. }
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose: Prepare for level transition, etc.
  967. //-----------------------------------------------------------------------------
  968. void CBaseServer::InactivateClients( void )
  969. {
  970. for (int i = 0; i < m_Clients.Count(); i++ )
  971. {
  972. CBaseClient *cl = m_Clients[ i ];
  973. // Fake clients get killed in here.
  974. #if defined( REPLAY_ENABLED )
  975. if ( cl->IsFakeClient() && !cl->IsHLTV() && !cl->IsReplay() )
  976. #else
  977. if ( cl->IsFakeClient() && !cl->IsHLTV() )
  978. #endif
  979. {
  980. // If we don't do this, it'll have a bunch of extra steam IDs for unauthenticated users.
  981. Steam3Server().NotifyClientDisconnect( cl );
  982. cl->Clear();
  983. continue;
  984. }
  985. else if ( !cl->IsConnected() )
  986. {
  987. continue;
  988. }
  989. cl->Inactivate();
  990. }
  991. }
  992. void CBaseServer::ReconnectClients( void )
  993. {
  994. for (int i=0 ; i< m_Clients.Count() ; i++ )
  995. {
  996. CBaseClient *cl = m_Clients[i];
  997. if ( cl->IsConnected() )
  998. {
  999. cl->m_nSignonState = SIGNONSTATE_CONNECTED;
  1000. NET_SignonState signon( cl->m_nSignonState, -1 );
  1001. cl->SendNetMsg( signon );
  1002. }
  1003. }
  1004. }
  1005. /*
  1006. ==================
  1007. SV_CheckTimeouts
  1008. If a packet has not been received from a client in sv_timeout.GetFloat()
  1009. seconds, drop the conneciton.
  1010. When a client is normally dropped, the CSVClient goes into a zombie state
  1011. for a few seconds to make sure any final reliable message gets resent
  1012. if necessary
  1013. ==================
  1014. */
  1015. void CBaseServer::CheckTimeouts (void)
  1016. {
  1017. VPROF_BUDGET( "CBaseServer::CheckTimeouts", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1018. // Don't timeout in _DEBUG builds
  1019. int i;
  1020. #if !defined( _DEBUG )
  1021. for (i=0 ; i< m_Clients.Count() ; i++ )
  1022. {
  1023. IClient *cl = m_Clients[ i ];
  1024. if ( cl->IsFakeClient() || !cl->IsConnected() )
  1025. continue;
  1026. INetChannel *netchan = cl->GetNetChannel();
  1027. if ( !netchan )
  1028. continue;
  1029. if ( netchan->IsTimedOut() )
  1030. {
  1031. cl->Disconnect( CLIENTNAME_TIMED_OUT, cl->GetClientName() );
  1032. }
  1033. }
  1034. #endif
  1035. for (i=0 ; i< m_Clients.Count() ; i++ )
  1036. {
  1037. IClient *cl = m_Clients[ i ];
  1038. if ( cl->IsFakeClient() || !cl->IsConnected() )
  1039. continue;
  1040. if ( cl->GetNetChannel() && cl->GetNetChannel()->IsOverflowed() )
  1041. {
  1042. cl->Disconnect( "Client %d overflowed reliable channel.", i );
  1043. }
  1044. }
  1045. }
  1046. // ==================
  1047. // check if clients update thier user setting (convars) and call
  1048. // ==================
  1049. void CBaseServer::UpdateUserSettings(void)
  1050. {
  1051. VPROF_BUDGET( "CBaseServer::UpdateUserSettings", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1052. for (int i=0 ; i< m_Clients.Count() ; i++ )
  1053. {
  1054. CBaseClient *cl = m_Clients[ i ];
  1055. cl->CheckFlushNameChange();
  1056. if ( cl->m_bConVarsChanged )
  1057. {
  1058. cl->UpdateUserSettings();
  1059. }
  1060. }
  1061. }
  1062. // ==================
  1063. // check if clients need the serverinfo packet sent
  1064. // ==================
  1065. void CBaseServer::SendPendingServerInfo()
  1066. {
  1067. VPROF_BUDGET( "CBaseServer::SendPendingServerInfo", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1068. for (int i=0 ; i< m_Clients.Count() ; i++ )
  1069. {
  1070. CBaseClient *cl = m_Clients[ i ];
  1071. if ( cl->m_bSendServerInfo )
  1072. {
  1073. cl->SendServerInfo();
  1074. }
  1075. }
  1076. }
  1077. // compresses a packed entity, returns data & bits
  1078. const char *CBaseServer::CompressPackedEntity(ServerClass *pServerClass, const char *data, int &bits)
  1079. {
  1080. ALIGN4 static char s_packedData[MAX_PACKEDENTITY_DATA] ALIGN4_POST;
  1081. bf_write writeBuf( "CompressPackedEntity", s_packedData, sizeof( s_packedData ) );
  1082. const void *pBaselineData = NULL;
  1083. int nBaselineBits = 0;
  1084. Assert( pServerClass != NULL );
  1085. GetClassBaseline( pServerClass, &pBaselineData, &nBaselineBits );
  1086. nBaselineBits *= 8;
  1087. Assert( pBaselineData != NULL );
  1088. SendTable_WriteAllDeltaProps(
  1089. pServerClass->m_pTable,
  1090. pBaselineData,
  1091. nBaselineBits,
  1092. data,
  1093. bits,
  1094. -1,
  1095. &writeBuf );
  1096. //overwrite in bits with out bits
  1097. bits = writeBuf.GetNumBitsWritten();
  1098. return s_packedData;
  1099. }
  1100. // uncompresses a
  1101. const char* CBaseServer::UncompressPackedEntity(PackedEntity *pPackedEntity, int &bits)
  1102. {
  1103. UnpackedDataCache_t *pdc = framesnapshotmanager->GetCachedUncompressedEntity( pPackedEntity );
  1104. if ( pdc->bits > 0 )
  1105. {
  1106. // found valid uncompressed version in cache
  1107. bits= pdc->bits;
  1108. return pdc->data;
  1109. }
  1110. // not in cache, so uncompress it
  1111. const void *pBaseline;
  1112. int nBaselineBytes = 0;
  1113. GetClassBaseline( pPackedEntity->m_pServerClass, &pBaseline, &nBaselineBytes );
  1114. Assert( pBaseline != NULL );
  1115. // store this baseline in u.m_pUpdateBaselines
  1116. bf_read oldBuf( "UncompressPackedEntity1", pBaseline, nBaselineBytes );
  1117. bf_read newBuf( "UncompressPackedEntity2", pPackedEntity->GetData(), Bits2Bytes(pPackedEntity->GetNumBits()) );
  1118. bf_write outBuf( "UncompressPackedEntity3", pdc->data, MAX_PACKEDENTITY_DATA );
  1119. Assert( pPackedEntity->m_pClientClass );
  1120. RecvTable_MergeDeltas(
  1121. pPackedEntity->m_pClientClass->m_pRecvTable,
  1122. &oldBuf,
  1123. &newBuf,
  1124. &outBuf );
  1125. bits = pdc->bits = outBuf.GetNumBitsWritten();
  1126. return pdc->data;
  1127. }
  1128. /*
  1129. ================
  1130. SV_CheckProtocol
  1131. Make sure connecting client is using proper protocol
  1132. ================
  1133. */
  1134. bool CBaseServer::CheckProtocol( netadr_t &adr, int nProtocol, int clientChallenge )
  1135. {
  1136. if ( nProtocol != PROTOCOL_VERSION )
  1137. {
  1138. // Client is newer than server
  1139. if ( nProtocol > PROTOCOL_VERSION )
  1140. {
  1141. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectOldProtocol" );
  1142. }
  1143. else
  1144. // Server is newer than client
  1145. {
  1146. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectNewProtocol" );
  1147. }
  1148. return false;
  1149. }
  1150. // Success
  1151. return true;
  1152. }
  1153. /*
  1154. ================
  1155. SV_CheckKeyInfo
  1156. Determine if client is outside appropriate address range
  1157. ================
  1158. */
  1159. bool CBaseServer::CheckChallengeType( CBaseClient * client, int nNewUserID, netadr_t & adr, int nAuthProtocol, const char *pchLogonCookie, int cbCookie, int clientChallenge )
  1160. {
  1161. if ( AllowDebugDedicatedServerOutsideSteam() )
  1162. return true;
  1163. // Check protocol ID
  1164. if ( ( nAuthProtocol <= 0 ) || ( nAuthProtocol > PROTOCOL_LASTVALID ) )
  1165. {
  1166. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectInvalidConnection");
  1167. return false;
  1168. }
  1169. if ( ( nAuthProtocol == PROTOCOL_HASHEDCDKEY ) && (Q_strlen( pchLogonCookie ) <= 0 || Q_strlen(pchLogonCookie) != 32 ) )
  1170. {
  1171. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectInvalidCertLen" );
  1172. return false;
  1173. }
  1174. Assert( !IsReplay() );
  1175. if ( IsHLTV() )
  1176. {
  1177. // Don't authenticate spectators or add them to the
  1178. // player list in the singleton Steam3Server()
  1179. Assert( nAuthProtocol == PROTOCOL_HASHEDCDKEY );
  1180. Assert( !client->m_SteamID.IsValid() );
  1181. }
  1182. else if ( nAuthProtocol == PROTOCOL_STEAM )
  1183. {
  1184. // Dev hack to allow 360/Steam PC cross platform play
  1185. // int ip0 = 207;
  1186. // int ip1 = 173;
  1187. // int ip2 = 179;
  1188. // int ip3Min = 230;
  1189. // int ip3Max = 245;
  1190. //
  1191. // if ( adr.ip[0] == ip0 &&
  1192. // adr.ip[1] == ip1 &&
  1193. // adr.ip[2] == ip2 &&
  1194. // adr.ip[3] >= ip3Min &&
  1195. // adr.ip[3] <= ip3Max )
  1196. // {
  1197. // return true;
  1198. // }
  1199. client->SetSteamID( CSteamID() ); // set an invalid SteamID
  1200. // Convert raw certificate back into data
  1201. if ( cbCookie <= 0 || cbCookie >= STEAM_KEYSIZE )
  1202. {
  1203. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectInvalidSteamCertLen" );
  1204. return false;
  1205. }
  1206. netadr_t checkAdr = adr;
  1207. if ( adr.GetType() == NA_LOOPBACK || adr.IsLocalhost() )
  1208. {
  1209. checkAdr.SetIP( net_local_adr.GetIPHostByteOrder() );
  1210. }
  1211. if ( !Steam3Server().NotifyClientConnect( client, nNewUserID, checkAdr, pchLogonCookie, cbCookie )
  1212. && !Steam3Server().BLanOnly() ) // the userID isn't alloc'd yet so we need to fill it in manually
  1213. {
  1214. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectSteam" );
  1215. return false;
  1216. }
  1217. //
  1218. // Any rejections below this must call SendUserDisconnect
  1219. //
  1220. // Now that we have auth'd with steam, client->GetSteamID() is now valid and we can verify against the GC lobby
  1221. bool bHasGCLobby = g_iServerGameDLLVersion >= 8 && serverGameDLL->GetServerGCLobby();
  1222. if ( bHasGCLobby )
  1223. {
  1224. if ( !serverGameDLL->GetServerGCLobby()->SteamIDAllowedToConnect( client->m_SteamID ) )
  1225. {
  1226. ISteamGameServer *pSteamGameServer = Steam3Server().SteamGameServer();
  1227. if ( pSteamGameServer )
  1228. pSteamGameServer->SendUserDisconnect( client->m_SteamID);
  1229. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectMustUseMatchmaking" );
  1230. return false;
  1231. }
  1232. }
  1233. }
  1234. else
  1235. {
  1236. if ( !Steam3Server().NotifyLocalClientConnect( client ) ) // the userID isn't alloc'd yet so we need to fill it in manually
  1237. {
  1238. RejectConnection( adr, clientChallenge, "#GameUI_ServerRejectGS" );
  1239. return false;
  1240. }
  1241. }
  1242. return true;
  1243. }
  1244. bool CBaseServer::CheckIPRestrictions( const netadr_t &adr, int nAuthProtocol )
  1245. {
  1246. // Determine if client is outside appropriate address range
  1247. if ( adr.IsLoopback() )
  1248. return true;
  1249. // X360TBD: network
  1250. if ( IsX360() )
  1251. return true;
  1252. // allow other users if they're on the same ip range
  1253. if ( Steam3Server().BLanOnly() )
  1254. {
  1255. // allow connection, if client is in the same subnet
  1256. if ( adr.CompareClassBAdr( net_local_adr ) )
  1257. return true;
  1258. // allow connection, if client has a private IP
  1259. if ( adr.IsReservedAdr() )
  1260. return true;
  1261. // reject connection
  1262. return false;
  1263. }
  1264. return true;
  1265. }
  1266. void CBaseServer::SetMasterServerRulesDirty()
  1267. {
  1268. m_bMasterServerRulesDirty = true;
  1269. }
  1270. bool CBaseServer::CheckPassword( netadr_t &adr, const char *password, const char *name )
  1271. {
  1272. const char *server_password = GetPassword();
  1273. if ( !server_password )
  1274. return true; // no password set
  1275. if ( adr.IsLocalhost() || adr.IsLoopback() )
  1276. {
  1277. return true; // local client can always connect
  1278. }
  1279. int iServerPassLen = Q_strlen(server_password);
  1280. if ( iServerPassLen != Q_strlen(password) )
  1281. {
  1282. return false; // different length cannot be equal
  1283. }
  1284. if ( Q_strncmp( password, server_password, iServerPassLen ) == 0)
  1285. {
  1286. return true; // passwords are equal
  1287. }
  1288. return false; // all test failed
  1289. }
  1290. float CBaseServer::GetTime() const
  1291. {
  1292. return m_nTickCount * m_flTickInterval;
  1293. }
  1294. float CBaseServer::GetFinalTickTime() const
  1295. {
  1296. return (m_nTickCount + (host_frameticks - host_currentframetick)) * m_flTickInterval;
  1297. }
  1298. void CBaseServer::DisconnectClient(IClient *client, const char *reason )
  1299. {
  1300. client->Disconnect( reason );
  1301. }
  1302. void CBaseServer::Clear( void )
  1303. {
  1304. if ( m_StringTables )
  1305. {
  1306. m_StringTables->RemoveAllTables();
  1307. m_StringTables = NULL;
  1308. }
  1309. m_pInstanceBaselineTable = NULL;
  1310. m_pLightStyleTable = NULL;
  1311. m_pUserInfoTable = NULL;
  1312. m_pServerStartupTable = NULL;
  1313. m_State = ss_dead;
  1314. m_nTickCount = 0;
  1315. Q_memset( m_szMapname, 0, sizeof( m_szMapname ) );
  1316. Q_memset( m_szSkyname, 0, sizeof( m_szSkyname ) );
  1317. V_memset( worldmapMD5.bits, 0, MD5_DIGEST_LENGTH );
  1318. MEM_ALLOC_CREDIT();
  1319. // Use a different limit on the signon buffer, so we can save some memory in SP (for xbox).
  1320. if ( IsMultiplayer() || IsDedicated() )
  1321. {
  1322. m_SignonBuffer.EnsureCapacity( NET_MAX_PAYLOAD );
  1323. }
  1324. else
  1325. {
  1326. m_SignonBuffer.EnsureCapacity( 16384 );
  1327. }
  1328. m_Signon.StartWriting( m_SignonBuffer.Base(), m_SignonBuffer.Count() );
  1329. m_Signon.SetDebugName( "m_Signon" );
  1330. serverclasses = 0;
  1331. serverclassbits = 0;
  1332. m_LastRandomNonce = m_CurrentRandomNonce = 0;
  1333. m_flPausedTimeEnd = -1.f;
  1334. }
  1335. /*
  1336. ================
  1337. SV_RejectConnection
  1338. Rejects connection request and sends back a message
  1339. ================
  1340. */
  1341. void CBaseServer::RejectConnection( const netadr_t &adr, int clientChallenge, const char *s )
  1342. {
  1343. ALIGN4 char msg_buffer[MAX_ROUTABLE_PAYLOAD] ALIGN4_POST;
  1344. bf_write msg( msg_buffer, sizeof(msg_buffer) );
  1345. msg.WriteLong( CONNECTIONLESS_HEADER );
  1346. msg.WriteByte( S2C_CONNREJECT );
  1347. msg.WriteLong( clientChallenge );
  1348. msg.WriteString( s );
  1349. NET_SendPacket ( NULL, m_Socket, adr, msg.GetData(), msg.GetNumBytesWritten() );
  1350. }
  1351. void CBaseServer::SetPaused(bool paused)
  1352. {
  1353. if ( !IsPausable() )
  1354. {
  1355. return;
  1356. }
  1357. if ( !IsActive() )
  1358. return;
  1359. if ( paused )
  1360. {
  1361. m_State = ss_paused;
  1362. }
  1363. else
  1364. {
  1365. m_State = ss_active;
  1366. }
  1367. SVC_SetPause setpause( paused );
  1368. BroadcastMessage( setpause );
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Purpose: General initialization of the server
  1372. //-----------------------------------------------------------------------------
  1373. void CBaseServer::Init (bool bIsDedicated)
  1374. {
  1375. m_nMaxclients = 0;
  1376. m_nSpawnCount = 0;
  1377. m_nUserid = 1;
  1378. m_nNumConnections = 0;
  1379. m_bIsDedicated = bIsDedicated;
  1380. m_Socket = NS_SERVER;
  1381. m_Signon.SetDebugName( "m_Signon" );
  1382. g_pCVar->InstallGlobalChangeCallback( ServerNotifyVarChangeCallback );
  1383. SetMasterServerRulesDirty();
  1384. Clear();
  1385. }
  1386. INetworkStringTable *CBaseServer::GetInstanceBaselineTable( void )
  1387. {
  1388. if ( m_pInstanceBaselineTable == NULL )
  1389. {
  1390. m_pInstanceBaselineTable = m_StringTables->FindTable( INSTANCE_BASELINE_TABLENAME );
  1391. }
  1392. return m_pInstanceBaselineTable;
  1393. }
  1394. INetworkStringTable *CBaseServer::GetLightStyleTable( void )
  1395. {
  1396. if ( m_pLightStyleTable == NULL )
  1397. {
  1398. m_pLightStyleTable= m_StringTables->FindTable( LIGHT_STYLES_TABLENAME );
  1399. }
  1400. return m_pLightStyleTable;
  1401. }
  1402. INetworkStringTable *CBaseServer::GetUserInfoTable( void )
  1403. {
  1404. if ( m_pUserInfoTable == NULL )
  1405. {
  1406. if ( m_StringTables == NULL )
  1407. {
  1408. return NULL;
  1409. }
  1410. m_pUserInfoTable = m_StringTables->FindTable( USER_INFO_TABLENAME );
  1411. }
  1412. return m_pUserInfoTable;
  1413. }
  1414. bool CBaseServer::GetClassBaseline( ServerClass *pClass, void const **pData, int *pDatalen )
  1415. {
  1416. if ( sv_instancebaselines.GetInt() )
  1417. {
  1418. ErrorIfNot( pClass->m_InstanceBaselineIndex != INVALID_STRING_INDEX,
  1419. ("SV_GetInstanceBaseline: missing instance baseline for class '%s'", pClass->m_pNetworkName)
  1420. );
  1421. AUTO_LOCK( g_svInstanceBaselineMutex );
  1422. *pData = GetInstanceBaselineTable()->GetStringUserData(
  1423. pClass->m_InstanceBaselineIndex,
  1424. pDatalen );
  1425. return *pData != NULL;
  1426. }
  1427. else
  1428. {
  1429. static char dummy[1] = {0};
  1430. *pData = dummy;
  1431. *pDatalen = 1;
  1432. return true;
  1433. }
  1434. }
  1435. bool CBaseServer::ShouldUpdateMasterServer()
  1436. {
  1437. // If the game server itself is ever running, then it's the one who gets to update the master server.
  1438. // (SourceTV will not update it in this case).
  1439. return true;
  1440. }
  1441. void CBaseServer::CheckMasterServerRequestRestart()
  1442. {
  1443. if ( !Steam3Server().SteamGameServer() || !Steam3Server().SteamGameServer()->WasRestartRequested() )
  1444. return;
  1445. // Connection was rejected by the HLMaster (out of date version)
  1446. // hack, vgui console looks for this string;
  1447. Msg("%cMasterRequestRestart\n", 3);
  1448. #ifndef _WIN32
  1449. if (CommandLine()->FindParm(AUTO_RESTART))
  1450. {
  1451. Msg("Your server will be restarted on map change.\n");
  1452. Log("Your server will be restarted on map change.\n");
  1453. SetRestartOnLevelChange( true );
  1454. }
  1455. #endif
  1456. if ( sv.IsDedicated() ) // under linux assume steam
  1457. {
  1458. Msg("Your server needs to be restarted in order to receive the latest update.\n");
  1459. Log("Your server needs to be restarted in order to receive the latest update.\n");
  1460. }
  1461. else
  1462. {
  1463. Msg("Your server is out of date. Please update and restart.\n");
  1464. }
  1465. }
  1466. void CBaseServer::UpdateMasterServer()
  1467. {
  1468. VPROF_BUDGET( "CBaseServer::UpdateMasterServer", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1469. if ( !ShouldUpdateMasterServer() )
  1470. return;
  1471. if ( !Steam3Server().SteamGameServer() )
  1472. return;
  1473. // Only update every so often.
  1474. double flCurTime = Plat_FloatTime();
  1475. if ( flCurTime - m_flLastMasterServerUpdateTime < MASTER_SERVER_UPDATE_INTERVAL )
  1476. return;
  1477. m_flLastMasterServerUpdateTime = flCurTime;
  1478. ForwardPacketsFromMasterServerUpdater();
  1479. CheckMasterServerRequestRestart();
  1480. if ( NET_IsDedicated() && sv_region.GetInt() == -1 )
  1481. {
  1482. sv_region.SetValue( 255 ); // HACK!HACK! undo me once we want to enforce regions
  1483. //Log_Printf( "You must set sv_region in your server.cfg or use +sv_region on the command line\n" );
  1484. //Con_Printf( "You must set sv_region in your server.cfg or use +sv_region on the command line\n" );
  1485. //Cbuf_AddText( "quit\n" );
  1486. //return;
  1487. }
  1488. static bool bUpdateMasterServers = !CommandLine()->FindParm( "-nomaster" );
  1489. if ( !bUpdateMasterServers )
  1490. return;
  1491. bool bActive = IsActive() && IsMultiplayer();
  1492. if ( serverGameDLL && serverGameDLL->ShouldHideServer() )
  1493. bActive = false;
  1494. Steam3Server().SteamGameServer()->EnableHeartbeats( bActive );
  1495. if ( !bActive )
  1496. return;
  1497. UpdateMasterServerRules();
  1498. UpdateMasterServerPlayers();
  1499. Steam3Server().SendUpdatedServerDetails();
  1500. }
  1501. void CBaseServer::UpdateMasterServerRules()
  1502. {
  1503. // Only do this if the rules vars are dirty.
  1504. if ( !m_bMasterServerRulesDirty )
  1505. return;
  1506. ISteamGameServer *pUpdater = Steam3Server().SteamGameServer();
  1507. if ( !pUpdater )
  1508. return;
  1509. pUpdater->ClearAllKeyValues();
  1510. // Need to respond with game directory, game name, and any server variables that have been set that
  1511. // effect rules. Also, probably need a hook into the .dll to respond with additional rule information.
  1512. ConCommandBase *var;
  1513. for ( var = g_pCVar->GetCommands() ; var ; var=var->GetNext() )
  1514. {
  1515. if ( !(var->IsFlagSet( FCVAR_NOTIFY ) ) )
  1516. continue;
  1517. if ( var->IsCommand() )
  1518. continue;
  1519. ConVar *pConVar = static_cast< ConVar* >( var );
  1520. if ( !pConVar )
  1521. continue;
  1522. SetMasterServerKeyValue( pUpdater, pConVar );
  1523. }
  1524. if ( Steam3Server().SteamGameServer() )
  1525. {
  1526. RecalculateTags();
  1527. }
  1528. // Ok.. it's all updated, only send incremental updates now until we decide they're all dirty.
  1529. m_bMasterServerRulesDirty = false;
  1530. }
  1531. void CBaseServer::ForwardPacketsFromMasterServerUpdater()
  1532. {
  1533. ISteamGameServer *p = Steam3Server().SteamGameServer();
  1534. if ( !p )
  1535. return;
  1536. while ( 1 )
  1537. {
  1538. uint32 netadrAddress;
  1539. uint16 netadrPort;
  1540. unsigned char packetData[16 * 1024];
  1541. int len = p->GetNextOutgoingPacket( packetData, sizeof( packetData ), &netadrAddress, &netadrPort );
  1542. if ( len <= 0 )
  1543. break;
  1544. // Send this packet for them..
  1545. netadr_t adr( netadrAddress, netadrPort );
  1546. NET_SendPacket( NULL, m_Socket, adr, packetData, len );
  1547. }
  1548. }
  1549. /*
  1550. =================
  1551. SV_ReadPackets
  1552. Read's packets from clients and executes messages as appropriate.
  1553. =================
  1554. */
  1555. void CBaseServer::RunFrame( void )
  1556. {
  1557. VPROF_BUDGET( "CBaseServer::RunFrame", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1558. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CBaseServer::RunFrame" );
  1559. NET_ProcessSocket( m_Socket, this );
  1560. #ifdef LINUX
  1561. // Process the linux sv lan port if it's open.
  1562. if ( NET_GetUDPPort( NS_SVLAN ) )
  1563. NET_ProcessSocket( NS_SVLAN, this );
  1564. #endif
  1565. CheckTimeouts(); // drop clients that timeed out
  1566. UpdateUserSettings(); // update client settings
  1567. SendPendingServerInfo(); // send outstanding signon packets after ALL user settings have been updated
  1568. CalculateCPUUsage(); // update CPU usage
  1569. UpdateMasterServer();
  1570. if ( m_flLastRandomNumberGenerationTime < 0 || (m_flLastRandomNumberGenerationTime + CHALLENGE_NONCE_LIFETIME) < g_ServerGlobalVariables.realtime )
  1571. {
  1572. m_LastRandomNonce = m_CurrentRandomNonce;
  1573. // RandomInt maps a uniform distribution on the interval [0,INT_MAX], so make two calls to get the random number.
  1574. // RandomInt will always return the minimum value if the difference in min and max is greater than or equal to INT_MAX.
  1575. m_CurrentRandomNonce = ( ( (uint32)RandomInt( 0, 0xFFFF ) ) << 16 ) | RandomInt( 0, 0xFFFF );
  1576. m_flLastRandomNumberGenerationTime = g_ServerGlobalVariables.realtime;
  1577. }
  1578. // Timed pause - resume game when time expires
  1579. if ( m_flPausedTimeEnd >= 0.f && m_State == ss_paused && Sys_FloatTime() >= m_flPausedTimeEnd )
  1580. {
  1581. SetPausedForced( false );
  1582. }
  1583. }
  1584. //-----------------------------------------------------------------------------
  1585. // Purpose:
  1586. // Input : *adr -
  1587. // *pslot -
  1588. // **ppClient -
  1589. // Output : int
  1590. //-----------------------------------------------------------------------------
  1591. CBaseClient * CBaseServer::GetFreeClient( netadr_t &adr )
  1592. {
  1593. CBaseClient *freeclient = NULL;
  1594. for ( int slot = 0 ; slot < m_Clients.Count() ; slot++ )
  1595. {
  1596. CBaseClient *client = m_Clients[slot];
  1597. if ( client->IsFakeClient() )
  1598. continue;
  1599. if ( client->IsConnected() )
  1600. {
  1601. if ( adr.CompareAdr ( client->m_NetChannel->GetRemoteAddress() ) )
  1602. {
  1603. ConMsg ( "%s:reconnect\n", adr.ToString() );
  1604. RemoveClientFromGame( client );
  1605. // perform a silent netchannel shutdown, don't send disconnect msg
  1606. client->m_NetChannel->Shutdown( NULL );
  1607. client->m_NetChannel = NULL;
  1608. client->Clear();
  1609. return client;
  1610. }
  1611. }
  1612. else
  1613. {
  1614. // use first found free slot
  1615. if ( !freeclient )
  1616. {
  1617. freeclient = client;
  1618. }
  1619. }
  1620. }
  1621. if ( !freeclient )
  1622. {
  1623. int count = m_Clients.Count();
  1624. if ( count >= m_nMaxclients )
  1625. {
  1626. return NULL; // server full
  1627. }
  1628. // we have to create a new client slot
  1629. freeclient = CreateNewClient( count );
  1630. m_Clients.AddToTail( freeclient );
  1631. }
  1632. // Success
  1633. return freeclient;
  1634. }
  1635. void CBaseServer::SendClientMessages ( bool bSendSnapshots )
  1636. {
  1637. VPROF_BUDGET( "SendClientMessages", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1638. for (int i=0; i< m_Clients.Count(); i++ )
  1639. {
  1640. CBaseClient* client = m_Clients[i];
  1641. // Update Host client send state...
  1642. if ( !client->ShouldSendMessages() )
  1643. continue;
  1644. // Connected, but inactive, just send reliable, sequenced info.
  1645. if ( client->m_NetChannel )
  1646. {
  1647. client->m_NetChannel->Transmit();
  1648. client->UpdateSendState();
  1649. }
  1650. else
  1651. {
  1652. Msg("Client has no netchannel.\n");
  1653. }
  1654. }
  1655. }
  1656. CBaseClient *CBaseServer::CreateFakeClient( const char *name )
  1657. {
  1658. netadr_t adr; // it's an empty address
  1659. CBaseClient *fakeclient = GetFreeClient( adr );
  1660. if ( !fakeclient )
  1661. {
  1662. // server is full
  1663. return NULL;
  1664. }
  1665. INetChannel *netchan = NULL;
  1666. if ( sv_stressbots.GetBool() )
  1667. {
  1668. netadr_t adrNull( 0, 0 ); // 0.0.0.0:0 signifies a bot. It'll plumb all the way down to winsock calls but it won't make them.
  1669. netchan = NET_CreateNetChannel( m_Socket, &adrNull, adrNull.ToString(), fakeclient, true );
  1670. }
  1671. // a NULL netchannel signals a fakeclient
  1672. m_nUserid = GetNextUserID();
  1673. m_nNumConnections++;
  1674. fakeclient->SetReportThisFakeClient( m_bReportNewFakeClients );
  1675. fakeclient->Connect( name, m_nUserid, netchan, true, 0 );
  1676. // fake some cvar settings
  1677. //fakeclient->SetUserCVar( "name", name ); // set already by Connect()
  1678. fakeclient->SetUserCVar( "rate", "30000" );
  1679. fakeclient->SetUserCVar( "cl_updaterate", "20" );
  1680. fakeclient->SetUserCVar( "cl_interp_ratio", "1.0" );
  1681. fakeclient->SetUserCVar( "cl_interp", "0.1" );
  1682. fakeclient->SetUserCVar( "cl_interpolate", "0" );
  1683. fakeclient->SetUserCVar( "cl_predict", "1" );
  1684. fakeclient->SetUserCVar( "cl_predictweapons", "1" );
  1685. fakeclient->SetUserCVar( "cl_lagcompensation", "1" );
  1686. fakeclient->SetUserCVar( "closecaption","0" );
  1687. fakeclient->SetUserCVar( "english", "1" );
  1688. fakeclient->SetUserCVar( "cl_clanid", "0" );
  1689. fakeclient->SetUserCVar( "cl_team", "blue" );
  1690. fakeclient->SetUserCVar( "hud_classautokill", "1" );
  1691. fakeclient->SetUserCVar( "tf_medigun_autoheal", "0" );
  1692. fakeclient->SetUserCVar( "cl_autorezoom", "1" );
  1693. fakeclient->SetUserCVar( "fov_desired", "75" );
  1694. fakeclient->SetUserCVar( "tf_remember_lastswitched", "0" );
  1695. fakeclient->SetUserCVar( "cl_autoreload", "0" );
  1696. fakeclient->SetUserCVar( "tf_remember_activeweapon", "0" );
  1697. fakeclient->SetUserCVar( "hud_combattext", "0" );
  1698. fakeclient->SetUserCVar( "cl_flipviewmodels", "0" );
  1699. // create client in game.dll
  1700. fakeclient->ActivatePlayer();
  1701. fakeclient->m_nSignonTick = m_nTickCount;
  1702. return fakeclient;
  1703. }
  1704. void CBaseServer::Shutdown( void )
  1705. {
  1706. if ( !IsActive() )
  1707. return;
  1708. m_State = ss_dead;
  1709. // Only drop clients if we have not cleared out entity data prior to this.
  1710. for( int i=m_Clients.Count()-1; i>=0; i-- )
  1711. {
  1712. CBaseClient * cl = m_Clients[ i ];
  1713. if ( cl->IsConnected() )
  1714. {
  1715. cl->Disconnect( "Server shutting down" );
  1716. }
  1717. else
  1718. {
  1719. // free any memory do this out side here in case the reason the server is shutting down
  1720. // is because the listen server client typed disconnect, in which case we won't call
  1721. // cl->DropClient, but the client might have some frame snapshot references left over, etc.
  1722. cl->Clear();
  1723. }
  1724. delete cl;
  1725. m_Clients.Remove( i );
  1726. }
  1727. // Let drop messages go out
  1728. Sys_Sleep( 100 );
  1729. // clear everything
  1730. Clear();
  1731. }
  1732. //-----------------------------------------------------------------------------
  1733. // Purpose: Sends text to all active clients
  1734. // Input : *fmt -
  1735. // ... -
  1736. //-----------------------------------------------------------------------------
  1737. void CBaseServer::BroadcastPrintf (const char *fmt, ...)
  1738. {
  1739. va_list argptr;
  1740. char string[1024];
  1741. va_start (argptr,fmt);
  1742. Q_vsnprintf (string, sizeof( string ), fmt,argptr);
  1743. va_end (argptr);
  1744. SVC_Print print( string );
  1745. BroadcastMessage( print );
  1746. }
  1747. void CBaseServer::BroadcastMessage( INetMessage &msg, bool onlyActive, bool reliable )
  1748. {
  1749. for ( int i = 0; i < m_Clients.Count(); i++ )
  1750. {
  1751. CBaseClient *cl = m_Clients[ i ];
  1752. if ( (onlyActive && !cl->IsActive()) || !cl->IsSpawned() )
  1753. {
  1754. continue;
  1755. }
  1756. if ( !cl->SendNetMsg( msg, reliable ) )
  1757. {
  1758. if ( msg.IsReliable() || reliable )
  1759. {
  1760. DevMsg( "BroadcastMessage: Reliable broadcast message overflow for client %s", cl->GetClientName() );
  1761. }
  1762. }
  1763. }
  1764. }
  1765. void CBaseServer::BroadcastMessage( INetMessage &msg, IRecipientFilter &filter )
  1766. {
  1767. if ( filter.IsInitMessage() )
  1768. {
  1769. // This really only applies to the first player to connect, but that works in single player well enought
  1770. if ( IsActive() )
  1771. {
  1772. ConDMsg( "SV_BroadcastMessage: Init message being created after signon buffer has been transmitted\n" );
  1773. }
  1774. if ( !msg.WriteToBuffer( m_Signon ) )
  1775. {
  1776. Sys_Error( "SV_BroadcastMessage: Init message would overflow signon buffer!\n" );
  1777. return;
  1778. }
  1779. }
  1780. else
  1781. {
  1782. msg.SetReliable( filter.IsReliable() );
  1783. int num = filter.GetRecipientCount();
  1784. for ( int i = 0; i < num; i++ )
  1785. {
  1786. int index = filter.GetRecipientIndex( i );
  1787. if ( index < 1 || index > m_Clients.Count() )
  1788. {
  1789. Msg( "SV_BroadcastMessage: Recipient Filter for message type %i (reliable: %s, init: %s) with bogus client index (%i) in list of %i clients\n",
  1790. msg.GetType(),
  1791. filter.IsReliable() ? "yes" : "no",
  1792. filter.IsInitMessage() ? "yes" : "no",
  1793. index, num );
  1794. if ( msg.IsReliable() )
  1795. Host_Error( "Reliable message (type %i) discarded.", msg.GetType() );
  1796. continue;
  1797. }
  1798. CBaseClient *cl = m_Clients[ index - 1 ];
  1799. if ( !cl->IsSpawned() )
  1800. {
  1801. continue;
  1802. }
  1803. if ( !cl->SendNetMsg( msg ) )
  1804. {
  1805. if ( msg.IsReliable() )
  1806. {
  1807. DevMsg( "BroadcastMessage: Reliable filter message overflow for client %s", cl->GetClientName() );
  1808. }
  1809. }
  1810. }
  1811. }
  1812. }
  1813. //-----------------------------------------------------------------------------
  1814. // Purpose: Writes events to the client's network buffer
  1815. // Input : *cl -
  1816. // *pack -
  1817. // *msg -
  1818. //-----------------------------------------------------------------------------
  1819. static ConVar sv_debugtempentities( "sv_debugtempentities", "0", 0, "Show temp entity bandwidth usage." );
  1820. static bool CEventInfo_LessFunc( CEventInfo * const &lhs, CEventInfo * const &rhs )
  1821. {
  1822. return lhs->classID < rhs->classID;
  1823. }
  1824. void CBaseServer::WriteTempEntities( CBaseClient *client, CFrameSnapshot *pCurrentSnapshot, CFrameSnapshot *pLastSnapshot, bf_write &buf, int ev_max )
  1825. {
  1826. VPROF_BUDGET( "CBaseServer::WriteTempEntities", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1827. ALIGN4 char data[NET_MAX_PAYLOAD] ALIGN4_POST;
  1828. SVC_TempEntities msg;
  1829. msg.m_DataOut.StartWriting( data, sizeof(data) );
  1830. bf_write &buffer = msg.m_DataOut; // shortcut
  1831. CFrameSnapshot *pSnapshot;
  1832. CEventInfo *pLastEvent = NULL;
  1833. bool bDebug = sv_debugtempentities.GetBool();
  1834. // limit max entities to field bit length
  1835. ev_max = min( ev_max, ((1<<CEventInfo::EVENT_INDEX_BITS)-1) );
  1836. if ( pLastSnapshot )
  1837. {
  1838. pSnapshot = pLastSnapshot->NextSnapshot();
  1839. }
  1840. else
  1841. {
  1842. pSnapshot = pCurrentSnapshot;
  1843. }
  1844. CUtlRBTree< CEventInfo * > sorted( 0, ev_max, CEventInfo_LessFunc );
  1845. // Build list of events sorted by send table classID (makes the delta work better in cases with a lot of the same message type )
  1846. while ( pSnapshot && ((int)sorted.Count() < ev_max) )
  1847. {
  1848. for( int i = 0; i < pSnapshot->m_nTempEntities; ++i )
  1849. {
  1850. CEventInfo *event = pSnapshot->m_pTempEntities[ i ];
  1851. if ( client->IgnoreTempEntity( event ) )
  1852. continue; // event is not seen by this player
  1853. sorted.Insert( event );
  1854. // More space still
  1855. if ( (int)sorted.Count() >= ev_max )
  1856. break;
  1857. }
  1858. // stop, we reached our current snapshot
  1859. if ( pSnapshot == pCurrentSnapshot )
  1860. break;
  1861. // got to next snapshot
  1862. pSnapshot = framesnapshotmanager->NextSnapshot( pSnapshot );
  1863. }
  1864. if ( sorted.Count() <= 0 )
  1865. return;
  1866. for ( int i = sorted.FirstInorder();
  1867. i != sorted.InvalidIndex();
  1868. i = sorted.NextInorder( i ) )
  1869. {
  1870. CEventInfo *event = sorted[ i ];
  1871. if ( event->fire_delay == 0.0f )
  1872. {
  1873. buffer.WriteOneBit( 0 );
  1874. }
  1875. else
  1876. {
  1877. buffer.WriteOneBit( 1 );
  1878. buffer.WriteSBitLong( event->fire_delay*100.0f, 8 );
  1879. }
  1880. if ( pLastEvent &&
  1881. pLastEvent->classID == event->classID )
  1882. {
  1883. buffer.WriteOneBit( 0 ); // delta against last temp entity
  1884. int startBit = bDebug ? buffer.GetNumBitsWritten() : 0;
  1885. SendTable_WriteAllDeltaProps( event->pSendTable,
  1886. pLastEvent->pData,
  1887. pLastEvent->bits,
  1888. event->pData,
  1889. event->bits,
  1890. -1,
  1891. &buffer );
  1892. if ( bDebug )
  1893. {
  1894. int length = buffer.GetNumBitsWritten() - startBit;
  1895. DevMsg("TE %s delta bits: %i\n", event->pSendTable->GetName(), length );
  1896. }
  1897. }
  1898. else
  1899. {
  1900. // full update, just compressed against zeros in MP
  1901. buffer.WriteOneBit( 1 );
  1902. int startBit = bDebug ? buffer.GetNumBitsWritten() : 0;
  1903. buffer.WriteUBitLong( event->classID, GetClassBits() );
  1904. if ( IsMultiplayer() )
  1905. {
  1906. SendTable_WriteAllDeltaProps( event->pSendTable,
  1907. NULL, // will write only non-zero elements
  1908. 0,
  1909. event->pData,
  1910. event->bits,
  1911. -1,
  1912. &buffer );
  1913. }
  1914. else
  1915. {
  1916. // write event with zero properties
  1917. buffer.WriteBits( event->pData, event->bits );
  1918. }
  1919. if ( bDebug )
  1920. {
  1921. int length = buffer.GetNumBitsWritten() - startBit;
  1922. DevMsg("TE %s full bits: %i\n", event->pSendTable->GetName(), length );
  1923. }
  1924. }
  1925. if ( IsMultiplayer() )
  1926. {
  1927. // in single player, don't used delta compression, lastEvent remains NULL
  1928. pLastEvent = event;
  1929. }
  1930. }
  1931. // set num entries
  1932. msg.m_nNumEntries = sorted.Count();
  1933. msg.WriteToBuffer( buf );
  1934. }
  1935. void CBaseServer::SetMaxClients( int number )
  1936. {
  1937. m_nMaxclients = clamp( number, 1, ABSOLUTE_PLAYER_LIMIT );
  1938. }
  1939. extern ConVar tv_enable;
  1940. //-----------------------------------------------------------------------------
  1941. // Purpose:
  1942. //-----------------------------------------------------------------------------
  1943. void CBaseServer::RecalculateTags( void )
  1944. {
  1945. if ( IsHLTV() || IsReplay() )
  1946. return;
  1947. // We're going to modify the sv_tags convar here, which will cause this to be called again. Prevent recursion.
  1948. static bool bRecalculatingTags = false;
  1949. if ( bRecalculatingTags )
  1950. return;
  1951. bRecalculatingTags = true;
  1952. // Games without this interface will have no tagged cvars besides "increased_maxplayers"
  1953. if ( serverGameTags )
  1954. {
  1955. KeyValues *pKV = new KeyValues( "GameTags" );
  1956. serverGameTags->GetTaggedConVarList( pKV );
  1957. KeyValues *p = pKV->GetFirstSubKey();
  1958. while ( p )
  1959. {
  1960. ConVar *pConVar = g_pCVar->FindVar( p->GetString("convar") );
  1961. if ( pConVar )
  1962. {
  1963. const char *pszDef = pConVar->GetDefault();
  1964. const char *pszCur = pConVar->GetString();
  1965. if ( Q_strcmp( pszDef, pszCur ) )
  1966. {
  1967. AddTag( p->GetString("tag") );
  1968. }
  1969. else
  1970. {
  1971. RemoveTag( p->GetString("tag") );
  1972. }
  1973. }
  1974. p = p->GetNextKey();
  1975. }
  1976. pKV->deleteThis();
  1977. }
  1978. // Check maxplayers
  1979. int minmaxplayers = 1;
  1980. int maxmaxplayers = ABSOLUTE_PLAYER_LIMIT;
  1981. int defaultmaxplayers = 1;
  1982. serverGameClients->GetPlayerLimits( minmaxplayers, maxmaxplayers, defaultmaxplayers );
  1983. int nMaxReportedClients = GetMaxClients() - GetNumProxies();
  1984. if ( sv_visiblemaxplayers.GetInt() > 0 && sv_visiblemaxplayers.GetInt() < nMaxReportedClients )
  1985. {
  1986. nMaxReportedClients = sv_visiblemaxplayers.GetInt();
  1987. }
  1988. if ( nMaxReportedClients > defaultmaxplayers )
  1989. {
  1990. AddTag( "increased_maxplayers" );
  1991. }
  1992. else
  1993. {
  1994. RemoveTag( "increased_maxplayers" );
  1995. }
  1996. #if defined( REPLAY_ENABLED )
  1997. ConVarRef replay_enable( "replay_enable", true );
  1998. if ( replay_enable.IsValid() && replay_enable.GetBool() )
  1999. {
  2000. AddTag( "replays" );
  2001. }
  2002. else
  2003. {
  2004. RemoveTag( "replays" );
  2005. }
  2006. #endif
  2007. bRecalculatingTags = false;
  2008. }
  2009. //-----------------------------------------------------------------------------
  2010. // Purpose:
  2011. //-----------------------------------------------------------------------------
  2012. void CBaseServer::AddTag( const char *pszTag )
  2013. {
  2014. CUtlVector<char*> TagList;
  2015. V_SplitString( sv_tags.GetString(), ",", TagList );
  2016. for ( int i = 0; i < TagList.Count(); i++ )
  2017. {
  2018. // Already in the tag list?
  2019. if ( !Q_stricmp(TagList[i],pszTag) )
  2020. return;
  2021. }
  2022. TagList.PurgeAndDeleteElements();
  2023. // Append it
  2024. char tmptags[MAX_TAG_STRING_LENGTH];
  2025. tmptags[0] = '\0';
  2026. Q_strncpy( tmptags, pszTag, MAX_TAG_STRING_LENGTH );
  2027. Q_strncat( tmptags, ",", MAX_TAG_STRING_LENGTH );
  2028. Q_strncat( tmptags, sv_tags.GetString(), MAX_TAG_STRING_LENGTH );
  2029. sv_tags.SetValue( tmptags );
  2030. }
  2031. //-----------------------------------------------------------------------------
  2032. // Purpose:
  2033. //-----------------------------------------------------------------------------
  2034. void CBaseServer::RemoveTag( const char *pszTag )
  2035. {
  2036. const char *pszTags = sv_tags.GetString();
  2037. if ( !pszTags || !pszTags[0] )
  2038. return;
  2039. char tmptags[MAX_TAG_STRING_LENGTH];
  2040. tmptags[0] = '\0';
  2041. CUtlVector<char*> TagList;
  2042. bool bFoundIt = false;
  2043. V_SplitString( sv_tags.GetString(), ",", TagList );
  2044. for ( int i = 0; i < TagList.Count(); i++ )
  2045. {
  2046. // Keep any tags other than the specified one
  2047. if ( Q_stricmp(TagList[i],pszTag) )
  2048. {
  2049. Q_strncat( tmptags, TagList[i], MAX_TAG_STRING_LENGTH );
  2050. Q_strncat( tmptags, ",", MAX_TAG_STRING_LENGTH );
  2051. }
  2052. else
  2053. {
  2054. bFoundIt = true;
  2055. }
  2056. }
  2057. TagList.PurgeAndDeleteElements();
  2058. // Didn't find it in our list?
  2059. if ( !bFoundIt )
  2060. return;
  2061. sv_tags.SetValue( tmptags );
  2062. }
  2063. //-----------------------------------------------------------------------------
  2064. // Purpose: Server-only override (ignores sv_pausable). Can be on a timer.
  2065. //-----------------------------------------------------------------------------
  2066. void CBaseServer::SetPausedForced( bool bPaused, float flDuration /*= -1.f*/ )
  2067. {
  2068. if ( !IsActive() )
  2069. return;
  2070. m_State = ( bPaused ) ? ss_paused : ss_active;
  2071. m_flPausedTimeEnd = ( bPaused && flDuration > 0.f ) ? Sys_FloatTime() + flDuration : -1.f;
  2072. SVC_SetPauseTimed setpause( bPaused, m_flPausedTimeEnd );
  2073. BroadcastMessage( setpause );
  2074. }