void WSClient::OnRead() { for(;;) { if(!_cmd) { if(GetReadBufferSize() < 6) break; Read(2, (uint8*)&_cmd); Read(4, (uint8*)&_remaining); } if(_remaining && GetReadBufferSize() < _remaining) break; if(_cmd == ISMSG_WOW_PACKET) { /* optimized version for packet passing, to reduce latency! ;) */ uint32 sid = *(uint32*)&m_readBuffer[0]; uint16 op = *(uint16*)&m_readBuffer[4]; uint32 sz = *(uint32*)&m_readBuffer[6]; WorldSession * session = sClusterInterface.GetSession(sid); if(session != NULL) { WorldPacket * pck = new WorldPacket(op, sz); pck->resize(sz); memcpy((void*)pck->contents(), &m_readBuffer[10], sz); session->QueuePacket(pck); } RemoveReadBufferBytes(sz + 10/*header*/, false); _cmd = 0; continue; } WorldPacket * pck = new WorldPacket(_cmd, _remaining); _cmd = 0; pck->resize(_remaining); Read(_remaining, (uint8*)pck->contents()); /* we could handle auth here */ switch(_cmd) { case ISMSG_AUTH_REQUEST: sClusterInterface.HandleAuthRequest(*pck); delete pck; break; default: sClusterInterface.QueuePacket(pck); } } }
void VoiceChatClientSocket::OnRead() { WorldPacket *data; // uint16 op // uint16 size // <data> for(;;) { // no more data if( GetReadBufferSize() < 4 ) break; Read(2, (uint8*)&op); Read(2, (uint8*)&remaining); if( GetReadBufferSize() < remaining ) break; data = new WorldPacket(op, remaining); data->resize(remaining); Read(remaining, (uint8*)data->contents()); // handle the packet sVoiceChatHandler.OnRead(data); delete data; remaining = op = 0; } }
bool UpdateData::buildPacket(WorldPacket& packet, bool hasTransport) { ByteBuffer buf(m_data.size() + 10 + m_guidList.size() * 8); buf << (u_int)(!m_guidList.empty() ? m_blockCount + 1 : m_blockCount); buf << (u_char)(hasTransport ? 1 : 0); if (!m_guidList.empty()) { buf << (u_char)UPDATETYPE_OUT_OF_RANGE_OBJECTS; buf << (u_int)m_guidList.size(); for (IDList::const_iterator itr = m_guidList.begin(); itr != m_guidList.end(); ++itr) { buf << (u_char)0xFF; buf << (u_int64)*itr; } } buf.append(m_data); packet.clear(); // 大小超过50字节的数据包要压缩 if (m_data.size() > 50) { u_int destSize = (u_int)buf.size() + buf.size() / 10 + 16; packet.resize(destSize); packet.put(0, (u_int)buf.size()); compress(const_cast<u_char*>(packet.contents()) + sizeof(u_int), &destSize, (void*)buf.contents(), (u_int)buf.size()); if (destSize == 0) return false; packet.resize(destSize + sizeof(u_int)); packet.setOpcode(SMSG_COMPRESSED_UPDATE_OBJECT); } else { packet.append(buf); packet.setOpcode(SMSG_UPDATE_OBJECT); } return true; }
void ClusterInterface::HandleWoWPacket(WorldPacket & pck) { uint32 size, sid; uint16 opcode; pck >> sid >> opcode >> size; if(!_sessions[sid]) { Log.Error("HandleWoWPacket", "Invalid session: %u", sid); return; } DEBUG_LOG("HandleWoWPacket", "Forwarding %s to client", LookupName(opcode, g_worldOpcodeNames)); WorldPacket * npck = new WorldPacket(opcode, size); npck->resize(size); memcpy((void*)npck->contents(), pck.contents()+10, size); _sessions[sid]->QueuePacket(npck); }
void WorldSocket::OnRead() { for(;;) { // Check for the header if we don't have any bytes to wait for. if(mRemaining == 0) { if(GetReadBuffer().GetSize() < 6) { // No header in the packet, let's wait. return; } // Copy from packet buffer into header local var ClientPktHeader Header; GetReadBuffer().Read(&Header, 6); // Decrypt the header _crypt.DecryptSixRecv((uint8*)&Header); mRemaining = mSize = ntohs(Header.size) - 4; mOpcode = Header.cmd; } WorldPacket * Packet; if(mRemaining > 0) { if( GetReadBuffer().GetSize() < mRemaining ) { // We have a fragmented packet. Wait for the complete one before proceeding. return; } } Packet = new WorldPacket(mOpcode, mSize); Packet->resize(mSize); if(mRemaining > 0) { // Copy from packet buffer into our actual buffer. //Read(mRemaining, (uint8*)Packet->contents()); GetReadBuffer().Read((uint8*)Packet->contents(), mRemaining); } /*sWorldLog.LogPacket(mSize, mOpcode, mSize ? Packet->contents() : NULL, 0);*/ mRemaining = mSize = mOpcode = 0; // Check for packets that we handle switch(Packet->GetOpcode()) { case CMSG_PING: { if(!m_session->m_currentPlayer) { _HandlePing(Packet); delete Packet; } else m_session->m_readQueue.Push(Packet); }break; case CMSG_AUTH_SESSION: { _HandleAuthSession(Packet); }break; default: { if(m_session) m_session->m_readQueue.Push(Packet); else delete Packet; }break; } } }
void WorldSocket::OnRead() { TcpSocket::OnRead(); if(!ibuf.GetLength()) { this->CloseAndDelete(); return; } while(ibuf.GetLength() > 0) // when all packets from the current ibuf are transformed into WorldPackets the remaining len will be zero { if(_gothdr) // already got header, this packet has to be the data part { ASSERT(_remaining > 0); // case pktsize==0 is handled below if(ibuf.GetLength() < _remaining) { DEBUG(logdebug("Delaying WorldPacket generation, bufsize is %u but should be >= %u",ibuf.GetLength(),_remaining)); break; } _gothdr=false; WorldPacket *wp = new WorldPacket(_remaining); wp->resize(_remaining); ibuf.Read((char*)wp->contents(),_remaining); wp->SetOpcode(_opcode); GetSession()->AddToPktQueue(wp); } else // no pending header stored, so this packet must be a header { if(ibuf.GetLength() < sizeof(ServerPktHeader)) { DEBUG(logdebug("Delaying header reading, bufsize is %u but should be >= %u",ibuf.GetLength(),sizeof(ServerPktHeader))); break; } if(GetSession()->GetInstance()->GetConf()->client > CLIENT_TBC)//Funny, old sources have this in TBC already... { // read first byte and check if size is 3 or 2 bytes uint8 firstSizeByte; ibuf.Read((char*)&firstSizeByte, 1); (_crypt.*pDecryptRecv)(&firstSizeByte, 1); if (firstSizeByte & 0x80) // got large packet { ServerPktHeaderBig hdr; ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte (_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd hdr.size[0] = firstSizeByte; // assign missing first byte uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2]; _remaining = realsize - 2; _opcode = hdr.cmd; } else // "normal" packet { ServerPktHeader hdr; ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte (_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first hdr.size |= firstSizeByte; // add already decrypted first byte _remaining = ntohs(hdr.size) - 2; _opcode = hdr.cmd; } } else { ServerPktHeader hdr; ibuf.Read(((char*)&hdr), sizeof(ServerPktHeader)); // read header (_crypt.*pDecryptRecv)(((uint8*)&hdr), sizeof(ServerPktHeader)); // decrypt all _remaining = ntohs(hdr.size) - 2; _opcode = hdr.cmd; } if(_opcode > MAX_OPCODE_ID) { logcritical("CRYPT ERROR: opcode=%u, remain=%u",_opcode,_remaining); // this should never be the case! GetSession()->GetInstance()->SetError(); // no way to recover the crypt, must exit // if the crypt gets messy its hardly possible to recover it, especially if we dont know // the length of the following data part // TODO: invent some way how to recover the crypt (reconnect?) return; } // the header is fine, now check if there are more data if(_remaining == 0) // this is a packet with no data (like CMSG_NULL_ACTION) { WorldPacket *wp = new WorldPacket; wp->SetOpcode(_opcode); GetSession()->AddToPktQueue(wp); } else // there is a data part to fetch { _gothdr=true; // only got the header, next packet will contain the data } } } }
void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { uint8 digest[SHA_DIGEST_LENGTH]; uint32 clientSeed; uint8 security; uint16 clientBuild; uint32 id; uint32 addonSize; LocaleConstant locale; std::string account; SHA1Hash sha; BigNumber k; bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); WorldPacket addonsData; uint8 loginServerType; uint32 realmIndex; recvPacket.read_skip<uint32>(); // ServerId - Used for GRUNT only recvPacket.read_skip<uint32>(); // Battlegroup recvPacket >> loginServerType; recvPacket >> digest[10]; recvPacket >> digest[18]; recvPacket >> digest[12]; recvPacket >> digest[5]; recvPacket.read_skip<uint64>(); recvPacket >> digest[15]; recvPacket >> digest[9]; recvPacket >> digest[19]; recvPacket >> digest[4]; recvPacket >> digest[7]; recvPacket >> digest[16]; recvPacket >> digest[3]; recvPacket >> clientBuild; recvPacket >> digest[8]; recvPacket >> realmIndex; recvPacket.read_skip<uint8>(); recvPacket >> digest[17]; recvPacket >> digest[6]; recvPacket >> digest[0]; recvPacket >> digest[1]; recvPacket >> digest[11]; recvPacket >> clientSeed; recvPacket >> digest[2]; recvPacket.read_skip<uint32>(); // Region recvPacket >> digest[14]; recvPacket >> digest[13]; recvPacket >> addonSize; if (addonSize) { addonsData.resize(addonSize); recvPacket.read((uint8*)addonsData.contents(), addonSize); } recvPacket.ReadBit(); // UseIPv6 uint32 accountNameLength = recvPacket.ReadBits(12); account = recvPacket.ReadString(accountNameLength); // Get the account information from the auth database // 0 1 2 3 4 5 6 7 8 9 // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os, battlenet_account FROM account WHERE username = ? PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); stmt->setString(0, account); PreparedQueryResult result = LoginDatabase.Query(stmt); // Stop if the account is not found if (!result) { // We can not log here, as we do not know the account. Thus, no accountId. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); DelayedCloseSocket(); return; } Field* fields = result->Fetch(); uint8 expansion = fields[4].GetUInt8(); uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); if (expansion > world_expansion) expansion = world_expansion; // For hook purposes, we get Remoteaddress at this point. std::string address = GetRemoteIpAddress().to_string(); // As we don't know if attempted login process by ip works, we update last_attempt_ip right away stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); stmt->setString(0, address); stmt->setString(1, account); LoginDatabase.Execute(stmt); // This also allows to check for possible "hack" attempts on account // id has to be fetched at this point, so that first actual account response that fails can be logged id = fields[0].GetUInt32(); k.SetHexStr(fields[1].GetCString()); // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it _authCrypt.Init(&k); // First reject the connection if packet contains invalid data or realm state doesn't allow logging in if (sWorld->IsClosed()) { SendAuthResponseError(AUTH_REJECT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); DelayedCloseSocket(); return; } if (realmIndex != realmID) { SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); DelayedCloseSocket(); return; } std::string os = fields[8].GetString(); // Must be done before WorldSession is created if (wardenActive && os != "Win" && os != "OSX") { SendAuthResponseError(AUTH_REJECT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); DelayedCloseSocket(); return; } // Check that Key and account name are the same on client and server uint32 t = 0; sha.UpdateData(account); sha.UpdateData((uint8*)&t, 4); sha.UpdateData((uint8*)&clientSeed, 4); sha.UpdateData((uint8*)&_authSeed, 4); sha.UpdateBigNumbers(&k, NULL); sha.Finalize(); if (memcmp(sha.GetDigest(), digest, SHA_DIGEST_LENGTH) != 0) { SendAuthResponseError(AUTH_FAILED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); DelayedCloseSocket(); return; } ///- Re-check ip locking (same check as in auth). if (fields[3].GetUInt8() == 1) // if ip is locked { if (strcmp(fields[2].GetCString(), address.c_str()) != 0) { SendAuthResponseError(AUTH_FAILED); TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well sScriptMgr->OnFailedAccountLogin(id); DelayedCloseSocket(); return; } } int64 mutetime = fields[5].GetInt64(); //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) { mutetime = time(NULL) + llabs(mutetime); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN); stmt->setInt64(0, mutetime); stmt->setUInt32(1, id); LoginDatabase.Execute(stmt); } locale = LocaleConstant(fields[6].GetUInt8()); if (locale >= TOTAL_LOCALES) locale = LOCALE_enUS; uint32 recruiter = fields[7].GetUInt32(); uint32 battlenetAccountId = 0; if (loginServerType == 1) battlenetAccountId = fields[9].GetUInt32(); // Checks gmlevel per Realm stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, id); stmt->setInt32(1, int32(realmID)); result = LoginDatabase.Query(stmt); if (!result) security = 0; else { fields = result->Fetch(); security = fields[0].GetUInt8(); } // Re-check account ban (same check as in auth) stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS); stmt->setUInt32(0, id); stmt->setString(1, address); PreparedQueryResult banresult = LoginDatabase.Query(stmt); if (banresult) // if account banned { SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); sScriptMgr->OnFailedAccountLogin(id); DelayedCloseSocket(); return; } // Check locked state for server AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit(); TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) { SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); sScriptMgr->OnFailedAccountLogin(id); DelayedCloseSocket(); return; } TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", account.c_str(), address.c_str()); // Check if this user is by any chance a recruiter stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER); stmt->setUInt32(0, id); result = LoginDatabase.Query(stmt); bool isRecruiter = false; if (result) isRecruiter = true; // Update the last_ip in the database as it was successful for login stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP); stmt->setString(0, address); stmt->setString(1, account); LoginDatabase.Execute(stmt); // At this point, we can safely hook a successful login sScriptMgr->OnAccountLogin(id); _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); _worldSession->LoadGlobalAccountData(); _worldSession->LoadTutorialsData(); _worldSession->ReadAddonsInfo(addonsData); _worldSession->LoadPermissions(); // Initialize Warden system only if it is enabled by config if (wardenActive) _worldSession->InitWarden(&k, os); sWorld->AddSession(_worldSession); }
void WorldSocket::OnRead() { for(;;) { // Check for the header if we don't have any bytes to wait for. if(mRemaining == 0) { if(GetReadBuffer().GetSize() < 6) { // No header in the packet, let's wait. return; } // Copy from packet buffer into header local var ClientPktHeader Header; GetReadBuffer().Read((uint8*)&Header, 6); // Decrypt the header _crypt.DecryptRecv((uint8*)&Header, sizeof (ClientPktHeader)); #ifdef USING_BIG_ENDIAN mRemaining = mSize = Header.size - 4; mOpcode = swap32(Header.cmd); #else mRemaining = mSize = ntohs(Header.size) - 4; mOpcode = Header.cmd; #endif } WorldPacket * Packet; if(mRemaining > 0) { if( GetReadBuffer().GetSize() < mRemaining ) { // We have a fragmented packet. Wait for the complete one before proceeding. return; } } Packet = new WorldPacket( static_cast<uint16>( mOpcode ), mSize); Packet->resize(mSize); if(mRemaining > 0) { // Copy from packet buffer into our actual buffer. ///Read(mRemaining, (uint8*)Packet->contents()); GetReadBuffer().Read((uint8*)Packet->contents(), mRemaining); } sWorldLog.LogPacket(mSize, static_cast<uint16>( mOpcode ), mSize ? Packet->contents() : NULL, 0, (mSession ? mSession->GetAccountId() : 0) ); mRemaining = mSize = mOpcode = 0; // Check for packets that we handle switch(Packet->GetOpcode()) { case CMSG_PING: { _HandlePing(Packet); delete Packet; }break; case CMSG_AUTH_SESSION: { _HandleAuthSession(Packet); }break; default: { if(mSession) mSession->QueuePacket(Packet); else delete Packet; }break; } } }
void WSSocket::OnRead() { for(;;) { if(!_cmd) { if(readBuffer.GetSize() < 6) break; readBuffer.Read(&_cmd, 2); readBuffer.Read(&_remaining, 4); } if(_remaining && readBuffer.GetSize() < _remaining) break; if(_cmd == ICMSG_WOW_PACKET) { uint32 sid; uint16 op; uint32 sz; GetReadBuffer().Read(&sid, 4); GetReadBuffer().Read(&op, 2); GetReadBuffer().Read(&sz, 4); Session * session = sClientMgr.GetSession(sid); if(session != NULL && session->GetSocket() != NULL) { uint8* buf = new uint8[sz]; GetReadBuffer().Read(buf, sz); session->GetSocket()->OutPacket(op, sz, buf); delete [] buf; } else GetReadBuffer().Remove(sz); _cmd = 0; continue; } WorldPacket * pck = new WorldPacket(_cmd, _remaining); _cmd = 0; pck->resize(_remaining); readBuffer.Read((uint8*)pck->contents(), _remaining); if(_authenticated) { // push to queue if(!_ws) { if(pck->GetOpcode() == ICMSG_REGISTER_WORKER) { // handle register worker HandleRegisterWorker(*pck); } /* I deliberately don't delete pck here for a reason :P */ } else { _ws->QueuePacket(pck); } } else { if(pck->GetOpcode() != ICMSG_AUTH_REPLY) Disconnect(); else HandleAuthRequest(*pck); delete pck; } } }
void WorldSocket::OnRecvData() { for(;;) { // Check for the header if we don't have any bytes to wait for. if(mRemaining == 0) { if(GetReadBuffer()->GetSize() < 6) { // No header in the packet, let's wait. return; } // Copy from packet buffer into header local var ClientPktHeader Header; Read(&Header, 6); // Decrypt the header _crypt.DecryptRecv((uint8*)&Header, sizeof (ClientPktHeader)); mRemaining = mSize = ntohs(Header.size) - 4; mOpcode = Header.cmd; } if(mRemaining > 0) { if( GetReadBuffer()->GetSize() < mRemaining ) { // We have a fragmented packet. Wait for the complete one before proceeding. return; } } WorldPacket *Packet = new WorldPacket(mOpcode, mSize); if(mRemaining > 0) { Packet->resize(mRemaining); Read((uint8*)Packet->contents(), mRemaining); if(!bServerShutdown) sWorld.NetworkStressIn += float(float(mSize+6)/1024); } mRemaining = mSize = mOpcode = 0; // Check for packets that we handle switch(Packet->GetOpcode()) { case CMSG_PING: { _HandlePing(Packet); delete Packet; }break; case CMSG_AUTH_SESSION: { _HandleAuthSession(Packet); }break; default: { if(mSession) mSession->QueuePacket(Packet); else { delete Packet; Packet = NULL; } }break; } } }
void WSClient::OnRecvData() { for(;;) { if(!_cmd) { if(GetReadBuffer()->GetSize() < 6) break; Read((uint8*)&_cmd, 2); Read((uint8*)&_remaining, 4); } if(_remaining && GetReadBuffer()->GetSize() < _remaining) return; if(_cmd == SMSGR_WOW_PACKET) { uint32 sid = 0; uint16 op = 0; uint32 sz = 0; Read(&sid, 4); Read(&op, 2); Read(&sz, 4); WorldSession * session = sClusterInterface.GetSession(sid); if(session != NULL) { WorldPacket * pck = new WorldPacket(op, sz); if (sz > 0) { pck->resize(sz); Read((void*)pck->contents(), sz); } if(session) session->QueuePacket(pck); else delete pck; } _cmd = 0; continue; } WorldPacket * pck = new WorldPacket(_cmd, _remaining); _cmd = 0; if(_remaining) { pck->resize(_remaining); Read((uint8*)pck->contents(), _remaining); } /* we could handle auth here */ switch(_cmd) { case SMSGR_AUTH_REQUEST: sClusterInterface.HandleAuthRequest(*pck); delete pck; break; default: sClusterInterface.QueuePacket(pck); } } }