/*======================================================================================// | // |Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated // | // |Description: // | // |---------------------------------------------------------------------------------------// | This file implements the CProcConUser class methods defined in ProcConSvc.h // |---------------------------------------------------------------------------------------// | // |Created: // | // | Jarl McDonald 07-98 // | // |Revision History: // | // |=======================================================================================*/ #include "ProcConSvc.h" const TCHAR *CProcConUser::PIPENAME = TEXT("\\\\.\\pipe\\ProcConPip"); // Constructor // Note: this function runs as part of service start so keep it quick! CProcConUser::CProcConUser( PCContext *ctxt ) : m_cPC( *ctxt->cPC ), m_cDB( *ctxt->cDB ), m_inBufChars( 4096 ), m_outBufChars( 65536 ), m_clientTimeout( 5000 ), m_clientCount( 0 ) { PCBuildAdminSecAttr( m_secAttr ); m_hConnEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if ( !m_hConnEvent ) PCLogUnExError( TEXT("PCClientConn"), TEXT("CreateEvent") ); m_olConn.hEvent = m_hConnEvent; } // Destructor CProcConUser::~CProcConUser( void ) { PCFreeSecAttr( m_secAttr ); if ( m_hConnEvent ) CloseHandle( m_hConnEvent ); } //--------------------------------------------------------------------------------------------// // Function to determine if all CProcConUser initial conditions have been met // // Input: None // // Returns: TRUE if ready, FALSE if not // //--------------------------------------------------------------------------------------------// BOOL CProcConUser::ReadyToRun( void ) { return m_hConnEvent != NULL && m_secAttr.lpSecurityDescriptor && !m_cPC.GotShutdown(); } //--------------------------------------------------------------------------------------------// // Function to set a new timeout // // Input: proposed new timeout // // Returns: NT or PC error code // // Note: lower and upper limits on timeout are a bit arbitrary (.1 secs to 30 secs OK) // // This timeout only applies to the pipe connection timeout at clients, not to // // transaction timeouts (which are handled by the client alone). // //--------------------------------------------------------------------------------------------// PCULONG32 CProcConUser::SetTimeout( PCULONG32 newTimeout ) { if ( newTimeout >= PC_MIN_TIMEOUT && newTimeout <= PC_MAX_TIMEOUT ) { m_clientTimeout = newTimeout; return ERROR_SUCCESS; } else return PCERROR_INVALID_PARAMETER; } //--------------------------------------------------------------------------------------------// // CProcConUser thread function -- this function runs in its own thread and simply offers the // // PC named pipe to the world. Each pipe connection causes a client thread with // // its own context to be launched and then a new pipe 'port' is created. // // Input: None // // Returns: 0 // //--------------------------------------------------------------------------------------------// PCULONG32 CProcConUser::Run( void ) { // Wait for DB initialization to complete before establishing user service environment. // If this isn't the first call here, the delay serves to provide some pacing. WaitForSingleObject( m_cDB.GetDbEvent(), 1000 ); HANDLE waitList[] = { m_olConn.hEvent, m_cPC.GetShutEvent() }; HANDLE hThread = NULL; ClientContext *context = NULL; // User connect thread main loop -- handles all user connections to ProcCon. // There is only one user connect thread. // This loop runs until shutdown is signalled or until a bad NT error occurs. for ( ; !m_cPC.GotShutdown(); ++m_clientCount ) { // Create a new client context.. context = new ClientContext( m_clientCount, &m_cPC, &m_cDB, this, m_inBufChars, m_outBufChars ); if ( !context ) { PCLogNoMemory( TEXT("ClientContext"), sizeof(ClientContext) ); break; } // Create a pipe instance... context->hPipe = CreateNamedPipe( PIPENAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access, overlapped enabled PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, // message-based, blocking PIPE_UNLIMITED_INSTANCES, // no limit m_outBufChars, // output buffer size m_inBufChars, // input buffer size m_clientTimeout, // client side time-out &m_secAttr ); // our security attr -- built in constructor if ( context->hPipe == INVALID_HANDLE_VALUE ) { PCLogUnExError( TEXT("PCClientConn"), TEXT("CreatePipe") ); context->hPipe = NULL; break; } // Initiate pipe connect (but don't wait for a connection)... DWORD connError = 0; BOOL launchClient = FALSE; ResetEvent( m_olConn.hEvent ); if ( !ConnectNamedPipe( context->hPipe, &m_olConn ) ) connError = GetLastError(); // If we have a suspended client from our last connect, release it before waiting on a new connection... if ( hThread ) { if ( ResumeThread( hThread ) == 0xffffffff ) PCLogUnExError( TEXT("PCClientConn"), TEXT("ResumeThread1") ); CloseHandle( hThread ); hThread = NULL; } // Analyze result of connect. If necessary, wait for a client or a shutdown request... if ( !connError || connError == ERROR_PIPE_CONNECTED ) launchClient = TRUE; else if ( connError == ERROR_IO_PENDING ) { PCULONG32 rc = WaitForMultipleObjects( ENTRY_COUNT(waitList), waitList, FALSE, INFINITE ); // If we got a client, create a thread for it... if ( rc - WAIT_OBJECT_0 == 0 ) { PCULONG32 bytes; if ( !GetOverlappedResult( context->hPipe, &m_olConn, &bytes, TRUE ) ) { PCLogUnExError( TEXT("PCClientConn"), TEXT("ConnectPipeResult") ); break; } else launchClient = TRUE; } // If we got a shutdown request, just break out... else if ( rc - WAIT_OBJECT_0 == 1 ) break; else { PCLogUnExError( TEXT("PCClientConn"), TEXT("WaitOnPipeOrShutdown") ); break; } } else { PCLogUnExError( TEXT("PCClientConn"), TEXT("ConnectPipe") ); break; } // If we have a good connection, start a suspended client thread. // The thread will be released after we have a new pipe instance ready to go. // This minimizes the interval during which a pipe instance is not available. if ( launchClient ) { hThread = CreateThread( NULL, 0, PCClientThread, context, CREATE_SUSPENDED, NULL ); if ( !hThread ) { PCLogUnExError( TEXT("PCClientConn"), TEXT("CreateThread") ); break; } context = NULL; // Client thread deletes its context, we're done with it } } // Clean up if we have a context that has not been passed to a client thread... if ( context ) { if ( context->hPipe ) { CancelIo( context->hPipe ); CloseHandle( context->hPipe ); } delete context; } // If we have a suspended client, release it before leaving... if ( hThread ) { if ( ResumeThread( hThread ) == 0xffffffff ) PCLogUnExError( TEXT("PCClientConn"), TEXT("ResumeThread2") ); CloseHandle( hThread ); } // Note: if this return is not due to a shutdwon request, this function will be called again. // This 'pipe restart' is the last line of recovery in case of serious pipe (or other) errors. return 0; } // End of CProcConUser.cpp //============================================================================J McDonald fecit====//