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.

937 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #ifndef VALVE_IPC_WIN32
  9. #define VALVE_IPC_WIN32
  10. #ifdef _WIN32
  11. #pragma once
  12. #endif
  13. #include <rpcdce.h>
  14. // Fwd declarations
  15. class CValveIpcMgr;
  16. class CValveIpcServer;
  17. class CValveIpcClient;
  18. class CValveIpcChannel;
  19. // Version of the protocol
  20. #define VALVE_IPC_PROTOCOL_VER "1"
  21. // Memory used for Valve IPC manager = 256 kB
  22. #define VALVE_IPC_MGR_MEMORY 256 * 1024
  23. // Name for Valve IPC manager
  24. #define VALVE_IPC_MGR_NAME "VALVE_IPC_MGR_"
  25. // Default IPC manager interaction timeout = 5 sec
  26. #define VALVE_IPC_TIMEOUT 5 * 1000
  27. // Valve IPC client-server pipe timeout = 5 sec
  28. #define VALVE_IPC_CS_TIMEOUT 5 * 1000
  29. // Valve IPC client-server pipe buffer = 64 kB
  30. #define VALVE_IPC_CS_BUFFER 64 * 1024
  31. #define VALVE_IPC_IMPL inline
  32. //
  33. // CValveIpcMgr
  34. // Used to discover, register, unregister IPC servers
  35. //
  36. // Internally the memory is stored as:
  37. // [zero-terminated server name-1] [128-bit UUID]
  38. // [zero-terminated server name-2] [128-bit UUID]
  39. // ...
  40. // [zero-terminated server name-N] [128-bit UUID]
  41. // [<empty string>] [GUID_NULL]
  42. //
  43. class CValveIpcMgr
  44. {
  45. friend CValveIpcServer;
  46. friend CValveIpcClient;
  47. protected: // Create-able only by server/client
  48. CValveIpcMgr();
  49. ~CValveIpcMgr();
  50. public:
  51. BOOL Init( DWORD dwTimeout );
  52. public:
  53. BOOL DiscoverServer( char const *szServerName, RPC_CSTR *pszServerUID );
  54. BOOL RegisterServer( char const *szServerName, RPC_CSTR *pszServerUID );
  55. BOOL UnregisterServer( RPC_CSTR szServerUID );
  56. public:
  57. HANDLE DuplicateMemorySegmentHandle();
  58. private:
  59. BOOL Shutdown();
  60. private:
  61. HANDLE m_hMutex;
  62. HANDLE m_hMemorySegment;
  63. char *m_pMemory;
  64. private:
  65. class Iterator
  66. {
  67. public:
  68. explicit Iterator( char *m_pMemory = NULL )
  69. {
  70. m_szServerName = m_pMemory ? m_pMemory : "";
  71. if ( *m_szServerName )
  72. {
  73. memcpy( &m_uuid, m_szServerName + strlen( m_szServerName ) + 1, sizeof( UUID ) );
  74. }
  75. else
  76. {
  77. m_uuid = GUID_NULL;
  78. }
  79. }
  80. public:
  81. BOOL IsValid() const
  82. {
  83. return m_szServerName && *m_szServerName &&
  84. memcmp( &m_uuid, &GUID_NULL, sizeof( UUID ) );
  85. }
  86. Iterator Next() const
  87. {
  88. return IsValid() ?
  89. Iterator( m_szServerName + strlen( m_szServerName ) + 1 + sizeof( UUID ) ) :
  90. Iterator( NULL );
  91. }
  92. public:
  93. char * WriteIntoMemory( char *pMemory ) const
  94. {
  95. size_t nLen = strlen( m_szServerName ) + 1;
  96. memmove( pMemory, m_szServerName, strlen( m_szServerName ) + 1 );
  97. memmove( pMemory + nLen, &m_uuid, sizeof( UUID ) );
  98. return pMemory + nLen + sizeof( UUID );
  99. }
  100. public:
  101. char *m_szServerName;
  102. UUID m_uuid;
  103. };
  104. };
  105. //
  106. // CValveIpcServer
  107. // Used to host an IPC server
  108. //
  109. class CValveIpcServer
  110. {
  111. public:
  112. explicit CValveIpcServer( char const *szServerName );
  113. ~CValveIpcServer();
  114. public:
  115. BOOL Register();
  116. BOOL Unregister();
  117. public:
  118. virtual BOOL ExecuteCommand( char *bufCommand, DWORD numCommandBytes, char *bufResult, DWORD &numResultBytes ) = 0;
  119. public:
  120. BOOL Start();
  121. BOOL Stop();
  122. BOOL IsRunning() const { return m_hThread && m_bRunning; }
  123. public:
  124. BOOL EnsureRegisteredAndRunning()
  125. {
  126. if ( IsRunning() )
  127. return TRUE;
  128. if ( Register() &&
  129. Start() &&
  130. IsRunning() )
  131. return TRUE;
  132. Unregister();
  133. return FALSE;
  134. }
  135. BOOL EnsureStoppedAndUnregistered()
  136. {
  137. Unregister();
  138. return TRUE;
  139. }
  140. public:
  141. static DWORD WINAPI RunDelegate( LPVOID lpvParam );
  142. DWORD RunImpl();
  143. protected:
  144. BOOL WaitForEvent();
  145. BOOL WaitForClient();
  146. BOOL WaitForCommand();
  147. BOOL WaitForResult();
  148. protected:
  149. char *m_szServerName;
  150. RPC_CSTR m_szServerUID;
  151. HANDLE m_hMemorySegment;
  152. HANDLE m_hServerAlive;
  153. HANDLE m_hServerPipe;
  154. HANDLE m_hPipeEvent;
  155. HANDLE m_hThread;
  156. BOOL m_bRunning;
  157. char *m_pBufferRead;
  158. DWORD m_cbBufferRead;
  159. char *m_pBufferWrite;
  160. DWORD m_cbBufferWrite;
  161. };
  162. //
  163. // CValveIpcClient
  164. // Used to discover a server and establish a comm channel
  165. //
  166. class CValveIpcClient
  167. {
  168. public:
  169. explicit CValveIpcClient( char const *szServerName );
  170. ~CValveIpcClient();
  171. public:
  172. BOOL Connect();
  173. BOOL Disconnect();
  174. public:
  175. BOOL ExecuteCommand( LPVOID bufIn, DWORD numInBytes, LPVOID bufOut, DWORD &numOutBytes );
  176. protected:
  177. char *m_szServerName;
  178. RPC_CSTR m_szServerUID;
  179. HANDLE m_hClientPipe;
  180. };
  181. #ifdef UTLBUFFER_H
  182. class CValveIpcServerUtl : public CValveIpcServer
  183. {
  184. public:
  185. explicit CValveIpcServerUtl( char const *szServerName ) : CValveIpcServer( szServerName ) {}
  186. virtual BOOL ExecuteCommand( char *bufCommand, DWORD numCommandBytes, char *bufResult, DWORD &numResultBytes )
  187. {
  188. CUtlBuffer cmd( bufCommand, numCommandBytes, CUtlBuffer::READ_ONLY );
  189. CUtlBuffer res( bufResult, VALVE_IPC_CS_BUFFER, int( 0 ) );
  190. if ( !ExecuteCommand( cmd, res ) )
  191. return FALSE;
  192. numResultBytes = res.TellPut();
  193. return TRUE;
  194. }
  195. virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) = 0;
  196. };
  197. class CValveIpcClientUtl : public CValveIpcClient
  198. {
  199. public:
  200. explicit CValveIpcClientUtl( char const *szServerName ) : CValveIpcClient( szServerName ) {}
  201. using CValveIpcClient::ExecuteCommand;
  202. BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res )
  203. {
  204. DWORD numResBytes = res.Size();
  205. if ( !ExecuteCommand( cmd.Base(), cmd.TellPut(), res.Base(), numResBytes ) )
  206. return FALSE;
  207. res.SeekPut( CUtlBuffer::SEEK_HEAD, numResBytes );
  208. return TRUE;
  209. }
  210. };
  211. #endif // UTLBUFFER_H
  212. //////////////////////////////////////////////////////////////////////////
  213. //
  214. // Implementation section of CValveIpcMgr
  215. //
  216. //////////////////////////////////////////////////////////////////////////
  217. VALVE_IPC_IMPL CValveIpcMgr::CValveIpcMgr() :
  218. m_hMutex( NULL ),
  219. m_hMemorySegment( NULL ),
  220. m_pMemory( NULL )
  221. {
  222. }
  223. VALVE_IPC_IMPL CValveIpcMgr::~CValveIpcMgr()
  224. {
  225. Shutdown();
  226. }
  227. VALVE_IPC_IMPL BOOL CValveIpcMgr::Init( DWORD dwTimeout )
  228. {
  229. if ( m_pMemory )
  230. return TRUE;
  231. m_hMutex = ::CreateMutex( NULL, FALSE, VALVE_IPC_MGR_NAME "_MTX_" VALVE_IPC_PROTOCOL_VER );
  232. DWORD dwWaitResult = m_hMutex ? ::WaitForSingleObject( m_hMutex, dwTimeout ) : WAIT_FAILED;
  233. if ( dwWaitResult == WAIT_OBJECT_0 ||
  234. dwWaitResult == WAIT_ABANDONED_0 )
  235. {
  236. // We own the mgr segment
  237. m_hMemorySegment = ::CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, VALVE_IPC_MGR_MEMORY,
  238. VALVE_IPC_MGR_NAME "_MEM_" VALVE_IPC_PROTOCOL_VER );
  239. if ( m_hMemorySegment )
  240. {
  241. LPVOID lpvMemSegment = ::MapViewOfFile( m_hMemorySegment, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
  242. if ( lpvMemSegment )
  243. {
  244. m_pMemory = ( char * ) lpvMemSegment;
  245. return TRUE;
  246. }
  247. }
  248. }
  249. if ( dwWaitResult == WAIT_OBJECT_0 ||
  250. dwWaitResult == WAIT_ABANDONED_0 )
  251. {
  252. ::ReleaseMutex( m_hMutex );
  253. ::CloseHandle( m_hMutex );
  254. m_hMutex = NULL;
  255. }
  256. // Otherwise shutdown due to an init error
  257. Shutdown();
  258. return FALSE;
  259. }
  260. VALVE_IPC_IMPL BOOL CValveIpcMgr::Shutdown()
  261. {
  262. if ( m_pMemory )
  263. {
  264. ::UnmapViewOfFile( m_pMemory );
  265. m_pMemory = NULL;
  266. }
  267. if ( m_hMemorySegment )
  268. {
  269. ::CloseHandle( m_hMemorySegment );
  270. m_hMemorySegment = NULL;
  271. }
  272. if ( m_hMutex )
  273. {
  274. ::ReleaseMutex( m_hMutex );
  275. ::CloseHandle( m_hMutex );
  276. m_hMutex = NULL;
  277. }
  278. return TRUE;
  279. }
  280. VALVE_IPC_IMPL BOOL CValveIpcMgr::DiscoverServer( char const *szServerName, RPC_CSTR *pszServerUID )
  281. {
  282. if ( !szServerName || !*szServerName )
  283. return FALSE;
  284. for ( Iterator it( m_pMemory ); it.IsValid(); it = it.Next() )
  285. {
  286. if ( !stricmp( szServerName, it.m_szServerName ) )
  287. {
  288. if ( pszServerUID )
  289. {
  290. UuidToString( &it.m_uuid, pszServerUID );
  291. }
  292. return TRUE;
  293. }
  294. }
  295. return FALSE;
  296. }
  297. VALVE_IPC_IMPL BOOL CValveIpcMgr::RegisterServer( char const *szServerName, RPC_CSTR *pszServerUID )
  298. {
  299. if ( !szServerName || !*szServerName )
  300. return FALSE;
  301. Iterator it( m_pMemory );
  302. for ( ; it.IsValid(); it = it.Next() )
  303. {
  304. if ( !stricmp( szServerName, it.m_szServerName ) )
  305. {
  306. // Server with same name already registered,
  307. // check if it is alive
  308. char chAliveName[ MAX_PATH ];
  309. RPC_CSTR szBaseName;
  310. UuidToString( &it.m_uuid, &szBaseName );
  311. sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, szBaseName );
  312. RpcStringFree( &szBaseName );
  313. HANDLE hAliveTest = ::OpenMutex( MUTEX_ALL_ACCESS, FALSE, chAliveName );
  314. if ( hAliveTest )
  315. {
  316. ::CloseHandle( hAliveTest );
  317. return FALSE; // Server is alive, can't register again
  318. }
  319. else
  320. {
  321. // Server is dead, re-use its UID
  322. if ( pszServerUID )
  323. {
  324. UuidToString( &it.m_uuid, pszServerUID );
  325. }
  326. return TRUE;
  327. }
  328. }
  329. }
  330. // Iterator points at the last element in the list, write the new server info
  331. Iterator itNewServer;
  332. itNewServer.m_szServerName = const_cast< char * >( szServerName );
  333. UuidCreate( &itNewServer.m_uuid );
  334. // Check that there's enough memory left in the storage
  335. char *pUpdateMemory = it.m_szServerName;
  336. if ( pUpdateMemory + strlen( szServerName ) + 1 + 32 + 2 * sizeof( UUID ) >
  337. m_pMemory + VALVE_IPC_MGR_MEMORY )
  338. {
  339. return FALSE;
  340. }
  341. // Insert the new server in the list
  342. pUpdateMemory = itNewServer.WriteIntoMemory( pUpdateMemory );
  343. pUpdateMemory = Iterator().WriteIntoMemory( pUpdateMemory );
  344. if ( pszServerUID )
  345. {
  346. UuidToString( &itNewServer.m_uuid, pszServerUID );
  347. }
  348. return TRUE;
  349. }
  350. VALVE_IPC_IMPL BOOL CValveIpcMgr::UnregisterServer( RPC_CSTR szServerUID )
  351. {
  352. if ( !szServerUID || !*szServerUID )
  353. return FALSE;
  354. RPC_STATUS rpcS;
  355. UUID uuid;
  356. if ( RPC_S_OK != UuidFromString( szServerUID, &uuid ) )
  357. return FALSE;
  358. for ( Iterator it( m_pMemory ); it.IsValid(); it = it.Next() )
  359. {
  360. if ( UuidEqual( &it.m_uuid, &uuid, &rpcS ) )
  361. {
  362. // This is our server, remove it from the list
  363. char *pMemoryUpdate = it.m_szServerName;
  364. for ( Iterator itRemaining = it.Next(); itRemaining.IsValid(); )
  365. {
  366. Iterator itNext = itRemaining.Next();
  367. pMemoryUpdate = itRemaining.WriteIntoMemory( pMemoryUpdate );
  368. itRemaining = itNext;
  369. }
  370. Iterator().WriteIntoMemory( pMemoryUpdate );
  371. return TRUE;
  372. }
  373. }
  374. return FALSE;
  375. }
  376. VALVE_IPC_IMPL HANDLE CValveIpcMgr::DuplicateMemorySegmentHandle()
  377. {
  378. if ( !m_hMemorySegment )
  379. return NULL;
  380. HANDLE hDup = NULL;
  381. ::DuplicateHandle( GetCurrentProcess(), m_hMemorySegment,
  382. GetCurrentProcess(), &hDup, DUPLICATE_SAME_ACCESS,
  383. FALSE, DUPLICATE_SAME_ACCESS );
  384. return hDup;
  385. }
  386. //////////////////////////////////////////////////////////////////////////
  387. //
  388. // Implementation section of CValveIpcServer
  389. //
  390. //////////////////////////////////////////////////////////////////////////
  391. VALVE_IPC_IMPL CValveIpcServer::CValveIpcServer( char const *szServerName )
  392. {
  393. // Copy server name
  394. size_t nLen = szServerName ? strlen( szServerName ) : 0;
  395. m_szServerName = new char[ nLen + 1 ];
  396. strcpy( m_szServerName, szServerName ? szServerName : "" );
  397. // Init remaining
  398. m_szServerUID = NULL;
  399. m_hMemorySegment = NULL;
  400. m_hServerAlive = NULL;
  401. m_hServerPipe = NULL;
  402. m_hPipeEvent = NULL;
  403. m_hThread = NULL;
  404. m_bRunning = FALSE;
  405. m_pBufferRead = NULL;
  406. m_cbBufferRead = 0;
  407. m_pBufferWrite = NULL;
  408. m_cbBufferWrite = 0;
  409. }
  410. VALVE_IPC_IMPL CValveIpcServer::~CValveIpcServer()
  411. {
  412. Unregister();
  413. if ( m_szServerName )
  414. {
  415. delete [] m_szServerName;
  416. m_szServerName = NULL;
  417. }
  418. }
  419. VALVE_IPC_IMPL BOOL CValveIpcServer::Register()
  420. {
  421. if ( m_szServerUID )
  422. return TRUE;
  423. CValveIpcMgr mgr;
  424. if ( !mgr.Init( VALVE_IPC_TIMEOUT ) )
  425. return FALSE;
  426. // Try registering the server
  427. if ( !mgr.RegisterServer( m_szServerName, &m_szServerUID ) )
  428. return FALSE;
  429. // Server got registered, duplicate memory segment handle
  430. m_hMemorySegment = mgr.DuplicateMemorySegmentHandle();
  431. // create the "server alive" object
  432. char chAliveName[ MAX_PATH ];
  433. sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID );
  434. m_hServerAlive = ::CreateMutex( NULL, FALSE, chAliveName );
  435. if ( !m_hServerAlive )
  436. {
  437. Unregister();
  438. return FALSE;
  439. }
  440. // Create the server pipe event
  441. m_hPipeEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL );
  442. if ( !m_hPipeEvent )
  443. {
  444. Unregister();
  445. return FALSE;
  446. }
  447. // Create the server end of the pipe
  448. char chPipeName[ MAX_PATH ];
  449. sprintf( chPipeName, "\\\\.\\pipe\\" "%s" "_PIPE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID );
  450. m_hServerPipe = ::CreateNamedPipe(
  451. chPipeName,
  452. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH,
  453. PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
  454. 1,
  455. VALVE_IPC_CS_BUFFER, VALVE_IPC_CS_BUFFER,
  456. VALVE_IPC_CS_TIMEOUT,
  457. NULL
  458. );
  459. if ( !m_hServerPipe )
  460. {
  461. Unregister();
  462. return FALSE;
  463. }
  464. // Allocate the pipe buffer
  465. m_pBufferRead = new char [ VALVE_IPC_CS_BUFFER ];
  466. if ( !m_pBufferRead )
  467. {
  468. Unregister();
  469. return FALSE;
  470. }
  471. m_pBufferWrite = new char [ VALVE_IPC_CS_BUFFER ];
  472. if ( !m_pBufferWrite )
  473. {
  474. Unregister();
  475. return FALSE;
  476. }
  477. return TRUE;
  478. }
  479. VALVE_IPC_IMPL BOOL CValveIpcServer::Unregister()
  480. {
  481. if ( !m_szServerUID )
  482. return FALSE;
  483. else
  484. {
  485. CValveIpcMgr mgr;
  486. if ( mgr.Init( VALVE_IPC_TIMEOUT ) )
  487. {
  488. mgr.UnregisterServer( m_szServerUID );
  489. }
  490. }
  491. // Stop the server if it is running
  492. Stop();
  493. m_cbBufferRead = 0;
  494. delete [] m_pBufferRead;
  495. m_pBufferRead = NULL;
  496. m_cbBufferWrite = 0;
  497. delete [] m_pBufferWrite;
  498. m_pBufferWrite = NULL;
  499. if ( m_hServerPipe )
  500. {
  501. ::CloseHandle( m_hServerPipe );
  502. m_hServerPipe = NULL;
  503. }
  504. if ( m_hPipeEvent )
  505. {
  506. ::CloseHandle( m_hPipeEvent );
  507. m_hPipeEvent = NULL;
  508. }
  509. if ( m_hServerAlive )
  510. {
  511. ::CloseHandle( m_hServerAlive );
  512. m_hServerAlive = NULL;
  513. }
  514. if ( m_hMemorySegment )
  515. {
  516. ::CloseHandle( m_hMemorySegment );
  517. m_hMemorySegment = NULL;
  518. }
  519. if ( m_szServerUID )
  520. {
  521. RpcStringFree( &m_szServerUID );
  522. m_szServerUID = NULL;
  523. }
  524. return TRUE;
  525. }
  526. VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForEvent()
  527. {
  528. for ( ; m_bRunning ; )
  529. {
  530. DWORD dwWaitResult = ::WaitForSingleObject( m_hPipeEvent, 50 );
  531. switch ( dwWaitResult )
  532. {
  533. case WAIT_TIMEOUT:
  534. continue;
  535. case WAIT_OBJECT_0:
  536. case WAIT_ABANDONED_0:
  537. ::ResetEvent( m_hPipeEvent );
  538. return m_bRunning;
  539. default:
  540. return FALSE;
  541. }
  542. }
  543. return FALSE;
  544. }
  545. VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForClient()
  546. {
  547. OVERLAPPED ov;
  548. memset( &ov, 0, sizeof( ov ) );
  549. ov.hEvent = m_hPipeEvent;
  550. BOOL bResult = ::ConnectNamedPipe( m_hServerPipe, &ov );
  551. if ( bResult ) // Overlapped "ConnectNamedPipe" always returns FALSE
  552. return FALSE;
  553. switch ( GetLastError() )
  554. {
  555. case ERROR_IO_PENDING:
  556. // Wait for client to connect
  557. break;
  558. case ERROR_PIPE_CONNECTED:
  559. SetEvent( ov.hEvent );
  560. return TRUE;
  561. default:
  562. return FALSE;
  563. }
  564. if ( !WaitForEvent() )
  565. return FALSE;
  566. DWORD dwConnectDummy;
  567. if ( !::GetOverlappedResult( m_hServerPipe, &ov, &dwConnectDummy, FALSE ) )
  568. return FALSE;
  569. return TRUE;
  570. }
  571. VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForCommand()
  572. {
  573. OVERLAPPED ov;
  574. memset( &ov, 0, sizeof( ov ) );
  575. ov.hEvent = m_hPipeEvent;
  576. m_cbBufferRead = 0;
  577. BOOL bRead = ::ReadFile( m_hServerPipe, m_pBufferRead, VALVE_IPC_CS_BUFFER, &m_cbBufferRead, &ov );
  578. if ( bRead &&
  579. m_cbBufferRead )
  580. return TRUE;
  581. if ( !bRead &&
  582. GetLastError() == ERROR_IO_PENDING )
  583. {
  584. if ( !WaitForEvent() )
  585. return FALSE;
  586. bRead = GetOverlappedResult( m_hServerPipe, &ov, &m_cbBufferRead, FALSE );
  587. if ( !bRead || !m_cbBufferRead )
  588. return FALSE;
  589. return TRUE;
  590. }
  591. return FALSE;
  592. }
  593. VALVE_IPC_IMPL BOOL CValveIpcServer::WaitForResult()
  594. {
  595. OVERLAPPED ov;
  596. memset( &ov, 0, sizeof( ov ) );
  597. ov.hEvent = m_hPipeEvent;
  598. DWORD cbWrite;
  599. BOOL bWrite = ::WriteFile( m_hServerPipe, m_pBufferWrite, m_cbBufferWrite, &cbWrite, &ov );
  600. if ( bWrite &&
  601. cbWrite == m_cbBufferWrite )
  602. return TRUE;
  603. if ( !bWrite &&
  604. GetLastError() == ERROR_IO_PENDING )
  605. {
  606. if ( !WaitForEvent() )
  607. return FALSE;
  608. bWrite = GetOverlappedResult( m_hServerPipe, &ov, &cbWrite, FALSE );
  609. if ( !bWrite ||
  610. cbWrite != m_cbBufferWrite )
  611. return FALSE;
  612. return TRUE;
  613. }
  614. return FALSE;
  615. }
  616. VALVE_IPC_IMPL DWORD WINAPI CValveIpcServer::RunDelegate( LPVOID lpvParam )
  617. {
  618. return reinterpret_cast< CValveIpcServer * >( lpvParam )->RunImpl();
  619. }
  620. VALVE_IPC_IMPL DWORD CValveIpcServer::RunImpl()
  621. {
  622. for ( ; WaitForClient() ; )
  623. {
  624. for ( ; WaitForCommand() ; )
  625. {
  626. m_cbBufferWrite = 0;
  627. BOOL bResult = ExecuteCommand( m_pBufferRead, m_cbBufferRead, m_pBufferWrite, m_cbBufferWrite );
  628. if ( !bResult || !m_cbBufferWrite )
  629. break;
  630. bResult = WaitForResult();
  631. if ( !bResult )
  632. break;
  633. }
  634. ::DisconnectNamedPipe( m_hServerPipe );
  635. }
  636. m_bRunning = FALSE;
  637. return FALSE;
  638. }
  639. VALVE_IPC_IMPL BOOL CValveIpcServer::Start()
  640. {
  641. if ( m_hThread )
  642. return FALSE;
  643. m_hThread = ::CreateThread( NULL, 0, RunDelegate, this, CREATE_SUSPENDED, NULL );
  644. if ( !m_hThread )
  645. return FALSE;
  646. m_bRunning = TRUE;
  647. ::ResumeThread( m_hThread );
  648. return TRUE;
  649. }
  650. VALVE_IPC_IMPL BOOL CValveIpcServer::Stop()
  651. {
  652. if ( !m_hThread )
  653. return FALSE;
  654. m_bRunning = FALSE;
  655. ::WaitForSingleObject( m_hThread, INFINITE );
  656. ::CloseHandle( m_hThread );
  657. m_hThread = NULL;
  658. return TRUE;
  659. }
  660. //////////////////////////////////////////////////////////////////////////
  661. //
  662. // Implementation section of CValveIpcClient
  663. //
  664. //////////////////////////////////////////////////////////////////////////
  665. VALVE_IPC_IMPL CValveIpcClient::CValveIpcClient( char const *szServerName )
  666. {
  667. // Copy server name
  668. size_t nLen = szServerName ? strlen( szServerName ) : 0;
  669. m_szServerName = new char[ nLen + 1 ];
  670. strcpy( m_szServerName, szServerName ? szServerName : "" );
  671. // Init remaining
  672. m_szServerUID = NULL;
  673. m_hClientPipe = NULL;
  674. }
  675. VALVE_IPC_IMPL CValveIpcClient::~CValveIpcClient()
  676. {
  677. Disconnect();
  678. if ( m_szServerName )
  679. {
  680. delete [] m_szServerName;
  681. m_szServerName = NULL;
  682. }
  683. }
  684. VALVE_IPC_IMPL BOOL CValveIpcClient::Connect()
  685. {
  686. if ( m_szServerUID )
  687. return TRUE;
  688. CValveIpcMgr mgr;
  689. if ( !mgr.Init( VALVE_IPC_TIMEOUT ) )
  690. return FALSE;
  691. // Try discovering the server
  692. if ( !mgr.DiscoverServer( m_szServerName, &m_szServerUID ) )
  693. return FALSE;
  694. // Server got discovered
  695. // check the "server alive" object
  696. char chAliveName[ MAX_PATH ];
  697. sprintf( chAliveName, "%s" "_ALIVE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID );
  698. HANDLE hServerAlive = ::OpenMutex( MUTEX_ALL_ACCESS, FALSE, chAliveName );
  699. if ( !hServerAlive )
  700. {
  701. Disconnect();
  702. return FALSE;
  703. }
  704. else
  705. {
  706. ::CloseHandle( hServerAlive );
  707. hServerAlive = NULL;
  708. }
  709. // Connect the server pipe
  710. char chPipeName[ MAX_PATH ];
  711. sprintf( chPipeName, "\\\\.\\pipe\\" "%s" "_PIPE_" VALVE_IPC_PROTOCOL_VER, m_szServerUID );
  712. m_hClientPipe = ::CreateFile(
  713. chPipeName,
  714. GENERIC_READ | GENERIC_WRITE,
  715. 0,
  716. NULL,
  717. OPEN_EXISTING,
  718. FILE_FLAG_WRITE_THROUGH,
  719. NULL
  720. );
  721. if ( !m_hClientPipe )
  722. {
  723. Disconnect();
  724. return FALSE;
  725. }
  726. DWORD dwPipeMode = PIPE_READMODE_MESSAGE;
  727. SetNamedPipeHandleState( m_hClientPipe, &dwPipeMode, NULL, NULL );
  728. return TRUE;
  729. }
  730. VALVE_IPC_IMPL BOOL CValveIpcClient::Disconnect()
  731. {
  732. if ( !m_szServerUID )
  733. return FALSE;
  734. if ( m_hClientPipe )
  735. {
  736. ::CloseHandle( m_hClientPipe );
  737. m_hClientPipe = NULL;
  738. }
  739. if ( m_szServerUID )
  740. {
  741. RpcStringFree( &m_szServerUID );
  742. m_szServerUID = NULL;
  743. }
  744. return TRUE;
  745. }
  746. VALVE_IPC_IMPL BOOL CValveIpcClient::ExecuteCommand( LPVOID bufIn, DWORD numInBytes, LPVOID bufOut, DWORD &numOutBytes )
  747. {
  748. if ( !m_szServerUID || !m_hClientPipe )
  749. return FALSE;
  750. BOOL bTransact = TransactNamedPipe( m_hClientPipe,
  751. bufIn, numInBytes,
  752. bufOut, numOutBytes,
  753. &numOutBytes,
  754. NULL );
  755. if ( !bTransact &&
  756. GetLastError() == ERROR_MORE_DATA )
  757. {
  758. bTransact = TRUE;
  759. }
  760. return bTransact;
  761. }
  762. #endif // #ifndef VALVE_IPC_WIN32