Add network profiling tool from Spearhead and Breakthrough

Profiling can be enabled with `cl_netprofile` and `sv_netprofile`, the overlay can be shown using `cl_netprofileoverlay` and `sv_netprofileoverlay` and the server can dump network profile using the `netprofiledump` command
This commit is contained in:
smallmodel 2024-11-09 21:15:49 +01:00
parent 23a035e2ca
commit 1ef1bad9ae
No known key found for this signature in database
GPG key ID: 9F2D623CEDF08512
14 changed files with 871 additions and 66 deletions

View file

@ -192,7 +192,9 @@ typedef struct client_s {
int snapshotMsec; // requests a snapshot every snapshotMsec unless rate choked
int pureAuthentic;
qboolean gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, and no cp command at all
netchan_t netchan;
netchan_t netchan;
// Added in 2.0
netprofclient_t netprofile;
// TTimo
// queuing outgoing fragmented messages to send them properly, without udp packet bursts
// in case large fragmented messages are stacking up
@ -319,6 +321,8 @@ typedef struct {
#ifndef DEDICATED
soundsystemsavegame_t soundSystem;
#endif
// Added in 2.0
netprofclient_t netprofile;
} serverStatic_t;
#define SERVER_MAXBANS 1024
@ -621,6 +625,10 @@ void SV_Netchan_Transmit( client_t *client, msg_t *msg);
int SV_Netchan_TransmitNextFragment( client_t *client );
qboolean SV_Netchan_Process( client_t *client, msg_t *msg );
void SV_Netchan_FreeQueue(client_t *client);
void SV_NET_OutOfBandPrint(netprofclient_t* netprof, netadr_t adr, const char* format, ...);
void SV_NET_UpdateClientNetProfileInfo(netprofclient_t* netprofile, int rate);
void SV_NET_UpdateAllNetProfileInfo();
void SV_NET_CalcTotalNetProfile(netprofclient_t* netprofile, qboolean server);
//
// sv_gamespy.c

View file

@ -502,7 +502,7 @@ static void SV_Ban_f( void ) {
// otherwise send their ip to the authorize server
if ( svs.authorizeAddress.type != NA_BAD ) {
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
SV_NET_OutOfBandPrint( &svs.netprofile, svs.authorizeAddress,
"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
Com_Printf("%s was banned from coming back\n", cl->name);
@ -556,7 +556,7 @@ static void SV_BanNum_f( void ) {
// otherwise send their ip to the authorize server
if ( svs.authorizeAddress.type != NA_BAD ) {
NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress,
SV_NET_OutOfBandPrint( &svs.netprofile, svs.authorizeAddress,
"banUser %i.%i.%i.%i", cl->netchan.remoteAddress.ip[0], cl->netchan.remoteAddress.ip[1],
cl->netchan.remoteAddress.ip[2], cl->netchan.remoteAddress.ip[3] );
Com_Printf("%s was banned from coming back\n", cl->name);
@ -1573,6 +1573,120 @@ void SV_LoadLastGame_f( void )
Cbuf_AddText( va( "loadgame %s\n", Cvar_Get( "g_lastsave", "", 0 )->string ) );
}
/*
=================
SV_NetProfileDump_PrintProf
=================
*/
void SV_NetProfileDump_PrintProf(fileHandle_t file, netprofclient_t* netprofile)
{
size_t totalProcessed;
char buffer[2048];
totalProcessed = netprofile->outPackets.totalProcessed + netprofile->inPackets.totalProcessed;
Com_sprintf(
buffer,
sizeof(buffer),
"%4i %4i %4i | %3i %3i %3i | %3i %3i %3i | %3i %3i %3i | %7i %7i %7i\n",
netprofile->inPackets.packetsPerSec,
netprofile->outPackets.packetsPerSec,
netprofile->outPackets.packetsPerSec + netprofile->inPackets.packetsPerSec,
netprofile->inPackets.percentFragmented,
netprofile->outPackets.percentFragmented,
(unsigned int)((float)(netprofile->outPackets.numFragmented + netprofile->inPackets.numFragmented) / totalProcessed),
netprofile->inPackets.percentDropped,
netprofile->outPackets.percentDropped,
(unsigned int)((float)(netprofile->outPackets.numDropped + netprofile->inPackets.numDropped) / totalProcessed),
netprofile->inPackets.percentDropped,
netprofile->outPackets.percentDropped,
(unsigned int)((float)(netprofile->outPackets.totalLengthConnectionLess + netprofile->inPackets.totalLengthConnectionLess) / (float)(netprofile->outPackets.totalSize + netprofile->inPackets.totalSize)),
netprofile->inPackets.bytesPerSec,
netprofile->outPackets.bytesPerSec,
netprofile->outPackets.bytesPerSec + netprofile->inPackets.bytesPerSec
);
FS_Write(buffer, strlen(buffer), file);
}
/*
=================
SV_NetProfileDump_f
=================
*/
void SV_NetProfileDump_f(void)
{
static fileHandle_t hFile = 0;
client_t *client;
int i;
char buffer[2048];
netprofclient_t netproftotal;
if (!hFile) {
hFile = FS_FOpenTextFileWrite("netprofile.log");
FS_ForceFlush(hFile);
Com_sprintf(buffer, sizeof(buffer), "NetProfile.log\n\n");
FS_Write(buffer, strlen(buffer), hFile);
Com_sprintf(buffer, sizeof(buffer), "Log Format:\n");
FS_Write(buffer, strlen(buffer), hFile);
Com_sprintf(
buffer,
sizeof(buffer),
"Source: Packets per Second In/Out/Total | %%Fragments In/Out/Total | %%Dropped In/Out/Total | %%OOB Data In/Out/Total"
" | Data per Second In/Out/Total\n"
"\n");
FS_Write(buffer, strlen(buffer), hFile);
}
if (!sv_netprofile->integer) {
return;
}
#ifndef DEDICATED
if (!com_cl_running->integer || com_sv_running->integer) {
#else
if (com_sv_running->integer) {
#endif
Com_sprintf(buffer, sizeof(buffer), "------------------\nServer Net Profile\n");
FS_Write(buffer, strlen(buffer), hFile);
SV_NET_CalcTotalNetProfile(&netproftotal, 1);
Com_sprintf(buffer, sizeof(buffer), "Total: ");
FS_Write(buffer, strlen(buffer), hFile);
SV_NetProfileDump_PrintProf(hFile, &netproftotal);
Com_sprintf(buffer, sizeof(buffer), "Clientless: ");
FS_Write(buffer, strlen(buffer), hFile);
SV_NetProfileDump_PrintProf(hFile, &svs.netprofile);
for (i = 0; i < svs.iNumClients; i++) {
client = &svs.clients[i];
if (client->state != CS_ACTIVE || !client->gentity) {
continue;
}
if (client->netchan.remoteAddress.type == NA_LOOPBACK) {
Com_sprintf(buffer, sizeof(buffer), "#%2i-Loopback: ");
} else {
Com_sprintf(buffer, sizeof(buffer), "Client #%2i: ");
}
FS_Write(buffer, strlen(buffer), hFile);
SV_NetProfileDump_PrintProf(hFile, &client->netprofile);
}
}
#ifndef DEDICATED
else if (com_cl_running->integer && cl_netprofile->integer) {
Com_sprintf(buffer, sizeof(buffer), "------------------\nClient Net Profile\n");
FS_Write(buffer, strlen(buffer), hFile);
SV_NetProfileDump_PrintProf(hFile, &cls.netprofile);
}
#endif
}
/*
=================
SV_ReloadMap_f
@ -1730,6 +1844,8 @@ void SV_AddOperatorCommands(void) {
Cmd_AddCommand("difficultyMedium", SV_MediumMode_f);
Cmd_AddCommand("difficultyHard", SV_HardMode_f);
// Added in 2.0
Cmd_AddCommand("netprofiledump", SV_NetProfileDump_f);
// Added in 2.30
Cmd_AddCommand("reloadmap", SV_ReloadMap_f);

View file

@ -89,7 +89,7 @@ void SV_GetChallenge(netadr_t from)
// it's also way more cool this way :)
if ( Sys_IsLANAddress( from ) ) {
challenge->pingTime = svs.time;
NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "challengeResponse %i", challenge->challenge );
return;
}
@ -97,7 +97,7 @@ void SV_GetChallenge(netadr_t from)
// mohaa below 2.0 doesn't handle gamespy key
// so send the challenge response directly
challenge->pingTime = svs.time;
NET_OutOfBandPrint(NS_SERVER, from, "challengeResponse %i", challenge->challenge);
SV_NET_OutOfBandPrint( &svs.netprofile, from, "challengeResponse %i", challenge->challenge);
return;
}
@ -106,12 +106,12 @@ void SV_GetChallenge(netadr_t from)
// however, it could be an useful feature for a far future
// where players could be authenticated
challenge->pingTime = svs.time;
NET_OutOfBandPrint(NS_SERVER, from, "challengeResponse %i", challenge->challenge);
SV_NET_OutOfBandPrint( &svs.netprofile, from, "challengeResponse %i", challenge->challenge);
return;
}
// check client's cd key
NET_OutOfBandPrint(NS_SERVER, from, "getKey %s", challenge->gsChallenge);
SV_NET_OutOfBandPrint( &svs.netprofile, from, "getKey %s", challenge->gsChallenge);
challenge->pingTime = svs.time;
}
@ -158,21 +158,21 @@ void SV_AuthorizeIpPacket( netadr_t from ) {
if ( !Q_stricmp( s, "demo" ) ) {
// they are a demo client trying to connect to a real server
NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nServer is not a demo server\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr, "print\nServer is not a demo server\n" );
// clear the challenge record so it won't timeout and let them through
Com_Memset( challengeptr, 0, sizeof( *challengeptr ) );
return;
}
if ( !Q_stricmp( s, "accept" ) ) {
NET_OutOfBandPrint(NS_SERVER, challengeptr->adr,
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr,
"challengeResponse %d %d %d", challengeptr->challenge, challengeptr->clientChallenge, com_protocol->integer);
return;
}
if ( !Q_stricmp( s, "unknown" ) ) {
if (!r) {
NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nAwaiting CD key authorization\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr, "print\nAwaiting CD key authorization\n" );
} else {
NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r);
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr, "print\n%s\n", r);
}
// clear the challenge record so it won't timeout and let them through
Com_Memset( challengeptr, 0, sizeof( *challengeptr ) );
@ -181,9 +181,9 @@ void SV_AuthorizeIpPacket( netadr_t from ) {
// authorization failed
if (!r) {
NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\nSomeone is using this CD Key\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr, "print\nSomeone is using this CD Key\n" );
} else {
NET_OutOfBandPrint( NS_SERVER, challengeptr->adr, "print\n%s\n", r );
SV_NET_OutOfBandPrint( &svs.netprofile, challengeptr->adr, "print\n%s\n", r );
}
// clear the challenge record so it won't timeout and let them through
@ -317,7 +317,7 @@ void SV_DirectConnect( netadr_t from ) {
// Check whether this client is banned.
if(SV_IsBanned(&from, qfalse))
{
NET_OutOfBandPrint(NS_SERVER, from, "droperror\nYou are banned from this server.\n");
SV_NET_OutOfBandPrint( &svs.netprofile, from, "droperror\nYou are banned from this server.\n");
return;
}
@ -330,7 +330,7 @@ void SV_DirectConnect( netadr_t from ) {
// Added in 2.30
// Only allow breakthrough clients when targeting mohaab
if (strcmp(clientType, "Breakthrough")) {
NET_OutOfBandPrint(NS_SERVER, from, "droperror\nRequires Medal of Honor Allied Assault Breakthrough\n");
SV_NET_OutOfBandPrint( &svs.netprofile, from, "droperror\nRequires Medal of Honor Allied Assault Breakthrough\n");
Com_DPrintf(" rejected connect - only Breakthrough clients allowed.\n");
return;
}
@ -346,7 +346,7 @@ void SV_DirectConnect( netadr_t from ) {
{
if(version != com_protocol->integer)
{
NET_OutOfBandPrint(NS_SERVER, from, "droperror\nServer uses protocol version %i "
SV_NET_OutOfBandPrint( &svs.netprofile, from, "droperror\nServer uses protocol version %i "
"(yours is %i).\n", com_protocol->integer, version);
Com_DPrintf(" rejected connect from version %i\n", version);
return;
@ -379,7 +379,7 @@ void SV_DirectConnect( netadr_t from ) {
else
ip = (char *)NET_AdrToString( from );
if( ( strlen( ip ) + strlen( userinfo ) + 4 ) >= MAX_INFO_STRING ) {
NET_OutOfBandPrint( NS_SERVER, from,
SV_NET_OutOfBandPrint( &svs.netprofile, from,
"droperror\nUserinfo string length exceeded. "
"Try removing setu cvars from your config.\n" );
return;
@ -403,7 +403,7 @@ void SV_DirectConnect( netadr_t from ) {
if (i == MAX_CHALLENGES)
{
NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for your address.\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "print\nNo or bad challenge for your address.\n" );
return;
}
@ -420,13 +420,13 @@ void SV_DirectConnect( netadr_t from ) {
// never reject a LAN client based on ping
if ( !Sys_IsLANAddress( from ) ) {
if ( sv_minPing->value && ping < sv_minPing->value ) {
NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "print\nServer is for high pings only\n" );
Com_DPrintf ("Client %i rejected on a too low ping\n", i);
challengeptr->wasrefused = qtrue;
return;
}
if ( sv_maxPing->value && ping > sv_maxPing->value ) {
NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "print\nServer is for low pings only\n" );
Com_DPrintf ("Client %i rejected on a too high ping\n", i);
challengeptr->wasrefused = qtrue;
return;
@ -509,7 +509,7 @@ void SV_DirectConnect( netadr_t from ) {
}
}
else {
NET_OutOfBandPrint( NS_SERVER, from, "droperror\nServer is full.\n" );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "droperror\nServer is full.\n" );
Com_DPrintf ("Rejected a connection.\n");
return;
}
@ -548,7 +548,7 @@ gotnewcl:
// get the game a chance to reject this connection or modify the userinfo
denied = ge->ClientConnect( clientNum, qtrue, qfalse );
if ( denied ) {
NET_OutOfBandPrint( NS_SERVER, from, "droperror\n%s\n", denied );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "droperror\n%s\n", denied );
Com_DPrintf ( "Game rejected a connection: %s.\n", denied );
return;
}
@ -560,8 +560,12 @@ gotnewcl:
SV_UserinfoChanged( newcl );
if (sv_netprofile->integer) {
SV_NET_UpdateClientNetProfileInfo(&newcl->netprofile, newcl->rate);
}
// send the connect packet to the client
NET_OutOfBandPrint(NS_SERVER, from, "connectResponse %d", challenge);
SV_NET_OutOfBandPrint( &svs.netprofile, from, "connectResponse %d", challenge);
Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name );

View file

@ -530,7 +530,7 @@ void SVC_Status( netadr_t from ) {
}
}
NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "statusResponse\n%s\n%s", infostring, status );
}
/*
@ -618,7 +618,7 @@ void SVC_Info( netadr_t from ) {
Info_SetValueForKey(infostring, "gamever", com_target_version->string);
Info_SetValueForKey(infostring, "serverType", va("%i", com_target_game->integer));
NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "infoResponse\n%s", infostring );
}
/*
@ -628,7 +628,7 @@ SVC_FlushRedirect
================
*/
static void SV_FlushRedirect( char *outputbuf ) {
NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
SV_NET_OutOfBandPrint( &svs.netprofile, svs.redirectAddress, "print\n%s", outputbuf );
}
/*
@ -720,6 +720,10 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
char *s;
char *c;
if (sv_netprofile->integer) {
NetProfileAddPacket(&svs.netprofile.inPackets, msg->cursize, NETPROF_PACKET_MESSAGE);
}
MSG_BeginReadingOOB( msg );
MSG_ReadLong( msg ); // skip the -1 marker
@ -818,7 +822,7 @@ void SV_PacketEvent( netadr_t from, msg_t *msg ) {
// if we received a sequenced packet from an address we don't recognize,
// send an out of band disconnect packet to it
NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
SV_NET_OutOfBandPrint( &svs.netprofile, from, "disconnect" );
}
@ -1023,6 +1027,8 @@ void SV_Frame( int msec ) {
return;
}
SV_NET_UpdateAllNetProfileInfo();
// allow pause if only the local client is connected
if ( SV_CheckPaused() ) {
return;

View file

@ -169,7 +169,7 @@ void SV_Netchan_TransmitNextInQueue(client_t *client)
SV_Netchan_Encode(client, &netbuf->msg, netbuf->clientCommandString);
#endif
Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);
Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data, sv_netprofile->integer ? &client->netprofile.outPackets : NULL);
// pop from queue
client->netchan_start_queue = netbuf->next;
@ -197,7 +197,7 @@ int SV_Netchan_TransmitNextFragment(client_t *client)
{
if(client->netchan.unsentFragments)
{
Netchan_TransmitNextFragment(&client->netchan);
Netchan_TransmitNextFragment(&client->netchan, sv_netprofile->integer ? &client->netprofile.outPackets : NULL);
return SV_RateMsec(client);
}
else if(client->netchan_start_queue)
@ -250,7 +250,7 @@ void SV_Netchan_Transmit( client_t *client, msg_t *msg)
if(client->compat)
SV_Netchan_Encode(client, msg, client->lastClientCommandString);
#endif
Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
Netchan_Transmit(&client->netchan, msg->cursize, msg->data, sv_netprofile->integer ? &client->netprofile.outPackets : NULL);
}
}
@ -261,7 +261,7 @@ Netchan_SV_Process
*/
qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
int ret;
ret = Netchan_Process( &client->netchan, msg );
ret = Netchan_Process( &client->netchan, msg, sv_netprofile->integer ? &client->netprofile.inPackets : NULL );
if (!ret)
return qfalse;
@ -273,3 +273,170 @@ qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
return qtrue;
}
/*
=================
SV_NET_OutOfBandPrint
=================
*/
void SV_NET_OutOfBandPrint(netprofclient_t* netprof, netadr_t adr, const char* format, ...) {
va_list argptr;
char string[MAX_MSGLEN];
va_start(argptr, format);
Q_vsnprintf(string, sizeof(string), format, argptr);
va_end(argptr);
NET_OutOfBandPrint(NS_SERVER, adr, "%s", string);
if (sv_netprofile->integer && netprof) {
NetProfileAddPacket(&netprof->outPackets, strlen(string), NETPROF_PACKET_MESSAGE);
}
}
/*
=================
SV_NET_UpdateClientNetProfileInfo
=================
*/
void SV_NET_UpdateClientNetProfileInfo(netprofclient_t* netprofile, int rate) {
int time;
if (!netprofile->initialized) {
memset(netprofile, 0, sizeof(*netprofile));
netprofile->initialized = qtrue;
}
if (netprofile->rate != rate) {
netprofile->rate = rate;
}
// set the update time
time = Com_Milliseconds();
netprofile->outPackets.updateTime = time;
netprofile->inPackets.updateTime = time;
}
/*
=================
SV_NET_UpdateAllNetProfileInfo
=================
*/
void SV_NET_UpdateAllNetProfileInfo() {
client_t *client;
int i;
if (!sv_netprofile->integer) {
//
// Clear all netprofile fields
//
svs.netprofile.initialized = qfalse;
for (i = 0; i < svs.iNumClients; i++) {
svs.clients[i].netprofile.initialized = qfalse;
}
return;
}
SV_NET_UpdateClientNetProfileInfo(&svs.netprofile, sv_maxRate->integer);
for (i = 0; i < svs.iNumClients; i++) {
client = &svs.clients[i];
if (client->state != CS_ACTIVE || !client->gentity) {
client->netprofile.initialized = qfalse;
continue;
}
SV_NET_UpdateClientNetProfileInfo(&client->netprofile, client->rate);
}
}
/*
=================
SV_NET_CalcTotalNetProfile
=================
*/
void SV_NET_CalcTotalNetProfile(netprofclient_t* netprofile, qboolean server) {
client_t *client;
int i;
int numValidClients;
numValidClients = 0;
memset(netprofile, 0, sizeof(*netprofile));
if (server) {
NetProfileCalcStats(&svs.netprofile.outPackets, 0);
NetProfileCalcStats(&svs.netprofile.inPackets, 0);
} else {
NetProfileCalcStats(&svs.netprofile.outPackets, 500);
NetProfileCalcStats(&svs.netprofile.inPackets, 500);
}
for (i = 0; i < svs.iNumClients; i++) {
client = &svs.clients[i];
if (client->state != CS_ACTIVE || !client->gentity) {
client->netprofile.initialized = qfalse;
continue;
}
if (server) {
NetProfileCalcStats(&client->netprofile.outPackets, 0);
NetProfileCalcStats(&client->netprofile.inPackets, 0);
} else {
NetProfileCalcStats(&client->netprofile.outPackets, 500);
NetProfileCalcStats(&client->netprofile.inPackets, 500);
}
numValidClients++;
netprofile->rate += client->netprofile.rate;
netprofile->outPackets.totalSize += client->netprofile.outPackets.totalSize;
netprofile->outPackets.bytesPerSec += client->netprofile.outPackets.bytesPerSec;
netprofile->outPackets.numDropped += client->netprofile.outPackets.numDropped;
netprofile->outPackets.percentDropped += client->netprofile.outPackets.percentDropped;
netprofile->outPackets.percentFragmented += client->netprofile.outPackets.percentFragmented;
netprofile->outPackets.numFragmented += client->netprofile.outPackets.numFragmented;
netprofile->outPackets.totalLengthConnectionLess += client->netprofile.outPackets.totalLengthConnectionLess;
netprofile->outPackets.percentConnectionLess += client->netprofile.outPackets.percentConnectionLess;
netprofile->outPackets.totalProcessed += client->netprofile.outPackets.totalProcessed;
netprofile->outPackets.packetsPerSec += client->netprofile.outPackets.packetsPerSec;
netprofile->inPackets.totalSize += client->netprofile.inPackets.totalSize;
netprofile->inPackets.bytesPerSec += client->netprofile.inPackets.bytesPerSec;
netprofile->inPackets.numDropped += client->netprofile.inPackets.numDropped;
netprofile->inPackets.percentDropped += client->netprofile.inPackets.percentDropped;
netprofile->inPackets.percentFragmented += client->netprofile.inPackets.percentFragmented;
netprofile->inPackets.numFragmented += client->netprofile.inPackets.numFragmented;
netprofile->inPackets.totalLengthConnectionLess += client->netprofile.inPackets.totalLengthConnectionLess;
netprofile->inPackets.percentConnectionLess += client->netprofile.inPackets.percentConnectionLess;
netprofile->inPackets.totalProcessed += client->netprofile.inPackets.totalProcessed;
netprofile->inPackets.packetsPerSec += client->netprofile.inPackets.packetsPerSec;
}
if (numValidClients && netprofile->rate) {
netprofile->rate /= numValidClients;
}
netprofile->outPackets.totalSize += svs.netprofile.outPackets.totalSize;
netprofile->outPackets.bytesPerSec += svs.netprofile.outPackets.bytesPerSec;
netprofile->outPackets.numDropped += svs.netprofile.outPackets.numDropped;
netprofile->outPackets.percentDropped += svs.netprofile.outPackets.percentDropped;
netprofile->outPackets.percentFragmented += svs.netprofile.outPackets.percentFragmented;
netprofile->outPackets.numFragmented += svs.netprofile.outPackets.numFragmented;
netprofile->outPackets.totalLengthConnectionLess += svs.netprofile.outPackets.totalLengthConnectionLess;
netprofile->outPackets.percentConnectionLess += svs.netprofile.outPackets.percentConnectionLess;
netprofile->outPackets.totalProcessed += svs.netprofile.outPackets.totalProcessed;
netprofile->outPackets.packetsPerSec += svs.netprofile.outPackets.packetsPerSec;
netprofile->inPackets.totalSize += svs.netprofile.inPackets.totalSize;
netprofile->inPackets.bytesPerSec += svs.netprofile.inPackets.bytesPerSec;
netprofile->inPackets.numDropped += svs.netprofile.inPackets.numDropped;
netprofile->inPackets.percentDropped += svs.netprofile.inPackets.percentDropped;
netprofile->inPackets.percentFragmented += svs.netprofile.inPackets.percentFragmented;
netprofile->inPackets.numFragmented += svs.netprofile.inPackets.numFragmented;
netprofile->inPackets.totalLengthConnectionLess += svs.netprofile.inPackets.totalLengthConnectionLess;
netprofile->inPackets.percentConnectionLess += svs.netprofile.inPackets.percentConnectionLess;
netprofile->inPackets.totalProcessed += svs.netprofile.inPackets.totalProcessed;
netprofile->inPackets.packetsPerSec += svs.netprofile.inPackets.packetsPerSec;
}