clean EQStream
This commit is contained in:
parent
7e9f7eb061
commit
d00e7cce75
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,6 @@
|
||||
/*
|
||||
EQ2Emulator: Everquest II Server Emulator
|
||||
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
|
||||
|
||||
This file is part of EQ2Emulator.
|
||||
|
||||
EQ2Emulator 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, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
EQ2Emulator is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// EQ2Emulator: Everquest II Server Emulator
|
||||
// Copyright (C) 2007 EQ2EMulator Development Team
|
||||
// Licensed under GPL v3 - see <http://www.gnu.org/licenses/>
|
||||
#ifndef _EQPROTOCOL_H
|
||||
#define _EQPROTOCOL_H
|
||||
|
||||
@ -24,12 +8,15 @@
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <queue>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#ifndef WIN32
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
// Unix networking headers
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
// Project headers
|
||||
#include "EQPacket.h"
|
||||
#include "Mutex.h"
|
||||
#include "opcodemgr.h"
|
||||
@ -38,338 +25,499 @@
|
||||
#include "Crypto.h"
|
||||
#include "zlib.h"
|
||||
#include "timer.h"
|
||||
|
||||
#ifdef WRITE_PACKETS
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Forward declarations
|
||||
class OpcodeManager;
|
||||
class EQStreamFactory;
|
||||
|
||||
/**
|
||||
* EverQuest stream connection states.
|
||||
* Represents the current state of a network stream connection.
|
||||
*/
|
||||
typedef enum {
|
||||
ESTABLISHED,
|
||||
WAIT_CLOSE,
|
||||
CLOSING,
|
||||
DISCONNECTING,
|
||||
CLOSED
|
||||
ESTABLISHED, // Active connection ready for data
|
||||
WAIT_CLOSE, // Waiting for graceful close
|
||||
CLOSING, // In process of closing
|
||||
DISCONNECTING, // Actively disconnecting
|
||||
CLOSED // Connection fully closed
|
||||
} EQStreamState;
|
||||
|
||||
#define FLAG_COMPRESSED 0x01
|
||||
#define FLAG_ENCODED 0x04
|
||||
// Packet flags
|
||||
#define FLAG_COMPRESSED 0x01 // Packet is compressed
|
||||
#define FLAG_ENCODED 0x04 // Packet is encoded/encrypted
|
||||
|
||||
#define RATEBASE 1048576 // 1 MB
|
||||
#define DECAYBASE 78642 // RATEBASE/10
|
||||
// Rate limiting and bandwidth constants
|
||||
#define RATEBASE 1048576 // Base rate: 1 MB
|
||||
#define DECAYBASE 78642 // Decay rate: RATEBASE/10
|
||||
|
||||
// Retransmission timing constants
|
||||
#ifndef RETRANSMIT_TIMEOUT_MULT
|
||||
#define RETRANSMIT_TIMEOUT_MULT 3.0
|
||||
#define RETRANSMIT_TIMEOUT_MULT 3.0 // Timeout multiplier
|
||||
#endif
|
||||
|
||||
#ifndef RETRANSMIT_TIMEOUT_MAX
|
||||
#define RETRANSMIT_TIMEOUT_MAX 5000
|
||||
#define RETRANSMIT_TIMEOUT_MAX 5000 // Maximum retransmit timeout (ms)
|
||||
#endif
|
||||
|
||||
#ifndef AVERAGE_DELTA_MAX
|
||||
#define AVERAGE_DELTA_MAX 2500
|
||||
#define AVERAGE_DELTA_MAX 2500 // Maximum average delta (ms)
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/**
|
||||
* Session request packet structure.
|
||||
* Sent by client to initiate a new session.
|
||||
*/
|
||||
struct SessionRequest {
|
||||
uint32 UnknownA;
|
||||
uint32 Session;
|
||||
uint32 MaxLength;
|
||||
uint32 UnknownA; // Unknown field A
|
||||
uint32 Session; // Requested session ID
|
||||
uint32 MaxLength; // Maximum packet length
|
||||
};
|
||||
|
||||
/**
|
||||
* Session response packet structure.
|
||||
* Sent by server in response to session request.
|
||||
*/
|
||||
struct SessionResponse {
|
||||
uint32 Session;
|
||||
uint32 Key;
|
||||
uint8 UnknownA;
|
||||
uint8 Format;
|
||||
uint8 UnknownB;
|
||||
uint32 MaxLength;
|
||||
uint32 UnknownD;
|
||||
uint32 Session; // Assigned session ID
|
||||
uint32 Key; // Encryption/authentication key
|
||||
uint8 UnknownA; // Unknown field A
|
||||
uint8 Format; // Packet format version
|
||||
uint8 UnknownB; // Unknown field B
|
||||
uint32 MaxLength; // Maximum packet length
|
||||
uint32 UnknownD; // Unknown field D
|
||||
};
|
||||
|
||||
//Deltas are in ms, representing round trip times
|
||||
/**
|
||||
* Client-side session statistics.
|
||||
* Deltas are in milliseconds, representing round trip times.
|
||||
*/
|
||||
struct ClientSessionStats {
|
||||
/*000*/ uint16 RequestID;
|
||||
/*002*/ uint32 last_local_delta;
|
||||
/*006*/ uint32 average_delta;
|
||||
/*010*/ uint32 low_delta;
|
||||
/*014*/ uint32 high_delta;
|
||||
/*018*/ uint32 last_remote_delta;
|
||||
/*022*/ uint64 packets_sent;
|
||||
/*030*/ uint64 packets_recieved;
|
||||
/*000*/ uint16 RequestID; // Statistics request ID
|
||||
/*002*/ uint32 last_local_delta; // Last local round trip time
|
||||
/*006*/ uint32 average_delta; // Average round trip time
|
||||
/*010*/ uint32 low_delta; // Lowest recorded round trip time
|
||||
/*014*/ uint32 high_delta; // Highest recorded round trip time
|
||||
/*018*/ uint32 last_remote_delta; // Last remote round trip time
|
||||
/*022*/ uint64 packets_sent; // Total packets sent
|
||||
/*030*/ uint64 packets_recieved; // Total packets received
|
||||
/*038*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Server-side session statistics.
|
||||
* Provides server perspective on connection quality.
|
||||
*/
|
||||
struct ServerSessionStats {
|
||||
uint16 RequestID;
|
||||
uint32 current_time;
|
||||
uint32 unknown1;
|
||||
uint32 received_packets;
|
||||
uint32 unknown2;
|
||||
uint32 sent_packets;
|
||||
uint32 unknown3;
|
||||
uint32 sent_packets2;
|
||||
uint32 unknown4;
|
||||
uint32 received_packets2;
|
||||
uint16 RequestID; // Statistics request ID
|
||||
uint32 current_time; // Current server time
|
||||
uint32 unknown1; // Unknown field 1
|
||||
uint32 received_packets; // Packets received by server
|
||||
uint32 unknown2; // Unknown field 2
|
||||
uint32 sent_packets; // Packets sent by server
|
||||
uint32 unknown3; // Unknown field 3
|
||||
uint32 sent_packets2; // Duplicate sent packets count
|
||||
uint32 unknown4; // Unknown field 4
|
||||
uint32 received_packets2; // Duplicate received packets count
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
class OpcodeManager;
|
||||
extern OpcodeManager *EQNetworkOpcodeManager;
|
||||
|
||||
class EQStreamFactory;
|
||||
// External opcode manager
|
||||
extern OpcodeManager* EQNetworkOpcodeManager;
|
||||
|
||||
/**
|
||||
* Types of EverQuest network streams.
|
||||
* Each type handles different aspects of the game protocol.
|
||||
*/
|
||||
typedef enum {
|
||||
UnknownStream=0,
|
||||
LoginStream,
|
||||
WorldStream,
|
||||
ZoneStream,
|
||||
ChatOrMailStream,
|
||||
ChatStream,
|
||||
MailStream,
|
||||
EQ2Stream,
|
||||
UnknownStream = 0, // Unidentified stream type
|
||||
LoginStream, // Login server authentication
|
||||
WorldStream, // World server communication
|
||||
ZoneStream, // Zone server gameplay
|
||||
ChatOrMailStream, // Combined chat/mail (legacy)
|
||||
ChatStream, // Chat system only
|
||||
MailStream, // Mail system only
|
||||
EQ2Stream, // EverQuest 2 specific stream
|
||||
} EQStreamType;
|
||||
|
||||
/**
|
||||
* EverQuest network stream class.
|
||||
* Handles reliable UDP communication with sequence numbers, acknowledgments,
|
||||
* compression, encryption, and packet combining for EverQuest protocols.
|
||||
*/
|
||||
class EQStream {
|
||||
protected:
|
||||
typedef enum {
|
||||
SeqPast,
|
||||
SeqInOrder,
|
||||
SeqFuture
|
||||
} SeqOrder;
|
||||
protected:
|
||||
/**
|
||||
* Sequence number ordering enumeration.
|
||||
* Used to determine packet sequence relationships.
|
||||
*/
|
||||
typedef enum {
|
||||
SeqPast, // Sequence is from the past (duplicate/old)
|
||||
SeqInOrder, // Sequence is the expected next sequence
|
||||
SeqFuture // Sequence is from the future (out of order)
|
||||
} SeqOrder;
|
||||
|
||||
uint32 received_packets;
|
||||
uint32 sent_packets;
|
||||
uint32 remote_ip;
|
||||
uint16 remote_port;
|
||||
uint8 buffer[8192];
|
||||
unsigned char *oversize_buffer;
|
||||
uint32 oversize_offset,oversize_length;
|
||||
unsigned char *rogue_buffer;
|
||||
uint32 roguebuf_offset,roguebuf_size;
|
||||
uint8 app_opcode_size;
|
||||
EQStreamType StreamType;
|
||||
bool compressed,encoded;
|
||||
|
||||
unsigned char write_buffer[2048];
|
||||
|
||||
uint32 retransmittimer;
|
||||
uint32 retransmittimeout;
|
||||
//uint32 buffer_len;
|
||||
// Packet statistics
|
||||
uint32 received_packets; // Total packets received
|
||||
uint32 sent_packets; // Total packets sent
|
||||
|
||||
// Remote endpoint information
|
||||
uint32 remote_ip; // Remote IP address
|
||||
uint16 remote_port; // Remote port number
|
||||
|
||||
// Packet buffers
|
||||
uint8 buffer[8192]; // Main packet buffer
|
||||
unsigned char* oversize_buffer; // Buffer for oversized packets
|
||||
uint32 oversize_offset; // Offset in oversize buffer
|
||||
uint32 oversize_length; // Length of oversize buffer data
|
||||
unsigned char* rogue_buffer; // Buffer for rogue/malformed packets
|
||||
uint32 roguebuf_offset; // Offset in rogue buffer
|
||||
uint32 roguebuf_size; // Size of rogue buffer
|
||||
|
||||
// Protocol configuration
|
||||
uint8 app_opcode_size; // Size of application opcodes
|
||||
EQStreamType StreamType; // Type of this stream
|
||||
bool compressed; // Stream supports compression
|
||||
bool encoded; // Stream supports encoding/encryption
|
||||
|
||||
// Write buffer for outgoing packets
|
||||
unsigned char write_buffer[2048];
|
||||
|
||||
// Retransmission timing
|
||||
uint32 retransmittimer; // Current retransmit timer
|
||||
uint32 retransmittimeout; // Retransmit timeout value
|
||||
|
||||
uint16 sessionAttempts;
|
||||
uint16 reconnectAttempt;
|
||||
bool streamactive;
|
||||
// Session management
|
||||
uint16 sessionAttempts; // Number of session attempts
|
||||
uint16 reconnectAttempt; // Number of reconnect attempts
|
||||
bool streamactive; // Stream is actively connected
|
||||
|
||||
uint32 Session, Key;
|
||||
uint16 NextInSeq;
|
||||
uint16 NextOutSeq;
|
||||
uint16 SequencedBase; //the sequence number of SequencedQueue[0]
|
||||
uint32 MaxLen;
|
||||
uint16 MaxSends;
|
||||
int8 timeout_delays;
|
||||
// Session state
|
||||
uint32 Session; // Session ID
|
||||
uint32 Key; // Session encryption key
|
||||
uint16 NextInSeq; // Next expected incoming sequence
|
||||
uint16 NextOutSeq; // Next outgoing sequence number
|
||||
uint16 SequencedBase; // Base sequence for SequencedQueue[0]
|
||||
uint32 MaxLen; // Maximum packet length
|
||||
uint16 MaxSends; // Maximum send attempts
|
||||
int8 timeout_delays; // Number of timeout delays accumulated
|
||||
|
||||
uint8 active_users; //how many things are actively using this
|
||||
Mutex MInUse;
|
||||
// Thread safety for stream usage
|
||||
uint8 active_users; // Number of active users of this stream
|
||||
Mutex MInUse; // Mutex for usage tracking
|
||||
|
||||
#ifdef WRITE_PACKETS
|
||||
FILE* write_packets = NULL;
|
||||
char GetChar(uchar in);
|
||||
void WriteToFile(char* pFormat, ...);
|
||||
void WritePackets(const char* opcodeName, uchar* data, int32 size, bool outgoing);
|
||||
void WritePackets(EQ2Packet* app, bool outgoing);
|
||||
Mutex MWritePackets;
|
||||
// Packet logging for debugging
|
||||
FILE* write_packets = nullptr; // File handle for packet dumps
|
||||
char GetChar(uchar in); // Convert byte to printable character
|
||||
void WriteToFile(char* pFormat, ...); // Write formatted data to file
|
||||
void WritePackets(const char* opcodeName, uchar* data, int32 size, bool outgoing);
|
||||
void WritePackets(EQ2Packet* app, bool outgoing);
|
||||
Mutex MWritePackets; // Mutex for packet writing
|
||||
#endif
|
||||
|
||||
EQStreamState State;
|
||||
Mutex MState;
|
||||
// Stream connection state
|
||||
EQStreamState State; // Current connection state
|
||||
Mutex MState; // Mutex for state access
|
||||
|
||||
uint32 LastPacket;
|
||||
Mutex MVarlock;
|
||||
// Timing and general variables
|
||||
uint32 LastPacket; // Timestamp of last packet activity
|
||||
Mutex MVarlock; // General variable lock
|
||||
|
||||
EQApplicationPacket* CombinedAppPacket;
|
||||
Mutex MCombinedAppPacket;
|
||||
// Combined application packet handling
|
||||
EQApplicationPacket* CombinedAppPacket; // Current combined packet
|
||||
Mutex MCombinedAppPacket; // Mutex for combined packet access
|
||||
|
||||
long LastSeqSent;
|
||||
Mutex MLastSeqSent;
|
||||
void SetLastSeqSent(uint32);
|
||||
// Sequence number tracking
|
||||
long LastSeqSent; // Last sequence number sent
|
||||
Mutex MLastSeqSent; // Mutex for last sequence sent
|
||||
void SetLastSeqSent(uint32 seq); // Set last sent sequence number
|
||||
|
||||
// Ack sequence tracking.
|
||||
long MaxAckReceived,NextAckToSend,LastAckSent;
|
||||
long GetMaxAckReceived();
|
||||
long GetNextAckToSend();
|
||||
long GetLastAckSent();
|
||||
void SetMaxAckReceived(uint32 seq);
|
||||
void SetNextAckToSend(uint32);
|
||||
void SetLastAckSent(uint32);
|
||||
// Acknowledgment sequence tracking
|
||||
long MaxAckReceived; // Highest ack sequence received
|
||||
long NextAckToSend; // Next ack sequence to send
|
||||
long LastAckSent; // Last ack sequence sent
|
||||
|
||||
// Acknowledgment accessor methods
|
||||
long GetMaxAckReceived();
|
||||
long GetNextAckToSend();
|
||||
long GetLastAckSent();
|
||||
void SetMaxAckReceived(uint32 seq);
|
||||
void SetNextAckToSend(uint32 seq);
|
||||
void SetLastAckSent(uint32 seq);
|
||||
|
||||
Mutex MAcks;
|
||||
Mutex MAcks; // Mutex for acknowledgment data
|
||||
|
||||
// Packets waiting to be sent
|
||||
queue<EQProtocolPacket*> NonSequencedQueue;
|
||||
deque<EQProtocolPacket*> SequencedQueue;
|
||||
map<uint16, EQProtocolPacket *> OutOfOrderpackets;
|
||||
Mutex MOutboundQueue;
|
||||
// Outbound packet queues
|
||||
queue<EQProtocolPacket*> NonSequencedQueue; // Non-sequenced packets
|
||||
deque<EQProtocolPacket*> SequencedQueue; // Sequenced packets
|
||||
map<uint16, EQProtocolPacket*> OutOfOrderpackets; // Out-of-order packets
|
||||
Mutex MOutboundQueue; // Mutex for outbound queues
|
||||
|
||||
// Packes waiting to be processed
|
||||
deque<EQApplicationPacket *> InboundQueue;
|
||||
Mutex MInboundQueue;
|
||||
// Inbound packet queue
|
||||
deque<EQApplicationPacket*> InboundQueue; // Packets waiting processing
|
||||
Mutex MInboundQueue; // Mutex for inbound queue
|
||||
|
||||
static uint16 MaxWindowSize;
|
||||
// Static configuration
|
||||
static uint16 MaxWindowSize; // Maximum window size for flow control
|
||||
|
||||
sint32 BytesWritten;
|
||||
// Rate limiting and flow control
|
||||
sint32 BytesWritten; // Bytes written this period
|
||||
Mutex MRate; // Mutex for rate limiting
|
||||
sint32 RateThreshold; // Rate limiting threshold
|
||||
sint32 DecayRate; // Rate decay per time period
|
||||
uint32 AverageDelta; // Average round-trip time
|
||||
|
||||
Mutex MRate;
|
||||
sint32 RateThreshold;
|
||||
sint32 DecayRate;
|
||||
uint32 AverageDelta;
|
||||
// Factory reference
|
||||
EQStreamFactory* Factory; // Factory that created this stream
|
||||
|
||||
EQStreamFactory *Factory;
|
||||
public:
|
||||
// EQ2-specific packet combining
|
||||
Mutex MCombineQueueLock; // Mutex for combine queue operations
|
||||
bool CheckCombineQueue(); // Check and process combine queue
|
||||
deque<EQ2Packet*> combine_queue; // Queue of packets to combine
|
||||
Timer* combine_timer; // Timer for combine operations
|
||||
|
||||
public:
|
||||
Mutex MCombineQueueLock;
|
||||
bool CheckCombineQueue();
|
||||
deque<EQ2Packet*> combine_queue;
|
||||
Timer* combine_timer;
|
||||
|
||||
Crypto* crypto;
|
||||
int8 EQ2_Compress(EQ2Packet* app, int8 offset = 3);
|
||||
z_stream stream;
|
||||
uchar* stream_buffer;
|
||||
int32 stream_buffer_size;
|
||||
bool eq2_compressed;
|
||||
int8 compressed_offset;
|
||||
int16 client_version;
|
||||
int16 GetClientVersion(){ return client_version; }
|
||||
void SetClientVersion(int16 version){ client_version = version; }
|
||||
void ResetSessionAttempts() { reconnectAttempt = 0; }
|
||||
bool HasSessionAttempts() { return reconnectAttempt>0; }
|
||||
EQStream() { init(); remote_ip = 0; remote_port = 0; State = CLOSED; StreamType = UnknownStream; compressed = true;
|
||||
encoded = false; app_opcode_size = 2;}
|
||||
EQStream(sockaddr_in addr);
|
||||
virtual ~EQStream() {
|
||||
MOutboundQueue.lock();
|
||||
SetState(CLOSED);
|
||||
MOutboundQueue.unlock();
|
||||
RemoveData();
|
||||
safe_delete(crypto);
|
||||
safe_delete(combine_timer);
|
||||
safe_delete(resend_que_timer);
|
||||
safe_delete_array(oversize_buffer);
|
||||
safe_delete_array(rogue_buffer);
|
||||
deque<EQ2Packet*>::iterator cmb;
|
||||
MCombineQueueLock.lock();
|
||||
for (cmb = combine_queue.begin(); cmb != combine_queue.end(); cmb++){
|
||||
safe_delete(*cmb);
|
||||
}
|
||||
MCombineQueueLock.unlock();
|
||||
deflateEnd(&stream);
|
||||
map<int16, EQProtocolPacket*>::iterator oop;
|
||||
for (oop = OutOfOrderpackets.begin(); oop != OutOfOrderpackets.end(); oop++){
|
||||
safe_delete(oop->second);
|
||||
}
|
||||
#ifdef WRITE_PACKETS
|
||||
if (write_packets)
|
||||
fclose(write_packets);
|
||||
#endif
|
||||
// Encryption and compression
|
||||
Crypto* crypto; // Cryptographic handler
|
||||
int8 EQ2_Compress(EQ2Packet* app, int8 offset = 3); // Compress EQ2 packet
|
||||
z_stream stream; // zlib compression stream
|
||||
uchar* stream_buffer; // Compression buffer
|
||||
int32 stream_buffer_size; // Size of compression buffer
|
||||
bool eq2_compressed; // Stream uses EQ2 compression
|
||||
int8 compressed_offset; // Offset for compressed data
|
||||
|
||||
// Client version management
|
||||
int16 client_version; // Client protocol version
|
||||
int16 GetClientVersion() { return client_version; }
|
||||
void SetClientVersion(int16 version) { client_version = version; }
|
||||
|
||||
// Session attempt management
|
||||
void ResetSessionAttempts() { reconnectAttempt = 0; }
|
||||
bool HasSessionAttempts() { return reconnectAttempt > 0; }
|
||||
|
||||
// Constructors
|
||||
EQStream() {
|
||||
init();
|
||||
remote_ip = 0;
|
||||
remote_port = 0;
|
||||
State = CLOSED;
|
||||
StreamType = UnknownStream;
|
||||
compressed = true;
|
||||
encoded = false;
|
||||
app_opcode_size = 2;
|
||||
}
|
||||
|
||||
EQStream(sockaddr_in addr);
|
||||
// Destructor
|
||||
virtual ~EQStream() {
|
||||
// Close stream safely
|
||||
MOutboundQueue.lock();
|
||||
SetState(CLOSED);
|
||||
MOutboundQueue.unlock();
|
||||
|
||||
// Clean up data structures
|
||||
RemoveData();
|
||||
|
||||
// Clean up allocated resources
|
||||
safe_delete(crypto);
|
||||
safe_delete(combine_timer);
|
||||
safe_delete(resend_que_timer);
|
||||
safe_delete_array(oversize_buffer);
|
||||
safe_delete_array(rogue_buffer);
|
||||
|
||||
// Clean up combine queue
|
||||
MCombineQueueLock.lock();
|
||||
for (auto cmb = combine_queue.begin(); cmb != combine_queue.end(); ++cmb) {
|
||||
safe_delete(*cmb);
|
||||
}
|
||||
inline void SetFactory(EQStreamFactory *f) { Factory=f; }
|
||||
void init(bool resetSession = true);
|
||||
void SetMaxLen(uint32 length) { MaxLen=length; }
|
||||
int8 getTimeoutDelays(){ return timeout_delays; }
|
||||
void addTimeoutDelay(){ timeout_delays++; }
|
||||
void EQ2QueuePacket(EQ2Packet* app, bool attempted_combine = false);
|
||||
void PreparePacket(EQ2Packet* app, int8 offset = 0);
|
||||
void UnPreparePacket(EQ2Packet* app);
|
||||
void EncryptPacket(EQ2Packet* app, int8 compress_offset, int8 offset);
|
||||
void FlushCombinedPacket();
|
||||
void SendPacket(EQApplicationPacket *p);
|
||||
void QueuePacket(EQProtocolPacket *p);
|
||||
void SendPacket(EQProtocolPacket *p);
|
||||
vector<EQProtocolPacket *> convert(EQApplicationPacket *p);
|
||||
void NonSequencedPush(EQProtocolPacket *p);
|
||||
void SequencedPush(EQProtocolPacket *p);
|
||||
|
||||
Mutex MResendQue;
|
||||
Mutex MCompressData;
|
||||
deque<EQProtocolPacket*>resend_que;
|
||||
void CheckResend(int eq_fd);
|
||||
|
||||
void AckPackets(uint16 seq);
|
||||
void Write(int eq_fd);
|
||||
|
||||
void SetActive(bool val) { streamactive = val; }
|
||||
|
||||
void WritePacket(int fd,EQProtocolPacket *p);
|
||||
|
||||
void EncryptPacket(uchar* data, int16 size);
|
||||
uint32 GetKey() { return Key; }
|
||||
void SetKey(uint32 k) { Key=k; }
|
||||
void SetSession(uint32 s) { Session=s; }
|
||||
void SetLastPacketTime(uint32 t) {LastPacket=t;}
|
||||
|
||||
void Process(const unsigned char *data, const uint32 length);
|
||||
void ProcessPacket(EQProtocolPacket *p, EQProtocolPacket* lastp=NULL);
|
||||
MCombineQueueLock.unlock();
|
||||
|
||||
bool ProcessEmbeddedPacket(uchar* pBuffer, uint16 length, int8 opcode = OP_Packet);
|
||||
bool HandleEmbeddedPacket(EQProtocolPacket *p, int16 offset = 2, int16 length = 0);
|
||||
|
||||
EQProtocolPacket * ProcessEncryptedPacket(EQProtocolPacket *p);
|
||||
EQProtocolPacket * ProcessEncryptedData(uchar* data, int32 size, int16 opcode);
|
||||
|
||||
virtual void DispatchPacket(EQApplicationPacket *p) { p->DumpRaw(); }
|
||||
|
||||
void SendSessionResponse();
|
||||
void SendSessionRequest();
|
||||
void SendDisconnect(bool setstate = true);
|
||||
void SendAck(uint16 seq);
|
||||
void SendOutOfOrderAck(uint16 seq);
|
||||
|
||||
bool CheckTimeout(uint32 now, uint32 timeout=30) { return (LastPacket && (now-LastPacket) > timeout); }
|
||||
bool Stale(uint32 now, uint32 timeout=30) { return (LastPacket && (now-LastPacket) > timeout); }
|
||||
|
||||
void InboundQueuePush(EQApplicationPacket *p);
|
||||
EQApplicationPacket *PopPacket(); // InboundQueuePop
|
||||
void InboundQueueClear();
|
||||
|
||||
void OutboundQueueClear();
|
||||
bool HasOutgoingData();
|
||||
void SendKeyRequest();
|
||||
int16 processRSAKey(EQProtocolPacket *p, uint16 subpacket_length = 0);
|
||||
void RemoveData() { InboundQueueClear(); OutboundQueueClear(); if (CombinedAppPacket) delete CombinedAppPacket; }
|
||||
|
||||
//
|
||||
inline bool IsInUse() { bool flag; MInUse.lock(); flag=(active_users>0); MInUse.unlock(); return flag; }
|
||||
inline void PutInUse() { MInUse.lock(); active_users++; MInUse.unlock(); }
|
||||
inline void ReleaseFromUse() { MInUse.lock(); if(active_users > 0) active_users--; MInUse.unlock(); }
|
||||
|
||||
static SeqOrder CompareSequence(uint16 expected_seq, uint16 seq);
|
||||
|
||||
inline EQStreamState GetState() { return State; }
|
||||
inline void SetState(EQStreamState state) { MState.lock(); State = state; MState.unlock(); }
|
||||
|
||||
inline uint32 GetRemoteIP() { return remote_ip; }
|
||||
inline uint32 GetrIP() { return remote_ip; }
|
||||
inline uint16 GetRemotePort() { return remote_port; }
|
||||
inline uint16 GetrPort() { return remote_port; }
|
||||
// Clean up compression stream
|
||||
deflateEnd(&stream);
|
||||
|
||||
// Clean up out-of-order packets
|
||||
for (auto oop = OutOfOrderpackets.begin(); oop != OutOfOrderpackets.end(); ++oop) {
|
||||
safe_delete(oop->second);
|
||||
}
|
||||
|
||||
#ifdef WRITE_PACKETS
|
||||
if (write_packets) {
|
||||
fclose(write_packets);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Factory and initialization
|
||||
void SetFactory(EQStreamFactory* f) { Factory = f; }
|
||||
void init(bool resetSession = true);
|
||||
|
||||
// Configuration
|
||||
void SetMaxLen(uint32 length) { MaxLen = length; }
|
||||
int8 getTimeoutDelays() { return timeout_delays; }
|
||||
void addTimeoutDelay() { timeout_delays++; }
|
||||
|
||||
// EQ2-specific packet handling
|
||||
void EQ2QueuePacket(EQ2Packet* app, bool attempted_combine = false);
|
||||
void PreparePacket(EQ2Packet* app, int8 offset = 0);
|
||||
void UnPreparePacket(EQ2Packet* app);
|
||||
void EncryptPacket(EQ2Packet* app, int8 compress_offset, int8 offset);
|
||||
void FlushCombinedPacket();
|
||||
|
||||
// General packet transmission
|
||||
void SendPacket(EQApplicationPacket* p);
|
||||
void QueuePacket(EQProtocolPacket* p);
|
||||
void SendPacket(EQProtocolPacket* p);
|
||||
vector<EQProtocolPacket*> convert(EQApplicationPacket* p);
|
||||
void NonSequencedPush(EQProtocolPacket* p);
|
||||
void SequencedPush(EQProtocolPacket* p);
|
||||
|
||||
static EQProtocolPacket *Read(int eq_fd, sockaddr_in *from);
|
||||
// Resend queue management
|
||||
Mutex MResendQue; // Mutex for resend queue
|
||||
Mutex MCompressData; // Mutex for compression operations
|
||||
deque<EQProtocolPacket*> resend_que; // Queue of packets needing resend
|
||||
void CheckResend(int eq_fd); // Check and handle packet resends
|
||||
|
||||
void Close() { SendDisconnect(); }
|
||||
bool CheckActive() { return (GetState()==ESTABLISHED); }
|
||||
bool CheckClosed() { return GetState()==CLOSED; }
|
||||
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
|
||||
void SetStreamType(EQStreamType t);
|
||||
inline const EQStreamType GetStreamType() const { return StreamType; }
|
||||
// Acknowledgment and writing
|
||||
void AckPackets(uint16 seq); // Acknowledge received packets
|
||||
void Write(int eq_fd); // Write packets to socket
|
||||
|
||||
void ProcessQueue();
|
||||
EQProtocolPacket* RemoveQueue(uint16 seq);
|
||||
// Stream state management
|
||||
void SetActive(bool val) { streamactive = val; }
|
||||
|
||||
// Low-level packet operations
|
||||
void WritePacket(int fd, EQProtocolPacket* p);
|
||||
void EncryptPacket(uchar* data, int16 size);
|
||||
|
||||
// Session management
|
||||
uint32 GetKey() { return Key; }
|
||||
void SetKey(uint32 k) { Key = k; }
|
||||
void SetSession(uint32 s) { Session = s; }
|
||||
void SetLastPacketTime(uint32 t) { LastPacket = t; }
|
||||
|
||||
void Decay();
|
||||
void AdjustRates(uint32 average_delta);
|
||||
Timer* resend_que_timer;
|
||||
// Packet processing
|
||||
void Process(const unsigned char* data, uint32 length);
|
||||
void ProcessPacket(EQProtocolPacket* p, EQProtocolPacket* lastp = nullptr);
|
||||
|
||||
// Embedded packet handling
|
||||
bool ProcessEmbeddedPacket(uchar* pBuffer, uint16 length, int8 opcode = OP_Packet);
|
||||
bool HandleEmbeddedPacket(EQProtocolPacket* p, int16 offset = 2, int16 length = 0);
|
||||
|
||||
// Encryption handling
|
||||
EQProtocolPacket* ProcessEncryptedPacket(EQProtocolPacket* p);
|
||||
EQProtocolPacket* ProcessEncryptedData(uchar* data, int32 size, int16 opcode);
|
||||
|
||||
// Virtual packet dispatch (override in derived classes)
|
||||
virtual void DispatchPacket(EQApplicationPacket* p) { p->DumpRaw(); }
|
||||
|
||||
// Session protocol messages
|
||||
void SendSessionResponse();
|
||||
void SendSessionRequest();
|
||||
void SendDisconnect(bool setstate = true);
|
||||
void SendAck(uint16 seq);
|
||||
void SendOutOfOrderAck(uint16 seq);
|
||||
|
||||
// Connection health checks
|
||||
bool CheckTimeout(uint32 now, uint32 timeout = 30) {
|
||||
return (LastPacket && (now - LastPacket) > timeout);
|
||||
}
|
||||
bool Stale(uint32 now, uint32 timeout = 30) {
|
||||
return (LastPacket && (now - LastPacket) > timeout);
|
||||
}
|
||||
|
||||
// Inbound queue management
|
||||
void InboundQueuePush(EQApplicationPacket* p);
|
||||
EQApplicationPacket* PopPacket(); // Pop packet from inbound queue
|
||||
void InboundQueueClear();
|
||||
|
||||
// Outbound queue management
|
||||
void OutboundQueueClear();
|
||||
bool HasOutgoingData();
|
||||
|
||||
// Key exchange and RSA
|
||||
void SendKeyRequest();
|
||||
int16 processRSAKey(EQProtocolPacket* p, uint16 subpacket_length = 0);
|
||||
|
||||
// Data cleanup
|
||||
void RemoveData() {
|
||||
InboundQueueClear();
|
||||
OutboundQueueClear();
|
||||
if (CombinedAppPacket) {
|
||||
delete CombinedAppPacket;
|
||||
CombinedAppPacket = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Usage tracking (thread-safe reference counting)
|
||||
bool IsInUse() {
|
||||
bool flag;
|
||||
MInUse.lock();
|
||||
flag = (active_users > 0);
|
||||
MInUse.unlock();
|
||||
return flag;
|
||||
}
|
||||
|
||||
void PutInUse() {
|
||||
MInUse.lock();
|
||||
active_users++;
|
||||
MInUse.unlock();
|
||||
}
|
||||
|
||||
void ReleaseFromUse() {
|
||||
MInUse.lock();
|
||||
if (active_users > 0) {
|
||||
active_users--;
|
||||
}
|
||||
MInUse.unlock();
|
||||
}
|
||||
|
||||
// Sequence number utilities
|
||||
static SeqOrder CompareSequence(uint16 expected_seq, uint16 seq);
|
||||
|
||||
// State management
|
||||
EQStreamState GetState() { return State; }
|
||||
void SetState(EQStreamState state) {
|
||||
MState.lock();
|
||||
State = state;
|
||||
MState.unlock();
|
||||
}
|
||||
|
||||
// Remote endpoint access
|
||||
uint32 GetRemoteIP() { return remote_ip; }
|
||||
uint32 GetrIP() { return remote_ip; } // Legacy alias
|
||||
uint16 GetRemotePort() { return remote_port; }
|
||||
uint16 GetrPort() { return remote_port; } // Legacy alias
|
||||
|
||||
// Static packet reading
|
||||
static EQProtocolPacket* Read(int eq_fd, sockaddr_in* from);
|
||||
|
||||
// Connection management
|
||||
void Close() { SendDisconnect(); }
|
||||
bool CheckActive() { return (GetState() == ESTABLISHED); }
|
||||
bool CheckClosed() { return GetState() == CLOSED; }
|
||||
|
||||
// Stream configuration
|
||||
void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
|
||||
void SetStreamType(EQStreamType t);
|
||||
EQStreamType GetStreamType() const { return StreamType; }
|
||||
|
||||
// Queue processing
|
||||
void ProcessQueue();
|
||||
EQProtocolPacket* RemoveQueue(uint16 seq);
|
||||
|
||||
// Rate limiting and flow control
|
||||
void Decay();
|
||||
void AdjustRates(uint32 average_delta);
|
||||
|
||||
// Resend timer
|
||||
Timer* resend_que_timer; // Timer for checking resend queue
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user