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

1085 lines
25 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // ThreadedTCPSocket.cpp : Defines the entry point for the console application.
  9. //
  10. #include <winsock2.h>
  11. #include <mswsock.h>
  12. #include "IThreadedTCPSocket.h"
  13. #include "utllinkedlist.h"
  14. #include "threadhelpers.h"
  15. #include "iphelpers.h"
  16. #include "tier1/strtools.h"
  17. #define SEND_KEEPALIVE_INTERVAL 3000
  18. #define KEEPALIVE_TIMEOUT 25000 // The sockets timeout after this long.
  19. #define KEEPALIVE_SENTINEL -12345 // When first 4 bytes of a packet = this, then it's just a keepalive.
  20. static int g_KeepaliveSentinel = KEEPALIVE_SENTINEL;
  21. bool g_bHandleTimeouts = true;
  22. // If true, it'll set the socket thread priorities lower than normal.
  23. bool g_bSetTCPSocketThreadPriorities = true;
  24. // We get crashes at runtime if they don't link in the multithreaded runtime libraries,
  25. // so raise a ruckus if they're using singlethreaded libraries.
  26. #ifndef _MT
  27. #pragma message( "**** WARNING **** ThreadedTCPSocket requires multithreaded runtime libraries to be used.\n" )
  28. class MTChecker
  29. {
  30. public:
  31. MTChecker() { Assert( false ); }
  32. } g_MTChecker;
  33. #endif
  34. // ------------------------------------------------------------------------------------------------ //
  35. // Static helpers.
  36. // ------------------------------------------------------------------------------------------------ //
  37. static SOCKET TCPBind( const CIPAddr *pAddr )
  38. {
  39. // Create a socket to send and receive through.
  40. SOCKET sock = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
  41. if ( sock == INVALID_SOCKET )
  42. {
  43. Assert( false );
  44. return INVALID_SOCKET;
  45. }
  46. // bind to it!
  47. sockaddr_in addr;
  48. IPAddrToSockAddr( pAddr, &addr );
  49. int status = bind( sock, (sockaddr*)&addr, sizeof(addr) );
  50. if ( status == 0 )
  51. {
  52. return sock;
  53. }
  54. else
  55. {
  56. closesocket( sock );
  57. return INVALID_SOCKET;
  58. }
  59. }
  60. // ------------------------------------------------------------------------------------------------ //
  61. // CTCPPacket.
  62. // ------------------------------------------------------------------------------------------------ //
  63. int CTCPPacket::GetUserData() const
  64. {
  65. return m_UserData;
  66. }
  67. void CTCPPacket::SetUserData( int userData )
  68. {
  69. m_UserData = userData;
  70. }
  71. void CTCPPacket::Release()
  72. {
  73. free( this );
  74. }
  75. // ------------------------------------------------------------------------------------------------ //
  76. // CThreadedTCPSocket.
  77. // ------------------------------------------------------------------------------------------------ //
  78. class CThreadedTCPSocket : public IThreadedTCPSocket
  79. {
  80. public:
  81. static IThreadedTCPSocket* Create( SOCKET iSocket, CIPAddr remoteAddr, ITCPSocketHandler *pHandler )
  82. {
  83. CThreadedTCPSocket *pRet = new CThreadedTCPSocket;
  84. if ( pRet->Init( iSocket, remoteAddr, pHandler ) )
  85. {
  86. return pRet;
  87. }
  88. else
  89. {
  90. pRet->Release();
  91. return NULL;
  92. }
  93. }
  94. // IThreadedTCPSocket implementation.
  95. public:
  96. virtual void Release()
  97. {
  98. delete this;
  99. }
  100. virtual CIPAddr GetRemoteAddr() const
  101. {
  102. return m_RemoteAddr;
  103. }
  104. virtual bool IsValid()
  105. {
  106. return !CheckErrorSignal();
  107. }
  108. virtual bool Send( const void *pData, int len )
  109. {
  110. const void *pChunks[1] = { pData };
  111. return SendChunks( pChunks, &len, 1 );
  112. }
  113. virtual bool SendChunks( void const * const *pChunks, const int *pChunkLengths, int nChunks )
  114. {
  115. if ( CheckErrorSignal() )
  116. return false;
  117. return InternalSend( pChunks, pChunkLengths, nChunks, true );
  118. }
  119. // Initialization.
  120. private:
  121. CThreadedTCPSocket()
  122. {
  123. m_Socket = INVALID_SOCKET;
  124. m_pHandler = NULL;
  125. memset( &m_SendOverlapped, 0, sizeof( m_SendOverlapped ) );
  126. memset( &m_RecvOverlapped, 0, sizeof( m_RecvOverlapped ) );
  127. m_bWaitingForSendCompletion = false;
  128. m_nBytesToReceive = -1;
  129. m_bWaitingForSize = false;
  130. m_bErrorSignal = false;
  131. m_pRecvBuffer = NULL;
  132. }
  133. virtual ~CThreadedTCPSocket()
  134. {
  135. Term();
  136. }
  137. bool Init( SOCKET iSocket, CIPAddr remoteAddr, ITCPSocketHandler *pHandler )
  138. {
  139. m_Socket = iSocket;
  140. m_RemoteAddr = remoteAddr;
  141. m_pHandler = pHandler;
  142. SetInitialSocketOptions();
  143. // Create all the event objects we'll use to communicate.
  144. m_hExitThreadsEvent.Init( true, false );
  145. m_hSendCompletionEvent.Init( false, false );
  146. m_hReadyToSendEvent.Init( false, false );
  147. m_hRecvEvent.Init( false, false );
  148. m_SendOverlapped.hEvent = m_hSendCompletionEvent.GetEventHandle();
  149. m_RecvOverlapped.hEvent = m_hRecvEvent.GetEventHandle();
  150. // Create our threads.
  151. DWORD dwSendThreadID, dwRecvThreadID;
  152. m_hSendThread = CreateThread( NULL, 0, &CThreadedTCPSocket::StaticSendThreadFn, this, CREATE_SUSPENDED, &dwSendThreadID );
  153. m_hRecvThread = CreateThread( NULL, 0, &CThreadedTCPSocket::StaticRecvThreadFn, this, CREATE_SUSPENDED, &dwRecvThreadID );
  154. if ( !m_hSendThread || !m_hRecvThread )
  155. {
  156. return false;
  157. }
  158. if ( g_bSetTCPSocketThreadPriorities )
  159. {
  160. SetThreadPriority( m_hSendThread, THREAD_PRIORITY_LOWEST );
  161. SetThreadPriority( m_hRecvThread, THREAD_PRIORITY_LOWEST );
  162. }
  163. ThreadSetDebugName( (ThreadId_t)dwSendThreadID, "TCPSend" );
  164. ThreadSetDebugName( (ThreadId_t)dwRecvThreadID, "TCPRecv" );
  165. // Make sure to init the handler before the threads actually run, so it isn't handed data before initializing.
  166. m_pHandler->Init( this );
  167. ResumeThread( m_hSendThread );
  168. ResumeThread( m_hRecvThread );
  169. return true;
  170. }
  171. void Term()
  172. {
  173. // Signal our threads to exit.
  174. m_hExitThreadsEvent.SetEvent();
  175. if ( m_hSendThread )
  176. {
  177. WaitForSingleObject( m_hSendThread, INFINITE );
  178. CloseHandle( m_hSendThread );
  179. m_hSendThread = NULL;
  180. }
  181. if ( m_hRecvThread )
  182. {
  183. WaitForSingleObject( m_hRecvThread, INFINITE );
  184. CloseHandle( m_hRecvThread );
  185. m_hRecvThread = NULL;
  186. }
  187. m_hExitThreadsEvent.ResetEvent();
  188. if ( m_Socket != INVALID_SOCKET )
  189. {
  190. closesocket( m_Socket );
  191. m_Socket = INVALID_SOCKET;
  192. }
  193. }
  194. // Set the initial socket options that we want.
  195. void SetInitialSocketOptions()
  196. {
  197. // Set nodelay to improve latency.
  198. BOOL val = TRUE;
  199. setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&val, sizeof(BOOL) );
  200. // Make it linger for 3 seconds when it exits.
  201. LINGER linger;
  202. linger.l_onoff = 1;
  203. linger.l_linger = 3;
  204. setsockopt( m_Socket, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof( linger ) );
  205. }
  206. // Send thread functionality.
  207. private:
  208. // This function copies off the payload and adds a SendChunk_t to the list of chunks to be sent.
  209. // It also fires the ReadyToSend event so the thread will pick it up.
  210. bool InternalSend( void const * const *pChunks, const int *pChunkLengths, int nChunks, bool bPrependLength )
  211. {
  212. int totalLength = 0;
  213. for ( int i=0; i < nChunks; i++ )
  214. totalLength += pChunkLengths[i];
  215. if ( bPrependLength )
  216. {
  217. if ( totalLength == 0 )
  218. return true;
  219. totalLength += 4;
  220. }
  221. // Copy all the data into a SendData_t.
  222. SendData_t *pSendData = (SendData_t*)malloc( sizeof( SendData_t ) - 1 + totalLength );
  223. pSendData->m_Len = totalLength;
  224. char *pOut = pSendData->m_Payload;
  225. if ( bPrependLength )
  226. {
  227. *((int*)pOut) = totalLength - 4; // The length we prepend is the size of the data, not data size + integer for length.
  228. pOut += 4;
  229. }
  230. for ( int i=0; i < nChunks; i++ )
  231. {
  232. memcpy( pOut, pChunks[i], pChunkLengths[i] );
  233. pOut += pChunkLengths[i];
  234. }
  235. CCriticalSectionLock csLock( &m_SendCS );
  236. csLock.Lock();
  237. m_SendDatas.AddToTail( pSendData );
  238. m_hReadyToSendEvent.SetEvent(); // Notify the thread that there is data to send.
  239. csLock.Unlock();
  240. return true;
  241. }
  242. void SendThread_HandleTimeout()
  243. {
  244. // Timeout.. send a keepalive.
  245. // But only if we're not already sending something.
  246. CCriticalSectionLock csLock( &m_SendCS );
  247. csLock.Lock();
  248. int count = m_SendDatas.Count();
  249. csLock.Unlock();
  250. if ( count == 0 )
  251. {
  252. void *pBuf[1] = { &g_KeepaliveSentinel };
  253. int len[1] = { sizeof( g_KeepaliveSentinel ) };
  254. InternalSend( pBuf, len, 1, false );
  255. }
  256. }
  257. bool SendThread_HandleSendCompletionEvent()
  258. {
  259. Assert( m_bWaitingForSendCompletion );
  260. m_bWaitingForSendCompletion = false;
  261. // A send operation just completed. Now do the next one.
  262. DWORD cbTransfer, flags;
  263. if ( !WSAGetOverlappedResult( m_Socket, &m_SendOverlapped, &cbTransfer, TRUE, &flags ) )
  264. {
  265. HandleError( WSAGetLastError() );
  266. return false;
  267. }
  268. if ( cbTransfer != m_nBytesToTransfer )
  269. {
  270. char str[512];
  271. Q_snprintf( str, sizeof( str ), "Invalid # bytes transferred (%d) in send thread (should be %d)", cbTransfer, m_nBytesToTransfer );
  272. HandleError( ITCPSocketHandler::SocketError, str );
  273. return false;
  274. }
  275. // Remove the block we just sent.
  276. CCriticalSectionLock csLock( &m_SendCS );
  277. csLock.Lock();
  278. SendData_t *pSendData = m_SendDatas[ m_SendDatas.Head() ];
  279. free( pSendData );
  280. m_SendDatas.Remove( m_SendDatas.Head() );
  281. m_bWaitingForSendCompletion = false;
  282. // Set our send event if there's anything else to send.
  283. if ( m_SendDatas.Count() > 0 )
  284. m_hReadyToSendEvent.SetEvent();
  285. csLock.Unlock();
  286. return true;
  287. }
  288. bool SendThread_HandleReadyToSendEvent()
  289. {
  290. // We've got at least one buffer that's ready to be sent.
  291. // NOTE: don't send anything until our current send is completed.
  292. CCriticalSectionLock csLock( &m_SendCS );
  293. csLock.Lock();
  294. Assert( !m_bWaitingForSendCompletion );
  295. // Send it off!
  296. SendData_t *pSendData = m_SendDatas[ m_SendDatas.Head() ];
  297. WSABUF buf = { pSendData->m_Len, pSendData->m_Payload };
  298. m_nBytesToTransfer = pSendData->m_Len;
  299. m_bWaitingForSendCompletion = true;
  300. csLock.Unlock();
  301. DWORD dwNumBytesSent = 0;
  302. DWORD ret = WSASend( m_Socket, &buf, 1, &dwNumBytesSent, 0, &m_SendOverlapped, NULL );
  303. DWORD err = WSAGetLastError();
  304. if ( ret == 0 || ( ret == SOCKET_ERROR && err == WSA_IO_PENDING ) )
  305. {
  306. // Either way, the operation completed successfully, and m_hSendCompletionEvent is now set.
  307. return true;
  308. }
  309. else
  310. {
  311. HandleError( err );
  312. return false;
  313. }
  314. return true;
  315. }
  316. DWORD SendThreadFn()
  317. {
  318. while ( 1 )
  319. {
  320. HANDLE handles[] =
  321. {
  322. m_hExitThreadsEvent.GetEventHandle(),
  323. m_hSendCompletionEvent.GetEventHandle(),
  324. m_hReadyToSendEvent.GetEventHandle()
  325. };
  326. int nHandles = ARRAYSIZE( handles );
  327. // While waiting for send completion, don't handle "ready to send" events.
  328. if ( m_bWaitingForSendCompletion )
  329. --nHandles;
  330. DWORD waitValue = WaitForMultipleObjects( nHandles, handles, FALSE, SEND_KEEPALIVE_INTERVAL );
  331. switch ( waitValue )
  332. {
  333. case WAIT_TIMEOUT:
  334. {
  335. if ( g_bHandleTimeouts )
  336. {
  337. // We haven't sent anything in a bit. Send out a keepalive.
  338. SendThread_HandleTimeout();
  339. }
  340. }
  341. break;
  342. case WAIT_OBJECT_0:
  343. {
  344. // The main thread is signaling us to exit.
  345. return 0;
  346. }
  347. case WAIT_OBJECT_0 + 1:
  348. {
  349. if ( !SendThread_HandleSendCompletionEvent() )
  350. return 1;
  351. }
  352. break;
  353. case WAIT_OBJECT_0 + 2:
  354. {
  355. if ( !SendThread_HandleReadyToSendEvent() )
  356. return 1;
  357. }
  358. break;
  359. case WAIT_FAILED:
  360. {
  361. // Uh oh. We're dead. Cleanup and signal an error.
  362. HandleError( GetLastError() );
  363. return 1;
  364. }
  365. default:
  366. {
  367. char str[512];
  368. Q_snprintf( str, sizeof( str ), "Unknown return value (%lu) from WaitForMultipleObjects", waitValue );
  369. HandleError( ITCPSocketHandler::SocketError, str );
  370. return 0;
  371. }
  372. }
  373. }
  374. return 0;
  375. }
  376. static DWORD WINAPI StaticSendThreadFn( LPVOID pParameter )
  377. {
  378. return ((CThreadedTCPSocket*)pParameter)->SendThreadFn();
  379. }
  380. // Receive thread functionality.
  381. private:
  382. bool RecvThread_WaitToReceiveSize()
  383. {
  384. return RecvThread_InternalRecv( &m_NextPacketLen, sizeof( m_NextPacketLen ), false, true );
  385. }
  386. bool RecvThread_InternalHandleRecvCompletion( DWORD dwTransfer )
  387. {
  388. int cbTransfer = (int)dwTransfer;
  389. int nBytesWanted = m_nBytesToReceive - m_nBytesReceivedSoFar;
  390. if ( cbTransfer > nBytesWanted )
  391. {
  392. char str[512];
  393. Q_snprintf( str, sizeof( str ), "Invalid # bytes received (%d) in recv thread (should be %d)", cbTransfer, m_nBytesToReceive );
  394. HandleError( ITCPSocketHandler::SocketError, str );
  395. return false;
  396. }
  397. else if ( cbTransfer < nBytesWanted )
  398. {
  399. // We have to reissue the receive command because it didn't receive all the data.
  400. m_nBytesReceivedSoFar += cbTransfer;
  401. char *pDest = (char*)&m_NextPacketLen;
  402. if ( !m_bWaitingForSize )
  403. {
  404. Assert( m_pRecvBuffer );
  405. pDest = m_pRecvBuffer->m_Data;
  406. }
  407. return RecvThread_InternalRecv( &pDest[m_nBytesReceivedSoFar], m_nBytesToReceive - m_nBytesReceivedSoFar, true );
  408. }
  409. if ( m_bWaitingForSize )
  410. {
  411. // If we were waiting for size, now wait for the data.
  412. if ( m_NextPacketLen == KEEPALIVE_SENTINEL )
  413. {
  414. // Ok, it was just a keepalive. Wait for size again.
  415. return RecvThread_WaitToReceiveSize();
  416. }
  417. else
  418. {
  419. if ( m_NextPacketLen < 1 || m_NextPacketLen > 1024*1024*75 )
  420. {
  421. char str[512];
  422. Q_snprintf( str, sizeof( str ), "Invalid packet size in RecvThread (size = %d)", m_NextPacketLen );
  423. HandleError( ITCPSocketHandler::SocketError, str );
  424. return false;
  425. }
  426. else
  427. {
  428. Assert( !m_pRecvBuffer );
  429. m_pRecvBuffer = (CTCPPacket*)malloc( sizeof( CTCPPacket ) - 1 + m_NextPacketLen );
  430. m_pRecvBuffer->m_UserData = 0;
  431. m_pRecvBuffer->m_Len = m_NextPacketLen;
  432. return RecvThread_InternalRecv( m_pRecvBuffer->m_Data, m_pRecvBuffer->m_Len, false, false );
  433. }
  434. }
  435. }
  436. else
  437. {
  438. // Got a packet! Give it to the app.
  439. m_pHandler->OnPacketReceived( m_pRecvBuffer );
  440. m_pRecvBuffer = NULL;
  441. return RecvThread_WaitToReceiveSize();
  442. }
  443. }
  444. bool RecvThread_HandleRecvCompletionEvent()
  445. {
  446. // A send operation just completed. Now do the next one.
  447. DWORD cbTransfer, flags;
  448. if ( !WSAGetOverlappedResult( m_Socket, &m_RecvOverlapped, &cbTransfer, TRUE, &flags ) )
  449. {
  450. HandleError( WSAGetLastError() );
  451. return false;
  452. }
  453. return RecvThread_InternalHandleRecvCompletion( cbTransfer );
  454. }
  455. bool RecvThread_InternalRecv( void *pDest, int destSize, bool bContinuation, bool bWaitingForSize = false )
  456. {
  457. WSABUF buf = { destSize, (char*)pDest };
  458. if ( !bContinuation )
  459. {
  460. // If this is not a continuation of whatever we were receiving before, then
  461. m_bWaitingForSize = bWaitingForSize;
  462. m_nBytesToReceive = destSize;
  463. m_nBytesReceivedSoFar = 0;
  464. }
  465. DWORD dwFlags = 0;
  466. DWORD nBytesReceived = 0;
  467. DWORD ret = WSARecv( m_Socket, &buf, 1, &nBytesReceived, &dwFlags, &m_RecvOverlapped, NULL );
  468. DWORD dwLastError = WSAGetLastError();
  469. if ( ret == 0 || ( ret == SOCKET_ERROR && dwLastError == WSA_IO_PENDING ) )
  470. {
  471. // Note: m_hRecvEvent is in a signaled state, so the RecvThread will pick up the results next time around.
  472. return true;
  473. }
  474. else
  475. {
  476. HandleError( dwLastError );
  477. return false;
  478. }
  479. }
  480. DWORD RecvThreadFn()
  481. {
  482. // Start us off by setting up to receive the first packet size.
  483. if ( !RecvThread_WaitToReceiveSize() )
  484. return 1;
  485. HANDLE handles[] =
  486. {
  487. m_hExitThreadsEvent.GetEventHandle(),
  488. m_hRecvEvent.GetEventHandle()
  489. };
  490. while ( 1 )
  491. {
  492. DWORD waitValue = WaitForMultipleObjects( ARRAYSIZE( handles ), handles, FALSE, KEEPALIVE_TIMEOUT );
  493. switch ( waitValue )
  494. {
  495. case WAIT_TIMEOUT:
  496. {
  497. if ( g_bHandleTimeouts )
  498. {
  499. HandleError( ITCPSocketHandler::ConnectionTimedOut, "Connection timed out" );
  500. return 1;
  501. }
  502. }
  503. break;
  504. case WAIT_OBJECT_0:
  505. {
  506. // We're being told to exit.
  507. return 0;
  508. }
  509. case WAIT_OBJECT_0 + 1:
  510. {
  511. // Just finished receiving something.
  512. if ( !RecvThread_HandleRecvCompletionEvent() )
  513. return 1;
  514. }
  515. break;
  516. case WAIT_FAILED:
  517. {
  518. // Uh oh. We're dead. Cleanup and signal an error.
  519. HandleError( GetLastError() );
  520. return 1;
  521. }
  522. default:
  523. {
  524. char str[512];
  525. Q_snprintf( str, sizeof( str ), "Unknown return value (%lu) from WaitForMultipleObjects", waitValue );
  526. HandleError( ITCPSocketHandler::SocketError, str );
  527. return 1;
  528. }
  529. }
  530. }
  531. return 0;
  532. }
  533. static DWORD WINAPI StaticRecvThreadFn( LPVOID pParameter )
  534. {
  535. return ((CThreadedTCPSocket*)pParameter)->RecvThreadFn();
  536. }
  537. // Error handling.
  538. private:
  539. // This checks to see if either thread has signaled an error. If so, it shuts down the socket and returns true.
  540. bool CheckErrorSignal()
  541. {
  542. return m_bErrorSignal;
  543. }
  544. // This is called from any of the threads and signals that something went awry. It shuts down the object
  545. // and makes it return false from all of its functions.
  546. void HandleError( DWORD errorValue )
  547. {
  548. char *lpMsgBuf;
  549. FormatMessage(
  550. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  551. FORMAT_MESSAGE_FROM_SYSTEM |
  552. FORMAT_MESSAGE_IGNORE_INSERTS,
  553. NULL,
  554. GetLastError(),
  555. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  556. (char*)&lpMsgBuf,
  557. 0,
  558. NULL
  559. );
  560. // Windows likes to stick a carriage return in there and we don't want it so get rid of it.
  561. int len = strlen( lpMsgBuf );
  562. while ( len > 0 && ( lpMsgBuf[len-1] == '\n' || lpMsgBuf[len-1] == '\r' ) )
  563. {
  564. --len;
  565. lpMsgBuf[len] = 0;
  566. }
  567. HandleError( ITCPSocketHandler::SocketError, lpMsgBuf );
  568. LocalFree( lpMsgBuf );
  569. }
  570. void HandleError( int errorCode, const char *pErrorString )
  571. {
  572. //Assert( false );
  573. // Tell the app.
  574. m_pHandler->OnError( errorCode, pErrorString );
  575. // Tell the threads to exit.
  576. m_hExitThreadsEvent.SetEvent();
  577. // Notify the main thread so it can call Term() when it gets a chance.
  578. m_bErrorSignal = true;
  579. }
  580. private:
  581. // Data for the send thread.
  582. typedef struct
  583. {
  584. //WSAOVERLAPPED m_Overlapped;
  585. int m_Len;
  586. char m_Payload[1];
  587. } SendData_t;
  588. HANDLE m_hSendThread;
  589. WSAOVERLAPPED m_SendOverlapped;
  590. CEvent m_hReadyToSendEvent;
  591. CEvent m_hSendCompletionEvent;
  592. CCriticalSection m_SendCS;
  593. DWORD m_nBytesToTransfer;
  594. bool m_bWaitingForSendCompletion;
  595. CUtlLinkedList<SendData_t*, int> m_SendDatas; // Added to the tail, popped off the head for sending.
  596. // Data for the recv thread.
  597. HANDLE m_hRecvThread;
  598. int m_nBytesToReceive; // This stores how many bytes we want to receive for the next packet.
  599. int m_nBytesReceivedSoFar; // This stores how many bytes we've received so far.
  600. bool m_bWaitingForSize; // This tells if we're trying to receive the next packet length or the next packet's data.
  601. int m_NextPacketLen; // Data is received INTO here before it receives each packet. This
  602. // holds the length of each incoming packet.
  603. WSAOVERLAPPED m_RecvOverlapped;
  604. CEvent m_hRecvEvent;
  605. CTCPPacket *m_pRecvBuffer; // This is allocated for each packet we're receiving and given to the
  606. // app when the packet is done being received.
  607. volatile bool m_bErrorSignal;
  608. CEvent m_hExitThreadsEvent;
  609. ITCPSocketHandler *m_pHandler;
  610. SOCKET m_Socket;
  611. CIPAddr m_RemoteAddr;
  612. };
  613. // ------------------------------------------------------------------------------------------------ //
  614. // CTCPConnectSocket_Listener
  615. // ------------------------------------------------------------------------------------------------ //
  616. class CTCPConnectSocket_Listener : public ITCPConnectSocket
  617. {
  618. public:
  619. CTCPConnectSocket_Listener()
  620. {
  621. m_Socket = INVALID_SOCKET;
  622. }
  623. virtual ~CTCPConnectSocket_Listener()
  624. {
  625. if ( m_Socket != INVALID_SOCKET )
  626. {
  627. closesocket( m_Socket );
  628. }
  629. }
  630. // The main function to create one of these suckers.
  631. static ITCPConnectSocket* Create(
  632. IHandlerCreator *pHandlerCreator,
  633. const unsigned short port,
  634. int nQueueLength
  635. )
  636. {
  637. CTCPConnectSocket_Listener *pRet = new CTCPConnectSocket_Listener;
  638. if ( !pRet )
  639. return NULL;
  640. if ( nQueueLength < 0 )
  641. {
  642. Error( "CTCPConnectSocket_Listener::Create - SOMAXCONN not allowed - causes some XP SP2 systems to stop receiving any network data (systemwide)." );
  643. }
  644. // Bind it to a socket and start listening.
  645. CIPAddr addr( 0, 0, 0, 0, port ); // INADDR_ANY
  646. pRet->m_Socket = TCPBind( &addr );
  647. if ( pRet->m_Socket == INVALID_SOCKET ||
  648. listen( pRet->m_Socket, nQueueLength == -1 ? SOMAXCONN : nQueueLength ) != 0 )
  649. {
  650. pRet->Release();
  651. return false;
  652. }
  653. pRet->m_pHandler = pHandlerCreator;
  654. return pRet;
  655. }
  656. // ITCPConnectSocket implementation.
  657. public:
  658. virtual void Release()
  659. {
  660. delete this;
  661. }
  662. virtual bool Update( IThreadedTCPSocket **pSocket, unsigned long milliseconds )
  663. {
  664. *pSocket = NULL;
  665. if ( m_Socket == INVALID_SOCKET )
  666. return false;
  667. // We're still ok.. just wait until the socket becomes writable (is connected) or we timeout.
  668. fd_set readSet;
  669. readSet.fd_count = 1;
  670. readSet.fd_array[0] = m_Socket;
  671. TIMEVAL timeVal = {0, milliseconds*1000};
  672. // Wait until it connects.
  673. int status = select( 0, &readSet, NULL, NULL, &timeVal );
  674. if ( status > 0 )
  675. {
  676. sockaddr_in addr;
  677. int addrSize = sizeof( addr );
  678. // Now accept the final connection.
  679. SOCKET newSock = accept( m_Socket, (struct sockaddr*)&addr, &addrSize );
  680. if ( newSock == INVALID_SOCKET )
  681. {
  682. Assert( false );
  683. return true;
  684. }
  685. else
  686. {
  687. CIPAddr connectedAddr;
  688. SockAddrToIPAddr( &addr, &connectedAddr );
  689. IThreadedTCPSocket *pRet = CThreadedTCPSocket::Create( newSock, connectedAddr, m_pHandler->CreateNewHandler() );
  690. if ( !pRet )
  691. {
  692. Assert( false );
  693. closesocket( m_Socket );
  694. m_Socket = INVALID_SOCKET;
  695. return false;
  696. }
  697. *pSocket = pRet;
  698. return true;
  699. }
  700. }
  701. else if ( status == SOCKET_ERROR )
  702. {
  703. closesocket( m_Socket );
  704. m_Socket = INVALID_SOCKET;
  705. return false;
  706. }
  707. else
  708. {
  709. return true;
  710. }
  711. }
  712. private:
  713. SOCKET m_Socket;
  714. IHandlerCreator *m_pHandler;
  715. };
  716. ITCPConnectSocket* ThreadedTCP_CreateListener(
  717. IHandlerCreator *pHandlerCreator,
  718. const unsigned short port,
  719. int nQueueLength
  720. )
  721. {
  722. return CTCPConnectSocket_Listener::Create( pHandlerCreator, port, nQueueLength );
  723. }
  724. // ------------------------------------------------------------------------------------------------ //
  725. // CTCPConnectSocket_Connector
  726. // ------------------------------------------------------------------------------------------------ //
  727. class CTCPConnectSocket_Connector : public ITCPConnectSocket
  728. {
  729. public:
  730. CTCPConnectSocket_Connector()
  731. {
  732. m_bConnected = false;
  733. m_Socket = INVALID_SOCKET;
  734. m_bError = false;
  735. }
  736. virtual ~CTCPConnectSocket_Connector()
  737. {
  738. if ( m_Socket != INVALID_SOCKET )
  739. {
  740. closesocket( m_Socket );
  741. }
  742. }
  743. static ITCPConnectSocket* Create(
  744. const CIPAddr &connectAddr,
  745. const CIPAddr &localAddr,
  746. IHandlerCreator *pHandlerCreator
  747. )
  748. {
  749. CTCPConnectSocket_Connector *pRet = new CTCPConnectSocket_Connector;
  750. pRet->m_Socket = TCPBind( &localAddr );
  751. if ( pRet->m_Socket == INVALID_SOCKET )
  752. {
  753. pRet->Release();
  754. return NULL;
  755. }
  756. sockaddr_in addr;
  757. IPAddrToSockAddr( &connectAddr, &addr );
  758. // We don't want the connect() call to block.
  759. DWORD val = 1;
  760. int status = ioctlsocket( pRet->m_Socket, FIONBIO, &val );
  761. if ( status != 0 )
  762. {
  763. Assert( false );
  764. pRet->Release();
  765. return NULL;
  766. }
  767. pRet->m_RemoteAddr = connectAddr;
  768. pRet->m_pHandlerCreator = pHandlerCreator;
  769. int ret = connect( pRet->m_Socket, (struct sockaddr*)&addr, sizeof( addr ) );
  770. if ( ret == 0 )
  771. {
  772. pRet->m_bConnected = true;
  773. return pRet;
  774. }
  775. else if ( ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK )
  776. {
  777. return pRet;
  778. }
  779. else
  780. {
  781. Assert( false );
  782. pRet->Release();
  783. return NULL;
  784. }
  785. }
  786. // ITCPConnectSocket implementation.
  787. public:
  788. virtual void Release()
  789. {
  790. delete this;
  791. }
  792. virtual bool Update( IThreadedTCPSocket **pSocket, unsigned long milliseconds )
  793. {
  794. *pSocket = NULL;
  795. // If we got an error previously, keep returning false.
  796. if ( m_bError )
  797. return false;
  798. // If this condition holds, then we already returned a valid socket and we're just waiting to be released.
  799. if ( m_Socket == INVALID_SOCKET )
  800. return true;
  801. // Ok, see if we're connected now.
  802. if ( !m_bConnected )
  803. {
  804. TIMEVAL timeVal = { 0, milliseconds*1000 };
  805. fd_set writeSet;
  806. writeSet.fd_count = 1;
  807. writeSet.fd_array[0] = m_Socket;
  808. int ret = select( 0, NULL, &writeSet, NULL, &timeVal );
  809. if ( ret > 0 )
  810. {
  811. m_bConnected = true;
  812. }
  813. else if ( ret == SOCKET_ERROR )
  814. {
  815. return EnterErrorMode();
  816. }
  817. }
  818. if ( m_bConnected )
  819. {
  820. // Ok, return a connected socket for them.
  821. // Make our socket blocking again.
  822. DWORD val = 0;
  823. int status = ioctlsocket( m_Socket, FIONBIO, &val );
  824. if ( status != 0 )
  825. {
  826. Assert( false );
  827. m_bError = true;
  828. closesocket( m_Socket );
  829. m_Socket = INVALID_SOCKET;
  830. return false;
  831. }
  832. IThreadedTCPSocket *pRet = CThreadedTCPSocket::Create( m_Socket, m_RemoteAddr, m_pHandlerCreator->CreateNewHandler() );
  833. if ( pRet )
  834. {
  835. m_Socket = INVALID_SOCKET;
  836. *pSocket = pRet;
  837. return true;
  838. }
  839. else
  840. {
  841. return EnterErrorMode();
  842. }
  843. }
  844. else
  845. {
  846. // Still waiting..
  847. return true;
  848. }
  849. }
  850. // Shutdown the socket and start returning false from Update().
  851. bool EnterErrorMode()
  852. {
  853. Assert( false );
  854. m_bError = true;
  855. closesocket( m_Socket );
  856. m_Socket = INVALID_SOCKET;
  857. return false;
  858. }
  859. private:
  860. bool m_bError;
  861. bool m_bConnected;
  862. SOCKET m_Socket;
  863. CIPAddr m_RemoteAddr;
  864. IHandlerCreator *m_pHandlerCreator;
  865. };
  866. ITCPConnectSocket* ThreadedTCP_CreateConnector(
  867. const CIPAddr &addr,
  868. const CIPAddr &localAddr,
  869. IHandlerCreator *pHandlerCreator
  870. )
  871. {
  872. return CTCPConnectSocket_Connector::Create( addr, localAddr, pHandlerCreator );
  873. }
  874. void ThreadedTCP_EnableTimeouts( bool bEnable )
  875. {
  876. g_bHandleTimeouts = bEnable;
  877. }
  878. void ThreadedTCP_SetTCPSocketThreadPriorities( bool bSetTCPSocketThreadPriorities )
  879. {
  880. g_bSetTCPSocketThreadPriorities = bSetTCPSocketThreadPriorities;
  881. }