From d721580c9f103f77fb77a930bf0c277c943404d9 Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Wed, 17 Dec 2014 17:55:21 -0500 Subject: [PATCH] EQStream changes as recommended by a community member in private. --- changelog.txt | 1 + common/eq_stream.cpp | 28 +++++++++++++++++++--------- common/eq_stream.h | 14 ++++++++++++-- common/eq_stream_ident.cpp | 3 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/changelog.txt b/changelog.txt index d1184037d..8c2630b6f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 12/17/2014 == demonstar55: Use vectors for route stuff, should be more CPU cache friendly so faster +Secrets: EQStream changes as recommended by a community member in private. == 12/15/2014 == Trevius: (RoF+) Implemented the 6th Augment Slot for Items. diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 879d57664..594f3b5bc 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -47,7 +47,13 @@ uint16 EQStream::MaxWindowSize=2048; -void EQStream::init() { +void EQStream::init(bool resetSession) { + // we only reset these statistics if it is a 'new' connection + if ( resetSession ) + { + streamactive = false; + sessionAttempts = 0; + } active_users = 0; Session=0; Key=0; @@ -313,18 +319,22 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) } #ifndef COLLECTOR if (GetState()==ESTABLISHED) { - _log(NET__ERROR, _L "Received OP_SessionRequest in ESTABLISHED state (%d)" __L, GetState()); + _log(NET__ERROR, _L "Received OP_SessionRequest in ESTABLISHED state (%d) streamactive (%i) attempt (%i)" __L, GetState(),streamactive,sessionAttempts); - /*RemoveData(); - init(); - State=UNESTABLISHED;*/ - _SendDisconnect(); - SetState(CLOSED); - break; + // 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; + } } #endif //std::cout << "Got OP_SessionRequest" << std::endl; - init(); + sessionAttempts++; + // we set established below, so statistics will not be reset for session attempts/stream active. + init(GetState()!=ESTABLISHED); OutboundQueueClear(); SessionRequest *Request=(SessionRequest *)p->pBuffer; Session=ntohl(Request->Session); diff --git a/common/eq_stream.h b/common/eq_stream.h index ee797021f..bcbb548e9 100644 --- a/common/eq_stream.h +++ b/common/eq_stream.h @@ -49,6 +49,10 @@ class EQProtocolPacket; #define RETRANSMIT_ACKED_PACKETS true #endif +#ifndef MAX_SESSION_RETRIES +#define MAX_SESSION_RETRIES 30 +#endif + #pragma pack(1) struct SessionRequest { uint32 UnknownA; @@ -104,6 +108,9 @@ class EQStream : public EQStreamInterface { uint32 retransmittimer; uint32 retransmittimeout; + uint16 sessionAttempts; + bool streamactive; + //uint32 buffer_len; uint32 Session, Key; @@ -197,9 +204,9 @@ class EQStream : public EQStreamInterface { void _SendDisconnect(); - void init(); + void init(bool resetSession=true); public: - EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); } + EQStream() { init(); remote_ip = 0; remote_port = 0; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); sessionAttempts = 0; streamactive=false; } EQStream(sockaddr_in addr) { init(); remote_ip=addr.sin_addr.s_addr; remote_port=addr.sin_port; State=UNESTABLISHED; StreamType=UnknownStream; compressed=true; encoded=false; app_opcode_size=2; bytes_sent=0; bytes_recv=0; create_time=Timer::GetTimeSeconds(); } virtual ~EQStream() { RemoveData(); SetState(CLOSED); } void SetMaxLen(uint32 length) { MaxLen=length; } @@ -224,6 +231,9 @@ class EQStream : public EQStreamInterface { void SetLastPacketTime(uint32 t) {LastPacket=t;} void Write(int eq_fd); + // whether or not the stream has been assigned (we passed our stream match) + void SetActive(bool val) { streamactive = val; } + // inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; } inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); } diff --git a/common/eq_stream_ident.cpp b/common/eq_stream_ident.cpp index b60ac28d0..97fdd2c48 100644 --- a/common/eq_stream_ident.cpp +++ b/common/eq_stream_ident.cpp @@ -110,6 +110,9 @@ void EQStreamIdentifier::Process() { _log(NET__IDENTIFY, "Identified stream %s:%d with signature %s", long2ip(r->stream->GetRemoteIP()).c_str(), ntohs(r->stream->GetRemotePort()), p->name.c_str()); + // before we assign the eqstream to an interface, let the stream recognize it is in use and the session should not be reset any further + r->stream->SetActive(true); + //might want to do something less-specific here... some day.. EQStreamInterface *s = new EQStreamProxy(r->stream, p->structs, p->opcodes); m_identified.push(s);