-> reconnecting does work now, finally. * updated conf setting: reconnect=0: dont reconnect; reconnect=X: reconnect after X msecs. * misc code cleanups, crash fixes, and overall improved stability. * splitted RealmSocket into a RealmSession and the original RealmSocket code. better read-/useabilty because now its handled as WorldSession and related.
130 lines
4.0 KiB
C++
130 lines
4.0 KiB
C++
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
#include "WorldSocket.h"
|
|
|
|
WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
|
|
{
|
|
_session = s;
|
|
_gothdr = false;
|
|
_ok=false;
|
|
}
|
|
|
|
bool WorldSocket::IsOk(void)
|
|
{
|
|
return _ok;
|
|
}
|
|
|
|
void WorldSocket::OnConnect()
|
|
{
|
|
log("Connected to world server.");
|
|
_ok = true;
|
|
}
|
|
|
|
void WorldSocket::OnConnectFailed()
|
|
{
|
|
logerror("Connecting to World Server failed!");
|
|
_ok = false;
|
|
}
|
|
|
|
void WorldSocket::OnDelete()
|
|
{
|
|
log("Connection to world server has been closed.");
|
|
_ok = false;
|
|
_session->SetMustDie(); // recreate the session if needed
|
|
}
|
|
|
|
void WorldSocket::OnException()
|
|
{
|
|
if(_ok)
|
|
{
|
|
logerror("WorldSocket::OnException()");
|
|
_ok = false;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
ServerPktHeader hdr;
|
|
ibuf.Read((char*)&hdr,sizeof(ServerPktHeader));
|
|
_crypt.DecryptRecv((uint8*)&hdr,sizeof(ServerPktHeader));
|
|
_remaining = ntohs(hdr.size)-2;
|
|
_opcode = hdr.cmd;
|
|
if(_opcode > 1000) // no opcode has yet a number over 1000
|
|
{
|
|
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 lentgh 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::SendWorldPacket(WorldPacket &pkt)
|
|
{
|
|
if(!_ok)
|
|
return;
|
|
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));
|
|
if(pkt.size())
|
|
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();
|
|
}
|