//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "stdafx.h" #include "service_conn_mgr.h" #include "vmpi.h" #include "tier0/dbg.h" #include "tcpsocket_helpers.h" #define SERVICECONNMGR_CONNECT_ATTEMPT_INTERVAL 1000 // ------------------------------------------------------------------------------------------- // // CServiceConn. // ------------------------------------------------------------------------------------------- // CServiceConn::CServiceConn() { m_pSocket = NULL; } CServiceConn::~CServiceConn() { if ( m_pSocket ) m_pSocket->Release(); } // ------------------------------------------------------------------------------------------- // // CServiceConnMgr. // ------------------------------------------------------------------------------------------- // CServiceConnMgr::CServiceConnMgr() { m_bServer = false; m_bShuttingDown = false; m_pListenSocket = NULL; } CServiceConnMgr::~CServiceConnMgr() { Term(); } bool CServiceConnMgr::InitServer() { Term(); m_bServer = true; // Create a socket to listen on. for ( int iPort=VMPI_SERVICE_FIRST_UI_PORT; iPort <= VMPI_SERVICE_LAST_UI_PORT; iPort++ ) { m_pListenSocket = CreateTCPListenSocketEmu( iPort, 5 ); if ( m_pListenSocket ) break; } if ( !m_pListenSocket ) return false; return true; } bool CServiceConnMgr::InitClient() { Term(); m_bServer = false; AttemptConnect(); return true; } void CServiceConnMgr::Term() { m_bShuttingDown = true; // This prevents some reentrancy. // Get rid of our registry key. if ( m_pListenSocket ) { m_pListenSocket->Release(); m_pListenSocket = NULL; } m_Connections.PurgeAndDeleteElements(); m_bShuttingDown = false; } bool CServiceConnMgr::IsConnected() { return m_Connections.Count() != 0; } void CServiceConnMgr::Update() { DWORD curTime = GetTickCount(); // Connect if we're an unconnected client. if ( m_bServer ) { if ( m_pListenSocket ) { // Listen for more connections. while ( 1 ) { CIPAddr addr; ITCPSocket *pSocket = m_pListenSocket->UpdateListen( &addr ); if ( !pSocket ) break; CServiceConn *pConn = new CServiceConn; pConn->m_ID = m_Connections.AddToTail( pConn ); pConn->m_LastRecvTime = curTime; pConn->m_pSocket = pSocket; OnNewConnection( pConn->m_ID ); } } } else { if ( !IsConnected() && curTime - m_LastConnectAttemptTime >= SERVICECONNMGR_CONNECT_ATTEMPT_INTERVAL ) { AttemptConnect(); } } // Check for timeouts and send acks. int iNext; for ( int iCur=m_Connections.Head(); iCur != m_Connections.InvalidIndex(); iCur=iNext ) { iNext = m_Connections.Next( iCur ); CServiceConn *pConn = m_Connections[iCur]; if ( pConn->m_pSocket->IsConnected() ) { DWORD startTime = GetTickCount(); CUtlVector data; while ( pConn->m_pSocket->Recv( data ) ) { HandlePacket( (char*)data.Base(), data.Count() ); // Don't sit in this loop too long. if ( (GetTickCount() - startTime) > 50 ) break; } } else { OnTerminateConnection( iCur ); m_Connections.Remove( iCur ); delete pConn; } } } void CServiceConnMgr::SendPacket( int id, const void *pData, int len ) { if ( id == -1 ) { FOR_EACH_LL( m_Connections, i ) { m_Connections[i]->m_pSocket->Send( pData, len ); } } else { m_Connections[id]->m_pSocket->Send( pData, len ); } } void CServiceConnMgr::AttemptConnect() { m_LastConnectAttemptTime = GetTickCount(); ITCPSocket *pSocket = NULL; for ( int iPort=VMPI_SERVICE_FIRST_UI_PORT; iPort <= VMPI_SERVICE_LAST_UI_PORT; iPort++ ) { pSocket = CreateTCPSocketEmu(); if ( !pSocket || !pSocket->BindToAny( 0 ) ) return; CIPAddr addr( 127, 0, 0, 1, iPort ); if ( TCPSocket_Connect( pSocket, &addr, 0.1 ) ) break; pSocket->Release(); pSocket = NULL; } if ( pSocket ) { CServiceConn *pConn = new CServiceConn; pConn->m_ID = m_Connections.AddToTail( pConn ); pConn->m_LastRecvTime = GetTickCount(); pConn->m_pSocket = pSocket; OnNewConnection( pConn->m_ID ); } } void CServiceConnMgr::OnNewConnection( int id ) { } void CServiceConnMgr::OnTerminateConnection( int id ) { } void CServiceConnMgr::HandlePacket( const char *pData, int len ) { }