• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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