eqemu-server/common/packetfile.cpp
2013-05-22 16:17:19 -04:00

443 lines
9.4 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();
//printf("Opening packet file: %s\n", name);
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;
//printf("Closed packet file.\n");
}
}
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();
//printf("Opening packet file: %s\n", name);
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;
//printf("Closed packet file.\n");
}
}
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);
}