home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / net_chan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  10.8 KB  |  453 lines

  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 = {"showpackets", "0"};
  80. cvar_t    showdrop = {"showdrop", "0"};
  81. cvar_t    qport = {"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.