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