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