/* * SV_ParseClientMessage * The current message is parsed for the given client */ void SV_ParseClientMessage( client_t *client, msg_t *msg ) { int c; char *s; qboolean move_issued; unsigned int cmdNum; if( !msg ) return; SV_UpdateActivity(); // only allow one move command move_issued = qfalse; while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Printf( "SV_ParseClientMessage: badread\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Bad message" ); return; } c = MSG_ReadByte( msg ); if( c == -1 ) break; switch( c ) { default: Com_Printf( "SV_ParseClientMessage: unknown command char\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Unknown command char" ); return; case clc_nop: break; case clc_move: { if( move_issued ) return; // someone is trying to cheat... move_issued = qtrue; SV_ParseMoveCommand( client, msg ); } break; case clc_svcack: { if( client->reliable ) { Com_Printf( "SV_ParseClientMessage: svack from reliable client\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: svack from reliable client" ); return; } cmdNum = MSG_ReadLong( msg ); if( cmdNum < client->reliableAcknowledge || cmdNum > client->reliableSent ) { //SV_DropClient( client, DROP_TYPE_GENERAL, "Error: bad server command acknowledged" ); return; } client->reliableAcknowledge = cmdNum; } break; case clc_clientcommand: if( !client->reliable ) { cmdNum = MSG_ReadLong( msg ); if( cmdNum <= client->clientCommandExecuted ) { s = MSG_ReadString( msg ); // read but ignore continue; } client->clientCommandExecuted = cmdNum; } s = MSG_ReadString( msg ); SV_ExecuteUserCommand( client, s ); if( client->state == CS_ZOMBIE ) return; // disconnect command break; case clc_extension: if( 1 ) { int ext, len; ext = MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length switch( ext ) { default: // unsupported MSG_SkipData( msg, len ); break; } } break; } } }
/** * @brief The current net_message is parsed for the given client */ void SV_ExecuteClientMessage (client_t * cl, int cmd, struct dbuffer *msg) { if (cmd == -1) return; switch (cmd) { default: Com_Printf("SV_ExecuteClientMessage: unknown command char '%d'\n", cmd); SV_DropClient(cl, "Unknown command\n"); return; case clc_nop: break; case clc_ack: cl->lastmessage = svs.realtime; break; case clc_userinfo: NET_ReadString(msg, cl->userinfo, sizeof(cl->userinfo)); Com_DPrintf(DEBUG_SERVER, "userinfo from client: %s\n", cl->userinfo); SV_UserinfoChanged(cl); break; case clc_stringcmd: { char str[1024]; NET_ReadString(msg, str, sizeof(str)); Com_DPrintf(DEBUG_SERVER, "stringcmd from client: %s\n", str); SV_ExecuteUserCommand(cl, str); if (cl->state == cs_free) return; /* disconnect command */ break; } case clc_action: /* client actions are handled by the game module */ sv->messageBuffer = msg; TH_MutexLock(svs.serverMutex); svs.ge->ClientAction(cl->player); TH_MutexUnlock(svs.serverMutex); sv->messageBuffer = NULL; break; case clc_endround: /* player wants to end round */ sv->messageBuffer = msg; TH_MutexLock(svs.serverMutex); svs.ge->ClientEndRound(cl->player); TH_MutexUnlock(svs.serverMutex); sv->messageBuffer = NULL; break; case clc_teaminfo: /* player sends team info */ /* actors spawn accordingly */ sv->messageBuffer = msg; TH_MutexLock(svs.serverMutex); svs.ge->ClientTeamInfo(cl->player); TH_MutexUnlock(svs.serverMutex); sv->messageBuffer = NULL; SV_SetClientState(cl, cs_spawned); break; case clc_initactorstates: /* player sends team info */ /* actors spawn accordingly */ sv->messageBuffer = msg; TH_MutexLock(svs.serverMutex); svs.ge->ClientInitActorStates(cl->player); TH_MutexUnlock(svs.serverMutex); sv->messageBuffer = NULL; break; } }
/* =================== SV_ExecuteClientMessage The current net_message is parsed for the given client =================== */ void SV_ExecuteClientMessage (client_t *cl) { int c; const char *s; usercmd_t oldest, oldcmd, newcmd; client_frame_t *frame; vec3_t o; // calc ping time frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; frame->ping_time = realtime - frame->senttime; // make sure the reply sequence number matches the incoming // sequence number if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence) cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence; else cl->send_message = false; // don't reply, sequences have slipped // save time for ping calculations cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime; cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1; host_client = cl; sv_player = host_client->edict; // mark time so clients will know how much to predict // other players cl->localtime = sv.time; cl->delta_sequence = -1; // no delta unless requested while (1) { if (msg_badread) { Con_Printf ("%s: badread\n", __thisfunc__); SV_DropClient (cl); return; } c = MSG_ReadByte (); if (c == -1) break; switch (c) { default: Con_Printf ("%s: unknown command char\n", __thisfunc__); SV_DropClient (cl); return; case clc_nop: break; case clc_delta: cl->delta_sequence = MSG_ReadByte (); break; case clc_move: MSG_ReadUsercmd (&oldest, false); MSG_ReadUsercmd (&oldcmd, false); MSG_ReadUsercmd (&newcmd, true); if ( cl->state != cs_spawned ) break; SV_PreRunCmd(); if (net_drop < 20) { while (net_drop > 2) { SV_RunCmd (&cl->lastcmd); net_drop--; } if (net_drop > 1) SV_RunCmd (&oldest); if (net_drop > 0) SV_RunCmd (&oldcmd); } SV_RunCmd (&newcmd); SV_PostRunCmd(); cl->lastcmd = newcmd; cl->lastcmd.buttons = 0; // avoid multiple fires on lag break; case clc_stringcmd: s = MSG_ReadString (); SV_ExecuteUserCommand (s); break; case clc_tmove: o[0] = MSG_ReadCoord(); o[1] = MSG_ReadCoord(); o[2] = MSG_ReadCoord(); // only allowed by spectators if (host_client->spectator) { VectorCopy(o, sv_player->v.origin); SV_LinkEdict(sv_player, false); } break; case clc_inv_select: cl->edict->v.inventory = MSG_ReadByte(); break; case clc_get_effect: c = MSG_ReadByte(); if (sv.Effects[c].type) { Con_Printf("Getting effect %d\n",(int)c); SV_SendEffect(&host_client->netchan.message, c); } break; } } }
/* =================== SV_ExecuteClientMessage The current net_message is parsed for the given client =================== */ void SV_ExecuteClientMessage(client_t *cl){ int c; char *s; usercmd_t nullcmd; usercmd_t oldest, oldcmd, newcmd; int net_drop; int stringCmdCount; int checksum, calculatedChecksum; int checksumIndex; qboolean move_issued; int lastframe; sv_client = cl; sv_player = sv_client->edict; // only allow one move command move_issued = false; stringCmdCount = 0; while(1){ if(net_message.readcount > net_message.cursize){ Com_Printf("SV_ReadClientMessage: badread\n"); SV_DropClient(cl); return; } c = MSG_ReadByte(&net_message); if(c == -1) break; switch(c){ default: Com_Printf("SV_ReadClientMessage: unknown command char\n"); SV_DropClient(cl); return; case clc_nop: break; case clc_userinfo: strncpy(cl->userinfo, MSG_ReadString(&net_message), sizeof(cl->userinfo) - 1); SV_UserinfoChanged(cl); break; case clc_move: if(move_issued) return; // someone is trying to cheat... move_issued = true; checksumIndex = net_message.readcount; checksum = MSG_ReadByte(&net_message); lastframe = MSG_ReadLong(&net_message); if(lastframe != cl->lastframe){ cl->lastframe = lastframe; if(cl->lastframe > 0){ cl->frame_latency[cl->lastframe&(LATENCY_COUNTS - 1)] = svs.realtime - cl->frames[cl->lastframe & UPDATE_MASK].senttime; } } memset(&nullcmd, 0, sizeof(nullcmd)); MSG_ReadDeltaUsercmd(&net_message, &nullcmd, &oldest); MSG_ReadDeltaUsercmd(&net_message, &oldest, &oldcmd); MSG_ReadDeltaUsercmd(&net_message, &oldcmd, &newcmd); if(cl->state != cs_spawned){ cl->lastframe = -1; break; } // if the checksum fails, ignore the rest of the packet calculatedChecksum = COM_BlockSequenceCRCByte( net_message.data + checksumIndex + 1, net_message.readcount - checksumIndex - 1, cl->netchan.incoming_sequence); if(calculatedChecksum != checksum){ Com_DPrintf("Failed command checksum for %s(%d != %d)/%d\n", cl->name, calculatedChecksum, checksum, cl->netchan.incoming_sequence); return; } if(!paused->value){ net_drop = cl->netchan.dropped; if(net_drop < 20){ // if(net_drop > 2) // Com_Printf("drop %i\n", net_drop); while(net_drop > 2){ SV_ClientThink(cl, &cl->lastcmd); net_drop--; } if(net_drop > 1) SV_ClientThink(cl, &oldest); if(net_drop > 0) SV_ClientThink(cl, &oldcmd); } SV_ClientThink(cl, &newcmd); } cl->lastcmd = newcmd; break; case clc_stringcmd: s = MSG_ReadString(&net_message); // malicious users may try using too many string commands if(++stringCmdCount < MAX_STRINGCMDS) SV_ExecuteUserCommand(s); if(cl->state == cs_zombie) return; // disconnect command break; } } }
void SV_ExecuteClientMessage (client_t *cl) { int c; char *s; usercmd_t oldest, oldcmd, newcmd; client_frame_t *frame; vec3_t o; qboolean move_issued = false; //only allow one move command int checksumIndex; byte checksum, calculatedChecksum; int seq_hash; // calc ping time frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK]; frame->ping_time = realtime - frame->senttime; // make sure the reply sequence number matches the incoming // sequence number if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence) cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence; else cl->send_message = false; // don't reply, sequences have slipped // save time for ping calculations cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime; cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1; host_client = cl; sv_player = host_client->edict; // seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH; seq_hash = cl->netchan.incoming_sequence; // mark time so clients will know how much to predict // other players cl->localtime = sv.time; cl->delta_sequence = -1; // no delta unless requested while (1) { if (msg_badread) { Con_Printf ("SV_ReadClientMessage: badread\n"); SV_DropClient (cl); return; } c = MSG_ReadByte (); if (c == -1) break; switch (c) { default: Con_Printf ("SV_ReadClientMessage: unknown command char\n"); SV_DropClient (cl); return; case clc_nop: break; case clc_delta: cl->delta_sequence = MSG_ReadByte (); break; case clc_move: if (move_issued) return; // someone is trying to cheat... move_issued = true; checksumIndex = MSG_GetReadCount(); checksum = (byte)MSG_ReadByte (); // read loss percentage cl->lossage = MSG_ReadByte(); MSG_ReadDeltaUsercmd (&nullcmd, &oldest); MSG_ReadDeltaUsercmd (&oldest, &oldcmd); MSG_ReadDeltaUsercmd (&oldcmd, &newcmd); if ( cl->state != cs_spawned ) break; // if the checksum fails, ignore the rest of the packet calculatedChecksum = COM_BlockSequenceCRCByte( net_message.data + checksumIndex + 1, MSG_GetReadCount() - checksumIndex - 1, seq_hash); if (calculatedChecksum != checksum) { Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n", cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum); return; } if (!sv.paused) { SV_PreRunCmd(); if (net_drop < 20) { while (net_drop > 2) { SV_RunCmd (&cl->lastcmd); net_drop--; } if (net_drop > 1) SV_RunCmd (&oldest); if (net_drop > 0) SV_RunCmd (&oldcmd); } SV_RunCmd (&newcmd); SV_PostRunCmd(); } cl->lastcmd = newcmd; cl->lastcmd.buttons = 0; // avoid multiple fires on lag break; case clc_stringcmd: s = MSG_ReadString (); SV_ExecuteUserCommand (s); break; case clc_tmove: o[0] = MSG_ReadCoord(); o[1] = MSG_ReadCoord(); o[2] = MSG_ReadCoord(); // only allowed by spectators if (host_client->spectator) { VectorCopy(o, sv_player->v.origin); SV_LinkEdict(sv_player, false); } break; case clc_upload: SV_NextUpload(); break; } } }