mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
439 lines
9.3 KiB
C++
439 lines
9.3 KiB
C++
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <winsock2.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "packetfile.h"
|
|
#include "../common/eq_opcodes.h"
|
|
#include "../common/eq_packet_structs.h"
|
|
#include "../common/misc.h"
|
|
#include <map>
|
|
|
|
PacketFileWriter::PacketFileWriter(bool _force_flush) {
|
|
out = NULL;
|
|
force_flush = _force_flush;
|
|
}
|
|
|
|
PacketFileWriter::~PacketFileWriter() {
|
|
CloseFile();
|
|
}
|
|
|
|
bool PacketFileWriter::SetPacketStamp(const char *name, uint32 stamp) {
|
|
FILE *in;
|
|
in = fopen(name, "r+b");
|
|
if(in == NULL) {
|
|
fprintf(stderr, "Error opening packet file '%s': %s\n", name, strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
unsigned long magic = 0;
|
|
|
|
if(fread(&magic, sizeof(magic), 1, in) != 1) {
|
|
fprintf(stderr, "Error reading header from packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
PacketFileReader *ret = NULL;
|
|
if(magic == OLD_PACKET_FILE_MAGIC) {
|
|
OldPacketFileHeader *pos = 0;
|
|
uint32 stamp_pos = (uint32) &pos->packet_file_stamp;
|
|
fseek(in, stamp_pos, SEEK_SET);
|
|
OldPacketFileHeader hdr;
|
|
hdr.packet_file_stamp = stamp;
|
|
if(fwrite(&hdr.packet_file_stamp, sizeof(hdr.packet_file_stamp), 1, in) != 1) {
|
|
fprintf(stderr, "Error writting to packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
} else if(magic == PACKET_FILE_MAGIC) {
|
|
PacketFileHeader *pos = 0;
|
|
uint32 stamp_pos = (uint32) &pos->packet_file_stamp;
|
|
fseek(in, stamp_pos, SEEK_SET);
|
|
PacketFileHeader hdr;
|
|
hdr.packet_file_stamp = stamp;
|
|
if(fwrite(&hdr.packet_file_stamp, sizeof(hdr.packet_file_stamp), 1, in) != 1) {
|
|
fprintf(stderr, "Error writting to packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
} else {
|
|
fprintf(stderr, "Unknown packet file type 0x%.8x\n", magic);
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
fclose(in);
|
|
return(true);
|
|
}
|
|
|
|
bool PacketFileWriter::OpenFile(const char *name) {
|
|
CloseFile();
|
|
|
|
printf("Opening packet file: %s\n", name);
|
|
|
|
out = fopen(name, "wb");
|
|
if(out == NULL) {
|
|
fprintf(stderr, "Error opening packet file '%s': %s\n", name, strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
PacketFileHeader head;
|
|
head.packet_file_magic = PACKET_FILE_MAGIC;
|
|
head.packet_file_version = PACKET_FILE_CURRENT_VERSION;
|
|
head.packet_file_stamp = time(NULL);
|
|
|
|
if(fwrite(&head, sizeof(head), 1, out) != 1) {
|
|
fprintf(stderr, "Error writting header to packet file: %s\n", strerror(errno));
|
|
fclose(out);
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
void PacketFileWriter::CloseFile() {
|
|
if(out != NULL) {
|
|
fclose(out);
|
|
out = NULL;
|
|
printf("Closed packet file.\n");
|
|
}
|
|
}
|
|
|
|
void PacketFileWriter::WritePacket(uint16 eq_op, uint32 packlen, const unsigned char *packet, bool to_server, const struct timeval &tv) {
|
|
if(out == NULL)
|
|
return;
|
|
|
|
_WriteBlock(eq_op, packet, packlen, to_server, tv);
|
|
|
|
/*
|
|
Could log only the packets we care about, but this is most of the stream,
|
|
so just log them all...
|
|
|
|
switch(eq_op) {
|
|
case OP_NewZone:
|
|
case OP_ZoneSpawns:
|
|
case OP_NewSpawn:
|
|
case OP_MobUpdate:
|
|
case OP_ClientUpdate:
|
|
case OP_Death:
|
|
case OP_DeleteSpawn:
|
|
case OP_CastSpell:
|
|
case OP_ShopRequest:
|
|
case OP_ShopEndConfirm:
|
|
case OP_ItemPacket:
|
|
_WriteBlock(eq_op, packet, packlen);
|
|
default:
|
|
return;
|
|
}
|
|
*/
|
|
}
|
|
|
|
bool PacketFileWriter::_WriteBlock(uint16 eq_op, const void *d, uint16 len, bool to_server, const struct timeval &tv) {
|
|
if(out == NULL)
|
|
return(false);
|
|
|
|
PacketFileSection s;
|
|
s.opcode = eq_op;
|
|
s.len = len;
|
|
s.tv_sec = tv.tv_sec;
|
|
s.tv_msec = tv.tv_usec/1000;
|
|
|
|
if(to_server)
|
|
SetToServer(s);
|
|
else
|
|
SetToClient(s);
|
|
|
|
if(fwrite(&s, sizeof(s), 1, out) != 1) {
|
|
fprintf(stderr, "Error writting block header: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
if(fwrite(d, 1, len, out) != len) {
|
|
fprintf(stderr, "Error writting block body: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
if(force_flush)
|
|
fflush(out);
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PacketFileReader *PacketFileReader::OpenPacketFile(const char *name) {
|
|
FILE *in;
|
|
in = fopen(name, "rb");
|
|
if(in == NULL) {
|
|
fprintf(stderr, "Error opening packet file '%s': %s\n", name, strerror(errno));
|
|
return(NULL);
|
|
}
|
|
|
|
unsigned long magic = 0;
|
|
|
|
if(fread(&magic, sizeof(magic), 1, in) != 1) {
|
|
fprintf(stderr, "Error reading header to packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(NULL);
|
|
}
|
|
|
|
PacketFileReader *ret = NULL;
|
|
if(magic == OLD_PACKET_FILE_MAGIC) {
|
|
ret = new OldPacketFileReader();
|
|
} else if(magic == PACKET_FILE_MAGIC) {
|
|
ret = new NewPacketFileReader();
|
|
} else {
|
|
fprintf(stderr, "Unknown packet file type 0x%.8x\n", magic);
|
|
fclose(in);
|
|
return(NULL);
|
|
}
|
|
|
|
if(!ret->OpenFile(name)) {
|
|
safe_delete(ret);
|
|
return(NULL);
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
PacketFileReader::PacketFileReader() {
|
|
packet_file_stamp = 0;
|
|
}
|
|
|
|
OldPacketFileReader::OldPacketFileReader()
|
|
: PacketFileReader()
|
|
{
|
|
in = NULL;
|
|
}
|
|
|
|
OldPacketFileReader::~OldPacketFileReader() {
|
|
CloseFile();
|
|
}
|
|
|
|
bool OldPacketFileReader::OpenFile(const char *name) {
|
|
CloseFile();
|
|
|
|
|
|
in = fopen(name, "rb");
|
|
if(in == NULL) {
|
|
fprintf(stderr, "Error opening packet file '%s': %s\n", name, strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
OldPacketFileHeader head;
|
|
|
|
if(fread(&head, sizeof(head), 1, in) != 1) {
|
|
fprintf(stderr, "Error reading header to packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
if(head.packet_file_magic != OLD_PACKET_FILE_MAGIC) {
|
|
fclose(in);
|
|
if(head.packet_file_magic > (OLD_PACKET_FILE_MAGIC)) {
|
|
fprintf(stderr, "Error: this is a build file, not a packet file, its allready processed!\n");
|
|
} else {
|
|
fprintf(stderr, "Error: this is not a packet file!\n");
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
uint32 now = time(NULL);
|
|
if(head.packet_file_stamp > now) {
|
|
fprintf(stderr, "Error: invalid timestamp in file. Your clock or the collector's is wrong (%d sec ahead).\n", head.packet_file_stamp-now);
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
packet_file_stamp = head.packet_file_stamp;
|
|
|
|
return(true);
|
|
}
|
|
|
|
void OldPacketFileReader::CloseFile() {
|
|
if(in != NULL) {
|
|
fclose(in);
|
|
in = NULL;
|
|
}
|
|
}
|
|
|
|
bool OldPacketFileReader::ResetFile() {
|
|
if(in == NULL)
|
|
return(false);
|
|
rewind(in);
|
|
|
|
//gotta read past the header again
|
|
OldPacketFileHeader head;
|
|
|
|
if(fread(&head, sizeof(head), 1, in) != 1) {
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool OldPacketFileReader::ReadPacket(uint16 &eq_op, uint32 &packlen, unsigned char *packet, bool &to_server, struct timeval &tv) {
|
|
if(in == NULL)
|
|
return(false);
|
|
if(feof(in))
|
|
return(false);
|
|
|
|
OldPacketFileSection s;
|
|
|
|
if(fread(&s, sizeof(s), 1, in) != 1) {
|
|
if(!feof(in))
|
|
fprintf(stderr, "Error reading section header: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
eq_op = s.opcode;
|
|
|
|
if(packlen < s.len) {
|
|
fprintf(stderr, "Packet buffer is too small! %d < %d, skipping\n", packlen, s.len);
|
|
fseek(in, s.len, SEEK_CUR);
|
|
return(false);
|
|
}
|
|
|
|
if(fread(packet, 1, s.len, in) != s.len) {
|
|
if(feof(in))
|
|
fprintf(stderr, "Error: EOF encountered when expecting packet data.\n");
|
|
else
|
|
fprintf(stderr, "Error reading packet body: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
packlen = s.len;
|
|
to_server = false;
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
NewPacketFileReader::NewPacketFileReader()
|
|
: PacketFileReader()
|
|
{
|
|
in = NULL;
|
|
}
|
|
|
|
NewPacketFileReader::~NewPacketFileReader() {
|
|
CloseFile();
|
|
}
|
|
|
|
bool NewPacketFileReader::OpenFile(const char *name) {
|
|
CloseFile();
|
|
|
|
|
|
in = fopen(name, "rb");
|
|
if(in == NULL) {
|
|
fprintf(stderr, "Error opening packet file '%s': %s\n", name, strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
PacketFileHeader head;
|
|
|
|
if(fread(&head, sizeof(head), 1, in) != 1) {
|
|
fprintf(stderr, "Error reading header to packet file: %s\n", strerror(errno));
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
if(head.packet_file_magic != PACKET_FILE_MAGIC) {
|
|
fclose(in);
|
|
if(head.packet_file_magic == (PACKET_FILE_MAGIC+1)) {
|
|
fprintf(stderr, "Error: this is a build file, not a packet file, its allready processed!\n");
|
|
} else {
|
|
fprintf(stderr, "Error: this is not a packet file!\n");
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
uint32 now = time(NULL);
|
|
if(head.packet_file_stamp > now) {
|
|
fprintf(stderr, "Error: invalid timestamp in file. Your clock or the collector's is wrong (%d sec ahead).\n", head.packet_file_stamp-now);
|
|
fclose(in);
|
|
return(false);
|
|
}
|
|
|
|
packet_file_stamp = head.packet_file_stamp;
|
|
|
|
return(true);
|
|
}
|
|
|
|
void NewPacketFileReader::CloseFile() {
|
|
if(in != NULL) {
|
|
fclose(in);
|
|
in = NULL;
|
|
}
|
|
}
|
|
|
|
bool NewPacketFileReader::ResetFile() {
|
|
if(in == NULL)
|
|
return(false);
|
|
rewind(in);
|
|
|
|
//gotta read past the header again
|
|
PacketFileHeader head;
|
|
|
|
if(fread(&head, sizeof(head), 1, in) != 1) {
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool NewPacketFileReader::ReadPacket(uint16 &eq_op, uint32 &packlen, unsigned char *packet, bool &to_server, struct timeval &tv) {
|
|
if(in == NULL)
|
|
return(false);
|
|
if(feof(in))
|
|
return(false);
|
|
|
|
PacketFileSection s;
|
|
|
|
if(fread(&s, sizeof(s), 1, in) != 1) {
|
|
if(!feof(in))
|
|
fprintf(stderr, "Error reading section header: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
eq_op = s.opcode;
|
|
|
|
if(packlen < s.len) {
|
|
fprintf(stderr, "Packet buffer is too small! %d < %d, skipping\n", packlen, s.len);
|
|
fseek(in, s.len, SEEK_CUR);
|
|
return(false);
|
|
}
|
|
|
|
if(fread(packet, 1, s.len, in) != s.len) {
|
|
if(feof(in))
|
|
fprintf(stderr, "Error: EOF encountered when expecting packet data.\n");
|
|
else
|
|
fprintf(stderr, "Error reading packet body: %s\n", strerror(errno));
|
|
return(false);
|
|
}
|
|
|
|
packlen = s.len;
|
|
to_server = IsToServer(s);
|
|
tv.tv_sec = s.tv_sec;
|
|
tv.tv_usec = 1000*s.tv_msec;
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|