zaela-Server/common/eq_stream.cpp

1441 lines
45 KiB
C++
Raw Permalink Normal View History

2013-05-06 13:07:41 -04:00
/*
2013-02-16 16:14:39 -08:00
Copyright (C) 2005 Michael S. Finger
2013-05-09 10:44:08 -04:00
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
2013-02-16 16:14:39 -08:00
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
2013-05-09 10:44:08 -04:00
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2013-02-16 16:14:39 -08:00
*/
#include "global_define.h"
#include "eqemu_logsys.h"
2014-08-21 19:33:02 -07:00
#include "eq_packet.h"
#include "eq_stream.h"
#include "op_codes.h"
2014-08-21 17:26:32 -07:00
#include "crc16.h"
#include "platform.h"
#include "string_util.h"
2013-02-16 16:14:39 -08:00
#include <string>
#include <iomanip>
#include <vector>
#include <algorithm>
2013-02-16 16:14:39 -08:00
#ifdef _WINDOWS
#include <time.h>
#else
#include <sys/types.h>
2013-02-16 16:14:39 -08:00
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <arpa/inet.h>
#endif
//for logsys
#define _L "%s:%d: "
#define __L , long2ip(remote_ip).c_str(), ntohs(remote_port)
uint16 EQStream::MaxWindowSize=2048;
void EQStream::init(bool resetSession) {
// we only reset these statistics if it is a 'new' connection
if ( resetSession )
{
streamactive = false;
sessionAttempts = 0;
}
2013-02-16 16:14:39 -08:00
active_users = 0;
Session=0;
Key=0;
MaxLen=0;
NextInSeq=0;
NextOutSeq=0;
NextAckToSend=-1;
LastAckSent=-1;
MaxSends=5;
LastPacket=0;
2013-05-04 18:06:58 -07:00
oversize_buffer=nullptr;
2013-02-16 16:14:39 -08:00
oversize_length=0;
oversize_offset=0;
RateThreshold=RATEBASE/250;
DecayRate=DECAYBASE/250;
BytesWritten=0;
2015-06-12 19:25:43 -04:00
sent_packet_count = 0;
received_packet_count = 0;
2013-02-16 16:14:39 -08:00
SequencedBase = 0;
AverageDelta = 500;
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
retransmittimer = Timer::GetCurrentTime();
retransmittimeout = 500 * RETRANSMIT_TIMEOUT_MULT;
}
2013-05-04 18:06:58 -07:00
OpMgr = nullptr;
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "init Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
}
EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p)
{
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *ap=nullptr;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Creating new application packet, length [{}]" __L, p->size);
// _raw(NET__APP_CREATE_HEX, 0xFFFF, p);
2013-02-16 16:14:39 -08:00
ap = p->MakeAppPacket();
return ap;
}
EQRawApplicationPacket *EQStream::MakeApplicationPacket(const unsigned char *buf, uint32 len)
{
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *ap=nullptr;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Creating new application packet, length [{}]" __L, len);
2013-02-16 16:14:39 -08:00
ap = new EQRawApplicationPacket(buf, len);
return ap;
}
EQProtocolPacket *EQStream::MakeProtocolPacket(const unsigned char *buf, uint32 len) {
uint16 proto_opcode = ntohs(*(const uint16 *)buf);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//advance over opcode.
buf += 2;
len -= 2;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return(new EQProtocolPacket(proto_opcode, buf, len));
}
void EQStream::ProcessPacket(EQProtocolPacket *p)
{
uint32 processed=0, subpacket_length=0;
2013-05-04 18:06:58 -07:00
if (p == nullptr)
2013-02-16 16:14:39 -08:00
return;
// Raw Application packet
if (p->opcode > 0xff) {
2013-05-09 10:44:08 -04:00
p->opcode = htons(p->opcode); //byte order is backwards in the protocol packet
2013-02-16 16:14:39 -08:00
EQRawApplicationPacket *ap=MakeApplicationPacket(p);
if (ap)
InboundQueuePush(ap);
return;
}
if (!Session && p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Session not initialized, packet ignored" __L);
// _raw(NET__DEBUG, 0xFFFF, p);
2013-02-16 16:14:39 -08:00
return;
}
switch (p->opcode) {
case OP_Combined: {
processed=0;
while(processed < p->size) {
subpacket_length=*(p->pBuffer+processed);
EQProtocolPacket *subp=MakeProtocolPacket(p->pBuffer+processed+1,subpacket_length);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Extracting combined packet of length [{}]" __L, subpacket_length);
// _raw(NET__NET_CREATE_HEX, 0xFFFF, subp);
2013-02-16 16:14:39 -08:00
subp->copyInfo(p);
ProcessPacket(subp);
delete subp;
processed+=subpacket_length+1;
}
}
break;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
case OP_AppCombined: {
processed=0;
while(processed<p->size) {
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *ap=nullptr;
2013-02-16 16:14:39 -08:00
if ((subpacket_length=(unsigned char)*(p->pBuffer+processed))!=0xff) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Extracting combined app packet of length [{}], short len" __L, subpacket_length);
2013-02-16 16:14:39 -08:00
ap=MakeApplicationPacket(p->pBuffer+processed+1,subpacket_length);
processed+=subpacket_length+1;
} else {
subpacket_length=ntohs(*(uint16 *)(p->pBuffer+processed+1));
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Extracting combined app packet of length [{}], short len" __L, subpacket_length);
2013-02-16 16:14:39 -08:00
ap=MakeApplicationPacket(p->pBuffer+processed+3,subpacket_length);
processed+=subpacket_length+3;
}
if (ap) {
ap->copyInfo(p);
InboundQueuePush(ap);
}
}
}
break;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
case OP_Packet: {
if(!p->pBuffer || (p->Size() < 4))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_Packet that was of malformed size" __L);
break;
}
2013-02-16 16:14:39 -08:00
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
SeqOrder check=CompareSequence(NextInSeq,seq);
if (check == SeqFuture) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Future OP_Packet: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
// _raw(NET__DEBUG, seq, p);
2013-02-16 16:14:39 -08:00
PacketQueue[seq]=p->Copy();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
2013-02-16 16:14:39 -08:00
//SendOutOfOrderAck(seq);
} else if (check == SeqPast) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Duplicate OP_Packet: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
// _raw(NET__DEBUG, seq, p);
2013-05-09 10:44:08 -04:00
SendOutOfOrderAck(seq); //we already got this packet but it was out of order
2013-02-16 16:14:39 -08:00
} else {
// In case we did queue one before as well.
EQProtocolPacket *qp=RemoveQueue(seq);
if (qp) {
2019-09-01 23:10:49 -05:00
LogNetcode("[NET_TRACE] OP_Packet: Removing older queued packet with sequence [{}]", seq);
2013-02-16 16:14:39 -08:00
delete qp;
}
SetNextAckToSend(seq);
NextInSeq++;
// Check for an embedded OP_AppCombinded (protocol level 0x19)
if (*(p->pBuffer+2)==0x00 && *(p->pBuffer+3)==0x19) {
EQProtocolPacket *subp=MakeProtocolPacket(p->pBuffer+2,p->size-2);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "seq [{}], Extracting combined packet of length [{}]" __L, seq, subp->size);
// _raw(NET__NET_CREATE_HEX, seq, subp);
2013-02-16 16:14:39 -08:00
subp->copyInfo(p);
ProcessPacket(subp);
delete subp;
} else {
EQRawApplicationPacket *ap=MakeApplicationPacket(p->pBuffer+2,p->size-2);
if (ap) {
ap->copyInfo(p);
InboundQueuePush(ap);
}
}
}
}
break;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
case OP_Fragment: {
if(!p->pBuffer || (p->Size() < 4))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_Fragment that was of malformed size" __L);
break;
}
2013-02-16 16:14:39 -08:00
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
SeqOrder check=CompareSequence(NextInSeq,seq);
if (check == SeqFuture) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Future OP_Fragment: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
// _raw(NET__DEBUG, seq, p);
2013-02-16 16:14:39 -08:00
PacketQueue[seq]=p->Copy();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_Fragment Queue size=[{}]" __L, PacketQueue.size());
2013-02-16 16:14:39 -08:00
//SendOutOfOrderAck(seq);
} else if (check == SeqPast) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Duplicate OP_Fragment: Expecting Seq=[{}], but got Seq=[{}]" __L, NextInSeq, seq);
// _raw(NET__DEBUG, seq, p);
2013-02-16 16:14:39 -08:00
SendOutOfOrderAck(seq);
} else {
// In case we did queue one before as well.
EQProtocolPacket *qp=RemoveQueue(seq);
if (qp) {
2019-09-01 23:10:49 -05:00
LogNetcode("[NET_TRACE] OP_Fragment: Removing older queued packet with sequence [{}]", seq);
2013-02-16 16:14:39 -08:00
delete qp;
}
SetNextAckToSend(seq);
NextInSeq++;
if (oversize_buffer) {
memcpy(oversize_buffer+oversize_offset,p->pBuffer+2,p->size-2);
oversize_offset+=p->size-2;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Fragment of oversized of length [{}], seq [{}]: now at [{}]/[{}]" __L, p->size-2, seq, oversize_offset, oversize_length);
2013-02-16 16:14:39 -08:00
if (oversize_offset==oversize_length) {
if (*(p->pBuffer+2)==0x00 && *(p->pBuffer+3)==0x19) {
EQProtocolPacket *subp=MakeProtocolPacket(oversize_buffer,oversize_offset);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "seq [{}], Extracting combined oversize packet of length [{}]" __L, seq, subp->size);
//// _raw(NET__NET_CREATE_HEX, subp);
2013-02-16 16:14:39 -08:00
subp->copyInfo(p);
ProcessPacket(subp);
delete subp;
} else {
EQRawApplicationPacket *ap=MakeApplicationPacket(oversize_buffer,oversize_offset);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "seq [{}], completed combined oversize packet of length [{}]" __L, seq, ap->size);
2013-02-16 16:14:39 -08:00
if (ap) {
ap->copyInfo(p);
InboundQueuePush(ap);
}
}
delete[] oversize_buffer;
2013-05-04 18:06:58 -07:00
oversize_buffer=nullptr;
2013-02-16 16:14:39 -08:00
oversize_offset=0;
}
} else {
oversize_length=ntohl(*(uint32 *)(p->pBuffer+2));
oversize_buffer=new unsigned char[oversize_length];
memcpy(oversize_buffer,p->pBuffer+6,p->size-6);
oversize_offset=p->size-6;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "First fragment of oversized of seq [{}]: now at [{}]/[{}]" __L, seq, oversize_offset, oversize_length);
2013-02-16 16:14:39 -08:00
}
}
}
break;
case OP_KeepAlive: {
NonSequencedPush(new EQProtocolPacket(p->opcode,p->pBuffer,p->size));
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received and queued reply to keep alive" __L);
2013-02-16 16:14:39 -08:00
}
break;
case OP_Ack: {
if(!p->pBuffer || (p->Size() < 4))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_Ack that was of malformed size" __L);
break;
}
2013-02-16 16:14:39 -08:00
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
AckPackets(seq);
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
retransmittimer = Timer::GetCurrentTime();
}
2013-02-16 16:14:39 -08:00
}
break;
case OP_SessionRequest: {
if(p->Size() < sizeof(SessionRequest))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionRequest that was of malformed size" __L);
2013-02-16 16:14:39 -08:00
break;
}
if (GetState()==ESTABLISHED) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionRequest in ESTABLISHED state ([{}]) streamactive ([{}]) attempt ([{}])" __L, GetState(),streamactive,sessionAttempts);
2013-05-06 13:07:41 -04:00
// client seems to try a max of 30 times (initial+3 retries) then gives up, giving it a few more attempts just in case
// streamactive means we identified the opcode for the stream, we cannot re-establish this connection
if ( streamactive || ( sessionAttempts > MAX_SESSION_RETRIES ) )
{
_SendDisconnect();
SetState(CLOSED);
break;
}
2013-02-16 16:14:39 -08:00
}
sessionAttempts++;
// we set established below, so statistics will not be reset for session attempts/stream active.
init(GetState()!=ESTABLISHED);
2013-02-16 16:14:39 -08:00
OutboundQueueClear();
SessionRequest *Request=(SessionRequest *)p->pBuffer;
Session=ntohl(Request->Session);
SetMaxLen(ntohl(Request->MaxLength));
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionRequest: session [{}], maxlen [{}]" __L, (unsigned long)Session, MaxLen);
2013-02-16 16:14:39 -08:00
SetState(ESTABLISHED);
Key=0x11223344;
SendSessionResponse();
}
break;
case OP_SessionResponse: {
if(p->Size() < sizeof(SessionResponse))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionResponse that was of malformed size" __L);
2013-02-16 16:14:39 -08:00
break;
}
init();
OutboundQueueClear();
SessionResponse *Response=(SessionResponse *)p->pBuffer;
SetMaxLen(ntohl(Response->MaxLength));
Key=ntohl(Response->Key);
NextInSeq=0;
SetState(ESTABLISHED);
if (!Session)
Session=ntohl(Response->Session);
compressed=(Response->Format&FLAG_COMPRESSED);
encoded=(Response->Format&FLAG_ENCODED);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionResponse: session [{}], maxlen [{}], key [{}], compressed? [{}], encoded? [{}]" __L, (unsigned long)Session, MaxLen, (unsigned long)Key, compressed?"yes":"no", encoded?"yes":"no");
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Kinda kludgy, but trie for now
if (StreamType==UnknownStream) {
if (compressed) {
if (remote_port==9000 || (remote_port==0 && p->src_port==9000)) {
SetStreamType(WorldStream);
} else {
SetStreamType(ZoneStream);
}
} else if (encoded) {
SetStreamType(ChatOrMailStream);
} else {
SetStreamType(LoginStream);
}
}
}
break;
case OP_SessionDisconnect: {
//NextInSeq=0;
EQStreamState state = GetState();
if(state == ESTABLISHED) {
//client initiated disconnect?
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received unsolicited OP_SessionDisconnect. Treating like a client-initiated disconnect" __L);
2013-02-16 16:14:39 -08:00
_SendDisconnect();
SetState(CLOSED);
} else if(state == CLOSING) {
//we were waiting for this anyways, ignore pending messages, send the reply and be closed.
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionDisconnect when we have a pending close, they beat us to it. Were happy though" __L);
2013-02-16 16:14:39 -08:00
_SendDisconnect();
SetState(CLOSED);
} else {
//we are expecting this (or have already gotten it, but dont care either way)
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received expected OP_SessionDisconnect. Moving to closed state" __L);
2013-02-16 16:14:39 -08:00
SetState(CLOSED);
}
}
break;
case OP_OutOfOrderAck: {
if(!p->pBuffer || (p->Size() < 4))
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_OutOfOrderAck that was of malformed size" __L);
break;
}
2013-02-16 16:14:39 -08:00
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
MOutboundQueue.lock();
2013-05-06 13:07:41 -04:00
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Pre-OOA Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
//if the packet they got out of order is between our last acked packet and the last sent packet, then its valid.
if (CompareSequence(SequencedBase,seq) != SeqPast && CompareSequence(NextOutSeq,seq) == SeqPast) {
Log(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck for sequence %d, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L,
seq, SequencedBase, SequencedBase+SequencedQueue.size());
uint16 sqsize = SequencedQueue.size();
uint16 index = seq - SequencedBase;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_OutOfOrderAck marking packet acked in queue (queue index = [{}], queue size = [{}])" __L, index, sqsize);
if (index < sqsize) {
SequencedQueue[index]->acked = true;
// flag packets for a resend
uint16 count = 0;
uint32 timeout = AverageDelta * 2 + 100;
for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end() && count < index; ++sitr, ++count) {
if (!(*sitr)->acked && (*sitr)->sent_time > 0 && (((*sitr)->sent_time + timeout) < Timer::GetCurrentTime())) {
(*sitr)->sent_time = 0;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_OutOfOrderAck Flagging packet [{}] for retransmission" __L, SequencedBase + count);
}
2013-02-16 16:14:39 -08:00
}
}
if(RETRANSMIT_TIMEOUT_MULT) {
2013-02-16 16:14:39 -08:00
retransmittimer = Timer::GetCurrentTime();
}
} else {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_OutOfOrderAck for out-of-window [{}]. Window ([{}]->[{}])" __L, seq, SequencedBase, NextOutSeq);
2013-02-16 16:14:39 -08:00
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Post-OOA Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
MOutboundQueue.unlock();
}
break;
case OP_SessionStatRequest: {
2015-06-12 19:25:43 -04:00
if(p->Size() < sizeof(ClientSessionStats))
2013-02-16 16:14:39 -08:00
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionStatRequest that was of malformed size" __L);
2013-02-16 16:14:39 -08:00
break;
}
2015-06-12 19:25:43 -04:00
ClientSessionStats *ClientStats=(ClientSessionStats *)p->pBuffer;
Log(Logs::Detail, Logs::Netcode, _L "Received Stats: %lu packets received, %lu packets sent, Deltas: local %lu, (%lu <- %lu -> %lu) remote %lu" __L,
2015-06-12 19:25:43 -04:00
(unsigned long)ntohl(ClientStats->packets_received), (unsigned long)ntohl(ClientStats->packets_sent), (unsigned long)ntohl(ClientStats->last_local_delta),
(unsigned long)ntohl(ClientStats->low_delta), (unsigned long)ntohl(ClientStats->average_delta),
(unsigned long)ntohl(ClientStats->high_delta), (unsigned long)ntohl(ClientStats->last_remote_delta));
AdjustRates(ntohl(ClientStats->average_delta));
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
2015-06-12 19:25:43 -04:00
if (RETRANSMIT_TIMEOUT_MULT && ntohl(ClientStats->average_delta)) {
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
2015-06-12 19:25:43 -04:00
if ((ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta)) > (ntohl(ClientStats->average_delta) * 2)) {
retransmittimeout = (ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta))
* RETRANSMIT_TIMEOUT_MULT;
} else {
2015-06-12 19:25:43 -04:00
retransmittimeout = ntohl(ClientStats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT;
}
retransmittimeout += 300;
if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX)
retransmittimeout = RETRANSMIT_TIMEOUT_MAX;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Retransmit timeout recalculated to [{}]ms" __L, retransmittimeout);
2013-02-16 16:14:39 -08:00
}
}
2015-06-12 19:25:43 -04:00
ServerSessionStats *ServerStats = (ServerSessionStats *)p->pBuffer;
//ServerStats->RequestID = ClientStats->RequestID; // no change
ServerStats->ServerTime = htonl(Timer::GetCurrentTime());
ServerStats->packets_sent_echo = ClientStats->packets_sent; // still in htonll format
ServerStats->packets_received_echo = ClientStats->packets_received; // still in htonll format
ServerStats->packets_sent = htonll(GetPacketsSent());
ServerStats->packets_received = htonll(GetPacketsReceived());
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse, p->pBuffer, p->size));
2013-02-16 16:14:39 -08:00
}
break;
case OP_SessionStatResponse: {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_SessionStatResponse. Ignoring" __L);
2013-02-16 16:14:39 -08:00
}
break;
case OP_OutOfSession: {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received OP_OutOfSession. Ignoring" __L);
2013-02-16 16:14:39 -08:00
}
break;
default:
EQRawApplicationPacket *ap = MakeApplicationPacket(p);
if (ap)
InboundQueuePush(ap);
break;
}
}
void EQStream::QueuePacket(const EQApplicationPacket *p, bool ack_req)
{
2013-05-04 18:06:58 -07:00
if(p == nullptr)
2013-02-16 16:14:39 -08:00
return;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
EQApplicationPacket *newp = p->Copy();
2013-05-04 18:06:58 -07:00
if (newp != nullptr)
2013-02-16 16:14:39 -08:00
FastQueuePacket(&newp, ack_req);
}
void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
{
EQApplicationPacket *pack=*p;
2013-05-04 18:06:58 -07:00
*p = nullptr; //clear caller's pointer.. effectively takes ownership
2013-05-06 13:07:41 -04:00
2013-05-04 18:06:58 -07:00
if(pack == nullptr)
2013-02-16 16:14:39 -08:00
return;
2013-05-06 13:07:41 -04:00
2013-05-04 18:06:58 -07:00
if(OpMgr == nullptr || *OpMgr == nullptr) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Packet enqueued into a stream with no opcode manager, dropping" __L);
2013-02-16 16:14:39 -08:00
delete pack;
return;
}
2013-05-06 13:07:41 -04:00
uint16 opcode = 0;
if(pack->GetOpcodeBypass() != 0) {
opcode = pack->GetOpcodeBypass();
} else {
2016-09-25 15:10:34 -07:00
opcode = (*OpMgr)->EmuToEQ(pack->GetOpcode());
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if (!ack_req) {
NonSequencedPush(new EQProtocolPacket(opcode, pack->pBuffer, pack->size));
delete pack;
} else {
SendPacket(opcode, pack);
}
}
void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
{
uint32 chunksize, used;
uint32 length;
2013-02-16 16:14:39 -08:00
if (LogSys.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size());
}
}
if (LogSys.log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){
if (p->GetOpcode() != OP_SpecialMesg){
Log(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str());
}
}
2013-02-16 16:14:39 -08:00
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Making oversized packet, len [{}]" __L, p->Size());
2013-02-16 16:14:39 -08:00
2016-05-25 16:10:28 -04:00
auto tmpbuff = new unsigned char[p->size + 3];
2013-02-16 16:14:39 -08:00
length=p->serialize(opcode, tmpbuff);
if (length != p->Size())
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Packet adjustment, len [{}] to [{}]" __L, p->Size(), length);
2013-05-06 13:07:41 -04:00
2016-05-25 16:10:28 -04:00
auto out = new EQProtocolPacket(OP_Fragment, nullptr, MaxLen - 4);
*(uint32 *)(out->pBuffer+2)=htonl(length);
2013-02-16 16:14:39 -08:00
used=MaxLen-10;
memcpy(out->pBuffer+6,tmpbuff,used);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "First fragment: used [{}]/[{}]. Payload size [{}] in the packet" __L, used, length, p->size);
2013-02-16 16:14:39 -08:00
SequencedPush(out);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
while (used<length) {
2013-05-04 18:06:58 -07:00
out=new EQProtocolPacket(OP_Fragment,nullptr,MaxLen-4);
chunksize=std::min(length-used,MaxLen-6);
2013-02-16 16:14:39 -08:00
memcpy(out->pBuffer+2,tmpbuff+used,chunksize);
out->size=chunksize+2;
SequencedPush(out);
used+=chunksize;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Subsequent fragment: len [{}], used [{}]/[{}]" __L, chunksize, used, length);
2013-02-16 16:14:39 -08:00
}
delete p;
delete[] tmpbuff;
} else {
2016-05-25 16:10:28 -04:00
auto tmpbuff = new unsigned char[p->Size() + 3];
2013-02-16 16:14:39 -08:00
length=p->serialize(opcode, tmpbuff+2) + 2;
2016-05-25 16:10:28 -04:00
auto out = new EQProtocolPacket(OP_Packet, tmpbuff, length);
2013-02-16 16:14:39 -08:00
delete[] tmpbuff;
SequencedPush(out);
delete p;
}
}
void EQStream::SequencedPush(EQProtocolPacket *p)
{
MOutboundQueue.lock();
if (uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
Log(Logs::Detail, Logs::Netcode, _L "Pre-Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L,
SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
Log(Logs::Detail, Logs::Netcode, _L "Pushing sequenced packet %d of length %d. Base Seq is %d." __L,
NextOutSeq, p->size, SequencedBase);
*(uint16 *)(p->pBuffer) = htons(NextOutSeq);
2013-02-16 16:14:39 -08:00
SequencedQueue.push_back(p);
NextOutSeq++;
if (uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
Log(Logs::Detail, Logs::Netcode, _L "Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L,
SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
MOutboundQueue.unlock();
}
void EQStream::NonSequencedPush(EQProtocolPacket *p)
{
MOutboundQueue.lock();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Pushing non-sequenced packet of length [{}]" __L, p->size);
2013-02-16 16:14:39 -08:00
NonSequencedQueue.push(p);
MOutboundQueue.unlock();
}
void EQStream::SendAck(uint16 seq)
{
uint16 Seq=htons(seq);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Sending ack with sequence [{}]" __L, seq);
2013-02-16 16:14:39 -08:00
SetLastAckSent(seq);
NonSequencedPush(new EQProtocolPacket(OP_Ack,(unsigned char *)&Seq,sizeof(uint16)));
}
void EQStream::SendOutOfOrderAck(uint16 seq)
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Sending out of order ack with sequence [{}]" __L, seq);
2013-02-16 16:14:39 -08:00
uint16 Seq=htons(seq);
NonSequencedPush(new EQProtocolPacket(OP_OutOfOrderAck,(unsigned char *)&Seq,sizeof(uint16)));
}
void EQStream::Write(int eq_fd)
{
std::queue<EQProtocolPacket *> ReadyToSend;
bool SeqEmpty=false, NonSeqEmpty=false;
std::deque<EQProtocolPacket *>::iterator sitr;
2013-02-16 16:14:39 -08:00
// Check our rate to make sure we can send more
MRate.lock();
int32 threshold=RateThreshold;
MRate.unlock();
if (BytesWritten > threshold) {
return;
}
// If we got more packets to we need to ack, send an ack on the highest one
MAcks.lock();
if (CompareSequence(LastAckSent, NextAckToSend) == SeqFuture)
SendAck(NextAckToSend);
MAcks.unlock();
// Lock the outbound queues while we process
MOutboundQueue.lock();
// Place to hold the base packet t combine into
2013-05-04 18:06:58 -07:00
EQProtocolPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
// Find the next sequenced packet to send from the "queue"
sitr = SequencedQueue.begin();
uint16 count = 0;
// get to start of packets
while (sitr != SequencedQueue.end() && (*sitr)->sent_time > 0) {
++sitr;
++count;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Loop until both are empty or MaxSends is reached
2013-05-09 10:44:08 -04:00
while(!SeqEmpty || !NonSeqEmpty) {
2013-02-16 16:14:39 -08:00
// See if there are more non-sequenced packets left
if (!NonSequencedQueue.empty()) {
if (!p) {
// If we don't have a packet to try to combine into, use this one as the base
// And remove it form the queue
p = NonSequencedQueue.front();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Starting combined packet with non-seq packet of len [{}]" __L, p->size);
2013-02-16 16:14:39 -08:00
NonSequencedQueue.pop();
} else if (!p->combine(NonSequencedQueue.front())) {
// Trying to combine this packet with the base didn't work (too big maybe)
2013-02-16 16:14:39 -08:00
// So just send the base packet (we'll try this packet again later)
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined packet full at len [{}], next non-seq packet is len [{}]" __L, p->size, (NonSequencedQueue.front())->size);
2013-02-16 16:14:39 -08:00
ReadyToSend.push(p);
BytesWritten+=p->size;
2013-05-04 18:06:58 -07:00
p=nullptr;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if (BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Exceeded write threshold in nonseq ([{}] > [{}])" __L, BytesWritten, threshold);
2013-02-16 16:14:39 -08:00
break;
}
} else {
// Combine worked, so just remove this packet and it's spot in the queue
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined non-seq packet of len [{}], yeilding [{}] combined" __L, (NonSequencedQueue.front())->size, p->size);
2013-02-16 16:14:39 -08:00
delete NonSequencedQueue.front();
NonSequencedQueue.pop();
}
} else {
// No more non-sequenced packets
NonSeqEmpty=true;
}
if (sitr != SequencedQueue.end()) {
uint16 seq_send = SequencedBase + count; //just for logging...
if(SequencedQueue.empty()) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Tried to write a packet with an empty queue ([{}] is past next out [{}])" __L, seq_send, NextOutSeq);
SeqEmpty=true;
continue;
}
2013-02-16 16:14:39 -08:00
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if ((*sitr)->acked || (*sitr)->sent_time != 0) {
++sitr;
++count;
if (p) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
ReadyToSend.push(p);
BytesWritten += p->size;
p = nullptr;
}
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Not retransmitting seq packet [{}] because already marked as acked" __L, seq_send);
} else if (!p) {
// If we don't have a packet to try to combine into, use this one as the base
// Copy it first as it will still live until it is acked
p=(*sitr)->Copy();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Starting combined packet with seq packet [{}] of len [{}]" __L, seq_send, p->size);
(*sitr)->sent_time = Timer::GetCurrentTime();
++sitr;
++count;
} else if (!p->combine(*sitr)) {
// Trying to combine this packet with the base didn't work (too big maybe)
// So just send the base packet (we'll try this packet again later)
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined packet full at len [{}], next seq packet [{}] is len [{}]" __L, p->size, seq_send + 1, (*sitr)->size);
ReadyToSend.push(p);
BytesWritten+=p->size;
p=nullptr;
if ((*sitr)->opcode != OP_Fragment && BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Exceeded write threshold in seq ([{}] > [{}])" __L, BytesWritten, threshold);
break;
}
} else {
// Combine worked
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined seq packet [{}] of len [{}], yeilding [{}] combined" __L, seq_send, (*sitr)->size, p->size);
(*sitr)->sent_time = Timer::GetCurrentTime();
++sitr;
++count;
2013-02-16 16:14:39 -08:00
}
} else {
if ((*sitr)->sent_time != 0) {
++sitr;
++count;
if (p) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
ReadyToSend.push(p);
BytesWritten += p->size;
p = nullptr;
}
} else if (!p) {
// If we don't have a packet to try to combine into, use this one as the base
// Copy it first as it will still live until it is acked
p=(*sitr)->Copy();
(*sitr)->sent_time = Timer::GetCurrentTime();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Starting combined packet with seq packet [{}] of len [{}]" __L, seq_send, p->size);
++sitr;
++count;
} else if (!p->combine(*sitr)) {
// Trying to combine this packet with the base didn't work (too big maybe)
// So just send the base packet (we'll try this packet again later)
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined packet full at len [{}], next seq packet [{}] is len [{}]" __L, p->size, seq_send, (*sitr)->size);
ReadyToSend.push(p);
BytesWritten+=p->size;
p=nullptr;
if (BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Exceeded write threshold in seq ([{}] > [{}])" __L, BytesWritten, threshold);
break;
}
} else {
// Combine worked
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Combined seq packet [{}] of len [{}], yielding [{}] combined" __L, seq_send, (*sitr)->size, p->size);
(*sitr)->sent_time = Timer::GetCurrentTime();
++sitr;
++count;
}
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Post send Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
} else {
// No more sequenced packets
SeqEmpty=true;
}
}
// Unlock the queue
MOutboundQueue.unlock();
// We have a packet still, must have run out of both seq and non-seq, so send it
if (p) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Final combined packet not full, len [{}]" __L, p->size);
2013-02-16 16:14:39 -08:00
ReadyToSend.push(p);
BytesWritten+=p->size;
}
// Send all the packets we "made"
while(!ReadyToSend.empty()) {
p = ReadyToSend.front();
WritePacket(eq_fd,p);
delete p;
ReadyToSend.pop();
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//see if we need to send our disconnect and finish our close
if(SeqEmpty && NonSeqEmpty) {
//no more data to send
if(CheckState(CLOSING)) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "All outgoing data flushed, closing stream" __L );
2013-02-16 16:14:39 -08:00
//we are waiting for the queues to empty, now we can do our disconnect.
//this packet will not actually go out until the next call to Write().
_SendDisconnect();
SetState(DISCONNECTING);
}
}
}
void EQStream::WritePacket(int eq_fd, EQProtocolPacket *p)
{
uint32 length;
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr=remote_ip;
address.sin_port=remote_port;
#ifdef NOWAY
uint32 ip=address.sin_addr.s_addr;
std::cout << "Sending to: "
2013-02-16 16:14:39 -08:00
<< (int)*(unsigned char *)&ip
<< "." << (int)*((unsigned char *)&ip+1)
<< "." << (int)*((unsigned char *)&ip+2)
<< "." << (int)*((unsigned char *)&ip+3)
<< "," << (int)ntohs(address.sin_port) << "(" << p->size << ")" << std::endl;
2013-02-16 16:14:39 -08:00
p->DumpRaw();
std::cout << "-------------" << std::endl;
2013-02-16 16:14:39 -08:00
#endif
length=p->serialize(buffer);
if (p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) {
if (compressed) {
BytesWritten -= p->size;
2013-02-16 16:14:39 -08:00
uint32 newlen=EQProtocolPacket::Compress(buffer,length, _tempBuffer, 2048);
memcpy(buffer,_tempBuffer,newlen);
length=newlen;
BytesWritten += newlen;
2013-02-16 16:14:39 -08:00
}
if (encoded) {
EQProtocolPacket::ChatEncode(buffer,length,Key);
}
*(uint16 *)(buffer+length)=htons(CRC16(buffer,length,Key));
length+=2;
}
//dump_message_column(buffer,length,"Writer: ");
sendto(eq_fd,(char *)buffer,length,0,(sockaddr *)&address,sizeof(address));
AddBytesSent(length);
}
void EQStream::SendSessionResponse()
{
2016-05-25 16:10:28 -04:00
auto out = new EQProtocolPacket(OP_SessionResponse, nullptr, sizeof(SessionResponse));
2013-02-16 16:14:39 -08:00
SessionResponse *Response=(SessionResponse *)out->pBuffer;
Response->Session=htonl(Session);
Response->MaxLength=htonl(MaxLen);
Response->UnknownA=2;
Response->Format=0;
if (compressed)
Response->Format|=FLAG_COMPRESSED;
if (encoded)
Response->Format|=FLAG_ENCODED;
Response->Key=htonl(Key);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
out->size=sizeof(SessionResponse);
2013-05-06 13:07:41 -04:00
Log(Logs::Detail, Logs::Netcode, _L "Sending OP_SessionResponse: session %lu, maxlen=%d, key=0x%x, compressed? %s, encoded? %s" __L,
2013-02-16 16:14:39 -08:00
(unsigned long)Session, MaxLen, Key, compressed?"yes":"no", encoded?"yes":"no");
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
NonSequencedPush(out);
}
void EQStream::SendSessionRequest()
{
2016-05-25 16:10:28 -04:00
auto out = new EQProtocolPacket(OP_SessionRequest, nullptr, sizeof(SessionRequest));
2013-02-16 16:14:39 -08:00
SessionRequest *Request=(SessionRequest *)out->pBuffer;
memset(Request,0,sizeof(SessionRequest));
2013-05-04 18:06:58 -07:00
Request->Session=htonl(time(nullptr));
2013-02-16 16:14:39 -08:00
Request->MaxLength=htonl(512);
2013-05-06 13:07:41 -04:00
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Sending OP_SessionRequest: session [{}], maxlen=[{}]" __L, (unsigned long)ntohl(Request->Session), ntohl(Request->MaxLength));
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
NonSequencedPush(out);
}
void EQStream::_SendDisconnect()
{
if(GetState() == CLOSED)
return;
2013-05-06 13:07:41 -04:00
2016-05-25 16:10:28 -04:00
auto out = new EQProtocolPacket(OP_SessionDisconnect, nullptr, sizeof(uint32));
2013-02-16 16:14:39 -08:00
*(uint32 *)out->pBuffer=htonl(Session);
NonSequencedPush(out);
2013-05-06 13:07:41 -04:00
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Sending OP_SessionDisconnect: session [{}]" __L, (unsigned long)Session);
2013-02-16 16:14:39 -08:00
}
void EQStream::InboundQueuePush(EQRawApplicationPacket *p)
{
MInboundQueue.lock();
InboundQueue.push_back(p);
MInboundQueue.unlock();
}
EQApplicationPacket *EQStream::PopPacket()
{
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
MInboundQueue.lock();
if (!InboundQueue.empty()) {
2016-05-25 16:10:28 -04:00
auto itr = InboundQueue.begin();
2013-02-16 16:14:39 -08:00
p=*itr;
InboundQueue.erase(itr);
}
MInboundQueue.unlock();
2013-05-06 13:07:41 -04:00
if (p) {
if (OpMgr != nullptr && *OpMgr != nullptr) {
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
if (emu_op == OP_Unknown) {
// Log(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str());
}
p->SetOpcode(emu_op);
2013-02-16 16:14:39 -08:00
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return p;
}
EQRawApplicationPacket *EQStream::PopRawPacket()
{
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
MInboundQueue.lock();
if (!InboundQueue.empty()) {
2016-05-25 16:10:28 -04:00
auto itr = InboundQueue.begin();
2013-02-16 16:14:39 -08:00
p=*itr;
InboundQueue.erase(itr);
}
MInboundQueue.unlock();
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//resolve the opcode if we can.
if(p) {
2013-05-04 18:06:58 -07:00
if(OpMgr != nullptr && *OpMgr != nullptr) {
2013-02-16 16:14:39 -08:00
EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode);
if(emu_op == OP_Unknown) {
LogNetcode("Unable to convert EQ opcode {:#04x} to an Application opcode", p->opcode);
2013-02-16 16:14:39 -08:00
}
2013-02-16 16:14:39 -08:00
p->SetOpcode(emu_op);
}
}
return p;
}
EQRawApplicationPacket *EQStream::PeekPacket()
{
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
MInboundQueue.lock();
if (!InboundQueue.empty()) {
2016-05-25 16:10:28 -04:00
auto itr = InboundQueue.begin();
2013-02-16 16:14:39 -08:00
p=*itr;
}
MInboundQueue.unlock();
return p;
}
void EQStream::InboundQueueClear()
{
2013-05-04 18:06:58 -07:00
EQApplicationPacket *p=nullptr;
2013-05-06 13:07:41 -04:00
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Clearing inbound queue" __L);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MInboundQueue.lock();
if (!InboundQueue.empty()) {
std::vector<EQRawApplicationPacket *>::iterator itr;
for(itr=InboundQueue.begin();itr!=InboundQueue.end();++itr) {
2013-02-16 16:14:39 -08:00
p=*itr;
delete p;
}
InboundQueue.clear();
}
MInboundQueue.unlock();
}
bool EQStream::HasOutgoingData()
{
bool flag;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//once closed, we have nothing more to say
if(CheckClosed())
return(false);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MOutboundQueue.lock();
flag=(!NonSequencedQueue.empty());
if (!flag) {
//not only wait until we send it all, but wait until they ack everything.
flag = !SequencedQueue.empty();
}
MOutboundQueue.unlock();
if (!flag) {
MAcks.lock();
flag= (NextAckToSend>LastAckSent);
MAcks.unlock();
}
return flag;
}
void EQStream::OutboundQueueClear()
{
2013-05-04 18:06:58 -07:00
EQProtocolPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Clearing outbound queue" __L);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MOutboundQueue.lock();
while(!NonSequencedQueue.empty()) {
delete NonSequencedQueue.front();
NonSequencedQueue.pop();
}
if(!SequencedQueue.empty()) {
std::deque<EQProtocolPacket *>::iterator itr;
for(itr=SequencedQueue.begin();itr!=SequencedQueue.end();++itr) {
2013-02-16 16:14:39 -08:00
p=*itr;
delete p;
}
SequencedQueue.clear();
}
MOutboundQueue.unlock();
}
void EQStream::PacketQueueClear()
{
2013-05-04 18:06:58 -07:00
EQProtocolPacket *p=nullptr;
2013-02-16 16:14:39 -08:00
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Clearing future packet queue" __L);
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if(!PacketQueue.empty()) {
std::map<unsigned short,EQProtocolPacket *>::iterator itr;
for(itr=PacketQueue.begin();itr!=PacketQueue.end();++itr) {
2013-02-16 16:14:39 -08:00
p=itr->second;
delete p;
}
PacketQueue.clear();
}
}
void EQStream::Process(const unsigned char *buffer, const uint32 length)
{
2015-06-12 19:25:43 -04:00
static unsigned char newbuffer[2048];
uint32 newlength=0;
2013-02-16 16:14:39 -08:00
if (EQProtocolPacket::ValidateCRC(buffer,length,Key)) {
if (compressed) {
newlength=EQProtocolPacket::Decompress(buffer,length,newbuffer,2048);
} else {
memcpy(newbuffer,buffer,length);
newlength=length;
if (encoded)
EQProtocolPacket::ChatDecode(newbuffer,newlength-2,Key);
}
if (buffer[1]!=0x01 && buffer[1]!=0x02 && buffer[1]!=0x1d)
newlength-=2;
EQProtocolPacket *p = MakeProtocolPacket(newbuffer,newlength);
ProcessPacket(p);
delete p;
ProcessQueue();
} else {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Incoming packet failed checksum" __L);
2013-02-16 16:14:39 -08:00
}
}
long EQStream::GetNextAckToSend()
{
MAcks.lock();
long l=NextAckToSend;
MAcks.unlock();
return l;
}
long EQStream::GetLastAckSent()
{
MAcks.lock();
long l=LastAckSent;
MAcks.unlock();
return l;
}
void EQStream::AckPackets(uint16 seq)
{
std::deque<EQProtocolPacket *>::iterator itr, tmp;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MOutboundQueue.lock();
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
SeqOrder ord = CompareSequence(SequencedBase, seq);
if(ord == SeqInOrder) {
//they are not acking anything new...
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received an ack with no window advancement (seq [{}])" __L, seq);
2013-02-16 16:14:39 -08:00
} else if(ord == SeqPast) {
//they are nacking blocks going back before our buffer, wtf?
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received an ack with backward window advancement (they gave [{}], our window starts at [{}]). This is bad" __L, seq, SequencedBase);
2013-02-16 16:14:39 -08:00
} else {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Received an ack up through sequence [{}]. Our base is [{}]" __L, seq, SequencedBase);
2013-02-16 16:14:39 -08:00
//this is a good ack, we get to ack some blocks.
seq++; //we stop at the block right after their ack, counting on the wrap of both numbers.
while(SequencedBase != seq) {
if(SequencedQueue.empty()) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OUT OF PACKETS acked packet with sequence [{}]. Next send is [{}] before this" __L, (unsigned long)SequencedBase, SequencedQueue.size());
SequencedBase = NextOutSeq;
break;
}
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Removing acked packet with sequence [{}]" __L, (unsigned long)SequencedBase);
2013-02-16 16:14:39 -08:00
//clean out the acked packet
delete SequencedQueue.front();
SequencedQueue.pop_front();
//advance the base sequence number to the seq of the block after the one we just got rid of.
SequencedBase++;
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Post-Ack on [{}] Invalid Sequenced queue: BS [{}] + SQ [{}] != NOS [{}]" __L, seq, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MOutboundQueue.unlock();
}
void EQStream::SetNextAckToSend(uint32 seq)
{
MAcks.lock();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Set Next Ack To Send to [{}]" __L, (unsigned long)seq);
2013-02-16 16:14:39 -08:00
NextAckToSend=seq;
MAcks.unlock();
}
void EQStream::SetLastAckSent(uint32 seq)
{
MAcks.lock();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Set Last Ack Sent to [{}]" __L, (unsigned long)seq);
2013-02-16 16:14:39 -08:00
LastAckSent=seq;
MAcks.unlock();
}
void EQStream::ProcessQueue()
{
if(PacketQueue.empty()) {
return;
}
2013-05-06 13:07:41 -04:00
2013-05-04 18:06:58 -07:00
EQProtocolPacket *qp=nullptr;
while((qp=RemoveQueue(NextInSeq))!=nullptr) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Processing Queued Packet: Seq=[{}]" __L, NextInSeq);
2013-02-16 16:14:39 -08:00
ProcessPacket(qp);
delete qp;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
2013-02-16 16:14:39 -08:00
}
}
EQProtocolPacket *EQStream::RemoveQueue(uint16 seq)
{
std::map<unsigned short,EQProtocolPacket *>::iterator itr;
2013-05-04 18:06:58 -07:00
EQProtocolPacket *qp=nullptr;
2013-02-16 16:14:39 -08:00
if ((itr=PacketQueue.find(seq))!=PacketQueue.end()) {
qp=itr->second;
PacketQueue.erase(itr);
2019-09-01 23:10:49 -05:00
LogNetcode(_L "OP_Packet Queue size=[{}]" __L, PacketQueue.size());
2013-02-16 16:14:39 -08:00
}
return qp;
}
void EQStream::SetStreamType(EQStreamType type)
{
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Changing stream type from [{}] to [{}]" __L, StreamTypeString(StreamType), StreamTypeString(type));
2013-02-16 16:14:39 -08:00
StreamType=type;
switch (StreamType) {
case LoginStream:
app_opcode_size=1;
compressed=false;
encoded=false;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Login stream has app opcode size [{}], is not compressed or encoded" __L, app_opcode_size);
2013-02-16 16:14:39 -08:00
break;
case ChatOrMailStream:
case ChatStream:
case MailStream:
app_opcode_size=1;
compressed=false;
encoded=true;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Chat/Mail stream has app opcode size [{}], is not compressed, and is encoded" __L, app_opcode_size);
2013-02-16 16:14:39 -08:00
break;
case ZoneStream:
case WorldStream:
default:
app_opcode_size=2;
compressed=true;
encoded=false;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "World/Zone stream has app opcode size [{}], is compressed, and is not encoded" __L, app_opcode_size);
2013-02-16 16:14:39 -08:00
break;
}
}
const char *EQStream::StreamTypeString(EQStreamType t)
{
switch (t) {
case LoginStream:
return "Login";
break;
case WorldStream:
return "World";
break;
case ZoneStream:
return "Zone";
break;
case ChatOrMailStream:
return "Chat/Mail";
break;
case ChatStream:
return "Chat";
break;
case MailStream:
return "Mail";
break;
case UnknownStream:
return "Unknown";
break;
}
return "UnknownType";
}
//returns SeqFuture if `seq` is later than `expected_seq`
EQStream::SeqOrder EQStream::CompareSequence(uint16 expected_seq , uint16 seq)
{
if (expected_seq==seq) {
// Curent
return SeqInOrder;
2013-05-09 10:44:08 -04:00
} else if ((seq > expected_seq && (uint32)seq < ((uint32)expected_seq + EQStream::MaxWindowSize)) || seq < (expected_seq - EQStream::MaxWindowSize)) {
2013-02-16 16:14:39 -08:00
// Future
return SeqFuture;
} else {
// Past
return SeqPast;
}
}
void EQStream::SetState(EQStreamState state) {
MState.lock();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Changing state from [{}] to [{}]" __L, State, state);
2013-02-16 16:14:39 -08:00
State=state;
MState.unlock();
}
void EQStream::CheckTimeout(uint32 now, uint32 timeout) {
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
bool outgoing_data = HasOutgoingData(); //up here to avoid recursive locking
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
EQStreamState orig_state = GetState();
if (orig_state == CLOSING && !outgoing_data) {
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Out of data in closing state, disconnecting" __L);
2013-02-16 16:14:39 -08:00
_SendDisconnect();
SetState(DISCONNECTING);
} else if (LastPacket && (now-LastPacket) > timeout) {
switch(orig_state) {
case CLOSING:
//if we time out in the closing state, they are not acking us, just give up
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Timeout expired in closing state. Moving to closed state" __L);
2013-02-16 16:14:39 -08:00
_SendDisconnect();
SetState(CLOSED);
break;
case DISCONNECTING:
//we timed out waiting for them to send us the disconnect reply, just give up.
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Timeout expired in disconnecting state. Moving to closed state" __L);
2013-02-16 16:14:39 -08:00
SetState(CLOSED);
break;
case CLOSED:
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Timeout expired in closed state??" __L);
2013-02-16 16:14:39 -08:00
break;
case ESTABLISHED:
//we timed out during normal operation. Try to be nice about it.
//we will almost certainly time out again waiting for the disconnect reply, but oh well.
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Timeout expired in established state. Closing connection" __L);
2013-02-16 16:14:39 -08:00
_SendDisconnect();
SetState(DISCONNECTING);
2013-05-23 20:22:42 -04:00
break;
default:
break;
2013-02-16 16:14:39 -08:00
}
}
}
void EQStream::Decay()
{
MRate.lock();
uint32 rate=DecayRate;
MRate.unlock();
if (BytesWritten>0) {
BytesWritten-=rate;
if (BytesWritten<0)
BytesWritten=0;
}
// check for any timed out acks
if ((GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) && RETRANSMIT_TIMEOUT_MULT && retransmittimeout) {
int count = 0;
MOutboundQueue.lock();
for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end(); ++sitr, count++) {
if (!(*sitr)->acked && (*sitr)->sent_time > 0 && ((*sitr)->sent_time + retransmittimeout) < Timer::GetCurrentTime()) {
(*sitr)->sent_time = 0;
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Timeout exceeded for seq [{}]. Flagging packet for retransmission" __L, SequencedBase + count);
}
}
MOutboundQueue.unlock();
}
2013-02-16 16:14:39 -08:00
}
void EQStream::AdjustRates(uint32 average_delta)
{
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if (average_delta && (average_delta <= AVERAGE_DELTA_MAX)) {
MRate.lock();
AverageDelta = average_delta;
RateThreshold=RATEBASE/average_delta;
DecayRate=DECAYBASE/average_delta;
if (BytesWritten > RateThreshold)
BytesWritten = RateThreshold + DecayRate;
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
RateThreshold, DecayRate, average_delta);
MRate.unlock();
} else {
Log(Logs::Detail, Logs::Netcode, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L,
average_delta, AVERAGE_DELTA_MAX);
AverageDelta = AVERAGE_DELTA_MAX;
}
2013-02-16 16:14:39 -08:00
} else {
if (average_delta) {
MRate.lock();
AverageDelta = average_delta;
BytesWritten = 0;
RateThreshold=RATEBASE/average_delta;
DecayRate=DECAYBASE/average_delta;
Log(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
RateThreshold, DecayRate, average_delta);
MRate.unlock();
}
2013-02-16 16:14:39 -08:00
}
}
void EQStream::Close() {
if(HasOutgoingData()) {
//there is pending data, wait for it to go out.
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Stream requested to Close(), but there is pending data, waiting for it" __L);
2013-02-16 16:14:39 -08:00
SetState(CLOSING);
} else {
//otherwise, we are done, we can drop immediately.
_SendDisconnect();
2019-09-01 23:10:49 -05:00
LogNetcode(_L "Stream closing immediate due to Close()" __L);
2013-02-16 16:14:39 -08:00
SetState(DISCONNECTING);
}
}
//this could be expanded to check more than the fitst opcode if
//we needed more complex matching
EQStream::MatchState EQStream::CheckSignature(const Signature *sig) {
2013-05-04 18:06:58 -07:00
EQRawApplicationPacket *p = nullptr;
2013-02-16 16:14:39 -08:00
MatchState res = MatchNotReady;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
MInboundQueue.lock();
if (!InboundQueue.empty()) {
//this is already getting hackish...
p = InboundQueue.front();
if(sig->ignore_eq_opcode != 0 && p->opcode == sig->ignore_eq_opcode) {
if(InboundQueue.size() > 1) {
p = InboundQueue[1];
} else {
2013-05-04 18:06:58 -07:00
p = nullptr;
2013-02-16 16:14:39 -08:00
}
}
2013-05-04 18:06:58 -07:00
if(p == nullptr) {
2013-02-16 16:14:39 -08:00
//first opcode is ignored, and nothing else remains... keep waiting
} else if(p->opcode == sig->first_eq_opcode) {
//opcode matches, check length..
if(p->size == sig->first_length) {
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x} and length matched [{}]", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
2013-02-16 16:14:39 -08:00
res = MatchSuccessful;
} else if(sig->first_length == 0) {
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x} and length ([{}]) is ignored", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size);
2013-02-16 16:14:39 -08:00
res = MatchSuccessful;
} else {
//opcode matched but length did not.
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode matched {:#04x}, but length [{}] did not match expected [{}]", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), sig->first_eq_opcode, p->size, sig->first_length);
2013-02-16 16:14:39 -08:00
res = MatchFailed;
}
} else {
//first opcode did not match..
LogNetcode("[StreamIdentify] [{}]:[{}]: First opcode {:#04x} did not match expected {:#04x}", long2ip(GetRemoteIP()).c_str(), ntohs(GetRemotePort()), p->opcode, sig->first_eq_opcode);
2013-02-16 16:14:39 -08:00
res = MatchFailed;
}
}
MInboundQueue.unlock();
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return(res);
}