/* ================== CL_ParseServerInfo ================== */ void CL_ParseServerInfo (void) { char *str; int i; int nummodels, numsounds; char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; Con_DPrintf ("Serverinfo packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number i = MSG_ReadLong (); if (i != PROTOCOL_VERSION) { Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION); return; } // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); return; } cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); // parse signon message str = MSG_ReadString (); strncpy (cl.levelname, str, sizeof(cl.levelname)-1); // seperate the printfs so the server message can have a color Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); Con_Printf ("%c%s\n", 2, str); // // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // // precache models memset (cl.model_precache, 0, sizeof(cl.model_precache)); for (nummodels=1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels==MAX_MODELS) { Con_Printf ("Server sent too many model precaches\n"); return; } strcpy (model_precache[nummodels], str); Mod_TouchModel (str); } // precache sounds memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); for (numsounds=1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds==MAX_SOUNDS) { Con_Printf ("Server sent too many sound precaches\n"); return; } strcpy (sound_precache[numsounds], str); S_TouchSound (str); } // // now we try to load everything else until a cache allocation fails // for (i=1 ; i<nummodels ; i++) { cl.model_precache[i] = Mod_ForName (model_precache[i], false); if (cl.model_precache[i] == NULL) { Con_Printf("Model %s not found\n", model_precache[i]); return; } CL_KeepaliveMessage (); } S_BeginPrecaching (); for (i=1 ; i<numsounds ; i++) { cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); CL_KeepaliveMessage (); } S_EndPrecaching (); // local state cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); Hunk_Check (); // make sure nothing is hurt noclip_anglehack = false; // noclip is turned off at start }
static int read_server_file(void) { char name[MAX_OSPATH], string[MAX_STRING_CHARS]; mapcmd_t cmd; size_t len; // errors like missing file, bad version, etc are // non-fatal and just return to the command handler if (read_binary_file("save/" SAVE_CURRENT "/server.ssv")) return -1; if (MSG_ReadLong() != SAVE_MAGIC1) return -1; if (MSG_ReadLong() != SAVE_VERSION) return -1; memset(&cmd, 0, sizeof(cmd)); // read the comment field MSG_ReadLong(); MSG_ReadLong(); if (MSG_ReadByte()) cmd.loadgame = 2; // autosave else cmd.loadgame = 1; // regular savegame MSG_ReadString(NULL, 0); // read the mapcmd len = MSG_ReadString(cmd.buffer, sizeof(cmd.buffer)); if (len >= sizeof(cmd.buffer)) return -1; // now try to load the map if (!SV_ParseMapCmd(&cmd)) return -1; // save pending CM to be freed later if ERR_DROP is thrown Com_AbortFunc(abort_func, &cmd.cm); // any error will drop from this point SV_Shutdown("Server restarted\n", ERR_RECONNECT); // the rest can't underflow msg_read.allowunderflow = qfalse; // read all CVAR_LATCH cvars // these will be things like coop, skill, deathmatch, etc while (1) { len = MSG_ReadString(name, MAX_QPATH); if (!len) break; if (len >= MAX_QPATH) Com_Error(ERR_DROP, "Savegame cvar name too long"); len = MSG_ReadString(string, sizeof(string)); if (len >= sizeof(string)) Com_Error(ERR_DROP, "Savegame cvar value too long"); Cvar_UserSet(name, string); } // start a new game fresh with new cvars SV_InitGame(MVD_SPAWN_DISABLED); // error out immediately if game doesn't support safe savegames if (!(g_features->integer & GMF_ENHANCED_SAVEGAMES)) Com_Error(ERR_DROP, "Game does not support enhanced savegames"); // read game state len = Q_snprintf(name, MAX_OSPATH, "%s/save/" SAVE_CURRENT "/game.ssv", fs_gamedir); if (len >= MAX_OSPATH) Com_Error(ERR_DROP, "Savegame path too long"); ge->ReadGame(name); // clear pending CM Com_AbortFunc(NULL, NULL); // go to the map SV_SpawnServer(&cmd); return 0; }
/* ===================== CL_ParseDownload A download message has been received from the server ===================== */ void CL_ParseDownload ( msg_t *msg ) { int size; unsigned char data[MAX_MSGLEN]; uint16_t block; if (!*clc.downloadTempName) { Com_Printf("Server sending download, but no download was requested\n"); CL_AddReliableCommand("stopdl", qfalse); return; } // read the data block = MSG_ReadShort ( msg ); if ( !block && !clc.downloadBlock ) { // block zero is special, contains file size clc.downloadSize = MSG_ReadLong ( msg ); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); if (clc.downloadSize < 0) { Com_Error(ERR_DROP, "%s", MSG_ReadString( msg ) ); return; } } size = /*(unsigned short)*/MSG_ReadShort ( msg ); if (size < 0 || size > (int)sizeof(data)) { Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk", size); return; } MSG_ReadData( msg, data, size ); if((clc.downloadBlock & 0xFFFF) != block) { Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", (clc.downloadBlock & 0xFFFF), block); return; } // open the file if not opened yet if (!clc.download) { clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName ); if (!clc.download) { Com_Printf( "Could not create %s\n", clc.downloadTempName ); CL_AddReliableCommand( "stopdl", qfalse ); CL_NextDownload(); return; } } if (size) FS_Write( data, size, clc.download ); CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock), qfalse ); clc.downloadBlock++; clc.downloadCount += size; // So UI gets access to it Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); if (!size) { // A zero length block means EOF if (clc.download) { FS_FCloseFile( clc.download ); clc.download = 0; // rename the file FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse ); } // send intentions now // We need this because without it, we would hold the last nextdl and then start // loading right away. If we take a while to load, the server is happily trying // to send us that last block over and over. // Write it twice to help make sure we acknowledge the download CL_WritePacket(); CL_WritePacket(); // get another file if needed CL_NextDownload (); } }
/* =============== SV_ClientCommand =============== */ static bool SV_ClientCommand( client_t *cl, msg_t *msg, bool premaprestart ) { int seq; const char *s; bool clientOk = true; bool floodprotect = true; seq = MSG_ReadLong( msg ); s = MSG_ReadString( msg ); // see if we have already executed it if ( cl->lastClientCommand >= seq ) { return true; } Log::Debug( "clientCommand: %s^7 : %i : %s", cl->name, seq, s ); // drop the connection if we have somehow lost commands if ( seq > cl->lastClientCommand + 1 ) { Log::Notice( "Client %s lost %i clientCommands\n", cl->name, seq - cl->lastClientCommand + 1 ); SV_DropClient( cl, "Lost reliable commands" ); return false; } // Gordon: AHA! Need to steal this for some other stuff BOOKMARK // NERVE - SMF - some server game-only commands we cannot have flood protect if ( !Q_strncmp( "team", s, 4 ) || !Q_strncmp( "setspawnpt", s, 10 ) || !Q_strncmp( "score", s, 5 ) || !Q_stricmp( "forcetapout", s ) ) { // Log::Debug( "Skipping flood protection for: %s", s ); floodprotect = false; } // malicious users may try using too many string commands // to lag other players. If we decide that we want to stall // the command, we will stop processing the rest of the packet, // including the usercmd. This causes flooders to lag themselves // but not other people // We don't do this when the client hasn't been active yet, since it is // by protocol to spam a lot of commands when downloading if ( !com_cl_running->integer && cl->state >= clientState_t::CS_ACTIVE && // (SA) this was commented out in Wolf. Did we do that? sv_floodProtect->integer && svs.time < cl->nextReliableTime && floodprotect ) { // ignore any other text messages from this client but let them keep playing // TTimo - moved the ignored verbose to the actual processing in SV_ExecuteClientCommand, only printing if the core doesn't intercept clientOk = false; } // don't allow another command for 800 msec if ( floodprotect && svs.time >= cl->nextReliableTime ) { cl->nextReliableTime = svs.time + 800; } SV_ExecuteClientCommand( cl, s, clientOk, premaprestart ); cl->lastClientCommand = seq; Com_sprintf( cl->lastClientCommandString, sizeof( cl->lastClientCommandString ), "%s", s ); return true; // continue processing }
void demoConvert( const char *oldName, const char *newBaseName, qboolean smoothen ) { fileHandle_t oldHandle = 0; fileHandle_t newHandle = 0; int temp; int oldSize; int msgSequence; msg_t oldMsg; byte oldData[ MAX_MSGLEN ]; int oldTime, nextTime, fullTime; int clientNum; demoFrame_t *workFrame; int parseEntitiesNum = 0; demoConvert_t *convert; char bigConfigString[BIG_INFO_STRING]; int bigConfigNumber; const char *s; clSnapshot_t *oldSnap = 0; clSnapshot_t *newSnap; int levelCount = 0; char newName[MAX_OSPATH]; oldSize = FS_FOpenFileRead( oldName, &oldHandle, qtrue ); if (!oldHandle) { Com_Printf("Failed to open %s for conversion.", oldName); return; } /* Alloc some memory */ convert = Z_Malloc( sizeof( demoConvert_t) ); /* Initialize the first workframe's strings */ while (oldSize > 0) { MSG_Init( &oldMsg, oldData, sizeof( oldData ) ); /* Read the sequence number */ if (FS_Read( &convert->messageNum, 4, oldHandle) != 4) goto conversionerror; convert->messageNum = LittleLong( convert->messageNum ); oldSize -= 4; /* Read the message size */ if (FS_Read( &oldMsg.cursize,4, oldHandle) != 4) goto conversionerror; oldSize -= 4; oldMsg.cursize = LittleLong( oldMsg.cursize ); /* Negative size signals end of demo */ if (oldMsg.cursize < 0) break; if ( oldMsg.cursize > oldMsg.maxsize ) goto conversionerror; /* Read the actual message */ if (FS_Read( oldMsg.data, oldMsg.cursize, oldHandle ) != oldMsg.cursize) goto conversionerror; oldSize -= oldMsg.cursize; // init the bitstream MSG_BeginReading( &oldMsg ); // Skip the reliable sequence acknowledge number MSG_ReadLong( &oldMsg ); // // parse the message // while ( 1 ) { byte cmd; if ( oldMsg.readcount > oldMsg.cursize ) { Com_Printf ("Demo conversion, read past end of server message.\n"); goto conversionerror; } cmd = MSG_ReadByte( &oldMsg ); if ( cmd == svc_EOF) { break; } workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ]; // other commands switch ( cmd ) { default: Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n"); break; case svc_nop: break; case svc_serverCommand: temp = MSG_ReadLong( &oldMsg ); s = MSG_ReadString( &oldMsg ); if (temp<=msgSequence) break; // Com_Printf( " server command %s\n", s ); msgSequence = temp; Cmd_TokenizeString( s ); if ( !Q_stricmp( Cmd_Argv(0), "bcs0" ) ) { bigConfigNumber = atoi( Cmd_Argv(1) ); Q_strncpyz( bigConfigString, Cmd_Argv(2), sizeof( bigConfigString )); break; } if ( !Q_stricmp( Cmd_Argv(0), "bcs1" ) ) { Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2)); break; } if ( !Q_stricmp( Cmd_Argv(0), "bcs2" ) ) { Q_strcat( bigConfigString, sizeof( bigConfigString ), Cmd_Argv(2)); demoFrameAddString( &workFrame->string, bigConfigNumber, bigConfigString ); break; } if ( !Q_stricmp( Cmd_Argv(0), "cs" ) ) { int num = atoi( Cmd_Argv(1) ); s = Cmd_ArgsFrom( 2 ); demoFrameAddString( &workFrame->string, num, Cmd_ArgsFrom( 2 ) ); break; } if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { int len = strlen( s ) + 1; char *dst; if (workFrame->commandUsed + len + 1 > sizeof( workFrame->commandData)) { Com_Printf("Overflowed state command data.\n"); goto conversionerror; } dst = workFrame->commandData + workFrame->commandUsed; *dst = clientNum; Com_Memcpy( dst+1, s, len ); workFrame->commandUsed += len + 1; } break; case svc_gamestate: if (newHandle) { FS_FCloseFile( newHandle ); newHandle = 0; } if (levelCount) { Com_sprintf( newName, sizeof( newName ), "%s.%d.mme", newBaseName, levelCount ); } else { Com_sprintf( newName, sizeof( newName ), "%s.mme", newBaseName ); } fullTime = -1; clientNum = -1; oldTime = -1; Com_Memset( convert, 0, sizeof( *convert )); convert->frames[0].string.used = 1; levelCount++; newHandle = FS_FOpenFileWrite( newName ); if (!newHandle) { Com_Printf("Failed to open %s for target conversion target.\n", newName); goto conversionerror; return; } else { FS_Write ( demoHeader, strlen( demoHeader ), newHandle ); } Com_sprintf( newName, sizeof( newName ), "%s.txt", newBaseName ); workFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES ]; msgSequence = MSG_ReadLong( &oldMsg ); while( 1 ) { cmd = MSG_ReadByte( &oldMsg ); if (cmd == svc_EOF) break; if ( cmd == svc_configstring) { int num; const char *s; num = MSG_ReadShort( &oldMsg ); s = MSG_ReadBigString( &oldMsg ); demoFrameAddString( &workFrame->string, num, s ); } else if ( cmd == svc_baseline ) { int num = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); if ( num < 0 || num >= MAX_GENTITIES ) { Com_Printf( "Baseline number out of range: %i.\n", num ); goto conversionerror; } MSG_ReadDeltaEntity( &oldMsg, &demoNullEntityState, &convert->entityBaselines[num], num ); } else { Com_Printf( "Unknown block while converting demo gamestate.\n" ); goto conversionerror; } } clientNum = MSG_ReadLong( &oldMsg ); /* Skip the checksum feed */ MSG_ReadLong( &oldMsg ); break; case svc_snapshot: nextTime = MSG_ReadLong( &oldMsg ); /* Delta number, not needed */ newSnap = &convert->snapshots[convert->messageNum & PACKET_MASK]; Com_Memset (newSnap, 0, sizeof(*newSnap)); newSnap->deltaNum = MSG_ReadByte( &oldMsg ); newSnap->messageNum = convert->messageNum; if (!newSnap->deltaNum) { newSnap->deltaNum = -1; newSnap->valid = qtrue; // uncompressed frame oldSnap = NULL; } else { newSnap->deltaNum = newSnap->messageNum - newSnap->deltaNum; oldSnap = &convert->snapshots[newSnap->deltaNum & PACKET_MASK]; if (!oldSnap->valid) { Com_Printf( "Delta snapshot without base.\n" ); goto conversionerror; } else if (oldSnap->messageNum != newSnap->deltaNum) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); } else if ( parseEntitiesNum - oldSnap->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { Com_Printf ("Delta parseEntitiesNum too old.\n"); } else { newSnap->valid = qtrue; // valid delta parse } } /* Snapflags, not needed */ newSnap->snapFlags = MSG_ReadByte( &oldMsg ); // read areamask workFrame->areaUsed = MSG_ReadByte( &oldMsg ); MSG_ReadData( &oldMsg, workFrame->areamask, workFrame->areaUsed ); if (clientNum <0 || clientNum >= MAX_CLIENTS) { Com_Printf("Got snapshot with invalid client.\n"); goto conversionerror; } MSG_ReadDeltaPlayerstate( &oldMsg, oldSnap ? &oldSnap->ps : &demoNullPlayerState, &newSnap->ps ); /* Read the individual entities */ newSnap->parseEntitiesNum = parseEntitiesNum; newSnap->numEntities = 0; Com_Memset( workFrame->entityData, 0, sizeof( workFrame->entityData )); /* The beast that is entity parsing */ { int newnum; entityState_t *oldstate, *newstate; int oldindex = 0; int oldnum; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); while ( 1 ) { // read the entity index number if (oldSnap && oldindex < oldSnap->numEntities) { oldstate = &convert->parseEntities[(oldSnap->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } else { oldstate = 0; oldnum = 99999; } newstate = &convert->parseEntities[parseEntitiesNum]; if ( !oldstate && (newnum == (MAX_GENTITIES-1))) { break; } else if ( oldnum < newnum ) { *newstate = *oldstate; oldindex++; } else if (oldnum == newnum) { oldindex++; MSG_ReadDeltaEntity( &oldMsg, oldstate, newstate, newnum ); if ( newstate->number != MAX_GENTITIES-1) workFrame->entityData[ newstate->number ] = 1; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); } else if (oldnum > newnum) { MSG_ReadDeltaEntity( &oldMsg, &convert->entityBaselines[newnum], newstate , newnum ); if ( newstate->number != MAX_GENTITIES-1) workFrame->entityData[ newstate->number ] = 1; newnum = MSG_ReadBits( &oldMsg, GENTITYNUM_BITS ); } if (newstate->number == MAX_GENTITIES-1) continue; parseEntitiesNum++; parseEntitiesNum &= (MAX_PARSE_ENTITIES-1); newSnap->numEntities++; }} /* Stop processing this further since it's an invalid snap due to lack of delta data */ if (!newSnap->valid) break; /* Skipped snapshots will be set invalid in the circular buffer */ if ( newSnap->messageNum - convert->lastMessageNum >= PACKET_BACKUP ) { convert->lastMessageNum = newSnap->messageNum - ( PACKET_BACKUP - 1 ); } for ( ; convert->lastMessageNum < newSnap->messageNum ; convert->lastMessageNum++ ) { convert->snapshots[convert->lastMessageNum & PACKET_MASK].valid = qfalse; } convert->lastMessageNum = newSnap->messageNum + 1; /* compress the frame into the new format */ if (nextTime > oldTime) { demoFrame_t *cleanFrame; int writeIndex; for (temp = 0;temp<newSnap->numEntities;temp++) { int p = (newSnap->parseEntitiesNum+temp) & (MAX_PARSE_ENTITIES-1); entityState_t *newState = &convert->parseEntities[p]; workFrame->entities[newState->number] = *newState; } workFrame->clientData[clientNum] = 1; workFrame->clients[clientNum] = newSnap->ps; workFrame->serverTime = nextTime; /* Which frame from the cache to save */ writeIndex = convert->frameIndex - (DEMOCONVERTFRAMES/2); if (writeIndex >= 0) { const demoFrame_t *newFrame; msg_t writeMsg; // init the message MSG_Init( &writeMsg, demoBuffer, sizeof (demoBuffer)); MSG_Clear( &writeMsg ); MSG_Bitstream( &writeMsg ); newFrame = &convert->frames[ writeIndex % DEMOCONVERTFRAMES]; if ( smoothen ) demoFrameInterpolate( convert->frames, DEMOCONVERTFRAMES, writeIndex ); if ( nextTime > fullTime || writeIndex <= 0 ) { /* Plan the next time for a full write */ fullTime = nextTime + 2000; demoFramePack( &writeMsg, newFrame, 0 ); } else { const demoFrame_t *oldFrame = &convert->frames[ ( writeIndex -1 ) % DEMOCONVERTFRAMES]; demoFramePack( &writeMsg, newFrame, oldFrame ); } /* Write away the new data in the msg queue */ temp = LittleLong( writeMsg.cursize ); FS_Write (&temp, 4, newHandle ); FS_Write ( writeMsg.data , writeMsg.cursize, newHandle ); } /* Clean up the upcoming frame for all new changes */ convert->frameIndex++; cleanFrame = &convert->frames[ convert->frameIndex % DEMOCONVERTFRAMES]; cleanFrame->serverTime = 0; for (temp = 0;temp<MAX_GENTITIES;temp++) cleanFrame->entities[temp].number = MAX_GENTITIES-1; Com_Memset( cleanFrame->clientData, 0, sizeof ( cleanFrame->clientData )); Com_Memcpy( cleanFrame->string.data, workFrame->string.data, workFrame->string.used ); Com_Memcpy( cleanFrame->string.offsets, workFrame->string.offsets, sizeof( workFrame->string.offsets )); cleanFrame->string.used = workFrame->string.used; cleanFrame->commandUsed = 0; /* keep track of this last frame's time */ oldTime = nextTime; } break; case svc_download: // read block number temp = MSG_ReadShort ( &oldMsg ); if (!temp) //0 block, read file size MSG_ReadLong( &oldMsg ); // read block size temp = MSG_ReadShort ( &oldMsg ); // read the data block for ( ;temp>0;temp--) MSG_ReadByte( &oldMsg ); break; } } } conversionerror: FS_FCloseFile( oldHandle ); FS_FCloseFile( newHandle ); Z_Free( convert ); return; }
static qsocket_t *_Datagram_Connect(char *host) { struct qsockaddr sendaddr; struct qsockaddr readaddr; qsocket_t *sock; int newsock; int ret; int reps; double start_time; int control; char *reason; // see if we can resolve the host name if (dfunc.GetAddrFromName(host, &sendaddr) == -1) { return NULL; } newsock = dfunc.OpenSocket(0); if (newsock == -1) { return NULL; } sock = NET_NewQSocket(); if (sock == NULL) { goto ErrorReturn2; } sock->socket = newsock; sock->landriver = net_landriverlevel; // connect to the host if (dfunc.Connect(newsock, &sendaddr) == -1) { goto ErrorReturn; } // send the connection request Con_Printf("trying...\n"); SCR_UpdateScreen(); start_time = net_time; for (reps = 0; reps < 3; reps++) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_CONNECT); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(newsock, net_message.data, net_message.cursize, &sendaddr); SZ_Clear(&net_message); do { ret = dfunc.Read(newsock, net_message.data, net_message.maxsize, &readaddr); // if we got something, validate it if (ret > 0) { // is it from the right place? if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) { #ifdef DEBUG Con_Printf("wrong reply address\n"); Con_Printf("Expected: %s\n", StrAddr(&sendaddr)); Con_Printf("Received: %s\n", StrAddr(&readaddr)); SCR_UpdateScreen(); #endif ret = 0; continue; } if (ret < sizeof(int)) { ret = 0; continue; } net_message.cursize = ret; MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { ret = 0; continue; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { ret = 0; continue; } if ((control & NETFLAG_LENGTH_MASK) != ret) { ret = 0; continue; } } } while (ret == 0 && (SetNetTime() - start_time) < 2.5); if (ret) { break; } Con_Printf("still trying...\n"); SCR_UpdateScreen(); start_time = SetNetTime(); } if (ret == 0) { reason = "No Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } if (ret == -1) { reason = "Network Error"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } ret = MSG_ReadByte(); if (ret == CCREP_REJECT) { reason = MSG_ReadString(); Con_Printf(reason); Q_strncpy(m_return_reason, reason, 31); goto ErrorReturn; } if (ret == CCREP_ACCEPT) { Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); dfunc.SetSocketPort(&sock->addr, MSG_ReadLong()); } else { reason = "Bad Response"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } dfunc.GetNameFromAddr(&sendaddr, sock->address); Con_Printf("Connection accepted\n"); sock->lastMessageTime = SetNetTime(); // switch the connection to the specified address if (dfunc.Connect(newsock, &sock->addr) == -1) { reason = "Connect to Game failed"; Con_Printf("%s\n", reason); Q_strcpy(m_return_reason, reason); goto ErrorReturn; } m_return_onerror = false; return sock; ErrorReturn: NET_FreeQSocket(sock); ErrorReturn2: dfunc.CloseSocket(newsock); if (m_return_onerror) { key_dest = key_menu; m_state = m_return_state; m_return_onerror = false; } return NULL; }
static qsocket_t *_Datagram_CheckNewConnections(void) { struct qsockaddr clientaddr; struct qsockaddr newaddr; int newsock; int acceptsock; qsocket_t *sock; qsocket_t *s; int len; int command; int control; int ret; acceptsock = dfunc.CheckNewConnections(); if (acceptsock == -1) { return NULL; } SZ_Clear(&net_message); len = dfunc.Read(acceptsock, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) { return NULL; } net_message.cursize = len; MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { return NULL; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { return NULL; } if ((control & NETFLAG_LENGTH_MASK) != len) { return NULL; } command = MSG_ReadByte(); if (command == CCREQ_SERVER_INFO) { if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) { return NULL; } SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_SERVER_INFO); dfunc.GetSocketAddr(acceptsock, &newaddr); MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); MSG_WriteString(&net_message, hostname.string); MSG_WriteString(&net_message, sv.name); MSG_WriteByte(&net_message, net_activeconnections); MSG_WriteByte(&net_message, svs.maxclients); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_PLAYER_INFO) { int playerNumber; int activeNumber; int clientNumber; client_t *client; playerNumber = MSG_ReadByte(); activeNumber = -1; for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) { if (client->active) { activeNumber++; if (activeNumber == playerNumber) { break; } } } if (clientNumber == svs.maxclients) { return NULL; } SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); MSG_WriteByte(&net_message, playerNumber); MSG_WriteString(&net_message, client->name); MSG_WriteLong(&net_message, client->colors); MSG_WriteLong(&net_message, (int)client->edict->v.frags); MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); MSG_WriteString(&net_message, client->netconnection->address); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command == CCREQ_RULE_INFO) { char *prevCvarName; cvar_t *var; // find the search start location prevCvarName = MSG_ReadString(); if (*prevCvarName) { var = Cvar_FindVar(prevCvarName); if (!var) { return NULL; } var = var->next; } else { var = cvar_vars; } // search for the next server cvar while (var) { if (var->server) { break; } var = var->next; } // send the response SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_RULE_INFO); if (var) { MSG_WriteString(&net_message, var->name); MSG_WriteString(&net_message, var->string); } *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } if (command != CCREQ_CONNECT) { return NULL; } if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) { return NULL; } if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Incompatible version.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } #ifdef BAN_TEST // check for a ban if (clientaddr.sa_family == AF_INET) { unsigned long testAddr; testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; if ((testAddr & banMask) == banAddr) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "You have been banned.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } } #endif // see if this guy is already connected for (s = net_activeSockets; s; s = s->next) { if (s->driver != net_driverlevel) { continue; } ret = dfunc.AddrCompare(&clientaddr, &s->addr); if (ret >= 0) { // is this a duplicate connection reqeust? if (ret == 0 && net_time - s->connecttime < 2.0) { // yes, so send a duplicate reply SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(s->socket, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // it's somebody coming back in from a crash/disconnect // so close the old qsocket and let their retry get them back in NET_Close(s); return NULL; } } // allocate a QSocket sock = NET_NewQSocket(); if (sock == NULL) { // no room; try to let him know SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_REJECT); MSG_WriteString(&net_message, "Server is full.\n"); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return NULL; } // allocate a network socket newsock = dfunc.OpenSocket(0); if (newsock == -1) { NET_FreeQSocket(sock); return NULL; } // connect to the client if (dfunc.Connect(newsock, &clientaddr) == -1) { dfunc.CloseSocket(newsock); NET_FreeQSocket(sock); return NULL; } // everything is allocated, just fill in the details sock->socket = newsock; sock->landriver = net_landriverlevel; sock->addr = clientaddr; Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr)); // send him back the info about the server connection he has been allocated SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREP_ACCEPT); dfunc.GetSocketAddr(newsock, &newaddr); MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); // MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(acceptsock, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); return sock; }
/* * CL_ParseServerData */ static void CL_ParseServerData( msg_t *msg ) { const char *str, *gamedir; int i, sv_bitflags, numpure; int http_portnum; Com_DPrintf( "Serverdata packet received.\n" ); // wipe the client_state_t struct CL_ClearState(); CL_SetClientState( CA_CONNECTED ); // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION && !(cls.demo.playing && i == APP_DEMO_PROTOCOL_VERSION) ) Com_Error( ERR_DROP, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); cl.servercount = MSG_ReadLong( msg ); cl.snapFrameTime = (unsigned int)MSG_ReadShort( msg ); cl.gamestart = true; // set extrapolation time to half snapshot time Cvar_ForceSet( "cl_extrapolationTime", va( "%i", (unsigned int)( cl.snapFrameTime * 0.5 ) ) ); cl_extrapolationTime->modified = false; // base game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty base game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid base game directory: %s", str ); if( strcmp( FS_BaseGameDirectory(), str ) ) { Com_Error( ERR_DROP, "Server has different base game directory (%s) than the client (%s)", str, FS_BaseGameDirectory() ); } // game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid game directory: %s", str ); gamedir = FS_GameDirectory(); if( strcmp( str, gamedir ) ) { // shutdown the cgame module first in case it is running for whatever reason // (happens on wswtv in lobby), otherwise precaches that are going to follow // will probably f**k up (like models trying to load before the world model) CL_GameModule_Shutdown(); if( !FS_SetGameDirectory( str, true ) ) Com_Error( ERR_DROP, "Failed to load game directory set by server: %s", str ); ML_Restart( true ); } // parse player entity number cl.playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( cl.servermessage, MSG_ReadString( msg ), sizeof( cl.servermessage ) ); sv_bitflags = MSG_ReadByte( msg ); if( cls.demo.playing ) { cls.reliable = ( sv_bitflags & SV_BITFLAGS_RELIABLE ); } else { if( cls.reliable != ( ( sv_bitflags & SV_BITFLAGS_RELIABLE ) != 0 ) ) Com_Error( ERR_DROP, "Server and client disagree about connection reliability" ); } // builting HTTP server port if( cls.httpbaseurl ) { Mem_Free( cls.httpbaseurl ); cls.httpbaseurl = NULL; } if( ( sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url cls.httpbaseurl = ZoneCopyString( MSG_ReadString( msg ) ); } else { http_portnum = MSG_ReadShort( msg ) & 0xffff; cls.httpaddress = cls.serveraddress; if( cls.httpaddress.type == NA_IP6 ) { cls.httpaddress.address.ipv6.port = BigShort( http_portnum ); } else { cls.httpaddress.address.ipv4.port = BigShort( http_portnum ); } if( http_portnum ) { if( cls.httpaddress.type == NA_LOOPBACK ) { cls.httpbaseurl = ZoneCopyString( va( "http://localhost:%hu/", http_portnum ) ); } else { cls.httpbaseurl = ZoneCopyString( va( "http://%s/", NET_AddressToString( &cls.httpaddress ) ) ); } } } } // pure list // clean old, if necessary Com_FreePureList( &cls.purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &cls.purelist, pakname, checksum, NULL ); numpure--; } //assert( numpure == 0 ); // get the configstrings request CL_AddReliableCommand( va( "configstrings %i 0", cl.servercount ) ); cls.sv_pure = ( sv_bitflags & SV_BITFLAGS_PURE ) != 0; cls.sv_tv = ( sv_bitflags & SV_BITFLAGS_TVSERVER ) != 0; #ifdef PURE_CHEAT cls.sv_pure = false; #endif cls.wakelock = Sys_AcquireWakeLock(); if( !cls.demo.playing && ( cls.serveraddress.type == NA_IP ) ) Steam_AdvertiseGame( cls.serveraddress.address.ipv4.ip, NET_GetAddressPort( &cls.serveraddress ) ); // separate the printfs so the server message can have a color Com_Printf( S_COLOR_WHITE "\n" "=====================================\n" ); Com_Printf( S_COLOR_WHITE "%s\n\n", cl.servermessage ); }
/* <667f7> ../engine/net_chan.c:1789 */ qboolean Netchan_CopyFileFragments(netchan_t *chan) { fragbuf_t *p; int nsize; unsigned char *buffer; int pos; signed int cursize; char filename[MAX_PATH]; char compressor[32]; fragbuf_s *n; qboolean bCompressed; unsigned int uncompressedSize; if (!chan->incomingready[FRAG_FILE_STREAM]) return FALSE; p = chan->incomingbufs[FRAG_FILE_STREAM]; if (!p) { Con_Printf("Netchan_CopyFileFragments: Called with no fragments readied\n"); chan->incomingready[FRAG_FILE_STREAM] = FALSE; return FALSE; } bCompressed = FALSE; SZ_Clear(&net_message); MSG_BeginReading(); SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize); Q_strncpy(filename, MSG_ReadString(), sizeof(filename) - 1); filename[sizeof(filename) - 1] = 0; Q_strncpy(compressor, MSG_ReadString(), sizeof(compressor) - 1); compressor[sizeof(compressor) - 1] = 0; if (!Q_stricmp(compressor, "bz2")) bCompressed = TRUE; uncompressedSize = (unsigned int)MSG_ReadLong(); #ifdef REHLDS_FIXES if (uncompressedSize > 1024 * 64) { Con_Printf("Received too large file (size=%u)\nFlushing input queue\n", uncompressedSize); Netchan_FlushIncoming(chan, 1); return FALSE; } #endif if (Q_strlen(filename) <= 0) { Con_Printf("File fragment received with no filename\nFlushing input queue\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } if (Q_strstr(filename, "..")) { Con_Printf("File fragment received with relative path, ignoring\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } if (filename[0] != '!' && !IsSafeFileToDownload(filename)) { Con_Printf("File fragment received with bad path, ignoring\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } if (g_pcls.state != ca_dedicated && filename[0] != '!') { Con_Printf("File fragment received with bad path, ignoring (2)\n"); Netchan_FlushIncoming(chan, 1); return FALSE; } Q_strncpy(chan->incomingfilename, filename, MAX_PATH - 1); chan->incomingfilename[MAX_PATH - 1] = 0; if (filename[0] != '!' && FS_FileExists(filename)) { Con_Printf("Can't download %s, already exists\n", filename); Netchan_FlushIncoming(chan, 1); return TRUE; } nsize = 0; while (p) { nsize += p->frag_message.cursize; if (p == chan->incomingbufs[FRAG_FILE_STREAM]) nsize -= msg_readcount; p = p->next; }; buffer = (unsigned char*)Mem_ZeroMalloc(nsize + 1); if (!buffer) { Con_Printf("Buffer allocation failed on %i bytes\n", nsize + 1); Netchan_FlushIncoming(chan, 1); return FALSE; } p = chan->incomingbufs[FRAG_FILE_STREAM]; pos = 0; while (p) { n = p->next; cursize = p->frag_message.cursize; // First message has the file name, don't write that into the data stream, just write the rest of the actual data if (p == chan->incomingbufs[FRAG_FILE_STREAM]) { // Copy it in cursize -= msg_readcount; Q_memcpy(&buffer[pos], &p->frag_message.data[msg_readcount], cursize); p->frag_message.cursize = cursize; } else { Q_memcpy(&buffer[pos], p->frag_message.data, cursize); } pos += p->frag_message.cursize; Mem_Free(p); p = n; } if (bCompressed) { unsigned char* uncompressedBuffer = (unsigned char*)Mem_Malloc(uncompressedSize); Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, nsize, uncompressedSize); BZ2_bzBuffToBuffDecompress((char*)uncompressedBuffer, &uncompressedSize, (char*)buffer, nsize, 1, 0); Mem_Free(buffer); pos = uncompressedSize; buffer = uncompressedBuffer; } if (filename[0] == '!') { if (chan->tempbuffer) { Con_DPrintf("Netchan_CopyFragments: Freeing holdover tempbuffer\n"); Mem_Free(chan->tempbuffer); } chan->tempbuffer = buffer; chan->tempbuffersize = pos; } else { #ifdef REHLDS_FIXES //Don't allow to write files to FS on server if (chan == &g_pcls.netchan) #endif // REHLDS_FIXES { char filedir[MAX_PATH]; char *pszFileName; FileHandle_t handle; #ifdef REHLDS_CHECKS Q_strncpy(filedir, filename, sizeof(filedir) - 1); filedir[sizeof(filedir) - 1] = 0; #else Q_strncpy(filedir, filename, sizeof(filedir)); #endif // REHLDS_CHECKS COM_FixSlashes(filedir); pszFileName = strrchr(filedir, '\\'); if (pszFileName) { *pszFileName = 0; #ifdef REHLDS_FIXES FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD"); #endif } #ifndef REHLDS_FIXES FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD"); #endif handle = FS_OpenPathID(filename, "wb", "GAMEDOWNLOAD"); if (!handle) { Con_Printf("File open failed %s\n", filename); Netchan_FlushIncoming(chan, 1); #ifdef REHLDS_FIXES Mem_Free(buffer); #endif return FALSE; } Sys_Printf("COM_WriteFile: %s\n", filename); FS_Write(buffer, pos, 1, handle); FS_Close(handle); } Mem_Free(buffer); } SZ_Clear(&net_message); chan->incomingbufs[FRAG_FILE_STREAM] = 0; chan->incomingready[FRAG_FILE_STREAM] = 0; msg_readcount = 0; return TRUE; }
/* * CL_ParseServerMessage */ void CL_ParseServerMessage( msg_t *msg ) { int cmd; if( cl_shownet->integer == 1 ) { Com_Printf( "%i ", msg->cursize ); } else if( cl_shownet->integer >= 2 ) { Com_Printf( "------------------\n" ); } // parse the message while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Bad server message" ); break; } cmd = MSG_ReadByte( msg ); if( cl_debug_serverCmd->integer & 4 ) { if( cmd == -1 ) Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, "EOF" ); else Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, !svc_strings[cmd] ? "bad" : svc_strings[cmd] ); } if( cmd == -1 ) { SHOWNET( msg, "END OF MESSAGE" ); break; } if( cl_shownet->integer >= 2 ) { if( !svc_strings[cmd] ) Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd ); else SHOWNET( msg, svc_strings[cmd] ); } // other commands switch( cmd ) { default: Com_Error( ERR_DROP, "CL_ParseServerMessage: Illegible server message" ); break; case svc_nop: // Com_Printf( "svc_nop\n" ); break; case svc_servercmd: if( !cls.reliable ) { int cmdNum = MSG_ReadLong( msg ); if( cmdNum < 0 ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Invalid cmdNum value received: %i\n", cmdNum ); return; } if( cmdNum <= cls.lastExecutedServerCommand ) { MSG_ReadString( msg ); // read but ignore break; } cls.lastExecutedServerCommand = cmdNum; } // fall through case svc_servercs: // configstrings from demo files. they don't have acknowledge CL_ParseServerCommand( msg ); break; case svc_serverdata: if( cls.state == CA_HANDSHAKE ) { Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); } else { return; // ignore rest of the packet (serverdata is always sent alone) } break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_download: CL_ParseDownload( msg ); break; case svc_clcack: if( cls.reliable ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: clack message for reliable client\n" ); return; } cls.reliableAcknowledge = (unsigned)MSG_ReadLong( msg ); cls.ucmdAcknowledged = (unsigned)MSG_ReadLong( msg ); if( cl_debug_serverCmd->integer & 4 ) Com_Printf( "svc_clcack:reliable cmd ack:%i ucmdack:%i\n", cls.reliableAcknowledge, cls.ucmdAcknowledged ); break; case svc_frame: CL_ParseFrame( msg ); break; case svc_demoinfo: assert( cls.demo.playing ); { size_t meta_data_maxsize; MSG_ReadLong( msg ); MSG_ReadLong( msg ); cls.demo.meta_data_realsize = (size_t)MSG_ReadLong( msg ); meta_data_maxsize = (size_t)MSG_ReadLong( msg ); // sanity check if( cls.demo.meta_data_realsize > meta_data_maxsize ) { cls.demo.meta_data_realsize = meta_data_maxsize; } if( cls.demo.meta_data_realsize > sizeof( cls.demo.meta_data ) ) { cls.demo.meta_data_realsize = sizeof( cls.demo.meta_data ); } MSG_ReadData( msg, cls.demo.meta_data, cls.demo.meta_data_realsize ); MSG_SkipData( msg, meta_data_maxsize - cls.demo.meta_data_realsize ); } break; case svc_playerinfo: case svc_packetentities: case svc_match: Com_Error( ERR_DROP, "Out of place frame data" ); break; case svc_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; } } CL_AddNetgraph(); // // if recording demos, copy the message out // // // we don't know if it is ok to save a demo message until // after we have parsed the frame // if( cls.demo.recording && !cls.demo.waiting ) CL_WriteDemoMessage( msg ); }
/* * CL_ParseDownload * Handles download message from the server. * Writes data to the file and requests next download block. */ static void CL_ParseDownload( msg_t *msg ) { size_t size, offset; char *svFilename; // read the data svFilename = MSG_ReadString( msg ); offset = MSG_ReadLong( msg ); size = MSG_ReadLong( msg ); if( cls.demo.playing ) { // ignore download commands coming from demo files return; } if( msg->readcount + size > msg->cursize ) { Com_Printf( "Error: Download message didn't have as much data as it promised\n" ); CL_RetryDownload(); return; } if( !cls.download.filenum ) { Com_Printf( "Error: Download message while not dowloading\n" ); msg->readcount += size; return; } if( Q_stricmp( cls.download.name, svFilename ) ) { Com_Printf( "Error: Download message for wrong file\n" ); msg->readcount += size; return; } if( offset+size > cls.download.size ) { Com_Printf( "Error: Invalid download message\n" ); msg->readcount += size; CL_RetryDownload(); return; } if( cls.download.offset != offset ) { Com_Printf( "Error: Download message for wrong position\n" ); msg->readcount += size; CL_RetryDownload(); return; } FS_Write( msg->data + msg->readcount, size, cls.download.filenum ); msg->readcount += size; cls.download.offset += size; cls.download.percent = (double)cls.download.offset / (double)cls.download.size; clamp( cls.download.percent, 0, 1 ); Cvar_ForceSet( "cl_download_percent", va( "%.1f", cls.download.percent * 100 ) ); if( cls.download.offset < cls.download.size ) { cls.download.timeout = Sys_Milliseconds() + 3000; cls.download.retries = 0; CL_AddReliableCommand( va( "nextdl \"%s\" %i", cls.download.name, cls.download.offset ) ); } else { Com_Printf( "Download complete: %s\n", cls.download.name ); CL_DownloadComplete(); // let the server know we're done CL_AddReliableCommand( va( "nextdl \"%s\" %i", cls.download.name, -1 ) ); CL_StopServerDownload(); CL_DownloadDone(); } }
void CDanBattleFunc::RecvCC_SuggestBattle() { if ( !IsGuildMasters( g_curPC ) ) return; REQUEST_RECORD reqRecord; REQUEST_RECORD sugRecord; reqRecord.No = 0; reqRecord.ServerNo = g_config.gameServerNo; reqRecord.ServerID = g_curPC->idx; reqRecord.DanIdx = g_curPC->guildIdx; memcpy(reqRecord.DanName,g_curPC->guildName,GUILDNAMESTRING); memcpy(reqRecord.MasterName,g_curPC->name,NAMESTRING); if ( !g_pDanBattleManager->isSuggester(&reqRecord)) { SendErrorCode(&g_curPC->sock,GSC_DAN_BATTLE,1,0); return; } if ( g_curPC->curChargeSE < g_logic.DanBattlePrice) { SendGSM_SuggestResult(2); return; } sugRecord.DanIdx=MSG_ReadLong(); sstrncpy( sugRecord.DanName, MSG_ReadString(), GUILDNAMESTRING - 1 ); if ( !g_pDanBattleManager->SetSuggester(&sugRecord)) { SendErrorCode(&g_curPC->sock,GSC_DAN_BATTLE,1,0); return; } LPREQUEST_RECORD pSuggest=g_pDanBattleManager->GetSuggester(); MSG_BeginWriting(&netMessage); MSG_Clear( &netMessage ); MSG_WriteByte(&netMessage, GSC_EXTEND); MSG_WriteByte(&netMessage, GSC_DAN_BATTLE); MSG_WriteByte(&netMessage, DANB_SUGGEST_BATTLE); LPREQUEST_RECORD pSugg=static_cast<LPREQUEST_RECORD>(g_pDanBattleManager->GetRequestPointer(&sugRecord)); if ( pSuggest->ServerID >= MAX_PCS || pSuggest->ServerID <0) return; NET_SendUnreliableMessage(&g_pc[pSuggest->ServerID].sock, &netMessage); MSG_EndWriting(&netMessage); }
/* ================ CL_ParseConfigString ================ */ void CL_ParseConfigString (void) { int i; char *s; char olds[MAX_QPATH]; i = MSG_ReadShort (&net_message); if (i < 0 || i >= MAX_CONFIGSTRINGS) Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS"); s = MSG_ReadString(&net_message); strncpy (olds, cl.configstrings[i], sizeof(olds)); olds[sizeof(olds) - 1] = 0; strcpy (cl.configstrings[i], s); // do something apropriate // Knightmare- 1/2/2002- BIG UGLY HACK for old demos or // connected to server using old protocol // Changed config strings require different parsing if ( LegacyProtocol()) { if (i >= OLD_CS_LIGHTS && i < OLD_CS_LIGHTS+MAX_LIGHTSTYLES) CL_SetLightstyle (i - OLD_CS_LIGHTS); else if (i == CS_CDTRACK) { if (cl.refresh_prepped) CL_PlayBackgroundTrack (); } else if (i >= CS_MODELS && i < CS_MODELS+OLD_MAX_MODELS) { if (cl.refresh_prepped) { cl.model_draw[i-CS_MODELS] = R_RegisterModel (cl.configstrings[i]); if (cl.configstrings[i][0] == '*') cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]); else cl.model_clip[i-CS_MODELS] = NULL; } } else if (i >= OLD_CS_SOUNDS && i < OLD_CS_SOUNDS+OLD_MAX_SOUNDS) { if (cl.refresh_prepped) cl.sound_precache[i-OLD_CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]); } else if (i >= OLD_CS_IMAGES && i < OLD_CS_IMAGES+OLD_MAX_IMAGES) { if (cl.refresh_prepped) cl.image_precache[i-OLD_CS_IMAGES] = R_DrawFindPic (cl.configstrings[i]); } else if (i >= OLD_CS_PLAYERSKINS && i < OLD_CS_PLAYERSKINS+MAX_CLIENTS) { if (cl.refresh_prepped && strcmp(olds, s)) CL_ParseClientinfo (i-OLD_CS_PLAYERSKINS); } } else // new configstring offsets { if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES) CL_SetLightstyle (i - CS_LIGHTS); else if (i == CS_CDTRACK) { if (cl.refresh_prepped) CL_PlayBackgroundTrack (); } else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS) { if (cl.refresh_prepped) { cl.model_draw[i-CS_MODELS] = R_RegisterModel (cl.configstrings[i]); if (cl.configstrings[i][0] == '*') cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]); else cl.model_clip[i-CS_MODELS] = NULL; } } else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_SOUNDS) //Knightmare- was MAX_MODELS { if (cl.refresh_prepped) cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]); } else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_IMAGES) //Knightmare- was MAX_MODELS { if (cl.refresh_prepped) cl.image_precache[i-CS_IMAGES] = R_DrawFindPic (cl.configstrings[i]); } else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS) { if (cl.refresh_prepped && strcmp(olds, s)) CL_ParseClientinfo (i-CS_PLAYERSKINS); } } //end Knightmare }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("CL_ParseServerMessage: Illegible server message\n"); break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: i = MSG_ReadShort (); CL_ParseClientdata (i); break; case svc_version: i = MSG_ReadLong (); if (i != PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); strcpy (cl.scores[i].name, MSG_ReadString ()); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i)); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: { cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); #ifdef _WIN32 VID_HandlePause (true); #endif } else { CDAudio_Resume (); #ifdef _WIN32 VID_HandlePause (false); #endif } } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; } } }
// Do very shallow parse of the demo (could be extended) just to get times and snapshot count static void CL_ParseDemo(void) { int tstart = 0; int demofile = 0; // Reset our demo data memset(&di, 0, sizeof(di)); // Parse start di.gameStartTime = -1; di.gameEndTime = -1; FS_Seek(clc.demofile, 0, FS_SEEK_SET); tstart = Sys_Milliseconds(); while (qtrue) { int r; msg_t buf; msg_t *msg; byte bufData[MAX_MSGLEN]; int s; int cmd; di.demoPos = FS_FTell(clc.demofile); // get the sequence number r = FS_Read(&s, 4, clc.demofile); if (r != 4) { CL_DemoCompleted(); return; } clc.serverMessageSequence = LittleLong(s); // init the message MSG_Init(&buf, bufData, sizeof(bufData)); // get the length r = FS_Read(&buf.cursize, 4, clc.demofile); if (r != 4) { break; } buf.cursize = LittleLong(buf.cursize); if (buf.cursize == -1) { break; } if (buf.cursize > buf.maxsize) { Com_FuncDPrinf("demoMsglen > MAX_MSGLEN"); break; } r = FS_Read(buf.data, buf.cursize, clc.demofile); if (r != buf.cursize) { Com_FuncDPrinf("Demo file was truncated.\n"); break; } clc.lastPacketTime = cls.realtime; buf.readcount = 0; // parse msg = &buf; MSG_Bitstream(msg); // get the reliable sequence acknowledge number clc.reliableAcknowledge = MSG_ReadLong(msg); if (clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS) { clc.reliableAcknowledge = clc.reliableSequence; } // parse the message while (qtrue) { if (msg->readcount > msg->cursize) { Com_FuncDrop("read past end of server message"); break; } cmd = MSG_ReadByte(msg); if (cmd == svc_EOF) { break; } // other commands switch (cmd) { default: Com_FuncDrop("Illegible server message %d", cmd); break; case svc_nop: break; case svc_serverCommand: MSG_ReadLong(msg); MSG_ReadString(msg); break; case svc_gamestate: clc.serverCommandSequence = MSG_ReadLong(msg); cl.gameState.dataCount = 1; while (qtrue) { int cmd2 = MSG_ReadByte(msg); if (cmd2 == svc_EOF) { break; } if (cmd2 == svc_configstring) { MSG_ReadShort(msg); MSG_ReadBigString(msg); } else if (cmd2 == svc_baseline) { entityState_t s1, s2; memset(&s1, 0, sizeof(s1)); memset(&s2, 0, sizeof(s2)); MSG_ReadBits(msg, GENTITYNUM_BITS); MSG_ReadDeltaEntity(msg, &s1, &s2, 0); } else { Com_FuncDrop("bad command byte"); } } MSG_ReadLong(msg); MSG_ReadLong(msg); break; case svc_snapshot: CL_ParseDemoSnapShotSimple(msg); break; case svc_download: MSG_ReadShort(msg); break; } } if (!cl.snap.valid) { Com_FuncDPrinf("!cl.snap.valid\n"); continue; } if (cl.snap.serverTime < cl.oldFrameServerTime) { // ignore snapshots that don't have entities if (cl.snap.snapFlags & SNAPFLAG_NOT_ACTIVE) { continue; } cls.state = CA_ACTIVE; // set the timedelta so we are exactly on this first frame cl.serverTimeDelta = cl.snap.serverTime - cls.realtime; cl.oldServerTime = cl.snap.serverTime; clc.timeDemoBaseTime = cl.snap.serverTime; } cl.oldFrameServerTime = cl.snap.serverTime; if (cl.newSnapshots) { CL_AdjustTimeDelta(); } di.lastServerTime = cl.snap.serverTime; if (di.firstServerTime == 0) { di.firstServerTime = cl.snap.serverTime; Com_FuncPrinf("firstServerTime %d\n", di.firstServerTime); } di.snapsInDemo++; } Com_FuncDPrinf("Snaps in demo: %i\n", di.snapsInDemo); Com_FuncDPrinf("last serverTime %d total %f minutes\n", cl.snap.serverTime, (cl.snap.serverTime - di.firstServerTime) / 1000.0 / 60.0); Com_FuncDPrinf("parse time %f seconds\n", (float)(Sys_Milliseconds() - tstart) / 1000.0); FS_Seek(clc.demofile, 0, FS_SEEK_SET); clc.demoplaying = qfalse; demofile = clc.demofile; CL_ClearState(); Com_Memset(&clc, 0, sizeof(clc)); clc.demofile = demofile; cls.state = CA_DISCONNECTED; cl_connectedToPureServer = qfalse; dpi.firstTime = di.firstServerTime; dpi.lastTime = di.lastServerTime; }
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; } } }
static void _Datagram_SearchForHosts(qboolean xmit) { int ret; int n; int i; struct qsockaddr readaddr; struct qsockaddr myaddr; int control; dfunc.GetSocketAddr(dfunc.controlSock, &myaddr); if (xmit) { SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); MSG_WriteString(&net_message, "QUAKE"); MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); SZ_Clear(&net_message); } while ((ret = dfunc.Read(dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) { if (ret < sizeof(int)) { continue; } net_message.cursize = ret; // don't answer our own query if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) { continue; } // is the cache full? if (hostCacheCount == HOSTCACHESIZE) { continue; } MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { continue; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { continue; } if ((control & NETFLAG_LENGTH_MASK) != ret) { continue; } if (MSG_ReadByte() != CCREP_SERVER_INFO) { continue; } dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); // search the cache for this server for (n = 0; n < hostCacheCount; n++) if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) { break; } // is it already there? if (n < hostCacheCount) { continue; } // add it hostCacheCount++; Q_strcpy(hostcache[n].name, MSG_ReadString()); Q_strcpy(hostcache[n].map, MSG_ReadString()); hostcache[n].users = MSG_ReadByte(); hostcache[n].maxusers = MSG_ReadByte(); if (MSG_ReadByte() != NET_PROTOCOL_VERSION) { Q_strcpy(hostcache[n].cname, hostcache[n].name); hostcache[n].cname[14] = 0; Q_strcpy(hostcache[n].name, "*"); Q_strcat(hostcache[n].name, hostcache[n].cname); } Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); hostcache[n].driver = net_driverlevel; hostcache[n].ldriver = net_landriverlevel; Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); // check for a name conflict for (i = 0; i < hostCacheCount; i++) { if (i == n) { continue; } if (Q_strcasecmp(hostcache[n].name, hostcache[i].name) == 0) { i = Q_strlen(hostcache[n].name); if (i < 15 && hostcache[n].name[i-1] > '8') { hostcache[n].name[i] = '0'; hostcache[n].name[i+1] = 0; } else { hostcache[n].name[i-1]++; } i = -1; } } } }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (net_message); while (1) { if (!host_client->active) return false; // a command caused an error if (net_message->badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (net_message); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("SV_ReadClientMessage: clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (net_message); ret = 0; if (nehahra) { if (strncasecmp(s, "max", 3) == 0) ret = 1; else if (strncasecmp(s, "monster", 7) == 0) ret = 1; else if (strncasecmp(s, "scrag", 5) == 0) ret = 1; else if (strncasecmp(s, "wraith", 6) == 0) ret = 1; else if (strncasecmp(s, "gimme", 5) == 0) ret = 1; } else { if (strncasecmp(s, "god", 3) == 0) ret = 1; else if (strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (strncasecmp(s, "fly", 3) == 0) ret = 1; else if (strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (strncasecmp(s, "give", 4) == 0) ret = 1; } if (strncasecmp(s, "status", 6) == 0) ret = 1; else if (strncasecmp(s, "freezeall", 9) == 0) ret = 1; else if (strncasecmp(s, "name", 4) == 0) ret = 1; else if (strncasecmp(s, "say", 3) == 0) ret = 1; else if (strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (strncasecmp(s, "tell", 4) == 0) ret = 1; else if (strncasecmp(s, "color", 5) == 0) ret = 1; else if (strncasecmp(s, "kill", 4) == 0) ret = 1; else if (strncasecmp(s, "pause", 5) == 0) ret = 1; else if (strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (strncasecmp(s, "begin", 5) == 0) ret = 1; else if (strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (strncasecmp(s, "kick", 4) == 0) ret = 1; else if (strncasecmp(s, "ping", 4) == 0) ret = 1; else if (strncasecmp(s, "ban", 3) == 0) ret = 1; else if (strncasecmp(s, "qcexec", 6) == 0) ret = 1; // qcexec command for qc testing if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
static void Test2_Poll(void) { struct qsockaddr clientaddr; int control; int len; char name[256]; char value[256]; net_landriverlevel = test2Driver; name[0] = 0; len = dfunc.Read(test2Socket, net_message.data, net_message.maxsize, &clientaddr); if (len < sizeof(int)) { goto Reschedule; } net_message.cursize = len; MSG_BeginReading(); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) { goto Error; } if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { goto Error; } if ((control & NETFLAG_LENGTH_MASK) != len) { goto Error; } if (MSG_ReadByte() != CCREP_RULE_INFO) { goto Error; } Q_strcpy(name, MSG_ReadString()); if (name[0] == 0) { goto Done; } Q_strcpy(value, MSG_ReadString()); Con_Printf("%-16.16s %-16.16s\n", name, value); SZ_Clear(&net_message); // save space for the header, filled in later MSG_WriteLong(&net_message, 0); MSG_WriteByte(&net_message, CCREQ_RULE_INFO); MSG_WriteString(&net_message, name); *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); dfunc.Write(test2Socket, net_message.data, net_message.cursize, &clientaddr); SZ_Clear(&net_message); Reschedule: SchedulePollProcedure(&test2PollProcedure, 0.05); return; Error: Con_Printf("Unexpected repsonse to Rule Info request\n"); Done: dfunc.CloseSocket(test2Socket); test2InProgress = false; return; }
void CHelperManager::ProcessMessage_Invite_REQ_fromHELPER(playerCharacter_t* pHelper) { if(TRUE == IsBadWritePtr(pHelper,sizeof(playerCharacter_t)) || TRUE == IsBadReadPtr(pHelper,sizeof(playerCharacter_t))) { return; } if( tagHelper::tagMemberList::HELPER != pHelper->tHelper.List.mode) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidMode ); g_logSystem->Write("Fail_RegistrationRequest_invalidMode" ); return ; } char cz_tempTakerName[NAMESTRING+1]; strncpy(cz_tempTakerName,MSG_ReadString(),NAMESTRING); cz_tempTakerName[NAMESTRING]=NULL; int idx = GTH_FindPCByName(cz_tempTakerName); playerCharacter_t * pTaker=gcpTools->GetPlayerRecordPointer(idx); if(NULL == pTaker){ SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidUser); g_logSystem->Write("Fail_RegistrationRequest_invalidUser" ); return; } if( tagHelper::tagMemberList::TAKER != pTaker->tHelper.List.mode) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidTakerMode ); g_logSystem->Write("Fail_RegistrationRequest_invalidMode" ); return ; } if(pTaker->idx == pHelper->idx) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidUser); g_logSystem->Write("Fail_RegistrationRequest_invalidUser" ); return; } if ( pHelper->tHelper.List.count > tagHelper::MAX_MEMBER) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidTakersCount); g_logSystem->Write("Fail_RegistrationRequest_invalidTakersCount" ); return; } if(pTaker->tHelper.List.count >= tagHelper::MAX_Accept_HELPERS) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidHelperCount); g_logSystem->Write("Fail_RegistrationRequest_invalidHelperCount" ); return; } if ( pHelper->worldIdx != pTaker->worldIdx ) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invalidWorldIndex); g_logSystem->Write("Fail_RegistrationRequest_invalidWorldIndex" ); return ; } if(TRUE == isMyChild(pHelper,pTaker->name)) { SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Fail_RegistrationRequest_invaliChild); g_logSystem->Write("Fail_RegistrationRequest_invaliChild" ); return ; } strncpy(pTaker->HelperAdd.RequestPlayer.Name,pHelper->name,NAMESTRING); pTaker->HelperAdd.RequestPlayer.Name[NAMESTRING]=NULL; pTaker->HelperAdd.RequestPlayer.pcIdx=pHelper->idx; SendMessage_Invite_Respond_toHelper( pHelper,tagHelperPacket_SC_INVITE_RES_toHELPER::Ready_Registration); ShowLogInfo("Helper_Invite_Suggest: name:%s,level:%d ",pHelper->name,pHelper->level); SendMessage_Invite_Request_toTaker( pTaker,pHelper->name); ShowLogInfo("Helper_Invite_Suggest: name:%s,level:%d ",pTaker->name,pTaker->level); }
/* ===================== CL_ParseDownload A download message has been received from the server ===================== */ void CL_ParseDownload( msg_t *msg ) { int size; unsigned char data[ MAX_MSGLEN ]; int block; if ( !*cls.downloadTempName ) { Com_Printf( "Server sending download, but no download was requested\n" ); // Eat the packet anyway block = MSG_ReadShort( msg ); if (block == -1) { MSG_ReadString( msg ); MSG_ReadLong( msg ); MSG_ReadLong( msg ); } else if (block != 0) { size = MSG_ReadShort( msg ); if ( size < 0 || size > (int) sizeof( data ) ) { Com_Error( ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size ); } MSG_ReadData( msg, data, size ); } CL_AddReliableCommand( "stopdl" ); return; } // read the data block = MSG_ReadShort( msg ); // TTimo - www dl // if we haven't acked the download redirect yet if ( block == -1 ) { if ( !clc.bWWWDl ) { // server is sending us a www download Q_strncpyz( cls.originalDownloadName, cls.downloadName, sizeof( cls.originalDownloadName ) ); Q_strncpyz( cls.downloadName, MSG_ReadString( msg ), sizeof( cls.downloadName ) ); clc.downloadSize = MSG_ReadLong( msg ); clc.downloadFlags = MSG_ReadLong( msg ); downloadLogger.Debug("Server sent us a new WWW DL '%s', size %i, flags %i", cls.downloadName, clc.downloadSize, clc.downloadFlags); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); clc.bWWWDl = true; // activate wwwdl client loop CL_AddReliableCommand( "wwwdl ack" ); cls.state = CA_DOWNLOADING; // make sure the server is not trying to redirect us again on a bad checksum if ( strstr( clc.badChecksumList, va( "@%s", cls.originalDownloadName ) ) ) { Com_Printf( "refusing redirect to %s by server (bad checksum)\n", cls.downloadName ); CL_AddReliableCommand( "wwwdl fail" ); clc.bWWWDlAborting = true; return; } if ( !DL_BeginDownload( cls.downloadTempName, cls.downloadName ) ) { // setting bWWWDl to false after sending the wwwdl fail doesn't work // not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us // still leave a flag so that CL_WWWDownload is inactive // we count on server sending us a gamestate to start up clean again CL_AddReliableCommand( "wwwdl fail" ); clc.bWWWDlAborting = true; Com_Printf( "Failed to initialize download for '%s'\n", cls.downloadName ); } // Check for a disconnected download // we'll let the server disconnect us when it gets the bbl8r message if ( clc.downloadFlags & ( 1 << DL_FLAG_DISCON ) ) { CL_AddReliableCommand( "wwwdl bbl8r" ); cls.bWWWDlDisconnected = true; } return; } else { // server keeps sending that message till we ack it, eat and ignore //MSG_ReadLong( msg ); MSG_ReadString( msg ); MSG_ReadLong( msg ); MSG_ReadLong( msg ); return; } } if ( !block ) { // block zero is special, contains file size clc.downloadSize = MSG_ReadLong( msg ); downloadLogger.Debug("Starting new direct download of size %i for '%s'", clc.downloadSize, cls.downloadTempName); Cvar_SetValue( "cl_downloadSize", clc.downloadSize ); if ( clc.downloadSize < 0 ) { Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) ); } } size = MSG_ReadShort( msg ); if ( size < 0 || size > (int) sizeof( data ) ) { Com_Error( ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size ); } downloadLogger.Debug("Received block of size %i", size); MSG_ReadData( msg, data, size ); if ( clc.downloadBlock != block ) { downloadLogger.Debug( "CL_ParseDownload: Expected block %i, got %i", clc.downloadBlock, block ); return; } // open the file if not opened yet if ( !clc.download ) { clc.download = FS_SV_FOpenFileWrite( cls.downloadTempName ); if ( !clc.download ) { Com_Printf( "Could not create %s\n", cls.downloadTempName ); CL_AddReliableCommand( "stopdl" ); CL_NextDownload(); return; } } if ( size ) { FS_Write( data, size, clc.download ); } CL_AddReliableCommand( va( "nextdl %d", clc.downloadBlock ) ); clc.downloadBlock++; clc.downloadCount += size; // So UI gets access to it Cvar_SetValue( "cl_downloadCount", clc.downloadCount ); if ( !size ) { downloadLogger.Debug("Received EOF, closing '%s'", cls.downloadTempName); // A zero length block means EOF if ( clc.download ) { FS_FCloseFile( clc.download ); clc.download = 0; // rename the file FS_SV_Rename( cls.downloadTempName, cls.downloadName ); } *cls.downloadTempName = *cls.downloadName = 0; Cvar_Set( "cl_downloadName", "" ); // send intentions now // We need this because without it, we would hold the last nextdl and then start // loading right away. If we take a while to load, the server is happily trying // to send us that last block over and over. // Write it twice to help make sure we acknowledge the download CL_WritePacket(); CL_WritePacket(); // get another file if needed CL_NextDownload(); } }
void CHelperManager::ProcessMessage_SC_REMOVE_NOTIFY_toPlayer() { int idx=-1; char removeName[NAMESTRING+1], playerName[NAMESTRING+1]; sstrncpy( removeName, MSG_ReadString(), NAMESTRING); removeName[NAMESTRING]=NULL; sstrncpy( playerName, MSG_ReadString(), NAMESTRING); playerName[NAMESTRING]=NULL; idx = GTH_FindPCByName(removeName); if (0 <= idx ) { playerCharacter_t* pRemover=gcpTools->GetPlayerRecordPointer(idx); if(NULL == pRemover) return; MSG_BeginWriting(&netMessage); MSG_Clear( &netMessage ); { MSG_WriteByte(&netMessage, EXTEND_SECOND); MSG_WriteShort( &netMessage, HELPER_SYSTEM ); MSG_WriteShort( &netMessage, SC_REMOVE_NOTIFY_toPlayer ); MSG_WriteString(&netMessage, playerName); NET_SendUnreliableMessage(&pRemover->sock, &netMessage); } MSG_EndWriting(&netMessage); GTH_SendMessage_AckMessage(playerName); } else { if (TRUE == g_config.isManager ) { int fromMemberIdx = MSG_ReadByte(); MSG_BeginWriting(&netMessage); MSG_Clear( &netMessage ); { MSG_WriteByte(&netMessage, EXTEND_SECOND); MSG_WriteShort( &netMessage, HELPER_SYSTEM ); MSG_WriteShort( &netMessage, SS_REMOVE_NOTIFY_toPlayer ); MSG_WriteString(&netMessage, removeName); MSG_WriteString(&netMessage, playerName); for (int gameseridx=1; gameseridx < MAX_MEMBER_SERVER; gameseridx++) { if ( !g_memberServer[gameseridx].active ) continue; if ( gameseridx == fromMemberIdx ) continue; NET_SendUnreliableMessage(&g_memberServer[gameseridx].sock, &netMessage); } } MSG_EndWriting(&netMessage); } } }
/* =================== SV_ReadClientMessage Returns false if the client should be killed =================== */ qboolean SV_ReadClientMessage (void) { int ret; int cmd; char *s; do { nextmsg: ret = NET_GetMessage (host_client->netconnection); if (ret == -1) { Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); return false; } if (!ret) return true; MSG_BeginReading (); while (1) { if (!host_client->active) return false; // a command caused an error if (msg_badread) { Sys_Printf ("SV_ReadClientMessage: badread\n"); return false; } cmd = MSG_ReadChar (); switch (cmd) { case -1: goto nextmsg; // end of message default: Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); return false; case clc_nop: // Sys_Printf ("clc_nop\n"); break; case clc_stringcmd: s = MSG_ReadString (); if (host_client->privileged) ret = 2; else ret = 0; if (Q_strncasecmp(s, "status", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "god", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "notarget", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "fly", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "name", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "noclip", 6) == 0) ret = 1; else if (Q_strncasecmp(s, "say", 3) == 0) ret = 1; else if (Q_strncasecmp(s, "say_team", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "tell", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "color", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "kill", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "pause", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "spawn", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "begin", 5) == 0) ret = 1; else if (Q_strncasecmp(s, "prespawn", 8) == 0) ret = 1; else if (Q_strncasecmp(s, "kick", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ping", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "give", 4) == 0) ret = 1; else if (Q_strncasecmp(s, "ban", 3) == 0) ret = 1; if (ret == 2) Cbuf_InsertText (s); else if (ret == 1) Cmd_ExecuteString (s, src_client); else Con_DPrintf("%s tried to %s\n", host_client->name, s); break; case clc_disconnect: // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); return false; case clc_move: SV_ReadClientMove (&host_client->cmd); break; } } } while (ret == 1); return true; }
void CHelperManager::ProcessMessage_ServerRequestSummons() { int idx =-1; char toName[NAMESTRING+1], summoner[NAMESTRING+1]; vec3_t position; strncpy(toName, MSG_ReadString(),NAMESTRING); toName[NAMESTRING]=NULL; strncpy(summoner, MSG_ReadString(),NAMESTRING); summoner[NAMESTRING]=NULL; int worldIdx = MSG_ReadByte(); MSG_ReadPosition( position ); idx = GTH_FindPCByName(toName); if (0 <= idx) { playerCharacter_t* pTaker=gcpTools->GetPlayerRecordPointer(idx); if(NULL == pTaker) return; if( (playerCharacter_t::tagGonryunBattlePractice::MEMBERSHIP_LEADER == pTaker->GonryunBattlePractice.MemberShip) || (playerCharacter_t::tagGonryunBattlePractice::MEMBERSHIP_OPENENT == pTaker->GonryunBattlePractice.MemberShip)) return; if( (pTaker->worldIdx == tagGolryunBattle::Golryun_Battle_Map_Index) || (pTaker->worldIdx == DAN_BATTLEMAP_NO)) return; if(BUSY_STATE_NONE != pTaker->busyState) return; PC_SetSummonsInfo(pTaker, summoner,worldIdx, position); MSG_BeginWriting(&netMessage); MSG_Clear( &netMessage ); { MSG_WriteByte(&netMessage, EXTEND_SECOND); MSG_WriteShort ( &netMessage, HELPER_SYSTEM); MSG_WriteShort(&netMessage, SC_SPAWN_Req_toTaker); MSG_WriteString(&netMessage, summoner); NET_SendMessage(&pTaker->sock, &netMessage); } MSG_EndWriting(&netMessage); } else { if (TRUE == g_config.isManager ) { int fromMemberIdx = MSG_ReadByte(); MSG_BeginWriting(&netMessage); MSG_Clear( &netMessage ); { MSG_WriteByte(&netMessage, EXTEND_SECOND); MSG_WriteShort ( &netMessage, HELPER_SYSTEM ); MSG_WriteShort(&netMessage, SS_SPAWN_Req_fromServer); MSG_WriteString(&netMessage, toName); MSG_WriteString(&netMessage, summoner); MSG_WriteByte(&netMessage, worldIdx); MSG_WritePosition(&netMessage, position); for (int serveridx =1; serveridx < MAX_MEMBER_SERVER; serveridx++) { if ( !g_memberServer[serveridx].active ) continue; if ( serveridx == fromMemberIdx ) continue; NET_SendUnreliableMessage(&g_memberServer[serveridx].sock, &netMessage); } } MSG_EndWriting(&netMessage); } } }
/* ================= CL_ConnectionlessPacket Responses to broadcasts, etc ================= */ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; const char *c; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 s = MSG_ReadStringLine( msg ); Cmd_TokenizeString( s ); c = Cmd_Argv(0); Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c); // challenge from the server we are connecting to if ( !strcmp(c, "challengeResponse") ) { if ( cls.state != CA_CONNECTING ) { Com_Printf( "Unwanted challenge response received. Ignored.\n" ); } else { // start sending challenge repsonse instead of challenge request packets clc.challenge = atoi(Cmd_Argv(1)); cls.state = CA_CHALLENGING; clc.connectPacketCount = 0; clc.connectTime = -99999; // take this address as the new server address. This allows // a server proxy to hand off connections to multiple servers clc.serverAddress = from; } return; } // server connection if ( !strcmp(c, "connectResponse") ) { if ( cls.state >= CA_CONNECTED ) { Com_Printf ("Dup connect received. Ignored.\n"); return; } if ( cls.state != CA_CHALLENGING ) { Com_Printf ("connectResponse packet while not connecting. Ignored.\n"); return; } if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) { Com_Printf( "connectResponse from a different address. Ignored.\n" ); Com_Printf( "%s should have been %s\n", NET_AdrToString( from ), NET_AdrToString( clc.serverAddress ) ); return; } Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableIntegerValue( "net_qport" ) ); cls.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; } // a disconnect message from the server, which will happen if the server // dropped the connection but it is still getting packets from us if (!strcmp(c, "disconnect")) { CL_DisconnectPacket( from ); return; } // echo request from server if ( !strcmp(c, "echo") ) { NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) ); return; } // print request from server if ( !strcmp(c, "print") ) { s = MSG_ReadString( msg ); UI_UpdateConnectionMessageString( s ); Com_Printf( "%s", s ); return; } Com_DPrintf ("Unknown connectionless packet command.\n"); }
/** * @brief A download message has been received from the server */ void CL_ParseDownload(msg_t *msg) { int size; unsigned char data[MAX_MSGLEN]; int block; if (!*cls.download.downloadTempName) { Com_Printf("Server sending download, but no download was requested\n"); CL_AddReliableCommand("stopdl"); return; } // read the data block = MSG_ReadShort(msg); // www dl, if we haven't acknowledged the download redirect yet if (block == DLTYPE_WWW) { if (!cls.download.bWWWDl) { // server is sending us a www download Q_strncpyz(cls.download.originalDownloadName, cls.download.downloadName, sizeof(cls.download.originalDownloadName)); Q_strncpyz(cls.download.downloadName, MSG_ReadString(msg), sizeof(cls.download.downloadName)); cls.download.downloadSize = MSG_ReadLong(msg); cls.download.downloadFlags = MSG_ReadLong(msg); if (cls.download.downloadFlags & (1 << DL_FLAG_URL)) { Sys_OpenURL(cls.download.downloadName, qtrue); Cbuf_ExecuteText(EXEC_APPEND, "quit\n"); CL_AddReliableCommand("wwwdl bbl8r"); // not sure if that's the right msg cls.download.bWWWDlAborting = qtrue; return; } Cvar_SetValue("cl_downloadSize", cls.download.downloadSize); Com_DPrintf("Server redirected download: %s\n", cls.download.downloadName); cls.download.bWWWDl = qtrue; // activate wwwdl client loop CL_AddReliableCommand("wwwdl ack"); // make sure the server is not trying to redirect us again on a bad checksum if (strstr(cls.download.badChecksumList, va("@%s", cls.download.originalDownloadName))) { Com_Printf("refusing redirect to %s by server (bad checksum)\n", cls.download.downloadName); CL_AddReliableCommand("wwwdl fail"); cls.download.bWWWDlAborting = qtrue; return; } // make downloadTempName an OS path Q_strncpyz(cls.download.downloadTempName, FS_BuildOSPath(Cvar_VariableString("fs_homepath"), cls.download.downloadTempName, ""), sizeof(cls.download.downloadTempName)); cls.download.downloadTempName[strlen(cls.download.downloadTempName) - 1] = '\0'; if (!DL_BeginDownload(cls.download.downloadTempName, cls.download.downloadName)) { // setting bWWWDl to false after sending the wwwdl fail doesn't work // not sure why, but I suspect we have to eat all remaining block -1 that the server has sent us // still leave a flag so that CL_WWWDownload is inactive // we count on server sending us a gamestate to start up clean again CL_AddReliableCommand("wwwdl fail"); cls.download.bWWWDlAborting = qtrue; Com_Printf("Failed to initialize download for '%s'\n", cls.download.downloadName); } // Check for a disconnected download // we'll let the server disconnect us when it gets the bbl8r message if (cls.download.downloadFlags & (1 << DL_FLAG_DISCON)) { CL_AddReliableCommand("wwwdl bbl8r"); cls.download.bWWWDlDisconnected = qtrue; } return; } else { // server keeps sending that message till we acknowledge it, eat and ignore //MSG_ReadLong( msg ); MSG_ReadString(msg); MSG_ReadLong(msg); MSG_ReadLong(msg); return; } } if (!block) { // block zero is special, contains file size cls.download.downloadSize = MSG_ReadLong(msg); Cvar_SetValue("cl_downloadSize", cls.download.downloadSize); if (cls.download.downloadSize < 0) { Com_Error(ERR_DROP, "%s", MSG_ReadString(msg)); return; } } size = MSG_ReadShort(msg); if (size < 0 || size > sizeof(data)) { Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size); return; } MSG_ReadData(msg, data, size); if (cls.download.downloadBlock != block) { Com_DPrintf("CL_ParseDownload: Expected block %d, got %d\n", cls.download.downloadBlock, block); return; } // open the file if not opened yet if (!cls.download.download) { cls.download.download = FS_SV_FOpenFileWrite(cls.download.downloadTempName); if (!cls.download.download) { Com_Printf("Could not create %s\n", cls.download.downloadTempName); CL_AddReliableCommand("stopdl"); Com_NextDownload(); return; } } if (size) { FS_Write(data, size, cls.download.download); } CL_AddReliableCommand(va("nextdl %d", cls.download.downloadBlock)); cls.download.downloadBlock++; cls.download.downloadCount += size; // So UI gets access to it Cvar_SetValue("cl_downloadCount", cls.download.downloadCount); if (!size) // A zero length block means EOF { if (cls.download.download) { FS_FCloseFile(cls.download.download); cls.download.download = 0; // rename the file FS_SV_Rename(cls.download.downloadTempName, cls.download.downloadName); } *cls.download.downloadTempName = *cls.download.downloadName = 0; Cvar_Set("cl_downloadName", ""); // send intentions now // We need this because without it, we would hold the last nextdl and then start // loading right away. If we take a while to load, the server is happily trying // to send us that last block over and over. // Write it twice to help make sure we acknowledge the download CL_WritePacket(); CL_WritePacket(); // get another file if needed Com_NextDownload(); } }
void CPostFunc::GTH_ProcessMessage_PostSystem_OpenWindow() { int PostIdx = 0; int PostCount = -1; enum tagGCPacket_POSTSYSTEM_OPEN::enumCode code = tagGCPacket_POSTSYSTEM_OPEN::enumCode::fail; code = static_cast<enum tagGCPacket_POSTSYSTEM_OPEN::enumCode>(MSG_ReadByte()); switch( code ) { case tagGCPacket_POSTSYSTEM_OPEN::enumCode::success: { PostCount = MSG_ReadLong(); g_cgv.myCharacterInfo->m_PostMng.InitPostSystem(); for ( PostIdx = 0; PostIdx < PostCount; PostIdx++) { CPostManager::PostPackage_t PostPackage; memset(&PostPackage, 0, sizeof(CPostManager::PostPackage_t) ); PostPackage.iPostIdx = MSG_ReadLong(); sstrncpy(PostPackage.szFromName, MSG_ReadString(), NAMESTRING); PostPackage.szFromName[NAMESTRING] = NULL; CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szFromName); sstrncpy(PostPackage.szPostTitle, MSG_ReadString(), CPostManager::POST_TITLESIZE); PostPackage.szPostTitle[CPostManager::POST_TITLESIZE] = NULL; CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szPostTitle); sstrncpy(PostPackage.szSendPostTime , MSG_ReadString(), CPostManager::POST_SENDTIME_INFO_STR_LEN); PostPackage.szSendPostTime[CPostManager::POST_SENDTIME_INFO_STR_LEN] = NULL; sstrncpy(PostPackage.szMailStr, MSG_ReadString(), CPostManager::POST_STRSIZE); PostPackage.szMailStr[CPostManager::POST_STRSIZE] = NULL; CTools::Replace_doubleQUOTATIONmark_by_singleQUOTATIONmark(PostPackage.szMailStr); int state = MSG_ReadLong(); if ( state == 0) PostPackage.MailState = CPostManager::enumPostPackageState::POSTPACKAGE_UNCHECK; else PostPackage.MailState = CPostManager::enumPostPackageState::POSTPACKAGE_CHECK; int nak = MSG_ReadLong(); PostPackage.Nak = nak; int SendType = MSG_ReadLong(); PostPackage.iRemainDays = MSG_ReadLong(); if ( SendType == 0) PostPackage.PostSendType = CPostManager::enumPostSendType::POST_SENDTYPE_WEB; else PostPackage.PostSendType = CPostManager::enumPostSendType::POST_SENDTYPE_CHAR; g_cgv.myCharacterInfo->m_PostMng.AddPostPackage(PostPackage); } g_ifMng->m_PostWin->InitIFPost(); g_ifMng->m_PostWin->SetDisplayMode(true); g_ifMng->m_chatWin->Enable( false ); g_ifMng->m_PostWin->Enable(1); g_ifMng->SetFocus( g_ifMng->m_PostWin ); } break; case tagGCPacket_POSTSYSTEM_OPEN::enumCode::fail: g_ifMng->SetMessage( g_LPACK.GetMassage(LPACK_TYPE_NORMAL, 322), g_LPACK.GetMassage(LPACK_TYPE_NORMAL2, 226) ); break; default: break; } }
qboolean CL_PeekSnapshot(int snapshotNumber, snapshot_t *snapshot) { clSnapshot_t *clSnap; clSnapshot_t csn; int i, count; int origPosition; int cmd; //char *s; char buffer[16]; qboolean success = qfalse; int r; msg_t buf; byte bufData[MAX_MSGLEN]; int j; int lastPacketTimeOrig; int parseEntitiesNumOrig; int currentSnapNum; //int serverMessageSequence; clSnap = &csn; if (!clc.demoplaying) { return qfalse; } if (snapshotNumber <= cl.snap.messageNum) { success = CL_GetSnapshot(snapshotNumber, snapshot); if (!success) { Com_FuncDPrinf("snapshot number outside of backup buffer\n"); return qfalse; } return qtrue; } if (snapshotNumber > cl.snap.messageNum + 1) { Com_FuncDPrinf("FIXME CL_PeekSnapshot %d > cl.snap.messageNum + 1 (%d)\n", snapshotNumber, cl.snap.messageNum); //return qfalse; } parseEntitiesNumOrig = cl.parseEntitiesNum; lastPacketTimeOrig = clc.lastPacketTime; // CL_ReadDemoMessage() origPosition = FS_FTell(clc.demofile); currentSnapNum = cl.snap.messageNum; for (j = 0; j < snapshotNumber - currentSnapNum; j++) { // get the sequence number memset(buffer, 0, sizeof(buffer)); r = FS_Read(&buffer, 4, clc.demofile); if (r != 4) { Com_FuncDPrinf("couldn't read sequence number\n"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return qfalse; } //serverMessageSequence = LittleLong(*((int *)buffer)); // init the message memset(&buf, 0, sizeof(msg_t)); MSG_Init(&buf, bufData, sizeof(bufData)); // get the length r = FS_Read(&buf.cursize, 4, clc.demofile); if (r != 4) { Com_FuncDPrinf("couldn't get length\n"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return qfalse; } buf.cursize = LittleLong(buf.cursize); if (buf.cursize == -1) { Com_FuncDPrinf("buf.cursize == -1\n"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return qfalse; } if (buf.cursize > buf.maxsize) { Com_FuncDrop("demoMsglen > MAX_MSGLEN"); } r = FS_Read(buf.data, buf.cursize, clc.demofile); if (r != buf.cursize) { Com_FuncDPrinf("Demo file was truncated.\n"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return qfalse; } clc.lastPacketTime = cls.realtime; buf.readcount = 0; MSG_Bitstream(&buf); // get the reliable sequence acknowledge number MSG_ReadLong(&buf); // parse the message while (qtrue) { if (buf.readcount > buf.cursize) { Com_FuncDrop("read past end of server message"); break; } cmd = MSG_ReadByte(&buf); if (cmd == svc_EOF) { break; } success = qfalse; switch (cmd) { default: Com_FuncDrop("Illegible server message"); break; case svc_nop: break; case svc_serverCommand: MSG_ReadLong(&buf); // seq //s = MSG_ReadString(&buf); MSG_ReadString(&buf); break; case svc_gamestate: Com_FuncDPrinf("FIXME gamestate\n"); goto alldone; break; case svc_snapshot: // TODO: changed this check if it works CL_ParseSnapshot(&buf); if (cl.snap.valid) { success = qtrue; } break; case svc_download: Com_FuncDPrinf("FIXME download\n"); goto alldone; break; } } alldone: if (!success) { Com_FuncDPrinf("failed\n"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return success; } // FIXME other ents not supported yet // if the entities in the frame have fallen out of their // circular buffer, we can't return it if (cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES) { Com_FuncDPrinf("cl.parseEntitiesNum - clSnap->parseEntitiesNum >= MAX_PARSE_ENTITIES"); FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; return qtrue; // FIXME if you fix other ents } // write the snapshot snapshot->snapFlags = clSnap->snapFlags; snapshot->serverCommandSequence = clSnap->serverCommandNum; snapshot->ping = clSnap->ping; snapshot->serverTime = clSnap->serverTime; Com_Memcpy(snapshot->areamask, clSnap->areamask, sizeof(snapshot->areamask)); snapshot->ps = clSnap->ps; count = clSnap->numEntities; if (count > MAX_ENTITIES_IN_SNAPSHOT) { Com_FuncDPrinf("truncated %i entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT); count = MAX_ENTITIES_IN_SNAPSHOT; } snapshot->numEntities = count; for (i = 0; i < count; i++) { snapshot->entities[i] = cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)]; } } FS_Seek(clc.demofile, origPosition, FS_SEEK_SET); clc.lastPacketTime = lastPacketTimeOrig; cl.parseEntitiesNum = parseEntitiesNumOrig; // TODO: configstring changes and server commands!!! return qtrue; }
/* ===================== CL_ParseCommandString Command strings are just saved off until cgame asks for them when it transitions a snapshot ===================== */ void CL_ParseCommandString( msg_t *msg ) { char *s; int seq; int index; #ifdef _DONETPROFILE_ int startBytes,endBytes; startBytes=msg->readcount; #endif seq = MSG_ReadLong( msg ); s = MSG_ReadString( msg ); #ifdef _DONETPROFILE_ endBytes=msg->readcount; ClReadProf().AddField("svc_serverCommand",endBytes-startBytes); #endif // see if we have already executed stored it off if ( clc.serverCommandSequence >= seq ) { return; } clc.serverCommandSequence = seq; index = seq & (MAX_RELIABLE_COMMANDS-1); /* if (s[0] == 'c' && s[1] == 's' && s[2] == ' ' && s[3] == '0' && s[4] == ' ') { //yes.. we seem to have an incoming server info. char *f = strstr(s, "g_debugMelee"); if (f) { while (*f && *f != '\\') { //find the \ after it f++; } if (*f == '\\') { //got it int i = 0; f++; while (*f && *f != '\\' && i < 128) { hiddenCvarVal[i] = *f; i++; f++; } hiddenCvarVal[i] = 0; //don't worry about backing over beginning of string I guess, //we already know we successfully strstr'd the initial string //which exceeds this length. //MSG_ReadString appears to just return a static buffer so I //can stomp over its contents safely. f--; *f = '\"'; f--; *f = ' '; f--; *f = '0'; f--; *f = ' '; f--; *f = 's'; f--; *f = 'c'; //the normal configstring gets to start here... s = f; } } } */ Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) ); }
/* * SV_ParseClientMessage * The current message is parsed for the given client */ void SV_ParseClientMessage( client_t *client, msg_t *msg ) { int c; char *s; bool move_issued; unsigned int cmdNum; if( !msg ) return; if (!client->tvclient) { SV_UpdateActivity(); } // only allow one move command move_issued = false; while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Printf( "SV_ParseClientMessage: badread\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "%s", "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, "%s", "Error: Unknown command char" ); return; case clc_nop: break; case clc_move: { if( move_issued ) return; // someone is trying to cheat... move_issued = true; 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, "%s", "Error: svack from reliable client" ); return; } cmdNum = MSG_ReadLong( msg ); if( cmdNum < client->reliableAcknowledge || cmdNum > client->reliableSent ) { //SV_DropClient( client, DROP_TYPE_GENERAL, "%s", "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; } } }