Source code of Windows XP (NT5)
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.

198 lines
9.6 KiB

  1. /*======================================================================================//
  2. | //
  3. |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated //
  4. | //
  5. |Description: //
  6. | //
  7. |---------------------------------------------------------------------------------------//
  8. | This file implements the CProcConUser class methods defined in ProcConSvc.h //
  9. |---------------------------------------------------------------------------------------//
  10. | //
  11. |Created: //
  12. | //
  13. | Jarl McDonald 07-98 //
  14. | //
  15. |Revision History: //
  16. | //
  17. |=======================================================================================*/
  18. #include "ProcConSvc.h"
  19. const TCHAR *CProcConUser::PIPENAME = TEXT("\\\\.\\pipe\\ProcConPip");
  20. // Constructor
  21. // Note: this function runs as part of service start so keep it quick!
  22. CProcConUser::CProcConUser( PCContext *ctxt ) :
  23. m_cPC( *ctxt->cPC ), m_cDB( *ctxt->cDB ),
  24. m_inBufChars( 4096 ), m_outBufChars( 65536 ),
  25. m_clientTimeout( 5000 ), m_clientCount( 0 )
  26. {
  27. PCBuildAdminSecAttr( m_secAttr );
  28. m_hConnEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  29. if ( !m_hConnEvent )
  30. PCLogUnExError( TEXT("PCClientConn"), TEXT("CreateEvent") );
  31. m_olConn.hEvent = m_hConnEvent;
  32. }
  33. // Destructor
  34. CProcConUser::~CProcConUser( void )
  35. {
  36. PCFreeSecAttr( m_secAttr );
  37. if ( m_hConnEvent ) CloseHandle( m_hConnEvent );
  38. }
  39. //--------------------------------------------------------------------------------------------//
  40. // Function to determine if all CProcConUser initial conditions have been met //
  41. // Input: None //
  42. // Returns: TRUE if ready, FALSE if not //
  43. //--------------------------------------------------------------------------------------------//
  44. BOOL CProcConUser::ReadyToRun( void )
  45. {
  46. return m_hConnEvent != NULL && m_secAttr.lpSecurityDescriptor && !m_cPC.GotShutdown();
  47. }
  48. //--------------------------------------------------------------------------------------------//
  49. // Function to set a new timeout //
  50. // Input: proposed new timeout //
  51. // Returns: NT or PC error code //
  52. // Note: lower and upper limits on timeout are a bit arbitrary (.1 secs to 30 secs OK) //
  53. // This timeout only applies to the pipe connection timeout at clients, not to //
  54. // transaction timeouts (which are handled by the client alone). //
  55. //--------------------------------------------------------------------------------------------//
  56. PCULONG32 CProcConUser::SetTimeout( PCULONG32 newTimeout )
  57. {
  58. if ( newTimeout >= PC_MIN_TIMEOUT && newTimeout <= PC_MAX_TIMEOUT ) {
  59. m_clientTimeout = newTimeout;
  60. return ERROR_SUCCESS;
  61. }
  62. else
  63. return PCERROR_INVALID_PARAMETER;
  64. }
  65. //--------------------------------------------------------------------------------------------//
  66. // CProcConUser thread function -- this function runs in its own thread and simply offers the //
  67. // PC named pipe to the world. Each pipe connection causes a client thread with //
  68. // its own context to be launched and then a new pipe 'port' is created. //
  69. // Input: None //
  70. // Returns: 0 //
  71. //--------------------------------------------------------------------------------------------//
  72. PCULONG32 CProcConUser::Run( void )
  73. {
  74. // Wait for DB initialization to complete before establishing user service environment.
  75. // If this isn't the first call here, the delay serves to provide some pacing.
  76. WaitForSingleObject( m_cDB.GetDbEvent(), 1000 );
  77. HANDLE waitList[] = { m_olConn.hEvent, m_cPC.GetShutEvent() };
  78. HANDLE hThread = NULL;
  79. ClientContext *context = NULL;
  80. // User connect thread main loop -- handles all user connections to ProcCon.
  81. // There is only one user connect thread.
  82. // This loop runs until shutdown is signalled or until a bad NT error occurs.
  83. for ( ; !m_cPC.GotShutdown(); ++m_clientCount ) {
  84. // Create a new client context..
  85. context = new ClientContext( m_clientCount, &m_cPC, &m_cDB, this, m_inBufChars, m_outBufChars );
  86. if ( !context ) {
  87. PCLogNoMemory( TEXT("ClientContext"), sizeof(ClientContext) );
  88. break;
  89. }
  90. // Create a pipe instance...
  91. context->hPipe = CreateNamedPipe( PIPENAME,
  92. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access, overlapped enabled
  93. PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, // message-based, blocking
  94. PIPE_UNLIMITED_INSTANCES, // no limit
  95. m_outBufChars, // output buffer size
  96. m_inBufChars, // input buffer size
  97. m_clientTimeout, // client side time-out
  98. &m_secAttr ); // our security attr -- built in constructor
  99. if ( context->hPipe == INVALID_HANDLE_VALUE ) {
  100. PCLogUnExError( TEXT("PCClientConn"), TEXT("CreatePipe") );
  101. context->hPipe = NULL;
  102. break;
  103. }
  104. // Initiate pipe connect (but don't wait for a connection)...
  105. DWORD connError = 0;
  106. BOOL launchClient = FALSE;
  107. ResetEvent( m_olConn.hEvent );
  108. if ( !ConnectNamedPipe( context->hPipe, &m_olConn ) )
  109. connError = GetLastError();
  110. // If we have a suspended client from our last connect, release it before waiting on a new connection...
  111. if ( hThread ) {
  112. if ( ResumeThread( hThread ) == 0xffffffff )
  113. PCLogUnExError( TEXT("PCClientConn"), TEXT("ResumeThread1") );
  114. CloseHandle( hThread );
  115. hThread = NULL;
  116. }
  117. // Analyze result of connect. If necessary, wait for a client or a shutdown request...
  118. if ( !connError || connError == ERROR_PIPE_CONNECTED )
  119. launchClient = TRUE;
  120. else if ( connError == ERROR_IO_PENDING ) {
  121. PCULONG32 rc = WaitForMultipleObjects( ENTRY_COUNT(waitList), waitList, FALSE, INFINITE );
  122. // If we got a client, create a thread for it...
  123. if ( rc - WAIT_OBJECT_0 == 0 ) {
  124. PCULONG32 bytes;
  125. if ( !GetOverlappedResult( context->hPipe, &m_olConn, &bytes, TRUE ) ) {
  126. PCLogUnExError( TEXT("PCClientConn"), TEXT("ConnectPipeResult") );
  127. break;
  128. }
  129. else launchClient = TRUE;
  130. }
  131. // If we got a shutdown request, just break out...
  132. else if ( rc - WAIT_OBJECT_0 == 1 )
  133. break;
  134. else {
  135. PCLogUnExError( TEXT("PCClientConn"), TEXT("WaitOnPipeOrShutdown") );
  136. break;
  137. }
  138. }
  139. else {
  140. PCLogUnExError( TEXT("PCClientConn"), TEXT("ConnectPipe") );
  141. break;
  142. }
  143. // If we have a good connection, start a suspended client thread.
  144. // The thread will be released after we have a new pipe instance ready to go.
  145. // This minimizes the interval during which a pipe instance is not available.
  146. if ( launchClient ) {
  147. hThread = CreateThread( NULL, 0, PCClientThread, context, CREATE_SUSPENDED, NULL );
  148. if ( !hThread ) {
  149. PCLogUnExError( TEXT("PCClientConn"), TEXT("CreateThread") );
  150. break;
  151. }
  152. context = NULL; // Client thread deletes its context, we're done with it
  153. }
  154. }
  155. // Clean up if we have a context that has not been passed to a client thread...
  156. if ( context ) {
  157. if ( context->hPipe ) {
  158. CancelIo( context->hPipe );
  159. CloseHandle( context->hPipe );
  160. }
  161. delete context;
  162. }
  163. // If we have a suspended client, release it before leaving...
  164. if ( hThread ) {
  165. if ( ResumeThread( hThread ) == 0xffffffff )
  166. PCLogUnExError( TEXT("PCClientConn"), TEXT("ResumeThread2") );
  167. CloseHandle( hThread );
  168. }
  169. // Note: if this return is not due to a shutdwon request, this function will be called again.
  170. // This 'pipe restart' is the last line of recovery in case of serious pipe (or other) errors.
  171. return 0;
  172. }
  173. // End of CProcConUser.cpp
  174. //============================================================================J McDonald fecit====//