net_chan.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. #include "../game/q_shared.h"
  2. #include "qcommon.h"
  3. /*
  4. packet header
  5. -------------
  6. 4 outgoing sequence. high bit will be set if this is a fragmented message
  7. 4 acknowledge sequence
  8. [2 qport (only for client to server)]
  9. [2 fragment start byte]
  10. [2 fragment length. if < FRAGMENT_SIZE, this is the last fragment]
  11. if the sequence number is -1, the packet should be handled as an out-of-band
  12. message instead of as part of a netcon.
  13. All fragments will have the same sequence numbers.
  14. The qport field is a workaround for bad address translating routers that
  15. sometimes remap the client's source port on a packet during gameplay.
  16. If the base part of the net address matches and the qport matches, then the
  17. channel matches even if the IP port differs. The IP port should be updated
  18. to the new value before sending out any replies.
  19. */
  20. #define MAX_PACKETLEN (MAX_MSGLEN) //(1400) // max size of a network packet
  21. #define MAX_LOOPDATA 16 * 1024
  22. #if (MAX_PACKETLEN > MAX_MSGLEN)
  23. #error MAX_PACKETLEN must be <= MAX_MSGLEN
  24. #endif
  25. #if (MAX_LOOPDATA > MAX_MSGLEN)
  26. #error MAX_LOOPDATA must be <= MAX_MSGLEN
  27. #endif
  28. #define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
  29. #define PACKET_HEADER 10 // two ints and a short
  30. #define FRAGMENT_BIT (1<<31)
  31. cvar_t *showpackets;
  32. cvar_t *showdrop;
  33. cvar_t *qport;
  34. static char *netsrcString[2] = {
  35. "client",
  36. "server"
  37. };
  38. typedef struct {
  39. char loopData[MAX_LOOPDATA];
  40. int get, send;
  41. } loopback_t;
  42. static loopback_t *loopbacks = NULL;
  43. /*
  44. ===============
  45. Netchan_Init
  46. ===============
  47. */
  48. void Netchan_Init( int port ) {
  49. if (!loopbacks)
  50. {
  51. loopbacks = (loopback_t*) Z_Malloc(sizeof(loopback_t) * 2, TAG_NEWDEL, qtrue);
  52. }
  53. port &= 0xffff;
  54. showpackets = Cvar_Get ("showpackets", "0", CVAR_TEMP );
  55. showdrop = Cvar_Get ("showdrop", "0", CVAR_TEMP );
  56. qport = Cvar_Get ("qport", va("%i", port), CVAR_INIT );
  57. }
  58. void Netchan_Shutdown()
  59. {
  60. if (loopbacks)
  61. {
  62. Z_Free(loopbacks);
  63. loopbacks = 0;
  64. }
  65. }
  66. /*
  67. ==============
  68. Netchan_Setup
  69. called to open a channel to a remote system
  70. ==============
  71. */
  72. void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
  73. memset (chan, 0, sizeof(*chan));
  74. chan->sock = sock;
  75. chan->remoteAddress = adr;
  76. chan->qport = qport;
  77. chan->incomingSequence = 0;
  78. chan->outgoingSequence = 1;
  79. }
  80. /*
  81. ===============
  82. Netchan_Transmit
  83. Sends a message to a connection, fragmenting if necessary
  84. A 0 length will still generate a packet.
  85. ================
  86. */
  87. void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) {
  88. msg_t send;
  89. byte send_buf[MAX_PACKETLEN];
  90. int fragmentStart, fragmentLength;
  91. fragmentStart = 0; // stop warning message
  92. fragmentLength = 0;
  93. // fragment large reliable messages
  94. if ( length >= FRAGMENT_SIZE ) {
  95. fragmentStart = 0;
  96. do {
  97. // write the packet header
  98. MSG_Init (&send, send_buf, sizeof(send_buf));
  99. MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );
  100. MSG_WriteLong( &send, chan->incomingSequence );
  101. // send the qport if we are a client
  102. if ( chan->sock == NS_CLIENT ) {
  103. MSG_WriteShort( &send, qport->integer );
  104. }
  105. // copy the reliable message to the packet first
  106. fragmentLength = FRAGMENT_SIZE;
  107. if ( fragmentStart + fragmentLength > length ) {
  108. fragmentLength = length - fragmentStart;
  109. }
  110. MSG_WriteShort( &send, fragmentStart );
  111. MSG_WriteShort( &send, fragmentLength );
  112. MSG_WriteData( &send, data + fragmentStart, fragmentLength );
  113. // send the datagram
  114. NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
  115. if ( showpackets->integer ) {
  116. Com_Printf ("%s send %4i : s=%i ack=%i fragment=%i,%i\n"
  117. , netsrcString[ chan->sock ]
  118. , send.cursize
  119. , chan->outgoingSequence - 1
  120. , chan->incomingSequence
  121. , fragmentStart, fragmentLength);
  122. }
  123. fragmentStart += fragmentLength;
  124. // this exit condition is a little tricky, because a packet
  125. // that is exactly the fragment length still needs to send
  126. // a second packet of zero length so that the other side
  127. // can tell there aren't more to follow
  128. } while ( fragmentStart != length || fragmentLength == FRAGMENT_SIZE );
  129. chan->outgoingSequence++;
  130. return;
  131. }
  132. // write the packet header
  133. MSG_Init (&send, send_buf, sizeof(send_buf));
  134. MSG_WriteLong( &send, chan->outgoingSequence );
  135. MSG_WriteLong( &send, chan->incomingSequence );
  136. chan->outgoingSequence++;
  137. // send the qport if we are a client
  138. if ( chan->sock == NS_CLIENT ) {
  139. MSG_WriteShort( &send, qport->integer );
  140. }
  141. MSG_WriteData( &send, data, length );
  142. // send the datagram
  143. NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
  144. if ( showpackets->integer ) {
  145. Com_Printf( "%s send %4i : s=%i ack=%i\n"
  146. , netsrcString[ chan->sock ]
  147. , send.cursize
  148. , chan->outgoingSequence - 1
  149. , chan->incomingSequence );
  150. }
  151. }
  152. /*
  153. =================
  154. Netchan_Process
  155. Returns qfalse if the message should not be processed due to being
  156. out of order or a fragment.
  157. Msg must be large enough to hold MAX_MSGLEN, because if this is the
  158. final fragment of a multi-part message, the entire thing will be
  159. copied out.
  160. =================
  161. */
  162. qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
  163. int sequence, sequence_ack;
  164. int qport;
  165. int fragmentStart, fragmentLength;
  166. qboolean fragmented;
  167. // get sequence numbers
  168. MSG_BeginReading( msg );
  169. sequence = MSG_ReadLong( msg );
  170. sequence_ack = MSG_ReadLong( msg );
  171. // check for fragment information
  172. if ( sequence & FRAGMENT_BIT ) {
  173. sequence &= ~FRAGMENT_BIT;
  174. fragmented = qtrue;
  175. } else {
  176. fragmented = qfalse;
  177. }
  178. // read the qport if we are a server
  179. if ( chan->sock == NS_SERVER ) {
  180. qport = MSG_ReadShort( msg );
  181. }
  182. // read the fragment information
  183. if ( fragmented ) {
  184. fragmentStart = MSG_ReadShort( msg );
  185. fragmentLength = MSG_ReadShort( msg );
  186. } else {
  187. fragmentStart = 0; // stop warning message
  188. fragmentLength = 0;
  189. }
  190. if ( showpackets->integer ) {
  191. if ( fragmented ) {
  192. Com_Printf( "%s recv %4i : s=%i ack=%i fragment=%i,%i\n"
  193. , netsrcString[ chan->sock ]
  194. , msg->cursize
  195. , sequence
  196. , sequence_ack
  197. , fragmentStart, fragmentLength );
  198. } else {
  199. Com_Printf( "%s recv %4i : s=%i ack=%i\n"
  200. , netsrcString[ chan->sock ]
  201. , msg->cursize
  202. , sequence
  203. , sequence_ack );
  204. }
  205. }
  206. //
  207. // discard out of order or duplicated packets
  208. //
  209. if ( sequence <= chan->incomingSequence ) {
  210. if ( showdrop->integer || showpackets->integer ) {
  211. Com_Printf( "%s:Out of order packet %i at %i\n"
  212. , NET_AdrToString( chan->remoteAddress )
  213. , sequence
  214. , chan->incomingSequence );
  215. }
  216. return qfalse;
  217. }
  218. //
  219. // dropped packets don't keep the message from being used
  220. //
  221. chan->dropped = sequence - (chan->incomingSequence+1);
  222. if ( chan->dropped > 0 ) {
  223. if ( showdrop->integer || showpackets->integer ) {
  224. Com_Printf( "%s:Dropped %i packets at %i\n"
  225. , NET_AdrToString( chan->remoteAddress )
  226. , chan->dropped
  227. , sequence );
  228. }
  229. }
  230. //
  231. // if this is the final framgent of a reliable message,
  232. // bump incoming_reliable_sequence
  233. //
  234. if ( fragmented ) {
  235. // make sure we
  236. if ( sequence != chan->fragmentSequence ) {
  237. chan->fragmentSequence = sequence;
  238. chan->fragmentLength = 0;
  239. }
  240. // if we missed a fragment, dump the message
  241. if ( fragmentStart != chan->fragmentLength ) {
  242. if ( showdrop->integer || showpackets->integer ) {
  243. Com_Printf( "%s:Dropped a message fragment\n"
  244. , NET_AdrToString( chan->remoteAddress )
  245. , sequence);
  246. }
  247. // we can still keep the part that we have so far,
  248. // so we don't need to clear chan->fragmentLength
  249. return qfalse;
  250. }
  251. // copy the fragment to the fragment buffer
  252. if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize ||
  253. chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) {
  254. if ( showdrop->integer || showpackets->integer ) {
  255. Com_Printf ("%s:illegal fragment length\n"
  256. , NET_AdrToString (chan->remoteAddress ) );
  257. }
  258. return qfalse;
  259. }
  260. memcpy( chan->fragmentBuffer + chan->fragmentLength,
  261. msg->data + msg->readcount, fragmentLength );
  262. chan->fragmentLength += fragmentLength;
  263. // if this wasn't the last fragment, don't process anything
  264. if ( fragmentLength == FRAGMENT_SIZE ) {
  265. return qfalse;
  266. }
  267. if ( chan->fragmentLength > msg->maxsize ) {
  268. Com_Printf( "%s:fragmentLength %i > msg->maxsize\n"
  269. , NET_AdrToString (chan->remoteAddress ),
  270. chan->fragmentLength );
  271. return qfalse;
  272. }
  273. // copy the full message over the partial fragment
  274. // make sure the sequence number is still there
  275. *(int *)msg->data = LittleLong( sequence );
  276. memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );
  277. msg->cursize = chan->fragmentLength + 4;
  278. chan->fragmentLength = 0;
  279. msg->readcount = 4; // past the sequence number
  280. return qtrue;
  281. }
  282. //
  283. // the message can now be read from the current message pointer
  284. //
  285. chan->incomingSequence = sequence;
  286. chan->incomingAcknowledged = sequence_ack;
  287. return qtrue;
  288. }
  289. //==============================================================================
  290. /*
  291. ===================
  292. NET_CompareBaseAdr
  293. Compares without the port
  294. ===================
  295. */
  296. qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
  297. {
  298. if (a.type != b.type)
  299. return qfalse;
  300. if (a.type == NA_LOOPBACK)
  301. return qtrue;
  302. Com_Printf ("NET_CompareBaseAdr: bad address type\n");
  303. return qfalse;
  304. }
  305. const char *NET_AdrToString (netadr_t a)
  306. {
  307. static char s[64];
  308. if (a.type == NA_LOOPBACK) {
  309. Com_sprintf (s, sizeof(s), "loopback");
  310. }
  311. return s;
  312. }
  313. qboolean NET_CompareAdr (netadr_t a, netadr_t b)
  314. {
  315. if (a.type != b.type)
  316. return qfalse;
  317. if (a.type == NA_LOOPBACK)
  318. return qtrue;
  319. Com_Printf ("NET_CompareAdr: bad address type\n");
  320. return qfalse;
  321. }
  322. qboolean NET_IsLocalAddress( netadr_t adr ) {
  323. return adr.type == NA_LOOPBACK;
  324. }
  325. /*
  326. =============================================================================
  327. LOOPBACK BUFFERS FOR LOCAL PLAYER
  328. =============================================================================
  329. */
  330. qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message)
  331. {
  332. int i;
  333. loopback_t *loop;
  334. loop = &loopbacks[sock];
  335. //If read and write positions are the same, nothing left to read.
  336. if (loop->get == loop->send)
  337. return qfalse;
  338. //Get read position. Wrap if too close to end.
  339. i = loop->get;
  340. if(i > MAX_LOOPDATA - 4) {
  341. i = 0;
  342. }
  343. //Get length of packet.
  344. int length = *(int*)(loop->loopData + i);
  345. i += 4;
  346. //See if entire packet is at end of buffer or part is at the beginning.
  347. if(i + length <= MAX_LOOPDATA) {
  348. //Everything fits, full copy.
  349. memcpy (net_message->data, loop->loopData + i, length);
  350. net_message->cursize = length;
  351. i += length;
  352. loop->get = i;
  353. } else {
  354. //Doesn't all fit, partial copy
  355. const int copyToEnd = MAX_LOOPDATA - i;
  356. memcpy (net_message->data, loop->loopData + i, copyToEnd);
  357. memcpy ((char*)net_message->data + copyToEnd,
  358. loop->loopData, length - copyToEnd);
  359. net_message->cursize = length;
  360. loop->get = length - copyToEnd;
  361. }
  362. memset (net_from, 0, sizeof(*net_from));
  363. net_from->type = NA_LOOPBACK;
  364. return qtrue;
  365. }
  366. void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to)
  367. {
  368. int i;
  369. loopback_t *loop;
  370. loop = &loopbacks[sock^1];
  371. //Make sure there is enough free space in the buffer.
  372. int freeSpace;
  373. if(loop->send >= loop->get) {
  374. freeSpace = MAX_LOOPDATA - (loop->send - loop->get);
  375. } else {
  376. freeSpace = loop->get - loop->send;
  377. }
  378. assert(freeSpace > length);
  379. //Get write position. Wrap around if too close to end.
  380. i = loop->send;
  381. if(i > MAX_LOOPDATA - 4) {
  382. i = 0;
  383. }
  384. //Write length of packet.
  385. *(int*)(loop->loopData + i) = length;
  386. i += 4;
  387. //See if the whole packet will fit on the end of the buffer or if we
  388. //need to write part of it back at the beginning.
  389. if(i + length <= MAX_LOOPDATA) {
  390. //Everything fits, full copy.
  391. memcpy (loop->loopData + i, data, length);
  392. i += length;
  393. loop->send = i;
  394. } else {
  395. //Doesn't all fit, partial copy
  396. int copyToEnd = MAX_LOOPDATA - i;
  397. memcpy(loop->loopData + i, data, copyToEnd);
  398. memcpy(loop->loopData, (char*)data + copyToEnd, length - copyToEnd);
  399. loop->send = length - copyToEnd;
  400. }
  401. }
  402. //=============================================================================
  403. void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {
  404. // sequenced packets are shown in netchan, so just show oob
  405. if ( showpackets->integer && *(int *)data == -1 ) {
  406. Com_Printf ("send packet %4i\n", length);
  407. }
  408. if ( to.type == NA_LOOPBACK ) {
  409. NET_SendLoopPacket (sock, length, data, to);
  410. return;
  411. }
  412. }
  413. /*
  414. ===============
  415. NET_OutOfBandPrint
  416. Sends a text message in an out-of-band datagram
  417. ================
  418. */
  419. void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) {
  420. va_list argptr;
  421. char string[MAX_MSGLEN];
  422. // set the header
  423. string[0] = (char) 0xff;
  424. string[1] = (char) 0xff;
  425. string[2] = (char) 0xff;
  426. string[3] = (char) 0xff;
  427. va_start( argptr, format );
  428. vsprintf( string+4, format, argptr );
  429. va_end( argptr );
  430. // send the datagram
  431. NET_SendPacket( sock, strlen( string ), string, adr );
  432. }
  433. /*
  434. =============
  435. NET_StringToAdr
  436. Traps "localhost" for loopback, passes everything else to system
  437. =============
  438. */
  439. qboolean NET_StringToAdr( const char *s, netadr_t *a ) {
  440. if (!strcmp (s, "localhost")) {
  441. memset (a, 0, sizeof(*a));
  442. a->type = NA_LOOPBACK;
  443. return qtrue;
  444. }
  445. a->type = NA_BAD;
  446. return qfalse;
  447. }