1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 #include "../qcommon/q_shared.h"
31 #include "../qcommon/qcommon.h"
32 #include "client.h"
33 
34 #ifdef LEGACY_PROTOCOL
35 /*
36 ==============
37 CL_Netchan_Encode
38 
39 	// first 12 bytes of the data are always:
40 	long serverId;
41 	long messageAcknowledge;
42 	long reliableAcknowledge;
43 
44 ==============
45 */
CL_Netchan_Encode(msg_t * msg)46 static void CL_Netchan_Encode( msg_t *msg ) {
47 	int serverId, messageAcknowledge, reliableAcknowledge;
48 	int i, index, srdc, sbit, soob;
49 	byte key, *string;
50 
51 	if ( msg->cursize <= CL_ENCODE_START ) {
52 		return;
53 	}
54 
55 	srdc = msg->readcount;
56 	sbit = msg->bit;
57 	soob = msg->oob;
58 
59 	msg->bit = 0;
60 	msg->readcount = 0;
61 	msg->oob = 0;
62 
63 	serverId = MSG_ReadLong( msg );
64 	messageAcknowledge = MSG_ReadLong( msg );
65 	reliableAcknowledge = MSG_ReadLong( msg );
66 
67 	msg->oob = soob;
68 	msg->bit = sbit;
69 	msg->readcount = srdc;
70 
71 	string = (byte *)clc.serverCommands[ reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ) ];
72 	index = 0;
73 	//
74 	key = clc.challenge ^ serverId ^ messageAcknowledge;
75 	for ( i = CL_ENCODE_START; i < msg->cursize; i++ ) {
76 		// modify the key with the last received now acknowledged server command
77 		if ( !string[index] ) {
78 			index = 0;
79 		}
80 		if ( string[index] > 127 || string[index] == '%' ) {
81 			key ^= '.' << ( i & 1 );
82 		} else {
83 			key ^= string[index] << ( i & 1 );
84 		}
85 		index++;
86 		// encode the data with this key
87 		*( msg->data + i ) = ( *( msg->data + i ) ) ^ key;
88 	}
89 }
90 #endif
91 
92 /*
93 ==============
94 CL_Netchan_Decode
95 
96 	// first four bytes of the data are always:
97 	long reliableAcknowledge;
98 
99 ==============
100 */
CL_Netchan_Decode(msg_t * msg)101 static void CL_Netchan_Decode( msg_t *msg ) {
102 	long reliableAcknowledge, i, index;
103 	byte key, *string;
104 	int srdc, sbit, soob;
105 
106 	srdc = msg->readcount;
107 	sbit = msg->bit;
108 	soob = msg->oob;
109 
110 	msg->oob = 0;
111 
112 	reliableAcknowledge = MSG_ReadLong( msg );
113 
114 	msg->oob = soob;
115 	msg->bit = sbit;
116 	msg->readcount = srdc;
117 
118 	string = (byte *) clc.reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ];
119 	index = 0;
120 	// xor the client challenge with the netchan sequence number (need something that changes every message)
121 	key = clc.challenge ^ LittleLong( *(unsigned *)msg->data );
122 	for ( i = msg->readcount + CL_DECODE_START; i < msg->cursize; i++ ) {
123 		// modify the key with the last sent and with this message acknowledged client command
124 		if ( !string[index] ) {
125 			index = 0;
126 		}
127 		if ( string[index] > 127 || string[index] == '%' ) {
128 			key ^= '.' << ( i & 1 );
129 		} else {
130 			key ^= string[index] << ( i & 1 );
131 		}
132 		index++;
133 		// decode the data with this key
134 		*( msg->data + i ) = *( msg->data + i ) ^ key;
135 	}
136 }
137 
138 /*
139 =================
140 CL_Netchan_TransmitNextFragment
141 =================
142 */
CL_Netchan_TransmitNextFragment(netchan_t * chan)143 qboolean CL_Netchan_TransmitNextFragment(netchan_t *chan)
144 {
145 	if(chan->unsentFragments)
146 	{
147 		Netchan_TransmitNextFragment(chan);
148 		return qtrue;
149 	}
150 
151 	return qfalse;
152 }
153 
154 /*
155 ================
156 CL_Netchan_Transmit
157 ================
158 */
CL_Netchan_Transmit(netchan_t * chan,msg_t * msg)159 void CL_Netchan_Transmit( netchan_t *chan, msg_t* msg ) {
160 	MSG_WriteByte( msg, clc_EOF );
161 
162 #ifdef LEGACY_PROTOCOL
163 	if(chan->compat)
164 		CL_Netchan_Encode(msg);
165 #endif
166 
167 	Netchan_Transmit(chan, msg->cursize, msg->data);
168 
169 	// Transmit all fragments without delay
170 	while(CL_Netchan_TransmitNextFragment(chan))
171 	{
172 		Com_DPrintf("WARNING: #462 unsent fragments (not supposed to happen!)\n");
173 	}
174 }
175 
176 /*
177 =================
178 CL_Netchan_Process
179 =================
180 */
CL_Netchan_Process(netchan_t * chan,msg_t * msg)181 qboolean CL_Netchan_Process( netchan_t *chan, msg_t *msg ) {
182 	int ret;
183 
184 	ret = Netchan_Process( chan, msg );
185 	if ( !ret ) {
186 		return qfalse;
187 	}
188 
189 #ifdef LEGACY_PROTOCOL
190 	if(chan->compat)
191 		CL_Netchan_Decode(msg);
192 #endif
193 
194 	return qtrue;
195 }
196