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.
275 lines
5.3 KiB
275 lines
5.3 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//
|
||
|
//=============================================================================//
|
||
|
// socket_stresstest.cpp : Defines the entry point for the console application.
|
||
|
//
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "utllinkedlist.h"
|
||
|
|
||
|
|
||
|
class CSocketInfo
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
bool IsValid()
|
||
|
{
|
||
|
return m_pSocket != 0;
|
||
|
}
|
||
|
|
||
|
void Term();
|
||
|
|
||
|
void ThreadFn();
|
||
|
|
||
|
|
||
|
|
||
|
public:
|
||
|
ITCPSocket *m_pSocket;
|
||
|
int m_iListenPort;
|
||
|
|
||
|
DWORD m_CreateTime; // When this socket was created.
|
||
|
DWORD m_ExpireTime;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
CSocketInfo g_Infos[132];
|
||
|
CRITICAL_SECTION g_CS, g_PrintCS;
|
||
|
HANDLE g_hThreads[ ARRAYSIZE( g_Infos ) ];
|
||
|
bool g_bShouldExit = false;
|
||
|
CUtlLinkedList<int,int> g_ListenPorts;
|
||
|
|
||
|
|
||
|
SpewRetval_t StressTestSpew( SpewType_t type, char const *pMsg )
|
||
|
{
|
||
|
EnterCriticalSection( &g_PrintCS );
|
||
|
printf( "%s", pMsg );
|
||
|
LeaveCriticalSection( &g_PrintCS );
|
||
|
|
||
|
if( type == SPEW_ASSERT )
|
||
|
return SPEW_DEBUGGER;
|
||
|
else if( type == SPEW_ERROR )
|
||
|
return SPEW_ABORT;
|
||
|
else
|
||
|
return SPEW_CONTINUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CSocketInfo::Term()
|
||
|
{
|
||
|
if ( m_pSocket )
|
||
|
{
|
||
|
m_pSocket->Release();
|
||
|
m_pSocket = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
CSocketInfo* FindOldestSocketInfo( CSocketInfo *pInfos, int nInfos )
|
||
|
{
|
||
|
int iOldest = 0;
|
||
|
DWORD oldestTime = 0xFFFFFFFF;
|
||
|
for ( int i=0; i < nInfos; i++ )
|
||
|
{
|
||
|
if ( !pInfos[i].IsValid() )
|
||
|
return &pInfos[i];
|
||
|
|
||
|
if ( pInfos[i].m_CreateTime < oldestTime )
|
||
|
{
|
||
|
oldestTime = pInfos[i].m_CreateTime;
|
||
|
iOldest = i;
|
||
|
}
|
||
|
}
|
||
|
return &pInfos[iOldest];
|
||
|
}
|
||
|
|
||
|
|
||
|
int g_iNextExpire = -1;
|
||
|
|
||
|
void CSocketInfo::ThreadFn()
|
||
|
{
|
||
|
int iInfo = this - g_Infos;
|
||
|
|
||
|
while ( !g_bShouldExit )
|
||
|
{
|
||
|
DWORD curTime = GetTickCount();
|
||
|
|
||
|
// Break the connection after a certain amount of time.
|
||
|
if ( m_pSocket && curTime >= m_ExpireTime )
|
||
|
{
|
||
|
Term();
|
||
|
Msg( "%02d: expire.\n", iInfo, m_iListenPort );
|
||
|
}
|
||
|
|
||
|
if ( m_pSocket )
|
||
|
{
|
||
|
EnterCriticalSection( &g_CS );
|
||
|
if ( g_iNextExpire == -1 )
|
||
|
{
|
||
|
g_iNextExpire = iInfo;
|
||
|
LeaveCriticalSection( &g_CS );
|
||
|
|
||
|
Msg( "%02d: forcing an expire.\n", iInfo, m_iListenPort );
|
||
|
Sleep( 16000 );
|
||
|
|
||
|
EnterCriticalSection( &g_CS );
|
||
|
g_iNextExpire = -1;
|
||
|
}
|
||
|
LeaveCriticalSection( &g_CS );
|
||
|
|
||
|
if ( m_pSocket->IsConnected() )
|
||
|
{
|
||
|
// Receive whatever data it has waiting for it.
|
||
|
CUtlVector<unsigned char> data;
|
||
|
while ( m_pSocket->Recv( data ) )
|
||
|
{
|
||
|
Msg( "%02d: recv %d.\n", iInfo, data.Count() );
|
||
|
}
|
||
|
|
||
|
// Send some data.
|
||
|
int size = rand() % 8192;
|
||
|
data.SetSize( size );
|
||
|
m_pSocket->Send( data.Base(), data.Count() );
|
||
|
//Msg( "%02d: send %d.\n", iInfo, data.Count() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Term();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Not initialized.. either listen or connect.
|
||
|
int iConnectPort = -1;
|
||
|
if ( rand() > VALVE_RAND_MAX/2 )
|
||
|
{
|
||
|
if ( rand() % 100 < 50 )
|
||
|
Sleep( 500 );
|
||
|
|
||
|
EnterCriticalSection( &g_CS );
|
||
|
int iHead = g_ListenPorts.Head();
|
||
|
if ( iHead != g_ListenPorts.InvalidIndex() )
|
||
|
iConnectPort = g_ListenPorts[iHead];
|
||
|
LeaveCriticalSection( &g_CS );
|
||
|
}
|
||
|
|
||
|
if ( iConnectPort != -1 )
|
||
|
{
|
||
|
CIPAddr addr( 127, 0, 0, 1, iConnectPort );
|
||
|
|
||
|
m_pSocket = CreateTCPSocket();
|
||
|
m_pSocket->BindToAny( 0 );
|
||
|
m_CreateTime = curTime;
|
||
|
m_ExpireTime = curTime + rand() % 5000;
|
||
|
if ( !TCPSocket_Connect( m_pSocket, &addr, 3.0f ) )
|
||
|
{
|
||
|
Term();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for ( int iTry=0; iTry < 32; iTry++ )
|
||
|
{
|
||
|
m_iListenPort = 100 + rand() % (VALVE_RAND_MAX/2);
|
||
|
ITCPListenSocket *pListenSocket = CreateTCPListenSocket( m_iListenPort );
|
||
|
if ( pListenSocket )
|
||
|
{
|
||
|
Msg( "%02d: listen on %d.\n", iInfo, m_iListenPort );
|
||
|
|
||
|
// Add us to the list of ports to connect to.
|
||
|
EnterCriticalSection( &g_CS );
|
||
|
g_ListenPorts.AddToTail( m_iListenPort );
|
||
|
LeaveCriticalSection( &g_CS );
|
||
|
|
||
|
// Listen for a connection.
|
||
|
CIPAddr connectedAddr;
|
||
|
m_pSocket = TCPSocket_ListenForOneConnection( pListenSocket, &connectedAddr, 4.0 );
|
||
|
|
||
|
// Remove us from the list of ports to connect to.
|
||
|
EnterCriticalSection( &g_CS );
|
||
|
g_ListenPorts.Remove( g_ListenPorts.Find( m_iListenPort ) );
|
||
|
LeaveCriticalSection( &g_CS );
|
||
|
|
||
|
pListenSocket->Release();
|
||
|
|
||
|
if ( m_pSocket )
|
||
|
{
|
||
|
Msg( "%02d: listen found connection.\n", iInfo );
|
||
|
m_CreateTime = curTime;
|
||
|
m_ExpireTime = curTime + rand() % 5000;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Sleep( 1 );
|
||
|
}
|
||
|
|
||
|
g_hThreads[iInfo] = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD WINAPI ThreadFn( LPVOID lpParameter )
|
||
|
{
|
||
|
CSocketInfo *pInfo = (CSocketInfo*)lpParameter;
|
||
|
pInfo->ThreadFn();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AllocError( unsigned long size )
|
||
|
{
|
||
|
Assert( false );
|
||
|
}
|
||
|
|
||
|
|
||
|
int main(int argc, char* argv[])
|
||
|
{
|
||
|
memset( g_Infos, 0, sizeof( g_Infos ) );
|
||
|
memset( g_hThreads, 0, sizeof( g_hThreads ) );
|
||
|
|
||
|
InitializeCriticalSection( &g_CS );
|
||
|
InitializeCriticalSection( &g_PrintCS );
|
||
|
|
||
|
SpewOutputFunc( StressTestSpew );
|
||
|
Plat_SetAllocErrorFn( AllocError );
|
||
|
|
||
|
SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
|
||
|
|
||
|
for ( int i=0; i < ARRAYSIZE( g_Infos ); i++ )
|
||
|
{
|
||
|
DWORD dwThreadID = 0;
|
||
|
g_hThreads[i] = CreateThread(
|
||
|
NULL,
|
||
|
0,
|
||
|
ThreadFn,
|
||
|
&g_Infos[i],
|
||
|
0,
|
||
|
&dwThreadID );
|
||
|
}
|
||
|
|
||
|
|
||
|
while ( !kbhit() )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
g_bShouldExit = true;
|
||
|
|
||
|
HANDLE hZeroArray[ ARRAYSIZE( g_Infos ) ];
|
||
|
memset( hZeroArray, 0, sizeof( hZeroArray ) );
|
||
|
|
||
|
while ( memcmp( hZeroArray, g_hThreads, sizeof( hZeroArray ) ) != 0 )
|
||
|
{
|
||
|
Sleep( 10 );
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|