net_chan.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, 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. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "../game/q_shared.h"
  19. #include "qcommon.h"
  20. /*
  21. packet header
  22. -------------
  23. 4 outgoing sequence. high bit will be set if this is a fragmented message
  24. [2 qport (only for client to server)]
  25. [2 fragment start byte]
  26. [2 fragment length. if < FRAGMENT_SIZE, this is the last fragment]
  27. if the sequence number is -1, the packet should be handled as an out-of-band
  28. message instead of as part of a netcon.
  29. All fragments will have the same sequence numbers.
  30. The qport field is a workaround for bad address translating routers that
  31. sometimes remap the client's source port on a packet during gameplay.
  32. If the base part of the net address matches and the qport matches, then the
  33. channel matches even if the IP port differs. The IP port should be updated
  34. to the new value before sending out any replies.
  35. */
  36. #define MAX_PACKETLEN 1400 // max size of a network packet
  37. #define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
  38. #define PACKET_HEADER 10 // two ints and a short
  39. #define FRAGMENT_BIT (1<<31)
  40. cvar_t *showpackets;
  41. cvar_t *showdrop;
  42. cvar_t *qport;
  43. static char *netsrcString[2] = {
  44. "client",
  45. "server"
  46. };
  47. /*
  48. ===============
  49. Netchan_Init
  50. ===============
  51. */
  52. void Netchan_Init( int port ) {
  53. port &= 0xffff;
  54. showpackets = Cvar_Get ("showpackets", "0", CVAR_TEMP );
  55. showdrop = Cvar_Get ("showdrop", "0", CVAR_TEMP );
  56. qport = Cvar_Get ("net_qport", va("%i", port), CVAR_INIT );
  57. }
  58. /*
  59. ==============
  60. Netchan_Setup
  61. called to open a channel to a remote system
  62. ==============
  63. */
  64. void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport ) {
  65. Com_Memset (chan, 0, sizeof(*chan));
  66. chan->sock = sock;
  67. chan->remoteAddress = adr;
  68. chan->qport = qport;
  69. chan->incomingSequence = 0;
  70. chan->outgoingSequence = 1;
  71. }
  72. // TTimo: unused, commenting out to make gcc happy
  73. #if 0
  74. /*
  75. ==============
  76. Netchan_ScramblePacket
  77. A probably futile attempt to make proxy hacking somewhat
  78. more difficult.
  79. ==============
  80. */
  81. #define SCRAMBLE_START 6
  82. static void Netchan_ScramblePacket( msg_t *buf ) {
  83. unsigned seed;
  84. int i, j, c, mask, temp;
  85. int seq[MAX_PACKETLEN];
  86. seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );
  87. c = buf->cursize;
  88. if ( c <= SCRAMBLE_START ) {
  89. return;
  90. }
  91. if ( c > MAX_PACKETLEN ) {
  92. Com_Error( ERR_DROP, "MAX_PACKETLEN" );
  93. }
  94. // generate a sequence of "random" numbers
  95. for (i = 0 ; i < c ; i++) {
  96. seed = (119 * seed + 1);
  97. seq[i] = seed;
  98. }
  99. // transpose each character
  100. for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
  101. }
  102. mask >>= 1;
  103. for (i = SCRAMBLE_START ; i < c ; i++) {
  104. j = SCRAMBLE_START + ( seq[i] & mask );
  105. temp = buf->data[j];
  106. buf->data[j] = buf->data[i];
  107. buf->data[i] = temp;
  108. }
  109. // byte xor the data after the header
  110. for (i = SCRAMBLE_START ; i < c ; i++) {
  111. buf->data[i] ^= seq[i];
  112. }
  113. }
  114. static void Netchan_UnScramblePacket( msg_t *buf ) {
  115. unsigned seed;
  116. int i, j, c, mask, temp;
  117. int seq[MAX_PACKETLEN];
  118. seed = ( LittleLong( *(unsigned *)buf->data ) * 3 ) ^ ( buf->cursize * 123 );
  119. c = buf->cursize;
  120. if ( c <= SCRAMBLE_START ) {
  121. return;
  122. }
  123. if ( c > MAX_PACKETLEN ) {
  124. Com_Error( ERR_DROP, "MAX_PACKETLEN" );
  125. }
  126. // generate a sequence of "random" numbers
  127. for (i = 0 ; i < c ; i++) {
  128. seed = (119 * seed + 1);
  129. seq[i] = seed;
  130. }
  131. // byte xor the data after the header
  132. for (i = SCRAMBLE_START ; i < c ; i++) {
  133. buf->data[i] ^= seq[i];
  134. }
  135. // transpose each character in reverse order
  136. for ( mask = 1 ; mask < c-SCRAMBLE_START ; mask = ( mask << 1 ) + 1 ) {
  137. }
  138. mask >>= 1;
  139. for (i = c-1 ; i >= SCRAMBLE_START ; i--) {
  140. j = SCRAMBLE_START + ( seq[i] & mask );
  141. temp = buf->data[j];
  142. buf->data[j] = buf->data[i];
  143. buf->data[i] = temp;
  144. }
  145. }
  146. #endif
  147. /*
  148. =================
  149. Netchan_TransmitNextFragment
  150. Send one fragment of the current message
  151. =================
  152. */
  153. void Netchan_TransmitNextFragment( netchan_t *chan ) {
  154. msg_t send;
  155. byte send_buf[MAX_PACKETLEN];
  156. int fragmentLength;
  157. // write the packet header
  158. MSG_InitOOB (&send, send_buf, sizeof(send_buf)); // <-- only do the oob here
  159. MSG_WriteLong( &send, chan->outgoingSequence | FRAGMENT_BIT );
  160. // send the qport if we are a client
  161. if ( chan->sock == NS_CLIENT ) {
  162. MSG_WriteShort( &send, qport->integer );
  163. }
  164. // copy the reliable message to the packet first
  165. fragmentLength = FRAGMENT_SIZE;
  166. if ( chan->unsentFragmentStart + fragmentLength > chan->unsentLength ) {
  167. fragmentLength = chan->unsentLength - chan->unsentFragmentStart;
  168. }
  169. MSG_WriteShort( &send, chan->unsentFragmentStart );
  170. MSG_WriteShort( &send, fragmentLength );
  171. MSG_WriteData( &send, chan->unsentBuffer + chan->unsentFragmentStart, fragmentLength );
  172. // send the datagram
  173. NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
  174. if ( showpackets->integer ) {
  175. Com_Printf ("%s send %4i : s=%i fragment=%i,%i\n"
  176. , netsrcString[ chan->sock ]
  177. , send.cursize
  178. , chan->outgoingSequence
  179. , chan->unsentFragmentStart, fragmentLength);
  180. }
  181. chan->unsentFragmentStart += fragmentLength;
  182. // this exit condition is a little tricky, because a packet
  183. // that is exactly the fragment length still needs to send
  184. // a second packet of zero length so that the other side
  185. // can tell there aren't more to follow
  186. if ( chan->unsentFragmentStart == chan->unsentLength && fragmentLength != FRAGMENT_SIZE ) {
  187. chan->outgoingSequence++;
  188. chan->unsentFragments = qfalse;
  189. }
  190. }
  191. /*
  192. ===============
  193. Netchan_Transmit
  194. Sends a message to a connection, fragmenting if necessary
  195. A 0 length will still generate a packet.
  196. ================
  197. */
  198. void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) {
  199. msg_t send;
  200. byte send_buf[MAX_PACKETLEN];
  201. if ( length > MAX_MSGLEN ) {
  202. Com_Error( ERR_DROP, "Netchan_Transmit: length = %i", length );
  203. }
  204. chan->unsentFragmentStart = 0;
  205. // fragment large reliable messages
  206. if ( length >= FRAGMENT_SIZE ) {
  207. chan->unsentFragments = qtrue;
  208. chan->unsentLength = length;
  209. Com_Memcpy( chan->unsentBuffer, data, length );
  210. // only send the first fragment now
  211. Netchan_TransmitNextFragment( chan );
  212. return;
  213. }
  214. // write the packet header
  215. MSG_InitOOB (&send, send_buf, sizeof(send_buf));
  216. MSG_WriteLong( &send, chan->outgoingSequence );
  217. chan->outgoingSequence++;
  218. // send the qport if we are a client
  219. if ( chan->sock == NS_CLIENT ) {
  220. MSG_WriteShort( &send, qport->integer );
  221. }
  222. MSG_WriteData( &send, data, length );
  223. // send the datagram
  224. NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
  225. if ( showpackets->integer ) {
  226. Com_Printf( "%s send %4i : s=%i ack=%i\n"
  227. , netsrcString[ chan->sock ]
  228. , send.cursize
  229. , chan->outgoingSequence - 1
  230. , chan->incomingSequence );
  231. }
  232. }
  233. /*
  234. =================
  235. Netchan_Process
  236. Returns qfalse if the message should not be processed due to being
  237. out of order or a fragment.
  238. Msg must be large enough to hold MAX_MSGLEN, because if this is the
  239. final fragment of a multi-part message, the entire thing will be
  240. copied out.
  241. =================
  242. */
  243. qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) {
  244. int sequence;
  245. int qport;
  246. int fragmentStart, fragmentLength;
  247. qboolean fragmented;
  248. // XOR unscramble all data in the packet after the header
  249. // Netchan_UnScramblePacket( msg );
  250. // get sequence numbers
  251. MSG_BeginReadingOOB( msg );
  252. sequence = MSG_ReadLong( msg );
  253. // check for fragment information
  254. if ( sequence & FRAGMENT_BIT ) {
  255. sequence &= ~FRAGMENT_BIT;
  256. fragmented = qtrue;
  257. } else {
  258. fragmented = qfalse;
  259. }
  260. // read the qport if we are a server
  261. if ( chan->sock == NS_SERVER ) {
  262. qport = MSG_ReadShort( msg );
  263. }
  264. // read the fragment information
  265. if ( fragmented ) {
  266. fragmentStart = MSG_ReadShort( msg );
  267. fragmentLength = MSG_ReadShort( msg );
  268. } else {
  269. fragmentStart = 0; // stop warning message
  270. fragmentLength = 0;
  271. }
  272. if ( showpackets->integer ) {
  273. if ( fragmented ) {
  274. Com_Printf( "%s recv %4i : s=%i fragment=%i,%i\n"
  275. , netsrcString[ chan->sock ]
  276. , msg->cursize
  277. , sequence
  278. , fragmentStart, fragmentLength );
  279. } else {
  280. Com_Printf( "%s recv %4i : s=%i\n"
  281. , netsrcString[ chan->sock ]
  282. , msg->cursize
  283. , sequence );
  284. }
  285. }
  286. //
  287. // discard out of order or duplicated packets
  288. //
  289. if ( sequence <= chan->incomingSequence ) {
  290. if ( showdrop->integer || showpackets->integer ) {
  291. Com_Printf( "%s:Out of order packet %i at %i\n"
  292. , NET_AdrToString( chan->remoteAddress )
  293. , sequence
  294. , chan->incomingSequence );
  295. }
  296. return qfalse;
  297. }
  298. //
  299. // dropped packets don't keep the message from being used
  300. //
  301. chan->dropped = sequence - (chan->incomingSequence+1);
  302. if ( chan->dropped > 0 ) {
  303. if ( showdrop->integer || showpackets->integer ) {
  304. Com_Printf( "%s:Dropped %i packets at %i\n"
  305. , NET_AdrToString( chan->remoteAddress )
  306. , chan->dropped
  307. , sequence );
  308. }
  309. }
  310. //
  311. // if this is the final framgent of a reliable message,
  312. // bump incoming_reliable_sequence
  313. //
  314. if ( fragmented ) {
  315. // TTimo
  316. // make sure we add the fragments in correct order
  317. // either a packet was dropped, or we received this one too soon
  318. // we don't reconstruct the fragments. we will wait till this fragment gets to us again
  319. // (NOTE: we could probably try to rebuild by out of order chunks if needed)
  320. if ( sequence != chan->fragmentSequence ) {
  321. chan->fragmentSequence = sequence;
  322. chan->fragmentLength = 0;
  323. }
  324. // if we missed a fragment, dump the message
  325. if ( fragmentStart != chan->fragmentLength ) {
  326. if ( showdrop->integer || showpackets->integer ) {
  327. Com_Printf( "%s:Dropped a message fragment\n"
  328. , NET_AdrToString( chan->remoteAddress )
  329. , sequence);
  330. }
  331. // we can still keep the part that we have so far,
  332. // so we don't need to clear chan->fragmentLength
  333. return qfalse;
  334. }
  335. // copy the fragment to the fragment buffer
  336. if ( fragmentLength < 0 || msg->readcount + fragmentLength > msg->cursize ||
  337. chan->fragmentLength + fragmentLength > sizeof( chan->fragmentBuffer ) ) {
  338. if ( showdrop->integer || showpackets->integer ) {
  339. Com_Printf ("%s:illegal fragment length\n"
  340. , NET_AdrToString (chan->remoteAddress ) );
  341. }
  342. return qfalse;
  343. }
  344. Com_Memcpy( chan->fragmentBuffer + chan->fragmentLength,
  345. msg->data + msg->readcount, fragmentLength );
  346. chan->fragmentLength += fragmentLength;
  347. // if this wasn't the last fragment, don't process anything
  348. if ( fragmentLength == FRAGMENT_SIZE ) {
  349. return qfalse;
  350. }
  351. if ( chan->fragmentLength > msg->maxsize ) {
  352. Com_Printf( "%s:fragmentLength %i > msg->maxsize\n"
  353. , NET_AdrToString (chan->remoteAddress ),
  354. chan->fragmentLength );
  355. return qfalse;
  356. }
  357. // copy the full message over the partial fragment
  358. // make sure the sequence number is still there
  359. *(int *)msg->data = LittleLong( sequence );
  360. Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength );
  361. msg->cursize = chan->fragmentLength + 4;
  362. chan->fragmentLength = 0;
  363. msg->readcount = 4; // past the sequence number
  364. msg->bit = 32; // past the sequence number
  365. // TTimo
  366. // clients were not acking fragmented messages
  367. chan->incomingSequence = sequence;
  368. return qtrue;
  369. }
  370. //
  371. // the message can now be read from the current message pointer
  372. //
  373. chan->incomingSequence = sequence;
  374. return qtrue;
  375. }
  376. //==============================================================================
  377. /*
  378. ===================
  379. NET_CompareBaseAdr
  380. Compares without the port
  381. ===================
  382. */
  383. qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
  384. {
  385. if (a.type != b.type)
  386. return qfalse;
  387. if (a.type == NA_LOOPBACK)
  388. return qtrue;
  389. if (a.type == NA_IP)
  390. {
  391. if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
  392. return qtrue;
  393. return qfalse;
  394. }
  395. if (a.type == NA_IPX)
  396. {
  397. if ((memcmp(a.ipx, b.ipx, 10) == 0))
  398. return qtrue;
  399. return qfalse;
  400. }
  401. Com_Printf ("NET_CompareBaseAdr: bad address type\n");
  402. return qfalse;
  403. }
  404. const char *NET_AdrToString (netadr_t a)
  405. {
  406. static char s[64];
  407. if (a.type == NA_LOOPBACK) {
  408. Com_sprintf (s, sizeof(s), "loopback");
  409. } else if (a.type == NA_BOT) {
  410. Com_sprintf (s, sizeof(s), "bot");
  411. } else if (a.type == NA_IP) {
  412. Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%hu",
  413. a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port));
  414. } else {
  415. Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu",
  416. a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9],
  417. BigShort(a.port));
  418. }
  419. return s;
  420. }
  421. qboolean NET_CompareAdr (netadr_t a, netadr_t b)
  422. {
  423. if (a.type != b.type)
  424. return qfalse;
  425. if (a.type == NA_LOOPBACK)
  426. return qtrue;
  427. if (a.type == NA_IP)
  428. {
  429. if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
  430. return qtrue;
  431. return qfalse;
  432. }
  433. if (a.type == NA_IPX)
  434. {
  435. if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
  436. return qtrue;
  437. return qfalse;
  438. }
  439. Com_Printf ("NET_CompareAdr: bad address type\n");
  440. return qfalse;
  441. }
  442. qboolean NET_IsLocalAddress( netadr_t adr ) {
  443. return adr.type == NA_LOOPBACK;
  444. }
  445. /*
  446. =============================================================================
  447. LOOPBACK BUFFERS FOR LOCAL PLAYER
  448. =============================================================================
  449. */
  450. // there needs to be enough loopback messages to hold a complete
  451. // gamestate of maximum size
  452. #define MAX_LOOPBACK 16
  453. typedef struct {
  454. byte data[MAX_PACKETLEN];
  455. int datalen;
  456. } loopmsg_t;
  457. typedef struct {
  458. loopmsg_t msgs[MAX_LOOPBACK];
  459. int get, send;
  460. } loopback_t;
  461. loopback_t loopbacks[2];
  462. qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message)
  463. {
  464. int i;
  465. loopback_t *loop;
  466. loop = &loopbacks[sock];
  467. if (loop->send - loop->get > MAX_LOOPBACK)
  468. loop->get = loop->send - MAX_LOOPBACK;
  469. if (loop->get >= loop->send)
  470. return qfalse;
  471. i = loop->get & (MAX_LOOPBACK-1);
  472. loop->get++;
  473. Com_Memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
  474. net_message->cursize = loop->msgs[i].datalen;
  475. Com_Memset (net_from, 0, sizeof(*net_from));
  476. net_from->type = NA_LOOPBACK;
  477. return qtrue;
  478. }
  479. void NET_SendLoopPacket (netsrc_t sock, int length, const void *data, netadr_t to)
  480. {
  481. int i;
  482. loopback_t *loop;
  483. loop = &loopbacks[sock^1];
  484. i = loop->send & (MAX_LOOPBACK-1);
  485. loop->send++;
  486. Com_Memcpy (loop->msgs[i].data, data, length);
  487. loop->msgs[i].datalen = length;
  488. }
  489. //=============================================================================
  490. void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to ) {
  491. // sequenced packets are shown in netchan, so just show oob
  492. if ( showpackets->integer && *(int *)data == -1 ) {
  493. Com_Printf ("send packet %4i\n", length);
  494. }
  495. if ( to.type == NA_LOOPBACK ) {
  496. NET_SendLoopPacket (sock, length, data, to);
  497. return;
  498. }
  499. if ( to.type == NA_BOT ) {
  500. return;
  501. }
  502. if ( to.type == NA_BAD ) {
  503. return;
  504. }
  505. Sys_SendPacket( length, data, to );
  506. }
  507. /*
  508. ===============
  509. NET_OutOfBandPrint
  510. Sends a text message in an out-of-band datagram
  511. ================
  512. */
  513. void QDECL NET_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... ) {
  514. va_list argptr;
  515. char string[MAX_MSGLEN];
  516. // set the header
  517. string[0] = -1;
  518. string[1] = -1;
  519. string[2] = -1;
  520. string[3] = -1;
  521. va_start( argptr, format );
  522. vsprintf( string+4, format, argptr );
  523. va_end( argptr );
  524. // send the datagram
  525. NET_SendPacket( sock, strlen( string ), string, adr );
  526. }
  527. /*
  528. ===============
  529. NET_OutOfBandPrint
  530. Sends a data message in an out-of-band datagram (only used for "connect")
  531. ================
  532. */
  533. void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ) {
  534. byte string[MAX_MSGLEN*2];
  535. int i;
  536. msg_t mbuf;
  537. // set the header
  538. string[0] = 0xff;
  539. string[1] = 0xff;
  540. string[2] = 0xff;
  541. string[3] = 0xff;
  542. for(i=0;i<len;i++) {
  543. string[i+4] = format[i];
  544. }
  545. mbuf.data = string;
  546. mbuf.cursize = len+4;
  547. Huff_Compress( &mbuf, 12);
  548. // send the datagram
  549. NET_SendPacket( sock, mbuf.cursize, mbuf.data, adr );
  550. }
  551. /*
  552. =============
  553. NET_StringToAdr
  554. Traps "localhost" for loopback, passes everything else to system
  555. =============
  556. */
  557. qboolean NET_StringToAdr( const char *s, netadr_t *a ) {
  558. qboolean r;
  559. char base[MAX_STRING_CHARS];
  560. char *port;
  561. if (!strcmp (s, "localhost")) {
  562. Com_Memset (a, 0, sizeof(*a));
  563. a->type = NA_LOOPBACK;
  564. return qtrue;
  565. }
  566. // look for a port number
  567. Q_strncpyz( base, s, sizeof( base ) );
  568. port = strstr( base, ":" );
  569. if ( port ) {
  570. *port = 0;
  571. port++;
  572. }
  573. r = Sys_StringToAdr( base, a );
  574. if ( !r ) {
  575. a->type = NA_BAD;
  576. return qfalse;
  577. }
  578. // inet_addr returns this if out of range
  579. if ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) {
  580. a->type = NA_BAD;
  581. return qfalse;
  582. }
  583. if ( port ) {
  584. a->port = BigShort( (short)atoi( port ) );
  585. } else {
  586. a->port = BigShort( PORT_SERVER );
  587. }
  588. return qtrue;
  589. }