PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/server/game/Server/WorldSocket.cpp

https://gitlab.com/IlluminatiCore/IlluminatiCore
C++ | 637 lines | 466 code | 119 blank | 52 comment | 71 complexity | 6cdb09358e3308854a74efb67ee0c2e6 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause
  1. /*
  2. * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
  3. * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "WorldSocket.h"
  19. #include "BigNumber.h"
  20. #include "Opcodes.h"
  21. #include "Player.h"
  22. #include "ScriptMgr.h"
  23. #include "SHA1.h"
  24. #include "PacketLog.h"
  25. #include "BattlenetAccountMgr.h"
  26. #include <memory>
  27. using boost::asio::ip::tcp;
  28. std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT");
  29. std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER");
  30. WorldSocket::WorldSocket(tcp::socket&& socket)
  31. : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false)
  32. {
  33. _headerBuffer.Resize(2);
  34. }
  35. void WorldSocket::Start()
  36. {
  37. AsyncRead();
  38. MessageBuffer initializer;
  39. ServerPktHeader header(ServerConnectionInitialize.size(), 0);
  40. initializer.Write(header.header, header.getHeaderLength() - 2);
  41. initializer.Write(ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length());
  42. std::unique_lock<std::mutex> dummy(_writeLock, std::defer_lock);
  43. QueuePacket(std::move(initializer), dummy);
  44. }
  45. void WorldSocket::HandleSendAuthSession()
  46. {
  47. WorldPacket packet(SMSG_AUTH_CHALLENGE, 37);
  48. BigNumber seed1;
  49. seed1.SetRand(16 * 8);
  50. packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds
  51. BigNumber seed2;
  52. seed2.SetRand(16 * 8);
  53. packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds
  54. packet << uint32(_authSeed);
  55. packet << uint8(1);
  56. SendPacket(packet);
  57. }
  58. void WorldSocket::ReadHandler()
  59. {
  60. if (!IsOpen())
  61. return;
  62. MessageBuffer& packet = GetReadBuffer();
  63. while (packet.GetActiveSize() > 0)
  64. {
  65. if (_headerBuffer.GetRemainingSpace() > 0)
  66. {
  67. // need to receive the header
  68. std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
  69. _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
  70. packet.ReadCompleted(readHeaderSize);
  71. if (_headerBuffer.GetRemainingSpace() > 0)
  72. {
  73. // Couldn't receive the whole header this time.
  74. ASSERT(packet.GetActiveSize() == 0);
  75. break;
  76. }
  77. // We just received nice new header
  78. if (!ReadHeaderHandler())
  79. return;
  80. }
  81. // We have full read header, now check the data payload
  82. if (_packetBuffer.GetRemainingSpace() > 0)
  83. {
  84. // need more data in the payload
  85. std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
  86. _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
  87. packet.ReadCompleted(readDataSize);
  88. if (_packetBuffer.GetRemainingSpace() > 0)
  89. {
  90. // Couldn't receive the whole data this time.
  91. ASSERT(packet.GetActiveSize() == 0);
  92. break;
  93. }
  94. }
  95. // just received fresh new payload
  96. if (!ReadDataHandler())
  97. return;
  98. _headerBuffer.Reset();
  99. }
  100. AsyncRead();
  101. }
  102. bool WorldSocket::ReadHeaderHandler()
  103. {
  104. ASSERT(_headerBuffer.GetActiveSize() == (_initialized ? sizeof(ClientPktHeader) : 2));
  105. _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), _headerBuffer.GetActiveSize());
  106. ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
  107. EndianConvertReverse(header->size);
  108. if (_initialized)
  109. EndianConvert(header->cmd);
  110. if (!header->IsValidSize() || (_initialized && !header->IsValidOpcode()))
  111. {
  112. if (_worldSession)
  113. {
  114. Player* player = _worldSession->GetPlayer();
  115. TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)",
  116. _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd);
  117. }
  118. else
  119. TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)",
  120. GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd);
  121. CloseSocket();
  122. return false;
  123. }
  124. if (_initialized)
  125. header->size -= sizeof(header->cmd);
  126. _packetBuffer.Resize(header->size);
  127. return true;
  128. }
  129. bool WorldSocket::ReadDataHandler()
  130. {
  131. if (_initialized)
  132. {
  133. ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
  134. Opcodes opcode = Opcodes(header->cmd);
  135. std::string opcodeName = GetOpcodeNameForLogging(opcode);
  136. WorldPacket packet(opcode, std::move(_packetBuffer));
  137. if (sPacketLog->CanLogPacket())
  138. sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
  139. TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), opcodeName.c_str());
  140. switch (opcode)
  141. {
  142. case CMSG_PING:
  143. HandlePing(packet);
  144. break;
  145. case CMSG_AUTH_SESSION:
  146. if (_worldSession)
  147. {
  148. TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
  149. break;
  150. }
  151. HandleAuthSession(packet);
  152. break;
  153. case CMSG_KEEP_ALIVE:
  154. TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
  155. sScriptMgr->OnPacketReceive(_worldSession, packet);
  156. break;
  157. case CMSG_LOG_DISCONNECT:
  158. packet.rfinish(); // contains uint32 disconnectReason;
  159. TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
  160. sScriptMgr->OnPacketReceive(_worldSession, packet);
  161. return true;
  162. case CMSG_ENABLE_NAGLE:
  163. {
  164. TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
  165. sScriptMgr->OnPacketReceive(_worldSession, packet);
  166. if (_worldSession)
  167. _worldSession->HandleEnableNagleAlgorithm();
  168. break;
  169. }
  170. default:
  171. {
  172. if (!_worldSession)
  173. {
  174. TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
  175. CloseSocket();
  176. return false;
  177. }
  178. // prevent invalid memory access/crash with custom opcodes
  179. if (opcode >= NUM_OPCODE_HANDLERS)
  180. {
  181. CloseSocket();
  182. return false;
  183. }
  184. OpcodeHandler const* handler = opcodeTable[opcode];
  185. if (!handler)
  186. {
  187. TC_LOG_ERROR("network.opcode", "No defined handler for opcode %s sent by %s", GetOpcodeNameForLogging(packet.GetOpcode()).c_str(), _worldSession->GetPlayerInfo().c_str());
  188. return true;
  189. }
  190. // Our Idle timer will reset on any non PING opcodes.
  191. // Catches people idling on the login screen and any lingering ingame connections.
  192. _worldSession->ResetTimeOutTime();
  193. // Copy the packet to the heap before enqueuing
  194. _worldSession->QueuePacket(new WorldPacket(std::move(packet)));
  195. break;
  196. }
  197. }
  198. }
  199. else
  200. {
  201. std::string initializer(reinterpret_cast<char const*>(_packetBuffer.GetReadPointer()), std::min(_packetBuffer.GetActiveSize(), ClientConnectionInitialize.length()));
  202. if (initializer != ClientConnectionInitialize)
  203. {
  204. CloseSocket();
  205. return false;
  206. }
  207. _initialized = true;
  208. _headerBuffer.Resize(sizeof(ClientPktHeader));
  209. _packetBuffer.Reset();
  210. HandleSendAuthSession();
  211. }
  212. return true;
  213. }
  214. void WorldSocket::SendPacket(WorldPacket& packet)
  215. {
  216. if (!IsOpen())
  217. return;
  218. if (sPacketLog->CanLogPacket())
  219. sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());
  220. if (_worldSession && packet.size() > 0x400 && !packet.IsCompressed())
  221. packet.Compress(_worldSession->GetCompressionStream());
  222. TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());
  223. ServerPktHeader header(packet.size() + 2, packet.GetOpcode());
  224. std::unique_lock<std::mutex> guard(_writeLock);
  225. _authCrypt.EncryptSend(header.header, header.getHeaderLength());
  226. #ifndef TC_SOCKET_USE_IOCP
  227. if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size())
  228. {
  229. _writeBuffer.Write(header.header, header.getHeaderLength());
  230. if (!packet.empty())
  231. _writeBuffer.Write(packet.contents(), packet.size());
  232. }
  233. else
  234. #endif
  235. {
  236. MessageBuffer buffer(header.getHeaderLength() + packet.size());
  237. buffer.Write(header.header, header.getHeaderLength());
  238. if (!packet.empty())
  239. buffer.Write(packet.contents(), packet.size());
  240. QueuePacket(std::move(buffer), guard);
  241. }
  242. }
  243. void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
  244. {
  245. uint8 digest[SHA_DIGEST_LENGTH];
  246. uint32 clientSeed;
  247. uint8 security;
  248. uint16 clientBuild;
  249. uint32 id;
  250. uint32 addonSize;
  251. LocaleConstant locale;
  252. std::string account;
  253. SHA1Hash sha;
  254. BigNumber k;
  255. bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
  256. WorldPacket addonsData;
  257. uint8 loginServerType;
  258. uint32 realmIndex;
  259. recvPacket.read_skip<uint32>(); // ServerId - Used for GRUNT only
  260. recvPacket.read_skip<uint32>(); // Battlegroup
  261. recvPacket >> loginServerType;
  262. recvPacket >> digest[10];
  263. recvPacket >> digest[18];
  264. recvPacket >> digest[12];
  265. recvPacket >> digest[5];
  266. recvPacket.read_skip<uint64>();
  267. recvPacket >> digest[15];
  268. recvPacket >> digest[9];
  269. recvPacket >> digest[19];
  270. recvPacket >> digest[4];
  271. recvPacket >> digest[7];
  272. recvPacket >> digest[16];
  273. recvPacket >> digest[3];
  274. recvPacket >> clientBuild;
  275. recvPacket >> digest[8];
  276. recvPacket >> realmIndex;
  277. recvPacket.read_skip<uint8>();
  278. recvPacket >> digest[17];
  279. recvPacket >> digest[6];
  280. recvPacket >> digest[0];
  281. recvPacket >> digest[1];
  282. recvPacket >> digest[11];
  283. recvPacket >> clientSeed;
  284. recvPacket >> digest[2];
  285. recvPacket.read_skip<uint32>(); // Region
  286. recvPacket >> digest[14];
  287. recvPacket >> digest[13];
  288. recvPacket >> addonSize;
  289. if (addonSize)
  290. {
  291. addonsData.resize(addonSize);
  292. recvPacket.read((uint8*)addonsData.contents(), addonSize);
  293. }
  294. recvPacket.ReadBit(); // UseIPv6
  295. uint32 accountNameLength = recvPacket.ReadBits(12);
  296. account = recvPacket.ReadString(accountNameLength);
  297. // Get the account information from the auth database
  298. // 0 1 2 3 4 5 6 7 8 9
  299. // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os, battlenet_account FROM account WHERE username = ?
  300. PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME);
  301. stmt->setString(0, account);
  302. PreparedQueryResult result = LoginDatabase.Query(stmt);
  303. // Stop if the account is not found
  304. if (!result)
  305. {
  306. // We can not log here, as we do not know the account. Thus, no accountId.
  307. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
  308. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
  309. DelayedCloseSocket();
  310. return;
  311. }
  312. Field* fields = result->Fetch();
  313. uint8 expansion = fields[4].GetUInt8();
  314. uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
  315. if (expansion > world_expansion)
  316. expansion = world_expansion;
  317. // For hook purposes, we get Remoteaddress at this point.
  318. std::string address = GetRemoteIpAddress().to_string();
  319. // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
  320. stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
  321. stmt->setString(0, address);
  322. stmt->setString(1, account);
  323. LoginDatabase.Execute(stmt);
  324. // This also allows to check for possible "hack" attempts on account
  325. // id has to be fetched at this point, so that first actual account response that fails can be logged
  326. id = fields[0].GetUInt32();
  327. k.SetHexStr(fields[1].GetCString());
  328. // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
  329. _authCrypt.Init(&k);
  330. // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
  331. if (sWorld->IsClosed())
  332. {
  333. SendAuthResponseError(AUTH_REJECT);
  334. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
  335. DelayedCloseSocket();
  336. return;
  337. }
  338. if (realmIndex != realmHandle.Index)
  339. {
  340. SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
  341. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm).");
  342. DelayedCloseSocket();
  343. return;
  344. }
  345. std::string os = fields[8].GetString();
  346. // Must be done before WorldSession is created
  347. if (wardenActive && os != "Win" && os != "OSX")
  348. {
  349. SendAuthResponseError(AUTH_REJECT);
  350. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
  351. DelayedCloseSocket();
  352. return;
  353. }
  354. // Check that Key and account name are the same on client and server
  355. uint32 t = 0;
  356. sha.UpdateData(account);
  357. sha.UpdateData((uint8*)&t, 4);
  358. sha.UpdateData((uint8*)&clientSeed, 4);
  359. sha.UpdateData((uint8*)&_authSeed, 4);
  360. sha.UpdateBigNumbers(&k, NULL);
  361. sha.Finalize();
  362. if (memcmp(sha.GetDigest(), digest, SHA_DIGEST_LENGTH) != 0)
  363. {
  364. SendAuthResponseError(AUTH_FAILED);
  365. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str());
  366. DelayedCloseSocket();
  367. return;
  368. }
  369. ///- Re-check ip locking (same check as in auth).
  370. if (fields[3].GetUInt8() == 1) // if ip is locked
  371. {
  372. if (strcmp(fields[2].GetCString(), address.c_str()) != 0)
  373. {
  374. SendAuthResponseError(AUTH_FAILED);
  375. TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str());
  376. // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
  377. sScriptMgr->OnFailedAccountLogin(id);
  378. DelayedCloseSocket();
  379. return;
  380. }
  381. }
  382. int64 mutetime = fields[5].GetInt64();
  383. //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
  384. if (mutetime < 0)
  385. {
  386. mutetime = time(NULL) + llabs(mutetime);
  387. stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
  388. stmt->setInt64(0, mutetime);
  389. stmt->setUInt32(1, id);
  390. LoginDatabase.Execute(stmt);
  391. }
  392. locale = LocaleConstant(fields[6].GetUInt8());
  393. if (locale >= TOTAL_LOCALES)
  394. locale = LOCALE_enUS;
  395. uint32 recruiter = fields[7].GetUInt32();
  396. uint32 battlenetAccountId = 0;
  397. if (loginServerType == 1)
  398. battlenetAccountId = fields[9].GetUInt32();
  399. // Checks gmlevel per Realm
  400. stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
  401. stmt->setUInt32(0, id);
  402. stmt->setInt32(1, int32(realmHandle.Index));
  403. result = LoginDatabase.Query(stmt);
  404. if (!result)
  405. security = 0;
  406. else
  407. {
  408. fields = result->Fetch();
  409. security = fields[0].GetUInt8();
  410. }
  411. // Re-check account ban (same check as in auth)
  412. stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS);
  413. stmt->setUInt32(0, id);
  414. stmt->setString(1, address);
  415. PreparedQueryResult banresult = LoginDatabase.Query(stmt);
  416. if (banresult) // if account banned
  417. {
  418. SendAuthResponseError(AUTH_BANNED);
  419. TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
  420. sScriptMgr->OnFailedAccountLogin(id);
  421. DelayedCloseSocket();
  422. return;
  423. }
  424. // Check locked state for server
  425. AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
  426. TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
  427. if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
  428. {
  429. SendAuthResponseError(AUTH_UNAVAILABLE);
  430. TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
  431. sScriptMgr->OnFailedAccountLogin(id);
  432. DelayedCloseSocket();
  433. return;
  434. }
  435. TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
  436. account.c_str(),
  437. address.c_str());
  438. // Check if this user is by any chance a recruiter
  439. stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER);
  440. stmt->setUInt32(0, id);
  441. result = LoginDatabase.Query(stmt);
  442. bool isRecruiter = false;
  443. if (result)
  444. isRecruiter = true;
  445. // Update the last_ip in the database as it was successful for login
  446. stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
  447. stmt->setString(0, address);
  448. stmt->setString(1, account);
  449. LoginDatabase.Execute(stmt);
  450. // At this point, we can safely hook a successful login
  451. sScriptMgr->OnAccountLogin(id);
  452. _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);
  453. _worldSession->LoadGlobalAccountData();
  454. _worldSession->LoadTutorialsData();
  455. _worldSession->ReadAddonsInfo(addonsData);
  456. _worldSession->LoadPermissions();
  457. // Initialize Warden system only if it is enabled by config
  458. if (wardenActive)
  459. _worldSession->InitWarden(&k, os);
  460. sWorld->AddSession(_worldSession);
  461. }
  462. void WorldSocket::SendAuthResponseError(uint8 code)
  463. {
  464. WorldPacket packet(SMSG_AUTH_RESPONSE, 1);
  465. packet.WriteBit(0); // has queue info
  466. packet.WriteBit(0); // has account info
  467. packet << uint8(code);
  468. SendPacket(packet);
  469. }
  470. void WorldSocket::HandlePing(WorldPacket& recvPacket)
  471. {
  472. uint32 ping;
  473. uint32 latency;
  474. // Get the ping packet content
  475. recvPacket >> latency;
  476. recvPacket >> ping;
  477. if (_LastPingTime == steady_clock::time_point())
  478. {
  479. _LastPingTime = steady_clock::now();
  480. }
  481. else
  482. {
  483. steady_clock::time_point now = steady_clock::now();
  484. steady_clock::duration diff = now - _LastPingTime;
  485. _LastPingTime = now;
  486. if (diff < seconds(27))
  487. {
  488. ++_OverSpeedPings;
  489. uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
  490. if (maxAllowed && _OverSpeedPings > maxAllowed)
  491. {
  492. if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING))
  493. {
  494. TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)",
  495. _worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().to_string().c_str());
  496. CloseSocket();
  497. return;
  498. }
  499. }
  500. }
  501. else
  502. _OverSpeedPings = 0;
  503. }
  504. if (_worldSession)
  505. {
  506. _worldSession->SetLatency(latency);
  507. _worldSession->ResetClientTimeDelay();
  508. }
  509. else
  510. {
  511. TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str());
  512. CloseSocket();
  513. return;
  514. }
  515. WorldPacket packet(SMSG_PONG, 4);
  516. packet << ping;
  517. return SendPacket(packet);
  518. }