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 _new_handler(void) { logcritical("ERROR: Out of memory!"); throw; }