Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

net_chan.c (10017B)


      1 /*
      2 Copyright (C) 1997-2001 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 "qcommon.h"
     22 
     23 /*
     24 
     25 packet header
     26 -------------
     27 31	sequence
     28 1	does this message contain a reliable payload
     29 31	acknowledge sequence
     30 1	acknowledge receipt of even/odd message
     31 16	qport
     32 
     33 The remote connection never knows if it missed a reliable message, the
     34 local side detects that it has been dropped by seeing a sequence acknowledge
     35 higher thatn the last reliable sequence, but without the correct evon/odd
     36 bit for the reliable set.
     37 
     38 If the sender notices that a reliable message has been dropped, it will be
     39 retransmitted.  It will not be retransmitted again until a message after
     40 the retransmit has been acknowledged and the reliable still failed to get there.
     41 
     42 if the sequence number is -1, the packet should be handled without a netcon
     43 
     44 The reliable message can be added to at any time by doing
     45 MSG_Write* (&netchan->message, <data>).
     46 
     47 If the message buffer is overflowed, either by a single message, or by
     48 multiple frames worth piling up while the last reliable transmit goes
     49 unacknowledged, the netchan signals a fatal error.
     50 
     51 Reliable messages are always placed first in a packet, then the unreliable
     52 message is included if there is sufficient room.
     53 
     54 To the receiver, there is no distinction between the reliable and unreliable
     55 parts of the message, they are just processed out as a single larger message.
     56 
     57 Illogical packet sequence numbers cause the packet to be dropped, but do
     58 not kill the connection.  This, combined with the tight window of valid
     59 reliable acknowledgement numbers provides protection against malicious
     60 address spoofing.
     61 
     62 
     63 The qport field is a workaround for bad address translating routers that
     64 sometimes remap the client's source port on a packet during gameplay.
     65 
     66 If the base part of the net address matches and the qport matches, then the
     67 channel matches even if the IP port differs.  The IP port should be updated
     68 to the new value before sending out any replies.
     69 
     70 
     71 If there is no information that needs to be transfered on a given frame,
     72 such as during the connection stage while waiting for the client to load,
     73 then a packet only needs to be delivered if there is something in the
     74 unacknowledged reliable
     75 */
     76 
     77 cvar_t		*showpackets;
     78 cvar_t		*showdrop;
     79 cvar_t		*qport;
     80 
     81 netadr_t	net_from;
     82 sizebuf_t	net_message;
     83 byte		net_message_buffer[MAX_MSGLEN];
     84 
     85 /*
     86 ===============
     87 Netchan_Init
     88 
     89 ===============
     90 */
     91 void Netchan_Init (void)
     92 {
     93 	int		port;
     94 
     95 	// pick a port value that should be nice and random
     96 	port = Sys_Milliseconds() & 0xffff;
     97 
     98 	showpackets = Cvar_Get ("showpackets", "0", 0);
     99 	showdrop = Cvar_Get ("showdrop", "0", 0);
    100 	qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
    101 }
    102 
    103 /*
    104 ===============
    105 Netchan_OutOfBand
    106 
    107 Sends an out-of-band datagram
    108 ================
    109 */
    110 void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
    111 {
    112 	sizebuf_t	send;
    113 	byte		send_buf[MAX_MSGLEN];
    114 
    115 // write the packet header
    116 	SZ_Init (&send, send_buf, sizeof(send_buf));
    117 	
    118 	MSG_WriteLong (&send, -1);	// -1 sequence means out of band
    119 	SZ_Write (&send, data, length);
    120 
    121 // send the datagram
    122 	NET_SendPacket (net_socket, send.cursize, send.data, adr);
    123 }
    124 
    125 /*
    126 ===============
    127 Netchan_OutOfBandPrint
    128 
    129 Sends a text message in an out-of-band datagram
    130 ================
    131 */
    132 void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
    133 {
    134 	va_list		argptr;
    135 	static char		string[MAX_MSGLEN - 4];
    136 	
    137 	va_start (argptr, format);
    138 	vsprintf (string, format,argptr);
    139 	va_end (argptr);
    140 
    141 	Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
    142 }
    143 
    144 
    145 /*
    146 ==============
    147 Netchan_Setup
    148 
    149 called to open a channel to a remote system
    150 ==============
    151 */
    152 void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
    153 {
    154 	memset (chan, 0, sizeof(*chan));
    155 	
    156 	chan->sock = sock;
    157 	chan->remote_address = adr;
    158 	chan->qport = qport;
    159 	chan->last_received = curtime;
    160 	chan->incoming_sequence = 0;
    161 	chan->outgoing_sequence = 1;
    162 
    163 	SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
    164 	chan->message.allowoverflow = true;
    165 }
    166 
    167 
    168 /*
    169 ===============
    170 Netchan_CanReliable
    171 
    172 Returns true if the last reliable message has acked
    173 ================
    174 */
    175 qboolean Netchan_CanReliable (netchan_t *chan)
    176 {
    177 	if (chan->reliable_length)
    178 		return false;			// waiting for ack
    179 	return true;
    180 }
    181 
    182 
    183 qboolean Netchan_NeedReliable (netchan_t *chan)
    184 {
    185 	qboolean	send_reliable;
    186 
    187 // if the remote side dropped the last reliable message, resend it
    188 	send_reliable = false;
    189 
    190 	if (chan->incoming_acknowledged > chan->last_reliable_sequence
    191 	&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
    192 		send_reliable = true;
    193 
    194 // if the reliable transmit buffer is empty, copy the current message out
    195 	if (!chan->reliable_length && chan->message.cursize)
    196 	{
    197 		send_reliable = true;
    198 	}
    199 
    200 	return send_reliable;
    201 }
    202 
    203 /*
    204 ===============
    205 Netchan_Transmit
    206 
    207 tries to send an unreliable message to a connection, and handles the
    208 transmition / retransmition of the reliable messages.
    209 
    210 A 0 length will still generate a packet and deal with the reliable messages.
    211 ================
    212 */
    213 void Netchan_Transmit (netchan_t *chan, int length, byte *data)
    214 {
    215 	sizebuf_t	send;
    216 	byte		send_buf[MAX_MSGLEN];
    217 	qboolean	send_reliable;
    218 	unsigned	w1, w2;
    219 
    220 // check for message overflow
    221 	if (chan->message.overflowed)
    222 	{
    223 		chan->fatal_error = true;
    224 		Com_Printf ("%s:Outgoing message overflow\n"
    225 			, NET_AdrToString (chan->remote_address));
    226 		return;
    227 	}
    228 
    229 	send_reliable = Netchan_NeedReliable (chan);
    230 
    231 	if (!chan->reliable_length && chan->message.cursize)
    232 	{
    233 		memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
    234 		chan->reliable_length = chan->message.cursize;
    235 		chan->message.cursize = 0;
    236 		chan->reliable_sequence ^= 1;
    237 	}
    238 
    239 
    240 // write the packet header
    241 	SZ_Init (&send, send_buf, sizeof(send_buf));
    242 
    243 	w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
    244 	w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
    245 
    246 	chan->outgoing_sequence++;
    247 	chan->last_sent = curtime;
    248 
    249 	MSG_WriteLong (&send, w1);
    250 	MSG_WriteLong (&send, w2);
    251 
    252 	// send the qport if we are a client
    253 	if (chan->sock == NS_CLIENT)
    254 		MSG_WriteShort (&send, qport->value);
    255 
    256 // copy the reliable message to the packet first
    257 	if (send_reliable)
    258 	{
    259 		SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
    260 		chan->last_reliable_sequence = chan->outgoing_sequence;
    261 	}
    262 	
    263 // add the unreliable part if space is available
    264 	if (send.maxsize - send.cursize >= length)
    265 		SZ_Write (&send, data, length);
    266 	else
    267 		Com_Printf ("Netchan_Transmit: dumped unreliable\n");
    268 
    269 // send the datagram
    270 	NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
    271 
    272 	if (showpackets->value)
    273 	{
    274 		if (send_reliable)
    275 			Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
    276 				, send.cursize
    277 				, chan->outgoing_sequence - 1
    278 				, chan->reliable_sequence
    279 				, chan->incoming_sequence
    280 				, chan->incoming_reliable_sequence);
    281 		else
    282 			Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
    283 				, send.cursize
    284 				, chan->outgoing_sequence - 1
    285 				, chan->incoming_sequence
    286 				, chan->incoming_reliable_sequence);
    287 	}
    288 }
    289 
    290 /*
    291 =================
    292 Netchan_Process
    293 
    294 called when the current net_message is from remote_address
    295 modifies net_message so that it points to the packet payload
    296 =================
    297 */
    298 qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
    299 {
    300 	unsigned	sequence, sequence_ack;
    301 	unsigned	reliable_ack, reliable_message;
    302 	int			qport;
    303 
    304 // get sequence numbers		
    305 	MSG_BeginReading (msg);
    306 	sequence = MSG_ReadLong (msg);
    307 	sequence_ack = MSG_ReadLong (msg);
    308 
    309 	// read the qport if we are a server
    310 	if (chan->sock == NS_SERVER)
    311 		qport = MSG_ReadShort (msg);
    312 
    313 	reliable_message = sequence >> 31;
    314 	reliable_ack = sequence_ack >> 31;
    315 
    316 	sequence &= ~(1<<31);
    317 	sequence_ack &= ~(1<<31);	
    318 
    319 	if (showpackets->value)
    320 	{
    321 		if (reliable_message)
    322 			Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
    323 				, msg->cursize
    324 				, sequence
    325 				, chan->incoming_reliable_sequence ^ 1
    326 				, sequence_ack
    327 				, reliable_ack);
    328 		else
    329 			Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
    330 				, msg->cursize
    331 				, sequence
    332 				, sequence_ack
    333 				, reliable_ack);
    334 	}
    335 
    336 //
    337 // discard stale or duplicated packets
    338 //
    339 	if (sequence <= chan->incoming_sequence)
    340 	{
    341 		if (showdrop->value)
    342 			Com_Printf ("%s:Out of order packet %i at %i\n"
    343 				, NET_AdrToString (chan->remote_address)
    344 				,  sequence
    345 				, chan->incoming_sequence);
    346 		return false;
    347 	}
    348 
    349 //
    350 // dropped packets don't keep the message from being used
    351 //
    352 	chan->dropped = sequence - (chan->incoming_sequence+1);
    353 	if (chan->dropped > 0)
    354 	{
    355 		if (showdrop->value)
    356 			Com_Printf ("%s:Dropped %i packets at %i\n"
    357 			, NET_AdrToString (chan->remote_address)
    358 			, chan->dropped
    359 			, sequence);
    360 	}
    361 
    362 //
    363 // if the current outgoing reliable message has been acknowledged
    364 // clear the buffer to make way for the next
    365 //
    366 	if (reliable_ack == chan->reliable_sequence)
    367 		chan->reliable_length = 0;	// it has been received
    368 	
    369 //
    370 // if this message contains a reliable message, bump incoming_reliable_sequence 
    371 //
    372 	chan->incoming_sequence = sequence;
    373 	chan->incoming_acknowledged = sequence_ack;
    374 	chan->incoming_reliable_acknowledged = reliable_ack;
    375 	if (reliable_message)
    376 	{
    377 		chan->incoming_reliable_sequence ^= 1;
    378 	}
    379 
    380 //
    381 // the message can now be read from the current message pointer
    382 //
    383 	chan->last_received = curtime;
    384 
    385 	return true;
    386 }
    387