Quake II RTX doxygen  1.0 dev
chan.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 #include "shared/shared.h"
20 #include "common/common.h"
21 #include "common/cvar.h"
22 #include "common/msg.h"
23 #include "common/net/chan.h"
24 #include "common/net/net.h"
25 #include "common/protocol.h"
26 #include "common/sizebuf.h"
27 #include "common/zone.h"
28 #include "system/system.h"
29 
30 /*
31 
32 packet header
33 -------------
34 31 sequence
35 1 does this message contain a reliable payload
36 31 acknowledge sequence
37 1 acknowledge receipt of even/odd message
38 16 qport
39 
40 The remote connection never knows if it missed a reliable message, the
41 local side detects that it has been dropped by seeing a sequence acknowledge
42 higher thatn the last reliable sequence, but without the correct evon/odd
43 bit for the reliable set.
44 
45 If the sender notices that a reliable message has been dropped, it will be
46 retransmitted. It will not be retransmitted again until a message after
47 the retransmit has been acknowledged and the reliable still failed to get theref.
48 
49 if the sequence number is -1, the packet should be handled without a netcon
50 
51 The reliable message can be added to at any time by doing
52 MSG_Write* (&netchan->message, <data>).
53 
54 If the message buffer is overflowed, either by a single message, or by
55 multiple frames worth piling up while the last reliable transmit goes
56 unacknowledged, the netchan signals a fatal error.
57 
58 Reliable messages are always placed first in a packet, then the unreliable
59 message is included if there is sufficient room.
60 
61 To the receiver, there is no distinction between the reliable and unreliable
62 parts of the message, they are just processed out as a single larger message.
63 
64 Illogical packet sequence numbers cause the packet to be dropped, but do
65 not kill the connection. This, combined with the tight window of valid
66 reliable acknowledgement numbers provides protection against malicious
67 address spoofing.
68 
69 
70 The qport field is a workaround for bad address translating routers that
71 sometimes remap the client's source port on a packet during gameplay.
72 
73 If the base part of the net address matches and the qport matches, then the
74 channel matches even if the IP port differs. The IP port should be updated
75 to the new value before sending out any replies.
76 
77 
78 If there is no information that needs to be transfered on a given frame,
79 such as during the connection stage while waiting for the client to load,
80 then a packet only needs to be delivered if there is something in the
81 unacknowledged reliable
82 */
83 
84 #ifdef _DEBUG
85 static cvar_t *showpackets;
86 static cvar_t *showdrop;
87 #define SHOWPACKET(...) \
88  if (showpackets->integer) \
89  Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__)
90 #define SHOWDROP(...) \
91  if (showdrop->integer) \
92  Com_LPrintf(PRINT_DEVELOPER, __VA_ARGS__)
93 #else
94 #define SHOWPACKET(...)
95 #define SHOWDROP(...)
96 #endif
97 
98 cvar_t *net_qport;
99 cvar_t *net_maxmsglen;
100 cvar_t *net_chantype;
101 
102 // allow either 0 (no hard limit), or an integer between 512 and 4086
103 static void net_maxmsglen_changed(cvar_t *self)
104 {
105  if (self->integer) {
106  Cvar_ClampInteger(self, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE);
107  }
108 }
109 
110 /*
111 ===============
112 Netchan_Init
113 
114 ===============
115 */
116 void Netchan_Init(void)
117 {
118  int port;
119 
120 #ifdef _DEBUG
121  showpackets = Cvar_Get("showpackets", "0", 0);
122  showdrop = Cvar_Get("showdrop", "0", 0);
123 #endif
124 
125  // pick a port value that should be nice and random
126  port = Sys_Milliseconds() & 0xffff;
127  net_qport = Cvar_Get("qport", va("%d", port), 0);
128  net_maxmsglen = Cvar_Get("net_maxmsglen", va("%d", MAX_PACKETLEN_WRITABLE_DEFAULT), 0);
130  net_chantype = Cvar_Get("net_chantype", "1", 0);
131 }
132 
133 /*
134 ===============
135 Netchan_OutOfBand
136 
137 Sends a text message in an out-of-band datagram
138 ================
139 */
140 void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address,
141  const char *format, ...)
142 {
143  va_list argptr;
144  struct {
145  uint32_t header;
146  char data[MAX_PACKETLEN_DEFAULT - 4];
147  } packet;
148  size_t len;
149 
150  // write the packet header
151  packet.header = 0xffffffff;
152 
153  va_start(argptr, format);
154  len = Q_vsnprintf(packet.data, sizeof(packet.data), format, argptr);
155  va_end(argptr);
156 
157  if (len >= sizeof(packet.data)) {
158  Com_WPrintf("%s: overflow\n", __func__);
159  return;
160  }
161 
162  // send the datagram
163  NET_SendPacket(sock, &packet, len + 4, address);
164 }
165 
166 // ============================================================================
167 
168 static size_t NetchanOld_TransmitNextFragment(netchan_t *netchan)
169 {
170  Com_Error(ERR_FATAL, "%s: not implemented", __func__);
171  return 0;
172 }
173 
174 /*
175 ===============
176 NetchanOld_Transmit
177 
178 tries to send an unreliable message to a connection, and handles the
179 transmition / retransmition of the reliable messages.
180 
181 A 0 length will still generate a packet and deal with the reliable messages.
182 ================
183 */
184 static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets)
185 {
186  netchan_old_t *chan = (netchan_old_t *)netchan;
187  sizebuf_t send;
188  byte send_buf[MAX_PACKETLEN];
189  qboolean send_reliable;
190  uint32_t w1, w2;
191  int i;
192 
193 // check for message overflow
194  if (netchan->message.overflowed) {
195  netchan->fatal_error = qtrue;
196  Com_WPrintf("%s: outgoing message overflow\n",
197  NET_AdrToString(&netchan->remote_address));
198  return 0;
199  }
200 
201  send_reliable = qfalse;
202 
203  // if the remote side dropped the last reliable message, resend it
204  if (netchan->incoming_acknowledged > chan->last_reliable_sequence &&
205  chan->incoming_reliable_acknowledged != chan->reliable_sequence) {
206  send_reliable = qtrue;
207  }
208 
209 // if the reliable transmit buffer is empty, copy the current message out
210  if (!netchan->reliable_length && netchan->message.cursize) {
211  send_reliable = qtrue;
212  memcpy(chan->reliable_buf, chan->message_buf,
213  netchan->message.cursize);
214  netchan->reliable_length = netchan->message.cursize;
215  netchan->message.cursize = 0;
216  chan->reliable_sequence ^= 1;
217  }
218 
219 // write the packet header
220  w1 = (netchan->outgoing_sequence & ~(1 << 31)) |
221  (send_reliable << 31);
222  w2 = (netchan->incoming_sequence & ~(1 << 31)) |
223  (chan->incoming_reliable_sequence << 31);
224 
225  SZ_TagInit(&send, send_buf, sizeof(send_buf), SZ_NC_SEND_OLD);
226 
227  SZ_WriteLong(&send, w1);
228  SZ_WriteLong(&send, w2);
229 
230 #if USE_CLIENT
231  // send the qport if we are a client
232  if (netchan->sock == NS_CLIENT) {
233  if (netchan->protocol < PROTOCOL_VERSION_R1Q2) {
234  SZ_WriteShort(&send, netchan->qport);
235  } else if (netchan->qport) {
236  SZ_WriteByte(&send, netchan->qport);
237  }
238  }
239 #endif
240 
241 // copy the reliable message to the packet first
242  if (send_reliable) {
243  SZ_Write(&send, chan->reliable_buf, netchan->reliable_length);
244  chan->last_reliable_sequence = netchan->outgoing_sequence;
245  }
246 
247 // add the unreliable part if space is available
248  if (send.maxsize - send.cursize >= length)
249  SZ_Write(&send, data, length);
250  else
251  Com_WPrintf("%s: dumped unreliable\n",
252  NET_AdrToString(&netchan->remote_address));
253 
254  SHOWPACKET("send %4"PRIz" : s=%d ack=%d rack=%d",
255  send.cursize,
256  netchan->outgoing_sequence,
257  netchan->incoming_sequence,
258  chan->incoming_reliable_sequence);
259  if (send_reliable) {
260  SHOWPACKET(" reliable=%i", chan->reliable_sequence);
261  }
262  SHOWPACKET("\n");
263 
264  // send the datagram
265  for (i = 0; i < numpackets; i++) {
266  NET_SendPacket(netchan->sock, send.data, send.cursize,
267  &netchan->remote_address);
268  }
269 
270  netchan->outgoing_sequence++;
271  netchan->reliable_ack_pending = qfalse;
272  netchan->last_sent = com_localTime;
273 
274  return send.cursize * numpackets;
275 }
276 
277 /*
278 =================
279 NetchanOld_Process
280 
281 called when the current net_message is from remote_address
282 modifies net_message so that it points to the packet payload
283 =================
284 */
285 static qboolean NetchanOld_Process(netchan_t *netchan)
286 {
287  netchan_old_t *chan = (netchan_old_t *)netchan;
288  uint32_t sequence, sequence_ack;
289  uint32_t reliable_ack, reliable_message;
290 
291 // get sequence numbers
293  sequence = MSG_ReadLong();
294  sequence_ack = MSG_ReadLong();
295 
296  // read the qport if we are a server
297 #if USE_CLIENT
298  if (netchan->sock == NS_SERVER)
299 #endif
300  {
301  if (netchan->protocol < PROTOCOL_VERSION_R1Q2) {
302  MSG_ReadShort();
303  } else if (netchan->qport) {
304  MSG_ReadByte();
305  }
306  }
307 
308  reliable_message = sequence >> 31;
309  reliable_ack = sequence_ack >> 31;
310 
311  sequence &= ~(1 << 31);
312  sequence_ack &= ~(1 << 31);
313 
314  SHOWPACKET("recv %4"PRIz" : s=%d ack=%d rack=%d",
315  msg_read.cursize,
316  sequence,
317  sequence_ack,
318  reliable_ack);
319  if (reliable_message) {
320  SHOWPACKET(" reliable=%d", chan->incoming_reliable_sequence ^ 1);
321  }
322  SHOWPACKET("\n");
323 
324 //
325 // discard stale or duplicated packets
326 //
327  if (sequence <= netchan->incoming_sequence) {
328  SHOWDROP("%s: out of order packet %i at %i\n",
329  NET_AdrToString(&netchan->remote_address),
330  sequence, netchan->incoming_sequence);
331  return qfalse;
332  }
333 
334 //
335 // dropped packets don't keep the message from being used
336 //
337  netchan->dropped = sequence - (netchan->incoming_sequence + 1);
338  if (netchan->dropped > 0) {
339  SHOWDROP("%s: dropped %i packets at %i\n",
340  NET_AdrToString(&netchan->remote_address),
341  netchan->dropped, sequence);
342  }
343 
344 //
345 // if the current outgoing reliable message has been acknowledged
346 // clear the buffer to make way for the next
347 //
348  chan->incoming_reliable_acknowledged = reliable_ack;
349  if (reliable_ack == chan->reliable_sequence)
350  netchan->reliable_length = 0; // it has been received
351 
352 //
353 // if this message contains a reliable message, bump incoming_reliable_sequence
354 //
355  netchan->incoming_sequence = sequence;
356  netchan->incoming_acknowledged = sequence_ack;
357  if (reliable_message) {
358  netchan->reliable_ack_pending = qtrue;
359  chan->incoming_reliable_sequence ^= 1;
360  }
361 
362 //
363 // the message can now be read from the current message pointer
364 //
365  netchan->last_received = com_localTime;
366 
367  netchan->total_dropped += netchan->dropped;
368  netchan->total_received += netchan->dropped + 1;
369 
370  return qtrue;
371 }
372 
373 /*
374 ===============
375 NetchanOld_ShouldUpdate
376 ================
377 */
378 static qboolean NetchanOld_ShouldUpdate(netchan_t *netchan)
379 {
380  if (netchan->message.cursize || netchan->reliable_ack_pending ||
381  com_localTime - netchan->last_sent > 1000) {
382  return qtrue;
383  }
384 
385  return qfalse;
386 }
387 
388 /*
389 ==============
390 NetchanOld_Setup
391 
392 called to open a channel to a remote system
393 ==============
394 */
395 static netchan_t *NetchanOld_Setup(netsrc_t sock, const netadr_t *adr,
396  int qport, size_t maxpacketlen)
397 {
398  netchan_old_t *chan;
399  netchan_t *netchan;
400 
401  Z_TagReserve(sizeof(*chan) + maxpacketlen * 2,
402  sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL);
403 
404  chan = Z_ReservedAlloc(sizeof(*chan));
405  memset(chan, 0, sizeof(*chan));
406  netchan = (netchan_t *)chan;
407  netchan->sock = sock;
408  netchan->remote_address = *adr;
409  netchan->qport = qport;
410  netchan->maxpacketlen = maxpacketlen;
411  netchan->last_received = com_localTime;
412  netchan->last_sent = com_localTime;
413  netchan->incoming_sequence = 0;
414  netchan->outgoing_sequence = 1;
415 
416  netchan->Process = NetchanOld_Process;
417  netchan->Transmit = NetchanOld_Transmit;
418  netchan->TransmitNextFragment = NetchanOld_TransmitNextFragment;
419  netchan->ShouldUpdate = NetchanOld_ShouldUpdate;
420 
421  chan->message_buf = Z_ReservedAlloc(maxpacketlen);
422  SZ_Init(&netchan->message, chan->message_buf, maxpacketlen);
423 
424  chan->reliable_buf = Z_ReservedAlloc(maxpacketlen);
425 
426  return netchan;
427 }
428 
429 // ============================================================================
430 
431 
432 /*
433 ===============
434 NetchanNew_TransmitNextFragment
435 ================
436 */
437 static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan)
438 {
439  netchan_new_t *chan = (netchan_new_t *)netchan;
440  sizebuf_t send;
441  byte send_buf[MAX_PACKETLEN];
442  qboolean send_reliable;
443  uint32_t w1, w2;
444  uint16_t offset;
445  size_t fragment_length;
446  qboolean more_fragments;
447 
448  send_reliable = netchan->reliable_length ? qtrue : qfalse;
449 
450  // write the packet header
451  w1 = (netchan->outgoing_sequence & 0x3FFFFFFF) | (1 << 30) |
452  (send_reliable << 31);
453  w2 = (netchan->incoming_sequence & 0x3FFFFFFF) | (0 << 30) |
454  (chan->incoming_reliable_sequence << 31);
455 
456  SZ_TagInit(&send, send_buf, sizeof(send_buf), SZ_NC_SEND_FRG);
457 
458  SZ_WriteLong(&send, w1);
459  SZ_WriteLong(&send, w2);
460 
461 #if USE_CLIENT
462  // send the qport if we are a client
463  if (netchan->sock == NS_CLIENT && netchan->qport) {
464  SZ_WriteByte(&send, netchan->qport);
465  }
466 #endif
467 
468  fragment_length = chan->fragment_out.cursize - chan->fragment_out.readcount;
469  if (fragment_length > netchan->maxpacketlen) {
470  fragment_length = netchan->maxpacketlen;
471  }
472 
473  more_fragments = qtrue;
474  if (chan->fragment_out.readcount + fragment_length ==
475  chan->fragment_out.cursize) {
476  more_fragments = qfalse;
477  }
478 
479  // write fragment offset
480  offset = (chan->fragment_out.readcount & 0x7FFF) |
481  (more_fragments << 15);
482  SZ_WriteShort(&send, offset);
483 
484  // write fragment contents
485  SZ_Write(&send, chan->fragment_out.data + chan->fragment_out.readcount,
486  fragment_length);
487 
488  SHOWPACKET("send %4"PRIz" : s=%d ack=%d rack=%d "
489  "fragment_offset=%"PRIz" more_fragments=%d",
490  send.cursize,
491  netchan->outgoing_sequence,
492  netchan->incoming_sequence,
493  chan->incoming_reliable_sequence,
494  chan->fragment_out.readcount,
495  more_fragments);
496  if (send_reliable) {
497  SHOWPACKET(" reliable=%i ", chan->reliable_sequence);
498  }
499  SHOWPACKET("\n");
500 
501  chan->fragment_out.readcount += fragment_length;
502  netchan->fragment_pending = more_fragments;
503 
504  // if the message has been sent completely, clear the fragment buffer
505  if (!netchan->fragment_pending) {
506  netchan->outgoing_sequence++;
507  netchan->last_sent = com_localTime;
508  SZ_Clear(&chan->fragment_out);
509  }
510 
511  // send the datagram
512  NET_SendPacket(netchan->sock, send.data, send.cursize,
513  &netchan->remote_address);
514 
515  return send.cursize;
516 }
517 
518 /*
519 ===============
520 NetchanNew_Transmit
521 ================
522 */
523 static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets)
524 {
525  netchan_new_t *chan = (netchan_new_t *)netchan;
526  sizebuf_t send;
527  byte send_buf[MAX_PACKETLEN];
528  qboolean send_reliable;
529  uint32_t w1, w2;
530  int i;
531 
532 // check for message overflow
533  if (netchan->message.overflowed) {
534  netchan->fatal_error = qtrue;
535  Com_WPrintf("%s: outgoing message overflow\n",
536  NET_AdrToString(&netchan->remote_address));
537  return 0;
538  }
539 
540  if (netchan->fragment_pending) {
541  return NetchanNew_TransmitNextFragment(netchan);
542  }
543 
544  send_reliable = qfalse;
545 
546 // if the remote side dropped the last reliable message, resend it
547  if (netchan->incoming_acknowledged > chan->last_reliable_sequence &&
548  chan->incoming_reliable_acknowledged != chan->reliable_sequence) {
549  send_reliable = qtrue;
550  }
551 
552 // if the reliable transmit buffer is empty, copy the current message out
553  if (!netchan->reliable_length && netchan->message.cursize) {
554  send_reliable = qtrue;
555  memcpy(chan->reliable_buf, chan->message_buf,
556  netchan->message.cursize);
557  netchan->reliable_length = netchan->message.cursize;
558  netchan->message.cursize = 0;
559  chan->reliable_sequence ^= 1;
560  }
561 
562  if (length > netchan->maxpacketlen || (send_reliable &&
563  (netchan->reliable_length + length > netchan->maxpacketlen))) {
564  if (send_reliable) {
565  chan->last_reliable_sequence = netchan->outgoing_sequence;
566  SZ_Write(&chan->fragment_out, chan->reliable_buf,
567  netchan->reliable_length);
568  }
569  // add the unreliable part if space is available
570  if (chan->fragment_out.maxsize - chan->fragment_out.cursize >= length)
571  SZ_Write(&chan->fragment_out, data, length);
572  else
573  Com_WPrintf("%s: dumped unreliable\n",
574  NET_AdrToString(&netchan->remote_address));
575  return NetchanNew_TransmitNextFragment(netchan);
576  }
577 
578 // write the packet header
579  w1 = (netchan->outgoing_sequence & 0x3FFFFFFF) | (send_reliable << 31);
580  w2 = (netchan->incoming_sequence & 0x3FFFFFFF) |
581  (chan->incoming_reliable_sequence << 31);
582 
583  SZ_TagInit(&send, send_buf, sizeof(send_buf), SZ_NC_SEND_NEW);
584 
585  SZ_WriteLong(&send, w1);
586  SZ_WriteLong(&send, w2);
587 
588 #if USE_CLIENT
589  // send the qport if we are a client
590  if (netchan->sock == NS_CLIENT && netchan->qport) {
591  SZ_WriteByte(&send, netchan->qport);
592  }
593 #endif
594 
595  // copy the reliable message to the packet first
596  if (send_reliable) {
597  chan->last_reliable_sequence = netchan->outgoing_sequence;
598  SZ_Write(&send, chan->reliable_buf, netchan->reliable_length);
599  }
600 
601  // add the unreliable part
602  SZ_Write(&send, data, length);
603 
604  SHOWPACKET("send %4"PRIz" : s=%d ack=%d rack=%d",
605  send.cursize,
606  netchan->outgoing_sequence,
607  netchan->incoming_sequence,
608  chan->incoming_reliable_sequence);
609  if (send_reliable) {
610  SHOWPACKET(" reliable=%d", chan->reliable_sequence);
611  }
612  SHOWPACKET("\n");
613 
614  // send the datagram
615  for (i = 0; i < numpackets; i++) {
616  NET_SendPacket(netchan->sock, send.data, send.cursize,
617  &netchan->remote_address);
618  }
619 
620  netchan->outgoing_sequence++;
621  netchan->reliable_ack_pending = qfalse;
622  netchan->last_sent = com_localTime;
623 
624  return send.cursize * numpackets;
625 }
626 
627 /*
628 =================
629 NetchanNew_Process
630 =================
631 */
632 static qboolean NetchanNew_Process(netchan_t *netchan)
633 {
634  netchan_new_t *chan = (netchan_new_t *)netchan;
635  uint32_t sequence, sequence_ack, reliable_ack;
636  qboolean reliable_message, fragmented_message, more_fragments;
637  uint16_t fragment_offset;
638  size_t length;
639 
640 // get sequence numbers
642  sequence = MSG_ReadLong();
643  sequence_ack = MSG_ReadLong();
644 
645  // read the qport if we are a server
646 #if USE_CLIENT
647  if (netchan->sock == NS_SERVER)
648 #endif
649  if (netchan->qport) {
650  MSG_ReadByte();
651  }
652 
653  reliable_message = sequence >> 31;
654  reliable_ack = sequence_ack >> 31;
655  fragmented_message = (sequence >> 30) & 1;
656 
657  sequence &= 0x3FFFFFFF;
658  sequence_ack &= 0x3FFFFFFF;
659 
660  fragment_offset = 0;
661  more_fragments = qfalse;
662  if (fragmented_message) {
663  fragment_offset = MSG_ReadShort();
664  more_fragments = fragment_offset >> 15;
665  fragment_offset &= 0x7FFF;
666  }
667 
668  SHOWPACKET("recv %4"PRIz" : s=%d ack=%d rack=%d",
669  msg_read.cursize, sequence, sequence_ack, reliable_ack);
670  if (fragmented_message) {
671  SHOWPACKET(" fragment_offset=%d more_fragments=%d",
672  fragment_offset, more_fragments);
673  }
674  if (reliable_message) {
675  SHOWPACKET(" reliable=%d", chan->incoming_reliable_sequence ^ 1);
676  }
677  SHOWPACKET("\n");
678 
679 //
680 // discard stale or duplicated packets
681 //
682  if (sequence <= netchan->incoming_sequence) {
683  SHOWDROP("%s: out of order packet %i at %i\n",
684  NET_AdrToString(&netchan->remote_address),
685  sequence, netchan->incoming_sequence);
686  return qfalse;
687  }
688 
689 //
690 // dropped packets don't keep the message from being used
691 //
692  netchan->dropped = sequence - (netchan->incoming_sequence + 1);
693  if (netchan->dropped > 0) {
694  SHOWDROP("%s: dropped %i packets at %i\n",
695  NET_AdrToString(&netchan->remote_address),
696  netchan->dropped, sequence);
697  }
698 
699 //
700 // if the current outgoing reliable message has been acknowledged
701 // clear the buffer to make way for the next
702 //
703  chan->incoming_reliable_acknowledged = reliable_ack;
704  if (reliable_ack == chan->reliable_sequence) {
705  netchan->reliable_length = 0; // it has been received
706  }
707 
708 
709 //
710 // parse fragment header, if any
711 //
712  if (fragmented_message) {
713  if (chan->fragment_sequence != sequence) {
714  // start new receive sequence
715  chan->fragment_sequence = sequence;
716  SZ_Clear(&chan->fragment_in);
717  }
718 
719  if (fragment_offset < chan->fragment_in.cursize) {
720  SHOWDROP("%s: out of order fragment at %i\n",
721  NET_AdrToString(&netchan->remote_address), sequence);
722  return qfalse;
723  }
724 
725  if (fragment_offset > chan->fragment_in.cursize) {
726  SHOWDROP("%s: dropped fragment(s) at %i\n",
727  NET_AdrToString(&netchan->remote_address), sequence);
728  return qfalse;
729  }
730 
731  length = msg_read.cursize - msg_read.readcount;
732  if (chan->fragment_in.cursize + length > chan->fragment_in.maxsize) {
733  SHOWDROP("%s: oversize fragment at %i\n",
734  NET_AdrToString(&netchan->remote_address), sequence);
735  return qfalse;
736  }
737 
738  SZ_Write(&chan->fragment_in, msg_read.data +
739  msg_read.readcount, length);
740  if (more_fragments) {
741  return qfalse;
742  }
743 
744  // message has been sucessfully assembled
745  SZ_Clear(&msg_read);
746  SZ_Write(&msg_read, chan->fragment_in.data,
747  chan->fragment_in.cursize);
748  SZ_Clear(&chan->fragment_in);
749  }
750 
751  netchan->incoming_sequence = sequence;
752  netchan->incoming_acknowledged = sequence_ack;
753 
754 //
755 // if this message contains a reliable message, bump incoming_reliable_sequence
756 //
757  if (reliable_message) {
758  netchan->reliable_ack_pending = qtrue;
759  chan->incoming_reliable_sequence ^= 1;
760  }
761 
762 //
763 // the message can now be read from the current message pointer
764 //
765  netchan->last_received = com_localTime;
766 
767  netchan->total_dropped += netchan->dropped;
768  netchan->total_received += netchan->dropped + 1;
769 
770  return qtrue;
771 }
772 
773 /*
774 ==============
775 NetchanNew_ShouldUpdate
776 ==============
777 */
778 static qboolean NetchanNew_ShouldUpdate(netchan_t *netchan)
779 {
780  netchan_new_t *chan = (netchan_new_t *)netchan;
781 
782  if (netchan->message.cursize ||
783  netchan->reliable_ack_pending ||
784  chan->fragment_out.cursize ||
785  com_localTime - netchan->last_sent > 1000) {
786  return qtrue;
787  }
788 
789  return qfalse;
790 }
791 
792 /*
793 ==============
794 NetchanNew_Setup
795 ==============
796 */
797 static netchan_t *NetchanNew_Setup(netsrc_t sock, const netadr_t *adr,
798  int qport, size_t maxpacketlen)
799 {
800  netchan_new_t *chan;
801  netchan_t *netchan;
802 
803  chan = Z_TagMallocz(sizeof(*chan),
804  sock == NS_SERVER ? TAG_SERVER : TAG_GENERAL);
805  netchan = (netchan_t *)chan;
806  netchan->sock = sock;
807  netchan->remote_address = *adr;
808  netchan->qport = qport;
809  netchan->maxpacketlen = maxpacketlen;
810  netchan->last_received = com_localTime;
811  netchan->last_sent = com_localTime;
812  netchan->incoming_sequence = 0;
813  netchan->outgoing_sequence = 1;
814 
815  netchan->Process = NetchanNew_Process;
816  netchan->Transmit = NetchanNew_Transmit;
817  netchan->TransmitNextFragment = NetchanNew_TransmitNextFragment;
818  netchan->ShouldUpdate = NetchanNew_ShouldUpdate;
819 
820  SZ_Init(&netchan->message, chan->message_buf,
821  sizeof(chan->message_buf));
822  SZ_TagInit(&chan->fragment_in, chan->fragment_in_buf,
823  sizeof(chan->fragment_in_buf), SZ_NC_FRG_IN);
824  SZ_TagInit(&chan->fragment_out, chan->fragment_out_buf,
825  sizeof(chan->fragment_out_buf), SZ_NC_FRG_OUT);
826 
827  return netchan;
828 }
829 
830 /*
831 ==============
832 Netchan_Setup
833 ==============
834 */
835 netchan_t *Netchan_Setup(netsrc_t sock, netchan_type_t type,
836  const netadr_t *adr, int qport, size_t maxpacketlen, int protocol)
837 {
838  netchan_t *netchan;
839 
840  clamp(maxpacketlen, MIN_PACKETLEN, MAX_PACKETLEN_WRITABLE);
841 
842  switch (type) {
843  case NETCHAN_OLD:
844  netchan = NetchanOld_Setup(sock, adr, qport, maxpacketlen);
845  break;
846  case NETCHAN_NEW:
847  netchan = NetchanNew_Setup(sock, adr, qport, maxpacketlen);
848  break;
849  default:
850  Com_Error(ERR_FATAL, "Netchan_Setup: bad type");
851  netchan = NULL;
852  }
853 
854  netchan->protocol = protocol;
855  netchan->type = type;
856 
857  return netchan;
858 
859 }
860 
861 /*
862 ==============
863 Netchan_Close
864 ==============
865 */
866 void Netchan_Close(netchan_t *netchan)
867 {
868  Z_Free(netchan);
869 }
870 
Z_ReservedAlloc
void * Z_ReservedAlloc(size_t size)
Definition: zone.c:349
NetchanOld_Process
static qboolean NetchanOld_Process(netchan_t *netchan)
Definition: chan.c:285
msg_read
sizebuf_t msg_read
Definition: msg.c:37
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
Netchan_Init
void Netchan_Init(void)
Definition: chan.c:116
MSG_BeginReading
void MSG_BeginReading(void)
Definition: msg.c:1437
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Netchan_Setup
netchan_t * Netchan_Setup(netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol)
Definition: chan.c:835
net_maxmsglen
cvar_t * net_maxmsglen
Definition: chan.c:99
Netchan_OutOfBand
void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *format,...)
Definition: chan.c:140
net_chantype
cvar_t * net_chantype
Definition: chan.c:100
SZ_WriteByte
void SZ_WriteByte(sizebuf_t *sb, int c)
Definition: sizebuf.c:82
net_maxmsglen_changed
static void net_maxmsglen_changed(cvar_t *self)
Definition: chan.c:103
SZ_WriteShort
void SZ_WriteShort(sizebuf_t *sb, int c)
Definition: sizebuf.c:90
net_qport
cvar_t * net_qport
Definition: chan.c:98
Q_vsnprintf
size_t Q_vsnprintf(char *dest, size_t size, const char *fmt, va_list argptr)
Definition: shared.c:791
NetchanOld_Setup
static netchan_t * NetchanOld_Setup(netsrc_t sock, const netadr_t *adr, int qport, size_t maxpacketlen)
Definition: chan.c:395
Sys_Milliseconds
unsigned Sys_Milliseconds(void)
Definition: system.c:644
SZ_Init
void SZ_Init(sizebuf_t *buf, void *data, size_t size)
Definition: sizebuf.c:31
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
NetchanNew_ShouldUpdate
static qboolean NetchanNew_ShouldUpdate(netchan_t *netchan)
Definition: chan.c:778
NetchanNew_Transmit
static size_t NetchanNew_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets)
Definition: chan.c:523
va
char * va(const char *format,...)
Definition: shared.c:429
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
SHOWPACKET
#define SHOWPACKET(...)
Definition: chan.c:94
Z_TagMallocz
void * Z_TagMallocz(size_t size, memtag_t tag)
Definition: zone.c:330
MSG_ReadLong
int MSG_ReadLong(void)
Definition: msg.c:1517
NetchanNew_Process
static qboolean NetchanNew_Process(netchan_t *netchan)
Definition: chan.c:632
NetchanNew_Setup
static netchan_t * NetchanNew_Setup(netsrc_t sock, const netadr_t *adr, int qport, size_t maxpacketlen)
Definition: chan.c:797
SZ_TagInit
void SZ_TagInit(sizebuf_t *buf, void *data, size_t size, uint32_t tag)
Definition: sizebuf.c:23
com_localTime
unsigned com_localTime
Definition: common.c:123
Z_TagReserve
void Z_TagReserve(size_t size, memtag_t tag)
Definition: zone.c:342
SHOWDROP
#define SHOWDROP(...)
Definition: chan.c:95
NetchanOld_ShouldUpdate
static qboolean NetchanOld_ShouldUpdate(netchan_t *netchan)
Definition: chan.c:378
NET_SendPacket
qboolean NET_SendPacket(netsrc_t sock, const void *data, size_t len, const netadr_t *to)
Definition: net.c:918
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
NetchanOld_Transmit
static size_t NetchanOld_Transmit(netchan_t *netchan, size_t length, const void *data, int numpackets)
Definition: chan.c:184
SZ_WriteLong
void SZ_WriteLong(sizebuf_t *sb, int c)
Definition: sizebuf.c:99
Netchan_Close
void Netchan_Close(netchan_t *netchan)
Definition: chan.c:866
MSG_ReadByte
int MSG_ReadByte(void)
Definition: msg.c:1475
NetchanNew_TransmitNextFragment
static size_t NetchanNew_TransmitNextFragment(netchan_t *netchan)
Definition: chan.c:437
SZ_Clear
void SZ_Clear(sizebuf_t *buf)
Definition: sizebuf.c:40
NetchanOld_TransmitNextFragment
static size_t NetchanOld_TransmitNextFragment(netchan_t *netchan)
Definition: chan.c:168
MSG_ReadShort
int MSG_ReadShort(void)
Definition: msg.c:1489