Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

sv_net_chan.c (6293B)


      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 Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #include "../game/q_shared.h"
     24 #include "../qcommon/qcommon.h"
     25 #include "server.h"
     26 
     27 /*
     28 ==============
     29 SV_Netchan_Encode
     30 
     31 	// first four bytes of the data are always:
     32 	long reliableAcknowledge;
     33 
     34 ==============
     35 */
     36 static void SV_Netchan_Encode( client_t *client, msg_t *msg ) {
     37 	long reliableAcknowledge, i, index;
     38 	byte key, *string;
     39         int	srdc, sbit, soob;
     40         
     41 	if ( msg->cursize < SV_ENCODE_START ) {
     42 		return;
     43 	}
     44 
     45         srdc = msg->readcount;
     46         sbit = msg->bit;
     47         soob = msg->oob;
     48         
     49         msg->bit = 0;
     50         msg->readcount = 0;
     51         msg->oob = 0;
     52         
     53 	reliableAcknowledge = MSG_ReadLong(msg);
     54 
     55         msg->oob = soob;
     56         msg->bit = sbit;
     57         msg->readcount = srdc;
     58         
     59 	string = (byte *)client->lastClientCommandString;
     60 	index = 0;
     61 	// xor the client challenge with the netchan sequence number
     62 	key = client->challenge ^ client->netchan.outgoingSequence;
     63 	for (i = SV_ENCODE_START; i < msg->cursize; i++) {
     64 		// modify the key with the last received and with this message acknowledged client command
     65 		if (!string[index])
     66 			index = 0;
     67 		if (string[index] > 127 || string[index] == '%') {
     68 			key ^= '.' << (i & 1);
     69 		}
     70 		else {
     71 			key ^= string[index] << (i & 1);
     72 		}
     73 		index++;
     74 		// encode the data with this key
     75 		*(msg->data + i) = *(msg->data + i) ^ key;
     76 	}
     77 }
     78 
     79 /*
     80 ==============
     81 SV_Netchan_Decode
     82 
     83 	// first 12 bytes of the data are always:
     84 	long serverId;
     85 	long messageAcknowledge;
     86 	long reliableAcknowledge;
     87 
     88 ==============
     89 */
     90 static void SV_Netchan_Decode( client_t *client, msg_t *msg ) {
     91 	int serverId, messageAcknowledge, reliableAcknowledge;
     92 	int i, index, srdc, sbit, soob;
     93 	byte key, *string;
     94 
     95         srdc = msg->readcount;
     96         sbit = msg->bit;
     97         soob = msg->oob;
     98         
     99         msg->oob = 0;
    100         
    101         serverId = MSG_ReadLong(msg);
    102 	messageAcknowledge = MSG_ReadLong(msg);
    103 	reliableAcknowledge = MSG_ReadLong(msg);
    104 
    105         msg->oob = soob;
    106         msg->bit = sbit;
    107         msg->readcount = srdc;
    108         
    109 	string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
    110 	index = 0;
    111 	//
    112 	key = client->challenge ^ serverId ^ messageAcknowledge;
    113 	for (i = msg->readcount + SV_DECODE_START; i < msg->cursize; i++) {
    114 		// modify the key with the last sent and acknowledged server command
    115 		if (!string[index])
    116 			index = 0;
    117 		if (string[index] > 127 || string[index] == '%') {
    118 			key ^= '.' << (i & 1);
    119 		}
    120 		else {
    121 			key ^= string[index] << (i & 1);
    122 		}
    123 		index++;
    124 		// decode the data with this key
    125 		*(msg->data + i) = *(msg->data + i) ^ key;
    126 	}
    127 }
    128 
    129 /*
    130 =================
    131 SV_Netchan_TransmitNextFragment
    132 =================
    133 */
    134 void SV_Netchan_TransmitNextFragment( client_t *client ) {
    135 	Netchan_TransmitNextFragment( &client->netchan );
    136 	if (!client->netchan.unsentFragments)
    137 	{
    138 		// make sure the netchan queue has been properly initialized (you never know)
    139 		if (!client->netchan_end_queue) {
    140 			Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
    141 		}
    142 		// the last fragment was transmitted, check wether we have queued messages
    143 		if (client->netchan_start_queue) {
    144 			netchan_buffer_t *netbuf;
    145 			Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
    146 			netbuf = client->netchan_start_queue;
    147 			SV_Netchan_Encode( client, &netbuf->msg );
    148 			Netchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data );
    149 			// pop from queue
    150 			client->netchan_start_queue = netbuf->next;
    151 			if (!client->netchan_start_queue) {
    152 				Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
    153 				client->netchan_end_queue = &client->netchan_start_queue;
    154 			}
    155 			else
    156 				Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
    157 			Z_Free(netbuf);
    158 		} 
    159 	}	
    160 }
    161 
    162 
    163 /*
    164 ===============
    165 SV_Netchan_Transmit
    166 TTimo
    167 https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=462
    168 if there are some unsent fragments (which may happen if the snapshots
    169 and the gamestate are fragmenting, and collide on send for instance)
    170 then buffer them and make sure they get sent in correct order
    171 ================
    172 */
    173 
    174 void SV_Netchan_Transmit( client_t *client, msg_t *msg) {	//int length, const byte *data ) {
    175 	MSG_WriteByte( msg, svc_EOF );
    176 	if (client->netchan.unsentFragments) {
    177 		netchan_buffer_t *netbuf;
    178 		Com_DPrintf("#462 SV_Netchan_Transmit: unsent fragments, stacked\n");
    179 		netbuf = (netchan_buffer_t *)Z_Malloc(sizeof(netchan_buffer_t));
    180 		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
    181 		MSG_Copy(&netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg);
    182 		netbuf->next = NULL;
    183 		// insert it in the queue, the message will be encoded and sent later
    184 		*client->netchan_end_queue = netbuf;
    185 		client->netchan_end_queue = &(*client->netchan_end_queue)->next;
    186 		// emit the next fragment of the current message for now
    187 		Netchan_TransmitNextFragment(&client->netchan);
    188 	} else {
    189 		SV_Netchan_Encode( client, msg );
    190 		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
    191 	}
    192 }
    193 
    194 /*
    195 =================
    196 Netchan_SV_Process
    197 =================
    198 */
    199 qboolean SV_Netchan_Process( client_t *client, msg_t *msg ) {
    200 	int ret;
    201 	ret = Netchan_Process( &client->netchan, msg );
    202 	if (!ret)
    203 		return qfalse;
    204 	SV_Netchan_Decode( client, msg );
    205 	return qtrue;
    206 }
    207