quakeforge/qw/source/net_packetlog.c
Bill Currie 6d5ffa9f8e [build] Move to non-recursive make
There's still some cleanup to do, but everything seems to be working
nicely: `make -j` works, `make distcheck` passes. There is probably
plenty of bitrot in the package directories (RPM, debian), though.

The vc project files have been removed since those versions are way out
of date and quakeforge is pretty much dependent on gcc now anyway.

Most of the old Makefile.am files  are now Makemodule.am.  This should
allow for new Makefile.am files that allow local building (to be added
on an as-needed bases).  The current remaining Makefile.am files are for
standalone sub-projects.a

The installable bins are currently built in the top-level build
directory. This may change if the clutter gets to be too much.

While this does make a noticeable difference in build times, the main
reason for the switch was to take care of the growing dependency issues:
now it's possible to build tools for code generation (eg, using qfcc and
ruamoko programs for code-gen).
2020-06-25 11:35:37 +09:00

1018 lines
27 KiB
C

/*
net_packetlog.c
packet logging/parsing - for debugging and educational purposes
**EXPERIMENTAL**
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
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <ctype.h>
#include <stdarg.h>
#include "QF/cmd.h"
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "compat.h"
#include "netchan.h"
#include "qw/protocol.h"
#include "qw/include/server.h"
cvar_t *net_packetlog;
cvar_t *net_loglevel;
// note: this is SUPPOSED to be duplicate, like many others
const 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"
};
const 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
static QFile *_stdout;
static QFile *Net_PacketLog;
static const char **Net_sound_precache;
static sizebuf_t _packet;
static qmsg_t packet = {0, 0, &_packet};
static int
Net_LogStart (const char *fname)
{
Sys_Printf ("Opening packet logfile: %s\n", fname);
Net_PacketLog = QFS_Open (fname, "at");
if (!Net_PacketLog)
return -1;
return 0;
}
void
Net_LogStop (void *data)
{
if (Net_PacketLog)
Qclose (Net_PacketLog);
Net_PacketLog = NULL;
}
static 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;
}
}
/*
static 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 (const byte *p, int len, int has_sequence, int is_server)
{
if (!net_loglevel->int_val)
return;
if (is_server) {
Net_LogPrintf ("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: "
"<<<<<<<<<<<<<<<<<<<<<<<<\n", len);
if (net_loglevel->int_val != 3)
hex_dump_buf ((unsigned char *) p, len);
if (net_loglevel->int_val > 1)
Analyze_Client_Packet (p, len, has_sequence);
} else {
Net_LogPrintf ("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: "
">>>>>>>>>>>>>>>>>>>>>>>>\n", len);
if (net_loglevel->int_val != 3)
hex_dump_buf ((unsigned char *) p, len);
if (net_loglevel->int_val > 1)
Analyze_Server_Packet (p, len, has_sequence);
}
return;
}
void
Log_Outgoing_Packet (const byte *p, int len, int has_sequence, int is_server)
{
if (!net_loglevel->int_val)
return;
if (is_server) {
Net_LogPrintf ("\n>>>>>>>>>>>>>>>>>>>>> server to client %d bytes: "
">>>>>>>>>>>>>>>>>>>>>>>>\n", len);
if (net_loglevel->int_val != 3)
hex_dump_buf ((unsigned char *) p, len);
if (net_loglevel->int_val > 1)
Analyze_Server_Packet (p, len, has_sequence);
} else {
Net_LogPrintf ("\n<<<<<<<<<<<<<<<<<<<<< client to server %d bytes: "
"<<<<<<<<<<<<<<<<<<<<<<<<\n", len);
if (net_loglevel->int_val != 3)
hex_dump_buf ((unsigned char *) p, len);
if (net_loglevel->int_val > 1)
Analyze_Client_Packet (p, len, has_sequence);
}
return;
}
static void
Log_Delta (int bits)
{
entity_state_t to;
int i;
// set everything to the state we are delta'ing from
to.number = bits & 511;
to.frame = 0;
to.effects = 0;
bits &= ~511;
if (bits & U_MOREBITS) { // read in the low order bits
i = MSG_ReadByte (&packet);
bits |= i;
}
// LordHavoc: Endy neglected to mark this as being part of the QSG
// version 2 stuff...
if (bits & U_EXTEND1) {
bits |= MSG_ReadByte (&packet) << 16;
if (bits & U_EXTEND2)
bits |= MSG_ReadByte (&packet) << 24;
}
to.flags = bits;
if (bits & U_MODEL)
Net_LogPrintf (" MdlIdx: %d", MSG_ReadByte (&packet));
if (bits & U_FRAME) {
to.frame = MSG_ReadByte (&packet);
Net_LogPrintf (" Frame: %d", to.frame);
}
if (bits & U_COLORMAP)
Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet));
if (bits & U_SKIN)
Net_LogPrintf (" Skinnum: %d", MSG_ReadByte (&packet));
if (bits & U_EFFECTS) {
to.effects = MSG_ReadByte (&packet);
Net_LogPrintf (" Effects: %d", to.effects);
}
if (bits & U_ORIGIN1)
Net_LogPrintf (" X: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE1)
Net_LogPrintf (" Pitch: %f", MSG_ReadAngle (&packet));
if (bits & U_ORIGIN2)
Net_LogPrintf (" Y: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE2)
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle (&packet));
if (bits & U_ORIGIN3)
Net_LogPrintf (" Z: %f", MSG_ReadCoord (&packet));
if (bits & U_ANGLE3)
Net_LogPrintf (" Roll: %f", MSG_ReadAngle (&packet));
// Ender (QSG - Begin)
if (bits & U_ALPHA)
Net_LogPrintf (" Alpha: %d", MSG_ReadByte (&packet));
if (bits & U_SCALE)
Net_LogPrintf (" Scale: %d", MSG_ReadByte (&packet));
if (bits & U_EFFECTS2)
Net_LogPrintf (" U_EFFECTS2: %d", (to.effects & 0xFF) |
(MSG_ReadByte (&packet) << 8));
if (bits & U_GLOWSIZE)
Net_LogPrintf (" GlowSize: %d", MSG_ReadByte (&packet));
if (bits & U_GLOWCOLOR)
Net_LogPrintf (" ColorGlow: %d", MSG_ReadByte (&packet));
if (bits & U_COLORMOD)
Net_LogPrintf (" Colormod: %d", MSG_ReadByte (&packet));
if (bits & U_FRAME2)
Net_LogPrintf (" Uframe2: %d", ((to.frame & 0xFF) |
(MSG_ReadByte (&packet) << 8)));
// Ender (QSG - End)
return;
}
static void
Parse_Server_Packet (int has_sequence)
{
const char *s;
int c = 0, i, ii, iii, mask1, mask2;
long seq1 = 0, seq2;
if (has_sequence) {
seq1 = MSG_ReadLong (&packet);
if (packet.badread)
return;
}
if (seq1 == -1) {
Net_LogPrintf ("Special Packet");
} else {
if (has_sequence) {
seq2 = MSG_ReadLong (&packet);
// 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 (packet.badread) {
Net_LogPrintf ("*** BAD READ *** %s", svc_string[c]);
break;
}
c = MSG_ReadByte (&packet);
if (c == -1)
break;
Net_LogPrintf ("<%06x> [0x%02x] ", MSG_GetReadCount (&packet), c);
if (c < 53)
Net_LogPrintf ("%s: ", svc_string[c]);
if (MSG_GetReadCount (&packet) > packet.message->cursize)
return;
switch (c) {
case svc_bad:
Net_LogPrintf (" - should not happen");
break;
case svc_nop:
Net_LogPrintf (" No operation");
break;
case svc_disconnect:
Net_LogPrintf (" <Quit>");
break;
case svc_updatestat:
i = MSG_ReadByte (&packet);
Net_LogPrintf (" index: %d value: %d", i, MSG_ReadByte
(&packet));
break;
case svc_version:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_setview:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_sound:
i = MSG_ReadShort (&packet);
Net_LogPrintf (": (%d) ", i);
if (i & SND_VOLUME)
Net_LogPrintf ("Volume %d ", MSG_ReadByte (&packet));
if (i & SND_ATTENUATION)
Net_LogPrintf ("Ann: %f",
(float) MSG_ReadByte (&packet) / 64.0);
ii = MSG_ReadByte (&packet);
Net_LogPrintf ("%d (%s) ", ii, Net_sound_precache[ii]);
Net_LogPrintf ("Pos: ");
for (ii = 0; ii < 3; ii++)
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
Net_LogPrintf ("Ent: %d ", (i >> 3) & 1023);
Net_LogPrintf ("Channel %d ", i & 7);
break;
case svc_time:
Net_LogPrintf ("**QW OBSOLETE**\n");
break;
case svc_print:
// FIXME: i==PRINT_CHAT
Net_LogPrintf ("[%d] ", MSG_ReadByte (&packet));
Net_LogPrintf ("%s", MSG_ReadString (&packet));
break;
case svc_stufftext:
Net_LogPrintf ("%s", MSG_ReadString (&packet));
break;
case svc_setangle:
for (i = 0; i < 3; i++)
Net_LogPrintf ("%f ", MSG_ReadAngle (&packet));
break;
case svc_serverdata:
Net_LogPrintf ("Ver: %d", MSG_ReadLong (&packet));
Net_LogPrintf (" Client ID: %d", MSG_ReadLong (&packet));
Net_LogPrintf (" Dir: %s", MSG_ReadString (&packet));
Net_LogPrintf (" User ID: %d", MSG_ReadByte (&packet));
Net_LogPrintf (" Map: %s", MSG_ReadString (&packet));
for (i = 0; i < 10; i++)
MSG_ReadFloat (&packet);
break;
case svc_lightstyle:
i = MSG_ReadByte (&packet);
if (i >= MAX_LIGHTSTYLES)
return;
Net_LogPrintf ("%d %s", i, MSG_ReadString (&packet));
break;
case svc_updatename:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_updatefrags:
Net_LogPrintf ("player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("frags: %d",
(short) MSG_ReadShort (&packet));
break;
case svc_clientdata:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_stopsound:
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
break;
case svc_updatecolors:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_particle:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_damage:
// FIXME: parse damage
Net_LogPrintf ("armor: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("health: %d from", MSG_ReadByte (&packet));
for (i = 0; i < 3; i++)
Net_LogPrintf ("%f%s", MSG_ReadCoord (&packet),
i < 2 ? "," : "");
break;
case svc_spawnstatic:
Net_LogPrintf ("Model: %d", MSG_ReadByte (&packet));
Net_LogPrintf (" Frame: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Color: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Skin: %d", MSG_ReadByte (&packet));
for (i = 0; i < 3; i++) {
Net_LogPrintf ("%d: %f ", i + 1,
MSG_ReadCoord (&packet));
Net_LogPrintf ("%f", MSG_ReadAngle (&packet));
}
break;
case svc_spawnbinary:
Net_LogPrintf ("**OBSOLETE**");
break;
case svc_spawnbaseline:
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
Net_LogPrintf (" idx: %d", MSG_ReadByte (&packet));
Net_LogPrintf (" Frame: %d", MSG_ReadByte (&packet));
Net_LogPrintf (" Colormap: %d", MSG_ReadByte (&packet));
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
for (i = 0; i < 3; i++) {
Net_LogPrintf (" %f", MSG_ReadCoord (&packet));
Net_LogPrintf (" %f", MSG_ReadAngle (&packet));
};
break;
case svc_temp_entity:
i = MSG_ReadByte (&packet);
switch (i) {
case 0:
case 1:
case 3:
case 4:
case 7:
case 8:
case 10:
case 11:
case 13:
Net_LogPrintf (" origin");
for (i = 0; i < 3; i++)
Net_LogPrintf (" %f", MSG_ReadCoord (&packet));
break;
case 5:
case 6:
case 9:
Net_LogPrintf (" created by %d",
MSG_ReadShort (&packet));
Net_LogPrintf (" origin:");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
Net_LogPrintf (" trace endpos:");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
break;
case 2:
case 12:
Net_LogPrintf (" count: %d", MSG_ReadByte
(&packet));
Net_LogPrintf (" origin:");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
break;
default:
Net_LogPrintf (" unknown value %d for tempentity",
i);
break;
}
break;
case svc_setpause:
Net_LogPrintf (" %d", MSG_ReadByte (&packet));
break;
case svc_signonnum:
Net_LogPrintf ("**QW OBSOLETE**");
break;
case svc_centerprint:
Net_LogPrintf ("%s\n", MSG_ReadString (&packet));
break;
case svc_killedmonster:
break;
case svc_foundsecret:
break;
case svc_spawnstaticsound:
Net_LogPrintf ("pos");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
for (i = 0; i < 3; i++)
Net_LogPrintf (" %d", MSG_ReadByte (&packet));
break;
case svc_intermission:
for (i = 0; i < 3; i++)
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
Net_LogPrintf ("\n");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%f ", MSG_ReadAngle (&packet));
break;
case svc_finale:
Net_LogPrintf ("%s", MSG_ReadString (&packet));
break;
case svc_cdtrack:
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
break;
case svc_sellscreen:
break;
case svc_smallkick:
break;
case svc_bigkick:
break;
case svc_updateping:
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Ping: %d", MSG_ReadShort (&packet));
break;
case svc_updateentertime:
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Time: %f", MSG_ReadFloat (&packet));
break;
case svc_updatestatlong:
i = MSG_ReadByte (&packet);
Net_LogPrintf ("%d value: %d", i, MSG_ReadLong (&packet));
break;
case svc_muzzleflash:
Net_LogPrintf ("%d", MSG_ReadShort (&packet));
break;
case svc_updateuserinfo:
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("ID: %d ", MSG_ReadLong (&packet));
Net_LogPrintf ("Info: %s", MSG_ReadString (&packet));
break;
case svc_download:
ii = MSG_ReadShort (&packet);
Net_LogPrintf ("%d bytes at %d", ii, MSG_ReadByte
(&packet));
for (i = 0; i < ii; i++)
MSG_ReadByte (&packet);
break;
case svc_playerinfo:
Net_LogPrintf ("\n\tPlayer: %d", MSG_ReadByte (&packet));
mask1 = MSG_ReadShort (&packet);
Net_LogPrintf (" Mask1: %d", mask1);
#if 1
Net_LogPrintf (" Origin:");
for (i = 0; i < 3; i++)
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
#endif
Net_LogPrintf (" Frame: %d", MSG_ReadByte (&packet));
#if 1
if (mask1 & PF_MSEC)
Net_LogPrintf (" Ping: %d", MSG_ReadByte (&packet));
if (mask1 & PF_COMMAND) {
mask2 = MSG_ReadByte (&packet); // command
if (mask2 & 0x01)
Net_LogPrintf (" Pitch: %f", MSG_ReadAngle16
(&packet));
if (mask2 & 0x80)
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle16
(&packet));
if (mask2 & 0x02)
Net_LogPrintf (" Roll: %f", MSG_ReadAngle16
(&packet));
if (mask2 & 0x04)
Net_LogPrintf (" Speed1: %d",
MSG_ReadShort (&packet));
if (mask2 & 0x08)
Net_LogPrintf (" Speed2: %d",
MSG_ReadShort (&packet));
if (mask2 & 0x10)
Net_LogPrintf (" Speed3: %d",
MSG_ReadShort (&packet));
if (mask2 & 0x20)
Net_LogPrintf (" Flag: %d", MSG_ReadByte
(&packet));
if (mask2 & 0x40)
Net_LogPrintf (" Impulse: %d", MSG_ReadByte
(&packet));
Net_LogPrintf (" Msec: %d", MSG_ReadByte (&packet));
}
if (mask1 & PF_VELOCITY1)
Net_LogPrintf (" Xspd: %f", MSG_ReadCoord (&packet));
if (mask1 & PF_VELOCITY2)
Net_LogPrintf (" Yspd: %f", MSG_ReadCoord (&packet));
if (mask1 & PF_VELOCITY3)
Net_LogPrintf (" ZSpd: %f", MSG_ReadCoord (&packet));
if (mask1 & PF_MODEL)
Net_LogPrintf (" Model: %d", MSG_ReadByte (&packet));
if (mask1 & PF_SKINNUM)
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
if (mask1 & PF_EFFECTS)
Net_LogPrintf (" Effects: %d", MSG_ReadByte (&packet));
if (mask1 & PF_WEAPONFRAME)
Net_LogPrintf (" Weapon frame: %d", MSG_ReadByte
(&packet));
#else
if (mask1 & (DF_ORIGIN | (DF_ORIGIN << 1)
| (DF_ORIGIN << 2))) {
Net_LogPrintf (" Origin:");
for (i = 0; i < 3; i++)
if (mask1 & (DF_ORIGIN << i))
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadCoord (&packet));
else
Net_LogPrintf ("%c", i ? ',' : ' ');
}
if (mask1 & (DF_ANGLES | (DF_ANGLES << 1)
| (DF_ANGLES << 2))) {
Net_LogPrintf (" Angles:");
for (i = 0; i < 3; i++)
if (mask1 & (DF_ANGLES << i))
Net_LogPrintf ("%c%f", i ? ',' : ' ',
MSG_ReadAngle16 (&packet));
else
Net_LogPrintf ("%c", i ? ',' : ' ');
}
if (mask1 & DF_MODEL)
Net_LogPrintf (" Model: %d", MSG_ReadByte (&packet));
if (mask1 & DF_SKINNUM)
Net_LogPrintf (" Skin: %d", MSG_ReadByte (&packet));
if (mask1 & DF_EFFECTS)
Net_LogPrintf (" Effects: %d", MSG_ReadByte (&packet));
if (mask1 & DF_WEAPONFRAME)
Net_LogPrintf (" Weapon frame: %d", MSG_ReadByte
(&packet));
#endif
break;
case svc_nails:
ii = MSG_ReadByte (&packet);
Net_LogPrintf (" %d (bits not parsed)", ii);
for (i = 0; i < ii; i++) {
for (iii = 0; iii < 6; iii++)
MSG_ReadByte (&packet);
}
break;
case svc_chokecount:
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
break;
case svc_modellist:
ii = MSG_ReadByte (&packet);
Net_LogPrintf ("start %d", ii);
for (i = ii; i < 256; i++) {
s = MSG_ReadString (&packet);
if (packet.badread)
break;
if (!s)
break;
if (strlen (s) == 0)
break;
Net_LogPrintf ("\n\tModel %d: %s", i, s);
}
i = MSG_ReadByte (&packet);
if (i)
Net_LogPrintf ("\n\tnext at %d", i);
else
Net_LogPrintf ("\n\t*End of modellist*");
break;
case svc_soundlist:
ii = MSG_ReadByte (&packet);
Net_LogPrintf ("start %d", ii);
for (i = ii; i < 256; i++) {
s = MSG_ReadString (&packet);
if (packet.badread)
break;
if (!s)
break;
if (strlen (s) == 0)
break;
Net_LogPrintf ("\n\tSound %d: %s", i, s);
}
i = MSG_ReadByte (&packet);
if (i)
Net_LogPrintf ("\n\tnext at %d", i);
else
Net_LogPrintf ("\n\t*End of sound list*");
break;
case svc_packetentities:
packetentities:
while (1) {
mask1 = MSG_ReadShort (&packet);
if (packet.badread) {
Net_LogPrintf ("Badread\n");
return;
}
if (!mask1)
break;
Net_LogPrintf ("%d", mask1 & 511);
if (mask1 & U_REMOVE)
Net_LogPrintf (" UREMOVE");
Log_Delta (mask1);
Net_LogPrintf ("\n");
}
break;
case svc_deltapacketentities:
Net_LogPrintf ("idx: %d\n", MSG_ReadByte (&packet));
goto packetentities;
break;
case svc_maxspeed:
Net_LogPrintf ("%f", MSG_ReadFloat (&packet));
break;
case svc_entgravity:
Net_LogPrintf ("%f", MSG_ReadFloat (&packet));
break;
case svc_setinfo:
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Keyname: %s ", MSG_ReadString (&packet));
Net_LogPrintf ("Value: %s", MSG_ReadString (&packet));
break;
case svc_serverinfo:
Net_LogPrintf ("Name: %s ", MSG_ReadString (&packet));
Net_LogPrintf ("Value: %s", MSG_ReadString (&packet));
break;
case svc_updatepl:
Net_LogPrintf ("Player: %d ", MSG_ReadByte (&packet));
Net_LogPrintf ("Ploss: %d", MSG_ReadByte (&packet));
break;
default:
Net_LogPrintf ("**UNKNOWN**: [%d]", c);
break;
}
Net_LogPrintf ("\n");
}
}
}
void
Analyze_Server_Packet (const byte * data, int len, int has_sequence)
{
if (!Net_PacketLog)
Net_PacketLog = _stdout;
packet.message->data = (byte*)data;
packet.message->cursize = len;
MSG_BeginReading (&packet);
Parse_Server_Packet (has_sequence);
if (Net_PacketLog == _stdout)
Net_PacketLog = NULL;
}
static void
Parse_Client_Packet (int has_sequence)
{
int mask, i, c, ii;
long seq1 = 0, seq2;
if (has_sequence)
seq1 = MSG_ReadLong (&packet);
if (seq1 == -1) {
Net_LogPrintf ("Special: %s\n", MSG_ReadString (&packet));
return;
} else {
if (has_sequence) {
// FIXME: display seqs right when reliable
seq2 = MSG_ReadLong (&packet);
Net_LogPrintf ("\nSeq: %ld Ack: %ld ", seq1 & 0x7FFFFFFF,
seq2 & 0x7FFFFFFF);
Net_LogPrintf ("QP: %u\n", MSG_ReadShort (&packet) & 0xFFFF);
}
while (1) {
if (packet.badread)
break;
c = MSG_ReadByte (&packet);
if (c == -1)
break;
Net_LogPrintf ("\n<%06x> [0x%02x] ", MSG_GetReadCount (&packet),
c);
if (c < 8)
Net_LogPrintf ("%s: ", clc_string[c]);
switch (c) {
case clc_nop:
break;
case clc_delta:
Net_LogPrintf ("%d", MSG_ReadByte (&packet));
break;
case clc_move:
Net_LogPrintf ("checksum = %02x ", MSG_ReadByte (&packet));
Net_LogPrintf ("PacketLoss: %d", MSG_ReadByte (&packet));
for (i = 0; i < 3; i++) {
mask = MSG_ReadByte (&packet);
Net_LogPrintf ("\n\t(%d) mask = %02x", i, mask);
if (mask & 0x01)
Net_LogPrintf (" Tilt: %f", MSG_ReadAngle16
(&packet));
if (mask & 0x80)
Net_LogPrintf (" Yaw: %f", MSG_ReadAngle16
(&packet));
if (mask & 0x02)
Net_LogPrintf (" Roll: %f", MSG_ReadAngle16
(&packet));
if (mask & 0x04)
Net_LogPrintf (" Fwd: %d",
MSG_ReadShort (&packet));
if (mask & 0x08)
Net_LogPrintf (" Right: %d",
MSG_ReadShort (&packet));
if (mask & 0x10)
Net_LogPrintf (" Up: %d",
MSG_ReadShort (&packet));
if (mask & 0x20)
Net_LogPrintf (" Flags: %d", MSG_ReadByte
(&packet));
if (mask & 0x40)
Net_LogPrintf (" Impulse: %d", MSG_ReadByte
(&packet));
Net_LogPrintf (" Msec: %d", MSG_ReadByte (&packet));
}
break;
case clc_stringcmd:
Net_LogPrintf ("%s", MSG_ReadString (&packet));
break;
case clc_tmove:
for (i = 0; i < 3; i++)
Net_LogPrintf ("%f ", MSG_ReadCoord (&packet));
break;
case clc_upload:
ii = MSG_ReadShort (&packet);
Net_LogPrintf ("%d bytes at %d", ii, MSG_ReadByte
(&packet));
for (i = 0; i < ii; i++)
MSG_ReadByte (&packet);
break;
default:
Net_LogPrintf ("**UNKNOWN**: [%d]", c);
break;
}
Net_LogPrintf ("\n");
}
}
}
void
Analyze_Client_Packet (const byte * data, int len, int has_sequence)
{
if (!Net_PacketLog)
Net_PacketLog = _stdout;
packet.message->data = (byte*)data;
packet.message->cursize = len;
MSG_BeginReading (&packet);
Parse_Client_Packet (has_sequence);
if (Net_PacketLog == _stdout)
Net_PacketLog = NULL;
}
static void
Net_PacketLog_f (cvar_t *var)
{
if (var->int_val) {
Net_LogStart ("qfpacket.log");
} else {
Net_LogStop (0);
}
}
static void
Net_PacketLog_Zap_f (void)
{
if (Net_PacketLog && Net_PacketLog != _stdout) {
Sys_Printf ("truncating packet logfile: %s\n", "qfpacket.log");
Qseek (Net_PacketLog, 0, 0);
Qwrite (Net_PacketLog, 0, 0);
} else {
Sys_Printf ("Deleting packet logfile: %s\n", "qfpacket.log");
QFS_Remove ("qfpacket.log");
}
}
int
Net_Log_Init (const char **sound_precache)
{
Net_sound_precache = sound_precache;
_stdout = Qdopen (1, "wt"); // create a QFile of stdout
net_packetlog = Cvar_Get ("net_packetlog", "0", CVAR_NONE, Net_PacketLog_f,
"enable/disable packet logging");
// 0 = no logging
// 1 = hex dump only
// 2 = parse/hexdump
// 3 = just parse
// 4 = parse/hexdump, skip movement/empty messages
net_loglevel = Cvar_Get ("net_loglevel", "2", CVAR_NONE, NULL,
"Packet logging/parsing");
Cmd_AddCommand ("net_packetlog_zap", Net_PacketLog_Zap_f,
"clear the packet log file");
return 0;
}
/*
NET_LogPrintf
Prints packet to logfile, adds time stamp etc.
*/
void
Net_LogPrintf (const char *fmt, ...)
{
char text[2048];
va_list argptr;
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);
}