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.
This commit is contained in:
Dabb 2000-12-11 15:35:01 +00:00
parent c3a0ab3aa1
commit 62ec1ccdc0
1 changed files with 786 additions and 0 deletions

786
source/net_packetlog.c Normal file
View File

@ -0,0 +1,786 @@
/*
net_packetlog.c
packet logging/parsing - for debugging and educational purposes
Copyright (C) 2000 Jukka Sorjonen <jukka.sorjonen@asikkala.fi>
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 <config.h>
#endif
#include <ctype.h>
#include <stdarg.h>
#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", // <see code>
"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", // <shortbits + data>
"svc_stopsound", // <see code>
"svc_updatecolors", // [byte] [byte]
"svc_particle", // [vec3] <variable>
"svc_damage", // [byte] impact [byte] blood [vec3] from
"svc_spawnstatic",
"svc_spawnbinary",
"svc_spawnbaseline",
"svc_temp_entity", // <variable>
"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 // <shortbits + data>
#define svc_updatecolors 17 // [byte] [byte]
#define svc_particle 18 // [vec3] <variable>
#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(" <Quit>");
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<ii;i++) MSG_ReadByte();
break;
case svc_playerinfo:
Net_LogPrintf("\n\tPlayer: %d",MSG_ReadByte());
mask1=MSG_ReadShort();
Net_LogPrintf(" Mask1: %d",mask1);
Net_LogPrintf(" Origin: %f,%f,%f",MSG_ReadCoord(),MSG_ReadCoord(),MSG_ReadCoord());
Net_LogPrintf(" Frame: %d",MSG_ReadByte());
if(mask1 & PF_MSEC) Net_LogPrintf(" Ping: %d",MSG_ReadByte());
if(mask1 & PF_COMMAND)
{
mask2 = MSG_ReadByte(); // command
if(mask2 & 0x01) Net_LogPrintf(" Pitch: %f", MSG_ReadAngle16());
if(mask2 & 0x80) Net_LogPrintf(" Yaw: %f", MSG_ReadAngle16());
if(mask2 & 0x02) Net_LogPrintf(" Roll: %f", MSG_ReadAngle16());
if(mask2 & 0x04) Net_LogPrintf(" Speed1: %d", MSG_ReadShort());
if(mask2 & 0x08) Net_LogPrintf(" Speed2: %d", MSG_ReadShort());
if(mask2 & 0x10) Net_LogPrintf(" Speed3: %d", MSG_ReadShort());
if(mask2 & 0x20) Net_LogPrintf(" Flag: %d", MSG_ReadByte());
if(mask2 & 0x40) Net_LogPrintf(" Impulse: %d", MSG_ReadByte());
Net_LogPrintf(" Msec: %d", MSG_ReadByte());
}
if(mask1 & PF_VELOCITY1) Net_LogPrintf(" Xspd: %f", MSG_ReadCoord());
if(mask1 & PF_VELOCITY2) Net_LogPrintf(" Yspd: %f", MSG_ReadCoord());
if(mask1 & PF_VELOCITY3) Net_LogPrintf(" ZSpd: %f", MSG_ReadCoord());
if(mask1 & PF_MODEL) Net_LogPrintf(" Model: %d", MSG_ReadByte());
if(mask1 & PF_SKINNUM) Net_LogPrintf(" Skin: %d", MSG_ReadByte());
if(mask1 & PF_EFFECTS) Net_LogPrintf(" Effects: %d", MSG_ReadByte());
if(mask1 & PF_WEAPONFRAME) Net_LogPrintf(" Weapon frame: %d", MSG_ReadByte());
break;
case svc_nails:
ii=MSG_ReadByte();
Net_LogPrintf(" %d (bits not parsed)",ii);
for(i=0;i<ii;i++) {
for (iii=0;iii<6;iii++) MSG_ReadByte();
}
break;
case svc_chokecount:
Net_LogPrintf("%d",MSG_ReadByte());
break;
case svc_modellist:
ii=MSG_ReadByte();
Net_LogPrintf("start %d",ii);
for(i=ii;i<256;i++) {
s=MSG_ReadString();
if (msg_badread) break;
if (!s) break;
if (strlen(s)==0) break;
Net_LogPrintf("\n\tModel %d: %s",i,s);
}
i=MSG_ReadByte();
if (i) Net_LogPrintf("\n\tnext at %d",i);
else Net_LogPrintf("\n\t*End of modellist*");
break;
case svc_soundlist:
ii=MSG_ReadByte();
Net_LogPrintf("start %d",ii);
for(i=ii;i<256;i++) {
s=MSG_ReadString();
if (msg_badread) break;
if (!s) break;
if (strlen(s)==0) break;
Net_LogPrintf("\n\tSound %d: %s",i,s);
}
i=MSG_ReadByte();
if (i) Net_LogPrintf("\n\tnext at %d",i);
else Net_LogPrintf("\n\t*End of sound list*");
break;
case svc_packetentities:
Net_LogPrintf("Not parsed (parser broken ;-)");
return;
while ((mask1=MSG_ReadShort()))
{
if (msg_badread) break;
Net_LogPrintf("\n\t");
if(mask1 & 0x8000) mask1|=MSG_ReadByte();
if(mask1 & U_MODEL) Net_LogPrintf(" Mdl: %d",MSG_ReadByte());
if(mask1 & U_FRAME) Net_LogPrintf(" Frame: %d",MSG_ReadByte());
if(mask1 & U_COLORMAP) Net_LogPrintf(" Colormap:%d",MSG_ReadByte());
if(mask1 & U_SKIN) Net_LogPrintf(" Skin: %d",MSG_ReadByte());
if(mask1 & U_EFFECTS) Net_LogPrintf(" Effects: %d",MSG_ReadByte());
if(mask1 & U_ORIGIN1) Net_LogPrintf(" X: %f",MSG_ReadCoord());
if(mask1 & U_ANGLE1) Net_LogPrintf(" Pitch: %d",MSG_ReadAngle());
if(mask1 & U_ORIGIN2) Net_LogPrintf(" Y: %f",MSG_ReadCoord());
if(mask1 & U_ANGLE2) Net_LogPrintf(" Yaw: %d",MSG_ReadAngle());
if(mask1 & U_ORIGIN3) Net_LogPrintf(" Z: %f",MSG_ReadCoord());
if(mask1 & U_ANGLE3) Net_LogPrintf(" Roll: %d",MSG_ReadAngle());
// if(mask1 & U_SOLID) return;
}
break;
case svc_deltapacketentities:
Net_LogPrintf("idx: %d",MSG_ReadByte());
return;
// break;
case svc_maxspeed :
Net_LogPrintf("%f",MSG_ReadFloat());
break;
case svc_entgravity :
Net_LogPrintf("%f",MSG_ReadFloat());
break;
case svc_setinfo:
Net_LogPrintf("Player: %d ",MSG_ReadByte());
Net_LogPrintf("Keyname: %s ",MSG_ReadString());
Net_LogPrintf("Value: %s",MSG_ReadString());
break;
case svc_serverinfo:
Net_LogPrintf("Name: %s Value: %s",MSG_ReadString(),MSG_ReadString());
break;
case svc_updatepl:
Net_LogPrintf("Player: %d Ploss: %d",MSG_ReadByte(),MSG_ReadByte());
break;
default:
Net_LogPrintf ("**UNKNOWN**: [%d]",c);
break;
}
Net_LogPrintf("\n");
}
}
}
void Analyze_Client_Packet(byte *data,int len)
{
// fixme quick-hack
net_message.data=data;
net_message.cursize=len;
MSG_BeginReading();
Parse_Client_Packet();
net_message.data=net_message_buffer;
}
void Parse_Client_Packet(void)
{
int i,c,ii;
long seq1,seq2;
int mask;
seq1 = MSG_ReadLong();
if(seq1==-1)
{
Net_LogPrintf("Special: %s\n",MSG_ReadString());
return;
} else
{
//fixme display seqs right when reliable
seq2 = MSG_ReadLong();
Net_LogPrintf("\nSeq: %ld Ack: %ld ",seq1 & 0x7FFFFFFF,seq2 & 0x7FFFFFFF);
/*
if ((seq1 >>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<ii;i++) MSG_ReadByte();
break;
default:
Net_LogPrintf ("**UNKNOWN**: [%d]",c);
break;
}
Net_LogPrintf("\n");
}
}
}
int Net_Log_Init(void)
{
netlogger=Cvar_Get("net_logger","1",CVAR_NONE,"Packet logging/parsing");
// 0 = no logging
// 1 = hex dump only
// 2 = parse/hexdump
// 3 = just parse
// 4 = parse/hexdump, skip movement/empty messages
netloglevel=Cvar_Get("net_loglevel","2",CVAR_NONE,"Packet logging/parsing");
Net_LogStart("QFPACKET.LOG");
return 0;
}