521 lines
12 KiB
C++
521 lines
12 KiB
C++
/*++
|
||
|
||
Copyright (c) 1995-1996 Microsoft Corporation
|
||
|
||
Module Name :
|
||
|
||
isainst.cpp
|
||
|
||
Abstract:
|
||
This module defines the functions for Internet Server Application
|
||
Instance and Instance Pool
|
||
|
||
Author:
|
||
|
||
Murali R. Krishnan ( MuraliK ) 9-Sept-1996
|
||
|
||
Environment:
|
||
Win32
|
||
|
||
Project:
|
||
|
||
Internet Application Server DLL
|
||
|
||
Functions Exported:
|
||
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
/************************************************************
|
||
* Include Headers
|
||
************************************************************/
|
||
|
||
# include "isainst.hxx"
|
||
# include "dbgutil.h"
|
||
|
||
# ifdef MTX_ENABLED
|
||
#include <vipapi.h>
|
||
# endif // MTX_ENABLED
|
||
|
||
#define IID_DEFINED
|
||
|
||
# ifdef MTX_ENABLED
|
||
|
||
#include <txctx.h>
|
||
#include <txctx_i.c>
|
||
|
||
# endif // MTX_ENABLED
|
||
|
||
#include "isat_i.c"
|
||
#include "hreq_i.c"
|
||
|
||
/************************************************************
|
||
* Functions
|
||
************************************************************/
|
||
|
||
PISA_INSTANCE
|
||
CreateNewInstance( IN LPCLSID pclsid);
|
||
|
||
|
||
|
||
/************************************************************
|
||
* Member functions of ISA_INSTANCE
|
||
************************************************************/
|
||
|
||
ISA_INSTANCE::ISA_INSTANCE(VOID)
|
||
: m_fInUse ( FALSE),
|
||
m_pIsa ( NULL),
|
||
m_pHttpReq ( NULL),
|
||
m_fInstantiated ( FALSE)
|
||
{
|
||
|
||
InitializeListHead( &m_listEntry);
|
||
|
||
IF_DEBUG( OBJECT) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT, "Created ISA_INSTANCE %08x\n",
|
||
this));
|
||
}
|
||
|
||
} // ISA_INSTANCE::ISA_INSTANCE()
|
||
|
||
ISA_INSTANCE::~ISA_INSTANCE(VOID)
|
||
{
|
||
DBG_ASSERT( !m_fInUse);
|
||
|
||
if ( m_pIsa != NULL) {
|
||
m_pIsa->Release();
|
||
m_pIsa = NULL;
|
||
}
|
||
|
||
if ( m_pHttpReq != NULL) {
|
||
m_pHttpReq->Release();
|
||
m_pHttpReq = NULL;
|
||
}
|
||
|
||
m_fInUse = FALSE;
|
||
m_fInstantiated = FALSE;
|
||
|
||
IF_DEBUG( OBJECT) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT, "Deleted ISA_INSTANCE %08x\n",
|
||
this));
|
||
}
|
||
|
||
} // ISA_INSTANCE::~ISA_INSTANCE()
|
||
|
||
|
||
|
||
BOOL
|
||
ISA_INSTANCE::Instantiate( IN LPCLSID pclsid)
|
||
{
|
||
HRESULT hr;
|
||
DBG_ASSERT( !m_fInstantiated);
|
||
DBG_ASSERT( NULL == m_pIsa);
|
||
DBG_ASSERT( NULL == m_pHttpReq);
|
||
DBG_ASSERT( NULL != pclsid);
|
||
|
||
m_clsidIsa = *pclsid;
|
||
|
||
# ifdef VIPER
|
||
// Get a Viper transaction context object (should only do once)
|
||
hr = CoCreateInstance(CLSID_TransactionContextEx, NULL,
|
||
CLSCTX_SERVER,
|
||
IID_ITransactionContextEx, (void**)&m_pTxContext);
|
||
if (!SUCCEEDED(hr)) goto Err;
|
||
# endif
|
||
|
||
|
||
#ifndef VIPER
|
||
hr = CoCreateInstance(m_clsidIsa, NULL,
|
||
CLSCTX_SERVER, IID_IInetServerApp,
|
||
(void ** ) &m_pIsa);
|
||
#else
|
||
// Create the COMISAPI instance that wraps the ISAPI DLL
|
||
hr = m_pTxContext->CreateInstance( m_clisidIsa, IID_IInetServerApp,
|
||
(void **) &m_pIsa);
|
||
# endif NO_VIPER
|
||
if (!SUCCEEDED(hr)) goto Err;
|
||
|
||
// NYI: Wrap the ECB in a Viper context property
|
||
hr = CoCreateInstance(CLSID_HttpRequest, NULL, CLSCTX_SERVER,
|
||
IID_IHttpRequest, (void **) &m_pHttpReq);
|
||
if (!SUCCEEDED(hr)) goto Err;
|
||
|
||
// store the context in the created ISA instance
|
||
hr = m_pIsa->SetContext( m_pHttpReq);
|
||
if (!SUCCEEDED(hr)) goto Err;
|
||
|
||
Err:
|
||
if (!SUCCEEDED(hr)) {
|
||
|
||
Print();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT, " Error = %0x8x\n", hr));
|
||
|
||
#ifdef VIPER
|
||
if (m_pTxContext) {
|
||
m_pTxContext->Release();
|
||
m_ppTxContext = NULL;
|
||
}
|
||
#endif // VIPER
|
||
|
||
if ( m_pIsa) {
|
||
m_pIsa->Release();
|
||
m_pIsa = NULL;
|
||
}
|
||
|
||
if ( m_pHttpReq) {
|
||
m_pHttpReq->Release();
|
||
m_pHttpReq = NULL;
|
||
}
|
||
} else {
|
||
m_fInstantiated = TRUE;
|
||
}
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[%08x]::Instantiate( %08x) returns hr=%08x \n",
|
||
this, pclsid, hr
|
||
));
|
||
|
||
return ( (SUCCEEDED(hr)? TRUE : FALSE));
|
||
|
||
} // ISA_INSTANCE::Instantiate()
|
||
|
||
|
||
|
||
HRESULT
|
||
ISA_INSTANCE::ProcessRequest(IN EXTENSION_CONTROL_BLOCK * pecb,
|
||
OUT LPDWORD pdwStatus)
|
||
{
|
||
HRESULT hr = E_FAIL;
|
||
|
||
DBG_ASSERT( m_fInstantiated);
|
||
DBG_ASSERT( NULL != m_pIsa);
|
||
DBG_ASSERT( NULL != m_pHttpReq);
|
||
DBG_ASSERT( !m_fInUse);
|
||
|
||
m_fInUse = TRUE;
|
||
hr = m_pHttpReq->SetECB( (long ) pecb);
|
||
if ( SUCCEEDED( hr)) {
|
||
hr = m_pIsa->ProcessRequest( pdwStatus);
|
||
}
|
||
|
||
m_fInUse = FALSE;
|
||
|
||
IF_DEBUG( OBJECT) {
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[%08x]ISA_INSTANCE::ProcessRequest() returns %08x"
|
||
,
|
||
this, hr));
|
||
}
|
||
|
||
return ( hr);
|
||
} // ISA_INSTANCE::ProcessRequest()
|
||
|
||
|
||
|
||
void
|
||
ISA_INSTANCE::Print(VOID) const
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"ISA_INSTANCE(%08x):"
|
||
" pIsa=%08x; pHttpReq=%08x; "
|
||
" fInUse=%d; fInstantiated=%d"
|
||
"\n"
|
||
,
|
||
this, m_pIsa, m_pHttpReq,
|
||
m_fInUse, m_fInstantiated
|
||
));
|
||
return;
|
||
} // ISA_INSTANCE::Print()
|
||
|
||
|
||
|
||
/************************************************************
|
||
* Member functions of ISA_INSTANCE
|
||
************************************************************/
|
||
|
||
ISA_INSTANCE_POOL::ISA_INSTANCE_POOL(VOID)
|
||
: m_fInstantiated ( FALSE),
|
||
m_nFreeEntries ( 0),
|
||
m_nActiveEntries( 0)
|
||
{
|
||
|
||
m_rgchProgId[0] = L'\0';
|
||
|
||
InitializeCriticalSection( & m_csLock);
|
||
InitializeListHead( &m_lActiveEntries);
|
||
InitializeListHead( &m_lFreeEntries);
|
||
|
||
IF_DEBUG( OBJECT) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT, "Created ISA_INSTANCE_POOL %08x\n",
|
||
this));
|
||
}
|
||
|
||
} // ISA_INSTANCE_POOL::ISA_INSTANCE_POOL()
|
||
|
||
|
||
ISA_INSTANCE_POOL::~ISA_INSTANCE_POOL(VOID)
|
||
{
|
||
PLIST_ENTRY pl;
|
||
|
||
DBG_ASSERT( IsListEmpty( &m_lActiveEntries));
|
||
DBG_ASSERT( 0 == m_nActiveEntries);
|
||
|
||
// free up all the instances in the pool
|
||
for( pl = m_lFreeEntries.Flink;
|
||
pl != &m_lFreeEntries;
|
||
m_nFreeEntries-- ) {
|
||
|
||
PLIST_ENTRY plNext;
|
||
|
||
PISA_INSTANCE pisaInstance =
|
||
CONTAINING_RECORD( pl, ISA_INSTANCE, m_listEntry);
|
||
|
||
plNext = pl->Flink;
|
||
|
||
DBG_ASSERT( pisaInstance);
|
||
RemoveEntryList( pl);
|
||
delete pisaInstance;
|
||
pl = plNext;
|
||
|
||
} // for
|
||
|
||
DBG_ASSERT( IsListEmpty(&m_lFreeEntries));
|
||
DBG_ASSERT( 0 == m_nFreeEntries);
|
||
|
||
m_fInstantiated = FALSE;
|
||
|
||
DeleteCriticalSection( & m_csLock);
|
||
|
||
IF_DEBUG( OBJECT) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT, "Deleted ISA_INSTANCE_POOL %08x\n",
|
||
this));
|
||
}
|
||
|
||
} // ISA_INSTANCE_POOL::~ISA_INSTANCE_POOL()
|
||
|
||
|
||
|
||
VOID
|
||
ISA_INSTANCE_POOL::Print(VOID)
|
||
{
|
||
PLIST_ENTRY pl;
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"ISA_INSTANCE_POOL (%08x):"
|
||
" ProgId = %ws. Instantiated=%d"
|
||
" Instances #Free = %d; #Active = %d"
|
||
"\n"
|
||
,
|
||
this, m_rgchProgId,
|
||
m_fInstantiated,
|
||
m_nFreeEntries, m_nActiveEntries
|
||
));
|
||
|
||
Lock();
|
||
// Print all free entries
|
||
DBGPRINTF(( DBG_CONTEXT, " Free Entries \n"));
|
||
for( pl = m_lFreeEntries.Flink; pl != &m_lFreeEntries;
|
||
pl = pl->Flink) {
|
||
|
||
PISA_INSTANCE pisaInstance =
|
||
CONTAINING_RECORD( pl, ISA_INSTANCE, m_listEntry);
|
||
|
||
pisaInstance->Print();
|
||
} // for
|
||
|
||
// Print all active entries
|
||
DBGPRINTF(( DBG_CONTEXT, " Active Entries \n"));
|
||
for( pl = m_lActiveEntries.Flink; pl != &m_lActiveEntries;
|
||
pl = pl->Flink) {
|
||
|
||
PISA_INSTANCE pisaInstance =
|
||
CONTAINING_RECORD( pl, ISA_INSTANCE, m_listEntry);
|
||
|
||
pisaInstance->Print();
|
||
} // for
|
||
|
||
Unlock();
|
||
|
||
return;
|
||
} // ISA_INSTANCE_POOL::Print()
|
||
|
||
|
||
|
||
BOOL
|
||
ISA_INSTANCE_POOL::Instantiate( IN LPCWSTR pszProgId)
|
||
/*++
|
||
ISA_INSTANCE_POOL::Instantiate()
|
||
|
||
o This function instantiates the instance pool. It stores the
|
||
program ID supplied as well as the class ID for the given object.
|
||
In the future new instances maybe created in this instance pool
|
||
using these values.
|
||
|
||
Arguments:
|
||
pszProgId - pointer to null-terminated-string containing the ProgID
|
||
for instance objects
|
||
|
||
Returns:
|
||
TRUE on success and FALSE if there is any error.
|
||
--*/
|
||
{
|
||
HRESULT hr;
|
||
DBG_ASSERT( !m_fInstantiated);
|
||
DBG_ASSERT( m_rgchProgId[0] == L'\0');
|
||
|
||
// Get the clsid for the instance
|
||
hr = CLSIDFromProgID( pszProgId, &m_clsidIsa);
|
||
|
||
if (!SUCCEEDED(hr)) {
|
||
|
||
Print();
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"ISA_INSTANCE_POOL::Instantiate(%ws) Error = %0x8x\n",
|
||
pszProgId, hr));
|
||
} else {
|
||
// make a local copy of the ProgId
|
||
lstrcpynW( m_rgchProgId, pszProgId,
|
||
(sizeof( m_rgchProgId) - 1)/sizeof(WCHAR));
|
||
m_fInstantiated = TRUE;
|
||
}
|
||
|
||
return ( (SUCCEEDED(hr)? TRUE : FALSE));
|
||
|
||
} // ISA_INSTANCE_POOL::Instantiate()
|
||
|
||
|
||
|
||
PISA_INSTANCE
|
||
ISA_INSTANCE_POOL::GetInstance(void)
|
||
{
|
||
PISA_INSTANCE pisa = NULL;
|
||
|
||
DBG_ASSERT( m_fInstantiated);
|
||
|
||
//
|
||
// 1. Look for a free instance
|
||
// 2. If a free one is found,
|
||
// move it to active list and return pointer for the same
|
||
// 3. If no free instance is found, create a new instance
|
||
// 4. Send the new instance off to the caller after putting it in
|
||
// the active list.
|
||
//
|
||
|
||
if ( m_nFreeEntries > 0) {
|
||
|
||
// Aha! there may be free entries, lock and pull one out.
|
||
Lock();
|
||
|
||
if ( m_nFreeEntries > 0) {
|
||
// remove an item from the list
|
||
PLIST_ENTRY pl = m_lFreeEntries.Flink;
|
||
RemoveEntryList( pl);
|
||
|
||
pisa = CONTAINING_RECORD( pl, ISA_INSTANCE, m_listEntry);
|
||
DBG_ASSERT( pisa != NULL);
|
||
m_nFreeEntries--;
|
||
DBG_ASSERT( m_nFreeEntries >= 0);
|
||
|
||
InsertTailList( &m_lActiveEntries, pl);
|
||
m_nActiveEntries++;
|
||
DBG_ASSERT( m_nActiveEntries > 0);
|
||
}
|
||
Unlock();
|
||
}
|
||
|
||
if ( NULL == pisa) {
|
||
|
||
// we did not find an item. we need to create a new instance
|
||
|
||
// create a new instance
|
||
pisa = CreateNewInstance( &m_clsidIsa);
|
||
|
||
if ( pisa != NULL) {
|
||
|
||
// Successfully created a new instance. Add it to the list.
|
||
Lock();
|
||
InsertTailList( &m_lActiveEntries, &pisa->m_listEntry);
|
||
m_nActiveEntries++;
|
||
DBG_ASSERT( m_nActiveEntries > 0);
|
||
Unlock();
|
||
} else {
|
||
|
||
// there was an error in creating the instance.
|
||
}
|
||
}
|
||
|
||
return ( pisa);
|
||
|
||
} // ISA_INSTANCE_POOL::GetInstance()
|
||
|
||
|
||
|
||
BOOL
|
||
ISA_INSTANCE_POOL::ReleaseInstance( PISA_INSTANCE pisaInstance)
|
||
{
|
||
DBG_ASSERT( NULL != pisaInstance);
|
||
|
||
//
|
||
// 1. Remove the request from the active list
|
||
// 2. Add this new item to the free list
|
||
// 3. Adjust the counts appropriately
|
||
//
|
||
|
||
Lock();
|
||
|
||
DBG_ASSERT( m_nActiveEntries > 0);
|
||
RemoveEntryList( &pisaInstance->m_listEntry);
|
||
m_nActiveEntries--;
|
||
DBG_ASSERT( m_nActiveEntries >= 0);
|
||
|
||
InsertHeadList( &m_lFreeEntries, &pisaInstance->m_listEntry);
|
||
m_nFreeEntries++;
|
||
DBG_ASSERT( m_nFreeEntries > 0);
|
||
|
||
Unlock();
|
||
|
||
return (TRUE);
|
||
} // ISA_INSTANCE_POOL::ReleaseInstance()
|
||
|
||
|
||
|
||
PISA_INSTANCE
|
||
CreateNewInstance( IN LPCLSID pclsid)
|
||
{
|
||
PISA_INSTANCE pisa;
|
||
|
||
pisa = new ISA_INSTANCE();
|
||
if ( NULL == pisa ) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"Creating ISA_INSTANCE failed. \n"
|
||
));
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
|
||
} else {
|
||
if ( !pisa->Instantiate( pclsid )) {
|
||
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"[%08x]::Instantiate( %08x) failed. Error=%d \n",
|
||
pisa, pclsid, GetLastError()
|
||
));
|
||
|
||
delete pisa;
|
||
pisa = NULL;
|
||
}
|
||
}
|
||
|
||
return ( pisa);
|
||
} // CreateNewInstance()
|
||
|
||
/************************ End of File ***********************/
|