Home | History | Annotate | Download | only in client
      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 */
     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 */
    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 */
    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 */
    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
    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 */
    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 */
    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 */
    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