1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 // cl_parse.c -- parse a message received from the server
23
24 #include "client.h"
25
26 char *svc_strings[256] = {
27 "svc_bad",
28
29 "svc_nop",
30 "svc_gamestate",
31 "svc_configstring",
32 "svc_baseline",
33 "svc_serverCommand",
34 "svc_download",
35 "svc_snapshot",
36 "svc_EOF",
37 "svc_extension",
38 "svc_voip",
39 };
40
SHOWNET(msg_t * msg,char * s)41 void SHOWNET( msg_t *msg, char *s) {
42 if ( cl_shownet->integer >= 2) {
43 Com_Printf ("%3i:%s\n", msg->readcount-1, s);
44 }
45 }
46
47
48 /*
49 =========================================================================
50
51 MESSAGE PARSING
52
53 =========================================================================
54 */
55
56 /*
57 ==================
58 CL_DeltaEntity
59
60 Parses deltas from the given base and adds the resulting entity
61 to the current frame
62 ==================
63 */
CL_DeltaEntity(msg_t * msg,clSnapshot_t * frame,int newnum,entityState_t * old,qboolean unchanged)64 void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old,
65 qboolean unchanged) {
66 entityState_t *state;
67
68 // save the parsed entity state into the big circular buffer so
69 // it can be used as the source for a later delta
70 state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
71
72 if ( unchanged ) {
73 *state = *old;
74 } else {
75 MSG_ReadDeltaEntity( msg, old, state, newnum );
76 }
77
78 if ( state->number == (MAX_GENTITIES-1) ) {
79 return; // entity was delta removed
80 }
81 cl.parseEntitiesNum++;
82 frame->numEntities++;
83 }
84
85 /*
86 ==================
87 CL_ParsePacketEntities
88
89 ==================
90 */
CL_ParsePacketEntities(msg_t * msg,clSnapshot_t * oldframe,clSnapshot_t * newframe)91 void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
92 int newnum;
93 entityState_t *oldstate;
94 int oldindex, oldnum;
95
96 newframe->parseEntitiesNum = cl.parseEntitiesNum;
97 newframe->numEntities = 0;
98
99 // delta from the entities present in oldframe
100 oldindex = 0;
101 oldstate = NULL;
102 if (!oldframe) {
103 oldnum = 99999;
104 } else {
105 if ( oldindex >= oldframe->numEntities ) {
106 oldnum = 99999;
107 } else {
108 oldstate = &cl.parseEntities[
109 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
110 oldnum = oldstate->number;
111 }
112 }
113
114 while ( 1 ) {
115 // read the entity index number
116 newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
117
118 if ( newnum == (MAX_GENTITIES-1) ) {
119 break;
120 }
121
122 if ( msg->readcount > msg->cursize ) {
123 Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
124 }
125
126 while ( oldnum < newnum ) {
127 // one or more entities from the old packet are unchanged
128 if ( cl_shownet->integer == 3 ) {
129 Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
130 }
131 CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
132
133 oldindex++;
134
135 if ( oldindex >= oldframe->numEntities ) {
136 oldnum = 99999;
137 } else {
138 oldstate = &cl.parseEntities[
139 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
140 oldnum = oldstate->number;
141 }
142 }
143 if (oldnum == newnum) {
144 // delta from previous state
145 if ( cl_shownet->integer == 3 ) {
146 Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
147 }
148 CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
149
150 oldindex++;
151
152 if ( oldindex >= oldframe->numEntities ) {
153 oldnum = 99999;
154 } else {
155 oldstate = &cl.parseEntities[
156 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
157 oldnum = oldstate->number;
158 }
159 continue;
160 }
161
162 if ( oldnum > newnum ) {
163 // delta from baseline
164 if ( cl_shownet->integer == 3 ) {
165 Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
166 }
167 CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );
168 continue;
169 }
170
171 }
172
173 // any remaining entities in the old frame are copied over
174 while ( oldnum != 99999 ) {
175 // one or more entities from the old packet are unchanged
176 if ( cl_shownet->integer == 3 ) {
177 Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
178 }
179 CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
180
181 oldindex++;
182
183 if ( oldindex >= oldframe->numEntities ) {
184 oldnum = 99999;
185 } else {
186 oldstate = &cl.parseEntities[
187 (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
188 oldnum = oldstate->number;
189 }
190 }
191 }
192
193
194 /*
195 ================
196 CL_ParseSnapshot
197
198 If the snapshot is parsed properly, it will be copied to
199 cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
200 for any reason, no changes to the state will be made at all.
201 ================
202 */
CL_ParseSnapshot(msg_t * msg)203 void CL_ParseSnapshot( msg_t *msg ) {
204 int len;
205 clSnapshot_t *old;
206 clSnapshot_t newSnap;
207 int deltaNum;
208 int oldMessageNum;
209 int i, packetNum;
210
211 // get the reliable sequence acknowledge number
212 // NOTE: now sent with all server to client messages
213 //clc.reliableAcknowledge = MSG_ReadLong( msg );
214
215 // read in the new snapshot to a temporary buffer
216 // we will only copy to cl.snap if it is valid
217 Com_Memset (&newSnap, 0, sizeof(newSnap));
218
219 // we will have read any new server commands in this
220 // message before we got to svc_snapshot
221 newSnap.serverCommandNum = clc.serverCommandSequence;
222
223 newSnap.serverTime = MSG_ReadLong( msg );
224
225 // if we were just unpaused, we can only *now* really let the
226 // change come into effect or the client hangs.
227 cl_paused->modified = 0;
228
229 newSnap.messageNum = clc.serverMessageSequence;
230
231 deltaNum = MSG_ReadByte( msg );
232 if ( !deltaNum ) {
233 newSnap.deltaNum = -1;
234 } else {
235 newSnap.deltaNum = newSnap.messageNum - deltaNum;
236 }
237 newSnap.snapFlags = MSG_ReadByte( msg );
238
239 // If the frame is delta compressed from data that we
240 // no longer have available, we must suck up the rest of
241 // the frame, but not use it, then ask for a non-compressed
242 // message
243 if ( newSnap.deltaNum <= 0 ) {
244 newSnap.valid = qtrue; // uncompressed frame
245 old = NULL;
246 clc.demowaiting = qfalse; // we can start recording now
247 } else {
248 old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
249 if ( !old->valid ) {
250 // should never happen
251 Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
252 } else if ( old->messageNum != newSnap.deltaNum ) {
253 // The frame that the server did the delta from
254 // is too old, so we can't reconstruct it properly.
255 Com_Printf ("Delta frame too old.\n");
256 } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
257 Com_Printf ("Delta parseEntitiesNum too old.\n");
258 } else {
259 newSnap.valid = qtrue; // valid delta parse
260 }
261 }
262
263 // read areamask
264 len = MSG_ReadByte( msg );
265
266 if(len > sizeof(newSnap.areamask))
267 {
268 Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask.", len);
269 return;
270 }
271
272 MSG_ReadData( msg, &newSnap.areamask, len);
273
274 // read playerinfo
275 SHOWNET( msg, "playerstate" );
276 if ( old ) {
277 MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
278 } else {
279 MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
280 }
281
282 // read packet entities
283 SHOWNET( msg, "packet entities" );
284 CL_ParsePacketEntities( msg, old, &newSnap );
285
286 // if not valid, dump the entire thing now that it has
287 // been properly read
288 if ( !newSnap.valid ) {
289 return;
290 }
291
292 // clear the valid flags of any snapshots between the last
293 // received and this one, so if there was a dropped packet
294 // it won't look like something valid to delta from next
295 // time we wrap around in the buffer
296 oldMessageNum = cl.snap.messageNum + 1;
297
298 if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
299 oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
300 }
301 for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
302 cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
303 }
304
305 // copy to the current good spot
306 cl.snap = newSnap;
307 cl.snap.ping = 999;
308 // calculate ping time
309 for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
310 packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
311 if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
312 cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
313 break;
314 }
315 }
316 // save the frame off in the backup array for later delta comparisons
317 cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
318
319 if (cl_shownet->integer == 3) {
320 Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
321 cl.snap.deltaNum, cl.snap.ping );
322 }
323
324 cl.newSnapshots = qtrue;
325 }
326
327
328 //=====================================================================
329
330 int cl_connectedToPureServer;
331 int cl_connectedToCheatServer;
332
333 #ifdef USE_VOIP
334 int cl_connectedToVoipServer;
335 #endif
336
337 /*
338 ==================
339 CL_SystemInfoChanged
340
341 The systeminfo configstring has been changed, so parse
342 new information out of it. This will happen at every
343 gamestate, and possibly during gameplay.
344 ==================
345 */
CL_SystemInfoChanged(void)346 void CL_SystemInfoChanged( void ) {
347 char *systemInfo;
348 const char *s, *t;
349 char key[BIG_INFO_KEY];
350 char value[BIG_INFO_VALUE];
351 qboolean gameSet;
352
353 systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
354 // NOTE TTimo:
355 // when the serverId changes, any further messages we send to the server will use this new serverId
356 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
357 // in some cases, outdated cp commands might get sent with this news serverId
358 cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
359
360 // don't set any vars when playing a demo
361 if ( clc.demoplaying ) {
362 return;
363 }
364
365 #ifdef USE_VOIP
366 // in the future, (val) will be a protocol version string, so only
367 // accept explicitly 1, not generally non-zero.
368 s = Info_ValueForKey( systemInfo, "sv_voip" );
369 if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))
370 cl_connectedToVoipServer = qfalse;
371 else
372 cl_connectedToVoipServer = (atoi( s ) == 1);
373
374 #endif
375
376 s = Info_ValueForKey( systemInfo, "sv_cheats" );
377 cl_connectedToCheatServer = atoi( s );
378 if ( !cl_connectedToCheatServer ) {
379 Cvar_SetCheatState();
380 }
381
382 // check pure server string
383 s = Info_ValueForKey( systemInfo, "sv_paks" );
384 t = Info_ValueForKey( systemInfo, "sv_pakNames" );
385 FS_PureServerSetLoadedPaks( s, t );
386
387 s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
388 t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
389 FS_PureServerSetReferencedPaks( s, t );
390
391 gameSet = qfalse;
392 // scan through all the variables in the systeminfo and locally set cvars to match
393 s = systemInfo;
394 while ( s ) {
395 int cvar_flags;
396
397 Info_NextPair( &s, key, value );
398 if ( !key[0] ) {
399 break;
400 }
401
402 // ehw!
403 if (!Q_stricmp(key, "fs_game"))
404 {
405 if(FS_CheckDirTraversal(value))
406 {
407 Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
408 continue;
409 }
410
411 gameSet = qtrue;
412 }
413
414 if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
415 Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
416 else
417 {
418 // If this cvar may not be modified by a server discard the value.
419 // I have added exceptions for sv_fps, pmove_fixed and pmove_msec. These should relly be corrected in the game logic code, but they are required\
420 for a lot of mods and not all can be changed. vq3 uses pmove_fixed, pmove_msec and g_synchronousClients. Most unlagged mods uses sv_fps too.
421 if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED)) && Q_stricmp(key, "sv_fps") && Q_stricmp(key, "pmove_fixed") &&\
422 Q_stricmp(key, "pmove_msec") && Q_stricmp(key, "g_synchronousClients"))
423 {
424 Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
425 continue;
426 }
427
428 Cvar_Set(key, value);
429 }
430 }
431 // if game folder should not be set and it is set at the client side
432 if ( !gameSet && *Cvar_VariableString("fs_game") ) {
433 Cvar_Set( "fs_game", "" );
434 }
435 cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
436 }
437
438 /*
439 ==================
440 CL_ParseServerInfo
441 ==================
442 */
CL_ParseServerInfo(void)443 static void CL_ParseServerInfo(void)
444 {
445 const char *serverInfo;
446
447 serverInfo = cl.gameState.stringData
448 + cl.gameState.stringOffsets[ CS_SERVERINFO ];
449
450 clc.sv_allowDownload = atoi(Info_ValueForKey(serverInfo,
451 "sv_allowDownload"));
452 Q_strncpyz(clc.sv_dlURL,
453 Info_ValueForKey(serverInfo, "sv_dlURL"),
454 sizeof(clc.sv_dlURL));
455 }
456
457 /*
458 ==================
459 CL_ParseGamestate
460 ==================
461 */
CL_ParseGamestate(msg_t * msg)462 void CL_ParseGamestate( msg_t *msg ) {
463 int i;
464 entityState_t *es;
465 int newnum;
466 entityState_t nullstate;
467 int cmd;
468 char *s;
469
470 Con_Close();
471
472 clc.connectPacketCount = 0;
473
474 // wipe local client state
475 CL_ClearState();
476
477 // a gamestate always marks a server command sequence
478 clc.serverCommandSequence = MSG_ReadLong( msg );
479
480 // parse all the configstrings and baselines
481 cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
482 while ( 1 ) {
483 cmd = MSG_ReadByte( msg );
484
485 if ( cmd == svc_EOF ) {
486 break;
487 }
488
489 if ( cmd == svc_configstring ) {
490 int len;
491
492 i = MSG_ReadShort( msg );
493 if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
494 Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
495 }
496 s = MSG_ReadBigString( msg );
497 len = strlen( s );
498
499 if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
500 Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
501 }
502
503 // append it to the gameState string buffer
504 cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
505 Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
506 cl.gameState.dataCount += len + 1;
507 } else if ( cmd == svc_baseline ) {
508 newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
509 if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
510 Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
511 }
512 Com_Memset (&nullstate, 0, sizeof(nullstate));
513 es = &cl.entityBaselines[ newnum ];
514 MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
515 } else {
516 Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
517 }
518 }
519
520 clc.clientNum = MSG_ReadLong(msg);
521 // read the checksum feed
522 clc.checksumFeed = MSG_ReadLong( msg );
523
524 // parse useful values out of CS_SERVERINFO
525 CL_ParseServerInfo();
526
527 // parse serverId and other cvars
528 CL_SystemInfoChanged();
529
530 // stop recording now so the demo won't have an unnecessary level load at the end.
531 if(cl_autoRecordDemo->integer && clc.demorecording)
532 CL_StopRecord_f();
533
534 // reinitialize the filesystem if the game directory has changed
535 FS_ConditionalRestart( clc.checksumFeed );
536
537 if (dangerousPaksFound) {
538 char PakList[MAX_STRING_CHARS];
539 for (i = 0; i < dangerousPaksFound; i++) {
540 Q_strcat(PakList, sizeof(PakList), va("%s.pk3, ", dangerousPakNames[i]));
541 }
542
543 PakList[strlen(PakList) - 2] = 0;
544
545 Cvar_Set("com_errorMessage", va(
546 "^1WARNING! ^7Dangerous file(s) found in downloaded pk3%s:\n\n%s\n\n"
547 "You should go delete %s immediately. %s could lead to malicious code execution.",
548 dangerousPaksFound == 1 ? "" : "s",
549 PakList,
550 dangerousPaksFound == 1 ? "that file" : "those files",
551 dangerousPaksFound == 1 ? "It" : "They"));
552
553 VM_Call(uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN);
554 return;
555 }
556
557 // This used to call CL_StartHunkUsers, but now we enter the download state before loading the
558 // cgame
559 CL_InitDownloads();
560
561 // make sure the game starts
562 Cvar_Set( "cl_paused", "0" );
563 }
564
565
566 //=====================================================================
567
568 /*
569 =====================
570 CL_ParseDownload
571
572 A download message has been received from the server
573 =====================
574 */
CL_ParseDownload(msg_t * msg)575 void CL_ParseDownload ( msg_t *msg ) {
576 int size;
577 unsigned char data[MAX_MSGLEN];
578 int block;
579
580 if (!*clc.downloadTempName) {
581 Com_Printf("Server sending download, but no download was requested\n");
582 CL_AddReliableCommand("stopdl", qfalse);
583 return;
584 }
585
586 // read the data
587 block = MSG_ReadShort ( msg );
588
589 if ( !block )
590 {
591 // block zero is special, contains file size
592 clc.downloadSize = MSG_ReadLong ( msg );
593
594 Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
595
596 if (clc.downloadSize < 0)
597 {
598 Com_Error( ERR_DROP, "%s", MSG_ReadString( msg ) );
599 return;
600 }
601 }
602
603 size = MSG_ReadShort ( msg );
604 if (size < 0 || size > sizeof(data))
605 {
606 Com_Error(ERR_DROP, "CL_ParseDownload: Invalid size %d for download chunk.", size);
607 return;
608 }
609
610 MSG_ReadData(msg, data, size);
611
612 if (clc.downloadBlock != block) {
613 Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
614 return;
615 }
616
617 // open the file if not opened yet
618 if (!clc.download)
619 {
620 clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
621
622 if (!clc.download) {
623 Com_Printf( "Could not create %s\n", clc.downloadTempName );
624 CL_AddReliableCommand("stopdl", qfalse);
625 CL_NextDownload();
626 return;
627 }
628 }
629
630 if (size)
631 FS_Write( data, size, clc.download );
632
633 CL_AddReliableCommand(va("nextdl %d", clc.downloadBlock), qfalse);
634 clc.downloadBlock++;
635
636 clc.downloadCount += size;
637
638 // So UI gets access to it
639 Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
640
641 if (!size) { // A zero length block means EOF
642 if (clc.download) {
643 FS_FCloseFile( clc.download );
644 clc.download = 0;
645
646 // rename the file
647 FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse );
648 }
649
650 // send intentions now
651 // We need this because without it, we would hold the last nextdl and then start
652 // loading right away. If we take a while to load, the server is happily trying
653 // to send us that last block over and over.
654 // Write it twice to help make sure we acknowledge the download
655 CL_WritePacket();
656 CL_WritePacket();
657
658 // get another file if needed
659 CL_NextDownload ();
660 }
661 }
662
663 #ifdef USE_VOIP
664 static
CL_ShouldIgnoreVoipSender(int sender)665 qboolean CL_ShouldIgnoreVoipSender(int sender)
666 {
667 if (!cl_voip->integer)
668 return qtrue; // VoIP is disabled.
669 else if ((sender == clc.clientNum) && (!clc.demoplaying))
670 return qtrue; // ignore own voice (unless playing back a demo).
671 else if (clc.voipMuteAll)
672 return qtrue; // all channels are muted with extreme prejudice.
673 else if (clc.voipIgnore[sender])
674 return qtrue; // just ignoring this guy.
675 else if (clc.voipGain[sender] == 0.0f)
676 return qtrue; // too quiet to play.
677
678 return qfalse;
679 }
680
681 /*
682 =====================
683 CL_ParseVoip
684
685 A VoIP message has been received from the server
686 =====================
687 */
688 static
CL_ParseVoip(msg_t * msg)689 void CL_ParseVoip ( msg_t *msg ) {
690 static short decoded[4096]; // !!! FIXME: don't hardcode.
691
692 const int sender = MSG_ReadShort(msg);
693 const int generation = MSG_ReadByte(msg);
694 const int sequence = MSG_ReadLong(msg);
695 const int frames = MSG_ReadByte(msg);
696 const int packetsize = MSG_ReadShort(msg);
697 char encoded[1024];
698 int seqdiff = sequence - clc.voipIncomingSequence[sender];
699 int written = 0;
700 int i;
701
702 Com_DPrintf("VoIP: %d-byte packet from client %d\n", packetsize, sender);
703
704 if (sender < 0)
705 return; // short/invalid packet, bail.
706 else if (generation < 0)
707 return; // short/invalid packet, bail.
708 else if (sequence < 0)
709 return; // short/invalid packet, bail.
710 else if (frames < 0)
711 return; // short/invalid packet, bail.
712 else if (packetsize < 0)
713 return; // short/invalid packet, bail.
714
715 if (packetsize > sizeof (encoded)) { // overlarge packet?
716 int bytesleft = packetsize;
717 while (bytesleft) {
718 int br = bytesleft;
719 if (br > sizeof (encoded))
720 br = sizeof (encoded);
721 MSG_ReadData(msg, encoded, br);
722 bytesleft -= br;
723 }
724 return; // overlarge packet, bail.
725 }
726
727 if (!clc.speexInitialized) {
728 MSG_ReadData(msg, encoded, packetsize); // skip payload.
729 return; // can't handle VoIP without libspeex!
730 } else if (sender >= MAX_CLIENTS) {
731 MSG_ReadData(msg, encoded, packetsize); // skip payload.
732 return; // bogus sender.
733 } else if (CL_ShouldIgnoreVoipSender(sender)) {
734 MSG_ReadData(msg, encoded, packetsize); // skip payload.
735 return; // Channel is muted, bail.
736 }
737
738 // !!! FIXME: make sure data is narrowband? Does decoder handle this?
739
740 Com_DPrintf("VoIP: packet accepted!\n");
741
742 // This is a new "generation" ... a new recording started, reset the bits.
743 if (generation != clc.voipIncomingGeneration[sender]) {
744 Com_DPrintf("VoIP: new generation %d!\n", generation);
745 speex_bits_reset(&clc.speexDecoderBits[sender]);
746 clc.voipIncomingGeneration[sender] = generation;
747 seqdiff = 0;
748 } else if (seqdiff < 0) { // we're ahead of the sequence?!
749 // This shouldn't happen unless the packet is corrupted or something.
750 Com_DPrintf("VoIP: misordered sequence! %d < %d!\n",
751 sequence, clc.voipIncomingSequence[sender]);
752 // reset the bits just in case.
753 speex_bits_reset(&clc.speexDecoderBits[sender]);
754 seqdiff = 0;
755 } else if (seqdiff > 100) { // more than 2 seconds of audio dropped?
756 // just start over.
757 Com_DPrintf("VoIP: Dropped way too many (%d) frames from client #%d\n",
758 seqdiff, sender);
759 speex_bits_reset(&clc.speexDecoderBits[sender]);
760 seqdiff = 0;
761 }
762
763 if (seqdiff != 0) {
764 Com_DPrintf("VoIP: Dropped %d frames from client #%d\n",
765 seqdiff, sender);
766 // tell speex that we're missing frames...
767 for (i = 0; i < seqdiff; i++) {
768 assert((written + clc.speexFrameSize) * 2 < sizeof (decoded));
769 speex_decode_int(clc.speexDecoder[sender], NULL, decoded + written);
770 written += clc.speexFrameSize;
771 }
772 }
773
774 for (i = 0; i < frames; i++) {
775 char encoded[256];
776 const int len = MSG_ReadByte(msg);
777 if (len < 0) {
778 Com_DPrintf("VoIP: Short packet!\n");
779 break;
780 }
781 MSG_ReadData(msg, encoded, len);
782
783 // shouldn't happen, but just in case...
784 if ((written + clc.speexFrameSize) * 2 > sizeof (decoded)) {
785 Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
786 written * 2, written, i);
787 S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
788 (const byte *) decoded, clc.voipGain[sender]);
789 written = 0;
790 }
791
792 speex_bits_read_from(&clc.speexDecoderBits[sender], encoded, len);
793 speex_decode_int(clc.speexDecoder[sender],
794 &clc.speexDecoderBits[sender], decoded + written);
795
796 #if 0
797 static FILE *encio = NULL;
798 if (encio == NULL) encio = fopen("voip-incoming-encoded.bin", "wb");
799 if (encio != NULL) { fwrite(encoded, len, 1, encio); fflush(encio); }
800 static FILE *decio = NULL;
801 if (decio == NULL) decio = fopen("voip-incoming-decoded.bin", "wb");
802 if (decio != NULL) { fwrite(decoded+written, clc.speexFrameSize*2, 1, decio); fflush(decio); }
803 #endif
804
805 written += clc.speexFrameSize;
806 }
807
808 Com_DPrintf("VoIP: playback %d bytes, %d samples, %d frames\n",
809 written * 2, written, i);
810
811 if (written > 0) {
812 S_RawSamples(sender + 1, written, clc.speexSampleRate, 2, 1,
813 (const byte *) decoded, clc.voipGain[sender]);
814 }
815
816 clc.voipIncomingSequence[sender] = sequence + frames;
817 }
818 #endif
819
820
821 /*
822 =====================
823 CL_ParseCommandString
824
825 Command strings are just saved off until cgame asks for them
826 when it transitions a snapshot
827 =====================
828 */
CL_ParseCommandString(msg_t * msg)829 void CL_ParseCommandString( msg_t *msg ) {
830 char *s;
831 int seq;
832 int index;
833
834 seq = MSG_ReadLong( msg );
835 s = MSG_ReadString( msg );
836
837 // see if we have already executed stored it off
838 if ( clc.serverCommandSequence >= seq ) {
839 return;
840 }
841 clc.serverCommandSequence = seq;
842
843 index = seq & (MAX_RELIABLE_COMMANDS-1);
844 Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );
845 }
846
847
848 /*
849 =====================
850 CL_ParseServerMessage
851 =====================
852 */
CL_ParseServerMessage(msg_t * msg)853 void CL_ParseServerMessage( msg_t *msg ) {
854 int cmd;
855
856 if ( cl_shownet->integer == 1 ) {
857 Com_Printf ("%i ",msg->cursize);
858 } else if ( cl_shownet->integer >= 2 ) {
859 Com_Printf ("------------------\n");
860 }
861
862 MSG_Bitstream(msg);
863
864 // get the reliable sequence acknowledge number
865 clc.reliableAcknowledge = MSG_ReadLong( msg );
866 //
867 if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
868 clc.reliableAcknowledge = clc.reliableSequence;
869 }
870
871 //
872 // parse the message
873 //
874 while ( 1 ) {
875 if ( msg->readcount > msg->cursize ) {
876 Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
877 break;
878 }
879
880 cmd = MSG_ReadByte( msg );
881
882 // See if this is an extension command after the EOF, which means we
883 // got data that a legacy client should ignore.
884 if ((cmd == svc_EOF) && (MSG_LookaheadByte( msg ) == svc_extension)) {
885 SHOWNET( msg, "EXTENSION" );
886 MSG_ReadByte( msg ); // throw the svc_extension byte away.
887 cmd = MSG_ReadByte( msg ); // something legacy clients can't do!
888 // sometimes you get a svc_extension at end of stream...dangling
889 // bits in the huffman decoder giving a bogus value?
890 if (cmd == -1) {
891 cmd = svc_EOF;
892 }
893 }
894
895 if (cmd == svc_EOF) {
896 SHOWNET( msg, "END OF MESSAGE" );
897 break;
898 }
899
900 if ( cl_shownet->integer >= 2 ) {
901 if ( (cmd < 0) || (!svc_strings[cmd]) ) {
902 Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
903 } else {
904 SHOWNET( msg, svc_strings[cmd] );
905 }
906 }
907
908 // other commands
909 switch ( cmd ) {
910 default:
911 Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
912 break;
913 case svc_nop:
914 break;
915 case svc_serverCommand:
916 CL_ParseCommandString( msg );
917 break;
918 case svc_gamestate:
919 CL_ParseGamestate( msg );
920 break;
921 case svc_snapshot:
922 CL_ParseSnapshot( msg );
923 break;
924 case svc_download:
925 CL_ParseDownload( msg );
926 break;
927 case svc_voip:
928 #ifdef USE_VOIP
929 CL_ParseVoip( msg );
930 #endif
931 break;
932 }
933 }
934 }
935
936
937