Advertisement
jxsl13

Untitled

Aug 22nd, 2015
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 69.61 KB | None | 0 0
  1. /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
  2. /* If you are missing that file, acquire a complete release at teeworlds.com. */
  3. /* Modified by Teelevision for zCatch/TeeVi, see readme.txt and license.txt. */
  4.  
  5. #include <base/math.h>
  6. #include <base/system.h>
  7.  
  8. #include <engine/config.h>
  9. #include <engine/console.h>
  10. #include <engine/engine.h>
  11. #include <engine/map.h>
  12. #include <engine/masterserver.h>
  13. #include <engine/server.h>
  14. #include <engine/storage.h>
  15.  
  16. #include <engine/shared/compression.h>
  17. #include <engine/shared/config.h>
  18. #include <engine/shared/datafile.h>
  19. #include <engine/shared/demo.h>
  20. #include <engine/shared/econ.h>
  21. #include <engine/shared/filecollection.h>
  22. #include <engine/shared/mapchecker.h>
  23. #include <engine/shared/netban.h>
  24. #include <engine/shared/network.h>
  25. #include <engine/shared/packer.h>
  26. #include <engine/shared/protocol.h>
  27. #include <engine/shared/snapshot.h>
  28.  
  29. #include <mastersrv/mastersrv.h>
  30.  
  31. #include "register.h"
  32. #include "server.h"
  33.  
  34. #include <string.h>
  35. #include <string>
  36. #include <map>
  37.  
  38. #include <ctime>
  39. #include <cstdio>
  40.  
  41.  
  42. #if defined(CONF_FAMILY_WINDOWS)
  43. #define _WIN32_WINNT 0x0501
  44. #define WIN32_LEAN_AND_MEAN
  45. #include <windows.h>
  46. #endif
  47.  
  48.  
  49.  
  50. const std::string currentDateTime() {
  51. time_t currentTime;
  52. struct tm *localTime;
  53.  
  54. time( &currentTime ); // Get the current time
  55. localTime = localtime( &currentTime ); // Convert the current time to the local time
  56.  
  57.  
  58.  
  59. char timeBuf[512];
  60. strftime(timeBuf, sizeof(timeBuf), "%H:%M:%S %d.%m.%Y", localTime);
  61. //str_format(timeBuf, sizeof(timeBuf), "%d:%d:%d %d.%d.%d", Hour, Min, Sec, Day, Month, Year);
  62.  
  63. return timeBuf;
  64. }
  65.  
  66.  
  67.  
  68. static const char *StrUTF8Ltrim(const char *pStr)
  69. {
  70. while(*pStr)
  71. {
  72. const char *pStrOld = pStr;
  73. int Code = str_utf8_decode(&pStr);
  74.  
  75. // check if unicode is not empty
  76. if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
  77. (Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
  78. Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
  79. {
  80. return pStrOld;
  81. }
  82. }
  83. return pStr;
  84. }
  85.  
  86. static void StrUTF8Rtrim(char *pStr)
  87. {
  88. const char *p = pStr;
  89. const char *pEnd = 0;
  90. while(*p)
  91. {
  92. const char *pStrOld = p;
  93. int Code = str_utf8_decode(&p);
  94.  
  95. // check if unicode is not empty
  96. if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
  97. (Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
  98. Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
  99. {
  100. pEnd = 0;
  101. }
  102. else if(pEnd == 0)
  103. pEnd = pStrOld;
  104. }
  105. if(pEnd != 0)
  106. *(const_cast<char *>(pEnd)) = 0;
  107. }
  108.  
  109.  
  110. CSnapIDPool::CSnapIDPool()
  111. {
  112. Reset();
  113. }
  114.  
  115. void CSnapIDPool::Reset()
  116. {
  117. for(int i = 0; i < MAX_IDS; i++)
  118. {
  119. m_aIDs[i].m_Next = i+1;
  120. m_aIDs[i].m_State = 0;
  121. }
  122.  
  123. m_aIDs[MAX_IDS-1].m_Next = -1;
  124. m_FirstFree = 0;
  125. m_FirstTimed = -1;
  126. m_LastTimed = -1;
  127. m_Usage = 0;
  128. m_InUsage = 0;
  129. }
  130.  
  131.  
  132. void CSnapIDPool::RemoveFirstTimeout()
  133. {
  134. int NextTimed = m_aIDs[m_FirstTimed].m_Next;
  135.  
  136. // add it to the free list
  137. m_aIDs[m_FirstTimed].m_Next = m_FirstFree;
  138. m_aIDs[m_FirstTimed].m_State = 0;
  139. m_FirstFree = m_FirstTimed;
  140.  
  141. // remove it from the timed list
  142. m_FirstTimed = NextTimed;
  143. if(m_FirstTimed == -1)
  144. m_LastTimed = -1;
  145.  
  146. m_Usage--;
  147. }
  148.  
  149. int CSnapIDPool::NewID()
  150. {
  151. int64 Now = time_get();
  152.  
  153. // process timed ids
  154. while(m_FirstTimed != -1 && m_aIDs[m_FirstTimed].m_Timeout < Now)
  155. RemoveFirstTimeout();
  156.  
  157. int ID = m_FirstFree;
  158. dbg_assert(ID != -1, "id error");
  159. if(ID == -1)
  160. return ID;
  161. m_FirstFree = m_aIDs[m_FirstFree].m_Next;
  162. m_aIDs[ID].m_State = 1;
  163. m_Usage++;
  164. m_InUsage++;
  165. return ID;
  166. }
  167.  
  168. void CSnapIDPool::TimeoutIDs()
  169. {
  170. // process timed ids
  171. while(m_FirstTimed != -1)
  172. RemoveFirstTimeout();
  173. }
  174.  
  175. void CSnapIDPool::FreeID(int ID)
  176. {
  177. if(ID < 0)
  178. return;
  179. dbg_assert(m_aIDs[ID].m_State == 1, "id is not alloced");
  180.  
  181. m_InUsage--;
  182. m_aIDs[ID].m_State = 2;
  183. m_aIDs[ID].m_Timeout = time_get()+time_freq()*5;
  184. m_aIDs[ID].m_Next = -1;
  185.  
  186. if(m_LastTimed != -1)
  187. {
  188. m_aIDs[m_LastTimed].m_Next = ID;
  189. m_LastTimed = ID;
  190. }
  191. else
  192. {
  193. m_FirstTimed = ID;
  194. m_LastTimed = ID;
  195. }
  196. }
  197.  
  198.  
  199. void CServerBan::InitServerBan(IConsole *pConsole, IStorage *pStorage, CServer* pServer)
  200. {
  201. CNetBan::Init(pConsole, pStorage);
  202.  
  203. m_pServer = pServer;
  204.  
  205. // overwrites base command, todo: improve this
  206. Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBanExt, this, "Ban player with ip/client id for x minutes for any reason");
  207. }
  208.  
  209. template<class T>
  210. int CServerBan::BanExt(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason)
  211. {
  212. // validate address
  213. if(Server()->m_RconClientID >= 0 && Server()->m_RconClientID < MAX_CLIENTS &&
  214. Server()->m_aClients[Server()->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY)
  215. {
  216. if(NetMatch(pData, Server()->m_NetServer.ClientAddr(Server()->m_RconClientID)))
  217. {
  218. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (you can't ban yourself)");
  219. return -1;
  220. }
  221.  
  222. for(int i = 0; i < MAX_CLIENTS; ++i)
  223. {
  224. if(i == Server()->m_RconClientID || Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
  225. continue;
  226.  
  227. if(Server()->m_aClients[i].m_Authed >= Server()->m_RconAuthLevel && NetMatch(pData, Server()->m_NetServer.ClientAddr(i)))
  228. {
  229. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (command denied)");
  230. return -1;
  231. }
  232. }
  233. }
  234. else if(Server()->m_RconClientID == IServer::RCON_CID_VOTE)
  235. {
  236. for(int i = 0; i < MAX_CLIENTS; ++i)
  237. {
  238. if(Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
  239. continue;
  240.  
  241. if(Server()->m_aClients[i].m_Authed != CServer::AUTHED_NO && NetMatch(pData, Server()->m_NetServer.ClientAddr(i)))
  242. {
  243. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (command denied)");
  244. return -1;
  245. }
  246. }
  247. }
  248.  
  249. int Result = Ban(pBanPool, pData, Seconds, pReason);
  250. if(Result != 0)
  251. return Result;
  252.  
  253. // drop banned clients
  254. typename T::CDataType Data = *pData;
  255. for(int i = 0; i < MAX_CLIENTS; ++i)
  256. {
  257. if(Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
  258. continue;
  259.  
  260. if(NetMatch(&Data, Server()->m_NetServer.ClientAddr(i)))
  261. {
  262. CNetHash NetHash(&Data);
  263. char aBuf[256];
  264. MakeBanInfo(pBanPool->Find(&Data, &NetHash), aBuf, sizeof(aBuf), MSGTYPE_PLAYER);
  265. Server()->m_NetServer.Drop(i, aBuf);
  266. }
  267. }
  268.  
  269. return Result;
  270. }
  271.  
  272. int CServerBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason)
  273. {
  274. return BanExt(&m_BanAddrPool, pAddr, Seconds, pReason);
  275. }
  276.  
  277. int CServerBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason)
  278. {
  279. if(pRange->IsValid())
  280. return BanExt(&m_BanRangePool, pRange, Seconds, pReason);
  281.  
  282. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)");
  283. return -1;
  284. }
  285.  
  286. void CServerBan::ConBanExt(IConsole::IResult *pResult, void *pUser)
  287. {
  288. CServerBan *pThis = static_cast<CServerBan *>(pUser);
  289. const int defaultMinutes = 5;
  290.  
  291. const char *pStr = pResult->GetString(0);
  292. int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : defaultMinutes;
  293. const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given";
  294.  
  295. // check if time was given or a reason instead
  296. const char *time;
  297. if(pResult->NumArguments() > 1)
  298. {
  299. // check if number given
  300. time = pResult->GetString(1);
  301. int i = str_length(time) - 1;
  302. for(; i >= 0; --i)
  303. if(time[i] < '0' || '9' < time[i])
  304. break;
  305. // in case that no number was given
  306. if(!(str_length(time) && i < 0))
  307. {
  308. Minutes = defaultMinutes;
  309. if(pResult->NumArguments() > 2)
  310. { // add to reason
  311. char *newReason = (char*)malloc(sizeof(char) * (str_length(time) + str_length(pReason) + 2));
  312. mem_copy(newReason, time, sizeof(char) * str_length(time));
  313. newReason[str_length(time)] = ' ';
  314. mem_copy(newReason + str_length(time) + 1, pReason, sizeof(char) * (str_length(pReason) + 1));
  315. pReason = newReason;
  316. }
  317. else
  318. { // the time is the actual reason
  319. pReason = time;
  320. }
  321. }
  322. }
  323.  
  324. int CID = -1;
  325. if(StrAllnum(pStr))
  326. CID = str_toint(pStr);
  327. else
  328. {
  329. NETADDR Addr;
  330. if(net_addr_from_str(&Addr, pStr) == 0)
  331. for(int i = 0; i < MAX_CLIENTS; i++)
  332. if(pThis->NetMatch(&Addr, pThis->Server()->m_NetServer.ClientAddr(i)))
  333. {
  334. CID = i;
  335. break;
  336. }
  337. }
  338.  
  339. if(StrAllnum(pStr))
  340. {
  341. int ClientID = str_toint(pStr);
  342. if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->Server()->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  343. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid client id)");
  344. else
  345. pThis->BanAddr(pThis->Server()->m_NetServer.ClientAddr(ClientID), Minutes*60, pReason);
  346. }
  347. else
  348. ConBan(pResult, pUser);
  349. }
  350.  
  351.  
  352. void CServer::CClient::Reset()
  353. {
  354. // reset input
  355. for(int i = 0; i < 200; i++)
  356. m_aInputs[i].m_GameTick = -1;
  357. m_CurrentInput = 0;
  358. mem_zero(&m_LatestInput, sizeof(m_LatestInput));
  359.  
  360. m_Snapshots.PurgeAll();
  361. m_LastAckedSnapshot = -1;
  362. m_LastInputTick = -1;
  363. m_SnapRate = CClient::SNAPRATE_INIT;
  364. m_Score = 0;
  365. }
  366.  
  367. CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
  368. {
  369. m_TickSpeed = SERVER_TICK_SPEED;
  370.  
  371. m_pGameServer = 0;
  372.  
  373. m_CurrentGameTick = 0;
  374. m_RunServer = 1;
  375.  
  376. m_pCurrentMapData = 0;
  377. m_CurrentMapSize = 0;
  378.  
  379. m_MapReload = 0;
  380.  
  381. m_RconClientID = IServer::RCON_CID_SERV;
  382. m_RconAuthLevel = AUTHED_SUBADMIN;
  383.  
  384. // when starting there are no admins
  385. m_numLoggedInAdmins = 0;
  386.  
  387. m_Votebans = NULL;
  388. m_InfoTexts = NULL;
  389. m_InfoTextInterval = -1;
  390.  
  391. Init();
  392. }
  393.  
  394. CServer::~CServer()
  395. {
  396. // delte votebans
  397. while(m_Votebans != NULL)
  398. {
  399. CVoteban *tmp = m_Votebans->m_Next;
  400. delete m_Votebans;
  401. m_Votebans = tmp;
  402. }
  403.  
  404. // delte info texts
  405. while(m_InfoTexts != NULL)
  406. {
  407. CInfoText *tmp = m_InfoTexts->m_Next;
  408. delete m_InfoTexts;
  409. m_InfoTexts = tmp;
  410. }
  411. }
  412.  
  413.  
  414. void CServer::UpdateLoggedInAdmins()
  415. {
  416. bool gotAny = (m_numLoggedInAdmins > 0);
  417. m_numLoggedInAdmins = 0;
  418. for(int i = 0; i < MAX_CLIENTS; ++i)
  419. {
  420. if(m_aClients[i].m_State == CClient::STATE_INGAME && m_aClients[i].m_Authed >= AUTHED_SUBADMIN)
  421. {
  422. ++m_numLoggedInAdmins;
  423. }
  424. }
  425. if(gotAny != (m_numLoggedInAdmins > 0))
  426. {
  427. UpdateServerInfo();
  428. }
  429. }
  430.  
  431. int CServer::TrySetClientName(int ClientID, const char *pName)
  432. {
  433. char aTrimmedName[64];
  434.  
  435. // trim the name
  436. str_copy(aTrimmedName, StrUTF8Ltrim(pName), sizeof(aTrimmedName));
  437. StrUTF8Rtrim(aTrimmedName);
  438.  
  439. // check if new and old name are the same
  440. if(m_aClients[ClientID].m_aName[0] && str_comp(m_aClients[ClientID].m_aName, aTrimmedName) == 0)
  441. return 0;
  442.  
  443. char aBuf[256];
  444. str_format(aBuf, sizeof(aBuf), "'%s' -> '%s'", pName, aTrimmedName);
  445. Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
  446. pName = aTrimmedName;
  447.  
  448.  
  449. // check for empty names
  450. if(!pName[0])
  451. return -1;
  452.  
  453. // make sure that two clients doesn't have the same name
  454. for(int i = 0; i < MAX_CLIENTS; i++)
  455. if(i != ClientID && m_aClients[i].m_State >= CClient::STATE_READY)
  456. {
  457. if(str_comp(pName, m_aClients[i].m_aName) == 0)
  458. return -1;
  459. }
  460.  
  461. // set the client name
  462. str_copy(m_aClients[ClientID].m_aName, pName, MAX_NAME_LENGTH);
  463. return 0;
  464. }
  465.  
  466.  
  467.  
  468. void CServer::SetClientName(int ClientID, const char *pName)
  469. {
  470. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
  471. return;
  472.  
  473. if(!pName)
  474. return;
  475.  
  476. char aNameTry[MAX_NAME_LENGTH];
  477. str_copy(aNameTry, pName, MAX_NAME_LENGTH);
  478. if(TrySetClientName(ClientID, aNameTry))
  479. {
  480. // auto rename
  481. for(int i = 1;; i++)
  482. {
  483. str_format(aNameTry, MAX_NAME_LENGTH, "(%d)%s", i, pName);
  484. if(TrySetClientName(ClientID, aNameTry) == 0)
  485. break;
  486. }
  487. }
  488. }
  489.  
  490. void CServer::SetClientClan(int ClientID, const char *pClan)
  491. {
  492. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY || !pClan)
  493. return;
  494.  
  495. str_copy(m_aClients[ClientID].m_aClan, pClan, MAX_CLAN_LENGTH);
  496. }
  497.  
  498. void CServer::SetClientCountry(int ClientID, int Country)
  499. {
  500. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
  501. return;
  502.  
  503. m_aClients[ClientID].m_Country = Country;
  504. }
  505.  
  506. void CServer::SetClientScore(int ClientID, int Score)
  507. {
  508. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY)
  509. return;
  510. m_aClients[ClientID].m_Score = Score;
  511. }
  512.  
  513. void CServer::Kick(int ClientID, const char *pReason)
  514. {
  515. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State == CClient::STATE_EMPTY)
  516. {
  517. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid client id to kick");
  518. return;
  519. }
  520. else if(m_RconClientID == ClientID)
  521. {
  522. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't kick yourself");
  523. return;
  524. }
  525. else if(m_aClients[ClientID].m_Authed > m_RconAuthLevel)
  526. {
  527. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "kick command denied");
  528. return;
  529. }
  530.  
  531. m_NetServer.Drop(ClientID, pReason);
  532. }
  533.  
  534. /*int CServer::Tick()
  535. {
  536. return m_CurrentGameTick;
  537. }*/
  538.  
  539. int64 CServer::TickStartTime(int Tick)
  540. {
  541. return m_GameStartTime + (time_freq()*Tick)/SERVER_TICK_SPEED;
  542. }
  543.  
  544. /*int CServer::TickSpeed()
  545. {
  546. return SERVER_TICK_SPEED;
  547. }*/
  548.  
  549. int CServer::Init()
  550. {
  551. for(int i = 0; i < MAX_CLIENTS; i++)
  552. {
  553. m_aClients[i].m_State = CClient::STATE_EMPTY;
  554. m_aClients[i].m_aName[0] = 0;
  555. m_aClients[i].m_aClan[0] = 0;
  556. m_aClients[i].m_Country = -1;
  557. m_aClients[i].m_Snapshots.Init();
  558. }
  559.  
  560. AdjustVotebanTime(m_CurrentGameTick);
  561. m_CurrentGameTick = 0;
  562.  
  563. return 0;
  564. }
  565.  
  566. void CServer::SetRconCID(int ClientID)
  567. {
  568. m_RconClientID = ClientID;
  569. }
  570.  
  571. bool CServer::IsAuthed(int ClientID)
  572. {
  573. return m_aClients[ClientID].m_Authed;
  574. }
  575.  
  576. int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo)
  577. {
  578. dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
  579. dbg_assert(pInfo != 0, "info can not be null");
  580.  
  581. if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
  582. {
  583. pInfo->m_pName = m_aClients[ClientID].m_aName;
  584. pInfo->m_Latency = m_aClients[ClientID].m_Latency;
  585. return 1;
  586. }
  587. return 0;
  588. }
  589.  
  590. void CServer::GetClientAddr(int ClientID, char *pAddrStr, int Size)
  591. {
  592. if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME)
  593. net_addr_str(m_NetServer.ClientAddr(ClientID), pAddrStr, Size, false);
  594. }
  595.  
  596.  
  597. const char *CServer::ClientName(int ClientID)
  598. {
  599. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  600. return "(invalid)";
  601. if(m_aClients[ClientID].m_State == CServer::CClient::STATE_INGAME)
  602. return m_aClients[ClientID].m_aName;
  603. else
  604. return "(connecting)";
  605.  
  606. }
  607.  
  608. const char *CServer::ClientClan(int ClientID)
  609. {
  610. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  611. return "";
  612. if(m_aClients[ClientID].m_State == CServer::CClient::STATE_INGAME)
  613. return m_aClients[ClientID].m_aClan;
  614. else
  615. return "";
  616. }
  617.  
  618. int CServer::ClientCountry(int ClientID)
  619. {
  620. if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  621. return -1;
  622. if(m_aClients[ClientID].m_State == CServer::CClient::STATE_INGAME)
  623. return m_aClients[ClientID].m_Country;
  624. else
  625. return -1;
  626. }
  627.  
  628. bool CServer::ClientIngame(int ClientID)
  629. {
  630. return ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CServer::CClient::STATE_INGAME;
  631. }
  632.  
  633. int CServer::MaxClients() const
  634. {
  635. return m_NetServer.MaxClients();
  636. }
  637.  
  638. int CServer::SendMsg(CMsgPacker *pMsg, int Flags, int ClientID)
  639. {
  640. return SendMsgEx(pMsg, Flags, ClientID, false);
  641. }
  642.  
  643. int CServer::SendMsgEx(CMsgPacker *pMsg, int Flags, int ClientID, bool System)
  644. {
  645. CNetChunk Packet;
  646. if(!pMsg)
  647. return -1;
  648.  
  649. mem_zero(&Packet, sizeof(CNetChunk));
  650.  
  651. Packet.m_ClientID = ClientID;
  652. Packet.m_pData = pMsg->Data();
  653. Packet.m_DataSize = pMsg->Size();
  654.  
  655. // HACK: modify the message id in the packet and store the system flag
  656. *((unsigned char*)Packet.m_pData) <<= 1;
  657. if(System)
  658. *((unsigned char*)Packet.m_pData) |= 1;
  659.  
  660. if(Flags&MSGFLAG_VITAL)
  661. Packet.m_Flags |= NETSENDFLAG_VITAL;
  662. if(Flags&MSGFLAG_FLUSH)
  663. Packet.m_Flags |= NETSENDFLAG_FLUSH;
  664.  
  665. // write message to demo recorder
  666. if(!(Flags&MSGFLAG_NORECORD))
  667. m_DemoRecorder.RecordMessage(pMsg->Data(), pMsg->Size());
  668.  
  669. if(!(Flags&MSGFLAG_NOSEND))
  670. {
  671. if(ClientID == -1)
  672. {
  673. // broadcast
  674. int i;
  675. for(i = 0; i < MAX_CLIENTS; i++)
  676. if(m_aClients[i].m_State == CClient::STATE_INGAME)
  677. {
  678. Packet.m_ClientID = i;
  679. m_NetServer.Send(&Packet);
  680. }
  681. }
  682. else
  683. m_NetServer.Send(&Packet);
  684. }
  685. return 0;
  686. }
  687.  
  688. void CServer::DoSnapshot()
  689. {
  690. GameServer()->OnPreSnap();
  691.  
  692. // create snapshot for demo recording
  693. if(m_DemoRecorder.IsRecording())
  694. {
  695. char aData[CSnapshot::MAX_SIZE];
  696. int SnapshotSize;
  697.  
  698. // build snap and possibly add some messages
  699. m_SnapshotBuilder.Init();
  700. GameServer()->OnSnap(-1);
  701. SnapshotSize = m_SnapshotBuilder.Finish(aData);
  702.  
  703. // write snapshot
  704. m_DemoRecorder.RecordSnapshot(Tick(), aData, SnapshotSize);
  705. }
  706.  
  707. // create snapshots for all clients
  708. for(int i = 0; i < MAX_CLIENTS; i++)
  709. {
  710. // client must be ingame to recive snapshots
  711. if(m_aClients[i].m_State != CClient::STATE_INGAME)
  712. continue;
  713.  
  714. // this client is trying to recover, don't spam snapshots
  715. if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_RECOVER && (Tick()%50) != 0)
  716. continue;
  717.  
  718. // this client is trying to recover, don't spam snapshots
  719. if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_INIT && (Tick()%10) != 0)
  720. continue;
  721.  
  722. {
  723. char aData[CSnapshot::MAX_SIZE];
  724. CSnapshot *pData = (CSnapshot*)aData; // Fix compiler warning for strict-aliasing
  725. char aDeltaData[CSnapshot::MAX_SIZE];
  726. char aCompData[CSnapshot::MAX_SIZE];
  727. int SnapshotSize;
  728. int Crc;
  729. static CSnapshot EmptySnap;
  730. CSnapshot *pDeltashot = &EmptySnap;
  731. int DeltashotSize;
  732. int DeltaTick = -1;
  733. int DeltaSize;
  734.  
  735. m_SnapshotBuilder.Init();
  736.  
  737. GameServer()->OnSnap(i);
  738.  
  739. // finish snapshot
  740. SnapshotSize = m_SnapshotBuilder.Finish(pData);
  741. Crc = pData->Crc();
  742.  
  743. // remove old snapshos
  744. // keep 3 seconds worth of snapshots
  745. m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentGameTick-SERVER_TICK_SPEED*3);
  746.  
  747. // save it the snapshot
  748. m_aClients[i].m_Snapshots.Add(m_CurrentGameTick, time_get(), SnapshotSize, pData, 0);
  749.  
  750. // find snapshot that we can preform delta against
  751. EmptySnap.Clear();
  752.  
  753. {
  754. DeltashotSize = m_aClients[i].m_Snapshots.Get(m_aClients[i].m_LastAckedSnapshot, 0, &pDeltashot, 0);
  755. if(DeltashotSize >= 0)
  756. DeltaTick = m_aClients[i].m_LastAckedSnapshot;
  757. else
  758. {
  759. // no acked package found, force client to recover rate
  760. if(m_aClients[i].m_SnapRate == CClient::SNAPRATE_FULL)
  761. m_aClients[i].m_SnapRate = CClient::SNAPRATE_RECOVER;
  762. }
  763. }
  764.  
  765. // create delta
  766. DeltaSize = m_SnapshotDelta.CreateDelta(pDeltashot, pData, aDeltaData);
  767.  
  768. if(DeltaSize)
  769. {
  770. // compress it
  771. int SnapshotSize;
  772. const int MaxSize = MAX_SNAPSHOT_PACKSIZE;
  773. int NumPackets;
  774.  
  775. SnapshotSize = CVariableInt::Compress(aDeltaData, DeltaSize, aCompData);
  776. NumPackets = (SnapshotSize+MaxSize-1)/MaxSize;
  777.  
  778. for(int n = 0, Left = SnapshotSize; Left; n++)
  779. {
  780. int Chunk = Left < MaxSize ? Left : MaxSize;
  781. Left -= Chunk;
  782.  
  783. if(NumPackets == 1)
  784. {
  785. CMsgPacker Msg(NETMSG_SNAPSINGLE);
  786. Msg.AddInt(m_CurrentGameTick);
  787. Msg.AddInt(m_CurrentGameTick-DeltaTick);
  788. Msg.AddInt(Crc);
  789. Msg.AddInt(Chunk);
  790. Msg.AddRaw(&aCompData[n*MaxSize], Chunk);
  791. SendMsgEx(&Msg, MSGFLAG_FLUSH, i, true);
  792. }
  793. else
  794. {
  795. CMsgPacker Msg(NETMSG_SNAP);
  796. Msg.AddInt(m_CurrentGameTick);
  797. Msg.AddInt(m_CurrentGameTick-DeltaTick);
  798. Msg.AddInt(NumPackets);
  799. Msg.AddInt(n);
  800. Msg.AddInt(Crc);
  801. Msg.AddInt(Chunk);
  802. Msg.AddRaw(&aCompData[n*MaxSize], Chunk);
  803. SendMsgEx(&Msg, MSGFLAG_FLUSH, i, true);
  804. }
  805. }
  806. }
  807. else
  808. {
  809. CMsgPacker Msg(NETMSG_SNAPEMPTY);
  810. Msg.AddInt(m_CurrentGameTick);
  811. Msg.AddInt(m_CurrentGameTick-DeltaTick);
  812. SendMsgEx(&Msg, MSGFLAG_FLUSH, i, true);
  813. }
  814. }
  815. }
  816.  
  817. GameServer()->OnPostSnap();
  818. }
  819.  
  820.  
  821. int CServer::NewClientCallback(int ClientID, void *pUser)
  822. {
  823. CServer *pThis = (CServer *)pUser;
  824. pThis->m_aClients[ClientID].m_State = CClient::STATE_AUTH;
  825. pThis->m_aClients[ClientID].m_aName[0] = 0;
  826. pThis->m_aClients[ClientID].m_aClan[0] = 0;
  827. pThis->m_aClients[ClientID].m_Country = -1;
  828. pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
  829. pThis->m_aClients[ClientID].m_AuthTries = 0;
  830. pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
  831. pThis->m_aClients[ClientID].Reset();
  832. return 0;
  833. }
  834.  
  835. int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
  836. {
  837. CServer *pThis = (CServer *)pUser;
  838.  
  839. char aAddrStr[NETADDR_MAXSTRSIZE];
  840. net_addr_str(pThis->m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
  841. char aBuf[256];
  842. str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
  843. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
  844.  
  845. // notify the mod about the drop
  846. if(pThis->m_aClients[ClientID].m_State >= CClient::STATE_READY)
  847. pThis->GameServer()->OnClientDrop(ClientID, pReason);
  848.  
  849. pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
  850. pThis->m_aClients[ClientID].m_aName[0] = 0;
  851. pThis->m_aClients[ClientID].m_aClan[0] = 0;
  852. pThis->m_aClients[ClientID].m_Country = -1;
  853. pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
  854. pThis->m_aClients[ClientID].m_AuthTries = 0;
  855. pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
  856. pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
  857.  
  858. // could have been an admin
  859. pThis->UpdateLoggedInAdmins();
  860.  
  861. return 0;
  862. }
  863.  
  864. void CServer::SendMap(int ClientID)
  865. {
  866. CMsgPacker Msg(NETMSG_MAP_CHANGE);
  867. Msg.AddString(GetMapName(), 0);
  868. Msg.AddInt(m_CurrentMapCrc);
  869. Msg.AddInt(m_CurrentMapSize);
  870. SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
  871. }
  872.  
  873. void CServer::SendConnectionReady(int ClientID)
  874. {
  875. CMsgPacker Msg(NETMSG_CON_READY);
  876. SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
  877. }
  878.  
  879. void CServer::SendRconLine(int ClientID, const char *pLine)
  880. {
  881. CMsgPacker Msg(NETMSG_RCON_LINE);
  882. Msg.AddString(pLine, 512);
  883. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  884. }
  885.  
  886. void CServer::SendRconLineAuthed(const char *pLine, void *pUser)
  887. {
  888. CServer *pThis = (CServer *)pUser;
  889. static volatile int ReentryGuard = 0;
  890. int i;
  891.  
  892. if(ReentryGuard) return;
  893. ReentryGuard++;
  894.  
  895. for(i = 0; i < MAX_CLIENTS; i++)
  896. {
  897. if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed >= pThis->m_RconAuthLevel)
  898. pThis->SendRconLine(i, pLine);
  899. }
  900.  
  901. ReentryGuard--;
  902. }
  903.  
  904. void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
  905. {
  906. CMsgPacker Msg(NETMSG_RCON_CMD_ADD);
  907. Msg.AddString(pCommandInfo->m_pName, IConsole::TEMPCMD_NAME_LENGTH);
  908. Msg.AddString(pCommandInfo->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH);
  909. Msg.AddString(pCommandInfo->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH);
  910. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  911. }
  912.  
  913. void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID)
  914. {
  915. CMsgPacker Msg(NETMSG_RCON_CMD_REM);
  916. Msg.AddString(pCommandInfo->m_pName, 256);
  917. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  918. }
  919.  
  920. void CServer::UpdateClientRconCommands()
  921. {
  922. int ClientID = Tick() % MAX_CLIENTS;
  923.  
  924. if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed)
  925. {
  926. int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : (AUTHED_SUBADMIN ? IConsole::ACCESS_LEVEL_SUBADMIN : IConsole::ACCESS_LEVEL_MOD);
  927. for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i)
  928. {
  929. SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID);
  930. m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER);
  931. }
  932. }
  933. }
  934.  
  935. void CServer::ProcessClientPacket(CNetChunk *pPacket)
  936. {
  937. int ClientID = pPacket->m_ClientID;
  938. CUnpacker Unpacker;
  939. Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize);
  940.  
  941. // unpack msgid and system flag
  942. int Msg = Unpacker.GetInt();
  943. int Sys = Msg&1;
  944. Msg >>= 1;
  945.  
  946. if(Unpacker.Error())
  947. return;
  948.  
  949. if(Sys)
  950. {
  951. // system message
  952. if(Msg == NETMSG_INFO)
  953. {
  954. if(m_aClients[ClientID].m_State == CClient::STATE_AUTH)
  955. {
  956. const char *pVersion = Unpacker.GetString(CUnpacker::SANITIZE_CC);
  957. if(str_comp(pVersion, GameServer()->NetVersion()) != 0)
  958. {
  959. // wrong version
  960. char aReason[256];
  961. str_format(aReason, sizeof(aReason), "Wrong version. Server is running '%s' and client '%s'", GameServer()->NetVersion(), pVersion);
  962. m_NetServer.Drop(ClientID, aReason);
  963. return;
  964. }
  965.  
  966. const char *pPassword = Unpacker.GetString(CUnpacker::SANITIZE_CC);
  967.  
  968.  
  969. if (!g_Config.m_SvPwAntispoof)
  970. {
  971. if(g_Config.m_Password[0] != 0 && str_comp(g_Config.m_Password, pPassword) != 0)
  972. {
  973. // wrong password
  974. m_NetServer.Drop(ClientID, "Wrong password");
  975. return;
  976. }
  977. }
  978. else
  979. {
  980. // anti spoof
  981. char aToken[5];
  982. m_NetServer.TokenToBaseString(m_NetServer.GetToken(*m_NetServer.ClientAddr(ClientID)), aToken);
  983.  
  984. // validate token
  985. if(str_comp(aToken, pPassword) != 0)
  986. {
  987. // wrong password
  988. m_NetServer.Drop(ClientID, "Wrong password");
  989. return;
  990. }
  991. }
  992.  
  993. m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
  994. SendMap(ClientID);
  995. }
  996. }
  997. else if(Msg == NETMSG_REQUEST_MAP_DATA)
  998. {
  999. if(m_aClients[ClientID].m_State < CClient::STATE_CONNECTING)
  1000. return;
  1001.  
  1002. int Chunk = Unpacker.GetInt();
  1003. unsigned int ChunkSize = 1024-128;
  1004. unsigned int Offset = Chunk * ChunkSize;
  1005. int Last = 0;
  1006.  
  1007. // drop faulty map data requests
  1008. if(Chunk < 0 || Offset > m_CurrentMapSize)
  1009. return;
  1010.  
  1011. if(Offset+ChunkSize >= m_CurrentMapSize)
  1012. {
  1013. ChunkSize = m_CurrentMapSize-Offset;
  1014. if(ChunkSize < 0)
  1015. ChunkSize = 0;
  1016. Last = 1;
  1017. }
  1018.  
  1019. CMsgPacker Msg(NETMSG_MAP_DATA);
  1020. Msg.AddInt(Last);
  1021. Msg.AddInt(m_CurrentMapCrc);
  1022. Msg.AddInt(Chunk);
  1023. Msg.AddInt(ChunkSize);
  1024. Msg.AddRaw(&m_pCurrentMapData[Offset], ChunkSize);
  1025. SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH, ClientID, true);
  1026.  
  1027. if(g_Config.m_Debug)
  1028. {
  1029. char aBuf[256];
  1030. str_format(aBuf, sizeof(aBuf), "sending chunk %d with size %d", Chunk, ChunkSize);
  1031. Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
  1032. }
  1033. }
  1034. else if(Msg == NETMSG_READY)
  1035. {
  1036. if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
  1037. {
  1038. char aAddrStr[NETADDR_MAXSTRSIZE];
  1039. net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
  1040.  
  1041. char aBuf[256];
  1042. str_format(aBuf, sizeof(aBuf), "player is ready. ClientID=%x addr=%s", ClientID, aAddrStr);
  1043. Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
  1044. m_aClients[ClientID].m_State = CClient::STATE_READY;
  1045. GameServer()->OnClientConnected(ClientID);
  1046. SendConnectionReady(ClientID);
  1047. }
  1048. }
  1049. else if(Msg == NETMSG_ENTERGAME)
  1050. {
  1051. if(m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID))
  1052. {
  1053. char aAddrStr[NETADDR_MAXSTRSIZE];
  1054. net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
  1055.  
  1056. char aBuf[256];
  1057. str_format(aBuf, sizeof(aBuf), "player has entered the game. ClientID=%x addr=%s", ClientID, aAddrStr);
  1058. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1059. m_aClients[ClientID].m_State = CClient::STATE_INGAME;
  1060. GameServer()->OnClientEnter(ClientID);
  1061. }
  1062. }
  1063. else if(Msg == NETMSG_INPUT)
  1064. {
  1065. CClient::CInput *pInput;
  1066. int64 TagTime;
  1067.  
  1068. m_aClients[ClientID].m_LastAckedSnapshot = Unpacker.GetInt();
  1069. int IntendedTick = Unpacker.GetInt();
  1070. int Size = Unpacker.GetInt();
  1071.  
  1072. // check for errors
  1073. if(Unpacker.Error() || Size/4 > MAX_INPUT_SIZE)
  1074. return;
  1075.  
  1076. if(m_aClients[ClientID].m_LastAckedSnapshot > 0)
  1077. m_aClients[ClientID].m_SnapRate = CClient::SNAPRATE_FULL;
  1078.  
  1079. if(m_aClients[ClientID].m_Snapshots.Get(m_aClients[ClientID].m_LastAckedSnapshot, &TagTime, 0, 0) >= 0)
  1080. m_aClients[ClientID].m_Latency = (int)(((time_get()-TagTime)*1000)/time_freq());
  1081.  
  1082. // add message to report the input timing
  1083. // skip packets that are old
  1084. if(IntendedTick > m_aClients[ClientID].m_LastInputTick)
  1085. {
  1086. int TimeLeft = ((TickStartTime(IntendedTick)-time_get())*1000) / time_freq();
  1087.  
  1088. CMsgPacker Msg(NETMSG_INPUTTIMING);
  1089. Msg.AddInt(IntendedTick);
  1090. Msg.AddInt(TimeLeft);
  1091. SendMsgEx(&Msg, 0, ClientID, true);
  1092. }
  1093.  
  1094. m_aClients[ClientID].m_LastInputTick = IntendedTick;
  1095.  
  1096. pInput = &m_aClients[ClientID].m_aInputs[m_aClients[ClientID].m_CurrentInput];
  1097.  
  1098. if(IntendedTick <= Tick())
  1099. IntendedTick = Tick()+1;
  1100.  
  1101. pInput->m_GameTick = IntendedTick;
  1102.  
  1103. for(int i = 0; i < Size/4; i++)
  1104. pInput->m_aData[i] = Unpacker.GetInt();
  1105.  
  1106. mem_copy(m_aClients[ClientID].m_LatestInput.m_aData, pInput->m_aData, MAX_INPUT_SIZE*sizeof(int));
  1107.  
  1108. m_aClients[ClientID].m_CurrentInput++;
  1109. m_aClients[ClientID].m_CurrentInput %= 200;
  1110.  
  1111. // call the mod with the fresh input data
  1112. if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
  1113. GameServer()->OnClientDirectInput(ClientID, m_aClients[ClientID].m_LatestInput.m_aData);
  1114. }
  1115. else if(Msg == NETMSG_RCON_CMD)
  1116. {
  1117. const char *pCmd = Unpacker.GetString();
  1118.  
  1119. if(Unpacker.Error() == 0 && m_aClients[ClientID].m_Authed)
  1120. {
  1121.  
  1122. // try to find first space
  1123. const char *delimiter = strchr(pCmd, ' ');
  1124.  
  1125. if(m_aClients[ClientID].m_Authed != AUTHED_SUBADMIN
  1126. || (
  1127. m_aClients[ClientID].m_Authed == AUTHED_SUBADMIN
  1128. && delimiter != NULL
  1129. && m_aClients[ClientID].m_SubAdminAuthPass == std::string(pCmd, delimiter - pCmd)
  1130. && (pCmd = delimiter + 1) != NULL)
  1131. )
  1132. {
  1133. char aBuf[256];
  1134. str_format(aBuf, sizeof(aBuf), "ClientID=%d rcon='%s'", ClientID, pCmd);
  1135. Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
  1136. m_RconClientID = ClientID;
  1137. m_RconAuthLevel = m_aClients[ClientID].m_Authed;
  1138. Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : (m_aClients[ClientID].m_Authed == AUTHED_SUBADMIN ? IConsole::ACCESS_LEVEL_SUBADMIN : IConsole::ACCESS_LEVEL_MOD));
  1139. Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER);
  1140. Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN);
  1141. m_RconClientID = IServer::RCON_CID_SERV;
  1142. m_RconAuthLevel = AUTHED_SUBADMIN;
  1143. }
  1144. else if(m_aClients[ClientID].m_Authed == AUTHED_SUBADMIN)
  1145. {
  1146. if(m_aClients[ClientID].m_SubAdminCommandPassFails >= 3)
  1147. {
  1148. // logout
  1149. rconLogClientOut(ClientID, "Too many wrong passwords. You were logged out.");
  1150. }
  1151. else
  1152. {
  1153. ++m_aClients[ClientID].m_SubAdminCommandPassFails;
  1154. SendRconLine(ClientID, "Wrong password.");
  1155. }
  1156. }
  1157. }
  1158. }
  1159. else if(Msg == NETMSG_RCON_AUTH)
  1160. {
  1161. const char *pPw;
  1162. Unpacker.GetString(); // login name, not used
  1163. pPw = Unpacker.GetString(CUnpacker::SANITIZE_CC);
  1164.  
  1165. // try matching username:password login
  1166. const char *delimiter = strchr(pPw, ':');
  1167. std::string username, password;
  1168. loginiterator loginit;
  1169. bool loginWithUsername = (delimiter != NULL);
  1170. if(loginWithUsername)
  1171. {
  1172. username.assign(pPw, delimiter - pPw);
  1173. password.assign(delimiter + 1);
  1174. }
  1175.  
  1176. if(Unpacker.Error() == 0)
  1177. {
  1178. if(g_Config.m_SvRconPassword[0] == 0 && g_Config.m_SvRconModPassword[0] == 0 && logins.empty())
  1179. {
  1180. SendRconLine(ClientID, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password or add logins using add_login to enable the remote console.");
  1181. }
  1182. else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0)
  1183. {
  1184. CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
  1185. Msg.AddInt(1); //authed
  1186. Msg.AddInt(1); //cmdlist
  1187. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  1188.  
  1189. m_aClients[ClientID].m_Authed = AUTHED_ADMIN;
  1190. int SendRconCmds = Unpacker.GetInt();
  1191. if(Unpacker.Error() == 0 && SendRconCmds){
  1192. m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER);
  1193. }
  1194.  
  1195. if(g_Config.m_SvAdminAuthLog == 1){
  1196.  
  1197. FILE *pFile = fopen(g_Config.m_SvAdminAuthLogFile, "a");
  1198. if(pFile)
  1199. {
  1200.  
  1201. fprintf(pFile, "[%s] %-16s authed as full admin.\n", currentDateTime().c_str(), ClientName(ClientID));
  1202. fclose(pFile);
  1203. }
  1204. else
  1205. {
  1206. //Datei konnte nicht geöffnet werden
  1207. }
  1208.  
  1209. }
  1210.  
  1211. SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted.");
  1212. char aBuf[256];
  1213. str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID);
  1214. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1215. UpdateLoggedInAdmins();
  1216. }
  1217. else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0)
  1218. {
  1219. CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
  1220. Msg.AddInt(1); //authed
  1221. Msg.AddInt(1); //cmdlist
  1222. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  1223.  
  1224. m_aClients[ClientID].m_Authed = AUTHED_MOD;
  1225. int SendRconCmds = Unpacker.GetInt();
  1226. if(Unpacker.Error() == 0 && SendRconCmds)
  1227. m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER);
  1228.  
  1229. //jxsl13
  1230.  
  1231. if(g_Config.m_SvAdminAuthLog == 1){
  1232.  
  1233.  
  1234. FILE *pFile = fopen(g_Config.m_SvAdminAuthLogFile, "a");
  1235. if(pFile)
  1236. {
  1237.  
  1238. fprintf(pFile, "[%s] %-16s authed as moderator.\n", currentDateTime().c_str(), ClientName(ClientID));
  1239. fclose(pFile);
  1240. }
  1241. else
  1242. {
  1243. //Datei konnte nicht geöffnet werden
  1244. }
  1245.  
  1246. }
  1247. //jxsl13
  1248.  
  1249. SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted.");
  1250. char aBuf[256];
  1251. str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID);
  1252. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1253. }
  1254. else if(loginWithUsername
  1255. && !logins.empty()
  1256. && (loginit = logins.find(username)) != logins.end()
  1257. && loginit->second == password)
  1258. {
  1259. CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
  1260. Msg.AddInt(1); //authed
  1261. Msg.AddInt(1); //cmdlist
  1262. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  1263.  
  1264. m_aClients[ClientID].m_Authed = AUTHED_SUBADMIN;
  1265. m_aClients[ClientID].m_SubAdminAuthName = loginit->first;
  1266. m_aClients[ClientID].m_SubAdminAuthPass = loginit->second;
  1267. m_aClients[ClientID].m_SubAdminCommandPassFails = 0;
  1268.  
  1269. int SendRconCmds = Unpacker.GetInt();
  1270. if(Unpacker.Error() == 0 && SendRconCmds)
  1271. m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_SUBADMIN, CFGFLAG_SERVER);
  1272.  
  1273. //jxsl13
  1274.  
  1275. if(g_Config.m_SvAdminAuthLog == 1){
  1276.  
  1277. FILE *pFile = fopen(g_Config.m_SvAdminAuthLogFile, "a");
  1278. if(pFile)
  1279. {
  1280.  
  1281. fprintf(pFile, "[%s] %-16s authed as subadmin:%s\n", currentDateTime().c_str(), ClientName(ClientID), loginit->first.c_str());
  1282. fclose(pFile);
  1283. }
  1284. else
  1285. {
  1286. //Datei konnte nicht geöffnet werden
  1287. }
  1288.  
  1289. }
  1290. //jxsl13
  1291.  
  1292. SendRconLine(ClientID, "Subadmin authentication successful. Limited remote console access granted.");
  1293. char aBuf[256];
  1294. str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (subadmin:%s)", ClientID, loginit->first.c_str());
  1295. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1296. UpdateLoggedInAdmins();
  1297. }
  1298. else if(g_Config.m_SvRconMaxTries)
  1299. {
  1300. m_aClients[ClientID].m_AuthTries++;
  1301.  
  1302. //jxsl13
  1303. if(g_Config.m_SvRconTriesLog == 1){
  1304.  
  1305. FILE *pFile = fopen(g_Config.m_SvRconTriesLogFile, "a");
  1306. if(pFile)
  1307. {
  1308. fprintf(pFile, "[%s] %-16s rcon attempt: %s\n", currentDateTime().c_str(), ClientName(ClientID), pPw);
  1309. fclose(pFile);
  1310. }
  1311. else
  1312. {
  1313. //Datei konnte nicht geöffnet werden
  1314. }
  1315. }
  1316. //jxsl13
  1317.  
  1318.  
  1319. char aBuf[128];
  1320. str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, g_Config.m_SvRconMaxTries);
  1321. SendRconLine(ClientID, aBuf);
  1322. if(m_aClients[ClientID].m_AuthTries >= g_Config.m_SvRconMaxTries)
  1323. {
  1324. if(!g_Config.m_SvRconBantime)
  1325. m_NetServer.Drop(ClientID, "Too many remote console authentication tries");
  1326. else
  1327. m_ServerBan.BanAddr(m_NetServer.ClientAddr(ClientID), g_Config.m_SvRconBantime*60, "Too many remote console authentication tries");
  1328. }
  1329. }
  1330. else
  1331. {
  1332. SendRconLine(ClientID, "Wrong password.");
  1333. }
  1334. }
  1335. }
  1336. else if(Msg == NETMSG_PING)
  1337. {
  1338. CMsgPacker Msg(NETMSG_PING_REPLY);
  1339. SendMsgEx(&Msg, 0, ClientID, true);
  1340. }
  1341. else
  1342. {
  1343. if(g_Config.m_Debug)
  1344. {
  1345. char aHex[] = "0123456789ABCDEF";
  1346. char aBuf[512];
  1347.  
  1348. for(int b = 0; b < pPacket->m_DataSize && b < 32; b++)
  1349. {
  1350. aBuf[b*3] = aHex[((const unsigned char *)pPacket->m_pData)[b]>>4];
  1351. aBuf[b*3+1] = aHex[((const unsigned char *)pPacket->m_pData)[b]&0xf];
  1352. aBuf[b*3+2] = ' ';
  1353. aBuf[b*3+3] = 0;
  1354. }
  1355.  
  1356. char aBufMsg[256];
  1357. str_format(aBufMsg, sizeof(aBufMsg), "strange message ClientID=%d msg=%d data_size=%d", ClientID, Msg, pPacket->m_DataSize);
  1358. Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBufMsg);
  1359. Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
  1360. }
  1361. }
  1362. }
  1363. else
  1364. {
  1365. // game message
  1366. if(m_aClients[ClientID].m_State >= CClient::STATE_READY)
  1367. GameServer()->OnMessage(Msg, &Unpacker, ClientID);
  1368. }
  1369. }
  1370.  
  1371. void CServer::SendServerInfo(const NETADDR *pAddr, int Token)
  1372. {
  1373. CNetChunk Packet;
  1374. CPacker p;
  1375. char aBuf[128];
  1376.  
  1377. // count the players
  1378. int PlayerCount = 0, ClientCount = 0;
  1379. for(int i = 0; i < MAX_CLIENTS; i++)
  1380. {
  1381. if(m_aClients[i].m_State != CClient::STATE_EMPTY)
  1382. {
  1383. if(GameServer()->IsClientPlayer(i))
  1384. PlayerCount++;
  1385.  
  1386. ClientCount++;
  1387. }
  1388. }
  1389.  
  1390. p.Reset();
  1391.  
  1392. p.AddRaw(SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
  1393. str_format(aBuf, sizeof(aBuf), "%d", Token);
  1394. p.AddString(aBuf, 6);
  1395.  
  1396. p.AddString(GameServer()->Version(), 32);
  1397.  
  1398. char aName[256];
  1399.  
  1400. if (g_Config.m_SvPwAntispoof)
  1401. {
  1402. // send the alternative server name when a admin is online
  1403. char aToken[5];
  1404. m_NetServer.TokenToBaseString(m_NetServer.GetToken(*pAddr), aToken);
  1405.  
  1406. str_format(aName, sizeof(aName), "Password: %s - %s", aToken, (m_numLoggedInAdmins && str_length(g_Config.m_SvNameAdmin)) ? g_Config.m_SvNameAdmin : g_Config.m_SvName);
  1407.  
  1408. p.AddString(aName, 64);
  1409. }
  1410. else{
  1411. p.AddString((m_numLoggedInAdmins && str_length(g_Config.m_SvNameAdmin)) ? g_Config.m_SvNameAdmin : g_Config.m_SvName, 64);
  1412. }
  1413.  
  1414. p.AddString(GetMapName(), 32);
  1415.  
  1416. // gametype
  1417. p.AddString(GameServer()->GameType(), 16);
  1418.  
  1419. // flags
  1420. int i = 0;
  1421. if(g_Config.m_Password[0]) // password set
  1422. i |= SERVER_FLAG_PASSWORD;
  1423. str_format(aBuf, sizeof(aBuf), "%d", i);
  1424. p.AddString(aBuf, 2);
  1425.  
  1426. str_format(aBuf, sizeof(aBuf), "%d", PlayerCount); p.AddString(aBuf, 3); // num players
  1427. str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()-g_Config.m_SvSpectatorSlots); p.AddString(aBuf, 3); // max players
  1428. str_format(aBuf, sizeof(aBuf), "%d", ClientCount); p.AddString(aBuf, 3); // num clients
  1429. str_format(aBuf, sizeof(aBuf), "%d", m_NetServer.MaxClients()); p.AddString(aBuf, 3); // max clients
  1430.  
  1431. for(i = 0; i < MAX_CLIENTS; i++)
  1432. {
  1433. if(m_aClients[i].m_State != CClient::STATE_EMPTY)
  1434. {
  1435. p.AddString(ClientName(i), MAX_NAME_LENGTH); // client name
  1436. p.AddString(ClientClan(i), MAX_CLAN_LENGTH); // client clan
  1437. str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Country); p.AddString(aBuf, 6); // client country
  1438. str_format(aBuf, sizeof(aBuf), "%d", m_aClients[i].m_Score); p.AddString(aBuf, 6); // client score
  1439. str_format(aBuf, sizeof(aBuf), "%d", GameServer()->IsClientPlayer(i)?1:0); p.AddString(aBuf, 2); // is player?
  1440. }
  1441. }
  1442.  
  1443. Packet.m_ClientID = -1;
  1444. Packet.m_Address = *pAddr;
  1445. Packet.m_Flags = NETSENDFLAG_CONNLESS;
  1446. Packet.m_DataSize = p.Size();
  1447. Packet.m_pData = p.Data();
  1448. m_NetServer.Send(&Packet);
  1449. }
  1450.  
  1451. void CServer::UpdateServerInfo()
  1452. {
  1453. for(int i = 0; i < MAX_CLIENTS; ++i)
  1454. {
  1455. if(m_aClients[i].m_State != CClient::STATE_EMPTY)
  1456. SendServerInfo(m_NetServer.ClientAddr(i), -1);
  1457. }
  1458. }
  1459.  
  1460.  
  1461. void CServer::PumpNetwork()
  1462. {
  1463. CNetChunk Packet;
  1464.  
  1465. m_NetServer.Update();
  1466.  
  1467. // process packets
  1468. while(m_NetServer.Recv(&Packet))
  1469. {
  1470. if(Packet.m_ClientID == -1)
  1471. {
  1472. // stateless
  1473. if(!m_Register.RegisterProcessPacket(&Packet))
  1474. {
  1475. if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETINFO)+1 &&
  1476. mem_comp(Packet.m_pData, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
  1477. {
  1478. SendServerInfo(&Packet.m_Address, ((unsigned char *)Packet.m_pData)[sizeof(SERVERBROWSE_GETINFO)]);
  1479. }
  1480. }
  1481. }
  1482. else
  1483. ProcessClientPacket(&Packet);
  1484. }
  1485.  
  1486. m_ServerBan.Update();
  1487. m_Econ.Update();
  1488. }
  1489.  
  1490. char *CServer::GetMapName()
  1491. {
  1492. // get the name of the map without his path
  1493. char *pMapShortName = &g_Config.m_SvMap[0];
  1494. for(int i = 0; i < str_length(g_Config.m_SvMap)-1; i++)
  1495. {
  1496. if(g_Config.m_SvMap[i] == '/' || g_Config.m_SvMap[i] == '\\')
  1497. pMapShortName = &g_Config.m_SvMap[i+1];
  1498. }
  1499. return pMapShortName;
  1500. }
  1501.  
  1502. int CServer::LoadMap(const char *pMapName)
  1503. {
  1504. //DATAFILE *df;
  1505. char aBuf[512];
  1506. str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName);
  1507.  
  1508. /*df = datafile_load(buf);
  1509. if(!df)
  1510. return 0;*/
  1511.  
  1512. // check for valid standard map
  1513. if(!m_MapChecker.ReadAndValidateMap(Storage(), aBuf, IStorage::TYPE_ALL))
  1514. {
  1515. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mapchecker", "invalid standard map");
  1516. return 0;
  1517. }
  1518.  
  1519. if(!m_pMap->Load(aBuf))
  1520. return 0;
  1521.  
  1522. // stop recording when we change map
  1523. m_DemoRecorder.Stop();
  1524.  
  1525. // reinit snapshot ids
  1526. m_IDPool.TimeoutIDs();
  1527.  
  1528. // get the crc of the map
  1529. m_CurrentMapCrc = m_pMap->Crc();
  1530. char aBufMsg[256];
  1531. str_format(aBufMsg, sizeof(aBufMsg), "%s crc is %08x", aBuf, m_CurrentMapCrc);
  1532. Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg);
  1533.  
  1534. str_copy(m_aCurrentMap, pMapName, sizeof(m_aCurrentMap));
  1535. //map_set(df);
  1536.  
  1537. // load complete map into memory for download
  1538. {
  1539. IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL);
  1540. m_CurrentMapSize = (int)io_length(File);
  1541. if(m_pCurrentMapData)
  1542. mem_free(m_pCurrentMapData);
  1543. m_pCurrentMapData = (unsigned char *)mem_alloc(m_CurrentMapSize, 1);
  1544. io_read(File, m_pCurrentMapData, m_CurrentMapSize);
  1545. io_close(File);
  1546. }
  1547. return 1;
  1548. }
  1549.  
  1550. void CServer::InitRegister(CNetServer *pNetServer, IEngineMasterServer *pMasterServer, IConsole *pConsole)
  1551. {
  1552. m_Register.Init(pNetServer, pMasterServer, pConsole);
  1553. }
  1554.  
  1555. int CServer::Run()
  1556. {
  1557. //
  1558. m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);
  1559.  
  1560. // load map
  1561. if(!LoadMap(g_Config.m_SvMap))
  1562. {
  1563. dbg_msg("server", "failed to load map. mapname='%s'", g_Config.m_SvMap);
  1564. return -1;
  1565. }
  1566.  
  1567. // start server
  1568. NETADDR BindAddr;
  1569. if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0)
  1570. {
  1571. // sweet!
  1572. BindAddr.type = NETTYPE_ALL;
  1573. BindAddr.port = g_Config.m_SvPort;
  1574. }
  1575. else
  1576. {
  1577. mem_zero(&BindAddr, sizeof(BindAddr));
  1578. BindAddr.type = NETTYPE_ALL;
  1579. BindAddr.port = g_Config.m_SvPort;
  1580. }
  1581.  
  1582. if(!m_NetServer.Open(BindAddr, &m_ServerBan, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
  1583. {
  1584. dbg_msg("server", "couldn't open socket. port %d might already be in use", g_Config.m_SvPort);
  1585. return -1;
  1586. }
  1587.  
  1588. m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this);
  1589.  
  1590. m_Econ.Init(Console(), &m_ServerBan);
  1591.  
  1592. char aBuf[256];
  1593. str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName);
  1594. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1595.  
  1596. GameServer()->OnInit();
  1597. str_format(aBuf, sizeof(aBuf), "version %s", GameServer()->NetVersion());
  1598. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1599.  
  1600. // process pending commands
  1601. m_pConsole->StoreCommands(false);
  1602.  
  1603. // start game
  1604. {
  1605. int64 ReportTime = time_get();
  1606. int ReportInterval = 3;
  1607.  
  1608. m_Lastheartbeat = 0;
  1609. m_GameStartTime = time_get();
  1610.  
  1611. if(g_Config.m_Debug)
  1612. {
  1613. str_format(aBuf, sizeof(aBuf), "baseline memory usage %dk", mem_stats()->allocated/1024);
  1614. Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "server", aBuf);
  1615. }
  1616.  
  1617. while(m_RunServer)
  1618. {
  1619. int64 t = time_get();
  1620. int NewTicks = 0;
  1621.  
  1622. // load new map TODO: don't poll this
  1623. if(str_comp(g_Config.m_SvMap, m_aCurrentMap) != 0 || m_MapReload)
  1624. {
  1625. m_MapReload = 0;
  1626.  
  1627. // load map
  1628. if(LoadMap(g_Config.m_SvMap))
  1629. {
  1630. // new map loaded
  1631. GameServer()->OnShutdown();
  1632.  
  1633. for(int c = 0; c < MAX_CLIENTS; c++)
  1634. {
  1635. if(m_aClients[c].m_State <= CClient::STATE_AUTH)
  1636. continue;
  1637.  
  1638. SendMap(c);
  1639. m_aClients[c].Reset();
  1640. m_aClients[c].m_State = CClient::STATE_CONNECTING;
  1641. }
  1642.  
  1643. m_GameStartTime = time_get();
  1644. AdjustVotebanTime(m_CurrentGameTick);
  1645. m_CurrentGameTick = 0;
  1646. Kernel()->ReregisterInterface(GameServer());
  1647. GameServer()->OnInit();
  1648. UpdateServerInfo();
  1649. }
  1650. else
  1651. {
  1652. str_format(aBuf, sizeof(aBuf), "failed to load map. mapname='%s'", g_Config.m_SvMap);
  1653. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  1654. str_copy(g_Config.m_SvMap, m_aCurrentMap, sizeof(g_Config.m_SvMap));
  1655. }
  1656. }
  1657.  
  1658. while(t > TickStartTime(m_CurrentGameTick+1))
  1659. {
  1660. m_CurrentGameTick++;
  1661. NewTicks++;
  1662.  
  1663. // apply new input
  1664. for(int c = 0; c < MAX_CLIENTS; c++)
  1665. {
  1666. if(m_aClients[c].m_State == CClient::STATE_EMPTY)
  1667. continue;
  1668. for(int i = 0; i < 200; i++)
  1669. {
  1670. if(m_aClients[c].m_aInputs[i].m_GameTick == Tick())
  1671. {
  1672. if(m_aClients[c].m_State == CClient::STATE_INGAME)
  1673. GameServer()->OnClientPredictedInput(c, m_aClients[c].m_aInputs[i].m_aData);
  1674. break;
  1675. }
  1676. }
  1677. }
  1678.  
  1679. GameServer()->OnTick();
  1680. }
  1681.  
  1682. // snap game
  1683. if(NewTicks)
  1684. {
  1685. if(g_Config.m_SvHighBandwidth || (m_CurrentGameTick%2) == 0)
  1686. DoSnapshot();
  1687.  
  1688. UpdateClientRconCommands();
  1689. }
  1690.  
  1691. // master server stuff
  1692. m_Register.RegisterUpdate(m_NetServer.NetType());
  1693.  
  1694. PumpNetwork();
  1695.  
  1696. if(ReportTime < time_get())
  1697. {
  1698. if(g_Config.m_Debug)
  1699. {
  1700. /*
  1701. static NETSTATS prev_stats;
  1702. NETSTATS stats;
  1703. netserver_stats(net, &stats);
  1704.  
  1705. perf_next();
  1706.  
  1707. if(config.dbg_pref)
  1708. perf_dump(&rootscope);
  1709.  
  1710. dbg_msg("server", "send=%8d recv=%8d",
  1711. (stats.send_bytes - prev_stats.send_bytes)/reportinterval,
  1712. (stats.recv_bytes - prev_stats.recv_bytes)/reportinterval);
  1713.  
  1714. prev_stats = stats;
  1715. */
  1716. }
  1717.  
  1718. ReportTime += time_freq()*ReportInterval;
  1719. }
  1720.  
  1721. // wait for incomming data
  1722. net_socket_read_wait(m_NetServer.Socket(), 5);
  1723. }
  1724. }
  1725. // disconnect all clients on shutdown
  1726. for(int i = 0; i < MAX_CLIENTS; ++i)
  1727. {
  1728. if(m_aClients[i].m_State != CClient::STATE_EMPTY)
  1729. m_NetServer.Drop(i, "Server shutdown");
  1730.  
  1731. m_Econ.Shutdown();
  1732. }
  1733.  
  1734. GameServer()->OnShutdown();
  1735. m_pMap->Unload();
  1736.  
  1737. if(m_pCurrentMapData)
  1738. mem_free(m_pCurrentMapData);
  1739. return 0;
  1740. }
  1741.  
  1742. // returns the time in seconds that the client is votebanned or 0 if he isn't
  1743. int CServer::ClientVotebannedTime(int ClientID)
  1744. {
  1745. CVoteban **v = IsVotebannedAddr(m_NetServer.ClientAddr(ClientID));
  1746. if(v != NULL && (*v)->m_Expire > Tick())
  1747. return ((*v)->m_Expire - Tick()) / TickSpeed();
  1748. return 0;
  1749. }
  1750.  
  1751. // decreases the time of all votebans by the given offset of ticks
  1752. void CServer::AdjustVotebanTime(int offset)
  1753. {
  1754. CleanVotebans();
  1755. CVoteban *v = m_Votebans;
  1756. while(v != NULL)
  1757. {
  1758. v->m_Expire -= offset;
  1759. v = v->m_Next;
  1760. }
  1761. }
  1762.  
  1763. // adds a new voteban for a specific address
  1764. void CServer::AddVotebanAddr(const NETADDR *addr, int expire)
  1765. {
  1766. CVoteban **v = IsVotebannedAddr(addr);
  1767. // create new
  1768. if(!v)
  1769. {
  1770. CVoteban *v = new CVoteban;
  1771. v->m_Addr = *addr;
  1772. v->m_Expire = expire;
  1773. // insert front
  1774. v->m_Next = m_Votebans;
  1775. m_Votebans = v;
  1776. }
  1777. // update existing entry
  1778. else
  1779. (*v)->m_Expire = expire;
  1780. }
  1781.  
  1782. // adds a new voteban for a client's address
  1783. void CServer::AddVoteban(int ClientID, int time)
  1784. {
  1785. int expire = Tick() + time * TickSpeed();
  1786. AddVotebanAddr(m_NetServer.ClientAddr(ClientID), expire);
  1787. }
  1788.  
  1789. // removes a voteban from a client's address
  1790. void CServer::RemoveVotebanClient(int ClientID)
  1791. {
  1792. RemoveVotebanAddr(m_NetServer.ClientAddr(ClientID));
  1793. }
  1794.  
  1795. // removes a voteban on an address
  1796. void CServer::RemoveVotebanAddr(const NETADDR *addr)
  1797. {
  1798. CVoteban **v = IsVotebannedAddr(addr);
  1799. if(v != NULL)
  1800. RemoveVoteban(v);
  1801. }
  1802.  
  1803. // removes a voteban
  1804. void CServer::RemoveVoteban(CVoteban **v)
  1805. {
  1806. CVoteban *next = (*v)->m_Next;
  1807. delete *v;
  1808. *v = next;
  1809. }
  1810.  
  1811. // returns the voteban with the given address if it exists
  1812. CServer::CVoteban **CServer::IsVotebannedAddr(const NETADDR *addr)
  1813. {
  1814. CVoteban **v = &m_Votebans;
  1815. while(*v != NULL)
  1816. {
  1817. // only check ip-type and ip, not port
  1818. if((*v)->m_Addr.type == addr->type && !mem_comp(&(*v)->m_Addr.ip, &addr->ip, sizeof(unsigned char[16])))
  1819. return v;
  1820. v = &(*v)->m_Next;
  1821. }
  1822. return NULL;
  1823. }
  1824.  
  1825. // removes expired votebans
  1826. void CServer::CleanVotebans()
  1827. {
  1828. CVoteban **v = &m_Votebans;
  1829. while(*v != NULL)
  1830. {
  1831. if((*v)->m_Expire <= Tick())
  1832. {
  1833. CVoteban *next = (*v)->m_Next;
  1834. delete *v;
  1835. *v = next;
  1836. }
  1837. else
  1838. v = &(*v)->m_Next;
  1839. }
  1840. }
  1841.  
  1842. void CServer::ConVoteban(IConsole::IResult *pResult, void *pUser)
  1843. {
  1844. CServer* pThis = static_cast<CServer *>(pUser);
  1845. int ClientID = pResult->GetInteger(0);
  1846. if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  1847. {
  1848. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Invalid ClientID");
  1849. return;
  1850. }
  1851. int time = (pResult->NumArguments() > 1) ? pResult->GetInteger(1) : 300;
  1852. pThis->AddVoteban(ClientID, time);
  1853. // message to console and chat
  1854. char aBuf[128];
  1855. str_format(aBuf, sizeof(aBuf), "'%s' has been banned from voting for %d:%02d min.", pThis->ClientName(ClientID), time/60, time%60);
  1856. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1857. pThis->GameServer()->InformPlayers(aBuf);
  1858. }
  1859.  
  1860. void CServer::ConUnvoteban(IConsole::IResult *pResult, void *pUser)
  1861. {
  1862. CServer* pThis = static_cast<CServer *>(pUser);
  1863.  
  1864. // index to unvoteban
  1865. int index = pResult->GetInteger(0);
  1866.  
  1867. CVoteban **v = &pThis->m_Votebans;
  1868. for(int c = 0; *v != NULL; ++c)
  1869. {
  1870. // index found
  1871. if(index == c)
  1872. {
  1873. char aBuf[128], aAddrStr[NETADDR_MAXSTRSIZE];
  1874. // print to console
  1875. net_addr_str(&(*v)->m_Addr, aAddrStr, sizeof(aAddrStr), false);
  1876. str_format(aBuf, sizeof(aBuf), "%s has been un-votebanned.", aAddrStr);
  1877. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1878. // remove ban
  1879. pThis->RemoveVoteban(v);
  1880. // don't look any further
  1881. return;
  1882. }
  1883. v = &(*v)->m_Next;
  1884. }
  1885.  
  1886. // not found
  1887. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "index was not found, please use 'votebans' to obtain an index");
  1888. }
  1889.  
  1890. void CServer::ConUnvotebanClient(IConsole::IResult *pResult, void *pUser)
  1891. {
  1892. CServer* pThis = static_cast<CServer *>(pUser);
  1893. int ClientID = pResult->GetInteger(0);
  1894. if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
  1895. {
  1896. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Invalid ClientID");
  1897. return;
  1898. }
  1899. pThis->RemoveVotebanClient(ClientID);
  1900. // message to console
  1901. char aBuf[128];
  1902. str_format(aBuf, sizeof(aBuf), "'%s' has been un-votebanned.", pThis->ClientName(ClientID));
  1903. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1904. }
  1905.  
  1906. void CServer::ConVotebans(IConsole::IResult *pResult, void *pUser)
  1907. {
  1908. CServer* pThis = static_cast<CServer *>(pUser);
  1909. char aBuf[128];
  1910. char aAddrStr[NETADDR_MAXSTRSIZE];
  1911. int time;
  1912. int count = 0;
  1913.  
  1914. pThis->CleanVotebans();
  1915. CVoteban *v = pThis->m_Votebans;
  1916. NETADDR addr;
  1917. while(v != NULL)
  1918. {
  1919. addr.type = v->m_Addr.type;
  1920. mem_copy(addr.ip, v->m_Addr.ip, sizeof(unsigned char[16]));
  1921. net_addr_str(&addr, aAddrStr, sizeof(aAddrStr), false);
  1922. time = (v->m_Expire - pThis->Tick()) / pThis->TickSpeed();
  1923. str_format(aBuf, sizeof(aBuf), "#%d addr=%s time=%d:%02d min", count++, aAddrStr, time/60, time%60);
  1924. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1925. v = v->m_Next;
  1926. }
  1927.  
  1928. str_format(aBuf, sizeof(aBuf), "%d votebanned ip(s)", count);
  1929. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1930. }
  1931.  
  1932. void CServer::ConAddLogin(IConsole::IResult *pResult, void *pUser)
  1933. {
  1934. CServer* pThis = static_cast<CServer *>(pUser);
  1935. char aBuf[128];
  1936. std::string username(pResult->GetString(0)),
  1937. password(pResult->GetString(1));
  1938.  
  1939. // insert if doesn't exist
  1940. if(pThis->logins.find(username) == pThis->logins.end())
  1941. {
  1942. pThis->logins[username] = password;
  1943.  
  1944. str_format(aBuf, sizeof(aBuf), "Added login for '%s'.", username.c_str());
  1945. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1946. }
  1947. else
  1948. {
  1949. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Did not overwrite existing login.");
  1950. }
  1951. }
  1952.  
  1953. void CServer::ConRemoveLogin(IConsole::IResult *pResult, void *pUser)
  1954. {
  1955. CServer* pThis = static_cast<CServer *>(pUser);
  1956. char aBuf[128];
  1957. loginiterator loginit;
  1958. std::string username(pResult->GetString(0));
  1959.  
  1960. // delete if exists
  1961. if((loginit = pThis->logins.find(username)) != pThis->logins.end())
  1962. {
  1963. // check if someone is logged in with this login
  1964. for(int i = 0; i < MAX_CLIENTS; i++)
  1965. {
  1966. if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY && pThis->m_aClients[i].m_Authed == CServer::AUTHED_SUBADMIN && pThis->m_aClients[i].m_SubAdminAuthName == loginit->first)
  1967. {
  1968. pThis->rconLogClientOut(i, "You were logged out.");
  1969. }
  1970. }
  1971.  
  1972. // finally delete
  1973. pThis->logins.erase(loginit);
  1974.  
  1975. str_format(aBuf, sizeof(aBuf), "Removed login '%s'.", username.c_str());
  1976. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  1977. }
  1978. else
  1979. {
  1980. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "No login with that username.");
  1981. }
  1982. }
  1983.  
  1984. void CServer::ConAddInfo(IConsole::IResult *pResult, void *pUser)
  1985. {
  1986. CServer* pThis = static_cast<CServer *>(pUser);
  1987. int interval = pResult->GetInteger(0);
  1988. if(interval < 1 || interval > 1440)
  1989. {
  1990. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Interval must be between 1 and 1440.");
  1991. return;
  1992. }
  1993.  
  1994. // add info text
  1995. CInfoText *t = new CInfoText;
  1996. t->m_Interval = interval;
  1997. t->m_Text = std::string(pResult->GetString(1));
  1998. // insert front
  1999. t->m_Next = pThis->m_InfoTexts;
  2000. pThis->m_InfoTexts = t;
  2001.  
  2002. pThis->UpdateInfoTexts();
  2003.  
  2004. // message to console
  2005. char aBuf[128];
  2006. str_format(aBuf, sizeof(aBuf), "Added the following info text: %s", t->m_Text.c_str());
  2007. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  2008. }
  2009.  
  2010. void CServer::ConRemoveInfo(IConsole::IResult *pResult, void *pUser)
  2011. {
  2012. CServer* pThis = static_cast<CServer *>(pUser);
  2013. int i = pResult->GetInteger(0);
  2014. int count = 0;
  2015. bool removed = false;
  2016.  
  2017. CInfoText **t = &(pThis->m_InfoTexts);
  2018. while(*t != NULL)
  2019. {
  2020. if(count++ == i)
  2021. {
  2022. // remove
  2023. CInfoText *next = (*t)->m_Next;
  2024. delete *t;
  2025. *t = next;
  2026. removed = true;
  2027. break;
  2028. }
  2029. t = &((*t)->m_Next);
  2030. }
  2031.  
  2032. pThis->UpdateInfoTexts();
  2033.  
  2034. if(removed)
  2035. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text removed");
  2036. else
  2037. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Info text not found");
  2038. }
  2039.  
  2040. void CServer::ConListInfo(IConsole::IResult *pResult, void *pUser)
  2041. {
  2042. CServer* pThis = static_cast<CServer *>(pUser);
  2043. char aBuf[128];
  2044. int count = 0;
  2045.  
  2046. CInfoText *t = pThis->m_InfoTexts;
  2047. while(t != NULL)
  2048. {
  2049. str_format(aBuf, sizeof(aBuf), "#%d interval=%d min text='%s'", count++, t->m_Interval, t->m_Text.c_str());
  2050. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  2051. t = t->m_Next;
  2052. }
  2053.  
  2054. str_format(aBuf, sizeof(aBuf), "%d info text(s)", count);
  2055. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  2056. }
  2057.  
  2058. void CServer::UpdateInfoTexts()
  2059. {
  2060. // in case that there are no info texts
  2061. if(m_InfoTexts == NULL)
  2062. {
  2063. m_InfoTextInterval = -1; // no interval
  2064. return;
  2065. }
  2066.  
  2067. // need some random numbers later
  2068. init_rand();
  2069.  
  2070. // update interval, set it to LCM(all text intervals)
  2071. m_InfoTextInterval = 1; // lowest possible interval
  2072. CInfoText *t = m_InfoTexts;
  2073. while(t != NULL)
  2074. {
  2075. m_InfoTextInterval = lcm(m_InfoTextInterval, t->m_Interval);
  2076. t->m_IntervalTicks = TickSpeed() * 60 * t->m_Interval; // min to ticks
  2077. t->m_NextTick = rand() % t->m_IntervalTicks; // variance
  2078. t = t->m_Next;
  2079. }
  2080. m_InfoTextInterval *= TickSpeed() * 60; // min to ticks
  2081.  
  2082. // count total number of messages per interval
  2083. int numMsg = 0;
  2084. t = m_InfoTexts;
  2085. while(t != NULL)
  2086. {
  2087. numMsg += m_InfoTextInterval / t->m_IntervalTicks;
  2088. t = t->m_Next;
  2089. }
  2090.  
  2091. // interval between messages
  2092. m_InfoTextMsgInterval = m_InfoTextInterval / numMsg;
  2093. // additional pause to sync interval and msg interval
  2094. m_InfoTextIntervalPause = m_InfoTextInterval % numMsg;
  2095. }
  2096.  
  2097. std::string CServer::GetNextInfoText()
  2098. {
  2099. CInfoText *selectedText = NULL,
  2100. *t = m_InfoTexts;
  2101. // the counter r keeps track of how many equally due texts there are and actually helps so that every text has the same chance even though there are r-1 random decisions
  2102. int r = 1;
  2103. while(t != NULL)
  2104. {
  2105. // use this text if none is selected or this one is more due than the previously selected
  2106. // in the case that both are equally due, select one random
  2107. if(selectedText == NULL
  2108. || t->m_NextTick < selectedText->m_NextTick
  2109. || (t->m_NextTick == selectedText->m_NextTick && (rand() % ++r) == 0))
  2110. selectedText = t;
  2111. t = t->m_Next;
  2112. }
  2113.  
  2114. // return empty string if no text applies
  2115. if(selectedText == NULL)
  2116. return std::string();
  2117.  
  2118. // update tick and return string
  2119. selectedText->m_NextTick += selectedText->m_IntervalTicks;
  2120. return selectedText->m_Text;
  2121. }
  2122.  
  2123. void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
  2124. {
  2125. if(pResult->NumArguments() > 1)
  2126. {
  2127. char aBuf[128];
  2128. str_format(aBuf, sizeof(aBuf), "Kicked (%s)", pResult->GetString(1));
  2129. ((CServer *)pUser)->Kick(pResult->GetInteger(0), aBuf);
  2130. }
  2131. else
  2132. ((CServer *)pUser)->Kick(pResult->GetInteger(0), "Kicked by console");
  2133. }
  2134.  
  2135. void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
  2136. {
  2137. char aBuf[1024];
  2138. char aAddrStr[NETADDR_MAXSTRSIZE];
  2139. CServer* pThis = static_cast<CServer *>(pUser);
  2140. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "==========================================================================================");
  2141. for(int i = 0; i < MAX_CLIENTS; i++)
  2142. {
  2143. if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY)
  2144. {
  2145. net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true);
  2146. if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME)
  2147. {
  2148. char bBuf[32];
  2149. str_format(bBuf, sizeof(bBuf), "(Subadmin:%s)", pThis->m_aClients[i].m_SubAdminAuthName.c_str());
  2150. const char *pAuthStr = pThis->m_aClients[i].m_Authed == CServer::AUTHED_ADMIN ? "(Admin)" :
  2151. pThis->m_aClients[i].m_Authed == CServer::AUTHED_SUBADMIN ? bBuf :
  2152. pThis->m_aClients[i].m_Authed == CServer::AUTHED_MOD ? "(Mod)" : "";
  2153. const char *pAimBotStr = pThis->GameServer()->IsClientAimBot(i) ? "[aimbot]" : "";
  2154. str_format(aBuf, sizeof(aBuf), "id=%d name='%s' score=%d addr=%s %s %s", i, pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score, aAddrStr,
  2155. pAuthStr, pAimBotStr);
  2156. }
  2157. else
  2158. str_format(aBuf, sizeof(aBuf), "id=%d addr=%s (connecting...)", i, aAddrStr);
  2159. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
  2160. }
  2161. }
  2162. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "Quick help: kick <id> <reason=''> | ban <id> <min=5> <reason=''> | voteban <id> <sec=300> | kill <id>");
  2163. pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", "==========================================================================================");
  2164. }
  2165.  
  2166. void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
  2167. {
  2168. ((CServer *)pUser)->m_RunServer = 0;
  2169. }
  2170.  
  2171. void CServer::DemoRecorder_HandleAutoStart()
  2172. {
  2173. if(g_Config.m_SvAutoDemoRecord)
  2174. {
  2175. m_DemoRecorder.Stop();
  2176. char aFilename[128];
  2177. char aDate[20];
  2178. str_timestamp(aDate, sizeof(aDate));
  2179. str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate);
  2180. m_DemoRecorder.Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "server");
  2181. if(g_Config.m_SvAutoDemoMax)
  2182. {
  2183. // clean up auto recorded demos
  2184. CFileCollection AutoDemos;
  2185. AutoDemos.Init(Storage(), "demos/server", "autorecord", ".demo", g_Config.m_SvAutoDemoMax);
  2186. }
  2187. }
  2188. }
  2189.  
  2190. void CServer::MapReload()
  2191. {
  2192. m_MapReload = 1;
  2193. }
  2194.  
  2195. bool CServer::DemoRecorder_IsRecording()
  2196. {
  2197. return m_DemoRecorder.IsRecording();
  2198. }
  2199.  
  2200. void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
  2201. {
  2202. CServer* pServer = (CServer *)pUser;
  2203. char aFilename[128];
  2204.  
  2205. if(pResult->NumArguments())
  2206. str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pResult->GetString(0));
  2207. else
  2208. {
  2209. char aDate[20];
  2210. str_timestamp(aDate, sizeof(aDate));
  2211. str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aDate);
  2212. }
  2213. pServer->m_DemoRecorder.Start(pServer->Storage(), pServer->Console(), aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_CurrentMapCrc, "server");
  2214. }
  2215.  
  2216. void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser)
  2217. {
  2218. ((CServer *)pUser)->m_DemoRecorder.Stop();
  2219. }
  2220.  
  2221. void CServer::ConMapReload(IConsole::IResult *pResult, void *pUser)
  2222. {
  2223. ((CServer *)pUser)->m_MapReload = 1;
  2224. }
  2225.  
  2226. void CServer::ConLogout(IConsole::IResult *pResult, void *pUser)
  2227. {
  2228. CServer *pServer = (CServer *)pUser;
  2229. pServer->rconLogClientOut(pServer->m_RconClientID);
  2230. }
  2231.  
  2232. void CServer::rconLogClientOut(int ClientID, const char *msg)
  2233. {
  2234. if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State != CServer::CClient::STATE_EMPTY && IsAuthed(ClientID))
  2235. {
  2236. CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
  2237. Msg.AddInt(0); //authed
  2238. Msg.AddInt(0); //cmdlist
  2239. SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true);
  2240.  
  2241. m_aClients[ClientID].m_Authed = AUTHED_NO;
  2242. m_aClients[ClientID].m_AuthTries = 0;
  2243. m_aClients[ClientID].m_pRconCmdToSend = 0;
  2244. SendRconLine(ClientID, msg);
  2245. char aBuf[32];
  2246. str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", ClientID);
  2247. Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
  2248. UpdateLoggedInAdmins();
  2249. }
  2250. }
  2251.  
  2252. void CServer::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
  2253. {
  2254. pfnCallback(pResult, pCallbackUserData);
  2255. if(pResult->NumArguments())
  2256. ((CServer *)pUserData)->UpdateServerInfo();
  2257. }
  2258.  
  2259. void CServer::ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
  2260. {
  2261. pfnCallback(pResult, pCallbackUserData);
  2262. if(pResult->NumArguments())
  2263. ((CServer *)pUserData)->m_NetServer.SetMaxClientsPerIP(pResult->GetInteger(0));
  2264. }
  2265.  
  2266. void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
  2267. {
  2268. if(pResult->NumArguments() == 2)
  2269. {
  2270. CServer *pThis = static_cast<CServer *>(pUserData);
  2271. const IConsole::CCommandInfo *pInfo = pThis->Console()->GetCommandInfo(pResult->GetString(0), CFGFLAG_SERVER, false);
  2272. int OldAccessLevel = 0;
  2273. if(pInfo)
  2274. OldAccessLevel = pInfo->GetAccessLevel();
  2275. pfnCallback(pResult, pCallbackUserData);
  2276. if(pInfo && OldAccessLevel != pInfo->GetAccessLevel())
  2277. {
  2278. for(int i = 0; i < MAX_CLIENTS; ++i)
  2279. {
  2280. if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || pThis->m_aClients[i].m_Authed != CServer::AUTHED_MOD ||
  2281. (pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0))
  2282. continue;
  2283.  
  2284. if(OldAccessLevel == IConsole::ACCESS_LEVEL_ADMIN)
  2285. pThis->SendRconCmdAdd(pInfo, i);
  2286. else
  2287. pThis->SendRconCmdRem(pInfo, i);
  2288. }
  2289. }
  2290. }
  2291. else
  2292. pfnCallback(pResult, pCallbackUserData);
  2293. }
  2294.  
  2295. void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
  2296. {
  2297. pfnCallback(pResult, pCallbackUserData);
  2298. if(pResult->NumArguments() == 1)
  2299. {
  2300. CServer *pThis = static_cast<CServer *>(pUserData);
  2301. pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
  2302. }
  2303. }
  2304.  
  2305. void CServer::RegisterCommands()
  2306. {
  2307. m_pConsole = Kernel()->RequestInterface<IConsole>();
  2308. m_pGameServer = Kernel()->RequestInterface<IGameServer>();
  2309. m_pMap = Kernel()->RequestInterface<IEngineMap>();
  2310. m_pStorage = Kernel()->RequestInterface<IStorage>();
  2311.  
  2312. // register console commands
  2313. Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason");
  2314. Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players");
  2315. Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down");
  2316. Console()->Register("logout", "", CFGFLAG_SERVER, ConLogout, this, "Logout of rcon");
  2317.  
  2318. Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file");
  2319. Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording");
  2320.  
  2321. Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "");
  2322.  
  2323. Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
  2324. Console()->Chain("sv_name_admin", ConchainSpecialInfoupdate, this);
  2325. Console()->Chain("password", ConchainSpecialInfoupdate, this);
  2326.  
  2327. Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this);
  2328. Console()->Chain("mod_command", ConchainModCommandUpdate, this);
  2329. Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this);
  2330.  
  2331. Console()->Register("voteban", "i?i", CFGFLAG_SERVER, ConVoteban, this, "Voteban a player by id");
  2332. Console()->Register("unvoteban", "i", CFGFLAG_SERVER, ConUnvoteban, this, "Remove voteban by index in list votebans");
  2333. Console()->Register("unvoteban_client", "i", CFGFLAG_SERVER, ConUnvotebanClient, this, "Remove voteban by player id");
  2334. Console()->Register("votebans", "", CFGFLAG_SERVER, ConVotebans, this, "Show all votebans");
  2335.  
  2336. Console()->Register("add_login", "ss", CFGFLAG_SERVER, ConAddLogin, this, "Add a subadmin login. The rcon password will be user:pass with no additional spaces.", IConsole::ACCESS_LEVEL_ADMIN);
  2337. Console()->Register("remove_login", "s", CFGFLAG_SERVER, ConRemoveLogin, this, "Remove a subadmin login", IConsole::ACCESS_LEVEL_ADMIN);
  2338.  
  2339. Console()->Register("add_info", "is", CFGFLAG_SERVER, ConAddInfo, this, "Add a info text that is printed in the chat repeatedly in the given interval of minutes.");
  2340. Console()->Register("remove_info", "i", CFGFLAG_SERVER, ConRemoveInfo, this, "Remove a info text");
  2341. Console()->Register("list_info", "", CFGFLAG_SERVER, ConListInfo, this, "Show all info texts");
  2342.  
  2343. // register console commands in sub parts
  2344. m_ServerBan.InitServerBan(Console(), Storage(), this);
  2345. m_pGameServer->OnConsoleInit();
  2346. }
  2347.  
  2348.  
  2349. int CServer::SnapNewID()
  2350. {
  2351. return m_IDPool.NewID();
  2352. }
  2353.  
  2354. void CServer::SnapFreeID(int ID)
  2355. {
  2356. m_IDPool.FreeID(ID);
  2357. }
  2358.  
  2359.  
  2360. void *CServer::SnapNewItem(int Type, int ID, int Size)
  2361. {
  2362. dbg_assert(Type >= 0 && Type <=0xffff, "incorrect type");
  2363. dbg_assert(ID >= 0 && ID <=0xffff, "incorrect id");
  2364. return ID < 0 ? 0 : m_SnapshotBuilder.NewItem(Type, ID, Size);
  2365. }
  2366.  
  2367. void CServer::SnapSetStaticsize(int ItemType, int Size)
  2368. {
  2369. m_SnapshotDelta.SetStaticsize(ItemType, Size);
  2370. }
  2371.  
  2372. static CServer *CreateServer() { return new CServer(); }
  2373.  
  2374. int main(int argc, const char **argv) // ignore_convention
  2375. {
  2376. #if defined(CONF_FAMILY_WINDOWS)
  2377. for(int i = 1; i < argc; i++) // ignore_convention
  2378. {
  2379. if(str_comp("-s", argv[i]) == 0 || str_comp("--silent", argv[i]) == 0) // ignore_convention
  2380. {
  2381. ShowWindow(GetConsoleWindow(), SW_HIDE);
  2382. break;
  2383. }
  2384. }
  2385. #endif
  2386.  
  2387. //bool UseDefaultConfig = false;
  2388. for(int i = 1; i < argc; i++) // ignore_convention
  2389. {
  2390. if(str_comp("-d", argv[i]) == 0 || str_comp("--default", argv[i]) == 0) // ignore_convention
  2391. {
  2392. //UseDefaultConfig = true;
  2393. break;
  2394. }
  2395. }
  2396.  
  2397. if(secure_random_init() != 0)
  2398. {
  2399. dbg_msg("secure", "could not initialize secure RNG");
  2400. return -1;
  2401. }
  2402.  
  2403. CServer *pServer = CreateServer();
  2404. IKernel *pKernel = IKernel::Create();
  2405.  
  2406. // create the components
  2407. IEngine *pEngine = CreateEngine("Teeworlds");
  2408. IEngineMap *pEngineMap = CreateEngineMap();
  2409. IGameServer *pGameServer = CreateGameServer();
  2410. IConsole *pConsole = CreateConsole(CFGFLAG_SERVER|CFGFLAG_ECON);
  2411. IEngineMasterServer *pEngineMasterServer = CreateEngineMasterServer();
  2412. IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_SERVER, argc, argv); // ignore_convention
  2413. IConfig *pConfig = CreateConfig();
  2414.  
  2415. pServer->InitRegister(&pServer->m_NetServer, pEngineMasterServer, pConsole);
  2416.  
  2417. {
  2418. bool RegisterFail = false;
  2419.  
  2420. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pServer); // register as both
  2421. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pEngine);
  2422. RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast<IEngineMap*>(pEngineMap)); // register as both
  2423. RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast<IMap*>(pEngineMap));
  2424. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pGameServer);
  2425. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConsole);
  2426. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pStorage);
  2427. RegisterFail = RegisterFail || !pKernel->RegisterInterface(pConfig);
  2428. RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast<IEngineMasterServer*>(pEngineMasterServer)); // register as both
  2429. RegisterFail = RegisterFail || !pKernel->RegisterInterface(static_cast<IMasterServer*>(pEngineMasterServer));
  2430.  
  2431. if(RegisterFail)
  2432. return -1;
  2433. }
  2434.  
  2435. pEngine->Init();
  2436. pConfig->Init();
  2437. pEngineMasterServer->Init();
  2438. pEngineMasterServer->Load();
  2439.  
  2440. // register all console commands
  2441. pServer->RegisterCommands();
  2442.  
  2443. /* This banmaster is added into the source of the server that i'm able to ban players even if no banmaster.cfg is used.
  2444. * Often serverhoster doesn't add this file because they don't know what it is for and remove it, not
  2445. * because they don't want it. If so, set sv_global_bantime to 0 or use a custom banmasters.cfg with "clear_banmasters"
  2446. * in first line or in normal config.
  2447. * ## For a Teeworlds without bots \o/ ##
  2448. */
  2449. pConsole->ExecuteLine("add_banmaster banmaster.teetw.de");
  2450.  
  2451. // execute autoexec file
  2452. pConsole->ExecuteFile("autoexec.cfg");
  2453.  
  2454. // parse the command line arguments
  2455. if(argc > 1) // ignore_convention
  2456. pConsole->ParseArguments(argc-1, &argv[1]); // ignore_convention
  2457.  
  2458. // restore empty config strings to their defaults
  2459. pConfig->RestoreStrings();
  2460.  
  2461. pEngine->InitLogfile();
  2462.  
  2463. // run the server
  2464. dbg_msg("server", "starting...");
  2465. pServer->Run();
  2466.  
  2467. // free
  2468. delete pServer;
  2469. delete pKernel;
  2470. delete pEngineMap;
  2471. delete pGameServer;
  2472. delete pConsole;
  2473. delete pEngineMasterServer;
  2474. delete pStorage;
  2475. delete pConfig;
  2476. return 0;
  2477. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement