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