199 lines
9.6 KiB
C++
199 lines
9.6 KiB
C++
/*======================================================================================//
|
|
| //
|
|
|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====//
|
|
|