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.

274 lines
5.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // socket_stresstest.cpp : Defines the entry point for the console application.
  9. //
  10. #include "stdafx.h"
  11. #include "utllinkedlist.h"
  12. class CSocketInfo
  13. {
  14. public:
  15. bool IsValid()
  16. {
  17. return m_pSocket != 0;
  18. }
  19. void Term();
  20. void ThreadFn();
  21. public:
  22. ITCPSocket *m_pSocket;
  23. int m_iListenPort;
  24. DWORD m_CreateTime; // When this socket was created.
  25. DWORD m_ExpireTime;
  26. };
  27. CSocketInfo g_Infos[132];
  28. CRITICAL_SECTION g_CS, g_PrintCS;
  29. HANDLE g_hThreads[ ARRAYSIZE( g_Infos ) ];
  30. bool g_bShouldExit = false;
  31. CUtlLinkedList<int,int> g_ListenPorts;
  32. SpewRetval_t StressTestSpew( SpewType_t type, char const *pMsg )
  33. {
  34. EnterCriticalSection( &g_PrintCS );
  35. printf( "%s", pMsg );
  36. LeaveCriticalSection( &g_PrintCS );
  37. if( type == SPEW_ASSERT )
  38. return SPEW_DEBUGGER;
  39. else if( type == SPEW_ERROR )
  40. return SPEW_ABORT;
  41. else
  42. return SPEW_CONTINUE;
  43. }
  44. void CSocketInfo::Term()
  45. {
  46. if ( m_pSocket )
  47. {
  48. m_pSocket->Release();
  49. m_pSocket = 0;
  50. }
  51. }
  52. CSocketInfo* FindOldestSocketInfo( CSocketInfo *pInfos, int nInfos )
  53. {
  54. int iOldest = 0;
  55. DWORD oldestTime = 0xFFFFFFFF;
  56. for ( int i=0; i < nInfos; i++ )
  57. {
  58. if ( !pInfos[i].IsValid() )
  59. return &pInfos[i];
  60. if ( pInfos[i].m_CreateTime < oldestTime )
  61. {
  62. oldestTime = pInfos[i].m_CreateTime;
  63. iOldest = i;
  64. }
  65. }
  66. return &pInfos[iOldest];
  67. }
  68. int g_iNextExpire = -1;
  69. void CSocketInfo::ThreadFn()
  70. {
  71. int iInfo = this - g_Infos;
  72. while ( !g_bShouldExit )
  73. {
  74. DWORD curTime = GetTickCount();
  75. // Break the connection after a certain amount of time.
  76. if ( m_pSocket && curTime >= m_ExpireTime )
  77. {
  78. Term();
  79. Msg( "%02d: expire.\n", iInfo, m_iListenPort );
  80. }
  81. if ( m_pSocket )
  82. {
  83. EnterCriticalSection( &g_CS );
  84. if ( g_iNextExpire == -1 )
  85. {
  86. g_iNextExpire = iInfo;
  87. LeaveCriticalSection( &g_CS );
  88. Msg( "%02d: forcing an expire.\n", iInfo, m_iListenPort );
  89. Sleep( 16000 );
  90. EnterCriticalSection( &g_CS );
  91. g_iNextExpire = -1;
  92. }
  93. LeaveCriticalSection( &g_CS );
  94. if ( m_pSocket->IsConnected() )
  95. {
  96. // Receive whatever data it has waiting for it.
  97. CUtlVector<unsigned char> data;
  98. while ( m_pSocket->Recv( data ) )
  99. {
  100. Msg( "%02d: recv %d.\n", iInfo, data.Count() );
  101. }
  102. // Send some data.
  103. int size = rand() % 8192;
  104. data.SetSize( size );
  105. m_pSocket->Send( data.Base(), data.Count() );
  106. //Msg( "%02d: send %d.\n", iInfo, data.Count() );
  107. }
  108. else
  109. {
  110. Term();
  111. }
  112. }
  113. else
  114. {
  115. // Not initialized.. either listen or connect.
  116. int iConnectPort = -1;
  117. if ( rand() > VALVE_RAND_MAX/2 )
  118. {
  119. if ( rand() % 100 < 50 )
  120. Sleep( 500 );
  121. EnterCriticalSection( &g_CS );
  122. int iHead = g_ListenPorts.Head();
  123. if ( iHead != g_ListenPorts.InvalidIndex() )
  124. iConnectPort = g_ListenPorts[iHead];
  125. LeaveCriticalSection( &g_CS );
  126. }
  127. if ( iConnectPort != -1 )
  128. {
  129. CIPAddr addr( 127, 0, 0, 1, iConnectPort );
  130. m_pSocket = CreateTCPSocket();
  131. m_pSocket->BindToAny( 0 );
  132. m_CreateTime = curTime;
  133. m_ExpireTime = curTime + rand() % 5000;
  134. if ( !TCPSocket_Connect( m_pSocket, &addr, 3.0f ) )
  135. {
  136. Term();
  137. }
  138. }
  139. else
  140. {
  141. for ( int iTry=0; iTry < 32; iTry++ )
  142. {
  143. m_iListenPort = 100 + rand() % (VALVE_RAND_MAX/2);
  144. ITCPListenSocket *pListenSocket = CreateTCPListenSocket( m_iListenPort );
  145. if ( pListenSocket )
  146. {
  147. Msg( "%02d: listen on %d.\n", iInfo, m_iListenPort );
  148. // Add us to the list of ports to connect to.
  149. EnterCriticalSection( &g_CS );
  150. g_ListenPorts.AddToTail( m_iListenPort );
  151. LeaveCriticalSection( &g_CS );
  152. // Listen for a connection.
  153. CIPAddr connectedAddr;
  154. m_pSocket = TCPSocket_ListenForOneConnection( pListenSocket, &connectedAddr, 4.0 );
  155. // Remove us from the list of ports to connect to.
  156. EnterCriticalSection( &g_CS );
  157. g_ListenPorts.Remove( g_ListenPorts.Find( m_iListenPort ) );
  158. LeaveCriticalSection( &g_CS );
  159. pListenSocket->Release();
  160. if ( m_pSocket )
  161. {
  162. Msg( "%02d: listen found connection.\n", iInfo );
  163. m_CreateTime = curTime;
  164. m_ExpireTime = curTime + rand() % 5000;
  165. }
  166. break;
  167. }
  168. }
  169. }
  170. }
  171. Sleep( 1 );
  172. }
  173. g_hThreads[iInfo] = 0;
  174. }
  175. DWORD WINAPI ThreadFn( LPVOID lpParameter )
  176. {
  177. CSocketInfo *pInfo = (CSocketInfo*)lpParameter;
  178. pInfo->ThreadFn();
  179. return 0;
  180. }
  181. void AllocError( unsigned long size )
  182. {
  183. Assert( false );
  184. }
  185. int main(int argc, char* argv[])
  186. {
  187. memset( g_Infos, 0, sizeof( g_Infos ) );
  188. memset( g_hThreads, 0, sizeof( g_hThreads ) );
  189. InitializeCriticalSection( &g_CS );
  190. InitializeCriticalSection( &g_PrintCS );
  191. SpewOutputFunc( StressTestSpew );
  192. Plat_SetAllocErrorFn( AllocError );
  193. SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
  194. for ( int i=0; i < ARRAYSIZE( g_Infos ); i++ )
  195. {
  196. DWORD dwThreadID = 0;
  197. g_hThreads[i] = CreateThread(
  198. NULL,
  199. 0,
  200. ThreadFn,
  201. &g_Infos[i],
  202. 0,
  203. &dwThreadID );
  204. }
  205. while ( !kbhit() )
  206. {
  207. }
  208. g_bShouldExit = true;
  209. HANDLE hZeroArray[ ARRAYSIZE( g_Infos ) ];
  210. memset( hZeroArray, 0, sizeof( hZeroArray ) );
  211. while ( memcmp( hZeroArray, g_hThreads, sizeof( hZeroArray ) ) != 0 )
  212. {
  213. Sleep( 10 );
  214. }
  215. return 0;
  216. }