clean EQPacket

This commit is contained in:
Sky Johnson 2025-08-31 22:10:29 -05:00
parent 6401247809
commit a8c533f012
2 changed files with 856 additions and 447 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,13 @@
/* // EQ2Emulator: Everquest II Server Emulator
EQ2Emulator: Everquest II Server Emulator // Copyright (C) 2007 EQ2EMulator Development Team
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) // Licensed under GPL v3 - see <http://www.gnu.org/licenses/>
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/>.
*/
#ifndef _EQPACKET_H #ifndef _EQPACKET_H
#define _EQPACKET_H #define _EQPACKET_H
#include "types.h" #include "types.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <memory>
#ifdef WIN32 #ifdef WIN32
#include <time.h> #include <time.h>
@ -36,59 +21,103 @@
#include "op_codes.h" #include "op_codes.h"
#include "packet_dump.h" #include "packet_dump.h"
// Forward declarations
class OpcodeManager; class OpcodeManager;
class EQStream; class EQStream;
/**
* Base class for all EverQuest packet types.
* Provides common functionality for packet management, opcode handling,
* and network information tracking.
*/
class EQPacket { class EQPacket {
friend class EQStream; friend class EQStream;
public: public:
unsigned char *pBuffer; // Packet data
uint32 size; unsigned char* pBuffer; // Raw packet data buffer
uint32 src_ip,dst_ip; uint32 size; // Size of packet data
uint16 src_port,dst_port;
uint32 priority; // Network information
timeval timestamp; uint32 src_ip, dst_ip; // Source and destination IP addresses
int16 version; uint16 src_port, dst_port; // Source and destination ports
uint32 priority; // Packet priority for processing
timeval timestamp; // Packet timestamp
int16 version; // Protocol version
~EQPacket(); ~EQPacket();
// Debug and display methods
void DumpRawHeader(uint16 seq = 0xffff, FILE* to = stdout) const; void DumpRawHeader(uint16 seq = 0xffff, FILE* to = stdout) const;
void DumpRawHeaderNoTime(uint16 seq = 0xffff, FILE* to = stdout) const; void DumpRawHeaderNoTime(uint16 seq = 0xffff, FILE* to = stdout) const;
void DumpRaw(FILE* to = stdout) const; void DumpRaw(FILE* to = stdout) const;
const char* GetOpcodeName(); const char* GetOpcodeName();
// Packet information setters
void setVersion(int16 new_version) { version = new_version; } void setVersion(int16 new_version) { version = new_version; }
void setSrcInfo(uint32 sip, uint16 sport) { src_ip = sip; src_port = sport; } void setSrcInfo(uint32 sip, uint16 sport) { src_ip = sip; src_port = sport; }
void setDstInfo(uint32 dip, uint16 dport) { dst_ip = dip; dst_port = dport; } void setDstInfo(uint32 dip, uint16 dport) { dst_ip = dip; dst_port = dport; }
void setTimeInfo(uint32 ts_sec, uint32 ts_usec) { timestamp.tv_sec=ts_sec; timestamp.tv_usec=ts_usec; } void setTimeInfo(uint32 ts_sec, uint32 ts_usec) {
void copyInfo(const EQPacket *p) { src_ip=p->src_ip; src_port=p->src_port; dst_ip=p->dst_ip; dst_port=p->dst_port; timestamp.tv_sec=p->timestamp.tv_sec; timestamp.tv_usec=p->timestamp.tv_usec; } timestamp.tv_sec = ts_sec;
timestamp.tv_usec = ts_usec;
}
// Copy network and timing info from another packet
void copyInfo(const EQPacket* p) {
src_ip = p->src_ip;
src_port = p->src_port;
dst_ip = p->dst_ip;
dst_port = p->dst_port;
timestamp.tv_sec = p->timestamp.tv_sec;
timestamp.tv_usec = p->timestamp.tv_usec;
}
// Get total packet size including opcode
uint32 Size() const { return size + 2; } uint32 Size() const { return size + 2; }
//no reason to have this method in zone or world // Get raw opcode value
uint16 GetRawOpcode() const { return opcode; }
uint16 GetRawOpcode() const { return(opcode); } // Comparison operator for timestamp-based sorting
bool operator<(const EQPacket& rhs) const {
return (timestamp.tv_sec < rhs.timestamp.tv_sec ||
inline bool operator<(const EQPacket &rhs) { (timestamp.tv_sec == rhs.timestamp.tv_sec &&
return (timestamp.tv_sec < rhs.timestamp.tv_sec || (timestamp.tv_sec==rhs.timestamp.tv_sec && timestamp.tv_usec < rhs.timestamp.tv_usec)); timestamp.tv_usec < rhs.timestamp.tv_usec));
} }
// Set the protocol opcode
void SetProtocolOpcode(int16 new_opcode) { void SetProtocolOpcode(int16 new_opcode) {
opcode = new_opcode; opcode = new_opcode;
} }
protected: protected:
uint16 opcode; uint16 opcode; // Packet opcode
EQPacket(const uint16 op, const unsigned char *buf, const uint32 len); // Constructors (protected to enforce proper inheritance)
EQPacket(uint16 op, const unsigned char* buf, uint32 len);
EQPacket(const EQPacket& p) { version = 0; } EQPacket(const EQPacket& p) { version = 0; }
EQPacket() { opcode=0; pBuffer=NULL; size=0; version = 0; setTimeInfo(0, 0); } EQPacket() {
opcode = 0;
pBuffer = nullptr;
size = 0;
version = 0;
setTimeInfo(0, 0);
}
}; };
// Forward declaration
class EQApplicationPacket; class EQApplicationPacket;
/**
* Protocol-level packet class for EverQuest network communication.
* Handles low-level protocol features like compression, encryption,
* sequencing, and packet combining.
*/
class EQProtocolPacket : public EQPacket { class EQProtocolPacket : public EQPacket {
public: public:
EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len) : EQPacket(op,buf,len) { // Constructor with opcode and buffer
EQProtocolPacket(uint16 op, const unsigned char* buf, uint32 len)
: EQPacket(op, buf, len) {
eq2_compressed = false; eq2_compressed = false;
packet_prepared = false; packet_prepared = false;
packet_encrypted = false; packet_encrypted = false;
@ -97,109 +126,181 @@ public:
attempt_count = 0; attempt_count = 0;
acked = false; acked = false;
} }
// Constructor from raw buffer with optional opcode override
EQProtocolPacket(const unsigned char* buf, uint32 len, int in_opcode = -1); EQProtocolPacket(const unsigned char* buf, uint32 len, int in_opcode = -1);
// Packet manipulation methods
bool combine(const EQProtocolPacket* rhs); bool combine(const EQProtocolPacket* rhs);
uint32 serialize(unsigned char* dest, int8 offset = 0) const; uint32 serialize(unsigned char* dest, int8 offset = 0) const;
// Static utility methods for packet processing
static bool ValidateCRC(const unsigned char* buffer, int length, uint32 Key); static bool ValidateCRC(const unsigned char* buffer, int length, uint32 Key);
static uint32 Decompress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize); static uint32 Decompress(const unsigned char* buffer, uint32 length,
static uint32 Compress(const unsigned char *buffer, const uint32 length, unsigned char *newbuf, uint32 newbufsize); unsigned char* newbuf, uint32 newbufsize);
static uint32 Compress(const unsigned char* buffer, uint32 length,
unsigned char* newbuf, uint32 newbufsize);
static void ChatDecode(unsigned char* buffer, int size, int DecodeKey); static void ChatDecode(unsigned char* buffer, int size, int DecodeKey);
static void ChatEncode(unsigned char* buffer, int size, int EncodeKey); static void ChatEncode(unsigned char* buffer, int size, int EncodeKey);
static bool IsProtocolPacket(const unsigned char* in_buff, uint32_t len, bool bTrimCRC); static bool IsProtocolPacket(const unsigned char* in_buff, uint32_t len, bool bTrimCRC);
// Create a copy of this packet
EQProtocolPacket* Copy() { EQProtocolPacket* Copy() {
EQProtocolPacket* new_packet = new EQProtocolPacket(opcode,pBuffer,size); auto new_packet = new EQProtocolPacket(opcode, pBuffer, size);
new_packet->eq2_compressed = this->eq2_compressed; new_packet->eq2_compressed = this->eq2_compressed;
new_packet->packet_prepared = this->packet_prepared; new_packet->packet_prepared = this->packet_prepared;
new_packet->packet_encrypted = this->packet_encrypted; new_packet->packet_encrypted = this->packet_encrypted;
return new_packet; return new_packet;
} }
// Convert to application-level packet
EQApplicationPacket* MakeApplicationPacket(uint8 opcode_size = 0) const; EQApplicationPacket* MakeApplicationPacket(uint8 opcode_size = 0) const;
bool eq2_compressed;
bool packet_prepared; // Protocol packet state flags
bool packet_encrypted; bool eq2_compressed; // Packet is compressed
bool acked; bool packet_prepared; // Packet has been prepared for sending
int32 sent_time; bool packet_encrypted; // Packet is encrypted
int8 attempt_count; bool acked; // Packet has been acknowledged
int32 sequence;
// Reliability and sequencing
int32 sent_time; // Timestamp when packet was sent
int8 attempt_count; // Number of send attempts
int32 sequence; // Sequence number for ordering
private: private:
EQProtocolPacket(const EQProtocolPacket &p) { } // Prevent copy construction
//bool dont_combine; EQProtocolPacket(const EQProtocolPacket& p) = delete;
EQProtocolPacket& operator=(const EQProtocolPacket& p) = delete;
}; };
/**
* EverQuest 2 specific packet class.
* Handles EQ2-specific packet operations like application combining
* and login opcode management.
*/
class EQ2Packet : public EQProtocolPacket { class EQ2Packet : public EQProtocolPacket {
public: public:
EQ2Packet(const EmuOpcode in_login_op, const unsigned char *buf, uint32 len) : EQProtocolPacket(OP_Packet,buf,len){ // Constructor with EQ2 login opcode
EQ2Packet(EmuOpcode in_login_op, const unsigned char* buf, uint32 len)
: EQProtocolPacket(OP_Packet, buf, len) {
login_op = in_login_op; login_op = in_login_op;
eq2_compressed = false; eq2_compressed = false;
packet_prepared = false; packet_prepared = false;
packet_encrypted = false; packet_encrypted = false;
} }
// EQ2-specific packet operations
bool AppCombine(EQ2Packet* rhs); bool AppCombine(EQ2Packet* rhs);
int8 PreparePacket(int16 MaxLen);
const char* GetOpcodeName();
// Create a copy of this EQ2 packet
EQ2Packet* Copy() { EQ2Packet* Copy() {
EQ2Packet* new_packet = new EQ2Packet(login_op,pBuffer,size); auto new_packet = new EQ2Packet(login_op, pBuffer, size);
new_packet->eq2_compressed = this->eq2_compressed; new_packet->eq2_compressed = this->eq2_compressed;
new_packet->packet_prepared = this->packet_prepared; new_packet->packet_prepared = this->packet_prepared;
new_packet->packet_encrypted = this->packet_encrypted; new_packet->packet_encrypted = this->packet_encrypted;
return new_packet; return new_packet;
} }
int8 PreparePacket(int16 MaxLen);
const char* GetOpcodeName(); EmuOpcode login_op; // EQ2 login/application opcode
EmuOpcode login_op;
}; };
/**
* Application-level packet class for EverQuest.
* Handles high-level game opcodes and application data.
* This is the main packet type used by game logic.
*/
class EQApplicationPacket : public EQPacket { class EQApplicationPacket : public EQPacket {
friend class EQProtocolPacket; friend class EQProtocolPacket;
friend class EQStream; friend class EQStream;
public: public:
EQApplicationPacket() : EQPacket(0,NULL,0) { emu_opcode = OP_Unknown; app_opcode_size=default_opcode_size; } // Default constructor
EQApplicationPacket(const EmuOpcode op) : EQPacket(0,NULL,0) { SetOpcode(op); app_opcode_size=default_opcode_size; } EQApplicationPacket() : EQPacket(0, nullptr, 0) {
EQApplicationPacket(const EmuOpcode op, const uint32 len) : EQPacket(0,NULL,len) { SetOpcode(op); app_opcode_size=default_opcode_size; } emu_opcode = OP_Unknown;
EQApplicationPacket(const EmuOpcode op, const unsigned char *buf, const uint32 len) : EQPacket(0,buf,len) { SetOpcode(op); app_opcode_size=default_opcode_size; } app_opcode_size = default_opcode_size;
}
// Constructor with opcode only
EQApplicationPacket(EmuOpcode op) : EQPacket(0, nullptr, 0) {
SetOpcode(op);
app_opcode_size = default_opcode_size;
}
// Constructor with opcode and size
EQApplicationPacket(EmuOpcode op, uint32 len) : EQPacket(0, nullptr, len) {
SetOpcode(op);
app_opcode_size = default_opcode_size;
}
// Constructor with opcode, buffer, and size
EQApplicationPacket(EmuOpcode op, const unsigned char* buf, uint32 len)
: EQPacket(0, buf, len) {
SetOpcode(op);
app_opcode_size = default_opcode_size;
}
// Packet operations
bool combine(const EQApplicationPacket* rhs); bool combine(const EQApplicationPacket* rhs);
uint32 serialize(unsigned char* dest) const; uint32 serialize(unsigned char* dest) const;
uint32 Size() const { return size + app_opcode_size; } uint32 Size() const { return size + app_opcode_size; }
// Create a deep copy of this packet
EQApplicationPacket* Copy() const { EQApplicationPacket* Copy() const {
EQApplicationPacket *it = new EQApplicationPacket; auto it = std::make_unique<EQApplicationPacket>();
try { try {
if (size > 0) {
it->pBuffer = new unsigned char[size]; it->pBuffer = new unsigned char[size];
memcpy(it->pBuffer, pBuffer, size); memcpy(it->pBuffer, pBuffer, size);
}
it->size = size; it->size = size;
it->opcode = opcode; it->opcode = opcode;
it->emu_opcode = emu_opcode; it->emu_opcode = emu_opcode;
it->version = version; it->version = version;
return(it); return it.release();
} }
catch( bad_alloc &ba ) catch (const std::bad_alloc& ba) {
{ // Memory allocation failed - return nullptr
cout << ba.what() << endl; return nullptr;
if( NULL != it )
delete it;
} }
return NULL;
} }
// Opcode management
void SetOpcodeSize(uint8 s) { app_opcode_size = s; } void SetOpcodeSize(uint8 s) { app_opcode_size = s; }
void SetOpcode(EmuOpcode op); void SetOpcode(EmuOpcode op);
const EmuOpcode GetOpcodeConst() const; const EmuOpcode GetOpcodeConst() const;
inline const EmuOpcode GetOpcode() const { return(GetOpcodeConst()); }
//caching version of get
inline const EmuOpcode GetOpcode() { EmuOpcode r = GetOpcodeConst(); emu_opcode = r; return(r); }
// Get opcode (const version)
const EmuOpcode GetOpcode() const { return GetOpcodeConst(); }
// Get opcode (caching version for performance)
EmuOpcode GetOpcode() {
EmuOpcode r = GetOpcodeConst();
emu_opcode = r;
return r;
}
// Default opcode size for all application packets
static uint8 default_opcode_size; static uint8 default_opcode_size;
protected: protected:
//this is just a cache so we dont look it up several times on Get() // Cached emulator opcode to avoid repeated lookups
EmuOpcode emu_opcode; EmuOpcode emu_opcode;
private: private:
//this constructor should only be used by EQProtocolPacket, as it // Constructor used by EQProtocolPacket - assumes first bytes are opcode
//assumes the first two bytes of buf are the opcode.
EQApplicationPacket(const unsigned char* buf, uint32 len, uint8 opcode_size = 0); EQApplicationPacket(const unsigned char* buf, uint32 len, uint8 opcode_size = 0);
EQApplicationPacket(const EQApplicationPacket &p) { emu_opcode = OP_Unknown; app_opcode_size=default_opcode_size; }
// Prevent copy construction
EQApplicationPacket(const EQApplicationPacket& p) = delete;
EQApplicationPacket& operator=(const EQApplicationPacket& p) = delete;
// Size of the opcode in bytes (1 or 2)
uint8 app_opcode_size; uint8 app_opcode_size;
}; };
// Packet debugging and display functions
void DumpPacketHex(const EQApplicationPacket* app); void DumpPacketHex(const EQApplicationPacket* app);
void DumpPacket(const EQProtocolPacket* app); void DumpPacket(const EQProtocolPacket* app);
void DumpPacketAscii(const EQApplicationPacket* app); void DumpPacketAscii(const EQApplicationPacket* app);