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.

466 lines
12 KiB

  1. //====== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Utility class to help in socket creation. Works for clients + servers
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #if defined(_WIN32)
  8. #if !defined(_X360)
  9. #include <winsock.h>
  10. #endif
  11. #undef SetPort // winsock screws with the SetPort string... *sigh*
  12. #define socklen_t int
  13. #define MSG_NOSIGNAL 0
  14. #elif defined(PLATFORM_POSIX)
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include <netinet/tcp.h>
  19. #include <errno.h>
  20. #ifdef OSX
  21. #define MSG_NOSIGNAL 0
  22. #endif
  23. #ifdef _PS3
  24. // NOTE: this socket creator doesn't work on PS3
  25. // here's a compile-hack:
  26. #define EWOULDBLOCK EAGAIN
  27. #else
  28. #include <sys/ioctl.h>
  29. #endif
  30. #define closesocket close
  31. #define WSAGetLastError() errno
  32. #define ioctlsocket ioctl
  33. #endif
  34. #include <tier0/dbg.h>
  35. #include "socketcreator.h"
  36. //#include "server.h"
  37. #if defined( _X360 )
  38. #include "xbox/xbox_win32stubs.h"
  39. #endif
  40. // memdbgon must be the last include file in a .cpp file!!!
  41. #include "tier0/memdbgon.h"
  42. /*
  43. ====================
  44. NET_ErrorString
  45. ====================
  46. */
  47. const char *NET_ErrorString (int code)
  48. {
  49. #if defined( _WIN32 )
  50. switch (code)
  51. {
  52. case WSAEINTR: return "WSAEINTR";
  53. case WSAEBADF: return "WSAEBADF";
  54. case WSAEACCES: return "WSAEACCES";
  55. case WSAEDISCON: return "WSAEDISCON";
  56. case WSAEFAULT: return "WSAEFAULT";
  57. case WSAEINVAL: return "WSAEINVAL";
  58. case WSAEMFILE: return "WSAEMFILE";
  59. case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
  60. case WSAEINPROGRESS: return "WSAEINPROGRESS";
  61. case WSAEALREADY: return "WSAEALREADY";
  62. case WSAENOTSOCK: return "WSAENOTSOCK";
  63. case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
  64. case WSAEMSGSIZE: return "WSAEMSGSIZE";
  65. case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
  66. case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
  67. case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
  68. case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
  69. case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
  70. case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
  71. case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
  72. case WSAEADDRINUSE: return "WSAEADDRINUSE";
  73. case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
  74. case WSAENETDOWN: return "WSAENETDOWN";
  75. case WSAENETUNREACH: return "WSAENETUNREACH";
  76. case WSAENETRESET: return "WSAENETRESET";
  77. case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
  78. case WSAECONNRESET: return "WSAECONNRESET";
  79. case WSAENOBUFS: return "WSAENOBUFS";
  80. case WSAEISCONN: return "WSAEISCONN";
  81. case WSAENOTCONN: return "WSAENOTCONN";
  82. case WSAESHUTDOWN: return "WSAESHUTDOWN";
  83. case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
  84. case WSAETIMEDOUT: return "WSAETIMEDOUT";
  85. case WSAECONNREFUSED: return "WSAECONNREFUSED";
  86. case WSAELOOP: return "WSAELOOP";
  87. case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
  88. case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
  89. case WSASYSNOTREADY: return "WSASYSNOTREADY";
  90. case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
  91. case WSANOTINITIALISED: return "WSANOTINITIALISED";
  92. case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
  93. case WSATRY_AGAIN: return "WSATRY_AGAIN";
  94. case WSANO_RECOVERY: return "WSANO_RECOVERY";
  95. case WSANO_DATA: return "WSANO_DATA";
  96. default: return "UNKNOWN ERROR";
  97. }
  98. #else
  99. return strerror( code );
  100. #endif
  101. }
  102. bool SocketWouldBlock()
  103. {
  104. #ifdef _WIN32
  105. return (WSAGetLastError() == WSAEWOULDBLOCK);
  106. #elif defined(POSIX)
  107. return (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS);
  108. #else
  109. Assert( false ); // Not implemented for this platform
  110. return false;
  111. #endif
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: Constructor
  115. //-----------------------------------------------------------------------------
  116. CSocketCreator::CSocketCreator( ISocketCreatorListener *pListener )
  117. {
  118. m_hListenSocket = -1;
  119. m_pListener = pListener;
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Destructor
  123. //-----------------------------------------------------------------------------
  124. CSocketCreator::~CSocketCreator()
  125. {
  126. Disconnect();
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: returns true if the listening socket is created and listening
  130. //-----------------------------------------------------------------------------
  131. bool CSocketCreator::IsListening() const
  132. {
  133. return m_hListenSocket != -1;
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose: Bind to a TCP port and accept incoming connections
  137. //-----------------------------------------------------------------------------
  138. bool CSocketCreator::CreateListenSocket( const netadr_t &netAdr, bool bListenOnAllInterfaces )
  139. {
  140. CloseListenSocket();
  141. #if PLATFORM_PS3
  142. Assert( 0 );
  143. return false;
  144. #else
  145. m_ListenAddress = netAdr;
  146. m_hListenSocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
  147. if ( m_hListenSocket == -1 )
  148. {
  149. Warning( "Socket unable to create socket (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  150. return false;
  151. }
  152. if ( !ConfigureSocket( m_hListenSocket ) )
  153. {
  154. CloseListenSocket();
  155. return false;
  156. }
  157. struct sockaddr_in s;
  158. m_ListenAddress.ToSockadr( (struct sockaddr *)&s );
  159. if ( bListenOnAllInterfaces )
  160. s.sin_addr.s_addr = INADDR_ANY;
  161. int ret = bind( m_hListenSocket, (struct sockaddr *)&s, sizeof(struct sockaddr_in) );
  162. if ( ret == -1 )
  163. {
  164. Warning( "Socket bind failed (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  165. CloseListenSocket();
  166. return false;
  167. }
  168. ret = listen( m_hListenSocket, SOCKET_TCP_MAX_ACCEPTS );
  169. if ( ret == -1 )
  170. {
  171. Warning( "Socket listen failed (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  172. CloseListenSocket();
  173. return false;
  174. }
  175. return true;
  176. #endif
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Configures a socket for use
  180. //-----------------------------------------------------------------------------
  181. bool CSocketCreator::ConfigureSocket( int sock )
  182. {
  183. #if PLATFORM_PS3
  184. Assert( 0 );
  185. return false;
  186. #else
  187. // disable NAGLE (rcon cmds are small in size)
  188. int nodelay = 1;
  189. setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay));
  190. nodelay = 1;
  191. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&nodelay, sizeof(nodelay));
  192. int opt = 1, ret;
  193. ret = ioctlsocket( sock, FIONBIO, (unsigned long*)&opt ); // non-blocking
  194. if ( ret == -1 )
  195. {
  196. Warning( "Socket accept ioctl(FIONBIO) failed (%i)\n", WSAGetLastError() );
  197. return false;
  198. }
  199. return true;
  200. #endif
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Handle a new connection
  204. //-----------------------------------------------------------------------------
  205. void CSocketCreator::ProcessAccept()
  206. {
  207. #if PLATFORM_PS3
  208. Assert( 0 );
  209. return;
  210. #else
  211. int newSocket;
  212. sockaddr sa;
  213. int nLengthAddr = sizeof(sa);
  214. newSocket = accept( m_hListenSocket, &sa, (socklen_t *)&nLengthAddr );
  215. if ( newSocket == -1 )
  216. {
  217. if ( !SocketWouldBlock()
  218. #ifdef POSIX
  219. && errno != EINTR
  220. #endif
  221. )
  222. {
  223. Warning ("Socket ProcessAccept Error: %s\n", NET_ErrorString( WSAGetLastError() ) );
  224. }
  225. return;
  226. }
  227. if ( !ConfigureSocket( newSocket ) )
  228. {
  229. closesocket( newSocket );
  230. return;
  231. }
  232. netadr_t adr;
  233. adr.SetFromSockadr( &sa );
  234. if ( m_pListener && !m_pListener->ShouldAcceptSocket( newSocket, adr ) )
  235. {
  236. closesocket( newSocket );
  237. return;
  238. }
  239. // new connection TCP request, put in accepted queue
  240. int nIndex = m_hAcceptedSockets.AddToTail();
  241. AcceptedSocket_t *pNewEntry = &m_hAcceptedSockets[nIndex];
  242. pNewEntry->m_hSocket = newSocket;
  243. pNewEntry->m_Address = adr;
  244. pNewEntry->m_pData = NULL;
  245. void* pData = NULL;
  246. if ( m_pListener )
  247. {
  248. m_pListener->OnSocketAccepted( newSocket, adr, &pData );
  249. }
  250. pNewEntry->m_pData = pData;
  251. #endif
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose: connect to the remote server
  255. //-----------------------------------------------------------------------------
  256. int CSocketCreator::ConnectSocket( const netadr_t &netAdr, bool bSingleSocket )
  257. {
  258. #if PLATFORM_PS3
  259. Assert( 0 );
  260. return -1;
  261. #else
  262. if ( bSingleSocket )
  263. {
  264. CloseAllAcceptedSockets();
  265. }
  266. SocketHandle_t hSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP );
  267. if ( hSocket == -1 )
  268. {
  269. Warning( "Unable to create socket (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  270. return -1;
  271. }
  272. int opt = 1, ret;
  273. ret = ioctlsocket( hSocket, FIONBIO, (unsigned long*)&opt ); // non-blocking
  274. if ( ret == -1 )
  275. {
  276. Warning( "Socket ioctl(FIONBIO) failed (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  277. closesocket( hSocket );
  278. return -1;
  279. }
  280. // disable NAGLE (rcon cmds are small in size)
  281. int nodelay = 1;
  282. setsockopt( hSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelay, sizeof(nodelay) );
  283. struct sockaddr_in s;
  284. netAdr.ToSockadr( (struct sockaddr *)&s );
  285. ret = connect( hSocket, (struct sockaddr *)&s, sizeof(s));
  286. if ( ret == -1 )
  287. {
  288. if ( !SocketWouldBlock() )
  289. {
  290. Warning( "Socket connection failed (%s)\n", NET_ErrorString( WSAGetLastError() ) );
  291. closesocket( hSocket );
  292. return -1;
  293. }
  294. fd_set writefds;
  295. struct timeval tv;
  296. tv.tv_usec = 0;
  297. tv.tv_sec = 1;
  298. FD_ZERO( &writefds );
  299. FD_SET( static_cast<u_int>( hSocket ), &writefds );
  300. if ( select ( hSocket + 1, NULL, &writefds, NULL, &tv ) < 1 ) // block for at most 1 second
  301. {
  302. closesocket( hSocket ); // took too long to connect to, give up
  303. return -1;
  304. }
  305. }
  306. if ( m_pListener && !m_pListener->ShouldAcceptSocket( hSocket, netAdr ) )
  307. {
  308. closesocket( hSocket );
  309. return -1;
  310. }
  311. // new connection TCP request, put in accepted queue
  312. void *pData = NULL;
  313. int nIndex = m_hAcceptedSockets.AddToTail();
  314. AcceptedSocket_t *pNewEntry = &m_hAcceptedSockets[nIndex];
  315. pNewEntry->m_hSocket = hSocket;
  316. pNewEntry->m_Address = netAdr;
  317. pNewEntry->m_pData = NULL;
  318. if ( m_pListener )
  319. {
  320. m_pListener->OnSocketAccepted( hSocket, netAdr, &pData );
  321. }
  322. pNewEntry->m_pData = pData;
  323. return nIndex;
  324. #endif
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Purpose: close an open rcon connection
  328. //-----------------------------------------------------------------------------
  329. void CSocketCreator::CloseListenSocket()
  330. {
  331. #if PLATFORM_PS3
  332. Assert( 0 );
  333. return;
  334. #else
  335. if ( m_hListenSocket != -1 )
  336. {
  337. closesocket( m_hListenSocket );
  338. m_hListenSocket = -1;
  339. }
  340. #endif
  341. }
  342. void CSocketCreator::CloseAcceptedSocket( int nIndex )
  343. {
  344. #if PLATFORM_PS3
  345. Assert( 0 );
  346. return;
  347. #else
  348. if ( nIndex >= m_hAcceptedSockets.Count() )
  349. return;
  350. AcceptedSocket_t& connected = m_hAcceptedSockets[nIndex];
  351. if ( m_pListener )
  352. {
  353. m_pListener->OnSocketClosed( connected.m_hSocket, connected.m_Address, connected.m_pData );
  354. }
  355. closesocket( connected.m_hSocket );
  356. m_hAcceptedSockets.Remove( nIndex );
  357. #endif
  358. }
  359. void CSocketCreator::CloseAllAcceptedSockets()
  360. {
  361. #if PLATFORM_PS3
  362. Warning( "CSocketCreator::CloseAllAcceptedSockets is UNIMPLEMENTED.\n" );
  363. return;
  364. #else
  365. int nCount = m_hAcceptedSockets.Count();
  366. for ( int i = 0; i < nCount; ++i )
  367. {
  368. AcceptedSocket_t& connected = m_hAcceptedSockets[i];
  369. if ( m_pListener )
  370. {
  371. m_pListener->OnSocketClosed( connected.m_hSocket, connected.m_Address, connected.m_pData );
  372. }
  373. closesocket( connected.m_hSocket );
  374. }
  375. m_hAcceptedSockets.RemoveAll();
  376. #endif
  377. }
  378. void CSocketCreator::Disconnect()
  379. {
  380. CloseListenSocket();
  381. CloseAllAcceptedSockets();
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Purpose: accept new connections and walk open sockets and handle any incoming data
  385. //-----------------------------------------------------------------------------
  386. void CSocketCreator::RunFrame()
  387. {
  388. if ( IsListening() )
  389. {
  390. ProcessAccept(); // handle any new connection requests
  391. }
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Returns socket info
  395. //-----------------------------------------------------------------------------
  396. int CSocketCreator::GetAcceptedSocketCount() const
  397. {
  398. return m_hAcceptedSockets.Count();
  399. }
  400. SocketHandle_t CSocketCreator::GetAcceptedSocketHandle( int nIndex ) const
  401. {
  402. return m_hAcceptedSockets[nIndex].m_hSocket;
  403. }
  404. const netadr_t& CSocketCreator::GetAcceptedSocketAddress( int nIndex ) const
  405. {
  406. return m_hAcceptedSockets[nIndex].m_Address;
  407. }
  408. void* CSocketCreator::GetAcceptedSocketData( int nIndex )
  409. {
  410. return m_hAcceptedSockets[nIndex].m_pData;
  411. }