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