Counter Strike : Global Offensive Source Code
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.

5160 lines
140 KiB

  1. //========= Copyright 1996-2005, 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/vprof.h"
  11. #include "net_ws_headers.h"
  12. #include "net_ws_queued_packet_sender.h"
  13. #include "tier1/lzss.h"
  14. #include "tier1/tokenset.h"
  15. #include "matchmaking/imatchframework.h"
  16. #include "tier2/tier2.h"
  17. #include "ienginetoolinternal.h"
  18. #include "server.h"
  19. #include "mathlib/IceKey.H"
  20. #include "steamdatagram/isteamdatagramclient.h"
  21. #include "steamdatagram/isteamdatagramserver.h"
  22. #include "steamdatagram/isteamnetworkingutils.h"
  23. #include "engine/inetsupport.h"
  24. #if !defined( _X360 ) && !defined( NO_STEAM )
  25. #include "sv_steamauth.h"
  26. #endif
  27. #ifndef DEDICATED
  28. #include "cl_steamauth.h"
  29. #endif
  30. #ifdef _PS3
  31. #include <cell/sysmodule.h>
  32. #endif
  33. // memdbgon must be the last include file in a .cpp file!!!
  34. #include "tier0/memdbgon.h"
  35. #define NET_COMPRESSION_STACKBUF_SIZE 4096
  36. static ConVar net_showsplits( "net_showsplits", "0", FCVAR_RELEASE, "Show info about packet splits" );
  37. static ConVar net_splitrate( "net_splitrate", "1", FCVAR_RELEASE, "Number of fragments for a splitpacket that can be sent per frame" );
  38. static ConVar ipname ( "ip", "localhost", FCVAR_RELEASE, "Overrides IP for multihomed hosts" );
  39. static ConVar ipname_tv ( "ip_tv", "", FCVAR_RELEASE, "Overrides IP used to bind TV port for multihomed hosts" );
  40. static ConVar ipname_tv1 ( "ip_tv1", "", FCVAR_RELEASE, "Overrides IP used to bind TV1 port for multihomed hosts" );
  41. static ConVar ipname_relay ( "ip_relay", "", FCVAR_RELEASE, "Overrides IP used to redirect TV relay connections for NAT hosts" );
  42. static ConVar ipname_steam ( "ip_steam", "", FCVAR_RELEASE, "Overrides IP used to bind Steam port for multihomed hosts" );
  43. static ConVar hostport ( "hostport", NETSTRING( PORT_SERVER ) , FCVAR_RELEASE, "Host game server port" );
  44. static ConVar hostip ( "hostip", "", FCVAR_RELEASE, "Host game server ip" );
  45. static ConVar net_public_adr( "net_public_adr", "", FCVAR_RELEASE, "For servers behind NAT/DHCP meant to be exposed to the public internet, this is the public facing ip address string: (\"x.x.x.x\" )" );
  46. static ConVar clientport ( "clientport", NETSTRING( PORT_CLIENT ), FCVAR_RELEASE, "Host game client port" );
  47. static ConVar hltvport ( "tv_port", NETSTRING( PORT_HLTV ), FCVAR_RELEASE, "Host GOTV[0] port" );
  48. static ConVar hltvport1 ( "tv_port1", NETSTRING( PORT_HLTV1 ), FCVAR_RELEASE, "Host GOTV[1] port" );
  49. #if defined( REPLAY_ENABLED )
  50. static ConVar replayport ( "replay_port", va("%i",PORT_REPLAY), 0, "Host Replay port" );
  51. #endif
  52. static ConVar fakelag ( "net_fakelag", "0", FCVAR_CHEAT, "Lag all incoming network data (including loopback) by this many milliseconds." );
  53. static ConVar fakeloss ( "net_fakeloss", "0", FCVAR_CHEAT, "Simulate packet loss as a percentage (negative means drop 1/n packets)" );
  54. static ConVar droppackets ( "net_droppackets", "0", FCVAR_CHEAT, "Drops next n packets on client" );
  55. static ConVar fakejitter ( "net_fakejitter", "0", FCVAR_CHEAT, "Jitter fakelag packet time" );
  56. static ConVar net_compressvoice( "net_compressvoice", "0", 0, "Attempt to compress out of band voice payloads (360 only)." );
  57. ConVar net_usesocketsforloopback( "net_usesocketsforloopback", "0",
  58. #ifdef _DEBUG
  59. FCVAR_RELEASE
  60. #else
  61. 0
  62. #endif
  63. , "Use network sockets layer even for listen server local player's packets (multiplayer only)." );
  64. static ConVar voice_verbose( "voice_verbose", "0", FCVAR_DEVELOPMENTONLY, "Turns on debug output with detailed spew about voice data processing." );
  65. static ConVar voice_xsend_debug( "voice_xsend_debug", "0" );
  66. #ifdef _DEBUG
  67. static ConVar fakenoise ( "net_fakenoise", "0", FCVAR_CHEAT, "Simulate corrupt network packets (changes n bits per packet randomly)" );
  68. static ConVar fakeshuffle ( "net_fakeshuffle", "0", FCVAR_CHEAT, "Shuffles order of every nth packet (needs net_fakelag)" );
  69. static ConVar recvpackets ( "net_recvpackets", "-1", FCVAR_CHEAT, "Receive exactly next n packets if >= 0" );
  70. 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." );
  71. #endif
  72. #ifdef _X360
  73. static void NET_LogServerCallback( IConVar *var, const char *pOldString, float flOldValue );
  74. static ConVar net_logserver( "net_logserver", "0", 0, "Dump server stats to a file", NET_LogServerCallback );
  75. static ConVar net_loginterval( "net_loginterval", "1", 0, "Time in seconds between server logs" );
  76. #endif
  77. static ConVar sv_steamdatagramtransport_port( "sv_steamdatagramtransport_port", "", FCVAR_RELEASE, "If non zero, listen for proxied traffic on the specified port" );
  78. //-----------------------------------------------------------------------------
  79. // Toggle Xbox 360 network security to allow cross-platform testing
  80. //-----------------------------------------------------------------------------
  81. #if !defined( _X360 )
  82. #define X360SecureNetwork() false
  83. #define IPPROTO_VDP IPPROTO_UDP
  84. #elif defined( _CERT )
  85. #define X360SecureNetwork() true
  86. #else
  87. bool X360SecureNetwork( void )
  88. {
  89. if ( CommandLine()->FindParm( "-xnet_bypass_security" ) )
  90. {
  91. return false;
  92. }
  93. return true;
  94. }
  95. #endif
  96. extern ConVar net_showudp;
  97. extern ConVar net_showudp_oob;
  98. extern ConVar net_showudp_remoteonly;
  99. extern ConVar net_showtcp;
  100. extern ConVar net_blocksize;
  101. extern int host_framecount;
  102. extern bool ShouldChecksumPackets();
  103. extern unsigned short BufferToShortChecksum( const void *pvData, size_t nLength );
  104. extern void NET_InitParanoidMode();
  105. void NET_ClearQueuedPacketsForChannel( INetChannel *chan );
  106. #define DEF_LOOPBACK_SIZE 2048
  107. typedef struct
  108. {
  109. int nPort; // UDP/TCP use same port number
  110. bool bListening; // true if TCP port is listening
  111. int hUDP; // handle to UDP socket from socket()
  112. int hTCP; // handle to TCP socket from socket()
  113. } netsocket_t;
  114. typedef struct
  115. {
  116. int newsock; // handle of new socket
  117. int netsock; // handle of listen socket
  118. float time;
  119. netadr_t addr;
  120. } pendingsocket_t;
  121. #include "tier0/memdbgoff.h"
  122. struct loopback_t
  123. {
  124. char *data; // loopback buffer
  125. int datalen; // current data length
  126. char defbuffer[ DEF_LOOPBACK_SIZE ];
  127. DECLARE_FIXEDSIZE_ALLOCATOR( loopback_t );
  128. };
  129. #include "tier0/memdbgon.h"
  130. DEFINE_FIXEDSIZE_ALLOCATOR( loopback_t, 2, CUtlMemoryPool::GROW_SLOW );
  131. // Split long packets. Anything over 1460 is failing on some routers
  132. typedef struct
  133. {
  134. int currentSequence;
  135. int splitCount;
  136. int totalSize;
  137. int nExpectedSplitSize;
  138. char buffer[ NET_MAX_MESSAGE ]; // This has to be big enough to hold the largest message
  139. } LONGPACKET;
  140. // Use this to pick apart the network stream, must be packed
  141. #pragma pack(1)
  142. typedef struct
  143. {
  144. int netID;
  145. int sequenceNumber;
  146. int packetID : 16;
  147. int nSplitSize : 16;
  148. } SPLITPACKET;
  149. #pragma pack()
  150. #define MIN_USER_MAXROUTABLE_SIZE 576 // ( X.25 Networks )
  151. #define MAX_USER_MAXROUTABLE_SIZE MAX_ROUTABLE_PAYLOAD
  152. #define MAX_SPLIT_SIZE (MAX_USER_MAXROUTABLE_SIZE - sizeof( SPLITPACKET ))
  153. #define MIN_SPLIT_SIZE (MIN_USER_MAXROUTABLE_SIZE - sizeof( SPLITPACKET ))
  154. static ConVar sv_maxroutable
  155. (
  156. "sv_maxroutable",
  157. "1200",
  158. 0,
  159. "Server upper bound on net_maxroutable that a client can use.",
  160. true, MIN_USER_MAXROUTABLE_SIZE,
  161. true, MAX_USER_MAXROUTABLE_SIZE
  162. );
  163. ConVar net_maxroutable
  164. (
  165. "net_maxroutable",
  166. "1200",
  167. FCVAR_ARCHIVE | FCVAR_USERINFO,
  168. "Requested max packet size before packets are 'split'.",
  169. true, MIN_USER_MAXROUTABLE_SIZE,
  170. true, MAX_USER_MAXROUTABLE_SIZE
  171. );
  172. netadr_t net_local_adr;
  173. double net_time = 0.0f; // current time, updated each frame
  174. static CUtlVector<netsocket_t> net_sockets; // the sockets
  175. static CUtlVector<netpacket_t> net_packets;
  176. static bool net_multiplayer = false; // if true, configured for Multiplayer
  177. static bool net_noip = false; // Disable IP support, can't switch to MP mode
  178. static bool net_nodns = false; // Disable DNS request to avoid long timeouts
  179. bool net_notcp = true; // Disable TCP support
  180. static bool net_nohltv = false; // disable HLTV support
  181. static bool net_addhltv1 = false; // by default, HLTV1 (sup)port is disabled. Must be enabled explicitly with -addhltv1 cmdline parameter
  182. #if defined( REPLAY_ENABLED )
  183. static bool net_noreplay = false; // disable Replay support
  184. #endif
  185. static bool net_dedicated = false; // true is dedicated system
  186. static bool net_dedicatedForXbox = false; // true is dedicated system serving xbox
  187. static bool net_dedicatedForXboxInsecure = false; // true if dedicated system serving insecure xbox
  188. static int net_error = 0; // global error code updated with NET_GetLastError()
  189. static int g_nFakeSocketHandle = 0; // for when we are only using Steam. Need a fake socket handle.
  190. volatile int g_NetChannelsRefreshCounter = 0;
  191. static CUtlVectorMT< CUtlVector< CNetChan* > > s_NetChannels;
  192. static CUtlVectorMT< CUtlVector< pendingsocket_t > > s_PendingSockets;
  193. CTSQueue<loopback_t *> s_LoopBacks[LOOPBACK_SOCKETS];
  194. static netpacket_t* s_pLagData[MAX_SOCKETS]; // List of lag structures, if fakelag is set.
  195. ISteamDatagramTransportGameserver *g_pSteamDatagramGameserver = nullptr;
  196. ISteamDatagramTransportClient *g_pSteamDatagramClient = nullptr;
  197. ns_address g_addrSteamDatagramProxiedGameServer;
  198. static void CloseSteamDatagramClientConnection()
  199. {
  200. if ( g_pSteamDatagramClient )
  201. {
  202. g_pSteamDatagramClient->Close();
  203. g_pSteamDatagramClient = nullptr;
  204. }
  205. g_addrSteamDatagramProxiedGameServer.Clear();
  206. }
  207. unsigned short NET_HostToNetShort( unsigned short us_in )
  208. {
  209. return htons( us_in );
  210. }
  211. unsigned short NET_NetToHostShort( unsigned short us_in )
  212. {
  213. return ntohs( us_in );
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. // Input : *s -
  218. // *sadr -
  219. // Output : bool NET_StringToSockaddr
  220. //-----------------------------------------------------------------------------
  221. bool NET_StringToSockaddr( const char *s, struct sockaddr *sadr )
  222. {
  223. char *colon;
  224. char copy[128];
  225. Q_memset (sadr, 0, sizeof(*sadr));
  226. ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
  227. ((struct sockaddr_in *)sadr)->sin_port = 0;
  228. Q_strncpy (copy, s, sizeof( copy ) );
  229. // strip off a trailing :port if present
  230. for (colon = copy ; *colon ; colon++)
  231. {
  232. if (*colon == ':')
  233. {
  234. *colon = 0;
  235. ((struct sockaddr_in *)sadr)->sin_port = NET_HostToNetShort((short)atoi(colon+1));
  236. }
  237. }
  238. if (copy[0] >= '0' && copy[0] <= '9' && Q_strstr( copy, "." ) )
  239. {
  240. *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
  241. }
  242. else
  243. {
  244. if ( net_nodns )
  245. return false; // DNS names disabled
  246. struct hostent *h;
  247. if ( (h = gethostbyname(copy)) == NULL )
  248. return false;
  249. *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
  250. }
  251. return true;
  252. }
  253. int NET_GetLastError( void )
  254. {
  255. #if defined( _WIN32 )
  256. net_error = WSAGetLastError();
  257. #else
  258. net_error = errno;
  259. #endif
  260. return net_error;
  261. }
  262. /*
  263. ==================
  264. NET_ClearLaggedList
  265. ==================
  266. */
  267. void NET_ClearLaggedList(netpacket_t **pList)
  268. {
  269. netpacket_t * p = (*pList);
  270. while ( p )
  271. {
  272. netpacket_t * n = p->pNext;
  273. if ( p->data )
  274. {
  275. delete[] p->data;
  276. p->data = NULL;
  277. }
  278. delete p;
  279. p = n;
  280. }
  281. (*pList) = NULL;
  282. }
  283. void NET_ClearLagData( int sock )
  284. {
  285. if ( sock < MAX_SOCKETS && s_pLagData[sock] )
  286. {
  287. NET_ClearLaggedList( &s_pLagData[sock] );
  288. }
  289. }
  290. /*
  291. =============
  292. NET_StringToAdr
  293. localhost
  294. idnewt
  295. idnewt:28000
  296. 192.246.40.70
  297. 192.246.40.70:28000
  298. =============
  299. */
  300. bool NET_StringToAdr ( const char *s, netadr_t *a)
  301. {
  302. return a->SetFromString( s, !net_nodns );
  303. }
  304. void NET_FindAllNetChannelAddresses( int socket, CUtlVector< struct sockaddr > &arrNetChans )
  305. {
  306. AUTO_LOCK_FM( s_NetChannels );
  307. int numChannels = s_NetChannels.Count();
  308. for ( int i = 0; i < numChannels; i++ )
  309. {
  310. CNetChan * chan = s_NetChannels[ i ];
  311. // sockets must match
  312. if ( socket != chan->GetSocket() )
  313. continue;
  314. // only ip based ones
  315. if ( chan->GetRemoteAddress().m_AddrType != NSAT_NETADR )
  316. {
  317. continue;
  318. }
  319. // and the IP:Port address
  320. struct sockaddr sockAddress;
  321. chan->GetRemoteAddress().m_adr.ToSockadr( &sockAddress );
  322. arrNetChans.AddToTail( sockAddress );
  323. }
  324. }
  325. CNetChan *NET_FindNetChannel(int socket, const ns_address &adr )
  326. {
  327. AUTO_LOCK_FM( s_NetChannels );
  328. int numChannels = s_NetChannels.Count();
  329. for ( int i = 0; i < numChannels; i++ )
  330. {
  331. CNetChan * chan = s_NetChannels[i];
  332. // sockets must match
  333. if ( socket != chan->GetSocket() )
  334. continue;
  335. // and the address
  336. if ( adr == chan->GetRemoteAddress() )
  337. {
  338. return chan; // found it
  339. }
  340. }
  341. return NULL; // no channel found
  342. }
  343. void NET_CloseSocket( int hSocket, int sock = -1)
  344. {
  345. if ( !hSocket )
  346. return;
  347. // close socket handle
  348. if ( !OnlyUseSteamSockets() )
  349. {
  350. // bugbug - shouldn't this clear net_sockets[sock].hUDP?
  351. int ret = closesocket( hSocket );
  352. if ( ret == -1 )
  353. {
  354. NET_GetLastError();
  355. ConMsg ("WARNING! NET_CloseSocket: %s\n", NET_ErrorString(net_error));
  356. }
  357. // if hSocket mapped to hTCP, clear hTCP
  358. if ( sock >= 0 )
  359. {
  360. if ( net_sockets[sock].hTCP == hSocket )
  361. {
  362. net_sockets[sock].hTCP = 0;
  363. net_sockets[sock].bListening = false;
  364. }
  365. }
  366. // If closing client socket, make sure we don't keep trying
  367. // to talk to server
  368. if ( sock == NS_CLIENT )
  369. {
  370. CloseSteamDatagramClientConnection();
  371. }
  372. }
  373. g_pSteamSocketMgr->CloseSocket( hSocket, sock );
  374. }
  375. /*
  376. ====================
  377. NET_IPSocket
  378. ====================
  379. */
  380. int NET_OpenSocket ( const char *net_interface, int& port, int protocol )
  381. {
  382. if ( OnlyUseSteamSockets() )
  383. {
  384. Msg ("WARNING: NET_OpenSocket: Not implemented - Should be using Steam\n");
  385. return 0;
  386. }
  387. struct sockaddr_in address;
  388. unsigned int opt;
  389. int newsocket = -1;
  390. if ( protocol == IPPROTO_TCP )
  391. {
  392. newsocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
  393. }
  394. else // as UDP or VDP
  395. {
  396. newsocket = socket( PF_INET, SOCK_DGRAM, protocol );
  397. }
  398. if ( newsocket == -1 )
  399. {
  400. NET_GetLastError();
  401. if ( net_error != WSAEAFNOSUPPORT )
  402. Msg ("WARNING: NET_OpenSocket: socket failed: %s", NET_ErrorString(net_error));
  403. return 0;
  404. }
  405. opt = 1; // make it non-blocking
  406. int ret = ioctlsocket( newsocket, FIONBIO, (unsigned long*)&opt );
  407. if ( ret == -1 )
  408. {
  409. NET_GetLastError();
  410. Msg ("WARNING: NET_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString(net_error) );
  411. }
  412. if ( protocol == IPPROTO_TCP )
  413. {
  414. if ( !IsX360() ) // SO_KEEPALIVE unsupported on the 360
  415. {
  416. opt = 1; // set TCP options: keep TCP connection alive
  417. ret = setsockopt( newsocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, sizeof(opt) );
  418. if (ret == -1)
  419. {
  420. NET_GetLastError();
  421. Msg ("WARNING: NET_OpenSocket: setsockopt SO_KEEPALIVE: %s\n", NET_ErrorString(net_error));
  422. return 0;
  423. }
  424. }
  425. linger optlinger; // set TCP options: Does not block close waiting for unsent data to be sent
  426. optlinger.l_linger = 0;
  427. optlinger.l_onoff = 0;
  428. ret = setsockopt( newsocket, SOL_SOCKET, SO_LINGER, (char *)&optlinger, sizeof(optlinger) );
  429. if (ret == -1)
  430. {
  431. NET_GetLastError();
  432. Msg ("WARNING: NET_OpenSocket: setsockopt SO_LINGER: %s\n", NET_ErrorString(net_error));
  433. return 0;
  434. }
  435. opt = 1; // set TCP options: Disables the Nagle algorithm for send coalescing.
  436. ret = setsockopt( newsocket, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt) );
  437. if (ret == -1)
  438. {
  439. NET_GetLastError();
  440. Msg ("WARNING: NET_OpenSocket: setsockopt TCP_NODELAY: %s\n", NET_ErrorString(net_error));
  441. return 0;
  442. }
  443. }
  444. // Set the send and receive buffer sizes for TCP sockets, and UDP sockets on Windows. Windows UDP
  445. // sockets default to 8 KB buffers which makes dataloss very common. Linux (Ubuntu 12.04 anyway)
  446. // UDP sockets default to 208 KB so there is no need to change the setting.
  447. // Use net_usesocketsforloopback 1 to use sockets for listen servers for testing.
  448. if ( protocol == IPPROTO_TCP || IsPlatformWindowsPC() )
  449. {
  450. const int UDP_BUFFER_SIZE = 128 * 1024; // Better than 8 KB.
  451. const int bufferSize = ( protocol == IPPROTO_TCP ) ? NET_MAX_MESSAGE : UDP_BUFFER_SIZE;
  452. opt = bufferSize;
  453. ret = setsockopt( newsocket, SOL_SOCKET, SO_SNDBUF, (char *)&opt, sizeof(opt) );
  454. if (ret == -1)
  455. {
  456. NET_GetLastError();
  457. Msg ("WARNING: NET_OpenSocket: setsockopt SO_SNDBUF: %s\n", NET_ErrorString(net_error));
  458. return 0;
  459. }
  460. opt = bufferSize;
  461. ret = setsockopt( newsocket, SOL_SOCKET, SO_RCVBUF, (char *)&opt, sizeof(opt) );
  462. if (ret == -1)
  463. {
  464. NET_GetLastError();
  465. Msg ("WARNING: NET_OpenSocket: setsockopt SO_RCVBUF: %s\n", NET_ErrorString(net_error));
  466. return 0;
  467. }
  468. }
  469. if ( protocol == IPPROTO_TCP )
  470. {
  471. return newsocket; // don't bind TCP sockets by default
  472. }
  473. // rest is UDP only
  474. // VDP protocol (Xbox 360 secure network) doesn't support SO_BROADCAST
  475. if ( !IsX360() || protocol != IPPROTO_VDP )
  476. {
  477. opt = 1; // set UDP options: make it broadcast capable
  478. ret = setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt) );
  479. if (ret == -1)
  480. {
  481. NET_GetLastError();
  482. Msg ("WARNING: NET_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString(net_error));
  483. return 0;
  484. }
  485. }
  486. if ( CommandLine()->FindParm( "-reuse" ) )
  487. {
  488. opt = 1; // make it reusable
  489. ret = setsockopt( newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt) );
  490. if (ret == -1)
  491. {
  492. NET_GetLastError();
  493. Msg ("WARNING: NET_OpenSocket: setsockopt SO_REUSEADDR: %s\n", NET_ErrorString(net_error));
  494. return 0;
  495. }
  496. }
  497. if (!net_interface || !net_interface[0] || !Q_strcmp(net_interface, "localhost"))
  498. {
  499. address.sin_addr.s_addr = INADDR_ANY;
  500. }
  501. else
  502. {
  503. NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  504. }
  505. address.sin_family = AF_INET;
  506. int port_offset; // try binding socket to port, try next 10 is port is already used
  507. int nNumTries = PORT_TRY_MAX;
  508. if ( IsChildProcess() )
  509. nNumTries = PORT_TRY_MAX_FORKED;
  510. // Add support for "+net_port_try" argument to override on command line
  511. int nCommandLineOverrideNumTries = nNumTries;
  512. nCommandLineOverrideNumTries = CommandLine()->ParmValue( "+net_port_try", nCommandLineOverrideNumTries );
  513. nCommandLineOverrideNumTries = CommandLine()->ParmValue( "-net_port_try", nCommandLineOverrideNumTries );
  514. if ( ( nCommandLineOverrideNumTries > 0 ) && ( nCommandLineOverrideNumTries < nNumTries ) )
  515. nNumTries = nCommandLineOverrideNumTries;
  516. for ( port_offset = 0; port_offset < nNumTries; port_offset++ )
  517. {
  518. if ( port == PORT_ANY )
  519. {
  520. address.sin_port = 0; // = INADDR_ANY
  521. }
  522. else
  523. {
  524. address.sin_port = NET_HostToNetShort((short)( port + port_offset ));
  525. }
  526. ret = bind( newsocket, (struct sockaddr *)&address, sizeof(address) );
  527. if ( ret != -1 )
  528. {
  529. if ( port != PORT_ANY && port_offset != 0 )
  530. {
  531. port += port_offset; // update port
  532. ConDMsg( "Socket bound to non-default port %i because original port was already in use.\n", port );
  533. }
  534. break;
  535. }
  536. NET_GetLastError();
  537. if ( port == PORT_ANY || net_error != WSAEADDRINUSE )
  538. {
  539. Msg ("WARNING: NET_OpenSocket: bind: %s\n", NET_ErrorString(net_error));
  540. NET_CloseSocket(newsocket,-1);
  541. return 0;
  542. }
  543. // Try next port
  544. }
  545. if ( port_offset == nNumTries )
  546. {
  547. Msg( "WARNING: UDP_OpenSocket: unable to bind socket\n" );
  548. NET_CloseSocket( newsocket,-1 );
  549. return 0;
  550. }
  551. return newsocket;
  552. }
  553. int NET_ConnectSocket( int sock, const netadr_t &addr )
  554. {
  555. Assert( (sock >= 0) && (sock < net_sockets.Count()) );
  556. netsocket_t *netsock = &net_sockets[sock];
  557. if ( netsock->hTCP )
  558. {
  559. NET_CloseSocket( netsock->hTCP, sock );
  560. }
  561. if ( net_notcp )
  562. return 0;
  563. sockaddr saddr;
  564. addr.ToSockadr( &saddr );
  565. int anyport = PORT_ANY;
  566. netsock->hTCP = NET_OpenSocket( ipname.GetString(), anyport, true );
  567. if ( !netsock->hTCP )
  568. {
  569. Msg( "Warning! NET_ConnectSocket failed opening socket %i, port %i.\n", sock, net_sockets[sock].nPort );
  570. return false;
  571. }
  572. int ret;
  573. ret = connect( netsock->hTCP, &saddr, sizeof(saddr) );
  574. if ( ret == -1 )
  575. {
  576. NET_GetLastError();
  577. if ( net_error != WSAEWOULDBLOCK )
  578. {
  579. Msg ("NET_ConnectSocket: %s\n", NET_ErrorString( net_error ) );
  580. return 0;
  581. }
  582. }
  583. return net_sockets[sock].hTCP;
  584. }
  585. int NET_SendStream( int nSock, const char * buf, int len, int flags )
  586. {
  587. if ( OnlyUseSteamSockets() )
  588. {
  589. Msg( "Warning! NET_SendStream called when only using Steam sockets\n" );
  590. return 0;
  591. }
  592. //int ret = send( nSock, buf, len, flags );
  593. int ret = send( nSock, buf, len, flags );
  594. if ( ret == -1 )
  595. {
  596. NET_GetLastError();
  597. if ( net_error == WSAEWOULDBLOCK )
  598. {
  599. return 0; // ignore EWOULDBLOCK
  600. }
  601. Msg ("NET_SendStream: %s\n", NET_ErrorString( net_error ) );
  602. }
  603. return ret;
  604. }
  605. int NET_ReceiveStream( int nSock, char * buf, int len, int flags )
  606. {
  607. if ( OnlyUseSteamSockets() )
  608. {
  609. Msg( "Warning! NET_ReceiveStream called when only using Steam sockets\n" );
  610. return 0;
  611. }
  612. int ret = recv( nSock, buf, len, flags );
  613. if ( ret == -1 )
  614. {
  615. NET_GetLastError();
  616. if ( net_error == WSAEWOULDBLOCK ||
  617. net_error == WSAENOTCONN )
  618. {
  619. return 0; // ignore EWOULDBLOCK
  620. }
  621. Msg ("NET_ReceiveStream: %s\n", NET_ErrorString( net_error ) );
  622. }
  623. return ret;
  624. }
  625. INetChannel *NET_CreateNetChannel( int socket, const ns_address *adr, const char * name, INetChannelHandler * handler, const byte *pbEncryptionKey, bool bForceNewChannel )
  626. {
  627. CNetChan *chan = NULL;
  628. if ( !bForceNewChannel && adr != NULL )
  629. {
  630. // try to find real network channel if already existing
  631. if ( ( chan = NET_FindNetChannel( socket, *adr ) ) != NULL )
  632. {
  633. // channel already known, clear any old stuff before Setup wipes all
  634. chan->Clear();
  635. }
  636. }
  637. if ( !chan )
  638. {
  639. // create new channel
  640. chan = new CNetChan();
  641. AUTO_LOCK_FM( s_NetChannels );
  642. s_NetChannels.AddToTail( chan );
  643. }
  644. NET_ClearLagData( socket );
  645. // just reset and return
  646. ns_address adrToUse;
  647. if ( adr )
  648. adrToUse = *adr;
  649. else
  650. adrToUse.Clear();
  651. chan->Setup( socket, adrToUse, name, handler, pbEncryptionKey );
  652. ++ g_NetChannelsRefreshCounter;
  653. return chan;
  654. }
  655. void NET_RemoveNetChannel(INetChannel *netchan, bool bDeleteNetChan)
  656. {
  657. if ( !netchan )
  658. {
  659. return;
  660. }
  661. AUTO_LOCK_FM( s_NetChannels );
  662. if ( s_NetChannels.Find( static_cast<CNetChan*>(netchan) ) == s_NetChannels.InvalidIndex() )
  663. {
  664. DevMsg(1, "NET_CloseNetChannel: unknown channel.\n");
  665. return;
  666. }
  667. s_NetChannels.FindAndRemove( static_cast<CNetChan*>(netchan) );
  668. NET_ClearQueuedPacketsForChannel( netchan );
  669. if ( bDeleteNetChan )
  670. delete netchan;
  671. ++ g_NetChannelsRefreshCounter;
  672. }
  673. /*
  674. =============================================================================
  675. LOOPBACK BUFFERS FOR LOCAL PLAYER
  676. =============================================================================
  677. */
  678. void NET_SendLoopPacket (int sock, int length, const unsigned char *data )
  679. {
  680. // Never loop on anything other than client/server
  681. if ( sock != NS_CLIENT && sock != NS_SERVER )
  682. return;
  683. loopback_t *loop;
  684. if ( length > NET_MAX_PAYLOAD )
  685. {
  686. DevMsg( "NET_SendLoopPacket: packet too big (%i).\n", length );
  687. return;
  688. }
  689. loop = new loopback_t;
  690. if ( length <= DEF_LOOPBACK_SIZE )
  691. {
  692. loop->data = loop->defbuffer;
  693. }
  694. else
  695. {
  696. loop->data = new char[ length ];
  697. }
  698. Q_memcpy (loop->data, data, length);
  699. loop->datalen = length;
  700. if ( sock == NS_SERVER )
  701. {
  702. s_LoopBacks[NS_CLIENT].PushItem( loop );
  703. }
  704. else if ( sock == NS_CLIENT )
  705. {
  706. s_LoopBacks[NS_SERVER].PushItem( loop );
  707. }
  708. else
  709. {
  710. DevMsg( "NET_SendLoopPacket: invalid socket (%i).\n", sock );
  711. return;
  712. }
  713. }
  714. //=============================================================================
  715. int NET_CountLaggedList( netpacket_t *pList )
  716. {
  717. int c = 0;
  718. netpacket_t *p = pList;
  719. while ( p )
  720. {
  721. c++;
  722. p = p->pNext;
  723. }
  724. return c;
  725. }
  726. /*
  727. ===================
  728. NET_AddToLagged
  729. ===================
  730. */
  731. void NET_AddToLagged( netpacket_t **pList, netpacket_t *pPacket )
  732. {
  733. if ( pPacket->pNext )
  734. {
  735. Msg("NET_AddToLagged::Packet already linked\n");
  736. return;
  737. }
  738. // first copy packet
  739. netpacket_t *newPacket = new netpacket_t;
  740. (*newPacket) = (*pPacket); // copy packet infos
  741. newPacket->data = new unsigned char[ pPacket->size ]; // create new data buffer
  742. Q_memcpy( newPacket->data, pPacket->data, pPacket->size ); // copy packet data
  743. newPacket->pNext = NULL;
  744. // if list is empty, this is our first element
  745. if ( (*pList) == NULL )
  746. {
  747. (*pList) = newPacket; // put packet in top of list
  748. }
  749. else
  750. {
  751. netpacket_t *last = (*pList);
  752. while ( last->pNext )
  753. {
  754. // got to end of list
  755. last = last->pNext;
  756. }
  757. // add at end
  758. last->pNext = newPacket;
  759. }
  760. }
  761. // Actual lag to use in msec
  762. static float s_FakeLag = 0.0;
  763. float NET_GetFakeLag()
  764. {
  765. return s_FakeLag;
  766. }
  767. // How quickly we converge to a new value for fakelag
  768. #define FAKELAG_CONVERGE 200 // ms per second
  769. /*
  770. ==============================
  771. NET_AdjustLag
  772. ==============================
  773. */
  774. void NET_AdjustLag( void )
  775. {
  776. // Already converged?
  777. if ( fakelag.GetFloat() == s_FakeLag )
  778. return;
  779. static double s_LastTime = 0;
  780. // Bound time step
  781. float dt = clamp( net_time - s_LastTime, 0.0f, 0.2f );
  782. s_LastTime = net_time;
  783. // Figure out how far we have to go
  784. float diff = fakelag.GetFloat() - s_FakeLag;
  785. // How much can we converge this frame
  786. float converge = FAKELAG_CONVERGE * dt;
  787. // Last step, go the whole way
  788. if ( converge > fabs( diff ) )
  789. {
  790. converge = fabs( diff );
  791. }
  792. // Converge toward fakelag.GetFloat()
  793. if ( diff < 0.0 )
  794. {
  795. // Converge toward fakelag.GetFloat()
  796. s_FakeLag -= converge;
  797. }
  798. else
  799. {
  800. s_FakeLag += converge;
  801. }
  802. }
  803. bool NET_LagPacket (bool newdata, netpacket_t * packet)
  804. {
  805. static int losscount[MAX_SOCKETS];
  806. if ( packet->source >= MAX_SOCKETS )
  807. return newdata; // fake lag not supported for extra sockets
  808. if ( (droppackets.GetInt() > 0) && newdata && (packet->source == NS_CLIENT) )
  809. {
  810. droppackets.SetValue( droppackets.GetInt() - 1 );
  811. return false;
  812. }
  813. if ( fakeloss.GetFloat() && newdata )
  814. {
  815. losscount[packet->source]++;
  816. if ( fakeloss.GetFloat() > 0.0f )
  817. {
  818. // Act like we didn't hear anything if we are going to lose the packet.
  819. // Depends on random # generator.
  820. if (RandomInt(0,100) <= (int)fakeloss.GetFloat())
  821. return false;
  822. }
  823. else
  824. {
  825. int ninterval;
  826. ninterval = (int)(fabs( fakeloss.GetFloat() ) );
  827. ninterval = MAX( 2, ninterval );
  828. if ( !( losscount[packet->source] % ninterval ) )
  829. {
  830. return false;
  831. }
  832. }
  833. }
  834. if (s_FakeLag <= 0.0)
  835. {
  836. // Never leave any old msgs around
  837. for ( int i=0; i<MAX_SOCKETS; i++ )
  838. {
  839. NET_ClearLagData( i );
  840. }
  841. return newdata;
  842. }
  843. // if new packet arrived in fakelag list
  844. if ( newdata )
  845. {
  846. NET_AddToLagged( &s_pLagData[packet->source], packet );
  847. }
  848. // Now check the correct list and feed any message that is old enough.
  849. netpacket_t *p = s_pLagData[packet->source]; // current packet
  850. if ( !p )
  851. return false; // no packet in lag list
  852. float target = s_FakeLag;
  853. if ( fakejitter.GetFloat() > 0.0f )
  854. {
  855. float maxjitter = MIN( fakejitter.GetFloat(), target * 0.5f );
  856. target += RandomFloat( -maxjitter, maxjitter );
  857. }
  858. if ( (p->received + (target/1000.0f)) > net_time )
  859. return false; // not time yet for this packet
  860. #ifdef _DEBUG
  861. if ( fakeshuffle.GetInt() && p->pNext )
  862. {
  863. if ( !RandomInt( 0, fakeshuffle.GetInt() ) )
  864. {
  865. // swap p and p->next
  866. netpacket_t * t = p->pNext;
  867. p->pNext = t->pNext;
  868. t->pNext = p;
  869. p = t;
  870. }
  871. }
  872. #endif
  873. // remove packet p from list (is head)
  874. s_pLagData[packet->source] = p->pNext;
  875. // copy & adjust content
  876. packet->source = p->source;
  877. packet->from = p->from;
  878. packet->pNext = NULL; // no next
  879. packet->received = net_time; // new time
  880. packet->size = p->size;
  881. packet->wiresize = p->wiresize;
  882. packet->stream = p->stream;
  883. Q_memcpy( packet->data, p->data, p->size );
  884. // free lag packet
  885. delete[] p->data;
  886. delete p;
  887. return true;
  888. }
  889. // Calculate MAX_SPLITPACKET_SPLITS according to the smallest split size
  890. #define MAX_SPLITPACKET_SPLITS ( NET_MAX_MESSAGE / MIN_SPLIT_SIZE )
  891. #define SPLIT_PACKET_STALE_TIME 15.0f
  892. class CSplitPacketEntry
  893. {
  894. public:
  895. CSplitPacketEntry()
  896. {
  897. int i;
  898. for ( i = 0; i < MAX_SPLITPACKET_SPLITS; i++ )
  899. {
  900. splitflags[ i ] = -1;
  901. }
  902. memset( &netsplit, 0, sizeof( netsplit ) );
  903. lastactivetime = 0.0f;
  904. }
  905. public:
  906. ns_address from;
  907. int splitflags[ MAX_SPLITPACKET_SPLITS ];
  908. LONGPACKET netsplit;
  909. // host_time the last time any entry was received for this entry
  910. float lastactivetime;
  911. };
  912. typedef CUtlVector< CSplitPacketEntry > vecSplitPacketEntries_t;
  913. static CUtlVector<vecSplitPacketEntries_t> net_splitpackets;
  914. //-----------------------------------------------------------------------------
  915. // Purpose:
  916. //-----------------------------------------------------------------------------
  917. void NET_DiscardStaleSplitpackets( const int sock )
  918. {
  919. if ( !net_splitpackets.IsValidIndex( sock ) )
  920. return;
  921. vecSplitPacketEntries_t &splitPacketEntries = net_splitpackets[sock];
  922. int i;
  923. for ( i = splitPacketEntries.Count() - 1; i >= 0; i-- )
  924. {
  925. CSplitPacketEntry *entry = &splitPacketEntries[ i ];
  926. Assert( entry );
  927. if ( net_time < ( entry->lastactivetime + SPLIT_PACKET_STALE_TIME ) )
  928. continue;
  929. splitPacketEntries.Remove( i );
  930. }
  931. }
  932. //-----------------------------------------------------------------------------
  933. // Purpose:
  934. // Input : *from -
  935. // Output : CSplitPacketEntry
  936. //-----------------------------------------------------------------------------
  937. CSplitPacketEntry *NET_FindOrCreateSplitPacketEntry( const int sock, const ns_address &from )
  938. {
  939. vecSplitPacketEntries_t &splitPacketEntries = net_splitpackets[sock];
  940. int i, count = splitPacketEntries.Count();
  941. CSplitPacketEntry *entry = NULL;
  942. for ( i = 0; i < count; i++ )
  943. {
  944. entry = &splitPacketEntries[ i ];
  945. Assert( entry );
  946. if ( from == entry->from )
  947. break;
  948. }
  949. if ( i >= count )
  950. {
  951. CSplitPacketEntry newentry;
  952. newentry.from = from;
  953. splitPacketEntries.AddToTail( newentry );
  954. entry = &splitPacketEntries[ splitPacketEntries.Count() - 1 ];
  955. }
  956. Assert( entry );
  957. return entry;
  958. }
  959. static const tokenset_t< ESocketIndex_t > s_SocketDescMap[] =
  960. {
  961. { "cl", NS_CLIENT },
  962. { "sv", NS_SERVER },
  963. #ifdef _X360
  964. { "Xsl", NS_X360_SYSTEMLINK },
  965. { "Xlb", NS_X360_LOBBY },
  966. { "Xtl", NS_X360_TEAMLINK },
  967. #endif
  968. { "htv", NS_HLTV },
  969. { "htv1", NS_HLTV1 },
  970. #if defined( REPLAY_ENABLED )
  971. { "rply", NS_REPLAY },
  972. #endif
  973. { NULL, (ESocketIndex_t)-1 }
  974. };
  975. static char const *DescribeSocket( int sock )
  976. {
  977. return s_SocketDescMap->GetNameByToken( ( ESocketIndex_t ) sock, "??" );
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Purpose:
  981. // Input : *pData -
  982. // size -
  983. // *outSize -
  984. // Output : bool
  985. //-----------------------------------------------------------------------------
  986. bool NET_GetLong( const int sock, netpacket_t *packet )
  987. {
  988. int packetNumber, packetCount, sequenceNumber, offset;
  989. short packetID;
  990. SPLITPACKET *pHeader;
  991. if ( packet->size < sizeof(SPLITPACKET) )
  992. {
  993. Msg( "Invalid split packet length %i\n", packet->size );
  994. return false;
  995. }
  996. CSplitPacketEntry *entry = NET_FindOrCreateSplitPacketEntry( sock, packet->from );
  997. Assert( entry );
  998. if ( !entry )
  999. return false;
  1000. entry->lastactivetime = net_time;
  1001. Assert( packet->from.CompareAdr( entry->from ) );
  1002. pHeader = ( SPLITPACKET * )packet->data;
  1003. // pHeader is network endian correct
  1004. sequenceNumber = LittleLong( pHeader->sequenceNumber );
  1005. packetID = LittleShort( (short)pHeader->packetID );
  1006. // High byte is packet number
  1007. packetNumber = ( packetID >> 8 );
  1008. // Low byte is number of total packets
  1009. packetCount = ( packetID & 0xff );
  1010. int nSplitSizeMinusHeader = (int)LittleShort( (short)pHeader->nSplitSize );
  1011. if ( nSplitSizeMinusHeader < MIN_SPLIT_SIZE ||
  1012. nSplitSizeMinusHeader > MAX_SPLIT_SIZE )
  1013. {
  1014. Msg( "NET_GetLong: Split packet from %s with invalid split size (number %i/ count %i) where size %i is out of valid range [%d - %d ]\n",
  1015. ns_address_render( packet->from ).String(),
  1016. packetNumber,
  1017. packetCount,
  1018. nSplitSizeMinusHeader,
  1019. MIN_SPLIT_SIZE,
  1020. MAX_SPLIT_SIZE );
  1021. return false;
  1022. }
  1023. if ( packetNumber >= MAX_SPLITPACKET_SPLITS ||
  1024. packetCount > MAX_SPLITPACKET_SPLITS )
  1025. {
  1026. Msg( "NET_GetLong: Split packet from %s with too many split parts (number %i/ count %i) where %i is max count allowed\n",
  1027. ns_address_render( packet->from ).String(),
  1028. packetNumber,
  1029. packetCount,
  1030. MAX_SPLITPACKET_SPLITS );
  1031. return false;
  1032. }
  1033. // First packet in split series?
  1034. if ( entry->netsplit.currentSequence == -1 ||
  1035. sequenceNumber != entry->netsplit.currentSequence )
  1036. {
  1037. entry->netsplit.currentSequence = sequenceNumber;
  1038. entry->netsplit.splitCount = packetCount;
  1039. entry->netsplit.nExpectedSplitSize = nSplitSizeMinusHeader;
  1040. }
  1041. if ( entry->netsplit.nExpectedSplitSize != nSplitSizeMinusHeader )
  1042. {
  1043. 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",
  1044. ns_address_render( packet->from ).String(),
  1045. packetNumber,
  1046. packetCount,
  1047. nSplitSizeMinusHeader,
  1048. entry->netsplit.nExpectedSplitSize
  1049. );
  1050. return false;
  1051. }
  1052. int size = packet->size - sizeof(SPLITPACKET);
  1053. if ( entry->splitflags[ packetNumber ] != sequenceNumber )
  1054. {
  1055. // Last packet in sequence? set size
  1056. if ( packetNumber == (packetCount-1) )
  1057. {
  1058. entry->netsplit.totalSize = (packetCount-1) * nSplitSizeMinusHeader + size;
  1059. }
  1060. entry->netsplit.splitCount--; // Count packet
  1061. entry->splitflags[ packetNumber ] = sequenceNumber;
  1062. if ( net_showsplits.GetInt() && net_showsplits.GetInt() != 3 )
  1063. {
  1064. Msg( "<-- [%s] Split packet %4i/%4i seq %5i size %4i mtu %4i from %s\n",
  1065. DescribeSocket( sock ),
  1066. packetNumber + 1,
  1067. packetCount,
  1068. sequenceNumber,
  1069. size,
  1070. nSplitSizeMinusHeader + sizeof( SPLITPACKET ),
  1071. ns_address_render( packet->from ).String() );
  1072. }
  1073. }
  1074. else
  1075. {
  1076. Msg( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes ) from %s\n", packetNumber + 1, packetCount, size, ns_address_render( packet->from ).String() );
  1077. }
  1078. // Copy the incoming data to the appropriate place in the buffer
  1079. offset = (packetNumber * nSplitSizeMinusHeader);
  1080. memcpy( entry->netsplit.buffer + offset, packet->data + sizeof(SPLITPACKET), size );
  1081. // Have we received all of the pieces to the packet?
  1082. if ( entry->netsplit.splitCount <= 0 )
  1083. {
  1084. entry->netsplit.currentSequence = -1; // Clear packet
  1085. if ( entry->netsplit.totalSize > sizeof(entry->netsplit.buffer) )
  1086. {
  1087. Msg("Split packet too large! %d bytes from %s\n", entry->netsplit.totalSize, ns_address_render( packet->from ).String() );
  1088. return false;
  1089. }
  1090. Q_memcpy( packet->data, entry->netsplit.buffer, entry->netsplit.totalSize );
  1091. packet->size = entry->netsplit.totalSize;
  1092. packet->wiresize = entry->netsplit.totalSize;
  1093. return true;
  1094. }
  1095. return false;
  1096. }
  1097. bool NET_GetLoopPacket ( netpacket_t * packet )
  1098. {
  1099. Assert ( packet );
  1100. loopback_t *loop = NULL;
  1101. if ( packet->source > NS_SERVER )
  1102. return false;
  1103. if ( !s_LoopBacks[packet->source].PopItem( &loop ) )
  1104. {
  1105. return false;
  1106. }
  1107. if (loop->datalen == 0)
  1108. {
  1109. // no packet in loopback buffer
  1110. delete loop;
  1111. return ( NET_LagPacket( false, packet ) );
  1112. }
  1113. // copy data from loopback buffer to packet
  1114. packet->from.SetAddrType( NSAT_NETADR );
  1115. packet->from.m_adr.SetType( NA_LOOPBACK );
  1116. packet->size = loop->datalen;
  1117. packet->wiresize = loop->datalen;
  1118. Q_memcpy ( packet->data, loop->data, packet->size );
  1119. loop->datalen = 0; // buffer is avalibale again
  1120. if ( loop->data != loop->defbuffer )
  1121. {
  1122. delete loop->data;
  1123. loop->data = loop->defbuffer;
  1124. }
  1125. delete loop;
  1126. // allow lag system to modify packet
  1127. return ( NET_LagPacket( true, packet ) );
  1128. }
  1129. static int NET_ReceiveRawPacket( int sock, void *buf, int len, ns_address *from )
  1130. {
  1131. int net_socket = net_sockets[ sock ].hUDP;
  1132. int ret = g_pSteamSocketMgr->recvfrom(net_socket, (char*)buf, len, 0, from );
  1133. if ( ret > 0 )
  1134. return ret;
  1135. // Still nothing? Check proxied clients
  1136. if ( g_pSteamDatagramGameserver )
  1137. {
  1138. CSteamID remoteSteamID;
  1139. uint64 usecTimeRecv;
  1140. if ( sock == NS_SERVER )
  1141. {
  1142. ret = g_pSteamDatagramGameserver->RecvDatagram( buf, len, &remoteSteamID, &usecTimeRecv, STEAM_P2P_GAME_SERVER );
  1143. if ( ret > 0 )
  1144. {
  1145. from->SetFromSteamID( remoteSteamID, STEAM_P2P_GAME_CLIENT );
  1146. from->m_AddrType = NSAT_PROXIED_CLIENT;
  1147. return ret;
  1148. }
  1149. }
  1150. else if ( sock == NS_HLTV )
  1151. {
  1152. ret = g_pSteamDatagramGameserver->RecvDatagram( buf, len, &remoteSteamID, &usecTimeRecv, STEAM_P2P_HLTV );
  1153. if ( ret > 0 )
  1154. {
  1155. from->SetFromSteamID( remoteSteamID, STEAM_P2P_GAME_CLIENT );
  1156. from->m_AddrType = NSAT_PROXIED_CLIENT;
  1157. return ret;
  1158. }
  1159. }
  1160. else if ( sock == NS_HLTV1 )
  1161. {
  1162. ret = g_pSteamDatagramGameserver->RecvDatagram( buf, len, &remoteSteamID, &usecTimeRecv, STEAM_P2P_HLTV1 );
  1163. if ( ret > 0 )
  1164. {
  1165. from->SetFromSteamID( remoteSteamID, STEAM_P2P_GAME_CLIENT );
  1166. from->m_AddrType = NSAT_PROXIED_CLIENT;
  1167. return ret;
  1168. }
  1169. }
  1170. }
  1171. // Still nothing? Check proxied server
  1172. #ifndef DEDICATED
  1173. if ( sock == NS_CLIENT && ret <= 0 && g_pSteamDatagramClient && g_addrSteamDatagramProxiedGameServer.IsValid() )
  1174. {
  1175. //CSteamID remoteSteamID;
  1176. uint64 usecTimeRecv;
  1177. int ret = g_pSteamDatagramClient->RecvDatagram( buf, len, &usecTimeRecv, STEAM_P2P_GAME_CLIENT );
  1178. if ( ret > 0 )
  1179. {
  1180. *from = g_addrSteamDatagramProxiedGameServer;
  1181. //pReceiveData->usTime = usecTimeRecv;
  1182. return ret;
  1183. }
  1184. }
  1185. #endif
  1186. // nothing
  1187. return 0;
  1188. }
  1189. static bool NET_ReceiveDatagram_Helper( const int sock, netpacket_t * packet, bool &bNoMorePacketsInSocketPipe )
  1190. {
  1191. Assert ( packet );
  1192. Assert ( net_multiplayer );
  1193. #if defined( _DEBUG ) && !defined( _PS3 )
  1194. if ( recvpackets.GetInt() >= 0 )
  1195. {
  1196. unsigned long bytes;
  1197. int net_socket = net_sockets[packet->source].hUDP;
  1198. ioctlsocket( net_socket, FIONREAD, &bytes );
  1199. if ( bytes <= 0 )
  1200. {
  1201. bNoMorePacketsInSocketPipe = true;
  1202. return false;
  1203. }
  1204. if ( recvpackets.GetInt() == 0 )
  1205. {
  1206. bNoMorePacketsInSocketPipe = true;
  1207. return false;
  1208. }
  1209. recvpackets.SetValue( recvpackets.GetInt() - 1 );
  1210. }
  1211. #endif
  1212. int ret = NET_ReceiveRawPacket( sock, packet->data, NET_MAX_MESSAGE, &packet->from );
  1213. bNoMorePacketsInSocketPipe = ( ret <= 0 );
  1214. if ( ret > 0 )
  1215. {
  1216. packet->wiresize = ret;
  1217. MEM_ALLOC_CREDIT();
  1218. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > bufVoice( NET_COMPRESSION_STACKBUF_SIZE );
  1219. unsigned int nVoiceBits = 0u;
  1220. if ( IsX360() || net_dedicatedForXbox )
  1221. {
  1222. // X360TBD: Check for voice data and forward it to XAudio
  1223. // For now, just pull off the 2-byte VDP header and shift the data
  1224. unsigned short nDataBytes = ( *( unsigned short * )packet->data );
  1225. // 0xFFFF check is necessary because our LAN is broadcasting Source Engine Query requests
  1226. // which uses the out of band header, 0xFFFFFFFF, so it's not an XBox VDP packet.
  1227. if ( nDataBytes != 0xFFFF )
  1228. {
  1229. Assert( nDataBytes > 0 && nDataBytes <= ret );
  1230. int nVoiceBytes = ret - nDataBytes - 2;
  1231. if ( nVoiceBytes > 0 )
  1232. {
  1233. if ( voice_verbose.GetBool() )
  1234. {
  1235. Msg( "* NET_ReceiveDatagram: receiving voice from %s (%d bytes)\n", ns_address_render( packet->from ).String(), nVoiceBytes );
  1236. }
  1237. byte *pVoice = (byte *)packet->data + 2 + nDataBytes;
  1238. nVoiceBits = (unsigned int)LittleShort( *( unsigned short *)pVoice );
  1239. unsigned int nExpectedVoiceBytes = Bits2Bytes( nVoiceBits );
  1240. pVoice += sizeof( unsigned short );
  1241. CLZSS lzss;
  1242. if ( lzss.IsCompressed( pVoice ) )
  1243. {
  1244. unsigned int unDecompressedVoice = lzss.GetActualSize( pVoice );
  1245. if ( unDecompressedVoice != nExpectedVoiceBytes )
  1246. {
  1247. return false;
  1248. }
  1249. bufVoice.EnsureCapacity( unDecompressedVoice );
  1250. // Decompress it
  1251. unsigned int unCheck = lzss.SafeUncompress( pVoice, bufVoice.Base(), unDecompressedVoice );
  1252. if ( unCheck != unDecompressedVoice )
  1253. {
  1254. return false;
  1255. }
  1256. nVoiceBytes = unDecompressedVoice;
  1257. }
  1258. else
  1259. {
  1260. bufVoice.EnsureCapacity( nVoiceBytes );
  1261. Q_memcpy( bufVoice.Base(), pVoice, nVoiceBytes );
  1262. }
  1263. }
  1264. Q_memmove( packet->data, &packet->data[2], nDataBytes );
  1265. ret = nDataBytes;
  1266. }
  1267. }
  1268. packet->size = ret;
  1269. if ( ret < NET_MAX_MESSAGE )
  1270. {
  1271. // Check for split message
  1272. if ( LittleLong( *(int *)packet->data ) == NET_HEADER_FLAG_SPLITPACKET )
  1273. {
  1274. if ( !NET_GetLong( sock, packet ) )
  1275. return false;
  1276. }
  1277. // Now check if the data on the wire is encrypted?
  1278. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memDecryptedAll( NET_COMPRESSION_STACKBUF_SIZE );
  1279. if ( LittleLong( *(int *)packet->data ) != CONNECTIONLESS_HEADER )
  1280. {
  1281. // If the channel has encryption then decrypt the packet
  1282. CNetChan * chan = NET_FindNetChannel( sock, packet->from );
  1283. if ( !chan )
  1284. return false; // this is not an error during connect/disconnect, but non-connectionless packets must have a channel to process anyways
  1285. if ( const unsigned char *pubEncryptionKey = chan->GetChannelEncryptionKey() )
  1286. {
  1287. // Decrypt the packet
  1288. IceKey iceKey( 2 );
  1289. iceKey.set( pubEncryptionKey );
  1290. if ( ( packet->size % iceKey.blockSize() ) == 0 )
  1291. {
  1292. // Decrypt the message
  1293. memDecryptedAll.EnsureCapacity( packet->size );
  1294. unsigned char *pchCryptoBuffer = ( unsigned char * ) stackalloc( iceKey.blockSize() );
  1295. for ( int k = 0; k < ( int ) packet->size; k += iceKey.blockSize() )
  1296. {
  1297. iceKey.decrypt( ( const unsigned char * ) ( packet->data + k ), pchCryptoBuffer );
  1298. Q_memcpy( memDecryptedAll.Base() + k, pchCryptoBuffer, iceKey.blockSize() );
  1299. }
  1300. // Check how much random fudge we have
  1301. int numRandomFudgeBytes = *memDecryptedAll.Base();
  1302. if ( ( numRandomFudgeBytes > 0 ) && ( int( numRandomFudgeBytes + 1 + sizeof( int32 ) ) < packet->size ) )
  1303. {
  1304. // Fetch the size of the encrypted message
  1305. int32 numBytesWrittenWire = 0;
  1306. Q_memcpy( &numBytesWrittenWire, memDecryptedAll.Base() + 1 + numRandomFudgeBytes, sizeof( int32 ) );
  1307. int32 const numBytesWritten = BigLong( numBytesWrittenWire ); // byteswap from the wire
  1308. // Make sure the total size of the message matches the expectations
  1309. if ( int( numRandomFudgeBytes + 1 + sizeof( int32 ) +numBytesWritten ) == packet->size )
  1310. {
  1311. // Fix the packet to point at decrypted data!
  1312. packet->size = numBytesWritten;
  1313. Q_memcpy( packet->data, memDecryptedAll.Base() + 1 + numRandomFudgeBytes + sizeof( int32 ), packet->size );
  1314. }
  1315. }
  1316. }
  1317. }
  1318. }
  1319. // Next check for compressed message
  1320. if ( LittleLong( *(int *)packet->data) == NET_HEADER_FLAG_COMPRESSEDPACKET )
  1321. {
  1322. byte *pCompressedData = packet->data + sizeof( unsigned int );
  1323. CLZSS lzss;
  1324. // Decompress
  1325. int actualSize = lzss.GetActualSize( pCompressedData );
  1326. if ( actualSize <= 0 || actualSize > NET_MAX_PAYLOAD )
  1327. return false;
  1328. MEM_ALLOC_CREDIT();
  1329. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memDecompressed( NET_COMPRESSION_STACKBUF_SIZE );
  1330. memDecompressed.EnsureCapacity( actualSize );
  1331. unsigned int uDecompressedSize = lzss.SafeUncompress( pCompressedData, memDecompressed.Base(), actualSize );
  1332. if ( uDecompressedSize == 0 || ((unsigned int)actualSize) != uDecompressedSize )
  1333. {
  1334. return false;
  1335. }
  1336. // packet->wiresize is already set
  1337. Q_memcpy( packet->data, memDecompressed.Base(), uDecompressedSize );
  1338. packet->size = uDecompressedSize;
  1339. }
  1340. if ( nVoiceBits > 0 )
  1341. {
  1342. // 9th byte is flag byte
  1343. byte flagByte = *( (byte *)packet->data + sizeof( unsigned int ) + sizeof( unsigned int ) );
  1344. unsigned int unPacketBits = packet->size << 3;
  1345. int nPadBits = DECODE_PAD_BITS( flagByte );
  1346. unPacketBits -= nPadBits;
  1347. //check the CRC value in the original data packet
  1348. if( ShouldChecksumPackets() )
  1349. {
  1350. //we still want to honor the old checksum so we need to do it here instead of the usual location in CNetChan::ProcessPacketHeader
  1351. //If the layout of the header ever changes this code will need to be updated.
  1352. int checkSumByteOffset = sizeof( unsigned int ) + sizeof( unsigned int ) + sizeof( byte );
  1353. packet->message.Seek( checkSumByteOffset << 3 );
  1354. int oldChecksum = packet->message.ReadUBitLong( 16 );
  1355. packet->message.Seek(0);
  1356. int rawDataByteOffset = sizeof( unsigned int ) + sizeof( unsigned int ) + sizeof( byte ) + sizeof( unsigned short );
  1357. void *pvData = packet->data + rawDataByteOffset;
  1358. int nCheckSumBytes = packet->size - rawDataByteOffset;
  1359. if ( nCheckSumBytes <= 0 || nCheckSumBytes > NET_MAX_PAYLOAD )
  1360. {
  1361. ConMsg ( "corrupted packet detected (checksumbytes %d)\n", nCheckSumBytes );
  1362. return false;
  1363. }
  1364. unsigned short usDataCheckSum = BufferToShortChecksum( pvData, nCheckSumBytes );
  1365. if ( usDataCheckSum != oldChecksum )
  1366. {
  1367. ConMsg ( "corrupted packet detected\n" );
  1368. return false;
  1369. }
  1370. }
  1371. // create the combined gamedata + voicedata packet
  1372. bf_write fixup;
  1373. fixup.SetDebugName( "X360 Fixup" );
  1374. fixup.StartWriting( packet->data, NET_MAX_MESSAGE, unPacketBits );
  1375. fixup.WriteBits( bufVoice.Base(), nVoiceBits );
  1376. // Make sure we have enough bits to read a final net_NOP opcode before compressing
  1377. int nRemainingBits = fixup.GetNumBitsWritten() % 8;
  1378. if ( nRemainingBits > 0 && nRemainingBits <= (8-NETMSG_TYPE_BITS) )
  1379. {
  1380. CNETMsg_NOP_t nop;
  1381. nop.WriteToBuffer( fixup );
  1382. }
  1383. packet->size = fixup.GetNumBytesWritten();
  1384. //recompute the new CRC value in the header.
  1385. if( ShouldChecksumPackets() )
  1386. {
  1387. //CNetChan::ProcessPacketHeader will still be looking for the checksum so we need to generate one that will keep it happy.
  1388. int checkSumByteOffset = sizeof( unsigned int ) + sizeof( unsigned int ) + sizeof( byte );
  1389. fixup.SeekToBit( checkSumByteOffset << 3 );//seek to bit position of checksum
  1390. int rawDataByteOffset = sizeof( unsigned int ) + sizeof( unsigned int ) + sizeof( byte ) + sizeof( unsigned short );
  1391. void *pvData = packet->data + rawDataByteOffset;
  1392. int nCheckSumBytes = packet->size - rawDataByteOffset;
  1393. unsigned short newChecksum = BufferToShortChecksum( pvData, nCheckSumBytes );
  1394. fixup.WriteUBitLong( newChecksum, 16 );
  1395. }
  1396. }
  1397. return NET_LagPacket( true, packet );
  1398. }
  1399. else
  1400. {
  1401. ConDMsg ( "NET_ReceiveDatagram: Oversize packet from %s\n", ns_address_render( packet->from ).String() );
  1402. }
  1403. }
  1404. else if ( ret == -1 ) // error?
  1405. {
  1406. NET_GetLastError();
  1407. switch ( net_error )
  1408. {
  1409. case WSAEWOULDBLOCK:
  1410. case WSAECONNRESET:
  1411. case WSAECONNREFUSED:
  1412. break;
  1413. case WSAEMSGSIZE:
  1414. ConDMsg ("NET_ReceivePacket: %s\n", NET_ErrorString(net_error));
  1415. break;
  1416. default:
  1417. // Let's continue even after errors
  1418. ConDMsg ("NET_ReceivePacket: %s\n", NET_ErrorString(net_error));
  1419. break;
  1420. }
  1421. }
  1422. return false;
  1423. }
  1424. #define NET_WS_PACKET_PROFILE 0
  1425. #if NET_WS_PACKET_PROFILE
  1426. static uint64 g_nSockUDPTotalGood = 0;
  1427. static uint64 g_nSockUDPTotalBad = 0;
  1428. static uint64 g_nSockUDPTotalProcess = 0;
  1429. #define NET_WS_PACKET_STAT( sock, var ) if ( sv.IsActive() ) { if ( sock == NS_SERVER ) ++ var; } else { if ( sock == NS_CLIENT ) ++ var; }
  1430. CON_COMMAND( net_show_packet_stats, "Displays UDP packet statistics and resets the counters\n" )
  1431. {
  1432. Msg( "UDP processed: %llu pumps, %llu good pkts, %llu bad pkts.\n", g_nSockUDPTotalProcess, g_nSockUDPTotalGood, g_nSockUDPTotalBad );
  1433. Msg( "UDP rate: %.6f good pkt/pmp, %.6f bad pkt/pmp.\n", double( g_nSockUDPTotalGood )/double( MAX( g_nSockUDPTotalProcess, 1 ) ), double( g_nSockUDPTotalBad )/double( MAX( g_nSockUDPTotalProcess, 1 ) ) );
  1434. g_nSockUDPTotalGood = 0;
  1435. g_nSockUDPTotalBad = 0;
  1436. g_nSockUDPTotalProcess = 0;
  1437. }
  1438. #else
  1439. #define NET_WS_PACKET_STAT( sock, var )
  1440. #endif
  1441. bool NET_ReceiveDatagram ( const int sock, netpacket_t * packet )
  1442. {
  1443. for ( ;; )
  1444. {
  1445. bool bNoMorePacketsInSocketPipe = true;
  1446. bool bFoundGoodPacket = NET_ReceiveDatagram_Helper( sock, packet, bNoMorePacketsInSocketPipe );
  1447. if ( bFoundGoodPacket )
  1448. {
  1449. NET_WS_PACKET_STAT( sock, g_nSockUDPTotalGood );
  1450. return true;
  1451. }
  1452. if ( bNoMorePacketsInSocketPipe )
  1453. {
  1454. return false;
  1455. }
  1456. else
  1457. {
  1458. NET_WS_PACKET_STAT( sock, g_nSockUDPTotalBad );
  1459. // continue, this was a bad code that in old networking code would cause a packet processing hitch
  1460. }
  1461. }
  1462. }
  1463. netpacket_t *NET_GetPacket (int sock, byte *scratch )
  1464. {
  1465. if ( !net_packets.IsValidIndex( sock ) )
  1466. return NULL;
  1467. // Each socket has its own netpacket to allow multithreading
  1468. netpacket_t &inpacket = net_packets[sock];
  1469. NET_AdjustLag();
  1470. NET_DiscardStaleSplitpackets( sock );
  1471. // setup new packet
  1472. inpacket.from.Clear();
  1473. inpacket.received = net_time;
  1474. inpacket.source = sock;
  1475. inpacket.data = scratch;
  1476. inpacket.size = 0;
  1477. inpacket.wiresize = 0;
  1478. inpacket.pNext = NULL;
  1479. inpacket.message.SetDebugName("inpacket.message");
  1480. // Check loopback first
  1481. if ( !NET_GetLoopPacket( &inpacket ) )
  1482. {
  1483. #ifdef PORTAL2
  1484. extern IVEngineClient *engineClient;
  1485. // PORTAL2-specific hack for console perf - don't waste time reading from the actual socket (expensive Steam code)
  1486. if ( !NET_IsMultiplayer() || engineClient->IsSplitScreenActive()
  1487. || ( !IsGameConsole() && sv.IsActive() && !sv. IsMultiplayer() ) )
  1488. #else // PORTAL2
  1489. if ( !NET_IsMultiplayer() )
  1490. #endif // !PORTAL2
  1491. {
  1492. return NULL;
  1493. }
  1494. // then check UDP data
  1495. if ( !NET_ReceiveDatagram( sock, &inpacket ) )
  1496. {
  1497. // at last check if the lag system has a packet for us
  1498. if ( !NET_LagPacket (false, &inpacket) )
  1499. {
  1500. return NULL; // we don't have any new packet
  1501. }
  1502. }
  1503. }
  1504. Assert ( inpacket.size );
  1505. #ifdef _DEBUG
  1506. if ( fakenoise.GetInt() > 0 )
  1507. {
  1508. COM_AddNoise( inpacket.data, inpacket.size, fakenoise.GetInt() );
  1509. }
  1510. #endif
  1511. // prepare bitbuffer for reading packet with new size
  1512. inpacket.message.StartReading( inpacket.data, inpacket.size );
  1513. return &inpacket;
  1514. }
  1515. void NET_ProcessPending( void )
  1516. {
  1517. AUTO_LOCK_FM( s_PendingSockets );
  1518. for ( int i=0; i<s_PendingSockets.Count();i++ )
  1519. {
  1520. pendingsocket_t * psock = &s_PendingSockets[i];
  1521. ALIGN4 char headerBuf[5] ALIGN4_POST;
  1522. if ( (net_time - psock->time) > TCP_CONNECT_TIMEOUT )
  1523. {
  1524. NET_CloseSocket( psock->newsock );
  1525. s_PendingSockets.Remove( i );
  1526. continue;
  1527. }
  1528. int ret = NET_ReceiveStream( psock->newsock, headerBuf, sizeof(headerBuf), 0 );
  1529. if ( ret == 0 )
  1530. {
  1531. continue; // nothing received
  1532. }
  1533. else if ( ret == -1 )
  1534. {
  1535. NET_CloseSocket( psock->newsock );
  1536. s_PendingSockets.Remove( i );
  1537. continue; // connection closed somehow
  1538. }
  1539. bf_read header( headerBuf, sizeof(headerBuf) );
  1540. int cmd = header.ReadByte();
  1541. unsigned long challengeNr = header.ReadLong();
  1542. bool bOK = false;
  1543. if ( cmd == STREAM_CMD_ACKN )
  1544. {
  1545. AUTO_LOCK_FM( s_NetChannels );
  1546. for ( int j = 0; j < s_NetChannels.Count(); j++ )
  1547. {
  1548. CNetChan * chan = s_NetChannels[j];
  1549. if ( chan->GetSocket() != psock->netsock )
  1550. continue;
  1551. if ( challengeNr == chan->GetChallengeNr() && !chan->m_StreamSocket )
  1552. {
  1553. if ( psock->addr.CompareAdr( chan->remote_address.AsType<netadr_t>(), true ) )
  1554. {
  1555. chan->m_StreamSocket = psock->newsock;
  1556. chan->m_StreamActive = true;
  1557. chan->ResetStreaming();
  1558. bOK = true;
  1559. if ( net_showtcp.GetInt() )
  1560. {
  1561. Msg ("TCP <- %s: connection accepted\n", psock->addr.ToString() );
  1562. }
  1563. break;
  1564. }
  1565. else
  1566. {
  1567. Msg ("TCP <- %s: IP address mismatch.\n", psock->addr.ToString() );
  1568. }
  1569. }
  1570. }
  1571. }
  1572. if ( !bOK )
  1573. {
  1574. Msg ("TCP <- %s: invalid connection request.\n", psock->addr.ToString() );
  1575. NET_CloseSocket( psock->newsock );
  1576. }
  1577. s_PendingSockets.Remove( i );
  1578. }
  1579. }
  1580. void NET_ProcessListen(int sock)
  1581. {
  1582. netsocket_t * netsock = &net_sockets[sock];
  1583. if ( !netsock->bListening || OnlyUseSteamSockets() )
  1584. return;
  1585. sockaddr sa;
  1586. int nLengthAddr = sizeof(sa);
  1587. int newSocket = accept( netsock->hTCP, &sa, (socklen_t*)&nLengthAddr );
  1588. if ( newSocket == -1 )
  1589. {
  1590. NET_GetLastError();
  1591. if ( net_error != WSAEWOULDBLOCK )
  1592. {
  1593. ConDMsg ("NET_ThreadListen: %s\n", NET_ErrorString(net_error));
  1594. }
  1595. return;
  1596. }
  1597. // new connection TCP request, put in pending queue
  1598. pendingsocket_t psock;
  1599. psock.newsock = newSocket;
  1600. psock.netsock = sock;
  1601. psock.addr.SetFromSockadr( &sa );
  1602. psock.time = net_time;
  1603. AUTO_LOCK_FM( s_PendingSockets );
  1604. s_PendingSockets.AddToTail( psock );
  1605. // tell client to send challenge number to identify
  1606. char authcmd = STREAM_CMD_AUTH;
  1607. NET_SendStream( newSocket, &authcmd, 1 , 0 );
  1608. if ( net_showtcp.GetInt() )
  1609. {
  1610. Msg ("TCP <- %s: connection request.\n", psock.addr.ToString() );
  1611. }
  1612. }
  1613. void NET_ProcessSocket( int sock, IConnectionlessPacketHandler *handler )
  1614. {
  1615. class CAutoNetProcessSocketStartEnd
  1616. {
  1617. public:
  1618. CAutoNetProcessSocketStartEnd( int sock ) : m_sock( sock )
  1619. {
  1620. extern void On_NET_ProcessSocket_Start( int hUDP, int sock );
  1621. On_NET_ProcessSocket_Start( net_sockets[m_sock].hUDP, m_sock );
  1622. NET_WS_PACKET_STAT( sock, g_nSockUDPTotalProcess );
  1623. }
  1624. ~CAutoNetProcessSocketStartEnd()
  1625. {
  1626. extern void On_NET_ProcessSocket_End( int hUDP, int sock );
  1627. On_NET_ProcessSocket_End( net_sockets[m_sock].hUDP, m_sock );
  1628. }
  1629. private:
  1630. int m_sock;
  1631. }
  1632. autoThreadSockController( sock );
  1633. netpacket_t * packet;
  1634. //Assert ( (sock >= 0) && (sock<net_sockets.Count()) );
  1635. // Scope for the auto_lock
  1636. {
  1637. AUTO_LOCK_FM( s_NetChannels );
  1638. // get streaming data from channel sockets
  1639. int numChannels = s_NetChannels.Count();
  1640. for ( int i = (numChannels-1); i >= 0 ; i-- )
  1641. {
  1642. CNetChan *netchan = s_NetChannels[i];
  1643. // sockets must match
  1644. if ( sock != netchan->GetSocket() )
  1645. continue;
  1646. if ( !netchan->ProcessStream() )
  1647. {
  1648. netchan->GetMsgHandler()->ConnectionCrashed("TCP connection failed.");
  1649. }
  1650. }
  1651. }
  1652. // now get datagrams from sockets
  1653. net_scratchbuffer_t scratch;
  1654. while ( ( packet = NET_GetPacket ( sock, scratch.GetBuffer() ) ) != NULL )
  1655. {
  1656. if ( Filter_ShouldDiscard ( packet->from ) ) // filtering is done by network layer
  1657. {
  1658. Filter_SendBan( packet->from ); // tell them we aren't listening...
  1659. continue;
  1660. }
  1661. // check for connectionless packet (0xffffffff) first
  1662. if ( LittleLong( *(unsigned int *)packet->data ) == CONNECTIONLESS_HEADER )
  1663. {
  1664. packet->message.ReadLong(); // read the -1
  1665. if ( net_showudp.GetInt() && net_showudp_oob.GetInt() )
  1666. {
  1667. Msg("UDP <- %s: sz=%d OOB '0x%02X' wire=%d\n", ns_address_render( packet->from ).String(), packet->size, packet->data[4], packet->wiresize );
  1668. // for ( int k = 0; k < packet->size; ++ k )
  1669. // Msg( " %02X", packet->data[k] );
  1670. // Msg( "\n" );
  1671. // for ( int k = 0; k < packet->size; ++ k )
  1672. // Msg( " %c", (packet->data[k] >= 32 && packet->data[k] < 127) ? packet->data[k] : '*' );
  1673. // Msg( "\n" );
  1674. }
  1675. handler->ProcessConnectionlessPacket( packet );
  1676. continue;
  1677. }
  1678. // check for packets from connected clients
  1679. CNetChan * netchan = NET_FindNetChannel( sock, packet->from );
  1680. if ( netchan )
  1681. {
  1682. netchan->ProcessPacket( packet, true );
  1683. }
  1684. /* else // Not an error that may happen during connect or disconnect
  1685. {
  1686. Msg ("Sequenced packet without connection from %s\n" , ns_address_render( packet->from ).String() );
  1687. }*/
  1688. }
  1689. }
  1690. void NET_LogBadPacket(netpacket_t * packet)
  1691. {
  1692. FileHandle_t fp;
  1693. int i = 0;
  1694. char filename[ MAX_OSPATH ];
  1695. bool done = false;
  1696. while ( i < 1000 && !done )
  1697. {
  1698. Q_snprintf( filename, sizeof( filename ), "badpacket%03i.dat", i );
  1699. fp = g_pFileSystem->Open( filename, "rb" );
  1700. if ( !fp )
  1701. {
  1702. fp = g_pFileSystem->Open( filename, "wb" );
  1703. g_pFileSystem->Write( packet->data, packet->size, fp );
  1704. done = true;
  1705. }
  1706. if ( fp )
  1707. {
  1708. g_pFileSystem->Close( fp );
  1709. }
  1710. i++;
  1711. }
  1712. if ( i < 1000 )
  1713. {
  1714. Msg( "Error buffer for %s written to %s\n", ns_address_render( packet->from ).String(), filename );
  1715. }
  1716. else
  1717. {
  1718. Msg( "Couldn't write error buffer, delete error###.dat files to make space\n" );
  1719. }
  1720. }
  1721. static int NET_SendRawPacket( SOCKET s, const void *buf, int len, const ns_address &to )
  1722. {
  1723. switch ( to.m_AddrType )
  1724. {
  1725. case NSAT_NETADR:
  1726. return g_pSteamSocketMgr->sendto( s, (const char *)buf, len, 0, to );
  1727. //case NSAT_P2P:
  1728. //{
  1729. // Assert( socket.m_pSteamNetworking );
  1730. // if ( !socket.m_pSteamNetworking )
  1731. // return -1;
  1732. // if ( socket.m_pSteamNetworking->SendP2PPacket( to.m_steamID.GetSteamID(), buf, len, k_EP2PSendUnreliable, to.m_steamID.GetSteamChannel() ) )
  1733. // return length;
  1734. //}
  1735. //break;
  1736. case NSAT_PROXIED_GAMESERVER:
  1737. {
  1738. if ( !g_pSteamDatagramClient )
  1739. {
  1740. Assert( false );
  1741. Warning( "Tried to send packet to proxied gameserver, but no ISteamDatagramTransportClient\n" );
  1742. return -1;
  1743. }
  1744. if ( to != g_addrSteamDatagramProxiedGameServer )
  1745. {
  1746. Assert( false );
  1747. Warning( "Tried to send packet to proxied gameserver %s, but client is currently pointed at gameserver %s\n", ns_address_render( to ).String(), ns_address_render( g_addrSteamDatagramProxiedGameServer ).String() );
  1748. return -1;
  1749. }
  1750. EResult result = g_pSteamDatagramClient->SendDatagram( buf, len, to.m_steamID.GetSteamChannel() );
  1751. if ( result == k_EResultOK || result == k_EResultNoConnection )
  1752. return len;
  1753. }
  1754. break;
  1755. case NSAT_PROXIED_CLIENT:
  1756. {
  1757. if ( !g_pSteamDatagramGameserver )
  1758. {
  1759. Assert( false );
  1760. Warning( "Tried to send packet to proxied client, but no ISteamDatagramTransportGameserver\n" );
  1761. return -1;
  1762. }
  1763. EResult result = g_pSteamDatagramGameserver->SendDatagram( buf, len, to.m_steamID.GetSteamID(), to.m_steamID.GetSteamChannel() );
  1764. if ( result == k_EResultOK )
  1765. return len;
  1766. }
  1767. break;
  1768. }
  1769. Warning( "Attempt to send to unknown address type %d\n", to.m_AddrType );
  1770. Assert( false );
  1771. return -1;
  1772. }
  1773. int NET_SendToImpl( SOCKET s, const char * buf, int len, const ns_address &to, int iGameDataLength )
  1774. {
  1775. int nSend = 0;
  1776. if ( IsX360() || net_dedicatedForXbox )
  1777. {
  1778. // 360 uses VDP protocol to piggyback voice data across the network.
  1779. // [cbGameData][GameData][VoiceData]
  1780. // cbGameData is a two-byte prefix that contains the number of game data bytes in native order.
  1781. // XLSP servers (the only cross-platform communication possible with a secure network)
  1782. // swaps the header at the SG, decrypts the GameData and then forwards the packet to the title server.
  1783. Assert( len < (unsigned short)-1 );
  1784. const unsigned short nDataBytes = iGameDataLength == -1 ? len : iGameDataLength;
  1785. if ( voice_xsend_debug.GetBool() && iGameDataLength >= 0 && iGameDataLength != len )
  1786. {
  1787. DevMsg( "XVoice: VDP packet to %d with unencrypted %d bytes out of %d bytes\n", s, len - iGameDataLength, len );
  1788. }
  1789. const int nVDPHeaderBytes = 2;
  1790. if ( !to.IsType<netadr_t>() )
  1791. {
  1792. Warning( "NET_SendToImpl - cannot send to non-IP address %s\n", ns_address_render( to ).String() );
  1793. return -1;
  1794. }
  1795. #if defined( _WIN32 )
  1796. sockaddr sadrto;
  1797. to.AsType<netadr_t>().ToSockadr( &sadrto );
  1798. WSABUF buffers[2];
  1799. buffers[0].len = nVDPHeaderBytes;
  1800. buffers[0].buf = (char*)&nDataBytes;
  1801. buffers[1].len = len;
  1802. buffers[1].buf = const_cast<char*>( buf );
  1803. if ( nDataBytes < len && voice_verbose.GetBool() )
  1804. {
  1805. Msg( "* NET_SendToImpl: sending voice to %s (%d bytes)\n", ns_address_render( to ).String(), len - nDataBytes );
  1806. }
  1807. WSASendTo( s, buffers, 2, (DWORD*)&nSend, 0, &sadrto, sizeof(sadrto), NULL, NULL );
  1808. #else
  1809. //!!perf!! use linux sendmsg for gather similar to WSASendTo http://linux.die.net/man/3/sendmsg
  1810. uint8 *pData = ( uint8 * ) stackalloc( nVDPHeaderBytes + len );
  1811. memcpy( pData, &nDataBytes, nVDPHeaderBytes );
  1812. memcpy( pData + nVDPHeaderBytes, buf, len );
  1813. nSend = NET_SendRawPacket( s, ( const char * ) pData, nVDPHeaderBytes + len, to );
  1814. #endif
  1815. }
  1816. else
  1817. {
  1818. nSend = NET_SendRawPacket( s, buf, len, to );
  1819. }
  1820. return nSend;
  1821. }
  1822. //-----------------------------------------------------------------------------
  1823. // Purpose:
  1824. // Input : sock -
  1825. // s -
  1826. // buf -
  1827. // len -
  1828. // flags -
  1829. // to -
  1830. // tolen -
  1831. // Output : int
  1832. //-----------------------------------------------------------------------------
  1833. bool CL_IsHL2Demo();
  1834. bool CL_IsPortalDemo();
  1835. static int NET_SendTo( bool verbose, SOCKET s, const char * buf, int len, const ns_address &to, int iGameDataLength )
  1836. {
  1837. int nSend = 0;
  1838. // If it's 0.0.0.0:0, then it's a fake player + sv_stressbots and we've plumbed everything all
  1839. // the way through here, where we finally bail out.
  1840. if ( to.IsNull() )
  1841. {
  1842. return len;
  1843. }
  1844. // Don't send anything out in VCR mode.. it just annoys other people testing in multiplayer.
  1845. #ifndef DEDICATED
  1846. if ( ( CL_IsHL2Demo() || CL_IsPortalDemo() ) && !net_dedicated )
  1847. {
  1848. Error( "NET_SendTo: Error" );
  1849. }
  1850. #endif // _WIN32
  1851. nSend = NET_SendToImpl
  1852. (
  1853. s,
  1854. buf,
  1855. len,
  1856. to,
  1857. iGameDataLength
  1858. );
  1859. #if defined( _DEBUG )
  1860. if ( verbose &&
  1861. ( nSend > 0 ) &&
  1862. ( len > MAX_ROUTABLE_PAYLOAD ) )
  1863. {
  1864. ConDMsg( "NET_SendTo: Packet length (%i) > (%i) bytes\n", len, MAX_ROUTABLE_PAYLOAD );
  1865. }
  1866. #endif
  1867. return nSend;
  1868. }
  1869. #if defined( _DEBUG )
  1870. #include "filesystem.h"
  1871. #include "filesystem_engine.h"
  1872. //-----------------------------------------------------------------------------
  1873. // Purpose:
  1874. // Output : char const
  1875. //-----------------------------------------------------------------------------
  1876. char const *NET_GetDebugFilename( char const *prefix )
  1877. {
  1878. static char filename[ MAX_OSPATH ];
  1879. int i;
  1880. for ( i = 0; i < 10000; i++ )
  1881. {
  1882. Q_snprintf( filename, sizeof( filename ), "debug/%s%04i.dat", prefix, i );
  1883. if ( g_pFileSystem->FileExists( filename ) )
  1884. continue;
  1885. return filename;
  1886. }
  1887. return NULL;
  1888. }
  1889. //-----------------------------------------------------------------------------
  1890. // Purpose:
  1891. // Input : *filename -
  1892. // *buf -
  1893. // len -
  1894. //-----------------------------------------------------------------------------
  1895. void NET_StorePacket( char const *filename, byte const *buf, int len )
  1896. {
  1897. FileHandle_t fh;
  1898. g_pFileSystem->CreateDirHierarchy( "debug/", "DEFAULT_WRITE_PATH" );
  1899. fh = g_pFileSystem->Open( filename, "wb" );
  1900. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1901. {
  1902. g_pFileSystem->Write( buf, len, fh );
  1903. g_pFileSystem->Close( fh );
  1904. }
  1905. }
  1906. #endif // _DEBUG
  1907. struct SendQueueItem_t
  1908. {
  1909. SendQueueItem_t() :
  1910. m_pChannel( NULL ),
  1911. m_Socket( (SOCKET)-1 )
  1912. {
  1913. }
  1914. CNetChan *m_pChannel;
  1915. SOCKET m_Socket;
  1916. CUtlBuffer m_Buffer;
  1917. ns_address m_To;
  1918. };
  1919. struct SendQueue_t
  1920. {
  1921. SendQueue_t() :
  1922. m_nHostFrame( 0 )
  1923. {
  1924. }
  1925. int m_nHostFrame;
  1926. CUtlLinkedList< SendQueueItem_t > m_SendQueue;
  1927. };
  1928. static SendQueue_t g_SendQueue;
  1929. static int NET_QueuePacketForSend( CNetChan *chan, bool verbose, SOCKET s, const char *buf, int len, const ns_address &to, uint32 msecDelay )
  1930. {
  1931. // If net_queued_packet_thread was -1 at startup, then we don't even have a thread.
  1932. if ( net_queued_packet_thread.GetInt() && g_pQueuedPackedSender->IsRunning() )
  1933. {
  1934. g_pQueuedPackedSender->QueuePacket( chan, s, buf, len, to, msecDelay );
  1935. }
  1936. else
  1937. {
  1938. Assert( chan );
  1939. // Set up data structure
  1940. SendQueueItem_t *sq = &g_SendQueue.m_SendQueue[ g_SendQueue.m_SendQueue.AddToTail() ];
  1941. sq->m_Socket = s;
  1942. sq->m_pChannel = chan;
  1943. sq->m_Buffer.Put( (const void *)buf, len );
  1944. sq->m_To = to;
  1945. sq->m_pChannel->IncrementQueuedPackets();
  1946. }
  1947. return len;
  1948. }
  1949. void NET_SendQueuedPacket( SendQueueItem_t *sq )
  1950. {
  1951. // Msg( "Send queued packet %d\n", sq->m_Buffer.TellPut() );
  1952. NET_SendTo
  1953. (
  1954. false,
  1955. sq->m_Socket,
  1956. ( const char FAR * )sq->m_Buffer.Base(),
  1957. sq->m_Buffer.TellPut(),
  1958. sq->m_To,
  1959. -1
  1960. );
  1961. sq->m_pChannel->DecrementQueuedPackets();
  1962. }
  1963. void NET_ClearQueuedPacketsForChannel( INetChannel *channel )
  1964. {
  1965. CUtlLinkedList< SendQueueItem_t >& list = g_SendQueue.m_SendQueue;
  1966. for ( unsigned short i = list.Head(); i != list.InvalidIndex(); )
  1967. {
  1968. unsigned short n = list.Next( i );
  1969. SendQueueItem_t &e = list[ i ];
  1970. if ( e.m_pChannel == channel )
  1971. {
  1972. list.Remove( i );
  1973. }
  1974. i = n;
  1975. }
  1976. }
  1977. void NET_SendQueuedPackets()
  1978. {
  1979. // Only do this once per frame
  1980. if ( host_framecount == g_SendQueue.m_nHostFrame )
  1981. return;
  1982. g_SendQueue.m_nHostFrame = host_framecount;
  1983. CUtlLinkedList< SendQueueItem_t >& list = g_SendQueue.m_SendQueue;
  1984. int nRemaining = net_splitrate.GetInt();
  1985. while ( nRemaining )
  1986. {
  1987. if ( list.IsValidIndex( list.Head() ) )
  1988. {
  1989. SendQueueItem_t *sq = &list[ list.Head() ];
  1990. NET_SendQueuedPacket( sq );
  1991. list.Remove( list.Head() );
  1992. --nRemaining;
  1993. }
  1994. else
  1995. {
  1996. break;
  1997. }
  1998. }
  1999. }
  2000. //-----------------------------------------------------------------------------
  2001. // Purpose:
  2002. // Input : sock -
  2003. // s -
  2004. // buf -
  2005. // len -
  2006. // flags -
  2007. // to -
  2008. // tolen -
  2009. // Output : int
  2010. //-----------------------------------------------------------------------------
  2011. static volatile int32 s_SplitPacketSequenceNumber[ MAX_SOCKETS ] = {1};
  2012. static int NET_SendLong( INetChannel *chan, int sock, SOCKET s, const char * buf, int len, const ns_address &to, int nMaxRoutableSize )
  2013. {
  2014. CNetChan *netchan = dynamic_cast< CNetChan * >( chan );
  2015. short nSplitSizeMinusHeader = nMaxRoutableSize - sizeof( SPLITPACKET );
  2016. int nSequenceNumber = -1;
  2017. if ( netchan )
  2018. {
  2019. nSequenceNumber = netchan->IncrementSplitPacketSequence();
  2020. }
  2021. else
  2022. {
  2023. nSequenceNumber = ThreadInterlockedIncrement( &s_SplitPacketSequenceNumber[ sock ] );
  2024. }
  2025. const char *sendbuf = buf;
  2026. int sendlen = len;
  2027. char packet[ MAX_ROUTABLE_PAYLOAD ];
  2028. SPLITPACKET *pPacket = (SPLITPACKET *)packet;
  2029. // Make pPacket data network endian correct
  2030. pPacket->netID = LittleLong( NET_HEADER_FLAG_SPLITPACKET );
  2031. pPacket->sequenceNumber = LittleLong( nSequenceNumber );
  2032. pPacket->nSplitSize = LittleShort( nSplitSizeMinusHeader );
  2033. int nPacketCount = (sendlen + nSplitSizeMinusHeader - 1) / nSplitSizeMinusHeader;
  2034. #if defined( _DEBUG )
  2035. if ( net_savelargesplits.GetInt() != -1 && nPacketCount >= net_savelargesplits.GetInt() )
  2036. {
  2037. char const *filename = NET_GetDebugFilename( "splitpacket" );
  2038. if ( filename )
  2039. {
  2040. Msg( "Saving split packet of %i bytes and %i packets to file %s\n",
  2041. sendlen, nPacketCount, filename );
  2042. NET_StorePacket( filename, (byte const *)sendbuf, sendlen );
  2043. }
  2044. else
  2045. {
  2046. Msg( "Too many files in debug directory, clear out old data!\n" );
  2047. }
  2048. }
  2049. #endif
  2050. int nBytesLeft = sendlen;
  2051. int nPacketNumber = 0;
  2052. int nTotalBytesSent = 0;
  2053. int nFragmentsSent = 0;
  2054. while ( nBytesLeft > 0 )
  2055. {
  2056. int size = MIN( nSplitSizeMinusHeader, nBytesLeft );
  2057. pPacket->packetID = LittleShort( (short)(( nPacketNumber << 8 ) + nPacketCount) );
  2058. Q_memcpy( packet + sizeof(SPLITPACKET), sendbuf + (nPacketNumber * nSplitSizeMinusHeader), size );
  2059. int ret = 0;
  2060. // 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.
  2061. // Linux threads aren't prioritized well enough for this to work well (i.e. the queued packet thread doesn't get enough
  2062. // attention to flush itself well). The behavior the queue fixes is that if you send too many DP packets
  2063. // 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
  2064. // snif packets to double check)
  2065. if ( netchan && (nFragmentsSent >= net_splitrate.GetInt() || net_queued_packet_thread.GetInt() == NET_QUEUED_PACKET_THREAD_DEBUG_VALUE) )
  2066. {
  2067. // Don't let this rate get too high or user's won't be able to receive all of the parts
  2068. // since they'll be too close together.
  2069. // This should use the same rate as is used elsewhere so that we throttle all sends to the
  2070. // same delays. Note that setting the socket's send/receive buffers to a larger size helps
  2071. // to minimize the issues. However unthrottled UDP is still a bad thing.
  2072. float flMaxSplitpacketDataRateBytesPerSecond = (float)netchan->GetDataRate();
  2073. // Calculate the delay (measured from now) for when this packet should be sent.
  2074. uint32 delay = (int)( 1000.0f * ( (float)( nPacketNumber * ( nMaxRoutableSize + UDP_HEADER_SIZE ) ) / flMaxSplitpacketDataRateBytesPerSecond ) + 0.5f );
  2075. ret = NET_QueuePacketForSend( netchan, false, s, packet, size + sizeof(SPLITPACKET), to, delay );
  2076. }
  2077. else
  2078. {
  2079. // Also, we send the first packet no matter what
  2080. // 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
  2081. // server query packets, which should never require splitting anyway.
  2082. ret = NET_SendTo( false, s, packet, size + sizeof(SPLITPACKET), to, -1 );
  2083. }
  2084. // First split send
  2085. ++nFragmentsSent;
  2086. if ( ret < 0 )
  2087. {
  2088. return ret;
  2089. }
  2090. if ( ret >= size )
  2091. {
  2092. nTotalBytesSent += size;
  2093. }
  2094. nBytesLeft -= size;
  2095. ++nPacketNumber;
  2096. // Always bitch about split packets in debug
  2097. if ( net_showsplits.GetInt() && net_showsplits.GetInt() != 2 )
  2098. {
  2099. Msg( "--> [%s] Split packet %4i/%4i seq %5i size %4i mtu %4i to %s [ total %4i ]\n",
  2100. DescribeSocket( sock ),
  2101. nPacketNumber,
  2102. nPacketCount,
  2103. nSequenceNumber,
  2104. size,
  2105. nMaxRoutableSize,
  2106. ns_address_render( to ).String(),
  2107. sendlen );
  2108. }
  2109. }
  2110. return nTotalBytesSent;
  2111. }
  2112. //-----------------------------------------------------------------------------
  2113. // Purpose:
  2114. // Input : sock -
  2115. // length -
  2116. // *data -
  2117. // to -
  2118. // Output : void NET_SendPacket
  2119. //-----------------------------------------------------------------------------
  2120. int NET_SendPacket ( INetChannel *chan, int sock, const ns_address &to, const unsigned char *data, int length, bf_write *pVoicePayload /* = NULL */, bool bUseCompression /*=false*/, uint32 unMillisecondsDelay /*=0u*/ )
  2121. {
  2122. int ret;
  2123. if ( (*(unsigned int*)data == CONNECTIONLESS_HEADER) && bUseCompression )
  2124. {
  2125. Warning( "[NET] Cannot send compressed connectionless packet to %s '0x%02X'\n", ns_address_render( to ).String(), data[4] );
  2126. Assert( 0 );
  2127. return 0;
  2128. }
  2129. if ( ( *( unsigned int* ) data == CONNECTIONLESS_HEADER ) && ( length > MAX_ROUTABLE_PAYLOAD ) )
  2130. {
  2131. Warning( "[NET] Cannot send connectionless packet to %s '0x%02X' exceeding MTU (%u)\n", ns_address_render( to ).String(), data[ 4 ], length );
  2132. Assert( 0 );
  2133. return 0;
  2134. }
  2135. if ( net_showudp.GetInt() && (*(unsigned int*)data == CONNECTIONLESS_HEADER) && net_showudp_oob.GetInt() )
  2136. {
  2137. Assert( !bUseCompression );
  2138. if ( !net_showudp_remoteonly.GetBool() || !( to.IsLocalhost() || to.IsLoopback() ) )
  2139. {
  2140. Msg("UDP -> %s: sz=%d OOB '0x%02X'\n", ns_address_render( to ).String(), length, data[4] );
  2141. }
  2142. }
  2143. if ( !NET_IsMultiplayer() || to.IsLoopback() || ( to.IsLocalhost() && !net_usesocketsforloopback.GetBool() ) )
  2144. {
  2145. Assert( !pVoicePayload );
  2146. NET_SendLoopPacket(sock, length, data );
  2147. return length;
  2148. }
  2149. int net_socket = 0;
  2150. if ( to.IsType<netadr_t>() )
  2151. {
  2152. net_socket = net_sockets[sock].hUDP;
  2153. if (!net_socket)
  2154. return length;
  2155. }
  2156. if ( (droppackets.GetInt() < 0) && sock == NS_CLIENT )
  2157. {
  2158. droppackets.SetValue( droppackets.GetInt() + 1 );
  2159. return length;
  2160. }
  2161. if ( fakeloss.GetFloat() > 0.0f )
  2162. {
  2163. // simulate sending this packet
  2164. if (RandomInt(0,100) <= (int)fakeloss.GetFloat())
  2165. return length;
  2166. }
  2167. MEM_ALLOC_CREDIT();
  2168. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memCompressed( NET_COMPRESSION_STACKBUF_SIZE );
  2169. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memCompressedVoice( NET_COMPRESSION_STACKBUF_SIZE );
  2170. CUtlMemoryFixedGrowable< byte, NET_COMPRESSION_STACKBUF_SIZE > memEncryptedAll( NET_COMPRESSION_STACKBUF_SIZE );
  2171. int iGameDataLength = pVoicePayload ? length : -1;
  2172. bool bWroteVoice = false;
  2173. unsigned int nVoiceBytes = 0;
  2174. if ( pVoicePayload )
  2175. {
  2176. memCompressedVoice.EnsureCapacity( pVoicePayload->GetNumBytesWritten() + sizeof( unsigned short ) );
  2177. byte *pVoice = (byte *)memCompressedVoice.Base();
  2178. unsigned short usVoiceBits = pVoicePayload->GetNumBitsWritten();
  2179. *( unsigned short * )pVoice = LittleShort( usVoiceBits );
  2180. pVoice += sizeof( unsigned short );
  2181. unsigned int nCompressedLength = pVoicePayload->GetNumBytesWritten();
  2182. byte *pOutput = NULL;
  2183. if ( net_compressvoice.GetBool() )
  2184. {
  2185. CLZSS lzss;
  2186. pOutput = lzss.CompressNoAlloc( pVoicePayload->GetData(), pVoicePayload->GetNumBytesWritten(), (byte *)pVoice, &nCompressedLength );
  2187. }
  2188. if ( !pOutput )
  2189. {
  2190. Q_memcpy( pVoice, pVoicePayload->GetData(), pVoicePayload->GetNumBytesWritten() );
  2191. }
  2192. nVoiceBytes = nCompressedLength + sizeof( unsigned short );
  2193. }
  2194. if ( voice_xsend_debug.GetBool() && nVoiceBytes )
  2195. {
  2196. DevMsg( "XVoice: voice data payload for %p: %d bytes\n", chan, nVoiceBytes );
  2197. }
  2198. if ( bUseCompression )
  2199. {
  2200. CLZSS lzss;
  2201. unsigned int nCompressedLength = length;
  2202. memCompressed.EnsureCapacity( length + nVoiceBytes + sizeof( unsigned int ) );
  2203. *(int *)memCompressed.Base() = LittleLong( NET_HEADER_FLAG_COMPRESSEDPACKET );
  2204. byte *pOutput = lzss.CompressNoAlloc( (byte *)data, length, memCompressed.Base() + sizeof( unsigned int ), &nCompressedLength );
  2205. if ( pOutput )
  2206. {
  2207. data = memCompressed.Base();
  2208. length = nCompressedLength + sizeof( unsigned int );
  2209. if ( pVoicePayload && pVoicePayload->GetNumBitsWritten() > 0 )
  2210. {
  2211. byte *pVoice = (byte *)memCompressed.Base() + length;
  2212. Q_memcpy( pVoice, memCompressedVoice.Base(), nVoiceBytes );
  2213. }
  2214. iGameDataLength = length;
  2215. length += nVoiceBytes;
  2216. bWroteVoice = true;
  2217. }
  2218. }
  2219. if ( !bWroteVoice && pVoicePayload && pVoicePayload->GetNumBitsWritten() > 0 )
  2220. {
  2221. memCompressed.EnsureCapacity( length + nVoiceBytes );
  2222. byte *pVoice = (byte *)memCompressed.Base();
  2223. Q_memcpy( pVoice, (const void *)data, length );
  2224. pVoice += length;
  2225. Q_memcpy( pVoice, memCompressedVoice.Base(), nVoiceBytes );
  2226. data = memCompressed.Base();
  2227. length += nVoiceBytes;
  2228. }
  2229. // If the network channel has encryption key then we should encrypt
  2230. if ( const unsigned char *pubEncryptionKey = chan ? chan->GetChannelEncryptionKey() : NULL )
  2231. {
  2232. IceKey iceKey( 2 );
  2233. iceKey.set( pubEncryptionKey );
  2234. // Generate some random fudge, ICE operates on 64-bit blocks, so make sure our total size is a multiple of 8 bytes
  2235. int numRandomFudgeBytes = RandomInt( 16, 72 );
  2236. int numTotalEncryptedBytes = 1 + numRandomFudgeBytes + sizeof( int32 ) + length;
  2237. numRandomFudgeBytes += iceKey.blockSize() - ( numTotalEncryptedBytes % iceKey.blockSize() );
  2238. numTotalEncryptedBytes = 1 + numRandomFudgeBytes + sizeof( int32 ) + length;
  2239. char *pchRandomFudgeBytes = ( char * ) stackalloc( numRandomFudgeBytes );
  2240. for ( int k = 0; k < numRandomFudgeBytes; ++k )
  2241. pchRandomFudgeBytes[ k ] = RandomInt( 16, 250 );
  2242. // Prepare the encrypted memory
  2243. memEncryptedAll.EnsureCapacity( numTotalEncryptedBytes );
  2244. * memEncryptedAll.Base() = numRandomFudgeBytes;
  2245. Q_memcpy( memEncryptedAll.Base() + 1, pchRandomFudgeBytes, numRandomFudgeBytes );
  2246. int32 const numBytesWrittenWire = BigLong( length ); // byteswap for the wire
  2247. Q_memcpy( memEncryptedAll.Base() + 1 + numRandomFudgeBytes, &numBytesWrittenWire, sizeof( numBytesWrittenWire ) );
  2248. Q_memcpy( memEncryptedAll.Base() + 1 + numRandomFudgeBytes + sizeof( int32 ), data, length );
  2249. // Encrypt the message
  2250. unsigned char *pchCryptoBuffer = ( unsigned char * ) stackalloc( iceKey.blockSize() );
  2251. for ( int k = 0; k < numTotalEncryptedBytes; k += iceKey.blockSize() )
  2252. {
  2253. iceKey.encrypt( ( const unsigned char * ) ( memEncryptedAll.Base() + k ), pchCryptoBuffer );
  2254. Q_memcpy( memEncryptedAll.Base() + k, pchCryptoBuffer, iceKey.blockSize() );
  2255. }
  2256. // Set the pointers to network out the encrypted data
  2257. data = memEncryptedAll.Base();
  2258. length = numTotalEncryptedBytes;
  2259. }
  2260. // Do we need to break this packet up?
  2261. int nMaxRoutable = MAX_ROUTABLE_PAYLOAD;
  2262. if ( chan )
  2263. {
  2264. nMaxRoutable = clamp( chan->GetMaxRoutablePayloadSize(), MIN_USER_MAXROUTABLE_SIZE, MIN( sv_maxroutable.GetInt(), MAX_USER_MAXROUTABLE_SIZE ) );
  2265. }
  2266. if ( ( unMillisecondsDelay != 0u ) &&
  2267. ( length > nMaxRoutable ) )
  2268. {
  2269. Warning( "Can't delay send a packet larger than maxroutable size %d/%d\n", length, nMaxRoutable );
  2270. unMillisecondsDelay = 0u;
  2271. }
  2272. if ( unMillisecondsDelay != 0u )
  2273. {
  2274. ret = NET_QueuePacketForSend( static_cast< CNetChan * >( chan ), false, net_socket, (const char *)data, length, to, unMillisecondsDelay );
  2275. }
  2276. else if ( length <= nMaxRoutable &&
  2277. !(net_queued_packet_thread.GetInt() == NET_QUEUED_PACKET_THREAD_DEBUG_VALUE && chan ) )
  2278. {
  2279. // simple case, small packet, just send it
  2280. ret = NET_SendTo( true, net_socket, (const char *)data, length, to, iGameDataLength );
  2281. }
  2282. else
  2283. {
  2284. // split packet into smaller pieces
  2285. ret = NET_SendLong( chan, sock, net_socket, (const char *)data, length, to, nMaxRoutable );
  2286. }
  2287. if (ret == -1)
  2288. {
  2289. NET_GetLastError();
  2290. // wouldblock is silent
  2291. if ( net_error == WSAEWOULDBLOCK )
  2292. return 0;
  2293. if ( net_error == WSAECONNRESET )
  2294. return 0;
  2295. // some PPP links dont allow broadcasts
  2296. if ( ( net_error == WSAEADDRNOTAVAIL) && ( to.IsBroadcast() ) )
  2297. return 0;
  2298. ConDMsg ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(net_error), ns_address_render( to ).String() );
  2299. ret = length;
  2300. }
  2301. return ret;
  2302. }
  2303. void NET_OutOfBandPrintf(int sock, const ns_address &adr, const char *format, ...)
  2304. {
  2305. va_list argptr;
  2306. char string[MAX_ROUTABLE_PAYLOAD];
  2307. *(unsigned int*)string = CONNECTIONLESS_HEADER;
  2308. va_start (argptr, format);
  2309. Q_vsnprintf (string+4, sizeof( string ) - 4, format,argptr);
  2310. va_end (argptr);
  2311. int length = Q_strlen(string+4) + 5;
  2312. NET_SendPacket ( NULL, sock, adr, (byte *)string, length );
  2313. }
  2314. void NET_OutOfBandDelayedPrintf(int sock, const ns_address &adr, uint32 unMillisecondsDelay, const char *format, ...)
  2315. {
  2316. va_list argptr;
  2317. char string[MAX_ROUTABLE_PAYLOAD];
  2318. *(unsigned int*)string = CONNECTIONLESS_HEADER;
  2319. va_start (argptr, format);
  2320. Q_vsnprintf (string+4, sizeof( string ) - 4, format,argptr);
  2321. va_end (argptr);
  2322. int length = Q_strlen(string+4) + 5;
  2323. NET_SendPacket ( NULL, sock, adr, (byte *)string, length, 0, false, unMillisecondsDelay );
  2324. }
  2325. /*
  2326. ====================
  2327. NET_CloseAllSockets
  2328. ====================
  2329. */
  2330. void NET_CloseAllSockets (void)
  2331. {
  2332. // shut down any existing and open sockets
  2333. for (int i=0 ; i<net_sockets.Count() ; i++)
  2334. {
  2335. if ( net_sockets[i].nPort )
  2336. {
  2337. NET_CloseSocket( net_sockets[i].hUDP );
  2338. NET_CloseSocket( net_sockets[i].hTCP );
  2339. net_sockets[i].nPort = 0;
  2340. net_sockets[i].bListening = false;
  2341. net_sockets[i].hUDP = 0;
  2342. net_sockets[i].hTCP = 0;
  2343. }
  2344. }
  2345. // shut down all pending sockets
  2346. AUTO_LOCK_FM( s_PendingSockets );
  2347. for(int j=0; j<s_PendingSockets.Count();j++ )
  2348. {
  2349. NET_CloseSocket( s_PendingSockets[j].newsock );
  2350. }
  2351. s_PendingSockets.RemoveAll();
  2352. // Close steam sockets as well
  2353. g_pSteamSocketMgr->Shutdown();
  2354. g_pSteamSocketMgr->Init();
  2355. // Shutdown steam datagram server, if we were listening
  2356. if ( g_pSteamDatagramGameserver )
  2357. {
  2358. g_pSteamDatagramGameserver->Destroy();
  2359. g_pSteamDatagramGameserver = NULL;
  2360. }
  2361. // Shutdown steam datagram client, if we have one
  2362. CloseSteamDatagramClientConnection();
  2363. }
  2364. /*
  2365. ====================
  2366. NET_FlushAllSockets
  2367. ====================
  2368. */
  2369. void NET_FlushAllSockets( void )
  2370. {
  2371. // drain any packets that my still lurk in our incoming queue
  2372. char data[2048];
  2373. ns_address from;
  2374. for (int i=0 ; i<net_sockets.Count() ; i++)
  2375. {
  2376. if ( net_sockets[i].hUDP )
  2377. {
  2378. int bytes = 1;
  2379. // loop until no packets are pending anymore
  2380. while ( bytes > 0 )
  2381. {
  2382. bytes = NET_ReceiveRawPacket( net_sockets[i].hUDP, data, sizeof(data), &from );
  2383. }
  2384. }
  2385. }
  2386. }
  2387. #if defined( IS_WINDOWS_PC )
  2388. #include <Iphlpapi.h>
  2389. // Simple helper class to enumerate and cache of IP addresses of local network adapters
  2390. class CBindAddressHelper
  2391. {
  2392. public:
  2393. CBindAddressHelper() : m_bInitialized( false )
  2394. {
  2395. }
  2396. void GetBindAddresses( CUtlVector< CUtlString >& list )
  2397. {
  2398. if ( !m_bInitialized )
  2399. {
  2400. m_bInitialized = true;
  2401. BuildBindAddresses( m_CachedAddresses );
  2402. }
  2403. for ( int i = 0; i < m_CachedAddresses.Count(); ++i )
  2404. {
  2405. list.AddToTail( m_CachedAddresses[ i ] );
  2406. }
  2407. }
  2408. private:
  2409. void BuildBindAddresses( CUtlVector< CUtlString >& list )
  2410. {
  2411. IP_ADAPTER_INFO info_temp;
  2412. ULONG len = 0;
  2413. if ( GetAdaptersInfo( &info_temp, &len ) != ERROR_BUFFER_OVERFLOW )
  2414. return;
  2415. IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[ len ];
  2416. if ( !infos )
  2417. {
  2418. Sys_Error( "BuildBindAddresses: Out of memory allocating %d bytes\n", sizeof( IP_ADAPTER_INFO ) * len );
  2419. return;
  2420. }
  2421. if ( GetAdaptersInfo( infos, &len ) == NO_ERROR )
  2422. {
  2423. for ( IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next )
  2424. {
  2425. if ( info->Type == MIB_IF_TYPE_LOOPBACK )
  2426. continue;
  2427. if ( !Q_strcmp( info->IpAddressList.IpAddress.String, "0.0.0.0" ) )
  2428. continue;
  2429. DevMsg( "NET_GetBindAddresses found %s: '%s'\n", info->IpAddressList.IpAddress.String, info->Description );
  2430. list.AddToTail( CUtlString( info->IpAddressList.IpAddress.String ) );
  2431. }
  2432. }
  2433. delete[] infos;
  2434. }
  2435. bool m_bInitialized;
  2436. CUtlVector< CUtlString > m_CachedAddresses;
  2437. };
  2438. static CBindAddressHelper g_BindAddressHelper;
  2439. #endif
  2440. #ifndef DEDICATED
  2441. // Initialize steam client datagram lib if we haven't already
  2442. static bool CheckInitSteamDatagramClientLib()
  2443. {
  2444. static bool bInittedNetwork = false;
  2445. if ( bInittedNetwork )
  2446. return true;
  2447. if ( !Steam3Client().SteamHTTP() )
  2448. {
  2449. Warning( "Cannot init steam datagram client, no Steam HTTP interface\n" );
  2450. return false;
  2451. }
  2452. // Locate the first PLATFORM path
  2453. char szAbsPlatform[MAX_FILEPATH] = "";
  2454. const char *pszConfigDir = "config";
  2455. g_pFullFileSystem->GetSearchPath( "PLATFORM", false, szAbsPlatform, sizeof(szAbsPlatform) );
  2456. char *semi = strchr( szAbsPlatform, ';' );
  2457. if ( semi )
  2458. *semi = '\0';
  2459. // Set partner. Running in china?
  2460. ESteamDatagramPartner ePartner = k_ESteamDatagramPartner_Steam;
  2461. if ( CommandLine()->HasParm( "-perfectworld" ) )
  2462. ePartner = k_ESteamDatagramPartner_China;
  2463. int iPartnerMark = -1; // CSGO doesn't prune the config based on partner!
  2464. char szAbsConfigDir[ MAX_FILEPATH];
  2465. V_ComposeFileName( szAbsPlatform, pszConfigDir, szAbsConfigDir, sizeof(szAbsConfigDir) );
  2466. SteamDatagramClient_Init( szAbsConfigDir, ePartner, iPartnerMark );
  2467. bInittedNetwork = true;
  2468. return true;
  2469. }
  2470. void NET_PrintSteamdatagramClientStatus()
  2471. {
  2472. if ( !g_pSteamDatagramClient )
  2473. {
  2474. Msg( "No steam datagram client connection active\n" );
  2475. return;
  2476. }
  2477. ISteamDatagramTransportClient::ConnectionStatus status;
  2478. g_pSteamDatagramClient->GetConnectionStatus( status );
  2479. int sz = status.Print( NULL, 0 );
  2480. CUtlMemory<char> buf;
  2481. buf.EnsureCapacity( sz );
  2482. char *p = buf.Base();
  2483. status.Print( p, sz );
  2484. for (;;)
  2485. {
  2486. char *newline = strchr( p, '\n' );
  2487. if ( newline )
  2488. *newline = '\0';
  2489. Msg( "%s\n", p );
  2490. if ( !newline )
  2491. break;
  2492. p = newline+1;
  2493. }
  2494. }
  2495. CON_COMMAND( steamdatagram_client_status, "Print steam datagram client status" )
  2496. {
  2497. NET_PrintSteamdatagramClientStatus();
  2498. }
  2499. bool NET_InitSteamDatagramProxiedGameserverConnection( const ns_address &adr )
  2500. {
  2501. Assert( adr.GetAddressType() == NSAT_PROXIED_GAMESERVER );
  2502. // Most common case - talking to the same server as before
  2503. if ( g_pSteamDatagramClient )
  2504. {
  2505. if ( g_addrSteamDatagramProxiedGameServer.m_steamID.GetSteamID() == adr.m_steamID.GetSteamID() )
  2506. {
  2507. g_addrSteamDatagramProxiedGameServer.m_steamID.SetSteamChannel( adr.m_steamID.GetSteamChannel() );
  2508. return true;
  2509. }
  2510. // We have a client, but it was to talk to a different server. Clear our ticket!
  2511. g_pSteamDatagramClient->Close();
  2512. g_addrSteamDatagramProxiedGameServer.Clear();
  2513. }
  2514. // Get a client to talk to this server
  2515. g_pSteamDatagramClient = SteamDatagramClient_Connect( adr.m_steamID.GetSteamID() );
  2516. if ( !g_pSteamDatagramClient )
  2517. return false;
  2518. // OK, remember who we're talking to
  2519. g_addrSteamDatagramProxiedGameServer = adr;
  2520. return true;
  2521. }
  2522. #endif
  2523. static void OpenSocketInternal( int nModule, int nSetPort, int nDefaultPort, const char *pName, int nProtocol, bool bTryAny )
  2524. {
  2525. CUtlVector< CUtlString > vecBindableAddresses;
  2526. if ( ( NS_HLTV == nModule )&& ipname_tv.GetString()[0] )
  2527. {
  2528. vecBindableAddresses.AddToTail( CUtlString( ipname_tv.GetString() ) );
  2529. }
  2530. else if ( ( NS_HLTV1 == nModule ) && ipname_tv1.GetString()[ 0 ] )
  2531. {
  2532. vecBindableAddresses.AddToTail( CUtlString( ipname_tv1.GetString() ) );
  2533. }
  2534. else
  2535. {
  2536. vecBindableAddresses.AddToTail( CUtlString( ipname.GetString() ) );
  2537. }
  2538. #if defined( IS_WINDOWS_PC )
  2539. g_BindAddressHelper.GetBindAddresses( vecBindableAddresses );
  2540. #endif
  2541. int port = nSetPort ? nSetPort : nDefaultPort;
  2542. int *handle = NULL;
  2543. if( nProtocol == IPPROTO_TCP )
  2544. {
  2545. handle = &net_sockets[nModule].hTCP;
  2546. }
  2547. else if ( nProtocol == IPPROTO_UDP || nProtocol == IPPROTO_VDP )
  2548. {
  2549. handle = &net_sockets[nModule].hUDP;
  2550. }
  2551. else
  2552. {
  2553. Sys_Error( "Unrecognized protocol type %d", nProtocol );
  2554. return;
  2555. }
  2556. if ( !net_sockets[nModule].nPort )
  2557. {
  2558. int nSavePort = port;
  2559. for ( int i = 0; i < vecBindableAddresses.Count(); ++i )
  2560. {
  2561. port = nSavePort;
  2562. char const *pchIPAddressToBind = vecBindableAddresses[ i ].String();
  2563. if ( i > 0 )
  2564. {
  2565. Msg( "Trying to open socket on %s\n", pchIPAddressToBind );
  2566. }
  2567. // If we are only using Steam sockets, get a fake handle
  2568. *handle = OnlyUseSteamSockets() ? ++g_nFakeSocketHandle : NET_OpenSocket (pchIPAddressToBind, port, nProtocol );
  2569. if ( !OnlyUseSteamSockets() && !*handle && bTryAny )
  2570. {
  2571. port = PORT_ANY; // try again with PORT_ANY
  2572. *handle = NET_OpenSocket (pchIPAddressToBind, port, nProtocol );
  2573. }
  2574. // Stop on first success
  2575. if ( *handle )
  2576. break;
  2577. }
  2578. if ( !*handle )
  2579. {
  2580. Warning( "Couldn't allocate any %s IP port, tried %d addresses %s", pName, vecBindableAddresses.Count(),
  2581. ( vecBindableAddresses.Count() ? vecBindableAddresses.Head().Get() : "(none)" ) );
  2582. Plat_ExitProcess( 0 ); // cause a silent exit without writing a core dump
  2583. return;
  2584. }
  2585. net_sockets[nModule].nPort = port;
  2586. }
  2587. else
  2588. {
  2589. Msg("WARNING: NET_OpenSockets: %s port %i already open.\n", pName, net_sockets[nModule].nPort );
  2590. }
  2591. if ( handle )
  2592. {
  2593. g_pSteamSocketMgr->OpenSocket( *handle, nModule, nSetPort, nDefaultPort, pName, nProtocol, bTryAny );
  2594. }
  2595. #ifndef DEDICATED
  2596. if ( nModule == NS_CLIENT )
  2597. CheckInitSteamDatagramClientLib();
  2598. #endif
  2599. }
  2600. /*
  2601. ====================
  2602. NET_OpenSockets
  2603. ====================
  2604. */
  2605. void NET_OpenSockets (void)
  2606. {
  2607. // Xbox 360 uses VDP protocol to combine encrypted game data with clear voice data
  2608. const int nProtocol = IsX360() ? IPPROTO_VDP : IPPROTO_UDP;
  2609. OpenSocketInternal( NS_SERVER, hostport.GetInt(), PORT_SERVER, "server", nProtocol, false );
  2610. OpenSocketInternal( NS_CLIENT, clientport.GetInt(), PORT_SERVER, "client", nProtocol, true );
  2611. #ifdef _X360
  2612. int nX360Port = PORT_X360_RESERVED_FIRST;
  2613. OpenSocketInternal( NS_X360_SYSTEMLINK, 0, nX360Port ++, "x360systemlink", IPPROTO_UDP, false );
  2614. OpenSocketInternal( NS_X360_LOBBY, 0, nX360Port ++, "x360lobby", nProtocol, false );
  2615. OpenSocketInternal( NS_X360_TEAMLINK, 0, nX360Port ++, "x360teamlink", nProtocol, false );
  2616. Assert( nX360Port <= PORT_X360_RESERVED_LAST );
  2617. #endif
  2618. if ( !net_nohltv )
  2619. {
  2620. OpenSocketInternal( NS_HLTV, hltvport.GetInt(), PORT_HLTV, "hltv", nProtocol, false );
  2621. if ( net_addhltv1 )
  2622. {
  2623. OpenSocketInternal( NS_HLTV1, hltvport1.GetInt(), PORT_HLTV1, "hltv1", nProtocol, false );
  2624. }
  2625. }
  2626. #if defined( REPLAY_ENABLED )
  2627. if ( !net_noreplay )
  2628. {
  2629. OpenSocketInternal( NS_REPLAY, replayport.GetInt(), PORT_REPLAY, "replay", nProtocol, false );
  2630. }
  2631. #endif
  2632. }
  2633. bool NET_IsSocketOpen( int nSockIdx )
  2634. {
  2635. if ( !net_sockets.IsValidIndex( nSockIdx ) )
  2636. return false;
  2637. if ( !net_sockets[nSockIdx].hUDP )
  2638. return false;
  2639. return true;
  2640. }
  2641. int NET_AddExtraSocket( int port )
  2642. {
  2643. int newSocket = net_sockets.AddToTail();
  2644. Q_memset( &net_sockets[newSocket], 0, sizeof(netsocket_t) );
  2645. OpenSocketInternal( newSocket, port, PORT_ANY, "extra", IPPROTO_UDP, true );
  2646. net_packets.EnsureCount( newSocket+1 );
  2647. net_splitpackets.EnsureCount( newSocket+1 );
  2648. return newSocket;
  2649. }
  2650. void NET_RemoveAllExtraSockets()
  2651. {
  2652. for (int i=MAX_SOCKETS ; i<net_sockets.Count() ; i++)
  2653. {
  2654. if ( net_sockets[i].nPort )
  2655. {
  2656. NET_CloseSocket( net_sockets[i].hUDP );
  2657. NET_CloseSocket( net_sockets[i].hTCP );
  2658. }
  2659. }
  2660. net_sockets.RemoveMultiple( MAX_SOCKETS, net_sockets.Count()-MAX_SOCKETS );
  2661. Assert( net_sockets.Count() == MAX_SOCKETS );
  2662. }
  2663. unsigned short NET_GetUDPPort(int socket)
  2664. {
  2665. return net_sockets.IsValidIndex( socket ) ?
  2666. net_sockets[socket].nPort : 0;
  2667. }
  2668. static void NET_ConPrintByteStream( uint8 const *pb, int nSize )
  2669. {
  2670. for ( int k = 0; k < nSize; ++ k, ++ pb )
  2671. Msg( " %02X", *pb );
  2672. }
  2673. /*
  2674. ================
  2675. NET_GetLocalAddress
  2676. Returns the servers' ip address as a string.
  2677. ================
  2678. */
  2679. void NET_GetLocalAddress (void)
  2680. {
  2681. net_local_adr.Clear();
  2682. if ( net_noip )
  2683. {
  2684. Msg("TCP/UDP Disabled.\n");
  2685. }
  2686. else
  2687. {
  2688. #ifdef _X360
  2689. int err = 0;
  2690. XNADDR xnaddrLocal;
  2691. ZeroMemory( &xnaddrLocal, sizeof( xnaddrLocal ) );
  2692. while( XNET_GET_XNADDR_PENDING == ( err = XNetGetTitleXnAddr( &xnaddrLocal ) ) )
  2693. continue;
  2694. static struct XnAddrType_t
  2695. {
  2696. int m_code;
  2697. char const *m_szValue;
  2698. }
  2699. arrXnAddrTypes[] = {
  2700. { XNET_GET_XNADDR_NONE, "NONE" },
  2701. { XNET_GET_XNADDR_ETHERNET, "ETHERNET" },
  2702. { XNET_GET_XNADDR_STATIC, "STATIC" },
  2703. { XNET_GET_XNADDR_DHCP, "DHCP" },
  2704. { XNET_GET_XNADDR_PPPOE, "PPPoE" },
  2705. { XNET_GET_XNADDR_GATEWAY, "GATEWAY" },
  2706. { XNET_GET_XNADDR_DNS, "DNS" },
  2707. { XNET_GET_XNADDR_ONLINE, "ONLINE" },
  2708. { XNET_GET_XNADDR_TROUBLESHOOT, "TROUBLESHOOT" },
  2709. { 0, NULL }
  2710. };
  2711. Msg( "Local XNetwork address type 0x%08X", err );
  2712. for ( XnAddrType_t const *pxat = arrXnAddrTypes; pxat->m_code; ++ pxat )
  2713. {
  2714. if ( ( err & pxat->m_code ) == pxat->m_code )
  2715. Msg( " %s", pxat->m_szValue );
  2716. }
  2717. Msg( "\n" );
  2718. net_local_adr.SetFromString( "127.0.0.1" );
  2719. Msg( "Local IP address: %d.%d.%d.%d\n",
  2720. xnaddrLocal.ina.S_un.S_un_b.s_b1,
  2721. xnaddrLocal.ina.S_un.S_un_b.s_b2,
  2722. xnaddrLocal.ina.S_un.S_un_b.s_b3,
  2723. xnaddrLocal.ina.S_un.S_un_b.s_b4 );
  2724. #elif defined( _PS3 )
  2725. CellNetCtlInfo cnci;
  2726. memset( &cnci, 0, sizeof( cnci ) );
  2727. // Print CELL network information for debug output
  2728. Msg( "=========== CELL network information ===========\n" );
  2729. for ( int iCellInfo = CELL_NET_CTL_INFO_DEVICE; iCellInfo <= CELL_NET_CTL_INFO_UPNP_CONFIG; ++ iCellInfo )
  2730. {
  2731. int ret = cellNetCtlGetInfo( iCellInfo, &cnci );
  2732. if ( CELL_OK != ret )
  2733. {
  2734. Warning( "NET: failed to obtain CELL NET INFO #%d, error code %d.\n", iCellInfo, ret );
  2735. }
  2736. else switch ( iCellInfo )
  2737. {
  2738. case CELL_NET_CTL_INFO_DEVICE:
  2739. Msg( " Device: %u\n", cnci.device );
  2740. break;
  2741. case CELL_NET_CTL_INFO_ETHER_ADDR:
  2742. Msg( " Ethernet Address: [" );
  2743. NET_ConPrintByteStream( cnci.ether_addr.data, sizeof( cnci.ether_addr.data ) );
  2744. NET_ConPrintByteStream( cnci.ether_addr.padding, sizeof( cnci.ether_addr.padding ) );
  2745. Msg( " ]\n" );
  2746. break;
  2747. case CELL_NET_CTL_INFO_MTU:
  2748. Msg( " MTU: %u\n", cnci.mtu );
  2749. break;
  2750. case CELL_NET_CTL_INFO_LINK:
  2751. Msg( " Link: %u\n", cnci.link );
  2752. break;
  2753. case CELL_NET_CTL_INFO_LINK_TYPE:
  2754. Msg( " Link type: %u\n", cnci.link_type );
  2755. break;
  2756. case CELL_NET_CTL_INFO_BSSID:
  2757. Msg( " BSSID Address: [" );
  2758. NET_ConPrintByteStream( cnci.bssid.data, sizeof( cnci.bssid.data ) );
  2759. NET_ConPrintByteStream( cnci.bssid.padding, sizeof( cnci.bssid.padding ) );
  2760. Msg( " ]\n" );
  2761. break;
  2762. case CELL_NET_CTL_INFO_SSID:
  2763. Msg( " SSID Address: [" );
  2764. NET_ConPrintByteStream( cnci.ssid.data, sizeof( cnci.ssid.data ) );
  2765. NET_ConPrintByteStream( &cnci.ssid.term, sizeof( cnci.ssid.term ) );
  2766. NET_ConPrintByteStream( cnci.ssid.padding, sizeof( cnci.ssid.padding ) );
  2767. Msg( " ]\n" );
  2768. break;
  2769. case CELL_NET_CTL_INFO_WLAN_SECURITY:
  2770. Msg( " WLAN security: %u\n", cnci.wlan_security );
  2771. break;
  2772. case CELL_NET_CTL_INFO_8021X_TYPE:
  2773. Msg( " WAuth 8021x type: %u\n", cnci.auth_8021x_type );
  2774. break;
  2775. case CELL_NET_CTL_INFO_8021X_AUTH_NAME:
  2776. Msg( " WAuth 8021x name: %s\n", cnci.auth_8021x_auth_name );
  2777. break;
  2778. case CELL_NET_CTL_INFO_RSSI:
  2779. Msg( " WRSSI: %u\n", cnci.rssi );
  2780. break;
  2781. case CELL_NET_CTL_INFO_CHANNEL:
  2782. Msg( " WChannel: %u\n", cnci.channel );
  2783. break;
  2784. case CELL_NET_CTL_INFO_IP_CONFIG:
  2785. Msg( " Ipconfig: %u\n", cnci.ip_config );
  2786. break;
  2787. case CELL_NET_CTL_INFO_DHCP_HOSTNAME:
  2788. Msg( " DHCP hostname: %s\n", cnci.dhcp_hostname );
  2789. break;
  2790. case CELL_NET_CTL_INFO_PPPOE_AUTH_NAME:
  2791. Msg( " PPPOE auth name: %s\n", cnci.pppoe_auth_name );
  2792. break;
  2793. case CELL_NET_CTL_INFO_IP_ADDRESS:
  2794. Msg( " IP address: %s\n", cnci.ip_address );
  2795. break;
  2796. case CELL_NET_CTL_INFO_NETMASK:
  2797. Msg( " Net mask: %s\n", cnci.netmask );
  2798. break;
  2799. case CELL_NET_CTL_INFO_DEFAULT_ROUTE:
  2800. Msg( " Default route: %s\n", cnci.default_route );
  2801. break;
  2802. case CELL_NET_CTL_INFO_PRIMARY_DNS:
  2803. Msg( " Primary DNS: %s\n", cnci.primary_dns );
  2804. break;
  2805. case CELL_NET_CTL_INFO_SECONDARY_DNS:
  2806. Msg( " Secondary DNS: %s\n", cnci.secondary_dns );
  2807. break;
  2808. case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG:
  2809. Msg( " HTTP proxy config: %u\n", cnci.http_proxy_config );
  2810. break;
  2811. case CELL_NET_CTL_INFO_HTTP_PROXY_SERVER:
  2812. Msg( " HTTP proxy server: %s\n", cnci.http_proxy_server );
  2813. break;
  2814. case CELL_NET_CTL_INFO_HTTP_PROXY_PORT:
  2815. Msg( " HTTP proxy port: %d\n", cnci.http_proxy_port );
  2816. break;
  2817. case CELL_NET_CTL_INFO_UPNP_CONFIG:
  2818. Msg( " UPNP config: %u\n", cnci.upnp_config );
  2819. break;
  2820. default:
  2821. Msg( " UNKNOWNNETDATA[%d]: [", iCellInfo );
  2822. NET_ConPrintByteStream( reinterpret_cast< const uint8* >( &cnci ), sizeof( cnci ) );
  2823. Msg( " ]\n" );
  2824. break;
  2825. }
  2826. }
  2827. Msg( "================================================\n" );
  2828. // -- end CELL network debug information
  2829. net_local_adr.SetFromString( "127.0.0.1" );
  2830. if ( CELL_OK == cellNetCtlGetInfo( CELL_NET_CTL_INFO_IP_ADDRESS, &cnci ) )
  2831. net_local_adr.SetFromString( cnci.ip_address );
  2832. #else
  2833. char buff[512];
  2834. // If we have changed the ip var from the command line, use that instead.
  2835. if ( Q_strcmp(ipname.GetString(), "localhost") )
  2836. {
  2837. Q_strncpy(buff, ipname.GetString(), sizeof( buff ) ); // use IP set with ipname
  2838. }
  2839. else
  2840. {
  2841. #if defined( LINUX )
  2842. // Run the systems ifconfig call to scan for an eth0 address so we don't show only the machine's loopback address
  2843. //
  2844. // note: This block simply grabs and prints out the IP address to the TTY stream
  2845. // the rest of the port/network information is printed in NET_Config()
  2846. FILE * fp = popen("ifconfig", "r");
  2847. if (fp)
  2848. {
  2849. char *curLine=NULL;
  2850. size_t n;
  2851. bool lastWasEth0 = false;
  2852. while ((getline(&curLine, &n, fp) > 0) && curLine)
  2853. {
  2854. // loop through each line returned from ifconfig
  2855. if( strstr(curLine, "Link encap:") )
  2856. {
  2857. if(strstr(curLine, "eth0") )
  2858. lastWasEth0 = true; // this is part of the entry we want, the next IP after this is the right one
  2859. else
  2860. lastWasEth0 = false;
  2861. }
  2862. if (lastWasEth0 && (curLine = strstr(curLine, "inet addr:") ))
  2863. {
  2864. curLine+=10; // skip past the eth0 lable and blank space to the address we want
  2865. char* curChar = strchr(curLine, ' ');
  2866. if ( curChar )
  2867. {
  2868. *curChar ='\0';
  2869. Msg("Network: IP %s ", curLine);
  2870. }
  2871. }
  2872. }
  2873. pclose(fp);
  2874. }
  2875. else
  2876. {
  2877. Msg( "Network: <failed to find IP> " );
  2878. }
  2879. #endif // LINUX
  2880. gethostname( buff, sizeof(buff) ); // get own IP address
  2881. buff[sizeof(buff)-1] = 0; // Ensure that it doesn't overrun the buffer
  2882. }
  2883. NET_StringToAdr (buff, &net_local_adr);
  2884. #endif
  2885. int ipaddr = ( net_local_adr.ip[0] << 24 ) +
  2886. ( net_local_adr.ip[1] << 16 ) +
  2887. ( net_local_adr.ip[2] << 8 ) +
  2888. net_local_adr.ip[3];
  2889. hostip.SetValue( ipaddr );
  2890. }
  2891. }
  2892. /*
  2893. ====================
  2894. NET_IsConfigured
  2895. Is winsock ip initialized?
  2896. ====================
  2897. */
  2898. bool NET_IsMultiplayer( void )
  2899. {
  2900. return net_multiplayer;
  2901. }
  2902. bool NET_IsDedicated( void )
  2903. {
  2904. return net_dedicated;
  2905. }
  2906. #ifdef SERVER_XLSP
  2907. bool NET_IsDedicatedForXbox( void )
  2908. {
  2909. return net_dedicated && net_dedicatedForXbox;
  2910. }
  2911. #endif
  2912. #ifdef _X360
  2913. #include "iengine.h"
  2914. static FileHandle_t g_fh;
  2915. void NET_LogServerStatus( void )
  2916. {
  2917. if ( !g_fh )
  2918. return;
  2919. static float fNextTime = 0.f;
  2920. float fCurrentTime = eng->GetCurTime();
  2921. if ( fCurrentTime >= fNextTime )
  2922. {
  2923. fNextTime = fCurrentTime + net_loginterval.GetFloat();
  2924. }
  2925. else
  2926. {
  2927. return;
  2928. }
  2929. AUTO_LOCK_FM( s_NetChannels );
  2930. int numChannels = s_NetChannels.Count();
  2931. if ( numChannels == 0 )
  2932. {
  2933. ConMsg( "No active net channels.\n" );
  2934. return;
  2935. }
  2936. enum
  2937. {
  2938. NET_LATENCY,
  2939. NET_LOSS,
  2940. NET_PACKETS_IN,
  2941. NET_PACKETS_OUT,
  2942. NET_CHOKE_IN,
  2943. NET_CHOKE_OUT,
  2944. NET_FLOW_IN,
  2945. NET_FLOW_OUT,
  2946. NET_TOTAL_IN,
  2947. NET_TOTAL_OUT,
  2948. NET_LAST,
  2949. };
  2950. float fStats[NET_LAST] = {0.f};
  2951. for ( int i = 0; i < numChannels; ++i )
  2952. {
  2953. INetChannel *chan = s_NetChannels[i];
  2954. fStats[NET_LATENCY] += chan->GetAvgLatency(FLOW_OUTGOING);
  2955. fStats[NET_LOSS] += chan->GetAvgLoss(FLOW_INCOMING);
  2956. fStats[NET_PACKETS_IN] += chan->GetAvgPackets(FLOW_INCOMING);
  2957. fStats[NET_PACKETS_OUT] += chan->GetAvgPackets(FLOW_OUTGOING);
  2958. fStats[NET_CHOKE_IN] += chan->GetAvgChoke(FLOW_INCOMING);
  2959. fStats[NET_CHOKE_OUT] += chan->GetAvgChoke(FLOW_OUTGOING);
  2960. fStats[NET_FLOW_IN] += chan->GetAvgData(FLOW_INCOMING);
  2961. fStats[NET_FLOW_OUT] += chan->GetAvgData(FLOW_OUTGOING);
  2962. fStats[NET_TOTAL_IN] += chan->GetTotalData(FLOW_INCOMING);
  2963. fStats[NET_TOTAL_OUT] += chan->GetTotalData(FLOW_OUTGOING);
  2964. }
  2965. for ( int i = 0; i < NET_LAST; ++i )
  2966. {
  2967. fStats[i] /= numChannels;
  2968. }
  2969. const unsigned int size = 128;
  2970. char msg[size];
  2971. Q_snprintf( msg, size, "%.0f,%d,%.0f,%.0f,%.0f,%.1f,%.1f,%.1f,%.1f,%.1f\n",
  2972. fCurrentTime,
  2973. numChannels,
  2974. fStats[NET_LATENCY],
  2975. fStats[NET_LOSS],
  2976. fStats[NET_PACKETS_IN],
  2977. fStats[NET_PACKETS_OUT],
  2978. fStats[NET_FLOW_IN]/1024.0f,
  2979. fStats[NET_FLOW_OUT]/1024.0f,
  2980. fStats[NET_CHOKE_IN],
  2981. fStats[NET_CHOKE_OUT]
  2982. );
  2983. g_pFileSystem->Write( msg, Q_strlen( msg ), g_fh );
  2984. }
  2985. void NET_LogServerCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
  2986. {
  2987. ConVarRef var( pConVar );
  2988. if ( var.GetBool() )
  2989. {
  2990. if ( g_fh )
  2991. {
  2992. g_pFileSystem->Close( g_fh );
  2993. g_fh = 0;
  2994. }
  2995. g_fh = g_pFileSystem->Open( "dump.csv", "wt" );
  2996. if ( !g_fh )
  2997. {
  2998. Msg( "Failed to open log file\n" );
  2999. pConVar->SetValue( 0 );
  3000. return;
  3001. }
  3002. char msg[128];
  3003. 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" );
  3004. g_pFileSystem->Write( msg, Q_strlen( msg ), g_fh );
  3005. }
  3006. else
  3007. {
  3008. if ( g_fh )
  3009. {
  3010. g_pFileSystem->Close( g_fh );
  3011. g_fh = 0;
  3012. }
  3013. }
  3014. }
  3015. #endif
  3016. /*
  3017. ====================
  3018. NET_SetTime
  3019. Updates net_time
  3020. ====================
  3021. */
  3022. void NET_SetTime( double realtime )
  3023. {
  3024. static double s_last_realtime = 0;
  3025. double frametime = realtime - s_last_realtime;
  3026. s_last_realtime = realtime;
  3027. if ( frametime > 1.0f )
  3028. {
  3029. // if we have very long frame times because of loading stuff
  3030. // don't apply that to net time to avoid unwanted timeouts
  3031. frametime = 1.0f;
  3032. }
  3033. else if ( frametime < 0.0f )
  3034. {
  3035. frametime = 0.0f;
  3036. }
  3037. #if !defined( DEDICATED )
  3038. // adjust network time so fakelag works with host_timescale
  3039. net_time += frametime * g_pEngineToolInternal->GetTimescale();
  3040. #else
  3041. net_time += frametime * sv.GetTimescale();
  3042. #endif
  3043. }
  3044. /*
  3045. ====================
  3046. NET_RunFrame
  3047. RunFrame must be called each system frame before reading/sending on any socket
  3048. ====================
  3049. */
  3050. void NET_RunFrame( double realtime )
  3051. {
  3052. NET_SetTime( realtime );
  3053. RCONServer().RunFrame();
  3054. #ifdef ENABLE_RPT
  3055. RPTServer().RunFrame();
  3056. #endif
  3057. Con_RunFrame();
  3058. #ifndef DEDICATED
  3059. RCONClient().RunFrame();
  3060. #ifdef ENABLE_RPT
  3061. RPTClient().RunFrame();
  3062. #endif
  3063. #endif
  3064. #ifdef _X360
  3065. if ( net_logserver.GetInt() )
  3066. {
  3067. NET_LogServerStatus();
  3068. }
  3069. #endif
  3070. if ( g_pMatchFramework )
  3071. {
  3072. g_pMatchFramework->RunFrame();
  3073. }
  3074. if ( !NET_IsMultiplayer() || net_notcp )
  3075. return;
  3076. // process TCP sockets:
  3077. for ( int i=0; i< net_sockets.Count(); i++ )
  3078. {
  3079. if ( net_sockets[i].hTCP && net_sockets[i].bListening )
  3080. {
  3081. NET_ProcessListen( i );
  3082. }
  3083. }
  3084. NET_ProcessPending();
  3085. }
  3086. void NET_ClearLoopbackBuffers()
  3087. {
  3088. for (int i = 0; i < LOOPBACK_SOCKETS; i++)
  3089. {
  3090. loopback_t *loop = NULL;
  3091. while ( s_LoopBacks[i].PopItem( &loop ) )
  3092. {
  3093. if ( loop->data && loop->data != loop->defbuffer )
  3094. {
  3095. delete [] loop->data;
  3096. }
  3097. delete loop;
  3098. }
  3099. }
  3100. }
  3101. void NET_ConfigLoopbackBuffers( bool bAlloc )
  3102. {
  3103. NET_ClearLoopbackBuffers();
  3104. }
  3105. /*
  3106. ====================
  3107. NET_Config
  3108. A single player game will only use the loopback code
  3109. ====================
  3110. */
  3111. void NET_Config ( void )
  3112. {
  3113. // free anything
  3114. NET_CloseAllSockets(); // close all UDP/TCP sockets
  3115. net_time = 0.0f;
  3116. // now reconfigure
  3117. if ( net_multiplayer )
  3118. {
  3119. // don't allocate loopback buffers
  3120. NET_ConfigLoopbackBuffers( false );
  3121. // get localhost IP address
  3122. NET_GetLocalAddress();
  3123. // reopen sockets if in MP mode
  3124. NET_OpenSockets();
  3125. // setup the rcon server sockets
  3126. if ( net_dedicated || CommandLine()->FindParm( "-usercon" ) )
  3127. {
  3128. netadr_t rconAddr = net_local_adr;
  3129. rconAddr.SetPort( net_sockets[NS_SERVER].nPort );
  3130. RCONServer().SetAddress( rconAddr.ToString() );
  3131. RCONServer().CreateSocket();
  3132. }
  3133. }
  3134. else
  3135. {
  3136. // allocate loopback buffers
  3137. NET_ConfigLoopbackBuffers( true );
  3138. }
  3139. #if !defined( LINUX )
  3140. // note: linux prints out the network IP before calling this function
  3141. DevMsg( "Network: IP %s ", net_local_adr.ToString(true));
  3142. #endif
  3143. DevMsg( "mode %s, dedicated %s, ports %i SV / %i CL\n",
  3144. net_multiplayer?"MP":"SP", net_dedicated?"Yes":"No",
  3145. net_sockets[NS_SERVER].nPort, net_sockets[NS_CLIENT].nPort );
  3146. }
  3147. /*
  3148. ====================
  3149. NET_SetDedicated
  3150. A single player game will only use the loopback code
  3151. ====================
  3152. */
  3153. void NET_SetDedicated ()
  3154. {
  3155. if ( net_noip )
  3156. {
  3157. Msg( "Warning! Dedicated not possible with -noip parameter.\n");
  3158. return;
  3159. }
  3160. net_dedicated = true;
  3161. net_dedicatedForXbox = ( CommandLine()->FindParm( "-xlsp" ) != 0 );
  3162. net_dedicatedForXboxInsecure = ( CommandLine()->FindParm( "-xlsp_insecure" ) != 0 );
  3163. }
  3164. void NET_ListenSocket( int sock, bool bListen )
  3165. {
  3166. Assert( (sock >= 0) && (sock < net_sockets.Count()) );
  3167. netsocket_t * netsock = &net_sockets[sock];
  3168. if ( netsock->hTCP )
  3169. {
  3170. NET_CloseSocket( netsock->hTCP, sock );
  3171. }
  3172. if ( !NET_IsMultiplayer() || net_notcp )
  3173. return;
  3174. if ( bListen )
  3175. {
  3176. const char * net_interface = ipname.GetString();
  3177. netsock->hTCP = NET_OpenSocket( net_interface, netsock->nPort, true );
  3178. if ( !netsock->hTCP )
  3179. {
  3180. Msg( "Warning! NET_ListenSocket failed opening socket %i, port %i.\n", sock, net_sockets[sock].nPort );
  3181. return;
  3182. }
  3183. struct sockaddr_in address;
  3184. if (!net_interface || !net_interface[0] || !Q_strcmp(net_interface, "localhost"))
  3185. {
  3186. address.sin_addr.s_addr = INADDR_ANY;
  3187. }
  3188. else
  3189. {
  3190. NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
  3191. }
  3192. address.sin_family = AF_INET;
  3193. address.sin_port = NET_HostToNetShort((short)( netsock->nPort ));
  3194. int ret;
  3195. ret = bind( netsock->hTCP, (struct sockaddr *)&address, sizeof(address) );
  3196. if ( ret == -1 )
  3197. {
  3198. NET_GetLastError();
  3199. Msg ("WARNING: NET_ListenSocket bind failed on socket %i, port %i.\n", netsock->hTCP, netsock->nPort );
  3200. return;
  3201. }
  3202. ret = listen( netsock->hTCP, TCP_MAX_ACCEPTS );
  3203. if ( ret == -1 )
  3204. {
  3205. NET_GetLastError();
  3206. Msg ("WARNING: NET_ListenSocket listen failed on socket %i, port %i.\n", netsock->hTCP, netsock->nPort );
  3207. return;
  3208. }
  3209. netsock->bListening = true;
  3210. }
  3211. }
  3212. void NET_SetMultiplayer(bool multiplayer)
  3213. {
  3214. if ( net_noip && multiplayer )
  3215. {
  3216. Msg( "Warning! Multiplayer mode not available with -noip parameter.\n");
  3217. return;
  3218. }
  3219. if ( net_dedicated && !multiplayer )
  3220. {
  3221. Msg( "Warning! Singleplayer mode not available on dedicated server.\n");
  3222. return;
  3223. }
  3224. // reconfigure if changed
  3225. if ( net_multiplayer != multiplayer )
  3226. {
  3227. net_multiplayer = multiplayer;
  3228. NET_Config();
  3229. }
  3230. // clear loopback buffer in single player mode
  3231. if ( !multiplayer )
  3232. {
  3233. NET_ClearLoopbackBuffers();
  3234. }
  3235. }
  3236. void NET_InitPostFork( void )
  3237. {
  3238. if ( CommandLine()->FindParm( "-NoQueuedPacketThread" ) )
  3239. Warning( "Found -NoQueuedPacketThread, so no queued packet thread will be created.\n" );
  3240. else
  3241. g_pQueuedPackedSender->Setup();
  3242. }
  3243. //-----------------------------------------------------------------------------
  3244. // Purpose:
  3245. // Input : bIsDedicated -
  3246. //-----------------------------------------------------------------------------
  3247. void NET_Init( bool bIsDedicated )
  3248. {
  3249. // In dedicated server mode network must be initialized post-fork
  3250. // single entry guard
  3251. {
  3252. static bool sbNetworkingIntialized = false;
  3253. if ( sbNetworkingIntialized )
  3254. {
  3255. return;
  3256. }
  3257. sbNetworkingIntialized = true;
  3258. }
  3259. if (CommandLine()->FindParm("-nodns"))
  3260. {
  3261. net_nodns = true;
  3262. }
  3263. if (CommandLine()->FindParm("-usetcp"))
  3264. {
  3265. net_notcp = false;
  3266. }
  3267. if ( IsGameConsole() || CommandLine()->FindParm( "-nohltv" ) )
  3268. {
  3269. net_nohltv = true;
  3270. }
  3271. if ( CommandLine()->FindParm( "-addhltv1" ) )
  3272. {
  3273. net_addhltv1 = true;
  3274. }
  3275. #if defined( REPLAY_ENABLED )
  3276. if ( CommandLine()->FindParm("-noreplay"))
  3277. {
  3278. net_noreplay = true;
  3279. }
  3280. #endif
  3281. if (CommandLine()->FindParm("-noip"))
  3282. {
  3283. net_noip = true;
  3284. }
  3285. else
  3286. {
  3287. #if defined( _X360 )
  3288. XOnlineCleanup();
  3289. XNetStartupParams xnsp;
  3290. memset( &xnsp, 0, sizeof( xnsp ) );
  3291. xnsp.cfgSizeOfStruct = sizeof( XNetStartupParams );
  3292. if ( X360SecureNetwork() )
  3293. {
  3294. Msg( "Xbox 360 Network: Secure.\n" );
  3295. }
  3296. else
  3297. {
  3298. // Allow cross-platform communication
  3299. xnsp.cfgFlags = XNET_STARTUP_BYPASS_SECURITY;
  3300. Warning( "Xbox 360 Network: Security Bypassed.\n" );
  3301. }
  3302. // Prepare for the number of connections required by the title
  3303. g_pMatchFramework->GetMatchTitle()->PrepareNetStartupParams( &xnsp );
  3304. INT err = XNetStartup( &xnsp );
  3305. if ( err )
  3306. {
  3307. Warning( "Error! XNetStartup() failed, error %d.\n", err);
  3308. }
  3309. else
  3310. {
  3311. Msg( "\n"
  3312. "Xbox 360 secure network initialized:\n"
  3313. " flags: 0x%08X\n"
  3314. " reg XNKID/XNKEY: %d\n"
  3315. " reg XNADDR/XNKID: %d\n"
  3316. " max UDP sockets: %d\n"
  3317. " max TCP sockets: %d\n"
  3318. " buffer size recv: %d K\n"
  3319. " buffer size send: %d K\n"
  3320. " QOS reply size: %d b\n"
  3321. " QOS timeout: %d sec\n"
  3322. " QOS retries: %d\n"
  3323. " QOS responses: %d\n"
  3324. " QOS pair wait: %d sec\n"
  3325. "\n",
  3326. xnsp.cfgFlags,
  3327. xnsp.cfgSockMaxDgramSockets,
  3328. xnsp.cfgSockMaxStreamSockets,
  3329. xnsp.cfgSockDefaultRecvBufsizeInK,
  3330. xnsp.cfgSockDefaultSendBufsizeInK,
  3331. xnsp.cfgKeyRegMax,
  3332. xnsp.cfgSecRegMax,
  3333. xnsp.cfgQosDataLimitDiv4 * 4,
  3334. xnsp.cfgQosProbeTimeoutInSeconds,
  3335. xnsp.cfgQosProbeRetries,
  3336. xnsp.cfgQosSrvMaxSimultaneousResponses,
  3337. xnsp.cfgQosPairWaitTimeInSeconds
  3338. );
  3339. // initialize winsock 2.2
  3340. WSAData wsaData = {0};
  3341. err = WSAStartup( MAKEWORD(2,2), &wsaData );
  3342. if ( err != 0 )
  3343. {
  3344. Warning( "Error! Failed to WSAStartup! err = %d.\n", err );
  3345. net_noip = true;
  3346. }
  3347. else
  3348. {
  3349. Msg( "Socket layer initialized:\n"
  3350. " wsa ver used: %d.%d\n"
  3351. " wsa ver max: %d.%d\n"
  3352. " description: %s\n"
  3353. " sys status: %s\n"
  3354. "\n",
  3355. LOBYTE( wsaData.wVersion ), HIBYTE( wsaData.wVersion ),
  3356. LOBYTE( wsaData.wHighVersion ), HIBYTE( wsaData.wHighVersion ),
  3357. wsaData.szDescription,
  3358. wsaData.szSystemStatus
  3359. );
  3360. err = XOnlineStartup();
  3361. if ( err != ERROR_SUCCESS )
  3362. {
  3363. Warning( "Error! XOnlineStartup() failed, error %d.\n", err );
  3364. }
  3365. else
  3366. {
  3367. Msg( "XOnline services started.\n\n" );
  3368. }
  3369. }
  3370. }
  3371. #elif defined( _WIN32 )
  3372. // initialize winsock 2.0
  3373. WSAData wsaData;
  3374. if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )
  3375. {
  3376. ConMsg( "Error! Failed to load network socket library.\n");
  3377. net_noip = true;
  3378. }
  3379. #elif defined( _PS3 )
  3380. #if !defined( NO_STEAM )
  3381. // Steam initializes networking
  3382. if ( cellSysmoduleIsLoaded( CELL_SYSMODULE_NET ) != CELL_SYSMODULE_LOADED )
  3383. net_noip = true;
  3384. #else
  3385. int err = cellSysmoduleLoadModule( CELL_SYSMODULE_NET );
  3386. if ( err < 0 )
  3387. {
  3388. ConMsg( "Error! cellSysmoduleLoadModule error %d loading NET!\n", err );
  3389. net_noip = true;
  3390. }
  3391. else
  3392. {
  3393. Msg( "cellSysmoduleLoadModule loaded NET.\n" );
  3394. sys_net_initialize_parameter_t netParams;
  3395. memset( &netParams, 0, sizeof( netParams ) );
  3396. // Prepare for the number of connections required by the title
  3397. g_pMatchFramework->GetMatchTitle()->PrepareNetStartupParams( &netParams );
  3398. err = sys_net_initialize_network_ex( &netParams );
  3399. if ( err < 0 )
  3400. {
  3401. ConMsg( "Error! sys_net_initialize_network_ex error %d ( %d kBytes of memory allocated )!\n", err, netParams.memory_size / 1024 );
  3402. net_noip = true;
  3403. cellSysmoduleUnloadModule( CELL_SYSMODULE_NET );
  3404. }
  3405. else
  3406. {
  3407. Msg( "sys_net_initialize_network_ex succeeded ( %d kBytes of memory allocated )!\n", netParams.memory_size / 1024 );
  3408. int err = cellNetCtlInit();
  3409. // GSidhu - in case of NO_STEAM we try and init this lib twice
  3410. if ( (err < 0) && (err != CELL_NET_CTL_ERROR_NOT_TERMINATED) )
  3411. {
  3412. ConMsg( "Error! cellNetCtlInit error %d!\n", err );
  3413. net_noip = true;
  3414. // sys_net_finalize_network();
  3415. // cellSysmoduleUnloadModule( CELL_SYSMODULE_NET );
  3416. }
  3417. else
  3418. {
  3419. Msg( "cellNetCtlInit succeeded.\n\n" );
  3420. }
  3421. }
  3422. }
  3423. #endif // NO_STEAM
  3424. #endif
  3425. }
  3426. Assert( NET_MAX_PAYLOAD < (1<<NET_MAX_PAYLOAD_BITS) );
  3427. Assert( MAX_FILE_SIZE < (1<<MAX_FILE_SIZE_BITS) );
  3428. net_time = 0.0f;
  3429. //
  3430. // Process ports configuration
  3431. //
  3432. {
  3433. // Host port
  3434. int nHostPort = hostport.GetInt();
  3435. nHostPort = CommandLine()->ParmValue( "-port", nHostPort );
  3436. nHostPort = CommandLine()->ParmValue( "+port", nHostPort );
  3437. nHostPort = CommandLine()->ParmValue( "+hostport", nHostPort );
  3438. hostport.SetValue( nHostPort );
  3439. // Client port
  3440. int nClientPort = clientport.GetInt();
  3441. nClientPort = CommandLine()->ParmValue( "+clientport", nClientPort );
  3442. clientport.SetValue( nClientPort );
  3443. // HLTV ports
  3444. {
  3445. int nHltvPort = hltvport.GetInt();
  3446. nHltvPort = CommandLine()->ParmValue( "+tv_port", nHltvPort );
  3447. hltvport.SetValue( nHltvPort );
  3448. }
  3449. {
  3450. int nHltvPort1 = hltvport1.GetInt();
  3451. nHltvPort1 = CommandLine()->ParmValue( "+tv_port1", nHltvPort1 );
  3452. hltvport1.SetValue( nHltvPort1 );
  3453. }
  3454. }
  3455. // clear static stuff
  3456. net_sockets.EnsureCount( MAX_SOCKETS );
  3457. net_packets.EnsureCount( MAX_SOCKETS );
  3458. net_splitpackets.EnsureCount( MAX_SOCKETS );
  3459. for ( int i = 0; i < MAX_SOCKETS; ++i )
  3460. {
  3461. s_pLagData[i] = NULL;
  3462. Q_memset( &net_sockets[i], 0, sizeof(netsocket_t) );
  3463. }
  3464. if ( const char *ip = CommandLine()->ParmValue( "-ip" ) ) // if they had a command line option for IP
  3465. {
  3466. ipname.SetValue( ip ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  3467. }
  3468. if ( const char *ip_tv = CommandLine()->ParmValue( "-ip_tv" ) ) // if they had a command line option for IP for GOTV
  3469. {
  3470. ipname_tv.SetValue( ip_tv ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  3471. }
  3472. if ( const char *ip_tv1 = CommandLine()->ParmValue( "-ip_tv1" ) ) // if they had a command line option for IP for GOTV
  3473. {
  3474. ipname_tv1.SetValue( ip_tv1 ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  3475. }
  3476. if ( const char *ip_relay = CommandLine()->ParmValue( "-ip_relay" ) ) // if they had a command line option for IP relay for GOTV
  3477. {
  3478. ipname_relay.SetValue( ip_relay ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  3479. }
  3480. if ( const char *ip_steam = CommandLine()->ParmValue( "-ip_steam" ) ) // if they had a command line option for IP for Steam
  3481. {
  3482. ipname_steam.SetValue( ip_steam ); // update the cvar right now, this will get overwritten by "stuffcmds" later
  3483. }
  3484. if ( bIsDedicated )
  3485. {
  3486. // set dedicated MP mode
  3487. NET_SetDedicated();
  3488. }
  3489. else
  3490. {
  3491. // set SP mode
  3492. NET_ConfigLoopbackBuffers( true );
  3493. }
  3494. NET_InitParanoidMode();
  3495. NET_SetMultiplayer( !!( g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_SETTING_MULTIPLAYER ) );
  3496. // Go ahead and create steam datagram client, and start measuring pings to data centers
  3497. #ifndef DEDICATED
  3498. if ( CheckInitSteamDatagramClientLib() )
  3499. {
  3500. if ( ::SteamNetworkingUtils() )
  3501. ::SteamNetworkingUtils()->CheckPingDataUpToDate( 0.0f );
  3502. }
  3503. #endif
  3504. }
  3505. /*
  3506. ====================
  3507. NET_Shutdown
  3508. ====================
  3509. */
  3510. void NET_Shutdown (void)
  3511. {
  3512. int nError = 0;
  3513. for (int i = 0; i < MAX_SOCKETS; i++)
  3514. {
  3515. NET_ClearLaggedList( &s_pLagData[i] );
  3516. }
  3517. g_pQueuedPackedSender->Shutdown();
  3518. net_multiplayer = false;
  3519. net_dedicated = false;
  3520. NET_CloseAllSockets();
  3521. NET_ConfigLoopbackBuffers( false );
  3522. #ifndef DEDICATED
  3523. SteamDatagramClient_Kill();
  3524. #endif
  3525. #if defined(_WIN32)
  3526. if ( !net_noip )
  3527. {
  3528. #if defined(_X360)
  3529. nError = XOnlineCleanup();
  3530. if ( nError != ERROR_SUCCESS )
  3531. {
  3532. Msg( "Warning! Failed to complete XOnlineCleanup = 0x%x.\n", nError );
  3533. }
  3534. #endif // _X360
  3535. nError = WSACleanup();
  3536. if ( nError )
  3537. {
  3538. Msg("Failed to complete WSACleanup = 0x%x.\n", nError );
  3539. }
  3540. }
  3541. #elif defined( _PS3 )
  3542. #if !defined( NO_STEAM )
  3543. // Steam manages networking
  3544. #else
  3545. if ( !net_noip )
  3546. {
  3547. cellNetCtlTerm();
  3548. sys_net_finalize_network();
  3549. cellSysmoduleUnloadModule( CELL_SYSMODULE_NET );
  3550. }
  3551. #endif
  3552. #endif // _WIN32
  3553. Assert( s_NetChannels.Count() == 0 );
  3554. Assert( s_PendingSockets.Count() == 0);
  3555. }
  3556. void NET_PrintChannelStatus( INetChannel * chan )
  3557. {
  3558. Msg( "NetChannel '%s':\n", chan->GetName() );
  3559. Msg( "- remote IP: %s\n", chan->GetAddress() );
  3560. Msg( "- online: %s\n", COM_FormatSeconds( chan->GetTimeConnected() ) );
  3561. Msg( "- reliable: %s\n", chan->HasPendingReliableData()?"pending data":"available" );
  3562. Msg( "- latency: %.1f, loss %.2f\n", chan->GetAvgLatency(FLOW_OUTGOING), chan->GetAvgLoss(FLOW_INCOMING) );
  3563. Msg( "- packets: in %.1f/s, out %.1f/s\n", chan->GetAvgPackets(FLOW_INCOMING), chan->GetAvgPackets(FLOW_OUTGOING) );
  3564. Msg( "- choke: in %.2f, out %.2f\n", chan->GetAvgChoke(FLOW_INCOMING), chan->GetAvgChoke(FLOW_OUTGOING) );
  3565. Msg( "- flow: in %.1f, out %.1f kB/s\n", chan->GetAvgData(FLOW_INCOMING)/1024.0f, chan->GetAvgData(FLOW_OUTGOING)/1024.0f );
  3566. Msg( "- total: in %.1f, out %.1f MB\n\n", (float)chan->GetTotalData(FLOW_INCOMING)/(1024*1024), (float)chan->GetTotalData(FLOW_OUTGOING)/(1024*1024) );
  3567. }
  3568. CON_COMMAND( net_channels, "Shows net channel info" )
  3569. {
  3570. int numChannels = s_NetChannels.Count();
  3571. if ( numChannels == 0 )
  3572. {
  3573. ConMsg( "No active net channels.\n" );
  3574. return;
  3575. }
  3576. AUTO_LOCK_FM( s_NetChannels );
  3577. for ( int i = 0; i < numChannels; i++ )
  3578. {
  3579. NET_PrintChannelStatus( s_NetChannels[i] );
  3580. }
  3581. }
  3582. CON_COMMAND( net_start, "Inits multiplayer network sockets" )
  3583. {
  3584. net_multiplayer = true;
  3585. NET_Config();
  3586. }
  3587. CON_COMMAND( net_status, "Shows current network status" )
  3588. {
  3589. AUTO_LOCK_FM( s_NetChannels );
  3590. int numChannels = s_NetChannels.Count();
  3591. ConMsg("Net status for host %s:\n",
  3592. net_local_adr.ToString(true) );
  3593. ConMsg("- Config: %s, %s, %i connections\n",
  3594. net_multiplayer?"Multiplayer":"Singleplayer",
  3595. net_dedicated?"dedicated":"listen",
  3596. numChannels );
  3597. ConMsg("- Ports: " );
  3598. for ( int k = 0; k < MAX_SOCKETS; ++ k )
  3599. {
  3600. ConMsg( "%s%d %u, ", DescribeSocket( k ), k, NET_GetUDPPort( k ) );
  3601. }
  3602. ConMsg( "%d total.\n", MAX_SOCKETS );
  3603. if ( numChannels <= 0 )
  3604. {
  3605. return;
  3606. }
  3607. // gather statistics:
  3608. float avgLatencyOut = 0;
  3609. float avgLatencyIn = 0;
  3610. float avgPacketsOut = 0;
  3611. float avgPacketsIn = 0;
  3612. float avgLossOut = 0;
  3613. float avgLossIn = 0;
  3614. float avgDataOut = 0;
  3615. float avgDataIn = 0;
  3616. for ( int i = 0; i < numChannels; i++ )
  3617. {
  3618. CNetChan *chan = s_NetChannels[i];
  3619. avgLatencyOut += chan->GetAvgLatency(FLOW_OUTGOING);
  3620. avgLatencyIn += chan->GetAvgLatency(FLOW_INCOMING);
  3621. avgLossIn += chan->GetAvgLoss(FLOW_INCOMING);
  3622. avgLossOut += chan->GetAvgLoss(FLOW_OUTGOING);
  3623. avgPacketsIn += chan->GetAvgPackets(FLOW_INCOMING);
  3624. avgPacketsOut += chan->GetAvgPackets(FLOW_OUTGOING);
  3625. avgDataIn += chan->GetAvgData(FLOW_INCOMING);
  3626. avgDataOut += chan->GetAvgData(FLOW_OUTGOING);
  3627. }
  3628. ConMsg( "- Latency: avg out %.2fs, in %.2fs\n", avgLatencyOut/numChannels, avgLatencyIn/numChannels );
  3629. ConMsg( "- Loss: avg out %.1f, in %.1f\n", avgLossOut/numChannels, avgLossIn/numChannels );
  3630. ConMsg( "- Packets: net total out %.1f/s, in %.1f/s\n", avgPacketsOut, avgPacketsIn );
  3631. ConMsg( " per client out %.1f/s, in %.1f/s\n", avgPacketsOut/numChannels, avgPacketsIn/numChannels );
  3632. ConMsg( "- Data: net total out %.1f, in %.1f kB/s\n", avgDataOut/1024.0f, avgDataIn/1024.0f );
  3633. ConMsg( " per client out %.1f, in %.1f kB/s\n", (avgDataOut/numChannels)/1024.0f, (avgDataIn/numChannels)/1024.0f );
  3634. }
  3635. //-----------------------------------------------------------------------------
  3636. // Purpose: Generic buffer compression from source into dest
  3637. // Input : *dest -
  3638. // *destLen -
  3639. // *source -
  3640. // sourceLen -
  3641. // Output : int
  3642. //-----------------------------------------------------------------------------
  3643. bool NET_BufferToBufferCompress( char *dest, unsigned int *destLen, char *source, unsigned int sourceLen )
  3644. {
  3645. Assert( dest );
  3646. Assert( destLen );
  3647. Assert( source );
  3648. Q_memcpy( dest, source, sourceLen );
  3649. CLZSS s;
  3650. unsigned int uCompressedLen = 0;
  3651. byte *pbOut = s.Compress( (byte *)source, sourceLen, &uCompressedLen );
  3652. if ( pbOut && uCompressedLen > 0 && uCompressedLen <= *destLen )
  3653. {
  3654. Q_memcpy( dest, pbOut, uCompressedLen );
  3655. *destLen = uCompressedLen;
  3656. free( pbOut );
  3657. }
  3658. else
  3659. {
  3660. if ( pbOut )
  3661. {
  3662. free( pbOut );
  3663. }
  3664. Q_memcpy( dest, source, sourceLen );
  3665. *destLen = sourceLen;
  3666. return false;
  3667. }
  3668. return true;
  3669. }
  3670. //-----------------------------------------------------------------------------
  3671. // Purpose: Generic buffer decompression from source into dest
  3672. // Input : *dest -
  3673. // *destLen -
  3674. // *source -
  3675. // sourceLen -
  3676. // Output : int
  3677. //-----------------------------------------------------------------------------
  3678. bool NET_BufferToBufferDecompress( char *dest, unsigned int *destLen, char *source, unsigned int sourceLen )
  3679. {
  3680. CLZSS s;
  3681. if ( s.IsCompressed( (byte *)source ) )
  3682. {
  3683. unsigned int uDecompressedLen = s.GetActualSize( (byte *)source );
  3684. if ( uDecompressedLen > *destLen )
  3685. {
  3686. Warning( "NET_BufferToBufferDecompress with improperly sized dest buffer (%u in, %u needed)\n", *destLen, uDecompressedLen );
  3687. return false;
  3688. }
  3689. else
  3690. {
  3691. *destLen = s.SafeUncompress( (byte *)source, (byte *)dest, *destLen );
  3692. }
  3693. }
  3694. else
  3695. {
  3696. if ( sourceLen > *destLen )
  3697. {
  3698. Warning( "NET_BufferToBufferDecompress with improperly sized dest buffer (%u in, %u needed)\n", *destLen, sourceLen );
  3699. return false;
  3700. }
  3701. Q_memcpy( dest, source, sourceLen );
  3702. *destLen = sourceLen;
  3703. }
  3704. return true;
  3705. }
  3706. void NET_SleepUntilMessages( int nMilliseconds )
  3707. {
  3708. fd_set fdset;
  3709. FD_ZERO(&fdset);
  3710. if ( !net_sockets[NS_SERVER].hUDP )
  3711. {
  3712. Sys_Sleep( nMilliseconds );
  3713. return;
  3714. }
  3715. unsigned int nSocket = (unsigned int)net_sockets[NS_SERVER].hUDP;
  3716. FD_SET( nSocket, &fdset );
  3717. struct timeval tv = { 0 };
  3718. tv.tv_usec = nMilliseconds * 1000;
  3719. select( nSocket + 1, &fdset, NULL, NULL, &tv );
  3720. }
  3721. bool NET_GetPublicAdr( netadr_t &adr )
  3722. {
  3723. bool bRet = false;
  3724. unsigned short port = NET_GetUDPPort( NS_SERVER );
  3725. if ( net_public_adr.GetString()[ 0 ] )
  3726. {
  3727. bRet = true;
  3728. adr.SetType( NA_IP );
  3729. adr.SetFromString( net_public_adr.GetString() );
  3730. if ( adr.GetPort() == 0 )
  3731. adr.SetPort( port );
  3732. }
  3733. #if !defined( _X360 ) && !defined( NO_STEAM )
  3734. else if ( NET_IsDedicated() &&
  3735. Steam3Server().SteamGameServer()->GetPublicIP() != 0u )
  3736. {
  3737. bRet = true;
  3738. adr.SetType( NA_IP );
  3739. adr.SetIPAndPort( Steam3Server().SteamGameServer()->GetPublicIP(), port );
  3740. }
  3741. #endif
  3742. return bRet;
  3743. }
  3744. void NET_SteamDatagramServerListen()
  3745. {
  3746. // Receiving on steam datagram transport?
  3747. // We only open one interface object (corresponding to one UDP port).
  3748. // The other "sockets" are different channels on this interface
  3749. if ( sv_steamdatagramtransport_port.GetInt() == 0 )
  3750. return;
  3751. if ( g_pSteamDatagramGameserver )
  3752. return;
  3753. SteamDatagramErrMsg errMsg;
  3754. EResult result;
  3755. g_pSteamDatagramGameserver = SteamDatagram_GameserverListen( GetSteamUniverse(), sv_steamdatagramtransport_port.GetInt(), &result, errMsg );
  3756. if ( g_pSteamDatagramGameserver )
  3757. {
  3758. Msg( "Listening for Steam datagram transport on port %d\n", sv_steamdatagramtransport_port.GetInt() );
  3759. }
  3760. else
  3761. {
  3762. Warning( "SteamDatagram_GameserverListen failed with error code %d. %s\n", result, errMsg );
  3763. // Clear the convar so we don't advertise that we are listening!
  3764. sv_steamdatagramtransport_port.SetValue( 0 );
  3765. }
  3766. }
  3767. void NET_TerminateConnection( int sock, const ns_address &peer )
  3768. {
  3769. #if defined( USE_STEAM_SOCKETS )
  3770. if ( peer.IsType<netadr_t)() )
  3771. {
  3772. uint64 steamIDRemote = g_pSteamSocketMgr->GetSteamIDForRemote( peer.AsType<netadr_t>() );
  3773. NET_TerminateSteamConnection( steamIDRemote );
  3774. }
  3775. #endif
  3776. #ifndef DEDICATED
  3777. if ( peer == g_addrSteamDatagramProxiedGameServer )
  3778. CloseSteamDatagramClientConnection();
  3779. #endif
  3780. }
  3781. //////////////////////////////////////////////////////////////////////////
  3782. //
  3783. // Cryptography support code
  3784. //
  3785. //////////////////////////////////////////////////////////////////////////
  3786. #ifdef Verify
  3787. #undef Verify
  3788. #endif
  3789. #define bswap_16 __bswap_16
  3790. #define bswap_64 __bswap_64
  3791. #include "cryptlib.h"
  3792. #include "rsa.h"
  3793. #include "osrng.h"
  3794. using namespace CryptoPP;
  3795. typedef AutoSeededX917RNG<AES> CAutoSeededRNG;
  3796. // list of auto-seeded RNG pointers
  3797. // these are very expensive to construct, so it makes sense to cache them
  3798. CTSList<CAutoSeededRNG>&
  3799. GlobalRNGList()
  3800. {
  3801. static CTSList<CAutoSeededRNG> g_tslistPAutoSeededRNG;
  3802. return g_tslistPAutoSeededRNG;
  3803. }
  3804. // to avoid deconstructor order issuses we allow to manually free the list
  3805. void FreeListRNG()
  3806. {
  3807. GlobalRNGList().Purge();
  3808. }
  3809. //-----------------------------------------------------------------------------
  3810. // Purpose: thread-safe access to a pool of cryptoPP random number generators
  3811. //-----------------------------------------------------------------------------
  3812. class CPoolAllocatedRNG
  3813. {
  3814. public:
  3815. CPoolAllocatedRNG()
  3816. {
  3817. m_pRNGNode = GlobalRNGList().Pop();
  3818. if ( !m_pRNGNode )
  3819. {
  3820. m_pRNGNode = new CTSList<CAutoSeededRNG>::Node_t;
  3821. }
  3822. }
  3823. ~CPoolAllocatedRNG()
  3824. {
  3825. GlobalRNGList().Push( m_pRNGNode );
  3826. }
  3827. CAutoSeededRNG &GetRNG()
  3828. {
  3829. return m_pRNGNode->elem;
  3830. }
  3831. private:
  3832. CTSList<CAutoSeededRNG>::Node_t *m_pRNGNode;
  3833. };
  3834. //////////////////////////////////////////////////////////////////////////
  3835. //
  3836. // Encrypted networking
  3837. //
  3838. //////////////////////////////////////////////////////////////////////////
  3839. bool NET_CryptVerifyServerCertificateAndAllocateSessionKey( bool bOfficial, const ns_address &from,
  3840. const byte *pchKeyPub, int numKeyPub,
  3841. const byte *pchKeySgn, int numKeySgn,
  3842. byte **pbAllocatedKey, int *pnAllocatedCryptoBlockSize )
  3843. {
  3844. static const byte CsgoMasterPublicKey[] = { 0 }; // Removed for partner depot
  3845. // For now, only IPv4 addresses allowed. Shouldn't be too hard to figure out how to
  3846. // generate blocks to sign for other types of addresses
  3847. uint32 unCertIP = 0;
  3848. switch ( from.GetAddressType() )
  3849. {
  3850. case NSAT_NETADR:
  3851. unCertIP = from.AsType<netadr_t>().GetIPHostByteOrder();
  3852. break;
  3853. case NSAT_PROXIED_GAMESERVER:
  3854. {
  3855. unCertIP = SteamNetworkingUtils()->GetIPForServerSteamIDFromTicket( from.m_steamID.GetSteamID() );
  3856. if ( unCertIP == 0 )
  3857. {
  3858. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey - cannot check signature for proxied server '%s', because we don't have an SDR ticket to that server.\n", ns_address_render( from ).String() );
  3859. Assert(false);
  3860. return false;
  3861. }
  3862. break;
  3863. }
  3864. }
  3865. if ( unCertIP == 0 )
  3866. {
  3867. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey - cannot check signature for '%s', cannot determine IP to use\n", ns_address_render( from ).String() );
  3868. Assert(false);
  3869. return false;
  3870. }
  3871. //
  3872. // Verify certificate
  3873. //
  3874. bool bCertificateValidated = false;
  3875. for ( int numAddrBits = 32; ( numAddrBits >= 16 ) && !bCertificateValidated; -- numAddrBits )
  3876. {
  3877. CUtlBuffer bufSignature;
  3878. try // handle any exceptions crypto++ may throw
  3879. {
  3880. StringSource stringSourcePublicKey( CsgoMasterPublicKey, Q_ARRAYSIZE( CsgoMasterPublicKey ), true );
  3881. RSASSA_PKCS1v15_SHA_Verifier pub( stringSourcePublicKey );
  3882. CUtlBuffer bufDataFile;
  3883. bufDataFile.EnsureCapacity( numKeyPub + 20 );
  3884. bufDataFile.Put( pchKeyPub, numKeyPub );
  3885. netadr_t adrMasked( unCertIP & ( (~0) << (32-numAddrBits) ), 0 );
  3886. char chBuffer[20] = {};
  3887. V_sprintf_safe( chBuffer, "%s/%u", adrMasked.ToString( true ), numAddrBits );
  3888. bufDataFile.Put( chBuffer, V_strlen( chBuffer ) );
  3889. bCertificateValidated = pub.VerifyMessage( ( byte* ) bufDataFile.Base(), bufDataFile.TellPut(), pchKeySgn, numKeySgn );
  3890. #ifdef _DEBUG
  3891. DevMsg( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: VerifyMessage for %s %s\n",
  3892. chBuffer, bCertificateValidated ? "succeeded" : "failed" );
  3893. #endif
  3894. }
  3895. catch ( Exception e )
  3896. {
  3897. #ifdef _DEBUG
  3898. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: VerifyMessage threw exception %s (%d)\n",
  3899. e.what(), e.GetErrorType() );
  3900. #endif
  3901. }
  3902. catch ( ... )
  3903. {
  3904. #ifdef _DEBUG
  3905. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: VerifyMessage threw unknown exception\n" );
  3906. #endif
  3907. }
  3908. }
  3909. if ( !bCertificateValidated )
  3910. return false;
  3911. //
  3912. // Allocate client key
  3913. //
  3914. float flTime = Plat_FloatTime();
  3915. RandomSeed( * reinterpret_cast< int * >( &flTime ) );
  3916. byte ubClientKey[NET_CRYPT_KEY_LENGTH];
  3917. for ( int j = 0; j < NET_CRYPT_KEY_LENGTH; ++j )
  3918. {
  3919. ubClientKey[ j ] = ( byte ) ( unsigned int ) RandomInt( 0, 255 );
  3920. }
  3921. //
  3922. // Encrypt client key using the public key
  3923. //
  3924. try // handle any exceptions crypto++ may throw
  3925. {
  3926. StringSource stringSourcePublicKey( pchKeyPub, numKeyPub, true );
  3927. RSAES_OAEP_SHA_Encryptor rsaEncryptor( stringSourcePublicKey );
  3928. // calculate how many blocks of encryption will we need to do
  3929. AssertFatal( rsaEncryptor.FixedMaxPlaintextLength() <= UINT32_MAX );
  3930. uint32 cBlocks = 1 + ( ( NET_CRYPT_KEY_LENGTH - 1 ) / ( uint32 ) rsaEncryptor.FixedMaxPlaintextLength() );
  3931. // calculate how big the output will be
  3932. AssertFatal( rsaEncryptor.FixedCiphertextLength() <= UINT32_MAX / cBlocks );
  3933. uint32 cubCipherText = cBlocks * ( uint32 ) rsaEncryptor.FixedCiphertextLength();
  3934. // ensure there is sufficient room in output buffer for result
  3935. byte *pbResult = new byte[ NET_CRYPT_KEY_LENGTH + cubCipherText ];
  3936. Q_memcpy( pbResult, ubClientKey, NET_CRYPT_KEY_LENGTH );
  3937. *pbAllocatedKey = pbResult;
  3938. *pnAllocatedCryptoBlockSize = cubCipherText;
  3939. // Encryption pass
  3940. uint32 cubPlaintextData = NET_CRYPT_KEY_LENGTH;
  3941. const byte *pubPlaintextData = ubClientKey;
  3942. byte *pubEncryptedData = pbResult + NET_CRYPT_KEY_LENGTH;
  3943. // encrypt the message, using as many blocks as required
  3944. CPoolAllocatedRNG rng;
  3945. for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ )
  3946. {
  3947. // encrypt either all remaining plaintext, or maximum allowed plaintext per RSA encryption operation
  3948. uint32 cubToEncrypt = MIN( cubPlaintextData, ( uint32 ) rsaEncryptor.FixedMaxPlaintextLength() );
  3949. // encrypt the plaintext
  3950. rsaEncryptor.Encrypt( rng.GetRNG(), pubPlaintextData, cubToEncrypt, pubEncryptedData );
  3951. // adjust input and output pointers and remaining plaintext byte count
  3952. pubPlaintextData += cubToEncrypt;
  3953. cubPlaintextData -= cubToEncrypt;
  3954. pubEncryptedData += rsaEncryptor.FixedCiphertextLength();
  3955. }
  3956. Assert( 0 == cubPlaintextData ); // should have no remaining plaintext to encrypt
  3957. #ifdef _DEBUG
  3958. DevMsg( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: Encrypted %u bytes key as %u bytes ciphertext\n",
  3959. NET_CRYPT_KEY_LENGTH, cubCipherText );
  3960. #endif
  3961. return true;
  3962. }
  3963. catch ( Exception e )
  3964. {
  3965. #ifdef _DEBUG
  3966. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: Encrypt threw exception %s (%d)\n",
  3967. e.what(), e.GetErrorType() );
  3968. #endif
  3969. return false;
  3970. }
  3971. catch ( ... )
  3972. {
  3973. #ifdef _DEBUG
  3974. Warning( "NET_CryptVerifyServerCertificateAndAllocateSessionKey: Encrypt threw unknown exception\n" );
  3975. #endif
  3976. return false;
  3977. }
  3978. }
  3979. bool NET_CryptVerifyClientSessionKey( bool bOfficial,
  3980. const byte *pchKeyPri, int numKeyPri,
  3981. const byte *pbEncryptedKey, int numEncryptedBytes,
  3982. byte *pbPlainKey, int numPlainKeyBytes )
  3983. {
  3984. try // handle any exceptions crypto++ may throw
  3985. {
  3986. StringSource stringSourcePrivateKey( pchKeyPri, numKeyPri, true );
  3987. RSAES_OAEP_SHA_Decryptor rsaDecryptor( stringSourcePrivateKey );
  3988. // calculate how many blocks of decryption will we need to do
  3989. AssertFatal( rsaDecryptor.FixedCiphertextLength() <= UINT32_MAX );
  3990. uint32 cubFixedCiphertextLength = ( uint32 ) rsaDecryptor.FixedCiphertextLength();
  3991. // Ensure encrypted data is valid and has length that is exact multiple of 128 bytes
  3992. uint32 cubEncryptedData = numEncryptedBytes;
  3993. if ( 0 != ( cubEncryptedData % cubFixedCiphertextLength ) )
  3994. {
  3995. #ifdef _DEBUG
  3996. Warning( "NET_CryptVerifyClientSessionKey: invalid ciphertext length %d, needs to be a multiple of %d\n",
  3997. cubEncryptedData, cubFixedCiphertextLength );
  3998. #endif
  3999. return false;
  4000. }
  4001. uint32 cBlocks = cubEncryptedData / cubFixedCiphertextLength;
  4002. // calculate how big the maximum output will be
  4003. size_t cubMaxPlaintext = rsaDecryptor.MaxPlaintextLength( rsaDecryptor.FixedCiphertextLength() );
  4004. AssertFatal( cubMaxPlaintext <= UINT32_MAX / cBlocks );
  4005. uint32 cubPlaintextDataMax = cBlocks * ( uint32 ) cubMaxPlaintext;
  4006. Assert( cubPlaintextDataMax > 0 );
  4007. // ensure there is sufficient room in output buffer for result
  4008. if ( int( cubPlaintextDataMax ) >= numPlainKeyBytes )
  4009. {
  4010. #ifdef _DEBUG
  4011. Warning( "NET_CryptVerifyClientSessionKey: insufficient output buffer for decryption, needed %d got %d\n",
  4012. cubPlaintextDataMax, numPlainKeyBytes );
  4013. #endif
  4014. return false;
  4015. }
  4016. // decrypt the data, using as many blocks as required
  4017. CPoolAllocatedRNG rng;
  4018. uint32 cubPlaintextData = 0;
  4019. for ( uint32 nBlock = 0; nBlock < cBlocks; nBlock++ )
  4020. {
  4021. // decrypt one block (always of fixed size)
  4022. int cubToDecrypt = cubFixedCiphertextLength;
  4023. DecodingResult decodingResult = rsaDecryptor.Decrypt( rng.GetRNG(), pbEncryptedKey, cubToDecrypt, pbPlainKey );
  4024. if ( !decodingResult.isValidCoding )
  4025. {
  4026. #ifdef _DEBUG
  4027. Warning( "NET_CryptVerifyClientSessionKey: failed to decrypt\n" );
  4028. #endif
  4029. return false;
  4030. }
  4031. // adjust input and output pointers and remaining encrypted byte count
  4032. pbEncryptedKey += cubToDecrypt;
  4033. cubEncryptedData -= cubToDecrypt;
  4034. pbPlainKey += decodingResult.messageLength;
  4035. AssertFatal( decodingResult.messageLength <= UINT32_MAX );
  4036. cubPlaintextData += ( uint32 ) decodingResult.messageLength;
  4037. }
  4038. Assert( 0 == cubEncryptedData ); // should have no remaining encrypted data to decrypt
  4039. if ( cubPlaintextData != NET_CRYPT_KEY_LENGTH )
  4040. {
  4041. #ifdef _DEBUG
  4042. Warning( "NET_CryptVerifyClientSessionKey: decrypted %u bytes when expecting %u bytes\n", cubPlaintextData, NET_CRYPT_KEY_LENGTH );
  4043. #endif
  4044. return false;
  4045. }
  4046. return true;
  4047. }
  4048. catch ( Exception e )
  4049. {
  4050. #ifdef _DEBUG
  4051. Warning( "NET_CryptVerifyClientSessionKey: Decrypt threw exception %s (%d)\n",
  4052. e.what(), e.GetErrorType() );
  4053. #endif
  4054. return false;
  4055. }
  4056. catch ( ... )
  4057. {
  4058. #ifdef _DEBUG
  4059. Warning( "NET_CryptVerifyClientSessionKey: Decrypt threw unknown exception\n" );
  4060. #endif
  4061. return false;
  4062. }
  4063. }
  4064. bool NET_CryptGetNetworkCertificate( ENetworkCertificate_t eType, const byte **pbData, int *pnumBytes )
  4065. {
  4066. static char const *s_szCertificateFile = CommandLine()->ParmValue( "-certificate", ( char const * ) NULL );
  4067. if ( !s_szCertificateFile )
  4068. return false;
  4069. static bool s_bCertificateFilesLoaded = false;
  4070. static CUtlBuffer bufCertificate;
  4071. static int s_nCertificateOffset[ k_ENetworkCertificate_Max ] = {};
  4072. static int s_nCertificateLength[ k_ENetworkCertificate_Max ] = {};
  4073. if ( !s_bCertificateFilesLoaded )
  4074. {
  4075. s_bCertificateFilesLoaded = true;
  4076. if ( !g_pFullFileSystem->ReadFile( s_szCertificateFile, NULL, bufCertificate ) ||
  4077. !bufCertificate.Base() || ( bufCertificate.Size() < ( k_ENetworkCertificate_Max + 1 ) * 3 * sizeof( int ) ) )
  4078. {
  4079. Warning( "NET_CryptGetNetworkCertificate failed to load certificate '%s'\n", s_szCertificateFile );
  4080. Plat_ExitProcess( 0 ); // we must exit process, but we will skip writing the core dump
  4081. return false;
  4082. }
  4083. if ( V_memcmp( bufCertificate.Base(), "CSv1", 4 ) )
  4084. {
  4085. Warning( "NET_CryptGetNetworkCertificate certificate version mismatch '%s'\n", s_szCertificateFile );
  4086. Plat_ExitProcess( 0 ); // we must exit process, but we will skip writing the core dump
  4087. return false;
  4088. }
  4089. bufCertificate.GetInt(); // CSv1
  4090. int nTOC = bufCertificate.GetInt();
  4091. if ( nTOC != k_ENetworkCertificate_Max )
  4092. {
  4093. Warning( "NET_CryptGetNetworkCertificate certificate TOC length mismatch '%s'\n", s_szCertificateFile );
  4094. Plat_ExitProcess( 0 ); // we must exit process, but we will skip writing the core dump
  4095. return false;
  4096. }
  4097. for ( int j = 0; j < k_ENetworkCertificate_Max; ++ j )
  4098. {
  4099. int nFileID = bufCertificate.GetInt();
  4100. if ( nFileID != j )
  4101. {
  4102. Warning( "NET_CryptGetNetworkCertificate certificate TOC entry %d invalid in '%s'\n", j, s_szCertificateFile );
  4103. Plat_ExitProcess( 0 ); // we must exit process, but we will skip writing the core dump
  4104. return false;
  4105. }
  4106. s_nCertificateOffset[j] = bufCertificate.GetInt();
  4107. s_nCertificateLength[j] = bufCertificate.GetInt();
  4108. }
  4109. }
  4110. *pbData = ( ( const byte * ) bufCertificate.Base() ) + s_nCertificateOffset[eType];
  4111. *pnumBytes = s_nCertificateLength[eType];
  4112. return true;
  4113. }
  4114. #ifdef _DEBUG
  4115. CON_COMMAND( net_encrypt_key_generate, "Generate a public/private keypair" )
  4116. {
  4117. if ( args.ArgC() <= 2 )
  4118. {
  4119. Warning( "Usage: net_encrypt_key_generate <numbits> <filename>\n" );
  4120. return;
  4121. }
  4122. uint32 cKeyBits = Q_atoi( args.Arg( 1 ) );
  4123. bool bSuccess = false;
  4124. std::string strPrivateKey;
  4125. std::string strPublicKey;
  4126. try // handle any exceptions crypto++ may throw
  4127. {
  4128. // generate private key
  4129. StringSink stringSinkPrivateKey( strPrivateKey );
  4130. CPoolAllocatedRNG rng;
  4131. RSAES_OAEP_SHA_Decryptor priv( rng.GetRNG(), cKeyBits );
  4132. priv.DEREncode( stringSinkPrivateKey );
  4133. // generate public key
  4134. StringSink stringSinkPublicKey( strPublicKey );
  4135. RSAES_OAEP_SHA_Encryptor pub( priv );
  4136. pub.DEREncode( stringSinkPublicKey );
  4137. bSuccess = true;
  4138. }
  4139. catch ( Exception e )
  4140. {
  4141. Warning( "net_encrypt_key_generate: crypto++ threw exception %s (%d)\n",
  4142. e.what(), e.GetErrorType() );
  4143. }
  4144. catch ( ... )
  4145. {
  4146. Warning( "net_encrypt_key_generate: crypto++ threw unknown exception\n" );
  4147. }
  4148. if ( bSuccess )
  4149. {
  4150. char chFile[256];
  4151. CUtlBuffer bufPrivate( strPrivateKey.c_str(), strPrivateKey.length(), CUtlBuffer::READ_ONLY );
  4152. V_sprintf_safe( chFile, "%s.private", args.Arg( 2 ) );
  4153. if ( !g_pFullFileSystem->WriteFile( chFile, NULL, bufPrivate ) )
  4154. {
  4155. Warning( "net_encrypt_key_generate: failed to write %u bits keypair file '%s'\n", cKeyBits, chFile );
  4156. return;
  4157. }
  4158. CUtlBuffer bufPublic( strPublicKey.c_str(), strPublicKey.length(), CUtlBuffer::READ_ONLY );
  4159. V_sprintf_safe( chFile, "%s.public", args.Arg( 2 ) );
  4160. if ( !g_pFullFileSystem->WriteFile( chFile, NULL, bufPublic ) )
  4161. {
  4162. Warning( "net_encrypt_key_generate: failed to write %u bits keypair file '%s'\n", cKeyBits, chFile );
  4163. return;
  4164. }
  4165. Msg( "net_encrypt_key_generate: wrote %u bits keypair files '%s.private/public'\n", cKeyBits, args.Arg( 2 ) );
  4166. }
  4167. else
  4168. {
  4169. Warning( "net_encrypt_key_generate: failed to generate %u bits keypair files '%s.private/public'\n", cKeyBits, args.Arg( 2 ) );
  4170. }
  4171. }
  4172. CON_COMMAND( net_encrypt_key_signature, "Compute key signature for the payloads" )
  4173. {
  4174. if ( args.ArgC() <= 4 )
  4175. {
  4176. Warning( "Usage: net_encrypt_key_signature <file.privatekey> <file.payload> <string.payload> <output.file>\n" );
  4177. return;
  4178. }
  4179. bool bRet = false;
  4180. CUtlBuffer bufSignature;
  4181. try // handle any exceptions crypto++ may throw
  4182. {
  4183. CUtlBuffer bufPrivateKey;
  4184. if ( !g_pFullFileSystem->ReadFile( args.Arg( 1 ), NULL, bufPrivateKey ) )
  4185. {
  4186. Warning( "net_encrypt_key_signature: failed to read private key file '%s'\n", args.Arg( 1 ) );
  4187. return;
  4188. }
  4189. CUtlBuffer bufDataFile;
  4190. if ( !g_pFullFileSystem->ReadFile( args.Arg( 2 ), NULL, bufDataFile ) )
  4191. {
  4192. Warning( "net_encrypt_key_signature: failed to read data file '%s'\n", args.Arg( 2 ) );
  4193. return;
  4194. }
  4195. char const *szStringPayload = args.Arg( 3 );
  4196. int nStringPayloadLength = Q_strlen( szStringPayload );
  4197. if ( nStringPayloadLength > 0 )
  4198. bufDataFile.Put( szStringPayload, nStringPayloadLength );
  4199. StringSource stringSourcePrivateKey( ( byte * ) bufPrivateKey.Base(), bufPrivateKey.TellPut(), true );
  4200. RSASSA_PKCS1v15_SHA_Signer rsaSigner( stringSourcePrivateKey );
  4201. CPoolAllocatedRNG rng;
  4202. bufSignature.EnsureCapacity( rsaSigner.MaxSignatureLength() );
  4203. {
  4204. size_t len = rsaSigner.SignMessage( rng.GetRNG(), ( byte * ) bufDataFile.Base(), bufDataFile.TellPut(), ( byte * ) bufSignature.Base() );
  4205. bufSignature.SeekPut( CUtlBuffer::SEEK_HEAD, ( int32 ) ( uint32 ) len );
  4206. bRet = true;
  4207. Msg( "net_encrypt_key_signature: generated %u bytes signature for payload data +%u=%u bytes\n", bufSignature.TellPut(), nStringPayloadLength, bufDataFile.TellPut() );
  4208. }
  4209. }
  4210. catch ( Exception e )
  4211. {
  4212. Warning( "net_encrypt_key_signature: SignMessage threw exception %s (%d)\n",
  4213. e.what(), e.GetErrorType() );
  4214. }
  4215. catch ( ... )
  4216. {
  4217. Warning( "net_encrypt_key_signature: SignMessage threw unknown exception\n" );
  4218. }
  4219. if ( bRet )
  4220. {
  4221. if ( !g_pFullFileSystem->WriteFile( args.Arg( 4 ), NULL, bufSignature ) )
  4222. {
  4223. Warning( "net_encrypt_key_signature: failed to write file '%s'\n", args.Arg( 4 ) );
  4224. return;
  4225. }
  4226. Msg( "net_encrypt_key_generate: wrote %u bytes signature file '%s'\n", bufSignature.TellPut(), args.Arg( 4 ) );
  4227. }
  4228. else
  4229. {
  4230. Warning( "net_encrypt_key_signature: failed\n" );
  4231. }
  4232. }
  4233. CON_COMMAND( net_encrypt_key_compress, "Compress all key signatures into a single file" )
  4234. {
  4235. if ( args.ArgC() <= 1 )
  4236. {
  4237. Warning( "Usage: net_encrypt_key_compress <file>\n" );
  4238. return;
  4239. }
  4240. CUtlBuffer bufComposite;
  4241. char const * arrFiles[] = { "public", "private", "signature" }; // ENetworkCertificate_t order
  4242. CUtlBuffer bufData[ Q_ARRAYSIZE( arrFiles ) ];
  4243. for ( int j = 0; j < Q_ARRAYSIZE( arrFiles ); ++ j )
  4244. {
  4245. char chFile[ 1024 ] = {};
  4246. V_sprintf_safe( chFile, "%s.%s", args.Arg( 1 ), arrFiles[j] );
  4247. if ( !g_pFullFileSystem->ReadFile( chFile, NULL, bufData[j] ) )
  4248. {
  4249. Warning( "net_encrypt_key_compress: failed to read data file '%s'\n", chFile );
  4250. return;
  4251. }
  4252. }
  4253. bufComposite.Put( "CSv1", 4 );
  4254. bufComposite.PutInt( Q_ARRAYSIZE( arrFiles ) );
  4255. int nDataOffsetBase = bufComposite.TellPut() + Q_ARRAYSIZE( arrFiles )*3*4;
  4256. int nDataOffset = nDataOffsetBase;
  4257. for ( int j = 0; j < Q_ARRAYSIZE( arrFiles ); ++ j )
  4258. {
  4259. bufComposite.PutInt( j ); // file ID
  4260. bufComposite.PutInt( nDataOffset ); // offset
  4261. bufComposite.PutInt( bufData[j].TellPut() ); // length
  4262. nDataOffset += bufData[j].TellPut();
  4263. }
  4264. if ( bufComposite.TellPut() != nDataOffsetBase )
  4265. {
  4266. Warning( "net_encrypt_key_compress: failed to align composite TOC for '%s'\n", args.Arg( 1 ) );
  4267. return;
  4268. }
  4269. for ( int j = 0; j < Q_ARRAYSIZE( arrFiles ); ++ j )
  4270. {
  4271. bufComposite.Put( bufData[j].Base(), bufData[j].TellPut() );
  4272. }
  4273. if ( !g_pFullFileSystem->WriteFile( args.Arg( 1 ), NULL, bufComposite ) )
  4274. {
  4275. Warning( "net_encrypt_key_compress: failed to write file '%s'\n", args.Arg( 1 ) );
  4276. return;
  4277. }
  4278. for ( int j = 0; j < Q_ARRAYSIZE( arrFiles ); ++ j )
  4279. {
  4280. char chFile[ 1024 ] = {};
  4281. V_sprintf_safe( chFile, "%s.%s", args.Arg( 1 ), arrFiles[j] );
  4282. g_pFullFileSystem->RemoveFile( chFile );
  4283. }
  4284. Msg( "net_encrypt_key_compress: compressed file '%s' (%u bytes)\n", args.Arg( 1 ), bufComposite.TellPut() );
  4285. }
  4286. CON_COMMAND( net_encrypt_key_make_clusters, "Generate certificates and their signatures using master key" )
  4287. {
  4288. if ( args.ArgC() <= 2 )
  4289. {
  4290. Warning( "Usage: net_encrypt_key_make_clusters <numbits> <file.privatekey>\n" );
  4291. return;
  4292. }
  4293. char const * arrAddressMasks[] = {
  4294. // "atl-1", "162.254.199.0/25" ,
  4295. // "dxb-1", "185.25.183.0/25" ,
  4296. // "eat-1", "192.69.96.0/23" ,
  4297. // "eat-2", "192.69.96.0/23" ,
  4298. // "eat-3", "192.69.96.0/23" ,
  4299. // "eat-4", "192.69.96.0/23" ,
  4300. // "gru-4", "205.185.194.0/24" ,
  4301. // "iad-1", "208.78.164.90/23" ,
  4302. // "iad-2", "208.78.164.0/23" ,
  4303. // "iad-3", "208.78.164.0/23" ,
  4304. // "iad-4", "208.78.166.0/24" ,
  4305. // "lax-1", "162.254.194.0/24" ,
  4306. // "lux-1", "146.66.152.0/23" ,
  4307. // "lux-2", "146.66.152.0/23" ,
  4308. // "lux-3", "146.66.152.0/23" ,
  4309. // "lux-4", "146.66.158.0/23" ,
  4310. // "lux-5", "146.66.158.0/23" ,
  4311. // "lux-6", "146.66.158.0/23" ,
  4312. // "lux-7", "155.133.240.0/23" ,
  4313. // "lux-8", "155.133.240.0/23" ,
  4314. // "sgp-1", "103.28.54.0/23" ,
  4315. // "sgp-2", "103.28.54.0/23" ,
  4316. // "sgp-3", "103.28.54.0/23" ,
  4317. // "sto-1", "146.66.156.0/23" ,
  4318. // "sto-2", "146.66.156.0/23" ,
  4319. // "sto-3", "146.66.156.0/23" ,
  4320. // "sto-4", "185.25.180.0/23" ,
  4321. // "sto-5", "185.25.180.0/23" ,
  4322. // "sto-6", "185.25.180.0/23" ,
  4323. // "sto-7", "155.133.242.0/23" ,
  4324. // "sto-8", "155.133.242.0/23" ,
  4325. // "syd-1", "103.10.125.0/24",
  4326. // "vie-1", "146.66.155.0/24" ,
  4327. // "vie-2", "185.25.182.0/24" ,
  4328. // "jhb-1", "197.80.200.48/29" ,
  4329. "jhb-1", "155.133.238.0/24" ,
  4330. "jhb-2", "155.133.238.0/24" ,
  4331. // "cpt-1", "197.84.209.20/30",
  4332. // "bom-1", "45.113.191.128/27",
  4333. // "bom-1", "45.113.137.128/27",
  4334. // "tyo-1", "45.121.186.0/23",
  4335. // "tyo-2", "45.121.186.0/23",
  4336. // "hkg-1", "155.133.244.0/24",
  4337. // "mad-1", "155.133.246.0/23",
  4338. // "blv-1", "172.16.0.0/16",
  4339. // "scl-1", "155.133.249.0/24",
  4340. // "lim-1", "143.137.146.0/24",
  4341. // "ord-1", "155.133.226.0/24",
  4342. // "vie-3", "155.133.228.0/23",
  4343. // "syd-2", "155.133.227.0/24",
  4344. // "gru-5", "155.133.224.0/23",
  4345. // "jhb-2", "155.133.238.0/24",
  4346. // "bom-2", "155.133.233.0/24",
  4347. // "maa-1", "155.133.232.0/24",
  4348. // "waw-1", "155.133.230.0/23",
  4349. // "lim-2", "190.216.121.0/24",
  4350. // "atl-2", "155.133.234.0/24",
  4351. // "ord-1", "208.78.167.0/24",
  4352. // "ord-2", "208.78.167.0/24",
  4353. // "tsn-1", "125.39.181.0/24",
  4354. // "tsn-2", "60.28.165.128/25",
  4355. // "can-2", "125.88.174.0/24",
  4356. // "sha-3", "121.46.225.0/24",
  4357. // "eleague-major-atlanta-2017", "172.27.10.20/31",
  4358. };
  4359. for ( int j = 0; j < Q_ARRAYSIZE( arrAddressMasks )/2; ++j )
  4360. {
  4361. char const *szName = arrAddressMasks[ 2*j ];
  4362. char const *szAddr = arrAddressMasks[ 2*j+1 ];
  4363. char const *szSlash = strchr( szAddr, '/' );
  4364. if ( !szSlash ) continue;
  4365. char chBuffer[ 1024 ] = {};
  4366. V_sprintf_safe( chBuffer, "net_encrypt_key_generate %s %s.certificate;\n", args.Arg( 1 ), szName );
  4367. Cbuf_AddText( CBUF_FIRST_PLAYER, chBuffer );
  4368. V_sprintf_safe( chBuffer, "net_encrypt_key_signature \"%s\" %s.certificate.public \"%s\" %s.certificate.signature;",
  4369. args.Arg( 2 ), szName, szAddr, szName );
  4370. Cbuf_AddText( CBUF_FIRST_PLAYER, chBuffer );
  4371. V_sprintf_safe( chBuffer, "net_encrypt_key_compress %s.certificate;\n", szName );
  4372. Cbuf_AddText( CBUF_FIRST_PLAYER, chBuffer );
  4373. Cbuf_Execute();
  4374. }
  4375. }
  4376. #endif