/// Update the WorldSession (triggered by World update) bool WorldSession::Update(PacketFilter& updater) { std::lock_guard<std::mutex> guard(m_recvQueueLock); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed while (m_Socket && !m_Socket->IsClosed() && !m_recvQueue.empty()) { auto const packet = std::move(m_recvQueue.front()); m_recvQueue.pop_front(); /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); #endif*/ OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if (!m_playerRecentlyLogout) LogUnexpectedOpcode(*packet, "the player has not logged in yet"); } else if (_player->IsInWorld()) ExecuteOpcode(opHandle, *packet); // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer #ifdef BUILD_PLAYERBOT if (_player && _player->GetPlayerbotMgr()) _player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet); #endif break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: if (!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(*packet, "the player has not logged in yet and not recently logout"); } else // not expected _player or must checked in packet hanlder ExecuteOpcode(opHandle, *packet); break; case STATUS_TRANSFER: if (!_player) LogUnexpectedOpcode(*packet, "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(*packet, "the player is still in world"); else ExecuteOpcode(opHandle, *packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(*packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; ExecuteOpcode(opHandle, *packet); break; case STATUS_NEVER: sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; case STATUS_UNHANDLED: DEBUG_LOG("SESSION: received not handled opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; default: sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; } } catch (ByteBufferException&) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) { DEBUG_LOG("Dumping error causing packet:"); packet->hexlike(); } if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET)) { DETAIL_LOG("Disconnecting session [account id %u / address %s] for badly formatted packet.", GetAccountId(), GetRemoteAddress().c_str()); KickPlayer(); } } } #ifdef BUILD_PLAYERBOT // Process player bot packets // The PlayerbotAI class adds to the packet queue to simulate a real player // since Playerbots are known to the World obj only by its master's WorldSession object // we need to process all master's bot's packets. if (GetPlayer() && GetPlayer()->GetPlayerbotMgr()) { for (PlayerBotMap::const_iterator itr = GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsBegin(); itr != GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsEnd(); ++itr) { Player* const botPlayer = itr->second; WorldSession* const pBotWorldSession = botPlayer->GetSession(); if (botPlayer->IsBeingTeleported()) botPlayer->GetPlayerbotAI()->HandleTeleportAck(); else if (botPlayer->IsInWorld()) { while (!pBotWorldSession->m_recvQueue.empty()) { auto const botpacket = std::move(pBotWorldSession->m_recvQueue.front()); pBotWorldSession->m_recvQueue.pop_front(); OpcodeHandler const& opHandle = opcodeTable[botpacket->GetOpcode()]; pBotWorldSession->ExecuteOpcode(opHandle, *botpacket); }; pBotWorldSession->m_recvQueue.clear(); } } } #endif // check if we are safe to proceed with logout // logout procedure should happen only in World::UpdateSessions() method!!! if (updater.ProcessLogout()) { ///- If necessary, log the player out const time_t currTime = time(nullptr); if (!m_Socket || m_Socket->IsClosed() || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); // finalize the session if disconnected. if (!m_Socket || m_Socket->IsClosed()) return false; } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 /*diff*/) { ///- Retrieve packets from the receive queue and call the appropriate handlers /// not proccess packets if socket already closed WorldPacket* packet; while (_recvQueue.next(packet) && m_Socket && !m_Socket->IsClosed ()) { /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ if(packet->GetOpcode() >= NUM_MSG_TYPES) { sLog.outError( "SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); } else { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; /* if(_player) { if(packet->GetOpcode()!=CMSG_MOVE_TIME_SKIPPED) { sLog.outError("Send:%u (OP:%u)<%s>",_player->GetGUID(), opcodeTable[packet->GetOpcode()],LookupOpcodeName(packet->GetOpcode())); packet->Print(); packet->rpos(0); } }*/ try { switch (opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: if(!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else { // not expected _player or must checked in packet hanlder (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if(!_player) LogUnexpectedOpcode(packet, "the player has not logged in yet"); else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if(m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); break; case STATUS_NEVER: break; sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch(ByteBufferException &) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if(sLog.IsOutDebug()) { sLog.outDebug("Dumping error causing packet:"); packet->hexlike(); } } } delete packet; } ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed ()) { m_Socket->RemoveReference (); m_Socket = NULL; } ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); if (!m_Socket) return false; //Will remove this session from the world session map return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff, PacketFilter& updater) { /// Update Timeout timer. UpdateTimeOutTime(diff); ///- Before we process anything: /// If necessary, kick the player from the character select screen if(IsConnectionIdle()) m_Socket->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; while(m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet, updater)) { if(packet->GetOpcode() >= NUM_MSG_TYPES) { sLog->outError("SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet)); } else { OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; try { switch(opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN", "the player has not logged in yet"); } else if(_player->IsInWorld()) { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if(sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: if(!_player && !m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", "the player has not logged in yet and not recently logout"); else { // not expected _player or must checked in packet hanlder sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if(sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if(!_player) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); else { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if(sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if(m_inQueue) { LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if(packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if(sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); break; case STATUS_NEVER: sLog->outError("SESSION (account: %u, guidlow: %u, char: %s): received not allowed opcode %s (0x%.4X)", GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; case STATUS_UNHANDLED: sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION (account: %u, guidlow: %u, char: %s): received not handled opcode %s (0x%.4X)", GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch(ByteBufferException &) { sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if(sLog->IsOutDebug()) { sLog->outDebug(LOG_FILTER_NETWORKIO, "Dumping error causing packet:"); packet->hexlike(); } } } delete packet; } ProcessQueryCallbacks(); if(m_Socket && !m_Socket->IsClosed() && m_Warden) m_Warden->Update(); //check if we are safe to proceed with logout //logout procedure should happen only in World::UpdateSessions() method!!! if(updater.ProcessLogout()) { time_t currTime = time(NULL); ///- If necessary, log the player out if(ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); ///- Cleanup socket pointer if need if(m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } if(!m_Socket) return false; //Will remove this session from the world session map } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(PacketFilter& updater) { ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet, updater)) { /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); #endif*/ OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if (!m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet"); } } else if (_player->IsInWorld()) { ExecuteOpcode(opHandle, packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: if (!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else // not expected _player or must checked in packet hanlder { ExecuteOpcode(opHandle, packet); } break; case STATUS_TRANSFER: if (!_player) { LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if (_player->IsInWorld()) { LogUnexpectedOpcode(packet, "the player is still in world"); } else { ExecuteOpcode(opHandle, packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. m_playerRecentlyLogout = false; ExecuteOpcode(opHandle, packet); break; case STATUS_NEVER: sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; case STATUS_UNHANDLED: DEBUG_LOG("SESSION: received not handled opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; default: sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)", packet->GetOpcodeName(), packet->GetOpcode()); break; } } catch (ByteBufferException&) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) { DEBUG_LOG("Dumping error causing packet:"); packet->hexlike(); } if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET)) { DETAIL_LOG("Disconnecting session [account id %u / address %s] for badly formatted packet.", GetAccountId(), GetRemoteAddress().c_str()); KickPlayer(); } } delete packet; } ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } // check if we are safe to proceed with logout // logout procedure should happen only in World::UpdateSessions() method!!! if (updater.ProcessLogout()) { ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) { LogoutPlayer(true); } if (!m_Socket) { return false; } // Will remove this session from the world session map } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff, PacketFilter& updater) { /// Update Timeout timer. UpdateTimeOutTime(diff); ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) m_Socket->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; //! Delete packet after processing by default bool deletePacket = true; //! To prevent infinite loop WorldPacket* firstDelayedPacket = NULL; //! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all //! *properly timed* packets, and we're now at the part of the queue where we find //! delayed packets that were re-enqueued due to improper timing. To prevent an infinite //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (!AntiDOS.EvaluateOpcode(*packet)) { KickPlayer(); } else if (packet->GetOpcode() >= NUM_MSG_TYPES) { TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() , GetPlayerInfo().c_str()); sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet)); } else { OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. if (!m_playerRecentlyLogout) { //! Prevent infinite loop if (!firstDelayedPacket) firstDelayedPacket = packet; //! Because checking a bool is faster than reallocating memory deletePacket = false; QueuePacket(packet); //! Log TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. " "Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()); } } else if (_player->IsInWorld()) { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); LogUnprocessedTail(packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", "the player has not logged in yet and not recently logout"); else { // not expected _player or must checked in packet handler sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if (!_player) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); else { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); break; } // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. if (packet->GetOpcode() == CMSG_CHAR_ENUM) m_playerRecentlyLogout = false; sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); LogUnprocessedTail(packet); break; case STATUS_NEVER: TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() , GetPlayerInfo().c_str()); break; case STATUS_UNHANDLED: TC_LOG_DEBUG(LOG_FILTER_OPCODES, "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str() , GetPlayerInfo().c_str()); break; } } catch (ByteBufferException const&) { TC_LOG_ERROR(LOG_FILTER_GENERAL, "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); packet->hexlike(); } } if (deletePacket) delete packet; deletePacket = true; } if (m_Socket && !m_Socket->IsClosed() && _warden) _warden->Update(); ProcessQueryCallbacks(); //check if we are safe to proceed with logout //logout procedure should happen only in World::UpdateSessions() method!!! if (updater.ProcessLogout()) { time_t currTime = time(NULL); ///- If necessary, log the player out if (ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); if (m_Socket && GetPlayer() && _warden) _warden->Update(); ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } if (!m_Socket) return false; //Will remove this session from the world session map } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 /*diff*/) { if (m_Socket && m_Socket->IsClosed ()) { m_Socket->RemoveReference (); m_Socket = NULL; } WorldPacket *packet; ///- Retrieve packets from the receive queue and call the appropriate handlers /// \todo Is there a way to consolidate the OpcondeHandlerTable and the g_worldOpcodeNames to only maintain 1 list? /// answer : there is a way, but this is better, because it would use redundant RAM while (!_recvQueue.empty()) { packet = _recvQueue.next(); /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ if(packet->GetOpcode() >= NUM_MSG_TYPES) { sLog.outError( "SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); } else { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; switch (opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) logUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) (this->*opHandle.handler)(*packet); // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_TRANSFER_PENDING: if(!_player) logUnexpectedOpcode(packet, "the player has not logged in yet"); else if(_player->IsInWorld()) logUnexpectedOpcode(packet, "the player is still in world"); else (this->*opHandle.handler)(*packet); break; case STATUS_AUTHED: m_playerRecentlyLogout = false; (this->*opHandle.handler)(*packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } delete packet; } ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); if (!m_Socket) return false; //Will remove this session from the world session map return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 /*diff*/) { ///- Retrieve packets from the receive queue and call the appropriate handlers /// not proccess packets if socket already closed while (!_recvQueue.empty() && m_Socket && !m_Socket->IsClosed ()) { WorldPacket *packet = _recvQueue.next(); /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ if(packet->GetOpcode() >= NUM_MSG_TYPES) { sLog.outError( "SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); } else { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; switch (opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) logUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) (this->*opHandle.handler)(*packet); // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_TRANSFER_PENDING: if(!_player) logUnexpectedOpcode(packet, "the player has not logged in yet"); else if(_player->IsInWorld()) logUnexpectedOpcode(packet, "the player is still in world"); else (this->*opHandle.handler)(*packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait if(m_inQueue) { logUnexpectedOpcode(packet, "the player not pass queue yet"); break; } m_playerRecentlyLogout = false; (this->*opHandle.handler)(*packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } delete packet; } ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed ()) { m_Socket->RemoveReference (); m_Socket = NULL; } ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); if (!m_Socket) return false; //Will remove this session from the world session map return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff, PacketFilter& updater) { if (updater.ProcessLogout()) { UpdateTimeOutTime(diff); if (IsConnectionIdle()) m_Socket->CloseSocket(); } HandleTeleportTimeout(updater.ProcessLogout()); uint32 _startMSTime = getMSTime(); WorldPacket* packet = NULL; WorldPacket* movementPacket = NULL; bool deletePacket = true; WorldPacket* firstDelayedPacket = NULL; uint32 processedPackets = 0; while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (packet->GetOpcode() < NUM_MSG_TYPES) { OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // pussywizard: such packets were sent to do something for a character that has already logged out, skip them } else if (!_player->IsInWorld()) { // pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue // pussywizard: previously such were skipped, so leave it as it is xD proper code below if we wish to change that // pussywizard: requeue only important packets not related to maps (PROCESS_THREADUNSAFE) /*if (opHandle.packetProcessing == PROCESS_THREADUNSAFE) { if (!firstDelayedPacket) firstDelayedPacket = packet; deletePacket = false; QueuePacket(packet); }*/ } else { if (opHandle.isGrouppedMovementOpcode) { if (movementPacket) delete movementPacket; movementPacket = new WorldPacket(packet->GetOpcode(), 0); movementPacket->append(*((ByteBuffer*)packet)); } else { if (movementPacket) { HandleMovementOpcodes(*movementPacket); delete movementPacket; movementPacket = NULL; } sScriptMgr->OnPacketReceive(this, *packet); #ifdef ELUNA if (!sEluna->OnPacketReceive(this, *packet)) break; #endif (this->*opHandle.handler)(*packet); } } break; case STATUS_TRANSFER: if (_player && !_player->IsInWorld()) { if (movementPacket) { delete movementPacket; movementPacket = NULL; } sScriptMgr->OnPacketReceive(this, *packet); #ifdef ELUNA if (!sEluna->OnPacketReceive(this, *packet)) break; #endif (this->*opHandle.handler)(*packet); } break; case STATUS_AUTHED: if (m_inQueue) // prevent cheating break; sScriptMgr->OnPacketReceive(this, *packet); #ifdef ELUNA if (!sEluna->OnPacketReceive(this, *packet)) break; #endif (this->*opHandle.handler)(*packet); break; case STATUS_NEVER: break; case STATUS_UNHANDLED: break; } } catch(ByteBufferException &) { sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog->IsOutDebug()) { sLog->outDebug(LOG_FILTER_NETWORKIO, "Dumping error causing packet:"); packet->hexlike(); } } } if (deletePacket) delete packet; else deletePacket = true; if (++processedPackets >= 150) // limit (by count) packets processed in one update, prevent DDoS break; if (getMSTimeDiff(_startMSTime, getMSTime()) >= 3) // limit (by time) packets processed in one update, prevent DDoS break; } if (movementPacket) { if (_player && _player->IsInWorld()) HandleMovementOpcodes(*movementPacket); delete movementPacket; } if (m_Socket && !m_Socket->IsClosed()) ProcessQueryCallbacks(); if (updater.ProcessLogout()) { time_t currTime = time(NULL); if (ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); if (m_Socket && !m_Socket->IsClosed() && _warden) _warden->Update(); if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } if (!m_Socket) return false; } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(PacketFilter& updater) { ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet, updater)) { /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ DEBUG_LOG("Received packet %u %s from %s", packet->GetOpcode(), LookupOpcodeName(packet->GetOpcode()), GetPlayer() ? GetPlayer()->GetGuidStr().c_str() : "<unknown>"); OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; try { if (GetPlayer()) DEBUG_LOG("Received packet %s (size %u) from %s", opHandle.name, packet->size(), GetPlayer()->GetGuidStr().c_str()); switch (opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) ExecuteOpcode(opHandle, packet); // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer // playerbot mod if (!sWorld.getConfig(CONFIG_BOOL_PLAYERBOT_DISABLE)) if (_player && _player->GetPlayerbotMgr()) _player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet); // playerbot mod end break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: if(!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else // not expected _player or must checked in packet hanlder ExecuteOpcode(opHandle, packet); break; case STATUS_TRANSFER: if(!_player) LogUnexpectedOpcode(packet, "the player has not logged in yet"); else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else ExecuteOpcode(opHandle, packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait if(m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; ExecuteOpcode(opHandle, packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; case STATUS_UNHANDLED: DEBUG_LOG("SESSION: received unhandled opcode %s (0x%.4X) (real value may be not shown there)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; default: sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch (ByteBufferException &) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: 0x%.4X, %s) from client %s, accountid = %i.", packet->GetOpcode(), LookupOpcodeName(packet->GetOpcode()), GetRemoteAddress().c_str(), GetAccountId()); if (sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) { DEBUG_LOG("Dumping error causing packet:"); packet->hexlike(); } if (sWorld.getConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET)) { DETAIL_LOG("Disconnecting session [account id %u / address %s] for badly formatted packet.", GetAccountId(), GetRemoteAddress().c_str()); KickPlayer(); } } delete packet; } // Playerbot mod - Process player bot packets // The PlayerbotAI class adds to the packet queue to simulate a real player // since Playerbots are known to the World obj only by its master's WorldSession object // we need to process all master's bot's packets. if (!sWorld.getConfig(CONFIG_BOOL_PLAYERBOT_DISABLE)) { if (GetPlayer() && GetPlayer()->GetPlayerbotMgr()) { for (PlayerBotMap::const_iterator itr = GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsBegin(); itr != GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsEnd(); ++itr) { Player* const botPlayer = itr->second; WorldSession* const pBotWorldSession = botPlayer->GetSession(); if (botPlayer->IsBeingTeleported()) botPlayer->GetPlayerbotAI()->HandleTeleportAck(); else if (botPlayer->IsInWorld()) { WorldPacket* packet; while (pBotWorldSession->_recvQueue.next(packet)) { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; (pBotWorldSession->*opHandle.handler)(*packet); delete packet; } } } } } if (m_Socket && !m_Socket->IsClosed() && m_Warden && GetPlayer() && !GetPlayer()->GetPlayerbotAI()) m_Warden->Update(); ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } //check if we are safe to proceed with logout //logout procedure should happen only in World::UpdateSessions() method!!! if(updater.ProcessLogout()) { ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); if (!m_Socket) return false; //Will remove this session from the world session map } return true; }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 /*diff*/) { ///- Retrieve packets from the receive queue and call the appropriate handlers /// not proccess packets if socket already closed WorldPacket* packet; while (_recvQueue.next(packet) && m_Socket && !m_Socket->IsClosed ()) { /*#if 1 sLog.outError( "MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if(!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if(!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer // playerbot mod if (_player && _player->GetPlayerbotMgr()) _player->GetPlayerbotMgr()->HandleMasterIncomingPacket(*packet); // playerbot mod end break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: if(!_player && !m_playerRecentlyLogout) { LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else { // not expected _player or must checked in packet hanlder (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if(!_player) LogUnexpectedOpcode(packet, "the player has not logged in yet"); else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else { (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if(m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } // single from authed time opcodes send in to after logout time // and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes. if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; (this->*opHandle.handler)(*packet); if (sLog.IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; case STATUS_UNHANDLED: sLog.outDebug("SESSION: received not handled opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; default: sLog.outError("SESSION: received wrong-status-req opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch(ByteBufferException &) { sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if(sLog.IsOutDebug()) { sLog.outDebug("Dumping error causing packet:"); packet->hexlike(); } } delete packet; } // Playerbot mod - Process player bot packets // The PlayerbotAI class adds to the packet queue to simulate a real player // since Playerbots are known to the World obj only by its master's WorldSession object // we need to process all master's bot's packets. if (GetPlayer() && GetPlayer()->GetPlayerbotMgr()) { for (PlayerBotMap::const_iterator itr = GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsBegin(); itr != GetPlayer()->GetPlayerbotMgr()->GetPlayerBotsEnd(); ++itr) { Player* const botPlayer = itr->second; WorldSession* const pBotWorldSession = botPlayer->GetSession(); if (botPlayer->IsBeingTeleported()) botPlayer->GetPlayerbotAI()->HandleTeleportAck(); else if (botPlayer->IsInWorld()) { WorldPacket* packet; while (pBotWorldSession->_recvQueue.next(packet)) { OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; (pBotWorldSession->*opHandle.handler)(*packet); delete packet; } } } } ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed ()) { m_Socket->RemoveReference (); m_Socket = NULL; } ///- If necessary, log the player out time_t currTime = time(NULL); if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) LogoutPlayer(true); if (!m_Socket) return false; //Will remove this session from the world session map return true; }
// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff) { /// Update Timeout timer. UpdateTimeOutTime(diff); ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) m_Socket->CloseSocket(); // Retrieve packets from the receive queue and call the appropriate handlers // not process packets if socket already closed WorldPacket* packet; while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet)) { /*#if 1 sLog.outError("MOEP: %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); #endif*/ if (packet->GetOpcode() >= NUM_MSG_TYPES) { sLog.outDebug("SESSION: received invalid opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); } else { OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets if (!m_playerRecentlyLogout) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if (_player->IsInWorld()) ExecuteOpcode(opHandle, packet); // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_TRANSFER_PENDING: if (!_player) LogUnexpectedOpcode(packet, "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else ExecuteOpcode(opHandle, packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(packet, "the player not pass queue yet"); break; } m_playerRecentlyLogout = false; ExecuteOpcode(opHandle, packet); break; case STATUS_NEVER: sLog.outDebug("SESSION: received not allowed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch(ByteBufferException &) { sLog.outDebug("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog.IsOutDebug()) { sLog.outDebug("Dumping error causing packet:"); packet->hexlike(); } } } delete packet; } ///- If necessary, log the player out time_t currTime = time(NULL); if (ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); // Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { m_Socket->RemoveReference(); m_Socket = NULL; } if (!m_Socket) return false; //Will remove this session from the world session map return true; }