1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 #include "quakedef.h"
22
23 #ifdef _WIN32
24 #include "winquake.h"
25 #endif
26
27 #define PACKET_HEADER 8
28
29 /*
30
31 packet header
32 -------------
33 31 sequence
34 1 does this message contain a reliable payload
35 31 acknowledge sequence
36 1 acknowledge receipt of even/odd message
37 16 qport
38
39 The remote connection never knows if it missed a reliable message, the
40 local side detects that it has been dropped by seeing a sequence acknowledge
41 higher thatn the last reliable sequence, but without the correct evon/odd
42 bit for the reliable set.
43
44 If the sender notices that a reliable message has been dropped, it will be
45 retransmitted. It will not be retransmitted again until a message after
46 the retransmit has been acknowledged and the reliable still failed to get there.
47
48 if the sequence number is -1, the packet should be handled without a netcon
49
50 The reliable message can be added to at any time by doing
51 MSG_Write* (&netchan->message, <data>).
52
53 If the message buffer is overflowed, either by a single message, or by
54 multiple frames worth piling up while the last reliable transmit goes
55 unacknowledged, the netchan signals a fatal error.
56
57 Reliable messages are allways placed first in a packet, then the unreliable
58 message is included if there is sufficient room.
59
60 To the receiver, there is no distinction between the reliable and unreliable
61 parts of the message, they are just processed out as a single larger message.
62
63 Illogical packet sequence numbers cause the packet to be dropped, but do
64 not kill the connection. This, combined with the tight window of valid
65 reliable acknowledgement numbers provides protection against malicious
66 address spoofing.
67
68 The qport field is a workaround for bad address translating routers that
69 sometimes remap the client's source port on a packet during gameplay.
70
71 If the base part of the net address matches and the qport matches, then the
72 channel matches even if the IP port differs. The IP port should be updated
73 to the new value before sending out any replies.
74
75
76 */
77
78 int net_drop;
79 cvar_t showpackets = CVAR2("showpackets", "0");
80 cvar_t showdrop = CVAR2("showdrop", "0");
81 cvar_t qport = CVAR2("qport", "0");
82
83 /*
84 ===============
85 Netchan_Init
86
87 ===============
88 */
Netchan_Init(void)89 void Netchan_Init (void)
90 {
91 int port;
92
93 // pick a port value that should be nice and random
94 #ifdef _WIN32
95 port = ((int)(timeGetTime()*1000) * time(NULL)) & 0xffff;
96 #else
97 port = ((int)(getpid()+getuid()*1000) * time(NULL)) & 0xffff;
98 #endif
99
100 Cvar_RegisterVariable (&showpackets);
101 Cvar_RegisterVariable (&showdrop);
102 Cvar_RegisterVariable (&qport);
103 Cvar_SetValue("qport", port);
104 }
105
106 /*
107 ===============
108 Netchan_OutOfBand
109
110 Sends an out-of-band datagram
111 ================
112 */
Netchan_OutOfBand(netadr_t adr,int length,byte * data)113 void Netchan_OutOfBand (netadr_t adr, int length, byte *data)
114 {
115 sizebuf_t send;
116 byte send_buf[MAX_MSGLEN + PACKET_HEADER];
117
118 // write the packet header
119 send.data = send_buf;
120 send.maxsize = sizeof(send_buf);
121 send.cursize = 0;
122
123 MSG_WriteLong (&send, -1); // -1 sequence means out of band
124 SZ_Write (&send, data, length);
125
126 // send the datagram
127 //zoid, no input in demo playback mode
128 #ifndef SERVERONLY
129 if (!cls.demoplayback)
130 #endif
131 NET_SendPacket (send.cursize, send.data, adr);
132 }
133
134 /*
135 ===============
136 Netchan_OutOfBandPrint
137
138 Sends a text message in an out-of-band datagram
139 ================
140 */
Netchan_OutOfBandPrint(netadr_t adr,char * format,...)141 void Netchan_OutOfBandPrint (netadr_t adr, char *format, ...)
142 {
143 va_list argptr;
144 static char string[8192]; // ??? why static?
145
146 va_start (argptr, format);
147 vsprintf (string, format,argptr);
148 va_end (argptr);
149
150
151 Netchan_OutOfBand (adr, strlen(string), (byte *)string);
152 }
153
154
155 /*
156 ==============
157 Netchan_Setup
158
159 called to open a channel to a remote system
160 ==============
161 */
Netchan_Setup(netchan_t * chan,netadr_t adr,int qport)162 void Netchan_Setup (netchan_t *chan, netadr_t adr, int qport)
163 {
164 memset (chan, 0, sizeof(*chan));
165
166 chan->remote_address = adr;
167 chan->last_received = realtime;
168
169 chan->message.data = chan->message_buf;
170 chan->message.allowoverflow = true;
171 chan->message.maxsize = sizeof(chan->message_buf);
172
173 chan->qport = qport;
174
175 chan->rate = 1.0/2500;
176 }
177
178
179 /*
180 ===============
181 Netchan_CanPacket
182
183 Returns true if the bandwidth choke isn't active
184 ================
185 */
186 #define MAX_BACKUP 200
Netchan_CanPacket(netchan_t * chan)187 qboolean Netchan_CanPacket (netchan_t *chan)
188 {
189 if (chan->cleartime < realtime + MAX_BACKUP*chan->rate)
190 return true;
191 return false;
192 }
193
194
195 /*
196 ===============
197 Netchan_CanReliable
198
199 Returns true if the bandwidth choke isn't
200 ================
201 */
Netchan_CanReliable(netchan_t * chan)202 qboolean Netchan_CanReliable (netchan_t *chan)
203 {
204 if (chan->reliable_length)
205 return false; // waiting for ack
206 return Netchan_CanPacket (chan);
207 }
208
209 #ifdef SERVERONLY
210 qboolean ServerPaused(void);
211 #endif
212
213 /*
214 ===============
215 Netchan_Transmit
216
217 tries to send an unreliable message to a connection, and handles the
218 transmition / retransmition of the reliable messages.
219
220 A 0 length will still generate a packet and deal with the reliable messages.
221 ================
222 */
Netchan_Transmit(netchan_t * chan,int length,byte * data)223 void Netchan_Transmit (netchan_t *chan, int length, byte *data)
224 {
225 sizebuf_t send;
226 byte send_buf[MAX_MSGLEN + PACKET_HEADER];
227 qboolean send_reliable;
228 unsigned w1, w2;
229 int i;
230
231 // check for message overflow
232 if (chan->message.overflowed)
233 {
234 chan->fatal_error = true;
235 Con_Printf ("%s:Outgoing message overflow\n"
236 , NET_AdrToString (chan->remote_address));
237 return;
238 }
239
240 // if the remote side dropped the last reliable message, resend it
241 send_reliable = false;
242
243 if (chan->incoming_acknowledged > chan->last_reliable_sequence
244 && chan->incoming_reliable_acknowledged != chan->reliable_sequence)
245 send_reliable = true;
246
247 // if the reliable transmit buffer is empty, copy the current message out
248 if (!chan->reliable_length && chan->message.cursize)
249 {
250 memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
251 chan->reliable_length = chan->message.cursize;
252 chan->message.cursize = 0;
253 chan->reliable_sequence ^= 1;
254 send_reliable = true;
255 }
256
257 // write the packet header
258 send.data = send_buf;
259 send.maxsize = sizeof(send_buf);
260 send.cursize = 0;
261
262 w1 = chan->outgoing_sequence | (send_reliable<<31);
263 w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence<<31);
264
265 chan->outgoing_sequence++;
266
267 MSG_WriteLong (&send, w1);
268 MSG_WriteLong (&send, w2);
269
270 // send the qport if we are a client
271 #ifndef SERVERONLY
272 MSG_WriteShort (&send, cls.qport);
273 #endif
274
275 // copy the reliable message to the packet first
276 if (send_reliable)
277 {
278 SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
279 chan->last_reliable_sequence = chan->outgoing_sequence;
280 }
281
282 // add the unreliable part if space is available
283 if (send.maxsize - send.cursize >= length)
284 SZ_Write (&send, data, length);
285
286 // send the datagram
287 i = chan->outgoing_sequence & (MAX_LATENT-1);
288 chan->outgoing_size[i] = send.cursize;
289 chan->outgoing_time[i] = realtime;
290
291 //zoid, no input in demo playback mode
292 #ifndef SERVERONLY
293 if (!cls.demoplayback)
294 #endif
295 NET_SendPacket (send.cursize, send.data, chan->remote_address);
296
297 if (chan->cleartime < realtime)
298 chan->cleartime = realtime + send.cursize*chan->rate;
299 else
300 chan->cleartime += send.cursize*chan->rate;
301 #ifdef SERVERONLY
302 if (ServerPaused())
303 chan->cleartime = realtime;
304 #endif
305
306 if (showpackets.value)
307 Con_Printf ("--> s=%i(%i) a=%i(%i) %i\n"
308 , chan->outgoing_sequence
309 , send_reliable
310 , chan->incoming_sequence
311 , chan->incoming_reliable_sequence
312 , send.cursize);
313
314 }
315
316 /*
317 =================
318 Netchan_Process
319
320 called when the current net_message is from remote_address
321 modifies net_message so that it points to the packet payload
322 =================
323 */
Netchan_Process(netchan_t * chan)324 qboolean Netchan_Process (netchan_t *chan)
325 {
326 unsigned sequence, sequence_ack;
327 unsigned reliable_ack, reliable_message;
328 #ifdef SERVERONLY
329 int qport;
330 #endif
331 int i;
332
333 if (
334 #ifndef SERVERONLY
335 !cls.demoplayback &&
336 #endif
337 !NET_CompareAdr (net_from, chan->remote_address))
338 return false;
339
340 // get sequence numbers
341 MSG_BeginReading ();
342 sequence = MSG_ReadLong ();
343 sequence_ack = MSG_ReadLong ();
344
345 // read the qport if we are a server
346 #ifdef SERVERONLY
347 qport = MSG_ReadShort ();
348 #endif
349
350 reliable_message = sequence >> 31;
351 reliable_ack = sequence_ack >> 31;
352
353 sequence &= ~(1<<31);
354 sequence_ack &= ~(1<<31);
355
356 if (showpackets.value)
357 Con_Printf ("<-- s=%i(%i) a=%i(%i) %i\n"
358 , sequence
359 , reliable_message
360 , sequence_ack
361 , reliable_ack
362 , net_message.cursize);
363
364 // get a rate estimation
365 #if 0
366 if (chan->outgoing_sequence - sequence_ack < MAX_LATENT)
367 {
368 int i;
369 double time, rate;
370
371 i = sequence_ack & (MAX_LATENT - 1);
372 time = realtime - chan->outgoing_time[i];
373 time -= 0.1; // subtract 100 ms
374 if (time <= 0)
375 { // gotta be a digital link for <100 ms ping
376 if (chan->rate > 1.0/5000)
377 chan->rate = 1.0/5000;
378 }
379 else
380 {
381 if (chan->outgoing_size[i] < 512)
382 { // only deal with small messages
383 rate = chan->outgoing_size[i]/time;
384 if (rate > 5000)
385 rate = 5000;
386 rate = 1.0/rate;
387 if (chan->rate > rate)
388 chan->rate = rate;
389 }
390 }
391 }
392 #endif
393
394 //
395 // discard stale or duplicated packets
396 //
397 if (sequence <= (unsigned)chan->incoming_sequence)
398 {
399 if (showdrop.value)
400 Con_Printf ("%s:Out of order packet %i at %i\n"
401 , NET_AdrToString (chan->remote_address)
402 , sequence
403 , chan->incoming_sequence);
404 return false;
405 }
406
407 //
408 // dropped packets don't keep the message from being used
409 //
410 net_drop = sequence - (chan->incoming_sequence+1);
411 if (net_drop > 0)
412 {
413 chan->drop_count += 1;
414
415 if (showdrop.value)
416 Con_Printf ("%s:Dropped %i packets at %i\n"
417 , NET_AdrToString (chan->remote_address)
418 , sequence-(chan->incoming_sequence+1)
419 , sequence);
420 }
421
422 //
423 // if the current outgoing reliable message has been acknowledged
424 // clear the buffer to make way for the next
425 //
426 if (reliable_ack == (unsigned)chan->reliable_sequence)
427 chan->reliable_length = 0; // it has been received
428
429 //
430 // if this message contains a reliable message, bump incoming_reliable_sequence
431 //
432 chan->incoming_sequence = sequence;
433 chan->incoming_acknowledged = sequence_ack;
434 chan->incoming_reliable_acknowledged = reliable_ack;
435 if (reliable_message)
436 chan->incoming_reliable_sequence ^= 1;
437
438 //
439 // the message can now be read from the current message pointer
440 // update statistics counters
441 //
442 chan->frame_latency = chan->frame_latency*OLD_AVG
443 + (chan->outgoing_sequence-sequence_ack)*(1.0-OLD_AVG);
444 chan->frame_rate = chan->frame_rate*OLD_AVG
445 + (realtime-chan->last_received)*(1.0-OLD_AVG);
446 chan->good_count += 1;
447
448 chan->last_received = realtime;
449
450 return true;
451 }
452
453