From 62ec1ccdc0f506247548e269ed6e5e54ce9cd2ca Mon Sep 17 00:00:00 2001 From: Dabb Date: Mon, 11 Dec 2000 15:35:01 +0000 Subject: [PATCH] Packet logging support for debugging and educational purposes. Experimental. Note: All parts are not YET transferred from quakeforge tree. Missing detailed and nonconnection packet parsing. --- source/net_packetlog.c | 786 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 786 insertions(+) create mode 100644 source/net_packetlog.c diff --git a/source/net_packetlog.c b/source/net_packetlog.c new file mode 100644 index 0000000..d039675 --- /dev/null +++ b/source/net_packetlog.c @@ -0,0 +1,786 @@ +/* + net_packetlog.c + + packet logging/parsing - for debugging and educational purposes + + Copyright (C) 2000 Jukka Sorjonen + + This program 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 2 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +// fixme: we did support Quake1 protocol too... +#define QUAKEWORLD + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "qtypes.h" +#include "quakeio.h" +#include "net.h" +#include "protocol.h" +#include "msg.h" + +#include "server.h" + +cvar_t *netlogger; +cvar_t *netloglevel; + +extern server_t sv; +extern qboolean is_server(void); + +//extern sizebuf_t net_message; +extern byte net_message_buffer[MAX_MSGLEN*2]; + +void Analyze_Server_Packet(byte *data,int len); +void Analyze_Client_Packet(byte *data,int len); + +void Parse_Server_Packet(void); +void Parse_Client_Packet(void); + +int Net_LogStart(char *fname); +void Net_LogStop(void); + +// note: this is SUPPOSED to be duplicate, like many others +char *svc_string[] = +{ + "svc_bad", + "svc_nop", + "svc_disconnect", + "svc_updatestat", + "svc_version", // [long] server version + "svc_setview", // [short] entity number + "svc_sound", // + "svc_time", // [float] server time + "svc_print", // [string] null terminated string + "svc_stufftext", // [string] stuffed into client's console buffer + // the string should be \n terminated + "svc_setangle", // [vec3] set the view angle to this absolute value + + "svc_serverdata", // [long] version ... + "svc_lightstyle", // [byte] [string] + "svc_updatename", // [byte] [string] + "svc_updatefrags", // [byte] [short] + "svc_clientdata", // + "svc_stopsound", // + "svc_updatecolors", // [byte] [byte] + "svc_particle", // [vec3] + "svc_damage", // [byte] impact [byte] blood [vec3] from + + "svc_spawnstatic", + "svc_spawnbinary", + "svc_spawnbaseline", + + "svc_temp_entity", // + "svc_setpause", + "svc_signonnum", + "svc_centerprint", + "svc_killedmonster", + "svc_foundsecret", + "svc_spawnstaticsound", + "svc_intermission", + "svc_finale", // [string] music [string] text + "svc_cdtrack", // [byte] track [byte] looptrack + "svc_sellscreen", + + "svc_smallkick", // Quake svc_cutscene + "svc_bigkick", + + "svc_updateping", + "svc_updateentertime", + + "svc_updatestatlong", + "svc_muzzleflash", + "svc_updateuserinfo", + "svc_download", + "svc_playerinfo", + "svc_nails", + "svc_chokecount", + "svc_modellist", + "svc_soundlist", + "svc_packetentities", + "svc_deltapacketentities", + "svc_maxspeed", + "svc_entgravity", + + "svc_setinfo", + "svc_serverinfo", + "svc_updatepl", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL", + "NEW PROTOCOL" +}; + +char *clc_string[] = +{ + "clc_bad", + "clc_nop", + "clc_disconnect", + "clc_move", + "clc_stringcmd", + "clc_delta", + "clc_tmove", + "clc_upload" +}; + +#ifndef svc_spawnbinary +#define svc_spawnbinary 21 +#endif + +// Quake1, obsolete for QW +#define svc_time 7 // [float] server time +#define svc_updatename 13 // [byte] [string] +#define svc_version 4 // [long] server version +#define svc_clientdata 15 // +#define svc_updatecolors 17 // [byte] [byte] +#define svc_particle 18 // [vec3] +#define svc_signonnum 25 // [byte] used for the signon sequence + +QFile *Net_PacketLog; + +/* +================= +NET_LogPrintf + +Prints packet to logfile, adds time stamp etc. +================= +*/ + +void Net_LogPrintf (char *fmt, ...) +{ + va_list argptr; + char text[2048]; + + va_start(argptr, fmt); + vsnprintf(text, sizeof(text), fmt, argptr); + va_end(argptr); + if (!Net_PacketLog) return; + + Qprintf(Net_PacketLog,"%s",text); + Qflush(Net_PacketLog); +} + +int Net_LogStart(char *fname) +{ + Con_Printf("Opening packet logfile: %s\n",fname); + Net_PacketLog=Qopen(fname,"wt+"); + if(!Net_PacketLog) return -1; + return 0; +} + +void Net_LogStop(void) +{ + if (Net_PacketLog) Qclose(Net_PacketLog); + Net_PacketLog=NULL; +} + +void hex_dump_buf(unsigned char *buf, int len) +{ +int pos = 0, llen, i; + + while(pos < len) + { + llen = (len - pos < 16 ? len - pos : 16); + Net_LogPrintf("%08x: ", pos); + for(i = 0; i < llen; i++) Net_LogPrintf("%02x ", buf[pos + i]); + for(i = 0; i < 16 - llen; i++) Net_LogPrintf(" "); + Net_LogPrintf(" | "); + + for(i = 0; i < llen; i++) + Net_LogPrintf("%c", isprint(buf[pos + i]) ? buf[pos + i] : '.'); + for(i = 0; i < 16 - llen; i++) Net_LogPrintf(" "); + Net_LogPrintf("\n"); + pos += llen; + } +} + +void ascii_dump_buf(unsigned char *buf, int len) +{ +int pos = 0, llen, i; + + while(pos < len) + { + llen = (len - pos < 60 ? len - pos : 60); + Net_LogPrintf("%08x: ", pos); + for(i = 0; i < llen; i++) + Net_LogPrintf("%c", isprint(buf[pos + i]) ? buf[pos + i] : '.'); + Net_LogPrintf("\n"); + pos += llen; + } +} + +void Log_Incoming_Packet(char *p, int len) +{ + if (!netloglevel->int_val) return; + + if (is_server) { + Net_LogPrintf("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: <<<<<<<<<<<<<<<<<<<<<<<<\n", len); + if (netloglevel->int_val!=3) hex_dump_buf((unsigned char *)p,len); + if (netloglevel->int_val>1) Analyze_Client_Packet(p,len); + } + else { + Net_LogPrintf("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: >>>>>>>>>>>>>>>>>>>>>>>>\n", len); + if (netloglevel->int_val!=3) hex_dump_buf((unsigned char *)p,len);; + if (netloglevel->int_val>1) Analyze_Server_Packet(p,len); + } + return; +} + +void Log_Outgoing_Packet(char *p, int len) +{ + if (!netloglevel->int_val) return; + + if (is_server) { + Net_LogPrintf("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: >>>>>>>>>>>>>>>>>>>>>>>>\n", len); + if (netloglevel->int_val!=3) hex_dump_buf((unsigned char *)p,len);; + if (netloglevel->int_val>1) Analyze_Server_Packet(p,len); + } + else { + Net_LogPrintf("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: <<<<<<<<<<<<<<<<<<<<<<<<\n", len); + if (netloglevel->int_val!=3) hex_dump_buf((unsigned char *)p,len);; + if (netloglevel->int_val>1) Analyze_Client_Packet(p,len); + } + return; +} + + +void Analyze_Server_Packet(byte *data,int len) +{ + // Fixme: quick-hack + net_message.data=data; + net_message.cursize=len; + MSG_BeginReading(); + Parse_Server_Packet(); + net_message.data=net_message_buffer; +} + + +void Parse_Server_Packet() +{ + long seq1,seq2; + int c,i,ii,iii,mask1,mask2; + char *s; + + seq1 = MSG_ReadLong(); + if (msg_badread) return; + + if(seq1==-1) + { + Net_LogPrintf("Special Packet"); + + } else + { + seq2=MSG_ReadLong(); + //fixme display seqs right when reliable + Net_LogPrintf("\nSeq: %ld Ack: %ld ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF); + + if ((seq1 >>31) &0x01) Net_LogPrintf("SV_REL "); + if ((seq2 >>31) &0x01) Net_LogPrintf("SV_RELACK"); + Net_LogPrintf("\n"); + + while(1) + { + if (msg_badread) break; + c = MSG_ReadByte(); + if (c == -1) break; +// Net_LogPrintf("\n<%ld,%ld> ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF); + Net_LogPrintf("<%06x> [0x%02x] ",MSG_GetReadCount(),c); + + if (c<53) Net_LogPrintf("%s: ",svc_string[c]); +// else Net_LogPrintf("(UNK: %d): ",c); + + if (MSG_GetReadCount()>net_message.cursize) return; + + switch (c) + { + case svc_bad: + Net_LogPrintf(" - should not happen"); + case svc_nop: + Net_LogPrintf(" No operation"); + break; + case svc_disconnect: + Net_LogPrintf(" "); + break; + case svc_updatestat: + i=MSG_ReadByte(); + Net_LogPrintf(" index: %d value: %d",i,MSG_ReadByte ()); + break; + case svc_version: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#endif + break; + case svc_setview: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#else + MSG_ReadShort(); +#endif + break; + case svc_sound: + i = MSG_ReadShort (); + Net_LogPrintf(": (%d) ",i); + if (i & SND_VOLUME) Net_LogPrintf("Volume %d ", MSG_ReadByte()); + if (i & SND_ATTENUATION) Net_LogPrintf("Ann: %f", (float)MSG_ReadByte () / 64.0); + ii = MSG_ReadByte (); + + // fixme: well, cl. for client :-) + Net_LogPrintf("%d (%s) ",ii,sv.sound_precache[ii]); + + Net_LogPrintf("Pos: "); + for (ii = 0; ii < 3; ii++) + Net_LogPrintf("%f ",MSG_ReadCoord()); + Net_LogPrintf("Ent: %d ",(i >> 3) & 1023); + Net_LogPrintf("Channel %d ",i & 7); + break; + case svc_time: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**\n"); +#else + MSG_ReadFloat(); +#endif + break; + case svc_print: + // fixme i==PRINT_CHAT + Net_LogPrintf(" %d",MSG_ReadByte()); + Net_LogPrintf(" %s",MSG_ReadString()); + break; + case svc_stufftext: + Net_LogPrintf("%s",MSG_ReadString()); + break; + case svc_setangle: + for (i=0;i<3;i++) Net_LogPrintf("%f ",MSG_ReadAngle()); + break; +#ifdef QUAKEWORLD + case svc_serverdata: + Net_LogPrintf("Ver: %ld",MSG_ReadLong()); + Net_LogPrintf(" Client ID: %ld",MSG_ReadLong()); + Net_LogPrintf(" Dir: %s",MSG_ReadString()); + Net_LogPrintf(" User ID: %d",MSG_ReadByte()); + Net_LogPrintf(" Map: %s",MSG_ReadString()); + for(i=0;i<10;i++) MSG_ReadFloat(); + break; +#endif + + case svc_lightstyle: + i=MSG_ReadByte(); + if (i >= MAX_LIGHTSTYLES) return; + Net_LogPrintf("%d %s",i,MSG_ReadString()); + break; + case svc_updatename: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#else + Net_LogPrintf("%d %s",MSG_ReadByte(),MSG_ReadString()); +#endif + break; + case svc_updatefrags: + Net_LogPrintf("player: %d frags: %d",MSG_ReadByte(),MSG_ReadShort()); + break; + case svc_clientdata: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#endif + break; + case svc_stopsound: + Net_LogPrintf("%d",MSG_ReadShort()); + break; + + case svc_updatecolors: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#else + Net_LogPrintf("%d %d",MSG_ReadByte(),MSG_ReadByte()); +#endif + break; + case svc_particle: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#else + for (i=0;i<3;i++) Net_LogPrintf(" %f",MSG_ReadCoord()); + for (i=0;i<3;i++) Net_LogPrintf(" %d",MSG_ReadChar()); + Net_LogPrintf(" Count: %d",MSG_ReadByte()); + Net_LogPrintf(" Color: %d",MSG_ReadByte()); +#endif + break; + + case svc_damage: + // fixme parse damage + Net_LogPrintf("armor: %d health: %d",MSG_ReadByte(),MSG_ReadByte()); + Net_LogPrintf(" from %f,%f,%f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord()); + break; + case svc_spawnstatic: + Net_LogPrintf("%d",MSG_ReadByte()); + Net_LogPrintf(" Frame: %d Color: %d Skin: %",MSG_ReadByte(),MSG_ReadByte(),MSG_ReadByte()); + for(i = 0; i < 3; i++) Net_LogPrintf("%d: %f %f", i+1, MSG_ReadCoord(), MSG_ReadAngle()); + break; + case svc_spawnbinary: + Net_LogPrintf("**OBSOLETE**"); + break; + case svc_spawnbaseline: + Net_LogPrintf("%d",MSG_ReadShort()); + Net_LogPrintf(" idx: %d",MSG_ReadByte()); + Net_LogPrintf(" Frame: %d",MSG_ReadByte()); + Net_LogPrintf(" Colormap: %d",MSG_ReadByte()); + Net_LogPrintf(" Skin: %d",MSG_ReadByte()); + for (i=0;i<3;i++) { + Net_LogPrintf(" %f",MSG_ReadCoord()); + Net_LogPrintf(" %d",MSG_ReadAngle()); + }; + break; + case svc_temp_entity: + i=MSG_ReadByte(); + switch(i) + { + case 0: + case 1: + case 3: + case 4: + case 7: + case 8: + case 10: + case 11: + case 13: + Net_LogPrintf(" origin %f %f %f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord()); + break; + case 5: + case 6: + case 9: + Net_LogPrintf(" created by %d",MSG_ReadShort()); + Net_LogPrintf(" origin: %f,%f,%f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord()); + Net_LogPrintf(" trace endpos: %f,%f,%f", MSG_ReadCoord(), MSG_ReadCoord(), MSG_ReadCoord()); + break; + case 2: + case 12: + Net_LogPrintf(" count: %d",MSG_ReadByte()); + printf(" origin: %f,%f,%f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord()); + break; + default: + Net_LogPrintf(" unknown value %d for tempentity",i); + break; + } + break; + + case svc_setpause: + Net_LogPrintf(" %d",MSG_ReadByte ()); + break; + case svc_signonnum: +#ifdef QUAKEWORLD + Net_LogPrintf("**QW OBSOLETE**"); +#else + Net_LogPrintf("%d",MSG_ReadByte()); +#endif + break; + case svc_centerprint: + Net_LogPrintf(MSG_ReadString()); + break; + case svc_killedmonster: + break; + case svc_foundsecret: + break; + case svc_spawnstaticsound: + Net_LogPrintf("pos %f,%f,%f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord()); + Net_LogPrintf("%d %d %d",MSG_ReadByte(),MSG_ReadByte(),MSG_ReadByte()); + break; + case svc_intermission: + for (i=0 ; i<3 ; i++) Net_LogPrintf("%f ",MSG_ReadCoord()); + Net_LogPrintf("\n"); + for (i=0 ; i<3 ; i++) Net_LogPrintf("%f ",MSG_ReadAngle ()); + break; + case svc_finale: + Net_LogPrintf("%s",MSG_ReadString()); + break; + case svc_cdtrack: + Net_LogPrintf("%d",MSG_ReadByte()); + break; + case svc_sellscreen: + break; + case svc_smallkick: + break; + case svc_bigkick: + break; + case svc_updateping: + Net_LogPrintf("Player: %d ",MSG_ReadByte()); + Net_LogPrintf("Ping: %d",MSG_ReadShort()); + break; + case svc_updateentertime: + Net_LogPrintf("Player: %d ",MSG_ReadByte()); + Net_LogPrintf("Time: %f",MSG_ReadFloat()); + break; + + case svc_updatestatlong: + i=MSG_ReadByte(); + Net_LogPrintf("%d value: %ld",i,MSG_ReadLong()); + break; + + case svc_muzzleflash: + Net_LogPrintf("%d",MSG_ReadShort()); + break; + + case svc_updateuserinfo: + Net_LogPrintf("Player: %d ",MSG_ReadByte()); + Net_LogPrintf("ID: %ld ",MSG_ReadLong()); + Net_LogPrintf("Info: %s",MSG_ReadString()); + break; + case svc_download: + ii=MSG_ReadShort(); + Net_LogPrintf("%d bytes at %d",ii,MSG_ReadByte()); + for (i=0;i>31) &0x01) Net_LogPrintf("CL_REL "); + if ((seq2 >>31) &0x01) Net_LogPrintf("CL_RELACK "); +*/ + + Net_LogPrintf("QP: %u\n",MSG_ReadShort()); + + while (1) + { + if (msg_badread) break; + c = MSG_ReadByte(); + if (c == -1) break; +// Net_LogPrintf("<%ld,%ld> ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF); + Net_LogPrintf("\n<%06x> [0x%02x] ",MSG_GetReadCount(),c); + if (c<8) Net_LogPrintf("%s: ",clc_string[c]); + + switch(c) + { + case clc_nop: + break; + case clc_delta: + Net_LogPrintf ("%d",MSG_ReadByte()); + break; + case clc_move: + Net_LogPrintf("checksum = %02x ",MSG_ReadByte()); + Net_LogPrintf("PacketLoss: %d",MSG_ReadByte()); + + for (i=0;i<3;i++) { + mask=MSG_ReadByte(); + Net_LogPrintf("\n\t(%d) mask = %02x",i,mask); + if(mask & 0x01) Net_LogPrintf(" Tilt: %f",MSG_ReadAngle16()); + if(mask & 0x80) Net_LogPrintf(" Yaw: %f",MSG_ReadAngle16()); + if(mask & 0x02) Net_LogPrintf(" Roll: %f",MSG_ReadAngle16()); + if(mask & 0x04) Net_LogPrintf(" Fwd: %d",MSG_ReadShort()); + if(mask & 0x08) Net_LogPrintf(" Right: %d",MSG_ReadShort()); + if(mask & 0x10) Net_LogPrintf(" Up: %d",MSG_ReadShort()); + if(mask & 0x20) Net_LogPrintf(" Flags: %d",MSG_ReadByte()); + if(mask & 0x40) Net_LogPrintf(" Impulse: %d",MSG_ReadByte()); + Net_LogPrintf(" Msec: %d",MSG_ReadByte()); + } + break; + case clc_stringcmd: + Net_LogPrintf("%s",MSG_ReadString()); + break; + case clc_tmove: + for (i=0;i<3;i++) Net_LogPrintf("%f ",MSG_ReadCoord()); + break; + case clc_upload: + ii=MSG_ReadShort(); + Net_LogPrintf("%d bytes at %d",ii,MSG_ReadByte()); + for (i=0;i