From 8add84b1291204bced79ed7ad56871284f96a924 Mon Sep 17 00:00:00 2001 From: "False.Genesis" Date: Sun, 7 Jan 2007 19:26:35 +0000 Subject: [PATCH] fixed logging to world + experimental pkt decrypt --- src/Client/Realm/RealmSocket.h | 1 - src/Client/World/WorldSession.cpp | 102 ++++++++++--------------- src/Client/World/WorldSession.h | 6 +- src/Client/World/WorldSocket.cpp | 120 ++++++++++++++++++++++++++++-- src/Client/World/WorldSocket.h | 21 ++++++ 5 files changed, 179 insertions(+), 71 deletions(-) diff --git a/src/Client/Realm/RealmSocket.h b/src/Client/Realm/RealmSocket.h index d48046b..39ea07c 100644 --- a/src/Client/Realm/RealmSocket.h +++ b/src/Client/Realm/RealmSocket.h @@ -31,7 +31,6 @@ public: void _HandleLogonChallenge(void); void OnRead(void); - //void OnAccept(void); void OnConnect(void); void OnConnectFailed(void); diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index 86027e1..f03e4d3 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -11,27 +11,11 @@ #include "RealmSocket.h" -struct ClientPktHeader -{ - uint16 size; - uint16 cmd; - uint16 nil; -}; - -struct ServerPktHeader -{ - uint16 size; - uint16 cmd; -}; - - WorldSession::WorldSession(PseuInstance *in) { _instance = in; _valid=_authed=_logged=false; _socket=new WorldSocket(_sh,this); - _socket->SetDeleteByHandler(); - _sh.Add(_socket); _targetGUID=0; // no target _followGUID=0; // dont follow anything _myGUID=0; // i dont have a guid yet @@ -41,33 +25,36 @@ WorldSession::WorldSession(PseuInstance *in) WorldSession::~WorldSession() { + WorldPacket *packet; + // clear the queue + while(!pktQueue.empty()) + { + packet = pktQueue.next(); + delete packet; + } //delete _socket; the socket will be deleted by its handler!! } void WorldSession::Start(void) { + printf("Connecting to '%s' on port %u\n",GetInstance()->GetConf()->worldhost.c_str(),GetInstance()->GetConf()->worldport); _socket->Open(GetInstance()->GetConf()->worldhost,GetInstance()->GetConf()->worldport); GetInstance()->GetRSession()->SetCloseAndDelete(); // realm socket is no longer needed _valid=true; + _sh.Add(_socket); + _socket->SetDeleteByHandler(); + _sh.Select(1,0); } -void WorldSession::AddToDataQueue(uint8 *data, uint32 len) +void WorldSession::AddToPktQueue(WorldPacket *pkt) { - for (uint32 i=0;iSendBuf((char*)final.contents(),final.size()); + _socket->SendWorldPacket(pkt); } void WorldSession::Update(void) @@ -76,42 +63,32 @@ void WorldSession::Update(void) return; if(_sh.GetCount()) _sh.Select(0,0); - WorldPacket packet; + OpcodeHandler *table = _GetOpcodeHandlerTable(); - while(pktQueue.size()>5) + bool known=false; + while(!pktQueue.empty()) { - packet = BuildWorldPacket(); + WorldPacket *packet = pktQueue.next(); + printf("QUEUE: %u packets left\n",pktQueue.size()); + printf(">> Opcode %u [%s]\n",packet->GetOpcode(),LookupName(packet->GetOpcode(),g_worldOpcodeNames)); for (uint16 i = 0; table[i].handler != NULL; i++) - if (table[i].opcode == packet.GetOpcode()) - (this->*table[i].handler)(packet); + { + if (table[i].opcode == packet->GetOpcode()) + { + (this->*table[i].handler)(*packet); + known=true; + break; + } + } + //if(!known) + - packet.clear(); + delete packet; } // do more stuff here } -WorldPacket WorldSession::BuildWorldPacket(void) -{ - ServerPktHeader hdr; - WorldPacket wp; - uint16 _remaining; - for (uint8 i=0;iGetScripts()->RunScriptByName("_enterworld",NULL,255); + //GetInstance()->GetScripts()->RunScriptByName("_enterworld",NULL,255); } } @@ -182,7 +159,7 @@ void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket) std::string acc = stringToUpper(GetInstance()->GetConf()->accname); uint32 serverseed; recvPacket >> serverseed; - //DEBUG3(printf("W:auth: serverseed=0x%X\n",serverseed);) + printf("W:auth: serverseed=0x%X\n",serverseed); Sha1Hash digest; digest.UpdateData(acc); uint32 unk=0; @@ -207,10 +184,13 @@ void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket) // printf("CMSG_AUTH_SESSION="); // printchex((char*)outpkt.contents(),outpkt.size(),true); //) - SendWorldPacket(auth); - _crypt.SetKey(GetInstance()->GetSessionKey().AsByteArray(), 40); - _crypt.Init(); - _authed=true; + SendWorldPacket(auth); + + // note that if the sessionkey/auth is wrong or failed, the server sends the following packet UNENCRYPTED! + // so its not 100% correct to init the crypt here, but it should do the job if authing was correct + _socket->InitCrypt(GetInstance()->GetSessionKey().AsByteArray(), 40); + + _authed=true; } diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 18172b0..cd44815 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -30,9 +30,8 @@ public: OpcodeHandler *_GetOpcodeHandlerTable(void) const; - void AddToDataQueue(uint8*, uint32); + void AddToPktQueue(WorldPacket *pkt); void Connect(std::string addr,uint16 port); - WorldPacket BuildWorldPacket(void); void Update(void); void Start(void); bool IsValid(void) { return _valid; } @@ -73,9 +72,8 @@ private: PseuInstance *_instance; - AuthCrypt _crypt; WorldSocket *_socket; - std::deque pktQueue; + ZThread::LockedQueue pktQueue; bool _valid,_authed,_logged; // world status SocketHandler _sh; // handles the WorldSocket uint64 _targetGUID,_followGUID,_myGUID; diff --git a/src/Client/World/WorldSocket.cpp b/src/Client/World/WorldSocket.cpp index b4ab0ed..684dff0 100644 --- a/src/Client/World/WorldSocket.cpp +++ b/src/Client/World/WorldSocket.cpp @@ -6,6 +6,7 @@ WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h) { _session = s; + _gothdr = false; } @@ -22,11 +23,120 @@ void WorldSocket::OnConnectFailed() void WorldSocket::OnRead() { TcpSocket::OnRead(); - printf("WorldSocket::OnRead() %u bytes\n",ibuf.GetLength()); - if(!ibuf.GetLength()) + uint32 len = ibuf.GetLength(); + printf("WorldSocket::OnRead() %u bytes\n",len); + if(!len) return; - uint8 *buf=new uint8[ibuf.GetLength()]; - ibuf.Read((char*)buf,ibuf.GetLength()); - GetSession()->AddToDataQueue(buf,ibuf.GetLength()); + + uint8 *buf=new uint8[len]; + ibuf.Read((char*)buf,len); + + ByteBuffer bb; + bb.append(buf,len); + bb.hexlike(); + + uint32 offset=0; + + // this is a bit tricky, but needed, because sometimes packets come over as [[hdr][data][hdr]] + // and the 2nd header needs to be extracted too + while(true) + { + + if(_gothdr) // already got header, this packet has to be the data part + { + _gothdr=false; + if( len != _remaining ) + { + printf("WP: Recieved packet is not correct (%u of %u)\n",len,_remaining); + break; + } + + printf("WP: Building complete WorldPacket with opcode %u\n",_opcode); + WorldPacket *wp = new WorldPacket; + wp->append(buf+offset,len); + wp->SetOpcode(_opcode); + GetSession()->AddToPktQueue(wp); + break; + } + else // no pending header stored, so this packet must be a header + { + printf("WP: Got header (%u bytes)\n",len); + ServerPktHeader hdr; + memcpy(&hdr,buf+offset,sizeof(ServerPktHeader)); + _crypt.DecryptRecv((uint8*)&hdr,sizeof(ServerPktHeader)); + _remaining = ntohs(hdr.size)-2; + _opcode = hdr.cmd; + printf("WP: Opcode=%u, remains=%u\n",_opcode,_remaining); + + // the header is fine, now check if there are more data + if(_remaining == 0) + { + printf("WP: Got header-only Packet, building WorldPacket\n"); + WorldPacket *wp = new WorldPacket; + wp->SetOpcode(_opcode); + GetSession()->AddToPktQueue(wp); + break; + } + else if( _remaining && len-4==0 ) + { + printf("WP: Got ONLY a header, waiting for data...\n"); + _gothdr=true; // only got the header, next packet wil contain the data + break; + } + else // if the packet is bigger then 4 bytes, header & packet are merged + { + if( (len - sizeof(ServerPktHeader)) == _remaining ) + { + printf("WP: Got merged Packet, building WorldPacket\n"); + WorldPacket *wp = new WorldPacket; + wp->append(buf+4+offset,_remaining); // skip first 4 bytes (header) + wp->SetOpcode(_opcode); + GetSession()->AddToPktQueue(wp); + break; + } + else if ( (len - sizeof(ServerPktHeader)) < _remaining ) + { + printf("WP: Got too small merged packet (total=%u, data=%u)\n",len,_remaining); + break; + } + else if( (len - sizeof(ServerPktHeader)) > _remaining) + { + WorldPacket *wp = new WorldPacket; + wp->append(buf+4+offset,_remaining); // skip first 4 bytes (header) + wp->SetOpcode(_opcode); + GetSession()->AddToPktQueue(wp); + + offset += (4 + _remaining); // skip the header & the data already used + len -= (4 + _remaining); + printf("WP: Got too big merged packet, new offset=%u, new len=%u, reading more data..\n",offset,len); + + if(len <= 0) + break; // all data done + else + continue; // read next part + } + } + } + } + delete buf; // UNSURE: delete or delete[] } + +void WorldSocket::SendWorldPacket(WorldPacket &pkt) +{ + ClientPktHeader hdr; + memset(&hdr,0,sizeof(ClientPktHeader)); + hdr.size = ntohs(pkt.size()+4); + hdr.cmd = pkt.GetOpcode(); + _crypt.EncryptSend((uint8*)&hdr, 6); + ByteBuffer final(pkt.size()+6); + final.append((uint8*)&hdr,sizeof(ClientPktHeader)); + final.append(pkt.contents(),pkt.size()); + SendBuf((char*)final.contents(),final.size()); +} + +void WorldSocket::InitCrypt(uint8 *key,uint32 len) +{ + _crypt.SetKey(key,len); + _crypt.Init(); +} diff --git a/src/Client/World/WorldSocket.h b/src/Client/World/WorldSocket.h index 45e2ce4..7984740 100644 --- a/src/Client/World/WorldSocket.h +++ b/src/Client/World/WorldSocket.h @@ -6,6 +6,19 @@ class WorldSession; +struct ClientPktHeader +{ + uint16 size; + uint16 cmd; + uint16 nil; +}; + +struct ServerPktHeader +{ + uint16 size; + uint16 cmd; +}; + class WorldSocket : public TcpSocket { public: @@ -16,8 +29,16 @@ public: void OnConnect(); void OnConnectFailed(); + void SendWorldPacket(WorldPacket &pkt); + void InitCrypt(uint8*,uint32); + private: WorldSession *_session; + AuthCrypt _crypt; + bool _gothdr; // true if only the header was recieved yet + ByteBuffer _hdr; + uint16 _opcode; + uint16 _remaining; };