diff options
Diffstat (limited to 'common/valve_ipc_win32.h')
| -rw-r--r-- | common/valve_ipc_win32.h | 937 |
1 files changed, 937 insertions, 0 deletions
diff --git a/common/valve_ipc_win32.h b/common/valve_ipc_win32.h new file mode 100644 index 0000000..13e63c8 --- /dev/null +++ b/common/valve_ipc_win32.h @@ -0,0 +1,937 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef VALVE_IPC_WIN32 +#define VALVE_IPC_WIN32 +#ifdef _WIN32 +#pragma once +#endif + +#include <rpcdce.h> + +// Fwd declarations +class CValveIpcMgr; +class CValveIpcServer; +class CValveIpcClient; +class CValveIpcChannel; + +// Version of the protocol +#define VALVE_IPC_PROTOCOL_VER "1" + +// Memory used for Valve IPC manager = 256 kB +#define VALVE_IPC_MGR_MEMORY 256 * 1024 +// Name for Valve IPC manager +#define VALVE_IPC_MGR_NAME "VALVE_IPC_MGR_" + +// Default IPC manager interaction timeout = 5 sec +#define VALVE_IPC_TIMEOUT 5 * 1000 + +// Valve IPC client-server pipe timeout = 5 sec +#define VALVE_IPC_CS_TIMEOUT 5 * 1000 + +// Valve IPC client-server pipe buffer = 64 kB +#define VALVE_IPC_CS_BUFFER 64 * 1024 + +#define VALVE_IPC_IMPL inline + +// +// CValveIpcMgr +// Used to discover, register, unregister IPC servers +// +// Internally the memory is stored as: +// [zero-terminated server name-1] [128-bit UUID] +// [zero-terminated server name-2] [128-bit UUID] +// ... +// [zero-terminated server name-N] [128-bit UUID] +// [<empty string>] [GUID_NULL] +// +class CValveIpcMgr +{ + friend CValveIpcServer; + friend CValveIpcClient; + +protected: // Create-able only by server/client + CValveIpcMgr(); + ~CValveIpcMgr(); + +public: + BOOL Init( DWORD dwTimeout ); + +public: + BOOL DiscoverServer( char const *szServerName, RPC_CSTR *pszServerUID ); + BOOL RegisterServer( char const *szServerName, RPC_CSTR *pszServerUID ); + BOOL UnregisterServer( RPC_CSTR szServerUID ); + +public: + HANDLE DuplicateMemorySegmentHandle(); + +private: + BOOL Shutdown(); + +private: + HANDLE m_hMutex; + HANDLE m_hMemorySegment; + char *m_pMemory; + +private: + class Iterator + { + public: + explicit Iterator( char *m_pMemory = NULL ) + { + m_szServerName = m_pMemory ? m_pMemory : ""; + if ( *m_szServerName ) + { + memcpy( &m_uuid, m_szServerName + strlen( m_szServerName ) + 1, sizeof( UUID ) ); + } + else + { + m_uuid = GUID_NULL; + } + } + + public: + BOOL IsValid() const + { + return m_szServerName && *m_szServerName && + memcmp( &m_uuid, &GUID_NULL, sizeof( UUID ) ); + } + + Iterator Next() const + { + return IsValid() ? + Iterator( m_szServerName + strlen( m_szServerName ) + 1 + sizeof( UUID ) ) : + Iterator( NULL ); + } + + public: + char * WriteIntoMemory( char *pMemory ) const + { + size_t nLen = strlen( m_szServerName ) + 1; + memmove( pMemory, m_szServerName, strlen( m_szServerName ) + 1 ); + memmove( pMemory + nLen, &m_uuid, sizeof( UUID ) ); + return pMemory + nLen + sizeof( UUID ); + } + + public: + char *m_szServerName; + UUID m_uuid; + }; +}; + +// +// CValveIpcServer +// Used to host an IPC server +// +class CValveIpcServer +{ +public: + explicit CValveIpcServer( char const *szServerName ); + ~CValveIpcServer(); + +public: + BOOL Register(); + BOOL Unregister(); + +public: + virtual BOOL ExecuteCommand( char *bufCommand, DWORD numCommandBytes, char *bufResult, DWORD &numResultBytes ) = 0; + +public: + BOOL Start(); + BOOL Stop(); + BOOL IsRunning() const { return m_hThread && m_bRunning; } + +public: + BOOL EnsureRegisteredAndRunning() + { + if ( IsRunning() ) + return TRUE; + + if ( Register() && + Start() && + IsRunning() ) + return TRUE; + + Unregister(); + return FALSE; + } + BOOL EnsureStoppedAndUnregistered() + { + Unregister(); + return TRUE; + } + +public: + static DWORD WINAPI RunDelegate( LPVOID lpvParam ); + DWORD RunImpl(); + +protected: + BOOL WaitForEvent(); + BOOL WaitForClient(); + BOOL WaitForCommand(); + BOOL WaitForResult(); + +protected: + char *m_szServerName; + RPC_CSTR m_szServerUID; + + HANDLE m_hMemorySegment; + HANDLE m_hServerAlive; + + HANDLE m_hServerPipe; + HANDLE m_hPipeEvent; + + HANDLE m_hThread; + BOOL m_bRunning; + + char *m_pBufferRead; + DWORD m_cbBufferRead; + + char *m_pBufferWrite; + DWORD m_cbBufferWrite; +}; + +// +// CValveIpcClient +// Used to discover a server and establish a comm channel +// +class CValveIpcClient +{ +public: + explicit CValveIpcClient( char const *szServerName ); + ~CValveIpcClient(); + +public: + BOOL Connect(); + BOOL Disconnect(); + +public: + BOOL ExecuteCommand( LPVOID bufIn, DWORD numInBytes, LPVOID bufOut, DWORD &numOutBytes ); + +protected: + char *m_szServerName; + RPC_CSTR m_szServerUID; + + HANDLE m_hClientPipe; +}; + + +#ifdef UTLBUFFER_H + + +class CValveIpcServerUtl : public CValveIpcServer +{ +public: + explicit CValveIpcServerUtl( char const *szServerName ) : CValveIpcServer( szServerName ) {} + virtual BOOL ExecuteCommand( char *bufCommand, DWORD numCommandBytes, char *bufResult, DWORD &numResultBytes ) + { + CUtlBuffer cmd( bufCommand, numCommandBytes, CUtlBuffer::READ_ONLY ); + CUtlBuffer res( bufResult, VALVE_IPC_CS_BUFFER, int( 0 ) ); + if ( !ExecuteCommand( cmd, res ) ) + return FALSE; + numResultBytes = res.TellPut(); + return TRUE; + } + virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) = 0; +}; + +class CValveIpcClientUtl : public CValveIpcClient +{ +public: + explicit CValveIpcClientUtl( char const *szServerName ) : CValveIpcClient( szServerName ) {} + using CValveIpcClient::ExecuteCommand; + BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) + { + DWORD numResBytes = res.Size(); + if ( !ExecuteCommand( cmd.Base(), cmd.TellPut(), res.Base(), numResBytes ) ) + return FALSE; + res.SeekPut( CUtlBuffer::SEEK_HEAD, numResBytes ); + return TRUE; + } +}; + + +#endif // UTLBUFFER_H + + + + + +////////////////////////////////////////////////////////////////////////// +// +// Implementation section of CValveIpcMgr +// +////////////////////////////////////////////////////////////////////////// + + +VALVE_IPC_IMPL CValveIpcMgr::CValveIpcMgr() : + m_hMutex( NULL ), + m_hMemorySegment( NULL ), + m_pMemory( NULL ) +{ +} + +VALVE_IPC_IMPL CValveIpcMgr::~CValveIpcMgr() +{ + Shutdown(); +} + +VALVE_IPC_IMPL BOOL CValveIpcMgr::Init( DWORD dwTimeout ) +{ + if ( m_pMemory ) + return TRUE; + + m_hMutex = ::CreateMutex( NULL, FALSE, VALVE_IPC_MGR_NAME "_MTX_" VALVE_IPC_PROTOCOL_VER ); + DWORD dwWaitResult = m_hMutex ? ::WaitForSingleObject( m_hMutex, dwTimeout ) : WAIT_FAILED; + + if ( dwWaitResult == WAIT_OBJECT_0 || + dwWaitResult == WAIT_ABANDONED_0 ) + { + // We own the mgr segment + + m_hMemorySegment = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, VALVE_IPC_MGR_MEMORY, + VALVE_IPC_MGR_NAME "_MEM_" VALVE_IPC_PROTOCOL_VER ); + + if ( m_hMemorySegment ) + { + LPVOID lpvMemSegment = ::MapViewOfFile( m_hMemorySegment, FILE_MAP_ALL_ACCESS, 0, 0, 0 ); + + if ( lpvMemSegment ) + { + m_pMemory = ( char * ) lpvMemSegment; + return TRUE; + } + } + } + + if ( dwWaitResult == WAIT_OBJECT_0 || + dwWaitResult == WAIT_ABANDONED_0 ) + { + ::ReleaseMutex( m_hMutex ); + ::CloseHandle( m_hMutex ); + m_hMutex = NULL; + } + + // Otherwise shutdown due to an init error + Shutdown(); + return FALSE; +} + +VALVE_IPC_IMPL BOOL CValveIpcMgr::Shutdown() +{ + if ( m_pMemory ) + { + ::UnmapViewOfFile( m_pMemory ); + m_pMemory = NULL; + } + + if ( m_hMemorySegment ) + { + ::CloseHandle( m_hMemorySegment ); + m_hMemorySegment = NULL; + } + + if ( m_hMutex ) + { + ::ReleaseMutex( m_hMutex ); + ::CloseHandle( m_hMutex ); + m_hMutex = NULL; + } + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcMgr::DiscoverServer( char const *szServerName, RPC_CSTR *pszServerUID ) +{ + if ( !szServerName || !*szServerName ) + return FALSE; + + for ( Iterator it( m_pMemory ); it.IsValid(); it = it.Next() ) + { + if ( !stricmp( szServerName, it.m_szServerName ) ) + { + if ( pszServerUID ) + { + UuidToString( &it.m_uuid, pszServerUID ); + } + return TRUE; + } + } + return FALSE; +} + +VALVE_IPC_IMPL BOOL CValveIpcMgr::RegisterServer( char const *szServerName, RPC_CSTR *pszServerUID ) +{ + if ( !szServerName || !*szServerName ) + return FALSE; + + Iterator it( m_pMemory ); + for ( ; it.IsValid(); it = it.Next() ) + { + if ( !stricmp( szServerName, it.m_szServerName ) ) + { + // Server with same name already registered, + // check if it is alive + char chAliveName[ MAX_PATH ]; + RPC_CSTR szBaseName; + UuidToString( &it.m_uuid, &szBaseName ); + sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, szBaseName ); + RpcStringFree( &szBaseName ); + HANDLE hAliveTest = ::OpenMutex( MUTEX_ALL_ACCESS, FALSE, chAliveName ); + if ( hAliveTest ) + { + ::CloseHandle( hAliveTest ); + return FALSE; // Server is alive, can't register again + } + else + { + // Server is dead, re-use its UID + if ( pszServerUID ) + { + UuidToString( &it.m_uuid, pszServerUID ); + } + return TRUE; + } + } + } + + // Iterator points at the last element in the list, write the new server info + Iterator itNewServer; + itNewServer.m_szServerName = const_cast< char * >( szServerName ); + UuidCreate( &itNewServer.m_uuid ); + + // Check that there's enough memory left in the storage + char *pUpdateMemory = it.m_szServerName; + if ( pUpdateMemory + strlen( szServerName ) + 1 + 32 + 2 * sizeof( UUID ) > + m_pMemory + VALVE_IPC_MGR_MEMORY ) + { + return FALSE; + } + + // Insert the new server in the list + pUpdateMemory = itNewServer.WriteIntoMemory( pUpdateMemory ); + pUpdateMemory = Iterator().WriteIntoMemory( pUpdateMemory ); + + if ( pszServerUID ) + { + UuidToString( &itNewServer.m_uuid, pszServerUID ); + } + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcMgr::UnregisterServer( RPC_CSTR szServerUID ) +{ + if ( !szServerUID || !*szServerUID ) + return FALSE; + + RPC_STATUS rpcS; + UUID uuid; + if ( RPC_S_OK != UuidFromString( szServerUID, &uuid ) ) + return FALSE; + + for ( Iterator it( m_pMemory ); it.IsValid(); it = it.Next() ) + { + if ( UuidEqual( &it.m_uuid, &uuid, &rpcS ) ) + { + // This is our server, remove it from the list + char *pMemoryUpdate = it.m_szServerName; + for ( Iterator itRemaining = it.Next(); itRemaining.IsValid(); ) + { + Iterator itNext = itRemaining.Next(); + pMemoryUpdate = itRemaining.WriteIntoMemory( pMemoryUpdate ); + itRemaining = itNext; + } + Iterator().WriteIntoMemory( pMemoryUpdate ); + + return TRUE; + } + } + return FALSE; +} + +VALVE_IPC_IMPL HANDLE CValveIpcMgr::DuplicateMemorySegmentHandle() +{ + if ( !m_hMemorySegment ) + return NULL; + + HANDLE hDup = NULL; + ::DuplicateHandle( GetCurrentProcess(), m_hMemorySegment, + GetCurrentProcess(), &hDup, DUPLICATE_SAME_ACCESS, + FALSE, DUPLICATE_SAME_ACCESS ); + + return hDup; +} + + + +////////////////////////////////////////////////////////////////////////// +// +// Implementation section of CValveIpcServer +// +////////////////////////////////////////////////////////////////////////// + +VALVE_IPC_IMPL CValveIpcServer::CValveIpcServer( char const *szServerName ) +{ + // Copy server name + size_t nLen = szServerName ? strlen( szServerName ) : 0; + m_szServerName = new char[ nLen + 1 ]; + strcpy( m_szServerName, szServerName ? szServerName : "" ); + + // Init remaining + m_szServerUID = NULL; + m_hMemorySegment = NULL; + m_hServerAlive = NULL; + m_hServerPipe = NULL; + m_hPipeEvent = NULL; + m_hThread = NULL; + m_bRunning = FALSE; + + m_pBufferRead = NULL; + m_cbBufferRead = 0; + m_pBufferWrite = NULL; + m_cbBufferWrite = 0; +} + +VALVE_IPC_IMPL CValveIpcServer::~CValveIpcServer() +{ + Unregister(); + + if ( m_szServerName ) + { + delete [] m_szServerName; + m_szServerName = NULL; + } +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::Register() +{ + if ( m_szServerUID ) + return TRUE; + + CValveIpcMgr mgr; + if ( !mgr.Init( VALVE_IPC_TIMEOUT ) ) + return FALSE; + + // Try registering the server + if ( !mgr.RegisterServer( m_szServerName, &m_szServerUID ) ) + return FALSE; + + // Server got registered, duplicate memory segment handle + m_hMemorySegment = mgr.DuplicateMemorySegmentHandle(); + + // create the "server alive" object + char chAliveName[ MAX_PATH ]; + sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID ); + m_hServerAlive = ::CreateMutex( NULL, FALSE, chAliveName ); + if ( !m_hServerAlive ) + { + Unregister(); + return FALSE; + } + + // Create the server pipe event + m_hPipeEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL ); + if ( !m_hPipeEvent ) + { + Unregister(); + return FALSE; + } + + // Create the server end of the pipe + char chPipeName[ MAX_PATH ]; + sprintf( chPipeName, "\\\\.\\pipe\\" "%s" "_PIPE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID ); + m_hServerPipe = ::CreateNamedPipe( + chPipeName, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + 1, + VALVE_IPC_CS_BUFFER, VALVE_IPC_CS_BUFFER, + VALVE_IPC_CS_TIMEOUT, + NULL + ); + if ( !m_hServerPipe ) + { + Unregister(); + return FALSE; + } + + // Allocate the pipe buffer + m_pBufferRead = new char [ VALVE_IPC_CS_BUFFER ]; + if ( !m_pBufferRead ) + { + Unregister(); + return FALSE; + } + m_pBufferWrite = new char [ VALVE_IPC_CS_BUFFER ]; + if ( !m_pBufferWrite ) + { + Unregister(); + return FALSE; + } + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::Unregister() +{ + if ( !m_szServerUID ) + return FALSE; + else + { + CValveIpcMgr mgr; + if ( mgr.Init( VALVE_IPC_TIMEOUT ) ) + { + mgr.UnregisterServer( m_szServerUID ); + } + } + + // Stop the server if it is running + Stop(); + + m_cbBufferRead = 0; + delete [] m_pBufferRead; + m_pBufferRead = NULL; + + m_cbBufferWrite = 0; + delete [] m_pBufferWrite; + m_pBufferWrite = NULL; + + if ( m_hServerPipe ) + { + ::CloseHandle( m_hServerPipe ); + m_hServerPipe = NULL; + } + + if ( m_hPipeEvent ) + { + ::CloseHandle( m_hPipeEvent ); + m_hPipeEvent = NULL; + } + + if ( m_hServerAlive ) + { + ::CloseHandle( m_hServerAlive ); + m_hServerAlive = NULL; + } + + if ( m_hMemorySegment ) + { + ::CloseHandle( m_hMemorySegment ); + m_hMemorySegment = NULL; + } + + if ( m_szServerUID ) + { + RpcStringFree( &m_szServerUID ); + m_szServerUID = NULL; + } + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForEvent() +{ + for ( ; m_bRunning ; ) + { + DWORD dwWaitResult = ::WaitForSingleObject( m_hPipeEvent, 50 ); + switch ( dwWaitResult ) + { + case WAIT_TIMEOUT: + continue; + + case WAIT_OBJECT_0: + case WAIT_ABANDONED_0: + ::ResetEvent( m_hPipeEvent ); + return m_bRunning; + + default: + return FALSE; + } + } + + return FALSE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForClient() +{ + OVERLAPPED ov; + memset( &ov, 0, sizeof( ov ) ); + ov.hEvent = m_hPipeEvent; + + BOOL bResult = ::ConnectNamedPipe( m_hServerPipe, &ov ); + if ( bResult ) // Overlapped "ConnectNamedPipe" always returns FALSE + return FALSE; + + switch ( GetLastError() ) + { + case ERROR_IO_PENDING: + // Wait for client to connect + break; + + case ERROR_PIPE_CONNECTED: + SetEvent( ov.hEvent ); + return TRUE; + + default: + return FALSE; + } + + if ( !WaitForEvent() ) + return FALSE; + + DWORD dwConnectDummy; + if ( !::GetOverlappedResult( m_hServerPipe, &ov, &dwConnectDummy, FALSE ) ) + return FALSE; + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForCommand() +{ + OVERLAPPED ov; + memset( &ov, 0, sizeof( ov ) ); + ov.hEvent = m_hPipeEvent; + + m_cbBufferRead = 0; + BOOL bRead = ::ReadFile( m_hServerPipe, m_pBufferRead, VALVE_IPC_CS_BUFFER, &m_cbBufferRead, &ov ); + + if ( bRead && + m_cbBufferRead ) + return TRUE; + + if ( !bRead && + GetLastError() == ERROR_IO_PENDING ) + { + if ( !WaitForEvent() ) + return FALSE; + + bRead = GetOverlappedResult( m_hServerPipe, &ov, &m_cbBufferRead, FALSE ); + if ( !bRead || !m_cbBufferRead ) + return FALSE; + + return TRUE; + } + + return FALSE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForResult() +{ + OVERLAPPED ov; + memset( &ov, 0, sizeof( ov ) ); + ov.hEvent = m_hPipeEvent; + + DWORD cbWrite; + BOOL bWrite = ::WriteFile( m_hServerPipe, m_pBufferWrite, m_cbBufferWrite, &cbWrite, &ov ); + + if ( bWrite && + cbWrite == m_cbBufferWrite ) + return TRUE; + + if ( !bWrite && + GetLastError() == ERROR_IO_PENDING ) + { + if ( !WaitForEvent() ) + return FALSE; + + bWrite = GetOverlappedResult( m_hServerPipe, &ov, &cbWrite, FALSE ); + if ( !bWrite || + cbWrite != m_cbBufferWrite ) + return FALSE; + + return TRUE; + } + + return FALSE; +} + +VALVE_IPC_IMPL DWORD WINAPI CValveIpcServer::RunDelegate( LPVOID lpvParam ) +{ + return reinterpret_cast< CValveIpcServer * >( lpvParam )->RunImpl(); +} + +VALVE_IPC_IMPL DWORD CValveIpcServer::RunImpl() +{ + for ( ; WaitForClient() ; ) + { + for ( ; WaitForCommand() ; ) + { + m_cbBufferWrite = 0; + BOOL bResult = ExecuteCommand( m_pBufferRead, m_cbBufferRead, m_pBufferWrite, m_cbBufferWrite ); + if ( !bResult || !m_cbBufferWrite ) + break; + + bResult = WaitForResult(); + if ( !bResult ) + break; + } + + ::DisconnectNamedPipe( m_hServerPipe ); + } + + m_bRunning = FALSE; + return FALSE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::Start() +{ + if ( m_hThread ) + return FALSE; + + m_hThread = ::CreateThread( NULL, 0, RunDelegate, this, CREATE_SUSPENDED, NULL ); + if ( !m_hThread ) + return FALSE; + + m_bRunning = TRUE; + ::ResumeThread( m_hThread ); + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcServer::Stop() +{ + if ( !m_hThread ) + return FALSE; + + m_bRunning = FALSE; + ::WaitForSingleObject( m_hThread, INFINITE ); + + ::CloseHandle( m_hThread ); + m_hThread = NULL; + + return TRUE; +} + + +////////////////////////////////////////////////////////////////////////// +// +// Implementation section of CValveIpcClient +// +////////////////////////////////////////////////////////////////////////// + + +VALVE_IPC_IMPL CValveIpcClient::CValveIpcClient( char const *szServerName ) +{ + // Copy server name + size_t nLen = szServerName ? strlen( szServerName ) : 0; + m_szServerName = new char[ nLen + 1 ]; + strcpy( m_szServerName, szServerName ? szServerName : "" ); + + // Init remaining + m_szServerUID = NULL; + m_hClientPipe = NULL; +} + +VALVE_IPC_IMPL CValveIpcClient::~CValveIpcClient() +{ + Disconnect(); + + if ( m_szServerName ) + { + delete [] m_szServerName; + m_szServerName = NULL; + } +} + +VALVE_IPC_IMPL BOOL CValveIpcClient::Connect() +{ + if ( m_szServerUID ) + return TRUE; + + CValveIpcMgr mgr; + if ( !mgr.Init( VALVE_IPC_TIMEOUT ) ) + return FALSE; + + // Try discovering the server + if ( !mgr.DiscoverServer( m_szServerName, &m_szServerUID ) ) + return FALSE; + + // Server got discovered + // check the "server alive" object + char chAliveName[ MAX_PATH ]; + sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID ); + + HANDLE hServerAlive = ::OpenMutex( MUTEX_ALL_ACCESS, FALSE, chAliveName ); + if ( !hServerAlive ) + { + Disconnect(); + return FALSE; + } + else + { + ::CloseHandle( hServerAlive ); + hServerAlive = NULL; + } + + // Connect the server pipe + char chPipeName[ MAX_PATH ]; + sprintf( chPipeName, "\\\\.\\pipe\\" "%s" "_PIPE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID ); + m_hClientPipe = ::CreateFile( + chPipeName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_WRITE_THROUGH, + NULL + ); + if ( !m_hClientPipe ) + { + Disconnect(); + return FALSE; + } + + DWORD dwPipeMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState( m_hClientPipe, &dwPipeMode, NULL, NULL ); + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcClient::Disconnect() +{ + if ( !m_szServerUID ) + return FALSE; + + if ( m_hClientPipe ) + { + ::CloseHandle( m_hClientPipe ); + m_hClientPipe = NULL; + } + + if ( m_szServerUID ) + { + RpcStringFree( &m_szServerUID ); + m_szServerUID = NULL; + } + + return TRUE; +} + +VALVE_IPC_IMPL BOOL CValveIpcClient::ExecuteCommand( LPVOID bufIn, DWORD numInBytes, LPVOID bufOut, DWORD &numOutBytes ) +{ + if ( !m_szServerUID || !m_hClientPipe ) + return FALSE; + + BOOL bTransact = TransactNamedPipe( m_hClientPipe, + bufIn, numInBytes, + bufOut, numOutBytes, + &numOutBytes, + NULL ); + if ( !bTransact && + GetLastError() == ERROR_MORE_DATA ) + { + bTransact = TRUE; + } + return bTransact; +} + + + + +#endif // #ifndef VALVE_IPC_WIN32 |