icculus quake2 doxygen  1.0 dev
net_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
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 even/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 
80 
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  vsnprintf (string, MAX_MSGLEN - 4, 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 */
176 {
177  if (chan->reliable_length)
178  return false; // waiting for ack
179  return true;
180 }
181 
182 
184 {
185  qboolean send_reliable;
186 
187 // if the remote side dropped the last reliable message, resend it
188  send_reliable = false;
189 
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);
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
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
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 */
299 {
300  unsigned sequence, sequence_ack;
301  unsigned reliable_ack, reliable_message;
302  int qport;
303 
304 // get sequence numbers
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"
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"
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 
curtime
int curtime
Definition: q_shwin.c:119
sizebuf_s
Definition: qcommon.h:75
netchan_t::sock
netsrc_t sock
Definition: qcommon.h:578
netchan_t::incoming_sequence
int incoming_sequence
Definition: qcommon.h:589
netchan_t::last_reliable_sequence
int last_reliable_sequence
Definition: qcommon.h:597
netchan_t::incoming_acknowledged
int incoming_acknowledged
Definition: qcommon.h:590
NS_SERVER
@ NS_SERVER
Definition: qcommon.h:536
CVAR_NOSET
#define CVAR_NOSET
Definition: q_shared.h:312
Netchan_CanReliable
qboolean Netchan_CanReliable(netchan_t *chan)
Definition: net_chan.c:175
MSG_ReadShort
int MSG_ReadShort(sizebuf_t *msg_read)
Definition: common.c:735
net_message
sizebuf_t net_message
Definition: net_chan.c:82
netchan_t::message
sizebuf_t message
Definition: qcommon.h:600
net_from
netadr_t net_from
Definition: net_chan.c:81
sizebuf_s::overflowed
qboolean overflowed
Definition: qcommon.h:78
qboolean
qboolean
Definition: q_shared.h:56
Netchan_OutOfBand
void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte *data)
Definition: net_chan.c:110
netchan_t
Definition: qcommon.h:574
netchan_t::dropped
int dropped
Definition: qcommon.h:580
MSG_WriteLong
void MSG_WriteLong(sizebuf_t *sb, int c)
Definition: common.c:349
NET_AdrToString
char * NET_AdrToString(netadr_t a)
Definition: net_wins.c:156
SZ_Init
void SZ_Init(sizebuf_t *buf, byte *data, int length)
Definition: common.c:904
sizebuf_s::data
byte * data
Definition: qcommon.h:79
Cvar_Get
cvar_t * Cvar_Get(char *var_name, char *var_value, int flags)
Definition: cvar.c:127
SZ_Write
void SZ_Write(sizebuf_t *buf, void *data, int length)
Definition: common.c:940
cvar_s
Definition: q_shared.h:317
Netchan_Init
void Netchan_Init(void)
Definition: net_chan.c:91
va
char * va(char *format,...)
Definition: q_shared.c:1050
msg
cvar_t * msg
Definition: cl_main.c:98
showdrop
cvar_t * showdrop
Definition: net_chan.c:78
sizebuf_s::maxsize
int maxsize
Definition: qcommon.h:80
netchan_t::fatal_error
qboolean fatal_error
Definition: qcommon.h:576
netchan_t::incoming_reliable_acknowledged
int incoming_reliable_acknowledged
Definition: qcommon.h:591
NET_SendPacket
void NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to)
Definition: net_wins.c:395
netchan_t::last_sent
int last_sent
Definition: qcommon.h:583
vsnprintf
#define vsnprintf
Definition: q_shared.h:32
cvar_s::value
float value
Definition: q_shared.h:324
MSG_WriteShort
void MSG_WriteShort(sizebuf_t *sb, int c)
Definition: common.c:335
Netchan_Process
qboolean Netchan_Process(netchan_t *chan, sizebuf_t *msg)
Definition: net_chan.c:298
netchan_t::remote_address
netadr_t remote_address
Definition: qcommon.h:585
Netchan_Setup
void Netchan_Setup(netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
Definition: net_chan.c:152
MAX_MSGLEN
#define MAX_MSGLEN
Definition: qcommon.h:527
netchan_t::reliable_length
int reliable_length
Definition: qcommon.h:604
qport
cvar_t * qport
Definition: net_chan.c:79
netchan_t::outgoing_sequence
int outgoing_sequence
Definition: qcommon.h:595
qcommon.h
MSG_ReadLong
int MSG_ReadLong(sizebuf_t *msg_read)
Definition: common.c:750
netchan_t::reliable_sequence
int reliable_sequence
Definition: qcommon.h:596
NS_CLIENT
@ NS_CLIENT
Definition: qcommon.h:536
netchan_t::last_received
int last_received
Definition: qcommon.h:582
netsrc_t
netsrc_t
Definition: qcommon.h:536
netchan_t::reliable_buf
byte reliable_buf[MAX_MSGLEN-16]
Definition: qcommon.h:605
sizebuf_s::allowoverflow
qboolean allowoverflow
Definition: qcommon.h:77
netchan_t::incoming_reliable_sequence
int incoming_reliable_sequence
Definition: qcommon.h:593
Netchan_Transmit
void Netchan_Transmit(netchan_t *chan, int length, byte *data)
Definition: net_chan.c:213
net_message_buffer
byte net_message_buffer[MAX_MSGLEN]
Definition: net_chan.c:83
sizebuf_s::cursize
int cursize
Definition: qcommon.h:81
Netchan_OutOfBandPrint
void Netchan_OutOfBandPrint(int net_socket, netadr_t adr, char *format,...)
Definition: net_chan.c:132
format
GLsizei GLenum format
Definition: qgl_win.c:131
netadr_t
Definition: qcommon.h:538
Com_Printf
void Com_Printf(char *fmt,...)
Definition: common.c:102
Sys_Milliseconds
int Sys_Milliseconds(void)
Definition: q_shwin.c:120
netchan_t::message_buf
byte message_buf[MAX_MSGLEN-16]
Definition: qcommon.h:601
showpackets
cvar_t * showpackets
Definition: net_chan.c:77
Netchan_NeedReliable
qboolean Netchan_NeedReliable(netchan_t *chan)
Definition: net_chan.c:183
MSG_BeginReading
void MSG_BeginReading(sizebuf_t *msg)
Definition: common.c:703
netchan_t::qport
int qport
Definition: qcommon.h:586