Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3457 lines
87 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // net_ws.c
  9. // Windows IP Support layer.
  10. #include "tier0/etwprof.h"
  11. #include "tier0/vprof.h"
  12. #include "net_ws_headers.h"
  13. #include "net_ws_queued_packet_sender.h"
  14. #include "fmtstr.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #define NET_COMPRESSION_STACKBUF_SIZE 4096
  18. static ConVar net_showudp_wire( "net_showudp_wire", "0", 0, "Show incoming packet information" );
  19. #define UDP_SO_RCVBUF_SIZE 131072
  20. static ConVar net_udp_rcvbuf( "net_udp_rcvbuf", NETSTRING( UDP_SO_RCVBUF_SIZE ), FCVAR_ALLOWED_IN_COMPETITIVE, "Default UDP receive buffer size", true, 8192, true, 128 * 1024 );
  21. static ConVar net_showsplits( "net_showsplits", "0", 0, "Show info about packet splits" );
  22. static ConVar net_splitrate( "net_splitrate", "1", 0, "Number of fragments for a splitpacket that can be sent per frame" );
  23. static ConVar ipname ( "ip", "localhost", FCVAR_ALLOWED_IN_COMPETITIVE, "Overrides IP for multihomed hosts" );
  24. static ConVar hostport ( "hostport", NETSTRING( PORT_SERVER ) , FCVAR_ALLOWED_IN_COMPETITIVE, "Host game server port" );
  25. static ConVar hostip ( "hostip", "", FCVAR_ALLOWED_IN_COMPETITIVE, "Host game server ip" );
  26. static ConVar clientport ( "clientport", NETSTRING( PORT_CLIENT ), FCVAR_ALLOWED_IN_COMPETITIVE, "Host game client port" );
  27. static ConVar hltvport ( "tv_port", NETSTRING( PORT_HLTV ), FCVAR_ALLOWED_IN_COMPETITIVE, "Host SourceTV port" );
  28. static ConVar matchmakingport( "matchmakingport", NETSTRING( PORT_MATCHMAKING ), FCVAR_ALLOWED_IN_COMPETITIVE, "Host Matchmaking port" );
  29. static ConVar systemlinkport( "systemlinkport", NETSTRING( PORT_SYSTEMLINK ), FCVAR_ALLOWED_IN_COMPETITIVE, "System Link port" );
  30. static ConVar fakelag ( "net_fakelag", "0", FCVAR_CHEAT, "Lag all incoming network data (including loopback) by this many milliseconds." );
  31. static ConVar fakeloss ( "net_fakeloss", "0", FCVAR_CHEAT, "Simulate packet loss as a percentage (negative means drop 1/n packets)" );
  32. static ConVar droppackets ( "net_droppackets", "0", FCVAR_CHEAT, "Drops next n packets on client" );
  33. static ConVar fakejitter ( "net_fakejitter", "0", FCVAR_CHEAT, "Jitter fakelag packet time" );
  34. static ConVar net_compressvoice( "net_compressvoice", "0", 0, "Attempt to compress out of band voice payloads (360 only)." );
  35. ConVar net_usesocketsforloopback( "net_usesocketsforloopback", "0", 0, "Use network sockets layer even for listen server local player's packets (multiplayer only)." );
  36. #ifdef _DEBUG
  37. static ConVar fakenoise ( "net_fakenoise", "0", FCVAR_CHEAT, "Simulate corrupt network packets (changes n bits per packet randomly)" );
  38. static ConVar fakeshuffle ( "net_fakeshuffle", "0", FCVAR_CHEAT, "Shuffles order of every nth packet (needs net_fakelag)" );
  39. static ConVar recvpackets ( "net_recvpackets", "-1", FCVAR_CHEAT, "Receive exactly next n packets if >= 0" );
  40. static ConVar net_savelargesplits( "net_savelargesplits", "-1", 0, "If not -1, then if a split has this many or more split parts, save the entire packet to disc for analysis." );
  41. #endif
  42. #ifdef _X360
  43. static void NET_LogServerCallback( IConVar *var, const char *pOldString, float flOldValue );
  44. static ConVar net_logserver( "net_logserver", "0", 0, "Dump server stats to a file", NET_LogServerCallback );
  45. static ConVar net_loginterval( "net_loginterval", "1", 0, "Time in seconds between server logs" );
  46. #endif
  47. //-----------------------------------------------------------------------------
  48. // Toggle Xbox 360 network security to allow cross-platform testing
  49. //-----------------------------------------------------------------------------
  50. #if !defined( _X360 )
  51. #define X360SecureNetwork() false
  52. #define IPPROTO_VDP IPPROTO_UDP
  53. #elif defined( _RETAIL )
  54. #define X360SecureNetwork() true
  55. #else
  56. bool X360SecureNetwork( void )
  57. {
  58. if ( CommandLine()->FindParm( "-xnet_bypass_security" ) )
  59. {
  60. return false;
  61. }
  62. return true;
  63. }
  64. #endif
  65. extern ConVar net_showudp;
  66. extern ConVar net_showtcp;
  67. extern ConVar net_blocksize;
  68. extern ConVar host_timescale;
  69. extern int host_framecount;
  70. void NET_ClearQueuedPacketsForChannel( INetChannel *chan );
  71. #define DEF_LOOPBACK_SIZE 2048
  72. typedef struct
  73. {
  74. int nPort; // UDP/TCP use same port number
  75. bool bListening; // true if TCP port is listening
  76. int hUDP; // handle to UDP socket from socket()
  77. int hTCP; // handle to TCP socket from socket()
  78. } netsocket_t;
  79. typedef struct
  80. {
  81. int newsock; // handle of new socket
  82. int netsock; // handle of listen socket
  83. float time;
  84. netadr_t addr;
  85. } pendingsocket_t;
  86. #include "tier0/memdbgoff.h"
  87. struct loopback_t
  88. {
  89. char *data; // loopback buffer
  90. int datalen; // current data length
  91. char defbuffer[ DEF_LOOPBACK_SIZE ];
  92. DECLARE_FIXEDSIZE_ALLOCATOR( loopback_t );
  93. };
  94. #include "tier0/memdbgon.h"
  95. DEFINE_FIXEDSIZE_ALLOCATOR( loopback_t, 2, CUtlMemoryPool::GROW_SLOW );
  96. // Split long packets. Anything over 1460 is failing on some routers
  97. typedef struct
  98. {
  99. int currentSequence;
  100. int splitCount;
  101. int totalSize;
  102. int nExpectedSplitSize;
  103. char buffer[ NET_MAX_MESSAGE ]; // This has to be big enough to hold the largest message
  104. } LONGPACKET;
  105. // Use this to pick apart the network stream, must be packed
  106. #pragma pack(1)
  107. typedef struct
  108. {
  109. int netID;
  110. int sequenceNumber;
  111. int packetID : 16;
  112. int nSplitSize : 16;
  113. } SPLITPACKET;
  114. #pragma pack()
  115. #define MIN_USER_MAXROUTABLE_SIZE 576 // ( X.25 Networks )
  116. #define MAX_USER_MAXROUTABLE_SIZE MAX_ROUTABLE_PAYLOAD
  117. #define MAX_SPLIT_SIZE (MAX_USER_MAXROUTABLE_SIZE - sizeof( SPLITPACKET ))
  118. #define MIN_SPLIT_SIZE (MIN_USER_MAXROUTABLE_SIZE - sizeof( SPLITPACKET ))
  119. // For metering out splitpackets, don't do them too fast as remote UDP socket will drop some payloads causing them to always fail to be reconstituted
  120. // This problem is largely solved by increasing the buffer sizes for UDP sockets on Windows
  121. #define SPLITPACKET_MAX_DATA_BYTES_PER_SECOND V_STRINGIFY(DEFAULT_RATE)
  122. static ConVar sv_maxroutable
  123. (
  124. "sv_maxroutable",
  125. "1260",
  126. 0,
  127. "Server upper bound on net_maxroutable that a client can use.",
  128. true, MIN_USER_MAXROUTABLE_SIZE,
  129. true, MAX_USER_MAXROUTABLE_SIZE
  130. );
  131. ConVar net_maxroutable
  132. (
  133. "net_maxroutable",
  134. "1260",
  135. FCVAR_ARCHIVE | FCVAR_USERINFO,
  136. "Requested max packet size before packets are 'split'.",
  137. true, MIN_USER_MAXROUTABLE_SIZE,
  138. true, MAX_USER_MAXROUTABLE_SIZE
  139. );
  140. netadr_t net_local_adr;
  141. double net_time = 0.0f; // current time, updated each frame
  142. static CUtlVector<netsocket_t> net_sockets; // the 4 sockets, Server, Client, HLTV, Matchmaking
  143. static CUtlVector<netpacket_t> net_packets;
  144. static bool net_multiplayer = false; // if true, configured for Multiplayer
  145. static bool net_noip = false; // Disable IP support, can't switch to MP mode
  146. static bool net_nodns = false; // Disable DNS request to avoid long timeouts
  147. static bool net_notcp = true; // Disable TCP support
  148. static bool net_nohltv = false; // disable HLTV support
  149. static bool net_dedicated = false; // true is dedicated system
  150. static int net_error = 0; // global error code updated with NET_GetLastError()
  151. static CUtlVectorMT< CUtlVector< CNetChan* > > s_NetChannels;
  152. static CUtlVectorMT< CUtlVector< pendingsocket_t > > s_PendingSockets;
  153. CTSQueue<loopback_t *> s_LoopBacks[LOOPBACK_SOCKETS];
  154. static netpacket_t* s_pLagData[MAX_SOCKETS]; // List of lag structures, if fakelag is set.
  155. unsigned short NET_HostToNetShort( unsigned short us_in )
  156. {
  157. return htons( us_in );
  158. }
  159. unsigned short NET_NetToHostShort( unsigned short us_in )
  160. {
  161. return ntohs( us_in );
  162. }
  163. // This macro is used to capture the return value of a function call while recording
  164. // a VCR file. During playback, it will get the return value out of the VCR file
  165. // instead of actually calling the function.
  166. #if !defined( NO_VCR )
  167. #define VCR_NONPLAYBACKFN( call, resultVar, eventName ) \
  168. { \
  169. if ( VCRGetMode() != VCR_Playback ) \
  170. resultVar = call; \
  171. \
  172. VCRGenericValue( eventName, &resultVar, sizeof( resultVar ) ); \
  173. }
  174. #else
  175. #define VCR_NONPLAYBACKFN( call, resultVar, eventName ) \
  176. { \
  177. if ( VCRGetMode() != VCR_Playback ) \
  178. resultVar = call; \
  179. \
  180. }
  181. #endif
  182. /*
  183. ====================
  184. NET_ErrorString
  185. ====================
  186. */
  187. const char *NET_ErrorString (int code)
  188. {
  189. #if defined( _WIN32 )
  190. switch (code)
  191. {
  192. case WSAEINTR: return "WSAEINTR";
  193. case WSAEBADF: return "WSAEBADF";
  194. case WSAEACCES: return "WSAEACCES";
  195. case WSAEDISCON: return "WSAEDISCON";
  196. case WSAEFAULT: return "WSAEFAULT";
  197. case WSAEINVAL: return "WSAEINVAL";
  198. case WSAEMFILE: return "WSAEMFILE";
  199. case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
  200. case WSAEINPROGRESS: return "WSAEINPROGRESS";
  201. case WSAEALREADY: return "WSAEALREADY";
  202. case WSAENOTSOCK: return "WSAENOTSOCK";
  203. case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
  204. case WSAEMSGSIZE: return "WSAEMSGSIZE";
  205. case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
  206. case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
  207. case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
  208. case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
  209. case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
  210. case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
  211. case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
  212. case WSAEADDRINUSE: return "WSAEADDRINUSE";
  213. case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
  214. case WSAENETDOWN: return "WSAENETDOWN";
  215. case WSAENETUNREACH: return "WSAENETUNREACH";
  216. case WSAENETRESET: return "WSAENETRESET";
  217. case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
  218. case WSAECONNRESET: return "WSAECONNRESET";
  219. case WSAENOBUFS: return "WSAENOBUFS";
  220. case WSAEISCONN: return "WSAEISCONN";
  221. case WSAENOTCONN: return "WSAENOTCONN";
  222. case WSAESHUTDOWN: return "WSAESHUTDOWN";
  223. case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
  224. case WSAETIMEDOUT: return "WSAETIMEDOUT";
  225. case WSAECONNREFUSED: return "WSAECONNREFUSED";
  226. case WSAELOOP: return "WSAELOOP";
  227. case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
  228. case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
  229. case WSASYSNOTREADY: return "WSASYSNOTREADY";
  230. case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
  231. case WSANOTINITIALISED: return "WSANOTINITIALISED";
  232. case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
  233. case WSATRY_AGAIN: return "WSATRY_AGAIN";
  234. case WSANO_RECOVERY: return "WSANO_RECOVERY";
  235. case WSANO_DATA: return "WSANO_DATA";
  236. default: return "UNKNOWN ERROR";
  237. }
  238. #else
  239. return strerror( code );
  240. #endif
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose:
  244. // Input : *s -
  245. // *sadr -
  246. // Output : bool NET_StringToSockaddr
  247. //-----------------------------------------------------------------------------
  248. bool NET_StringToSockaddr( const char *s, struct sockaddr *sadr )
  249. {
  250. char *colon;
  251. char copy[128];
  252. Q_memset (sadr, 0, sizeof(*sadr));
  253. ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
  254. ((struct sockaddr_in *)sadr)->sin_port = 0;
  255. Q_strncpy (copy, s, sizeof( copy ) );
  256. // strip off a trailing :port if present
  257. for (colon = copy ; *colon ; colon++)
  258. {
  259. if (*colon == ':')
  260. {
  261. *colon = 0;
  262. ((struct sockaddr_in *)sadr)->sin_port = NET_HostToNetShort((short)atoi(colon+1));
  263. }
  264. }
  265. if (copy[0] >= '0' && copy[0] <= '9' && Q_strstr( copy, "." ) )
  266. {
  267. *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
  268. }
  269. else
  270. {
  271. if ( net_nodns )
  272. return false; // DNS names disabled
  273. struct hostent *h;
  274. if ( (h = gethostbyname(copy)) == NULL )
  275. return false;
  276. *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
  277. }
  278. return true;
  279. }
  280. void NET_ClearLastError( void )
  281. {
  282. net_error = 0;
  283. }
  284. int NET_GetLastError( void )
  285. {
  286. #if defined( _WIN32 )
  287. net_error = WSAGetLastError();
  288. #else
  289. net_error = errno;
  290. #endif
  291. #if !defined( NO_VCR )
  292. VCRGenericValue( "WSAGetLastError", &net_error, sizeof( net_error ) );
  293. #endif
  294. return net_error;
  295. }
  296. /*
  297. ==================
  298. NET_ClearLaggedList
  299. ==================
  300. */
  301. void NET_ClearLaggedList(netpacket_t **pList)
  302. {
  303. netpacket_t * p = (*pList);
  304. while ( p )
  305. {
  306. netpacket_t * n = p->pNext;
  307. if ( p->data )
  308. {
  309. delete[] p->data;
  310. p->data = NULL;
  311. }
  312. delete p;
  313. p = n;
  314. }
  315. (*pList) = NULL;
  316. }
  317. void NET_ClearLagData( int sock )
  318. {
  319. if ( sock < MAX_SOCKETS && s_pLagData[sock] )
  320. {
  321. NET_ClearLaggedList( &s_pLagData[sock] );
  322. }
  323. }
  324. /*
  325. =============
  326. NET_StringToAdr
  327. localhost
  328. idnewt
  329. idnewt:28000
  330. 192.246.40.70
  331. 192.246.40.70:28000
  332. =============
  333. */
  334. bool NET_StringToAdr ( const char *s, netadr_t *a)
  335. {
  336. struct sockaddr saddr;
  337. char address[128];
  338. Q_strncpy( address, s, sizeof(address) );
  339. if ( !Q_strncmp( address, "localhost", 10 ) || !Q_strncmp( address, "localhost:", 10 ) )
  340. {
  341. // subsitute 'localhost' with '127.0.0.1", both have 9 chars
  342. // this way we can resolve 'localhost' without DNS and still keep the port
  343. Q_memcpy( address, "127.0.0.1", 9 );
  344. }
  345. if ( !NET_StringToSockaddr (address, &saddr) )
  346. return false;
  347. a->SetFromSockadr( &saddr );
  348. return true;
  349. }
  350. CNetChan *NET_FindNetChannel(int socket, netadr_t &adr)
  351. {
  352. AUTO_LOCK( s_NetChannels );
  353. int numChannels = s_NetChannels.Count();
  354. for ( int i = 0; i < numChannels; i++ )
  355. {
  356. CNetChan * chan = s_NetChannels[i];
  357. // sockets must match
  358. if ( socket != chan->GetSocket() )
  359. continue;
  360. // and the IP:Port address
  361. if ( adr.CompareAdr( chan->GetRemoteAddress() ) )
  362. {
  363. return chan; // found it
  364. }
  365. }
  366. return NULL; // no channel found
  367. }
  368. void NET_CloseSocket( int hSocket, int sock = -1)
  369. {
  370. if ( !hSocket )
  371. return;
  372. // close socket handle
  373. int ret;
  374. VCR_NONPLAYBACKFN( closesocket( hSocket ), ret, "closesocket" );
  375. if ( ret == -1 )
  376. {
  377. NET_GetLastError();
  378. ConMsg ("WARNING! NET_CloseSocket: %s\n", NET_ErrorString(net_error));
  379. }
  380. // if hSocket mapped to hTCP, clear hTCP
  381. if ( sock >= 0 )
  382. {
  383. if ( net_sockets[sock].hTCP == hSocket )
  384. {
  385. net_sockets[sock].hTCP = 0;
  386. net_sockets[sock].bListening = false;
  387. }
  388. }
  389. }
  390. /*
  391. ====================
  392. NET_IPSocket
  393. ====================
  394. */
  395. int NET_OpenSocket ( const char *net_interface, int& port, int protocol )
  396. {
  397. struct sockaddr_in address;
  398. unsigned int opt;
  399. int newsocket = -1;
  400. if ( protocol == IPPROTO_TCP )
  401. {
  402. VCR_NONPLAYBACKFN( socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), newsocket, "socket()" );
  403. }
  404. else // as UDP or VDP
  405. {
  406. VCR_NONPLAYBACKFN( socket (PF_INET, SOCK_DGRAM, protocol), newsocket, "socket()" );
  407. }
  408. if ( newsocket == -1 )
  409. {
  410. NET_GetLastError();
  411. if ( net_error != WSAEAFNOSUPPORT )
  412. Msg ("WARNING: NET_OpenSockett: socket failed: %s", NET_ErrorString(net_error));
  413. return 0;
  414. }
  415. opt = 1; // make it non-blocking
  416. int ret;
  417. VCR_NONPLAYBACKFN( ioctlsocket (newsocket, FIONBIO, (unsigned long*)&opt), ret, "ioctlsocket" );
  418. if ( ret == -1 )
  419. {
  420. NET_GetLastError();
  421. Msg ("WARNING: NET_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString(net_error) );
  422. }
  423. if ( protocol == IPPROTO_TCP )
  424. {
  425. if ( !IsX360() ) // SO_KEEPALIVE unsupported on the 360
  426. {
  427. opt = 1; // set TCP options: keep TCP connection alive
  428. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  429. if (ret == -1)
  430. {
  431. NET_GetLastError();
  432. Msg ("WARNING: NET_OpenSocket: setsockopt SO_KEEPALIVE: %s\n", NET_ErrorString(net_error));
  433. return 0;
  434. }
  435. }
  436. linger optlinger; // set TCP options: Does not block close waiting for unsent data to be sent
  437. optlinger.l_linger = 0;
  438. optlinger.l_onoff = 0;
  439. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_LINGER, (char *)&optlinger, sizeof(optlinger)), ret, "setsockopt" );
  440. if (ret == -1)
  441. {
  442. NET_GetLastError();
  443. Msg ("WARNING: NET_OpenSocket: setsockopt SO_LINGER: %s\n", NET_ErrorString(net_error));
  444. return 0;
  445. }
  446. opt = 1; // set TCP options: Disables the Nagle algorithm for send coalescing.
  447. VCR_NONPLAYBACKFN( setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  448. if (ret == -1)
  449. {
  450. NET_GetLastError();
  451. Msg ("WARNING: NET_OpenSocket: setsockopt TCP_NODELAY: %s\n", NET_ErrorString(net_error));
  452. return 0;
  453. }
  454. opt = NET_MAX_MESSAGE; // set TCP options: set send buffer size
  455. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_SNDBUF, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  456. if (ret == -1)
  457. {
  458. NET_GetLastError();
  459. Msg ("WARNING: NET_OpenSocket: setsockopt SO_SNDBUF: %s\n", NET_ErrorString(net_error));
  460. return 0;
  461. }
  462. opt = NET_MAX_MESSAGE; // set TCP options: set receive buffer size
  463. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  464. if (ret == -1)
  465. {
  466. NET_GetLastError();
  467. Msg ("WARNING: NET_OpenSocket: setsockopt SO_RCVBUF: %s\n", NET_ErrorString(net_error));
  468. return 0;
  469. }
  470. return newsocket; // don't bind TCP sockets by default
  471. }
  472. // rest is UDP only
  473. opt = 0;
  474. socklen_t len = sizeof( opt );
  475. VCR_NONPLAYBACKFN( getsockopt( newsocket, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &len ), ret, "getsockopt" );
  476. if ( ret == -1 )
  477. {
  478. NET_GetLastError();
  479. Msg ("WARNING: NET_OpenSocket: getsockopt SO_RCVBUF: %s\n", NET_ErrorString(net_error));
  480. return 0;
  481. }
  482. if ( net_showudp.GetBool() )
  483. {
  484. static bool bFirst = true;
  485. if ( bFirst )
  486. {
  487. Msg( "UDP socket SO_RCVBUF size %d bytes, changing to %d\n", opt, net_udp_rcvbuf.GetInt() );
  488. }
  489. bFirst = false;
  490. }
  491. opt = net_udp_rcvbuf.GetInt(); // set UDP receive buffer size
  492. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_RCVBUF, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  493. if (ret == -1)
  494. {
  495. NET_GetLastError();
  496. Msg ("WARNING: NET_OpenSocket: setsockopt SO_RCVBUF: %s\n", NET_ErrorString(net_error));
  497. return 0;
  498. }
  499. opt = net_udp_rcvbuf.GetInt(); // set UDP send buffer size
  500. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_SNDBUF, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  501. if (ret == -1)
  502. {
  503. NET_GetLastError();
  504. Msg ("WARNING: NET_OpenSocket: setsockopt SO_SNDBUF: %s\n", NET_ErrorString(net_error));
  505. return 0;
  506. }
  507. // VDP protocol (Xbox 360 secure network) doesn't support SO_BROADCAST
  508. if ( !X360SecureNetwork() || protocol != IPPROTO_VDP )
  509. {
  510. opt = 1; // set UDP options: make it broadcast capable
  511. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  512. if (ret == -1)
  513. {
  514. NET_GetLastError();
  515. Msg ("WARNING: NET_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString(net_error));
  516. return 0;
  517. }
  518. }
  519. if ( CommandLine()->FindParm( "-reuse" ) )
  520. {
  521. opt = 1; // make it reusable
  522. VCR_NONPLAYBACKFN( setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)), ret, "setsockopt" );
  523. if (ret == -1)
  524. {
  525. NET_GetLastError();
  526. Msg ("WARNING: NET_OpenSocket: setsockopt SO_REUSEADDR: %s\n", NET_ErrorString(net_error));
  527. return 0;
  528. }
  529. }
  530. if (!net_interface || !net_interface[0] || !Q_strcmp(net_interface, "localhost"))
  531. {
  532. address.sin_addr.s_addr = INADDR_ANY;
  533. }
  534. else
  535. {
  536. NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  537. }
  538. address.sin_family = AF_INET;
  539. int port_offset; // try binding socket to port, try next 10 is port is already used
  540. for ( port_offset = 0; port_offset < PORT_TRY_MAX; port_offset++ )
  541. {
  542. if ( port == PORT_ANY )
  543. {
  544. address.sin_port = 0; // = INADDR_ANY
  545. }
  546. else
  547. {
  548. address.sin_port = NET_HostToNetShort((short)( port + port_offset ));
  549. }
  550. VCR_NONPLAYBACKFN( bind (newsocket, (struct sockaddr *)&address, sizeof(address)), ret, "bind" );
  551. if ( ret != -1 )
  552. {
  553. if ( port != PORT_ANY && port_offset != 0 )
  554. {
  555. port += port_offset; // update port
  556. ConDMsg( "Socket bound to non-default port %i because original port was already in use.\n", port );
  557. }
  558. break;
  559. }
  560. NET_GetLastError();
  561. if ( port == PORT_ANY || net_error != WSAEADDRINUSE )
  562. {
  563. Msg ("WARNING: NNET_OpenSocket: bind: %s\n", NET_ErrorString(net_error));
  564. NET_CloseSocket(newsocket,-1);
  565. return 0;
  566. }
  567. // Try next port
  568. }
  569. const bool bStrictBind = CommandLine()->FindParm( "-strictportbind" );
  570. if ( port_offset == PORT_TRY_MAX && !bStrictBind )
  571. {
  572. Msg( "WARNING: UDP_OpenSocket: unable to bind socket\n" );
  573. NET_CloseSocket( newsocket,-1 );
  574. return 0;
  575. }
  576. if ( port_offset > 0 )
  577. {
  578. if ( bStrictBind )
  579. {
  580. // The server op wants to exit if the desired port was not avialable.
  581. Sys_Exit( "ERROR: Port %i was unavailable - quitting due to \"-strictportbind\" command-line flag!\n", port - port_offset );
  582. }
  583. else
  584. {
  585. Warning( "WARNING: Port %i was unavailable - bound to port %i instead\n", port - port_offset, port );
  586. }
  587. }
  588. return newsocket;
  589. }
  590. int NET_ConnectSocket( int sock, const netadr_t &addr )
  591. {
  592. Assert( (sock >= 0) && (sock < net_sockets.Count()) );
  593. netsocket_t *netsock = &net_sockets[sock];
  594. if ( netsock->hTCP )
  595. {
  596. NET_CloseSocket( netsock->hTCP, sock );
  597. }
  598. if ( net_notcp )
  599. return 0;
  600. sockaddr saddr;
  601. addr.ToSockadr( &saddr );
  602. int anyport = PORT_ANY;
  603. netsock->hTCP = NET_OpenSocket( ipname.GetString(), anyport, true );
  604. if ( !netsock->hTCP )
  605. {
  606. Msg( "Warning! NET_ConnectSocket failed opening socket %i, port %i.\n", sock, net_sockets[sock].nPort );
  607. return false;
  608. }
  609. int ret;
  610. VCR_NONPLAYBACKFN( connect( netsock->hTCP, &saddr, sizeof(saddr) ), ret, "connect" );
  611. if ( ret == -1 )
  612. {
  613. NET_GetLastError();
  614. if ( net_error != WSAEWOULDBLOCK )
  615. {
  616. Msg ("NET_ConnectSocket: %s\n", NET_ErrorString( net_error ) );
  617. return 0;
  618. }
  619. }
  620. return net_sockets[sock].hTCP;
  621. }
  622. int NET_SendStream( int nSock, const char * buf, int len, int flags )
  623. {
  624. //int ret = send( nSock, buf, len, flags );
  625. int ret = VCRHook_send( nSock, buf, len, flags );
  626. if ( ret == -1 )
  627. {
  628. NET_GetLastError();
  629. if ( net_error == WSAEWOULDBLOCK )
  630. {
  631. return 0; // ignore EWOULDBLOCK
  632. }
  633. Msg ("NET_SendStream: %s\n", NET_ErrorString( net_error ) );
  634. }
  635. return ret;
  636. }
  637. int NET_ReceiveStream( int nSock, char * buf, int len, int flags )
  638. {
  639. int ret = VCRHook_recv( nSock, buf, len, flags );
  640. if ( ret == -1 )
  641. {
  642. NET_GetLastError();
  643. if ( net_error == WSAEWOULDBLOCK ||
  644. net_error == WSAENOTCONN )
  645. {
  646. return 0; // ignore EWOULDBLOCK
  647. }
  648. Msg ("NET_ReceiveStream: %s\n", NET_ErrorString( net_error ) );
  649. }
  650. return ret;
  651. }
  652. INetChannel *NET_CreateNetChannel(int socket, netadr_t *adr, const char * name, INetChannelHandler * handler, bool bForceNewChannel/*=false*/,
  653. int nProtocolVersion/*=PROTOCOL_VERSION*/)
  654. {
  655. CNetChan *chan = NULL;
  656. if ( !bForceNewChannel && adr != NULL )
  657. {
  658. // try to find real network channel if already existing
  659. if ( ( chan = NET_FindNetChannel( socket, *adr ) ) != NULL )
  660. {
  661. // channel already known, clear any old stuff before Setup wipes all
  662. chan->Clear();
  663. }
  664. }
  665. if ( !chan )
  666. {
  667. // create new channel
  668. chan = new CNetChan();
  669. AUTO_LOCK( s_NetChannels );
  670. s_NetChannels.AddToTail( chan );
  671. }
  672. NET_ClearLagData( socket );
  673. // just reset and return
  674. chan->Setup( socket, adr, name, handler, nProtocolVersion );
  675. return chan;
  676. }
  677. void NET_RemoveNetChannel(INetChannel *netchan, bool bDeleteNetChan)
  678. {
  679. if ( !netchan )
  680. {
  681. return;
  682. }
  683. AUTO_LOCK( s_NetChannels );
  684. if ( s_NetChannels.Find( static_cast<CNetChan*>(netchan) ) == s_NetChannels.InvalidIndex() )
  685. {
  686. DevMsg(1, "NET_CloseNetChannel: unknown channel.\n");
  687. return;
  688. }
  689. s_NetChannels.FindAndRemove( static_cast<CNetChan*>(netchan) );
  690. NET_ClearQueuedPacketsForChannel( netchan );
  691. if ( bDeleteNetChan )
  692. delete netchan;
  693. }
  694. /*
  695. =============================================================================
  696. LOOPBACK BUFFERS FOR LOCAL PLAYER
  697. =============================================================================
  698. */
  699. void NET_SendLoopPacket (int sock, int length, const unsigned char *data, const netadr_t &to)
  700. {
  701. loopback_t *loop;
  702. if ( length > NET_MAX_PAYLOAD )
  703. {
  704. DevMsg( "NET_SendLoopPacket: packet too big (%i).\n", length );
  705. return;
  706. }
  707. loop = new loopback_t;
  708. if ( length <= DEF_LOOPBACK_SIZE )
  709. {
  710. loop->data = loop->defbuffer;
  711. }
  712. else
  713. {
  714. loop->data = new char[ length ];
  715. }
  716. Q_memcpy (loop->data, data, length);
  717. loop->datalen = length;
  718. if ( sock == NS_SERVER )
  719. {
  720. s_LoopBacks[NS_CLIENT].PushItem( loop );
  721. }
  722. else if ( sock == NS_CLIENT )
  723. {
  724. s_LoopBacks[NS_SERVER].PushItem( loop );
  725. }
  726. else
  727. {
  728. DevMsg( "NET_SendLoopPacket: invalid socket (%i).\n", sock );
  729. return;
  730. }
  731. }
  732. //=============================================================================
  733. int NET_CountLaggedList( netpacket_t *pList )
  734. {
  735. int c = 0;
  736. netpacket_t *p = pList;
  737. while ( p )
  738. {
  739. c++;
  740. p = p->pNext;
  741. }
  742. return c;
  743. }
  744. /*
  745. ===================
  746. NET_AddToLagged
  747. ===================
  748. */
  749. void NET_AddToLagged( netpacket_t **pList, netpacket_t *pPacket )
  750. {
  751. if ( pPacket->pNext )
  752. {
  753. Msg("NET_AddToLagged::Packet already linked\n");
  754. return;
  755. }
  756. // first copy packet
  757. netpacket_t *newPacket = new netpacket_t;
  758. (*newPacket) = (*pPacket); // copy packet infos
  759. newPacket->data = new unsigned char[ pPacket->size ]; // create new data buffer
  760. Q_memcpy( newPacket->data, pPacket->data, pPacket->size ); // copy packet data
  761. newPacket->pNext = NULL;
  762. // if list is empty, this is our first element
  763. if ( (*pList) == NULL )
  764. {
  765. (*pList) = newPacket; // put packet in top of list
  766. }
  767. else
  768. {
  769. netpacket_t *last = (*pList);
  770. while ( last->pNext )
  771. {
  772. // got to end of list
  773. last = last->pNext;
  774. }
  775. // add at end
  776. last->pNext = newPacket;
  777. }
  778. }
  779. // Actual lag to use in msec
  780. static float s_FakeLag = 0.0;
  781. float NET_GetFakeLag()
  782. {
  783. return s_FakeLag;
  784. }
  785. // How quickly we converge to a new value for fakelag
  786. #define FAKELAG_CONVERGE 200 // ms per second
  787. /*
  788. ==============================
  789. NET_AdjustLag
  790. ==============================
  791. */
  792. void NET_AdjustLag( void )
  793. {
  794. static double s_LastTime = 0;
  795. // Bound time step
  796. float dt = net_time - s_LastTime;
  797. dt = clamp( dt, 0.0f, 0.2f );
  798. s_LastTime = net_time;
  799. // Already converged?
  800. if ( fakelag.GetFloat() == s_FakeLag )
  801. return;
  802. // Figure out how far we have to go
  803. float diff = fakelag.GetFloat() - s_FakeLag;
  804. // How much can we converge this frame
  805. float converge = FAKELAG_CONVERGE * dt;
  806. // Last step, go the whole way
  807. if ( converge > fabs( diff ) )
  808. {
  809. converge = fabs( diff );
  810. }
  811. // Converge toward fakelag.GetFloat()
  812. if ( diff < 0.0 )
  813. {
  814. // Converge toward fakelag.GetFloat()
  815. s_FakeLag -= converge;
  816. }
  817. else
  818. {
  819. s_FakeLag += converge;
  820. }
  821. }
  822. bool NET_LagPacket (bool newdata, netpacket_t * packet)
  823. {
  824. static int losscount[MAX_SOCKETS];
  825. if ( packet->source >= MAX_SOCKETS )
  826. return newdata; // fake lag not supported for extra sockets
  827. if ( (droppackets.GetInt() > 0) && newdata && (packet->source == NS_CLIENT) )
  828. {
  829. droppackets.SetValue( droppackets.GetInt() - 1 );
  830. return false;
  831. }
  832. if ( fakeloss.GetFloat() && newdata )
  833. {
  834. losscount[packet->source]++;
  835. if ( fakeloss.GetFloat() > 0.0f )
  836. {
  837. // Act like we didn't hear anything if we are going to lose the packet.
  838. // Depends on random # generator.
  839. if (RandomInt(0,100) <= (int)fakeloss.GetFloat())
  840. return false;
  841. }
  842. else
  843. {
  844. int ninterval;
  845. ninterval = (int)(fabs( fakeloss.GetFloat() ) );
  846. ninterval = max( 2, ninterval );
  847. if ( !( losscount[packet->source] % ninterval ) )
  848. {
  849. return false;
  850. }
  851. }
  852. }
  853. if (s_FakeLag <= 0.0)
  854. {
  855. // Never leave any old msgs around
  856. for ( int i=0; i<MAX_SOCKETS; i++ )
  857. {
  858. NET_ClearLagData( i );
  859. }
  860. return newdata;
  861. }
  862. // if new packet arrived in fakelag list
  863. if ( newdata )
  864. {
  865. NET_AddToLagged( &s_pLagData[packet->source], packet );
  866. }
  867. // Now check the correct list and feed any message that is old enough.
  868. netpacket_t *p = s_pLagData[packet->source]; // current packet
  869. if ( !p )
  870. return false; // no packet in lag list
  871. float target = s_FakeLag;
  872. float maxjitter = min( fakejitter.GetFloat(), target * 0.5f );
  873. target += RandomFloat( -maxjitter, maxjitter );
  874. if ( (p->received + (target/1000.0f)) > net_time )
  875. return false; // not time yet for this packet
  876. #ifdef _DEBUG
  877. if ( fakeshuffle.GetInt() && p->pNext )
  878. {
  879. if ( !RandomInt( 0, fakeshuffle.GetInt() ) )
  880. {
  881. // swap p and p->next
  882. netpacket_t * t = p->pNext;
  883. p->pNext = t->pNext;
  884. t->pNext = p;
  885. p = t;
  886. }
  887. }
  888. #endif
  889. // remove packet p from list (is head)
  890. s_pLagData[packet->source] = p->pNext;
  891. // copy & adjust content
  892. packet->source = p->source;
  893. packet->from = p->from;
  894. packet->pNext = NULL; // no next
  895. packet->received = net_time; // new time
  896. packet->size = p->size;
  897. packet->wiresize = p->wiresize;
  898. packet->stream = p->stream;
  899. Q_memcpy( packet->data, p->data, p->size );
  900. // free lag packet
  901. delete[] p->data;
  902. delete p;
  903. return true;
  904. }
  905. // Calculate MAX_SPLITPACKET_SPLITS according to the smallest split size
  906. #define MAX_SPLITPACKET_SPLITS ( NET_MAX_MESSAGE / MIN_SPLIT_SIZE )
  907. #define SPLIT_PACKET_STALE_TIME 2.0f
  908. #define SPLIT_PACKET_TRACKING_MAX 256 // most number of outstanding split packets to allow
  909. class CSplitPacketEntry
  910. {
  911. public:
  912. CSplitPacketEntry()
  913. {
  914. memset( &from, 0, sizeof( from ) );
  915. int i;
  916. for ( i = 0; i < MAX_SPLITPACKET_SPLITS; i++ )
  917. {
  918. splitflags[ i ] = -1;
  919. }
  920. memset( &netsplit, 0, sizeof( netsplit ) );
  921. lastactivetime = 0.0f;
  922. }
  923. public:
  924. netadr_t from;
  925. int splitflags[ MAX_SPLITPACKET_SPLITS ];
  926. LONGPACKET netsplit;
  927. // host_time the last time any entry was received for this entry
  928. float lastactivetime;
  929. };
  930. typedef CUtlVector< CSplitPacketEntry > vecSplitPacketEntries_t;
  931. static CUtlVector<vecSplitPacketEntries_t> net_splitpackets;
  932. //-----------------------------------------------------------------------------
  933. // Purpose:
  934. //-----------------------------------------------------------------------------
  935. void NET_DiscardStaleSplitpackets( const int sock )
  936. {
  937. vecSplitPacketEntries_t &splitPacketEntries = net_splitpackets[sock];
  938. int i;
  939. for ( i = splitPacketEntries.Count() - 1; i >= 0; i-- )
  940. {
  941. CSplitPacketEntry *entry = &splitPacketEntries[ i ];
  942. Assert( entry );
  943. if ( net_time < ( entry->lastactivetime + SPLIT_PACKET_STALE_TIME ) )
  944. continue;
  945. splitPacketEntries.Remove( i );
  946. }
  947. if ( splitPacketEntries.Count() > SPLIT_PACKET_TRACKING_MAX )
  948. {
  949. while ( splitPacketEntries.Count() > SPLIT_PACKET_TRACKING_MAX )
  950. {
  951. CSplitPacketEntry *entry = &splitPacketEntries[ i ];
  952. if ( net_time != entry->lastactivetime )
  953. splitPacketEntries.Remove(0); // we add to tail each time, so head is the oldest entry, kill them first
  954. }
  955. }
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Purpose:
  959. // Input : *from -
  960. // Output : CSplitPacketEntry
  961. //-----------------------------------------------------------------------------
  962. CSplitPacketEntry *NET_FindOrCreateSplitPacketEntry( const int sock, netadr_t *from )
  963. {
  964. vecSplitPacketEntries_t &splitPacketEntries = net_splitpackets[sock];
  965. int i, count = splitPacketEntries.Count();
  966. CSplitPacketEntry *entry = NULL;
  967. for ( i = 0; i < count; i++ )
  968. {
  969. entry = &splitPacketEntries[ i ];
  970. Assert( entry );
  971. if ( from->CompareAdr(entry->from) )
  972. break;
  973. }
  974. if ( i >= count )
  975. {
  976. CSplitPacketEntry newentry;
  977. newentry.from = *from;
  978. splitPacketEntries.AddToTail( newentry );
  979. entry = &splitPacketEntries[ splitPacketEntries.Count() - 1 ];
  980. }
  981. Assert( entry );
  982. return entry;
  983. }
  984. static char const *DescribeSocket( int sock )
  985. {
  986. switch ( sock )
  987. {
  988. default:
  989. break;
  990. case NS_CLIENT:
  991. return "cl ";
  992. case NS_SERVER:
  993. return "sv ";
  994. case NS_HLTV:
  995. return "htv";
  996. case NS_MATCHMAKING:
  997. return "mat";
  998. case NS_SYSTEMLINK:
  999. return "lnk";
  1000. #ifdef LINUX
  1001. case NS_SVLAN:
  1002. return "lan";
  1003. #endif
  1004. }
  1005. return "??";
  1006. }
  1007. //-----------------------------------------------------------------------------
  1008. // Purpose:
  1009. // Input : *pData -
  1010. // size -
  1011. // *outSize -
  1012. // Output : bool
  1013. //-----------------------------------------------------------------------------
  1014. bool NET_GetLong( const int sock, netpacket_t *packet )
  1015. {
  1016. int packetNumber, packetCount, sequenceNumber, offset;
  1017. short packetID;
  1018. SPLITPACKET *pHeader;
  1019. if ( packet->size < sizeof(SPLITPACKET) )
  1020. {
  1021. Msg( "Invalid split packet length %i\n", packet->size );
  1022. return false;
  1023. }
  1024. pHeader = ( SPLITPACKET * )packet->data;
  1025. // pHeader is network endian correct
  1026. sequenceNumber = LittleLong( pHeader->sequenceNumber );
  1027. packetID = LittleShort( (short)pHeader->packetID );
  1028. // High byte is packet number
  1029. packetNumber = ( packetID >> 8 );
  1030. // Low byte is number of total packets
  1031. packetCount = ( packetID & 0xff );
  1032. int nSplitSizeMinusHeader = (int)LittleShort( (short)pHeader->nSplitSize );
  1033. if ( nSplitSizeMinusHeader < MIN_SPLIT_SIZE ||
  1034. nSplitSizeMinusHeader > MAX_SPLIT_SIZE )
  1035. {
  1036. Msg( "NET_GetLong: Split packet from %s with invalid split size (number %i/ count %i) where size %i is out of valid range [%llu - %llu]\n",
  1037. packet->from.ToString(),
  1038. packetNumber,
  1039. packetCount,
  1040. nSplitSizeMinusHeader,
  1041. (uint64)MIN_SPLIT_SIZE,
  1042. (uint64)MAX_SPLIT_SIZE );
  1043. return false;
  1044. }
  1045. if ( packetNumber >= MAX_SPLITPACKET_SPLITS ||
  1046. packetCount > MAX_SPLITPACKET_SPLITS )
  1047. {
  1048. Msg( "NET_GetLong: Split packet from %s with too many split parts (number %i/ count %i) where %llu is max count allowed\n",
  1049. packet->from.ToString(),
  1050. packetNumber,
  1051. packetCount,
  1052. (uint64)MAX_SPLITPACKET_SPLITS );
  1053. return false;
  1054. }
  1055. CSplitPacketEntry *entry = NET_FindOrCreateSplitPacketEntry( sock, &packet->from );
  1056. Assert( entry );
  1057. if ( !entry )
  1058. return false;
  1059. entry->lastactivetime = net_time;
  1060. Assert( packet->from.CompareAdr( entry->from ) );
  1061. // First packet in split series?
  1062. if ( entry->netsplit.currentSequence == -1 ||
  1063. sequenceNumber != entry->netsplit.currentSequence )
  1064. {
  1065. entry->netsplit.currentSequence = sequenceNumber;
  1066. entry->netsplit.splitCount = packetCount;
  1067. entry->netsplit.nExpectedSplitSize = nSplitSizeMinusHeader;
  1068. }
  1069. if ( entry->netsplit.nExpectedSplitSize != nSplitSizeMinusHeader )
  1070. {
  1071. Msg( "NET_GetLong: Split packet from %s with inconsistent split size (number %i/ count %i) where size %i not equal to initial size of %i\n",
  1072. packet->from.ToString(),
  1073. packetNumber,
  1074. packetCount,
  1075. nSplitSizeMinusHeader,
  1076. entry->netsplit.nExpectedSplitSize
  1077. );
  1078. entry->lastactivetime = net_time + SPLIT_PACKET_STALE_TIME;
  1079. return false;
  1080. }
  1081. int size = packet->size - sizeof(SPLITPACKET);
  1082. if ( entry->splitflags[ packetNumber ] != sequenceNumber )
  1083. {
  1084. // Last packet in sequence? set size
  1085. if ( packetNumber == (packetCount-1) )
  1086. {
  1087. entry->netsplit.totalSize = (packetCount-1) * nSplitSizeMinusHeader + size;
  1088. }
  1089. entry->netsplit.splitCount--; // Count packet
  1090. entry->splitflags[ packetNumber ] = sequenceNumber;
  1091. if ( net_showsplits.GetInt() && net_showsplits.GetInt() != 3 )
  1092. {
  1093. Msg( "<-- [%s] Split packet %4i/%4i seq %5i size %4i mtu %4llu from %s\n",
  1094. DescribeSocket( sock ),
  1095. packetNumber + 1,
  1096. packetCount,
  1097. sequenceNumber,
  1098. size,
  1099. (uint64)(nSplitSizeMinusHeader + sizeof( SPLITPACKET )),
  1100. packet->from.ToString() );
  1101. }
  1102. }
  1103. else
  1104. {
  1105. Msg( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes ) from %s\n", packetNumber + 1, packetCount, size, packet->from.ToString() );
  1106. }
  1107. // Copy the incoming data to the appropriate place in the buffer
  1108. offset = (packetNumber * nSplitSizeMinusHeader);
  1109. memcpy( entry->netsplit.buffer + offset, packet->data + sizeof(SPLITPACKET), size );
  1110. // Have we received all of the pieces to the packet?
  1111. if ( entry->netsplit.splitCount <= 0 )
  1112. {
  1113. entry->netsplit.currentSequence = -1; // Clear packet
  1114. if ( entry->netsplit.totalSize > sizeof(entry->netsplit.buffer) )
  1115. {
  1116. Msg("Split packet too large! %d bytes from %s\n", entry->netsplit.totalSize, packet->from.ToString() );
  1117. return false;
  1118. }
  1119. Q_memcpy( packet->data, entry->netsplit.buffer, entry->netsplit.totalSize );
  1120. packet->size = entry->netsplit.totalSize;
  1121. packet->wiresize = entry->netsplit.totalSize;
  1122. return true;
  1123. }
  1124. return false;
  1125. }
  1126. bool NET_GetLoopPacket ( netpacket_t * packet )
  1127. {
  1128. Assert ( packet );
  1129. loopback_t *loop;
  1130. if ( packet->source > NS_SERVER )
  1131. return false;
  1132. if ( !s_LoopBacks[packet->source].PopItem( &loop ) )
  1133. {
  1134. return false;
  1135. }
  1136. if (loop->datalen == 0)
  1137. {
  1138. // no packet in loopback buffer
  1139. delete loop;
  1140. return ( NET_LagPacket( false, packet ) );
  1141. }
  1142. // copy data from loopback buffer to packet
  1143. packet->from.SetType( NA_LOOPBACK );
  1144. packet->size = loop->datalen;
  1145. packet->wiresize = loop->datalen;
  1146. Q_memcpy ( packet->data, loop->data, packet->size );
  1147. loop->datalen = 0; // buffer is avalibale again
  1148. if ( loop->data != loop->defbuffer )
  1149. {
  1150. delete loop->data;
  1151. loop->data = loop->defbuffer;
  1152. }
  1153. delete loop;
  1154. // allow lag system to modify packet
  1155. return ( NET_LagPacket( true, packet ) );
  1156. }
  1157. bool NET_ReceiveDatagram ( const int sock, netpacket_t * packet )
  1158. {
  1159. VPROF_BUDGET( "NET_ReceiveDatagram", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1160. Assert ( packet );
  1161. Assert ( net_multiplayer );
  1162. struct sockaddr from;
  1163. int fromlen = sizeof(from);
  1164. int net_socket = net_sockets[packet->source].hUDP;
  1165. int ret = 0;
  1166. {
  1167. VPROF_BUDGET( "recvfrom", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1168. ret = VCRHook_recvfrom(net_socket, (char *)packet->data, NET_MAX_MESSAGE, 0, (struct sockaddr *)&from, (int *)&fromlen );
  1169. }
  1170. if ( ret >= NET_MIN_MESSAGE )
  1171. {
  1172. packet->wiresize = ret;
  1173. packet->from.SetFromSockadr( &from );
  1174. packet->size = ret;
  1175. if ( net_showudp_wire.GetBool() )
  1176. {
  1177. Msg( "WIRE: UDP sz=%d tm=%f rt %f from %s\n", ret, net_time, Plat_FloatTime(), packet->from.ToString() );
  1178. }
  1179. MEM_ALLOC_CREDIT();
  1180. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > bufVoice( NET_COMPRESSION_STACKBUF_SIZE );
  1181. unsigned int nVoiceBits = 0u;
  1182. if ( X360SecureNetwork() )
  1183. {
  1184. // X360TBD: Check for voice data and forward it to XAudio
  1185. // For now, just pull off the 2-byte VDP header and shift the data
  1186. unsigned short nDataBytes = ( *( unsigned short * )packet->data );
  1187. Assert( nDataBytes > 0 && nDataBytes <= ret );
  1188. int nVoiceBytes = ret - nDataBytes - 2;
  1189. if ( nVoiceBytes > 0 )
  1190. {
  1191. char *pVoice = (char *)packet->data + 2 + nDataBytes;
  1192. nVoiceBits = (unsigned int)LittleShort( *( unsigned short *)pVoice );
  1193. unsigned int nExpectedVoiceBytes = Bits2Bytes( nVoiceBits );
  1194. pVoice += sizeof( unsigned short );
  1195. int nCompressedSize = nVoiceBytes - sizeof( unsigned short );
  1196. int nDecompressedVoice = COM_GetUncompressedSize( pVoice, nCompressedSize );
  1197. if ( nDecompressedVoice >= 0 )
  1198. {
  1199. if ( (unsigned)nDecompressedVoice != nExpectedVoiceBytes )
  1200. {
  1201. return false;
  1202. }
  1203. bufVoice.EnsureCapacity( nDecompressedVoice );
  1204. // Decompress it
  1205. unsigned unActualDecompressedSize = (unsigned)nDecompressedVoice;
  1206. if ( !COM_BufferToBufferDecompress( (char*)bufVoice.Base(), &unActualDecompressedSize, pVoice, nCompressedSize ) )
  1207. return false;
  1208. Assert( unActualDecompressedSize == (unsigned)nDecompressedVoice );
  1209. nVoiceBytes = unActualDecompressedSize;
  1210. }
  1211. else
  1212. {
  1213. bufVoice.EnsureCapacity( nVoiceBytes );
  1214. Q_memcpy( bufVoice.Base(), pVoice, nVoiceBytes );
  1215. }
  1216. }
  1217. Q_memmove( packet->data, &packet->data[2], nDataBytes );
  1218. ret = nDataBytes;
  1219. }
  1220. if ( ret < NET_MAX_MESSAGE )
  1221. {
  1222. // Check for split message
  1223. if ( LittleLong( *(int *)packet->data ) == NET_HEADER_FLAG_SPLITPACKET )
  1224. {
  1225. if ( !NET_GetLong( sock, packet ) )
  1226. return false;
  1227. }
  1228. // Next check for compressed message
  1229. if ( LittleLong( *(int *)packet->data) == NET_HEADER_FLAG_COMPRESSEDPACKET )
  1230. {
  1231. char *pCompressedData = (char*)packet->data + sizeof( unsigned int );
  1232. unsigned nCompressedDataSize = packet->wiresize - sizeof( unsigned int );
  1233. // Decompress
  1234. int actualSize = COM_GetUncompressedSize( pCompressedData, nCompressedDataSize );
  1235. if ( actualSize <= 0 || actualSize > NET_MAX_PAYLOAD )
  1236. return false;
  1237. MEM_ALLOC_CREDIT();
  1238. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memDecompressed( NET_COMPRESSION_STACKBUF_SIZE );
  1239. memDecompressed.EnsureCapacity( actualSize );
  1240. unsigned uDecompressedSize = (unsigned)actualSize;
  1241. COM_BufferToBufferDecompress( (char*)memDecompressed.Base(), &uDecompressedSize, pCompressedData, nCompressedDataSize );
  1242. if ( uDecompressedSize == 0 || ((unsigned int)actualSize) != uDecompressedSize )
  1243. {
  1244. if ( net_showudp.GetBool() )
  1245. {
  1246. Msg( "UDP: discarding %d bytes from %s due to decompression error [%d decomp, actual %d] at tm=%f rt=%f\n", ret, packet->from.ToString(), uDecompressedSize, actualSize,
  1247. (float)net_time, (float)Plat_FloatTime() );
  1248. }
  1249. return false;
  1250. }
  1251. // packet->wiresize is already set
  1252. Q_memcpy( packet->data, memDecompressed.Base(), uDecompressedSize );
  1253. packet->size = uDecompressedSize;
  1254. }
  1255. if ( nVoiceBits > 0 )
  1256. {
  1257. // 9th byte is flag byte
  1258. byte flagByte = *( (byte *)packet->data + sizeof( unsigned int ) + sizeof( unsigned int ) );
  1259. unsigned int unPacketBits = packet->size << 3;
  1260. int nPadBits = DECODE_PAD_BITS( flagByte );
  1261. unPacketBits -= nPadBits;
  1262. bf_write fixup;
  1263. fixup.SetDebugName( "X360 Fixup" );
  1264. fixup.StartWriting( packet->data, NET_MAX_MESSAGE, unPacketBits );
  1265. fixup.WriteBits( bufVoice.Base(), nVoiceBits );
  1266. // Make sure we have enough bits to read a final net_NOP opcode before compressing
  1267. int nRemainingBits = fixup.GetNumBitsWritten() % 8;
  1268. if ( nRemainingBits > 0 && nRemainingBits <= (8-NETMSG_TYPE_BITS) )
  1269. {
  1270. fixup.WriteUBitLong( net_NOP, NETMSG_TYPE_BITS );
  1271. }
  1272. packet->size = fixup.GetNumBytesWritten();
  1273. }
  1274. return NET_LagPacket( true, packet );
  1275. }
  1276. else
  1277. {
  1278. ConDMsg ( "NET_ReceiveDatagram: Oversize packet from %s\n", packet->from.ToString() );
  1279. }
  1280. }
  1281. else if ( ret == -1 ) // error?
  1282. {
  1283. NET_GetLastError();
  1284. switch ( net_error )
  1285. {
  1286. case WSAEWOULDBLOCK:
  1287. case WSAECONNRESET:
  1288. case WSAECONNREFUSED:
  1289. break;
  1290. case WSAEMSGSIZE:
  1291. ConDMsg ("NET_ReceivePacket: %s\n", NET_ErrorString(net_error));
  1292. break;
  1293. default:
  1294. // Let's continue even after errors
  1295. ConDMsg ("NET_ReceivePacket: %s\n", NET_ErrorString(net_error));
  1296. break;
  1297. }
  1298. }
  1299. return false;
  1300. }
  1301. bool NET_ReceiveValidDatagram ( const int sock, netpacket_t * packet )
  1302. {
  1303. #ifdef _DEBUG
  1304. if ( recvpackets.GetInt() >= 0 )
  1305. {
  1306. unsigned long bytes = 0;
  1307. ioctlsocket( net_sockets[ sock ].hUDP , FIONREAD, &bytes );
  1308. if ( bytes <= 0 )
  1309. return false;
  1310. if ( recvpackets.GetInt() == 0 )
  1311. return false;
  1312. recvpackets.SetValue( recvpackets.GetInt() - 1 );
  1313. }
  1314. #endif
  1315. // Failsafe: never call recvfrom more than a fixed number of times per frame.
  1316. // We don't like the potential for infinite loops. Yes this means that 66000
  1317. // invalid packets per frame will effectively DOS the server, but at that point
  1318. // you're basically flooding the network and you need to solve this at a higher
  1319. // firewall or router level instead which is beyond the scope of our netcode.
  1320. // --henryg 10/12/2011
  1321. for ( int i = 1000; i > 0; --i )
  1322. {
  1323. // Attempt to receive a valid packet.
  1324. NET_ClearLastError();
  1325. if ( NET_ReceiveDatagram ( sock, packet ) )
  1326. {
  1327. // Received a valid packet.
  1328. return true;
  1329. }
  1330. // NET_ReceiveDatagram calls Net_GetLastError() in case of socket errors
  1331. // or a would-have-blocked-because-there-is-no-data-to-read condition.
  1332. if ( net_error )
  1333. {
  1334. break;
  1335. }
  1336. }
  1337. return false;
  1338. }
  1339. netpacket_t *NET_GetPacket (int sock, byte *scratch )
  1340. {
  1341. VPROF_BUDGET( "NET_GetPacket", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1342. // Each socket has its own netpacket to allow multithreading
  1343. netpacket_t &inpacket = net_packets[sock];
  1344. NET_AdjustLag();
  1345. NET_DiscardStaleSplitpackets( sock );
  1346. // setup new packet
  1347. inpacket.from.SetType( NA_IP );
  1348. inpacket.from.Clear();
  1349. inpacket.received = net_time;
  1350. inpacket.source = sock;
  1351. inpacket.data = scratch;
  1352. inpacket.size = 0;
  1353. inpacket.wiresize = 0;
  1354. inpacket.pNext = NULL;
  1355. inpacket.message.SetDebugName("inpacket.message");
  1356. // Check loopback first
  1357. if ( !NET_GetLoopPacket( &inpacket ) )
  1358. {
  1359. if ( !NET_IsMultiplayer() )
  1360. {
  1361. return NULL;
  1362. }
  1363. // then check UDP data
  1364. if ( !NET_ReceiveValidDatagram( sock, &inpacket ) )
  1365. {
  1366. // at last check if the lag system has a packet for us
  1367. if ( !NET_LagPacket (false, &inpacket) )
  1368. {
  1369. return NULL; // we don't have any new packet
  1370. }
  1371. }
  1372. }
  1373. Assert ( inpacket.size );
  1374. #ifdef _DEBUG
  1375. if ( fakenoise.GetInt() > 0 )
  1376. {
  1377. COM_AddNoise( inpacket.data, inpacket.size, fakenoise.GetInt() );
  1378. }
  1379. #endif
  1380. // prepare bitbuffer for reading packet with new size
  1381. inpacket.message.StartReading( inpacket.data, inpacket.size );
  1382. return &inpacket;
  1383. }
  1384. void NET_ProcessPending( void )
  1385. {
  1386. AUTO_LOCK( s_PendingSockets );
  1387. for ( int i=0; i<s_PendingSockets.Count();i++ )
  1388. {
  1389. pendingsocket_t * psock = &s_PendingSockets[i];
  1390. ALIGN4 char headerBuf[5] ALIGN4_POST;
  1391. if ( (net_time - psock->time) > TCP_CONNECT_TIMEOUT )
  1392. {
  1393. NET_CloseSocket( psock->newsock );
  1394. s_PendingSockets.Remove( i );
  1395. continue;
  1396. }
  1397. int ret = NET_ReceiveStream( psock->newsock, headerBuf, sizeof(headerBuf), 0 );
  1398. if ( ret == 0 )
  1399. {
  1400. continue; // nothing received
  1401. }
  1402. else if ( ret == -1 )
  1403. {
  1404. NET_CloseSocket( psock->newsock );
  1405. s_PendingSockets.Remove( i );
  1406. continue; // connection closed somehow
  1407. }
  1408. bf_read header( headerBuf, sizeof(headerBuf) );
  1409. int cmd = header.ReadByte();
  1410. unsigned long challengeNr = header.ReadLong();
  1411. bool bOK = false;
  1412. if ( cmd == STREAM_CMD_ACKN )
  1413. {
  1414. AUTO_LOCK( s_NetChannels );
  1415. for ( int j = 0; j < s_NetChannels.Count(); j++ )
  1416. {
  1417. CNetChan * chan = s_NetChannels[j];
  1418. if ( chan->GetSocket() != psock->netsock )
  1419. continue;
  1420. if ( challengeNr == chan->GetChallengeNr() && !chan->m_StreamSocket )
  1421. {
  1422. if ( psock->addr.CompareAdr( chan->remote_address, true ) )
  1423. {
  1424. chan->m_StreamSocket = psock->newsock;
  1425. chan->m_StreamActive = true;
  1426. chan->ResetStreaming();
  1427. bOK = true;
  1428. if ( net_showtcp.GetInt() )
  1429. {
  1430. Msg ("TCP <- %s: connection accepted\n", psock->addr.ToString() );
  1431. }
  1432. break;
  1433. }
  1434. else
  1435. {
  1436. Msg ("TCP <- %s: IP address mismatch.\n", psock->addr.ToString() );
  1437. }
  1438. }
  1439. }
  1440. }
  1441. if ( !bOK )
  1442. {
  1443. Msg ("TCP <- %s: invalid connection request.\n", psock->addr.ToString() );
  1444. NET_CloseSocket( psock->newsock );
  1445. }
  1446. s_PendingSockets.Remove( i );
  1447. }
  1448. }
  1449. void NET_ProcessListen(int sock)
  1450. {
  1451. netsocket_t * netsock = &net_sockets[sock];
  1452. if ( !netsock->bListening )
  1453. return;
  1454. sockaddr sa;
  1455. int nLengthAddr = sizeof(sa);
  1456. int newSocket;
  1457. VCR_NONPLAYBACKFN( accept( netsock->hTCP, &sa, (socklen_t*)&nLengthAddr), newSocket, "accept" );
  1458. #if !defined( NO_VCR )
  1459. VCRGenericValue( "sockaddr", &sa, sizeof( sa ) );
  1460. #endif
  1461. if ( newSocket == -1 )
  1462. {
  1463. NET_GetLastError();
  1464. if ( net_error != WSAEWOULDBLOCK )
  1465. {
  1466. ConDMsg ("NET_ThreadListen: %s\n", NET_ErrorString(net_error));
  1467. }
  1468. return;
  1469. }
  1470. // new connection TCP request, put in pending queue
  1471. pendingsocket_t psock;
  1472. psock.newsock = newSocket;
  1473. psock.netsock = sock;
  1474. psock.addr.SetFromSockadr( &sa );
  1475. psock.time = net_time;
  1476. AUTO_LOCK( s_PendingSockets );
  1477. s_PendingSockets.AddToTail( psock );
  1478. // tell client to send challenge number to identify
  1479. char authcmd = STREAM_CMD_AUTH;
  1480. NET_SendStream( newSocket, &authcmd, 1 , 0 );
  1481. if ( net_showtcp.GetInt() )
  1482. {
  1483. Msg ("TCP <- %s: connection request.\n", psock.addr.ToString() );
  1484. }
  1485. }
  1486. struct NetScratchBuffer_t : TSLNodeBase_t
  1487. {
  1488. byte data[NET_MAX_MESSAGE];
  1489. };
  1490. CTSSimpleList<NetScratchBuffer_t> g_NetScratchBuffers;
  1491. void NET_ProcessSocket( int sock, IConnectionlessPacketHandler *handler )
  1492. {
  1493. VPROF_BUDGET( "NET_ProcessSocket", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1494. netpacket_t * packet;
  1495. Assert ( (sock >= 0) && (sock<net_sockets.Count()) );
  1496. // Scope for the auto_lock
  1497. {
  1498. AUTO_LOCK( s_NetChannels );
  1499. // get streaming data from channel sockets
  1500. int numChannels = s_NetChannels.Count();
  1501. for ( int i = (numChannels-1); i >= 0 ; i-- )
  1502. {
  1503. CNetChan *netchan = s_NetChannels[i];
  1504. // sockets must match
  1505. if ( sock != netchan->GetSocket() )
  1506. continue;
  1507. if ( !netchan->ProcessStream() )
  1508. {
  1509. netchan->GetMsgHandler()->ConnectionCrashed("TCP connection failed.");
  1510. }
  1511. }
  1512. }
  1513. // now get datagrams from sockets
  1514. NetScratchBuffer_t *scratch = g_NetScratchBuffers.Pop();
  1515. if ( !scratch )
  1516. {
  1517. scratch = new NetScratchBuffer_t;
  1518. }
  1519. while ( ( packet = NET_GetPacket ( sock, scratch->data ) ) != NULL )
  1520. {
  1521. if ( Filter_ShouldDiscard ( packet->from ) ) // filtering is done by network layer
  1522. {
  1523. Filter_SendBan( packet->from ); // tell them we aren't listening...
  1524. continue;
  1525. }
  1526. // check for connectionless packet (0xffffffff) first
  1527. if ( LittleLong( *(unsigned int *)packet->data ) == CONNECTIONLESS_HEADER )
  1528. {
  1529. packet->message.ReadLong(); // read the -1
  1530. if ( net_showudp.GetInt() )
  1531. {
  1532. Msg("UDP <- %s: sz=%i OOB '%c' wire=%i\n", packet->from.ToString(), packet->size, packet->data[4], packet->wiresize );
  1533. }
  1534. handler->ProcessConnectionlessPacket( packet );
  1535. continue;
  1536. }
  1537. // check for packets from connected clients
  1538. CNetChan * netchan = NET_FindNetChannel( sock, packet->from );
  1539. if ( netchan )
  1540. {
  1541. netchan->ProcessPacket( packet, true );
  1542. }
  1543. /* else // Not an error that may happen during connect or disconnect
  1544. {
  1545. Msg ("Sequenced packet without connection from %s\n" , packet->from.ToString() );
  1546. }*/
  1547. }
  1548. g_NetScratchBuffers.Push( scratch );
  1549. }
  1550. void NET_LogBadPacket(netpacket_t * packet)
  1551. {
  1552. FileHandle_t fp;
  1553. int i = 0;
  1554. char filename[ MAX_OSPATH ];
  1555. bool done = false;
  1556. while ( i < 1000 && !done )
  1557. {
  1558. Q_snprintf( filename, sizeof( filename ), "badpacket%03i.dat", i );
  1559. fp = g_pFileSystem->Open( filename, "rb" );
  1560. if ( !fp )
  1561. {
  1562. fp = g_pFileSystem->Open( filename, "wb" );
  1563. g_pFileSystem->Write( packet->data, packet->size, fp );
  1564. done = true;
  1565. }
  1566. if ( fp )
  1567. {
  1568. g_pFileSystem->Close( fp );
  1569. }
  1570. i++;
  1571. }
  1572. if ( i < 1000 )
  1573. {
  1574. Msg( "Error buffer for %s written to %s\n", packet->from.ToString(), filename );
  1575. }
  1576. else
  1577. {
  1578. Msg( "Couldn't write error buffer, delete error###.dat files to make space\n" );
  1579. }
  1580. }
  1581. int NET_SendToImpl( SOCKET s, const char FAR * buf, int len, const struct sockaddr FAR * to, int tolen, int iGameDataLength )
  1582. {
  1583. int nSend = 0;
  1584. #if defined( _X360 )
  1585. if ( X360SecureNetwork() )
  1586. {
  1587. // 360 uses VDP protocol to piggyback voice data across the network.
  1588. // Two-byte VDP Header contains the number of game data bytes
  1589. // NOTE: The header bytes *should* be swapped to network endian, however when communicating
  1590. // with XLSP servers (the only cross-platform communication possible with a secure network)
  1591. // the server's network stack swaps the header at the receiving end.
  1592. const int nVDPHeaderBytes = 2;
  1593. Assert( len < (unsigned short)-1 );
  1594. const unsigned short nDataBytes = iGameDataLength == -1 ? len : iGameDataLength;
  1595. WSABUF buffers[2];
  1596. buffers[0].len = nVDPHeaderBytes;
  1597. buffers[0].buf = (char*)&nDataBytes;
  1598. buffers[1].len = len;
  1599. buffers[1].buf = const_cast<char*>( buf );
  1600. WSASendTo( s, buffers, 2, (DWORD*)&nSend, 0, to, tolen, NULL, NULL );
  1601. }
  1602. else
  1603. #endif //defined( _X360 )
  1604. {
  1605. nSend = sendto( s, buf, len, 0, to, tolen );
  1606. }
  1607. return nSend;
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // Purpose:
  1611. // Input : sock -
  1612. // s -
  1613. // buf -
  1614. // len -
  1615. // flags -
  1616. // to -
  1617. // tolen -
  1618. // Output : int
  1619. //-----------------------------------------------------------------------------
  1620. bool CL_IsHL2Demo();
  1621. bool CL_IsPortalDemo();
  1622. int NET_SendTo( bool verbose, SOCKET s, const char FAR * buf, int len, const struct sockaddr FAR * to, int tolen, int iGameDataLength )
  1623. {
  1624. int nSend = 0;
  1625. VPROF_BUDGET( "NET_SendTo", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1626. // If it's 0.0.0.0:0, then it's a fake player + sv_stressbots and we've plumbed everything all
  1627. // the way through here, where we finally bail out.
  1628. sockaddr_in *pInternetAddr = (sockaddr_in*)to;
  1629. #ifdef _WIN32
  1630. if ( pInternetAddr->sin_addr.S_un.S_addr == 0
  1631. #else
  1632. if ( pInternetAddr->sin_addr.s_addr == 0
  1633. #endif
  1634. && pInternetAddr->sin_port == 0 )
  1635. {
  1636. return len;
  1637. }
  1638. // Normally, we shouldn't need to write this data to the file, but it can help catch
  1639. // out-of-sync errors earlier.
  1640. if ( VCRGetMode() != VCR_Disabled && vcr_verbose.GetInt() )
  1641. {
  1642. #if !defined( NO_VCR )
  1643. VCRGenericValue( "senddata", &len, sizeof( len ) );
  1644. VCRGenericValue( "senddata2", (char*)buf, len );
  1645. #endif
  1646. }
  1647. // Don't send anything out in VCR mode.. it just annoys other people testing in multiplayer.
  1648. if ( VCRGetMode() != VCR_Playback )
  1649. {
  1650. #ifndef SWDS
  1651. if ( ( CL_IsHL2Demo() || CL_IsPortalDemo() ) && !net_dedicated )
  1652. {
  1653. Error( " " );
  1654. }
  1655. #endif // _WIN32
  1656. nSend = NET_SendToImpl
  1657. (
  1658. s,
  1659. buf,
  1660. len,
  1661. to,
  1662. tolen,
  1663. iGameDataLength
  1664. );
  1665. }
  1666. #if defined( _DEBUG )
  1667. if ( verbose &&
  1668. ( nSend > 0 ) &&
  1669. ( len > MAX_ROUTABLE_PAYLOAD ) )
  1670. {
  1671. ConDMsg( "NET_SendTo: Packet length (%i) > (%i) bytes\n", len, MAX_ROUTABLE_PAYLOAD );
  1672. }
  1673. #endif
  1674. return nSend;
  1675. }
  1676. #if defined( _DEBUG )
  1677. #include "filesystem.h"
  1678. #include "filesystem_engine.h"
  1679. //-----------------------------------------------------------------------------
  1680. // Purpose:
  1681. // Output : char const
  1682. //-----------------------------------------------------------------------------
  1683. char const *NET_GetDebugFilename( char const *prefix )
  1684. {
  1685. static char filename[ MAX_OSPATH ];
  1686. int i;
  1687. for ( i = 0; i < 10000; i++ )
  1688. {
  1689. Q_snprintf( filename, sizeof( filename ), "debug/%s%04i.dat", prefix, i );
  1690. if ( g_pFileSystem->FileExists( filename ) )
  1691. continue;
  1692. return filename;
  1693. }
  1694. return NULL;
  1695. }
  1696. //-----------------------------------------------------------------------------
  1697. // Purpose:
  1698. // Input : *filename -
  1699. // *buf -
  1700. // len -
  1701. //-----------------------------------------------------------------------------
  1702. void NET_StorePacket( char const *filename, byte const *buf, int len )
  1703. {
  1704. FileHandle_t fh;
  1705. g_pFileSystem->CreateDirHierarchy( "debug/", "DEFAULT_WRITE_PATH" );
  1706. fh = g_pFileSystem->Open( filename, "wb" );
  1707. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1708. {
  1709. g_pFileSystem->Write( buf, len, fh );
  1710. g_pFileSystem->Close( fh );
  1711. }
  1712. }
  1713. #endif // _DEBUG
  1714. struct SendQueueItem_t
  1715. {
  1716. SendQueueItem_t() :
  1717. m_pChannel( NULL ),
  1718. m_Socket( (SOCKET)-1 )
  1719. {
  1720. }
  1721. CNetChan *m_pChannel;
  1722. SOCKET m_Socket;
  1723. CUtlBuffer m_Buffer;
  1724. CUtlBuffer m_To;
  1725. };
  1726. struct SendQueue_t
  1727. {
  1728. SendQueue_t() :
  1729. m_nHostFrame( 0 )
  1730. {
  1731. }
  1732. int m_nHostFrame;
  1733. CUtlLinkedList< SendQueueItem_t > m_SendQueue;
  1734. };
  1735. static SendQueue_t g_SendQueue;
  1736. int NET_QueuePacketForSend( CNetChan *chan, bool verbose, SOCKET s, const char FAR *buf, int len, const struct sockaddr FAR * to, int tolen, uint32 msecDelay )
  1737. {
  1738. // If net_queued_packet_thread was -1 at startup, then we don't even have a thread.
  1739. if ( net_queued_packet_thread.GetInt() && g_pQueuedPackedSender->IsRunning() )
  1740. {
  1741. g_pQueuedPackedSender->QueuePacket( chan, s, buf, len, to, tolen, msecDelay );
  1742. }
  1743. else
  1744. {
  1745. Assert( chan );
  1746. // Set up data structure
  1747. SendQueueItem_t *sq = &g_SendQueue.m_SendQueue[ g_SendQueue.m_SendQueue.AddToTail() ];
  1748. sq->m_Socket = s;
  1749. sq->m_pChannel = chan;
  1750. sq->m_Buffer.Put( (const void *)buf, len );
  1751. sq->m_To.Put( (const void *)to, tolen );
  1752. sq->m_pChannel->IncrementQueuedPackets();
  1753. }
  1754. return len;
  1755. }
  1756. void NET_SendQueuedPacket( SendQueueItem_t *sq )
  1757. {
  1758. // Msg( "Send queued packet %d\n", sq->m_Buffer.TellPut() );
  1759. NET_SendTo
  1760. (
  1761. false,
  1762. sq->m_Socket,
  1763. ( const char FAR * )sq->m_Buffer.Base(),
  1764. sq->m_Buffer.TellPut(),
  1765. ( const struct sockaddr FAR * )sq->m_To.Base(),
  1766. sq->m_To.TellPut() , -1
  1767. );
  1768. sq->m_pChannel->DecrementQueuedPackets();
  1769. }
  1770. void NET_ClearQueuedPacketsForChannel( INetChannel *channel )
  1771. {
  1772. CUtlLinkedList< SendQueueItem_t >& list = g_SendQueue.m_SendQueue;
  1773. for ( unsigned short i = list.Head(); i != list.InvalidIndex(); )
  1774. {
  1775. unsigned short n = list.Next( i );
  1776. SendQueueItem_t &e = list[ i ];
  1777. if ( e.m_pChannel == channel )
  1778. {
  1779. list.Remove( i );
  1780. }
  1781. i = n;
  1782. }
  1783. }
  1784. void NET_SendQueuedPackets()
  1785. {
  1786. // Only do this once per frame
  1787. if ( host_framecount == g_SendQueue.m_nHostFrame )
  1788. return;
  1789. g_SendQueue.m_nHostFrame = host_framecount;
  1790. CUtlLinkedList< SendQueueItem_t >& list = g_SendQueue.m_SendQueue;
  1791. int nRemaining = net_splitrate.GetInt();
  1792. while ( nRemaining )
  1793. {
  1794. if ( list.IsValidIndex( list.Head() ) )
  1795. {
  1796. SendQueueItem_t *sq = &list[ list.Head() ];
  1797. NET_SendQueuedPacket( sq );
  1798. list.Remove( list.Head() );
  1799. --nRemaining;
  1800. }
  1801. else
  1802. {
  1803. break;
  1804. }
  1805. }
  1806. }
  1807. //-----------------------------------------------------------------------------
  1808. // Purpose:
  1809. // Input : sock -
  1810. // s -
  1811. // buf -
  1812. // len -
  1813. // flags -
  1814. // to -
  1815. // tolen -
  1816. // Output : int
  1817. //-----------------------------------------------------------------------------
  1818. static volatile int32 s_SplitPacketSequenceNumber[ MAX_SOCKETS ] = {1};
  1819. static ConVar net_splitpacket_maxrate( "net_splitpacket_maxrate", SPLITPACKET_MAX_DATA_BYTES_PER_SECOND, 0, "Max bytes per second when queueing splitpacket chunks", true, MIN_RATE, true, MAX_RATE );
  1820. int NET_SendLong( INetChannel *chan, int sock, SOCKET s, const char FAR * buf, int len, const struct sockaddr FAR * to, int tolen, int nMaxRoutableSize )
  1821. {
  1822. VPROF_BUDGET( "NET_SendLong", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1823. CNetChan *netchan = dynamic_cast< CNetChan * >( chan );
  1824. short nSplitSizeMinusHeader = nMaxRoutableSize - sizeof( SPLITPACKET );
  1825. int nSequenceNumber = -1;
  1826. if ( netchan )
  1827. {
  1828. nSequenceNumber = netchan->IncrementSplitPacketSequence();
  1829. }
  1830. else
  1831. {
  1832. nSequenceNumber = ThreadInterlockedIncrement( &s_SplitPacketSequenceNumber[ sock ] );
  1833. }
  1834. const char *sendbuf = buf;
  1835. int sendlen = len;
  1836. char packet[ MAX_ROUTABLE_PAYLOAD ];
  1837. SPLITPACKET *pPacket = (SPLITPACKET *)packet;
  1838. // Make pPacket data network endian correct
  1839. pPacket->netID = LittleLong( NET_HEADER_FLAG_SPLITPACKET );
  1840. pPacket->sequenceNumber = LittleLong( nSequenceNumber );
  1841. pPacket->nSplitSize = LittleShort( nSplitSizeMinusHeader );
  1842. int nPacketCount = (sendlen + nSplitSizeMinusHeader - 1) / nSplitSizeMinusHeader;
  1843. #if defined( _DEBUG )
  1844. if ( net_savelargesplits.GetInt() != -1 && nPacketCount >= net_savelargesplits.GetInt() )
  1845. {
  1846. char const *filename = NET_GetDebugFilename( "splitpacket" );
  1847. if ( filename )
  1848. {
  1849. Msg( "Saving split packet of %i bytes and %i packets to file %s\n",
  1850. sendlen, nPacketCount, filename );
  1851. NET_StorePacket( filename, (byte const *)sendbuf, sendlen );
  1852. }
  1853. else
  1854. {
  1855. Msg( "Too many files in debug directory, clear out old data!\n" );
  1856. }
  1857. }
  1858. #endif
  1859. int nBytesLeft = sendlen;
  1860. int nPacketNumber = 0;
  1861. int nTotalBytesSent = 0;
  1862. int nFragmentsSent = 0;
  1863. while ( nBytesLeft > 0 )
  1864. {
  1865. int size = min( (int)nSplitSizeMinusHeader, nBytesLeft );
  1866. pPacket->packetID = LittleShort( (short)(( nPacketNumber << 8 ) + nPacketCount) );
  1867. Q_memcpy( packet + sizeof(SPLITPACKET), sendbuf + (nPacketNumber * nSplitSizeMinusHeader), size );
  1868. int ret = 0;
  1869. // Setting net_queued_packet_thread to NET_QUEUED_PACKET_THREAD_DEBUG_VALUE goes into a mode where all packets are queued.. can be used to stress-test it.
  1870. // Linux threads aren't prioritized well enough for this to work well (i.e. the queued packet thread doesn't get enough
  1871. // attention to flush itself well). The behavior the queue fixes is that if you send too many DP packets
  1872. // without giving up your timeslice, it'll just discard the 7th and later packets until you Sleep() (issue might be on client recipient side, need to
  1873. // snif packets to double check)
  1874. if ( netchan && (nFragmentsSent >= net_splitrate.GetInt() || net_queued_packet_thread.GetInt() == NET_QUEUED_PACKET_THREAD_DEBUG_VALUE) )
  1875. {
  1876. // Don't let this rate get too high (SPLITPACKET_MAX_DATA_BYTES_PER_SECOND == 15000 bytes/sec)
  1877. // or user's won't be able to receive all of the parts since they'll be too close together.
  1878. /// XXX(JohnS): (float)cv.GetInt() is just preserving what this was doing before to avoid changing the
  1879. /// semantics of this convar
  1880. float flMaxSplitpacketDataRateBytesPerSecond = min( (float)netchan->GetDataRate(), (float)net_splitpacket_maxrate.GetInt() );
  1881. // Calculate the delay (measured from now) for when this packet should be sent.
  1882. uint32 delay = (int)( 1000.0f * ( (float)( nPacketNumber * ( nMaxRoutableSize + UDP_HEADER_SIZE ) ) / flMaxSplitpacketDataRateBytesPerSecond ) + 0.5f );
  1883. ret = NET_QueuePacketForSend( netchan, false, s, packet, size + sizeof(SPLITPACKET), to, tolen, delay );
  1884. }
  1885. else
  1886. {
  1887. // Also, we send the first packet no matter what
  1888. // w/o a netchan, if there are too many splits, its possible the packet can't be delivered. However, this would only apply to out of band stuff like
  1889. // server query packets, which should never require splitting anyway.
  1890. ret = NET_SendTo( false, s, packet, size + sizeof(SPLITPACKET), to, tolen, -1 );
  1891. }
  1892. // First split send
  1893. ++nFragmentsSent;
  1894. if ( ret < 0 )
  1895. {
  1896. return ret;
  1897. }
  1898. if ( ret >= size )
  1899. {
  1900. nTotalBytesSent += size;
  1901. }
  1902. nBytesLeft -= size;
  1903. ++nPacketNumber;
  1904. // Always bitch about split packets in debug
  1905. if ( net_showsplits.GetInt() && net_showsplits.GetInt() != 2 )
  1906. {
  1907. netadr_t adr;
  1908. adr.SetFromSockadr( (struct sockaddr*)to );
  1909. Msg( "--> [%s] Split packet %4i/%4i seq %5i size %4i mtu %4i to %s [ total %4i ]\n",
  1910. DescribeSocket( sock ),
  1911. nPacketNumber,
  1912. nPacketCount,
  1913. nSequenceNumber,
  1914. size,
  1915. nMaxRoutableSize,
  1916. adr.ToString(),
  1917. sendlen );
  1918. }
  1919. }
  1920. return nTotalBytesSent;
  1921. }
  1922. //-----------------------------------------------------------------------------
  1923. // Purpose:
  1924. // Input : sock -
  1925. // length -
  1926. // *data -
  1927. // to -
  1928. // Output : void NET_SendPacket
  1929. //-----------------------------------------------------------------------------
  1930. int NET_SendPacket ( INetChannel *chan, int sock, const netadr_t &to, const unsigned char *data, int length, bf_write *pVoicePayload /* = NULL */, bool bUseCompression /*=false*/ )
  1931. {
  1932. VPROF_BUDGET( "NET_SendPacket", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1933. ETWSendPacket( to.ToString() , length , 0 , 0 );
  1934. int ret;
  1935. struct sockaddr addr;
  1936. int net_socket;
  1937. if ( net_showudp.GetInt() && (*(unsigned int*)data == CONNECTIONLESS_HEADER) )
  1938. {
  1939. Assert( !bUseCompression );
  1940. Msg("UDP -> %s: sz=%i OOB '%c'\n", to.ToString(), length, data[4] );
  1941. }
  1942. if ( !NET_IsMultiplayer() || to.type == NA_LOOPBACK || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
  1943. {
  1944. Assert( !pVoicePayload );
  1945. NET_SendLoopPacket (sock, length, data, to);
  1946. return length;
  1947. }
  1948. if ( to.type == NA_BROADCAST )
  1949. {
  1950. net_socket = net_sockets[sock].hUDP;
  1951. if (!net_socket)
  1952. return length;
  1953. }
  1954. else if ( to.type == NA_IP )
  1955. {
  1956. net_socket = net_sockets[sock].hUDP;
  1957. if (!net_socket)
  1958. return length;
  1959. }
  1960. else
  1961. {
  1962. DevMsg("NET_SendPacket: bad address type (%i)\n", to.type );
  1963. return length;
  1964. }
  1965. if ( (droppackets.GetInt() < 0) && sock == NS_CLIENT )
  1966. {
  1967. droppackets.SetValue( droppackets.GetInt() + 1 );
  1968. return length;
  1969. }
  1970. if ( fakeloss.GetFloat() > 0.0f )
  1971. {
  1972. // simulate sending this packet
  1973. if (RandomInt(0,100) <= (int)fakeloss.GetFloat())
  1974. return length;
  1975. }
  1976. to.ToSockadr ( &addr );
  1977. MEM_ALLOC_CREDIT();
  1978. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memCompressed( NET_COMPRESSION_STACKBUF_SIZE );
  1979. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memCompressedVoice( NET_COMPRESSION_STACKBUF_SIZE );
  1980. int iGameDataLength = pVoicePayload ? length : -1;
  1981. bool bWroteVoice = false;
  1982. unsigned int nVoiceBytes = 0;
  1983. if ( pVoicePayload )
  1984. {
  1985. VPROF_BUDGET( "NET_SendPacket_CompressVoice", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  1986. unsigned int nCompressedLength = COM_GetIdealDestinationCompressionBufferSize_Snappy( pVoicePayload->GetNumBytesWritten() );
  1987. memCompressedVoice.EnsureCapacity( nCompressedLength + sizeof( unsigned short ) );
  1988. byte *pVoice = (byte *)memCompressedVoice.Base();
  1989. unsigned short usVoiceBits = pVoicePayload->GetNumBitsWritten();
  1990. *( unsigned short * )pVoice = LittleShort( usVoiceBits );
  1991. pVoice += sizeof( unsigned short );
  1992. byte *pOutput = NULL;
  1993. if ( net_compressvoice.GetBool() )
  1994. {
  1995. if ( COM_BufferToBufferCompress_Snappy( pVoice, &nCompressedLength, pVoicePayload->GetData(), pVoicePayload->GetNumBytesWritten()
  1996. && ( (int)nCompressedLength < pVoicePayload->GetNumBytesWritten() ) ) )
  1997. {
  1998. pOutput = pVoice;
  1999. }
  2000. }
  2001. if ( !pOutput )
  2002. {
  2003. Q_memcpy( pVoice, pVoicePayload->GetData(), pVoicePayload->GetNumBytesWritten() );
  2004. }
  2005. nVoiceBytes = nCompressedLength + sizeof( unsigned short );
  2006. }
  2007. if ( bUseCompression )
  2008. {
  2009. VPROF_BUDGET( "NET_SendPacket_Compress", VPROF_BUDGETGROUP_OTHER_NETWORKING );
  2010. unsigned int nCompressedLength = COM_GetIdealDestinationCompressionBufferSize_Snappy( length );
  2011. memCompressed.EnsureCapacity( nCompressedLength + nVoiceBytes + sizeof( unsigned int ) );
  2012. *(int *)memCompressed.Base() = LittleLong( NET_HEADER_FLAG_COMPRESSEDPACKET );
  2013. if ( COM_BufferToBufferCompress_Snappy( memCompressed.Base() + sizeof( unsigned int ), &nCompressedLength, data, length )
  2014. && (int)nCompressedLength < length )
  2015. {
  2016. data = memCompressed.Base();
  2017. length = nCompressedLength + sizeof( unsigned int );
  2018. if ( pVoicePayload && pVoicePayload->GetNumBitsWritten() > 0 )
  2019. {
  2020. byte *pVoice = (byte *)memCompressed.Base() + length;
  2021. Q_memcpy( pVoice, memCompressedVoice.Base(), nVoiceBytes );
  2022. }
  2023. iGameDataLength = length;
  2024. length += nVoiceBytes;
  2025. bWroteVoice = true;
  2026. }
  2027. }
  2028. if ( !bWroteVoice && pVoicePayload && pVoicePayload->GetNumBitsWritten() > 0 )
  2029. {
  2030. memCompressed.EnsureCapacity( length + nVoiceBytes );
  2031. byte *pVoice = (byte *)memCompressed.Base();
  2032. Q_memcpy( pVoice, (const void *)data, length );
  2033. pVoice += length;
  2034. Q_memcpy( pVoice, memCompressedVoice.Base(), nVoiceBytes );
  2035. data = memCompressed.Base();
  2036. length += nVoiceBytes;
  2037. }
  2038. // Do we need to break this packet up?
  2039. int nMaxRoutable = MAX_ROUTABLE_PAYLOAD;
  2040. if ( chan )
  2041. {
  2042. nMaxRoutable = clamp( chan->GetMaxRoutablePayloadSize(), MIN_USER_MAXROUTABLE_SIZE, min( sv_maxroutable.GetInt(), MAX_USER_MAXROUTABLE_SIZE ) );
  2043. }
  2044. if ( length <= nMaxRoutable &&
  2045. !(net_queued_packet_thread.GetInt() == NET_QUEUED_PACKET_THREAD_DEBUG_VALUE && chan ) )
  2046. {
  2047. // simple case, small packet, just send it
  2048. ret = NET_SendTo( true, net_socket, (const char *)data, length, &addr, sizeof(addr), iGameDataLength );
  2049. }
  2050. else
  2051. {
  2052. // split packet into smaller pieces
  2053. ret = NET_SendLong( chan, sock, net_socket, (const char *)data, length, &addr, sizeof(addr), nMaxRoutable );
  2054. }
  2055. if (ret == -1)
  2056. {
  2057. NET_GetLastError();
  2058. // wouldblock is silent
  2059. if ( net_error == WSAEWOULDBLOCK )
  2060. return 0;
  2061. if ( net_error == WSAECONNRESET )
  2062. return 0;
  2063. // some PPP links dont allow broadcasts
  2064. if ( ( net_error == WSAEADDRNOTAVAIL) && ( to.type == NA_BROADCAST ) )
  2065. return 0;
  2066. ConDMsg ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(net_error), to.ToString() );
  2067. ret = length;
  2068. }
  2069. return ret;
  2070. }
  2071. void NET_OutOfBandPrintf(int sock, const netadr_t &adr, const char *format, ...)
  2072. {
  2073. va_list argptr;
  2074. char string[MAX_ROUTABLE_PAYLOAD];
  2075. *(unsigned int*)string = CONNECTIONLESS_HEADER;
  2076. va_start (argptr, format);
  2077. Q_vsnprintf (string+4, sizeof( string ) - 4, format,argptr);
  2078. va_end (argptr);
  2079. int length = Q_strlen(string+4) + 5;
  2080. NET_SendPacket ( NULL, sock, adr, (byte *)string, length );
  2081. }
  2082. /*
  2083. ====================
  2084. NET_CloseAllSockets
  2085. ====================
  2086. */
  2087. void NET_CloseAllSockets (void)
  2088. {
  2089. // shut down any existing and open sockets
  2090. for (int i=0 ; i<net_sockets.Count() ; i++)
  2091. {
  2092. if ( net_sockets[i].nPort )
  2093. {
  2094. NET_CloseSocket( net_sockets[i].hUDP );
  2095. NET_CloseSocket( net_sockets[i].hTCP );
  2096. net_sockets[i].nPort = 0;
  2097. net_sockets[i].bListening = false;
  2098. net_sockets[i].hUDP = 0;
  2099. net_sockets[i].hTCP = 0;
  2100. }
  2101. }
  2102. // shut down all pending sockets
  2103. AUTO_LOCK( s_PendingSockets );
  2104. for(int j=0; j<s_PendingSockets.Count();j++ )
  2105. {
  2106. NET_CloseSocket( s_PendingSockets[j].newsock );
  2107. }
  2108. s_PendingSockets.RemoveAll();
  2109. }
  2110. /*
  2111. ====================
  2112. NET_FlushAllSockets
  2113. ====================
  2114. */
  2115. void NET_FlushAllSockets( void )
  2116. {
  2117. // drain any packets that my still lurk in our incoming queue
  2118. char data[2048];
  2119. struct sockaddr from;
  2120. int fromlen = sizeof(from);
  2121. for (int i=0 ; i<net_sockets.Count() ; i++)
  2122. {
  2123. if ( net_sockets[i].hUDP )
  2124. {
  2125. int bytes = 1;
  2126. // loop until no packets are pending anymore
  2127. while ( bytes > 0 )
  2128. {
  2129. bytes = VCRHook_recvfrom( net_sockets[i].hUDP, data, sizeof(data), 0, (struct sockaddr *)&from, (int *)&fromlen );
  2130. }
  2131. }
  2132. }
  2133. }
  2134. enum
  2135. {
  2136. OSOCKET_FLAG_USE_IPNAME = 0x00000001, // Use ipname convar for net_interface.
  2137. OSOCKET_FLAG_FAIL = 0x00000002, // Call Sys_exit on error.
  2138. };
  2139. static bool OpenSocketInternal( int nModule, int nSetPort, int nDefaultPort, const char *pName, int nProtocol, bool bTryAny,
  2140. int flags = ( OSOCKET_FLAG_USE_IPNAME | OSOCKET_FLAG_FAIL ) )
  2141. {
  2142. int port = nSetPort ? nSetPort : nDefaultPort;
  2143. int *handle = NULL;
  2144. if( nProtocol == IPPROTO_TCP )
  2145. {
  2146. handle = &net_sockets[nModule].hTCP;
  2147. }
  2148. else if ( nProtocol == IPPROTO_UDP || nProtocol == IPPROTO_VDP )
  2149. {
  2150. handle = &net_sockets[nModule].hUDP;
  2151. }
  2152. else
  2153. {
  2154. Sys_Error( "Unrecognized protocol type %d", nProtocol );
  2155. return false;
  2156. }
  2157. if ( !net_sockets[nModule].nPort )
  2158. {
  2159. const char *netinterface = ( flags & OSOCKET_FLAG_USE_IPNAME ) ? ipname.GetString() : NULL;
  2160. *handle = NET_OpenSocket (netinterface, port, nProtocol );
  2161. if ( !*handle && bTryAny )
  2162. {
  2163. port = PORT_ANY; // try again with PORT_ANY
  2164. *handle = NET_OpenSocket ( netinterface, port, nProtocol );
  2165. }
  2166. if ( !*handle )
  2167. {
  2168. if ( flags & OSOCKET_FLAG_FAIL )
  2169. Sys_Exit( "Couldn't allocate any %s IP port", pName );
  2170. return false;
  2171. }
  2172. net_sockets[nModule].nPort = port;
  2173. }
  2174. else
  2175. {
  2176. Msg( "WARNING: NET_OpenSockets: %s port %i already open.\n", pName, net_sockets[nModule].nPort );
  2177. return false;
  2178. }
  2179. return ( net_sockets[nModule].nPort != 0 );
  2180. }
  2181. /*
  2182. ====================
  2183. NET_OpenSockets
  2184. ====================
  2185. */
  2186. void NET_OpenSockets (void)
  2187. {
  2188. // Xbox 360 uses VDP protocol to combine encrypted game data with clear voice data
  2189. const int nProtocol = X360SecureNetwork() ? IPPROTO_VDP : IPPROTO_UDP;
  2190. OpenSocketInternal( NS_SERVER, hostport.GetInt(), PORT_SERVER, "server", nProtocol, false );
  2191. OpenSocketInternal( NS_CLIENT, clientport.GetInt(), PORT_SERVER, "client", nProtocol, true );
  2192. if ( !net_nohltv )
  2193. {
  2194. OpenSocketInternal( NS_HLTV, hltvport.GetInt(), PORT_HLTV, "hltv", nProtocol, false );
  2195. }
  2196. if ( IsX360() )
  2197. {
  2198. OpenSocketInternal( NS_MATCHMAKING, matchmakingport.GetInt(), PORT_MATCHMAKING, "matchmaking", nProtocol, false );
  2199. OpenSocketInternal( NS_SYSTEMLINK, systemlinkport.GetInt(), PORT_SYSTEMLINK, "systemlink", IPPROTO_UDP, false );
  2200. }
  2201. #ifdef LINUX
  2202. // On Linux, if you bind to a specific address then you will NOT receive broadcast messages.
  2203. // This means that if you do a +ip X.X.X.X, your game will not show up on the LAN server browser page.
  2204. // To workaround this, if the user has specified sv_lan and an IP address, we open an INADDR_ANY port.
  2205. // See http://developerweb.net/viewtopic.php?id=5722 for more information.
  2206. extern ConVar sv_lan;
  2207. if ( sv_lan.GetBool() )
  2208. {
  2209. const char *net_interface = ipname.GetString();
  2210. // If net_interface was specified and it's not localhost...
  2211. if ( net_interface[ 0 ] && ( Q_strcmp( net_interface, "localhost" ) != 0 ) )
  2212. {
  2213. // From clientdll/matchmaking/ServerList.cpp, the ports queried are:
  2214. // 27015 - 27020, 26900 - 26905
  2215. // 4242: RDKF, 27215: Lost Planet
  2216. static int s_ports[] =
  2217. {
  2218. 26900, 26901, 26902, 26903, 26904, 26905,
  2219. 27015, 27016, 27017, 27018, 27019, 27020
  2220. };
  2221. for ( size_t iport = 0; iport < ARRAYSIZE( s_ports ); iport++ )
  2222. {
  2223. bool bPortUsed = false;
  2224. for ( int i = NS_CLIENT; i < NS_SVLAN; i++ )
  2225. {
  2226. // Move along if this port is already used.
  2227. if ( net_sockets[ i ].nPort == s_ports[ iport ] )
  2228. {
  2229. bPortUsed = true;
  2230. break;
  2231. }
  2232. }
  2233. if ( !bPortUsed )
  2234. {
  2235. // Try to open the socket and break if we succeeded.
  2236. if ( OpenSocketInternal( NS_SVLAN, s_ports[ iport ], PORT_SERVER, "lan", nProtocol, false, 0 ) )
  2237. break;
  2238. }
  2239. }
  2240. if ( net_sockets[ NS_SVLAN ].nPort )
  2241. Msg( "Opened sv_lan port %d\n", net_sockets[ NS_SVLAN ].nPort );
  2242. else
  2243. Warning( "%s, Failed to open sv_lan port.\n", __FUNCTION__ );
  2244. }
  2245. }
  2246. #endif // LINUX
  2247. }
  2248. int NET_AddExtraSocket( int port )
  2249. {
  2250. int newSocket = net_sockets.AddToTail();
  2251. Q_memset( &net_sockets[newSocket], 0, sizeof(netsocket_t) );
  2252. OpenSocketInternal( newSocket, port, PORT_ANY, "extra", IPPROTO_UDP, true );
  2253. net_packets.EnsureCount( newSocket+1 );
  2254. net_splitpackets.EnsureCount( newSocket+1 );
  2255. return newSocket;
  2256. }
  2257. void NET_RemoveAllExtraSockets()
  2258. {
  2259. for (int i=MAX_SOCKETS ; i<net_sockets.Count() ; i++)
  2260. {
  2261. if ( net_sockets[i].nPort )
  2262. {
  2263. NET_CloseSocket( net_sockets[i].hUDP );
  2264. NET_CloseSocket( net_sockets[i].hTCP );
  2265. }
  2266. }
  2267. net_sockets.RemoveMultiple( MAX_SOCKETS, net_sockets.Count()-MAX_SOCKETS );
  2268. Assert( net_sockets.Count() == MAX_SOCKETS );
  2269. }
  2270. unsigned short NET_GetUDPPort(int socket)
  2271. {
  2272. if ( socket < 0 || socket >= net_sockets.Count() )
  2273. return 0;
  2274. return net_sockets[socket].nPort;
  2275. }
  2276. /*
  2277. ================
  2278. NET_GetLocalAddress
  2279. Returns the servers' ip address as a string.
  2280. ================
  2281. */
  2282. void NET_GetLocalAddress (void)
  2283. {
  2284. net_local_adr.Clear();
  2285. if ( net_noip )
  2286. {
  2287. Msg("TCP/UDP Disabled.\n");
  2288. }
  2289. else
  2290. {
  2291. char buff[512];
  2292. // If we have changed the ip var from the command line, use that instead.
  2293. if ( Q_strcmp(ipname.GetString(), "localhost") )
  2294. {
  2295. Q_strncpy(buff, ipname.GetString(), sizeof( buff ) ); // use IP set with ipname
  2296. }
  2297. else
  2298. {
  2299. gethostname( buff, sizeof(buff) ); // get own IP address
  2300. buff[sizeof(buff)-1] = 0; // Ensure that it doesn't overrun the buffer
  2301. }
  2302. NET_StringToAdr (buff, &net_local_adr);
  2303. int ipaddr = ( net_local_adr.ip[0] << 24 ) +
  2304. ( net_local_adr.ip[1] << 16 ) +
  2305. ( net_local_adr.ip[2] << 8 ) +
  2306. net_local_adr.ip[3];
  2307. hostip.SetValue( ipaddr );
  2308. }
  2309. }
  2310. /*
  2311. ====================
  2312. NET_IsConfigured
  2313. Is winsock ip initialized?
  2314. ====================
  2315. */
  2316. bool NET_IsMultiplayer( void )
  2317. {
  2318. return net_multiplayer;
  2319. }
  2320. bool NET_IsDedicated( void )
  2321. {
  2322. return net_dedicated;
  2323. }
  2324. #ifdef _X360
  2325. #include "iengine.h"
  2326. static FileHandle_t g_fh;
  2327. void NET_LogServerStatus( void )
  2328. {
  2329. if ( !g_fh )
  2330. return;
  2331. static float fNextTime = 0.f;
  2332. float fCurrentTime = eng->GetCurTime();
  2333. if ( fCurrentTime >= fNextTime )
  2334. {
  2335. fNextTime = fCurrentTime + net_loginterval.GetFloat();
  2336. }
  2337. else
  2338. {
  2339. return;
  2340. }
  2341. AUTO_LOCK( s_NetChannels );
  2342. int numChannels = s_NetChannels.Count();
  2343. if ( numChannels == 0 )
  2344. {
  2345. ConMsg( "No active net channels.\n" );
  2346. return;
  2347. }
  2348. enum
  2349. {
  2350. NET_LATENCY,
  2351. NET_LOSS,
  2352. NET_PACKETS_IN,
  2353. NET_PACKETS_OUT,
  2354. NET_CHOKE_IN,
  2355. NET_CHOKE_OUT,
  2356. NET_FLOW_IN,
  2357. NET_FLOW_OUT,
  2358. NET_TOTAL_IN,
  2359. NET_TOTAL_OUT,
  2360. NET_LAST,
  2361. };
  2362. float fStats[NET_LAST] = {0.f};
  2363. for ( int i = 0; i < numChannels; ++i )
  2364. {
  2365. INetChannel *chan = s_NetChannels[i];
  2366. fStats[NET_LATENCY] += chan->GetAvgLatency(FLOW_OUTGOING);
  2367. fStats[NET_LOSS] += chan->GetAvgLoss(FLOW_INCOMING);
  2368. fStats[NET_PACKETS_IN] += chan->GetAvgPackets(FLOW_INCOMING);
  2369. fStats[NET_PACKETS_OUT] += chan->GetAvgPackets(FLOW_OUTGOING);
  2370. fStats[NET_CHOKE_IN] += chan->GetAvgChoke(FLOW_INCOMING);
  2371. fStats[NET_CHOKE_OUT] += chan->GetAvgChoke(FLOW_OUTGOING);
  2372. fStats[NET_FLOW_IN] += chan->GetAvgData(FLOW_INCOMING);
  2373. fStats[NET_FLOW_OUT] += chan->GetAvgData(FLOW_OUTGOING);
  2374. fStats[NET_TOTAL_IN] += chan->GetTotalData(FLOW_INCOMING);
  2375. fStats[NET_TOTAL_OUT] += chan->GetTotalData(FLOW_OUTGOING);
  2376. }
  2377. for ( int i = 0; i < NET_LAST; ++i )
  2378. {
  2379. fStats[i] /= numChannels;
  2380. }
  2381. const unsigned int size = 128;
  2382. char msg[size];
  2383. Q_snprintf( msg, size, "%.0f,%d,%.0f,%.0f,%.0f,%.1f,%.1f,%.1f,%.1f,%.1f\n",
  2384. fCurrentTime,
  2385. numChannels,
  2386. fStats[NET_LATENCY],
  2387. fStats[NET_LOSS],
  2388. fStats[NET_PACKETS_IN],
  2389. fStats[NET_PACKETS_OUT],
  2390. fStats[NET_FLOW_IN]/1024.0f,
  2391. fStats[NET_FLOW_OUT]/1024.0f,
  2392. fStats[NET_CHOKE_IN],
  2393. fStats[NET_CHOKE_OUT]
  2394. );
  2395. g_pFileSystem->Write( msg, Q_strlen( msg ), g_fh );
  2396. }
  2397. void NET_LogServerCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
  2398. {
  2399. ConVarRef var( pConVar );
  2400. if ( var.GetBool() )
  2401. {
  2402. if ( g_fh )
  2403. {
  2404. g_pFileSystem->Close( g_fh );
  2405. g_fh = 0;
  2406. }
  2407. g_fh = g_pFileSystem->Open( "dump.csv", "wt" );
  2408. if ( !g_fh )
  2409. {
  2410. Msg( "Failed to open log file\n" );
  2411. pConVar->SetValue( 0 );
  2412. return;
  2413. }
  2414. char msg[128];
  2415. Q_snprintf( msg, 128, "Time,Channels,Latency,Loss,Packets In,Packets Out,Flow In(kB/s),Flow Out(kB/s),Choke In,Choke Out\n" );
  2416. g_pFileSystem->Write( msg, Q_strlen( msg ), g_fh );
  2417. }
  2418. else
  2419. {
  2420. if ( g_fh )
  2421. {
  2422. g_pFileSystem->Close( g_fh );
  2423. g_fh = 0;
  2424. }
  2425. }
  2426. }
  2427. #endif
  2428. /*
  2429. ====================
  2430. NET_SetTime
  2431. Updates net_time
  2432. ====================
  2433. */
  2434. void NET_SetTime( double flRealtime )
  2435. {
  2436. static double s_last_realtime = 0;
  2437. double frametime = flRealtime - s_last_realtime;
  2438. s_last_realtime = flRealtime;
  2439. if ( frametime > 1.0f )
  2440. {
  2441. // if we have very long frame times because of loading stuff
  2442. // don't apply that to net time to avoid unwanted timeouts
  2443. frametime = 1.0f;
  2444. }
  2445. else if ( frametime < 0.0f )
  2446. {
  2447. frametime = 0.0f;
  2448. }
  2449. // adjust network time so fakelag works with host_timescale
  2450. net_time += frametime * host_timescale.GetFloat();
  2451. }
  2452. /*
  2453. ====================
  2454. NET_RunFrame
  2455. RunFrame must be called each system frame before reading/sending on any socket
  2456. ====================
  2457. */
  2458. void NET_RunFrame( double flRealtime )
  2459. {
  2460. NET_SetTime( flRealtime );
  2461. RCONServer().RunFrame();
  2462. #ifdef ENABLE_RPT
  2463. RPTServer().RunFrame();
  2464. #endif // ENABLE_RPT
  2465. #ifndef SWDS
  2466. RCONClient().RunFrame();
  2467. #ifdef ENABLE_RPT
  2468. RPTClient().RunFrame();
  2469. #endif // ENABLE_RPT
  2470. #endif // SWDS
  2471. #ifdef _X360
  2472. if ( net_logserver.GetInt() )
  2473. {
  2474. NET_LogServerStatus();
  2475. }
  2476. g_pMatchmaking->RunFrame();
  2477. #endif
  2478. if ( !NET_IsMultiplayer() || net_notcp )
  2479. return;
  2480. // process TCP sockets:
  2481. for ( int i=0; i< net_sockets.Count(); i++ )
  2482. {
  2483. if ( net_sockets[i].hTCP && net_sockets[i].bListening )
  2484. {
  2485. NET_ProcessListen( i );
  2486. }
  2487. }
  2488. NET_ProcessPending();
  2489. }
  2490. void NET_ClearLoopbackBuffers()
  2491. {
  2492. for (int i = 0; i < LOOPBACK_SOCKETS; i++)
  2493. {
  2494. loopback_t *loop;
  2495. while ( s_LoopBacks[i].PopItem( &loop ) )
  2496. {
  2497. if ( loop->data && loop->data != loop->defbuffer )
  2498. {
  2499. delete [] loop->data;
  2500. }
  2501. delete loop;
  2502. }
  2503. }
  2504. }
  2505. void NET_ConfigLoopbackBuffers( bool bAlloc )
  2506. {
  2507. NET_ClearLoopbackBuffers();
  2508. }
  2509. /*
  2510. ====================
  2511. NET_Config
  2512. A single player game will only use the loopback code
  2513. ====================
  2514. */
  2515. void NET_Config ( void )
  2516. {
  2517. // free anything
  2518. NET_CloseAllSockets(); // close all UDP/TCP sockets
  2519. net_time = 0.0f;
  2520. // now reconfiguare
  2521. if ( net_multiplayer )
  2522. {
  2523. // don't allocate loopback buffers
  2524. NET_ConfigLoopbackBuffers( false );
  2525. // get localhost IP address
  2526. NET_GetLocalAddress();
  2527. // reopen sockets if in MP mode
  2528. NET_OpenSockets();
  2529. // setup the rcon server sockets
  2530. if ( net_dedicated || CommandLine()->FindParm( "-usercon" ) )
  2531. {
  2532. netadr_t rconAddr = net_local_adr;
  2533. rconAddr.SetPort( net_sockets[NS_SERVER].nPort );
  2534. RCONServer().SetAddress( rconAddr.ToString() );
  2535. RCONServer().CreateSocket();
  2536. }
  2537. }
  2538. else
  2539. {
  2540. // allocate loopback buffers
  2541. NET_ConfigLoopbackBuffers( true );
  2542. }
  2543. Msg( "Network: IP %s, mode %s, dedicated %s, ports %i SV / %i CL\n",
  2544. net_local_adr.ToString(true), net_multiplayer?"MP":"SP", net_dedicated?"Yes":"No",
  2545. net_sockets[NS_SERVER].nPort, net_sockets[NS_CLIENT].nPort );
  2546. }
  2547. /*
  2548. ====================
  2549. NET_SetDedicated
  2550. A single player game will only use the loopback code
  2551. ====================
  2552. */
  2553. void NET_SetDedicated ()
  2554. {
  2555. if ( net_noip )
  2556. {
  2557. Msg( "Warning! Dedicated not possible with -noip parameter.\n");
  2558. return;
  2559. }
  2560. net_dedicated = true;
  2561. }
  2562. void NET_ListenSocket( int sock, bool bListen )
  2563. {
  2564. Assert( (sock >= 0) && (sock < net_sockets.Count()) );
  2565. netsocket_t * netsock = &net_sockets[sock];
  2566. if ( netsock->hTCP )
  2567. {
  2568. NET_CloseSocket( netsock->hTCP, sock );
  2569. }
  2570. if ( !NET_IsMultiplayer() || net_notcp )
  2571. return;
  2572. if ( bListen )
  2573. {
  2574. const char * net_interface = ipname.GetString();
  2575. netsock->hTCP = NET_OpenSocket( net_interface, netsock->nPort, true );
  2576. if ( !netsock->hTCP )
  2577. {
  2578. Msg( "Warning! NET_ListenSocket failed opening socket %i, port %i.\n", sock, net_sockets[sock].nPort );
  2579. return;
  2580. }
  2581. struct sockaddr_in address;
  2582. if (!net_interface || !net_interface[0] || !Q_strcmp(net_interface, "localhost"))
  2583. {
  2584. address.sin_addr.s_addr = INADDR_ANY;
  2585. }
  2586. else
  2587. {
  2588. NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  2589. }
  2590. address.sin_family = AF_INET;
  2591. address.sin_port = NET_HostToNetShort((short)( netsock->nPort ));
  2592. int ret;
  2593. VCR_NONPLAYBACKFN( bind( netsock->hTCP, (struct sockaddr *)&address, sizeof(address)), ret, "bind" );
  2594. if ( ret == -1 )
  2595. {
  2596. NET_GetLastError();
  2597. Msg ("WARNING: NET_ListenSocket bind failed on socket %i, port %i.\n", netsock->hTCP, netsock->nPort );
  2598. return;
  2599. }
  2600. VCR_NONPLAYBACKFN( listen( netsock->hTCP, TCP_MAX_ACCEPTS), ret, "listen" );
  2601. if ( ret == -1 )
  2602. {
  2603. NET_GetLastError();
  2604. Msg ("WARNING: NET_ListenSocket listen failed on socket %i, port %i.\n", netsock->hTCP, netsock->nPort );
  2605. return;
  2606. }
  2607. netsock->bListening = true;
  2608. }
  2609. }
  2610. void NET_SetMutiplayer(bool multiplayer)
  2611. {
  2612. if ( net_noip && multiplayer )
  2613. {
  2614. Msg( "Warning! Multiplayer mode not available with -noip parameter.\n");
  2615. return;
  2616. }
  2617. if ( net_dedicated && !multiplayer )
  2618. {
  2619. Msg( "Warning! Singleplayer mode not available on dedicated server.\n");
  2620. return;
  2621. }
  2622. // reconfigure if changed
  2623. if ( net_multiplayer != multiplayer )
  2624. {
  2625. net_multiplayer = multiplayer;
  2626. NET_Config();
  2627. }
  2628. // clear loopback buffer in single player mode
  2629. if ( !multiplayer )
  2630. {
  2631. NET_ClearLoopbackBuffers();
  2632. }
  2633. }
  2634. //-----------------------------------------------------------------------------
  2635. // Purpose:
  2636. // Input : bIsDedicated -
  2637. //-----------------------------------------------------------------------------
  2638. void NET_Init( bool bIsDedicated )
  2639. {
  2640. if ( CommandLine()->FindParm( "-NoQueuedPacketThread" ) )
  2641. Warning( "Found -NoQueuedPacketThread, so no queued packet thread will be created.\n" );
  2642. else
  2643. g_pQueuedPackedSender->Setup();
  2644. if (CommandLine()->FindParm("-nodns"))
  2645. {
  2646. net_nodns = true;
  2647. }
  2648. if (CommandLine()->FindParm("-usetcp"))
  2649. {
  2650. net_notcp = false;
  2651. }
  2652. if (CommandLine()->FindParm("-nohltv"))
  2653. {
  2654. net_nohltv = true;
  2655. }
  2656. if (CommandLine()->FindParm("-noip"))
  2657. {
  2658. net_noip = true;
  2659. }
  2660. else
  2661. {
  2662. #if defined(_WIN32)
  2663. #if defined(_X360)
  2664. XNetStartupParams xnsp;
  2665. memset( &xnsp, 0, sizeof( xnsp ) );
  2666. xnsp.cfgSizeOfStruct = sizeof( XNetStartupParams );
  2667. if ( X360SecureNetwork() )
  2668. {
  2669. Msg( "Xbox 360 network is Secure\n" );
  2670. }
  2671. else
  2672. {
  2673. // Allow cross-platform communication
  2674. xnsp.cfgFlags = XNET_STARTUP_BYPASS_SECURITY;
  2675. Msg( "Xbox 360 network is Unsecure\n" );
  2676. }
  2677. INT err = XNetStartup( &xnsp );
  2678. if ( err )
  2679. {
  2680. ConMsg( "Error! Failed to set XNET Security Bypass.\n");
  2681. }
  2682. err = XOnlineStartup();
  2683. if ( err != ERROR_SUCCESS )
  2684. {
  2685. ConMsg( "Error! XOnlineStartup failed.\n");
  2686. }
  2687. #else
  2688. // initialize winsock 2.0
  2689. WSAData wsaData;
  2690. if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )
  2691. {
  2692. ConMsg( "Error! Failed to load network socket library.\n");
  2693. net_noip = true;
  2694. }
  2695. #endif // _X360
  2696. #endif // _WIN32
  2697. }
  2698. COMPILE_TIME_ASSERT( SVC_LASTMSG < (1<<NETMSG_TYPE_BITS) );
  2699. COMPILE_TIME_ASSERT( MAX_FILE_SIZE < (1<<MAX_FILE_SIZE_BITS) );
  2700. net_time = 0.0f;
  2701. int hPort = CommandLine()->ParmValue( "-port", -1 );
  2702. if ( hPort == -1 )
  2703. {
  2704. hPort = CommandLine()->ParmValue( "+port", -1 ); // check if they used +port by mistake
  2705. }
  2706. if ( hPort != -1 )
  2707. {
  2708. hostport.SetValue( hPort );
  2709. }
  2710. // clear static stuff
  2711. net_sockets.EnsureCount( MAX_SOCKETS );
  2712. net_packets.EnsureCount( MAX_SOCKETS );
  2713. net_splitpackets.EnsureCount( MAX_SOCKETS );
  2714. for ( int i = 0; i < MAX_SOCKETS; ++i )
  2715. {
  2716. s_pLagData[i] = NULL;
  2717. Q_memset( &net_sockets[i], 0, sizeof(netsocket_t) );
  2718. }
  2719. const char *ip = CommandLine()->ParmValue( "-ip" );
  2720. if ( ip ) // if they had a command line option for IP
  2721. {
  2722. ipname.SetValue( ip ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  2723. }
  2724. if ( bIsDedicated )
  2725. {
  2726. // set dedicated MP mode
  2727. NET_SetDedicated();
  2728. }
  2729. else
  2730. {
  2731. // set SP mode
  2732. NET_ConfigLoopbackBuffers( true );
  2733. }
  2734. }
  2735. /*
  2736. ====================
  2737. NET_Shutdown
  2738. ====================
  2739. */
  2740. void NET_Shutdown (void)
  2741. {
  2742. int nError = 0;
  2743. for (int i = 0; i < MAX_SOCKETS; i++)
  2744. {
  2745. NET_ClearLaggedList( &s_pLagData[i] );
  2746. }
  2747. g_pQueuedPackedSender->Shutdown();
  2748. net_multiplayer = false;
  2749. net_dedicated = false;
  2750. NET_CloseAllSockets();
  2751. NET_ConfigLoopbackBuffers( false );
  2752. #if defined(_WIN32)
  2753. if ( !net_noip )
  2754. {
  2755. nError = WSACleanup();
  2756. if ( nError )
  2757. {
  2758. Msg("Failed to complete WSACleanup = 0x%x.\n", nError );
  2759. }
  2760. #if defined(_X360)
  2761. nError = XOnlineCleanup();
  2762. if ( nError != ERROR_SUCCESS )
  2763. {
  2764. Msg( "Warning! Failed to complete XOnlineCleanup = 0x%x.\n", nError );
  2765. }
  2766. #endif // _X360
  2767. }
  2768. #endif // _WIN32
  2769. Assert( s_NetChannels.Count() == 0 );
  2770. Assert( s_PendingSockets.Count() == 0);
  2771. }
  2772. void NET_PrintChannelStatus( INetChannel * chan )
  2773. {
  2774. Msg( "NetChannel '%s':\n", chan->GetName() );
  2775. Msg( "- remote IP: %s %s\n", chan->GetAddress(), chan->IsPlayback()?"(Demo)":"" );
  2776. Msg( "- online: %s\n", COM_FormatSeconds( chan->GetTimeConnected() ) );
  2777. Msg( "- reliable: %s\n", chan->HasPendingReliableData()?"pending data":"available" );
  2778. Msg( "- latency: %.1f, loss %.2f\n", chan->GetAvgLatency(FLOW_OUTGOING), chan->GetAvgLoss(FLOW_INCOMING) );
  2779. Msg( "- packets: in %.1f/s, out %.1f/s\n", chan->GetAvgPackets(FLOW_INCOMING), chan->GetAvgPackets(FLOW_OUTGOING) );
  2780. Msg( "- choke: in %.2f, out %.2f\n", chan->GetAvgChoke(FLOW_INCOMING), chan->GetAvgChoke(FLOW_OUTGOING) );
  2781. Msg( "- flow: in %.1f, out %.1f kB/s\n", chan->GetAvgData(FLOW_INCOMING)/1024.0f, chan->GetAvgData(FLOW_OUTGOING)/1024.0f );
  2782. Msg( "- total: in %.1f, out %.1f MB\n\n", (float)chan->GetTotalData(FLOW_INCOMING)/(1024*1024), (float)chan->GetTotalData(FLOW_OUTGOING)/(1024*1024) );
  2783. }
  2784. CON_COMMAND( net_channels, "Shows net channel info" )
  2785. {
  2786. int numChannels = s_NetChannels.Count();
  2787. if ( numChannels == 0 )
  2788. {
  2789. ConMsg( "No active net channels.\n" );
  2790. return;
  2791. }
  2792. AUTO_LOCK( s_NetChannels );
  2793. for ( int i = 0; i < numChannels; i++ )
  2794. {
  2795. NET_PrintChannelStatus( s_NetChannels[i] );
  2796. }
  2797. }
  2798. CON_COMMAND( net_start, "Inits multiplayer network sockets" )
  2799. {
  2800. net_multiplayer = true;
  2801. NET_Config();
  2802. }
  2803. CON_COMMAND( net_status, "Shows current network status" )
  2804. {
  2805. AUTO_LOCK( s_NetChannels );
  2806. int numChannels = s_NetChannels.Count();
  2807. ConMsg("Net status for host %s:\n",
  2808. net_local_adr.ToString(true) );
  2809. ConMsg("- Config: %s, %s, %i connections\n",
  2810. net_multiplayer?"Multiplayer":"Singleplayer",
  2811. net_dedicated?"dedicated":"listen",
  2812. numChannels );
  2813. CFmtStrN<128> lan_str;
  2814. #ifdef LINUX
  2815. lan_str.sprintf( ", Lan %u", net_sockets[NS_SVLAN].nPort );
  2816. #endif
  2817. ConMsg("- Ports: Client %u, Server %u, HLTV %u, Matchmaking %u, Systemlink %u%s\n",
  2818. net_sockets[NS_CLIENT].nPort,
  2819. net_sockets[NS_SERVER].nPort,
  2820. net_sockets[NS_HLTV].nPort,
  2821. net_sockets[NS_MATCHMAKING].nPort,
  2822. net_sockets[NS_SYSTEMLINK].nPort,
  2823. lan_str.Get() );
  2824. if ( numChannels <= 0 )
  2825. {
  2826. return;
  2827. }
  2828. // gather statistics:
  2829. float avgLatencyOut = 0;
  2830. float avgLatencyIn = 0;
  2831. float avgPacketsOut = 0;
  2832. float avgPacketsIn = 0;
  2833. float avgLossOut = 0;
  2834. float avgLossIn = 0;
  2835. float avgDataOut = 0;
  2836. float avgDataIn = 0;
  2837. for ( int i = 0; i < numChannels; i++ )
  2838. {
  2839. CNetChan *chan = s_NetChannels[i];
  2840. avgLatencyOut += chan->GetAvgLatency(FLOW_OUTGOING);
  2841. avgLatencyIn += chan->GetAvgLatency(FLOW_INCOMING);
  2842. avgLossIn += chan->GetAvgLoss(FLOW_INCOMING);
  2843. avgLossOut += chan->GetAvgLoss(FLOW_OUTGOING);
  2844. avgPacketsIn += chan->GetAvgPackets(FLOW_INCOMING);
  2845. avgPacketsOut += chan->GetAvgPackets(FLOW_OUTGOING);
  2846. avgDataIn += chan->GetAvgData(FLOW_INCOMING);
  2847. avgDataOut += chan->GetAvgData(FLOW_OUTGOING);
  2848. }
  2849. ConMsg( "- Latency: avg out %.2fs, in %.2fs\n", avgLatencyOut/numChannels, avgLatencyIn/numChannels );
  2850. ConMsg( "- Loss: avg out %.1f, in %.1f\n", avgLossOut/numChannels, avgLossIn/numChannels );
  2851. ConMsg( "- Packets: net total out %.1f/s, in %.1f/s\n", avgPacketsOut, avgPacketsIn );
  2852. ConMsg( " per client out %.1f/s, in %.1f/s\n", avgPacketsOut/numChannels, avgPacketsIn/numChannels );
  2853. ConMsg( "- Data: net total out %.1f, in %.1f kB/s\n", avgDataOut/1024.0f, avgDataIn/1024.0f );
  2854. ConMsg( " per client out %.1f, in %.1f kB/s\n", (avgDataOut/numChannels)/1024.0f, (avgDataIn/numChannels)/1024.0f );
  2855. }