2136 lines
61 KiB
C++
2136 lines
61 KiB
C++
/*-----------------------------------------------------------------------------
|
||
|
||
Copyright (c) 1995-1997 Microsoft Corporation
|
||
|
||
Module Name :
|
||
wamexec.cxx
|
||
|
||
Abstract:
|
||
This module executes a wam request
|
||
|
||
Author:
|
||
David Kaplan ( DaveK ) 11-Mar-1997
|
||
Lei Jin (leijin) 24-Apr-1997 (WamInfo & WamDictator)
|
||
|
||
Environment:
|
||
User Mode - Win32
|
||
|
||
Project:
|
||
W3 services DLL
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
#include <w3p.hxx>
|
||
#include "wamexec.hxx"
|
||
#include "wamreq.hxx"
|
||
#include <wmrgexp.h>
|
||
#include <ole2.h>
|
||
#include <imd.h>
|
||
#include <mb.hxx>
|
||
#include <issched.hxx>
|
||
|
||
#define dwMDDefaultTimeOut 2000
|
||
|
||
#define PERIODIC_RESTART_TIME_DEFAULT 0
|
||
#define PERIODIC_RESTART_REQUESTS_DEFAULT 0
|
||
#define SHUTDOWN_TIME_LIMIT_DEFAULT 600
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
Globals
|
||
-----------------------------------------------------------------------------*/
|
||
WAM_DICTATOR * g_pWamDictator; // global wam dictator
|
||
PFN_INTERLOCKED_COMPARE_EXCHANGE g_pfnInterlockedCompareExchange = NULL;
|
||
static VOID UnloadNTApis(VOID);
|
||
static VOID LoadNTApis(VOID);
|
||
|
||
// Default Package name, defined in wamreg.h, shared by wamreg.dll.
|
||
WCHAR g_szIISInProcWAMCLSID[] = W3_INPROC_WAM_CLSID;
|
||
WCHAR g_szIISOOPPoolWAMCLSID[] = W3_OOP_POOL_WAM_CLSID;
|
||
WCHAR g_szIISOOPPoolPackageID[] = W3_OOP_POOL_PACKAGE_ID;
|
||
// Sink function at wamreg.dll
|
||
// This function will get called when user change application configuration on the fly.
|
||
//
|
||
HRESULT W3SVC_WamRegSink( LPCSTR szAppPath,
|
||
const DWORD dwCommand,
|
||
DWORD* pdwResult
|
||
);
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
CreateWamRequestInstance
|
||
Similar to CoCreateInstance followed by QueryInterface
|
||
|
||
Arguments:
|
||
pHttpRequest - pointer to the HTTP REQUEST object containing all information
|
||
about the current request.
|
||
pExec - Execution descriptor block
|
||
pstrPath - Fully qualified path to Isapi DLL
|
||
pWamInfo - pointer to wam-info which will process this request
|
||
ppWamRequestOut -pointer to a pointer that contains the return WamRequest.
|
||
|
||
Return Value:
|
||
HRESULT
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
CreateWamRequestInstance
|
||
(
|
||
HTTP_REQUEST * pHttpRequest,
|
||
EXEC_DESCRIPTOR * pExec,
|
||
const STR * pstrPath,
|
||
CWamInfo * pWamInfo,
|
||
WAM_REQUEST ** ppWamRequestOut
|
||
)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
WAM_REQUEST * pWamRequest =
|
||
new WAM_REQUEST(
|
||
pHttpRequest
|
||
, pExec
|
||
, pWamInfo
|
||
);
|
||
|
||
*ppWamRequestOut = NULL;
|
||
if( pWamRequest == NULL)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
goto LExit;
|
||
}
|
||
|
||
// Init the wam req
|
||
hr = pWamRequest->InitWamRequest( pstrPath );
|
||
|
||
if ( FAILED( hr ) )
|
||
{
|
||
|
||
DBGPRINTF((
|
||
DBG_CONTEXT
|
||
, "CreateWamRequestInstance - "
|
||
"failed to init wam request. "
|
||
"pHttpRequest(%08x) "
|
||
"pWamInfo(%08x) "
|
||
"pstrPath(%s) "
|
||
"hr(%d) "
|
||
"\n"
|
||
, pHttpRequest
|
||
, pWamInfo
|
||
, pstrPath
|
||
, hr
|
||
));
|
||
|
||
delete pWamRequest;
|
||
pWamRequest = NULL;
|
||
goto LExit;
|
||
|
||
}
|
||
|
||
pWamRequest->AddRef();
|
||
|
||
*ppWamRequestOut = pWamRequest;
|
||
|
||
LExit:
|
||
return hr;
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::ProcessWamRequest
|
||
This function finds a WamInfo and makes a call to the WamInfo to process a Http Server
|
||
Extension Request.
|
||
It uses the HTTP_REQUEST passed in as well as the EXEC_DESCRIPTOR.
|
||
|
||
Arguments:
|
||
pHttpRequest - pointer to the HTTP REQUEST object containing all information
|
||
about the current request.
|
||
pExec - Execution descriptor block
|
||
pstrPath - Fully qualified path to Module (DLL or ComIsapi ProgId)
|
||
pfHandled - Indicates we handled this request
|
||
pfFinished - Indicates no further processing is required
|
||
|
||
Return Value:
|
||
HRESULT
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::ProcessWamRequest
|
||
(
|
||
HTTP_REQUEST * pHttpRequest,
|
||
EXEC_DESCRIPTOR * pExec,
|
||
const STR * pstrPath,
|
||
BOOL * pfHandled,
|
||
BOOL * pfFinished
|
||
)
|
||
{
|
||
|
||
HRESULT hr = NOERROR;
|
||
CWamInfo* pWamInfo = NULL;
|
||
STR * pstrAppPath = NULL;
|
||
CLSID clsidWam;
|
||
BOOL fRet = FALSE;
|
||
|
||
DBG_ASSERT(pHttpRequest);
|
||
DBG_ASSERT(pExec);
|
||
|
||
if (m_fShutdownInProgress)
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT, "Wam Dictator: Shut down in progress, stops serving requests.\n"));
|
||
|
||
// Signal the child event to indicate that the request should terminate.
|
||
if ( pExec->IsChild() ) {
|
||
pExec->SetChildEvent();
|
||
}
|
||
|
||
return E_FAIL;
|
||
}
|
||
|
||
pstrAppPath = pExec->QueryAppPath();
|
||
|
||
if (pstrAppPath == NULL)
|
||
{
|
||
hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
|
||
goto LExit;
|
||
}
|
||
|
||
hr = GetWamInfo( pstrAppPath, pHttpRequest, &pWamInfo );
|
||
if ( FAILED(hr) )
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT,
|
||
"WAM_DICTATOR::ProcessWamRequest: GetWamInfo failed, hr = %08x\n",
|
||
hr
|
||
));
|
||
|
||
//
|
||
// For Child execution just return the error and don't
|
||
// disconnect, otherwise a race ensues between SSI and the disconnect
|
||
// cleanup
|
||
//
|
||
|
||
if ( pExec->IsChild() )
|
||
{
|
||
SetLastError( hr );
|
||
goto LExit;
|
||
}
|
||
|
||
//
|
||
// Since WAM_DICTATOR is going to send some message to the browser, we need
|
||
// to set pfHandled = TRUE here.
|
||
//
|
||
*pfHandled = TRUE;
|
||
|
||
if (W3PlatformType == PtWindows95)
|
||
{
|
||
pHttpRequest->SetLogStatus( HT_SERVER_ERROR, hr);
|
||
// Win95 platform, no event log, special message without mention EventLog.
|
||
pHttpRequest->Disconnect(HT_SERVER_ERROR, IDS_WAM_FAILTOLOADONW95_ERROR, TRUE, pfFinished);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Log to Event Log first.
|
||
//
|
||
const CHAR *pszEventLog[2];
|
||
CHAR szErrorDescription[2048];
|
||
CHAR * pszErrorDescription = NULL;
|
||
HANDLE hMetabase = GetModuleHandle( "METADATA.DLL" );
|
||
|
||
if(FormatMessage(
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
FORMAT_MESSAGE_FROM_HMODULE |
|
||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
hMetabase,
|
||
hr,
|
||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
(LPTSTR) &pszErrorDescription,
|
||
sizeof(szErrorDescription) - 1,
|
||
NULL
|
||
) && pszErrorDescription )
|
||
{
|
||
strcpy(szErrorDescription, pszErrorDescription);
|
||
LocalFree(pszErrorDescription);
|
||
|
||
} else {
|
||
wsprintf(szErrorDescription, "%08x", hr);
|
||
}
|
||
|
||
pszEventLog[0] = pstrAppPath->QueryStr();
|
||
pszEventLog[1] = szErrorDescription;
|
||
// Event log
|
||
g_pInetSvc->LogEvent(W3_EVENT_FAIL_LOADWAM,
|
||
2,
|
||
pszEventLog,
|
||
0);
|
||
|
||
pHttpRequest->SetLogStatus( HT_SERVER_ERROR, hr);
|
||
pHttpRequest->Disconnect(HT_SERVER_ERROR, IDS_WAM_FAILTOLOAD_ERROR, TRUE, pfFinished);
|
||
}
|
||
//
|
||
// Since we already called Disconnect, WAM_DICTATOR should return TRUE to high level.
|
||
//
|
||
hr = NOERROR;
|
||
goto LExit;
|
||
}
|
||
|
||
hr = pWamInfo->ProcessWamRequest(pHttpRequest, pExec, pstrPath, pfHandled,pfFinished);
|
||
|
||
LExit:
|
||
return hr;
|
||
} // WAM_DICTATOR::ProcessWamRequest()
|
||
|
||
/*-----------------------------------------------------------------------------*
|
||
WAM_DICTATOR::WAM_DICTATOR
|
||
Constructor
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Value:
|
||
None
|
||
-----------------------------------------------------------------------------*/
|
||
|
||
WAM_DICTATOR::WAM_DICTATOR
|
||
(
|
||
)
|
||
:
|
||
//m_pPackageCtl(NULL),
|
||
m_cRef(0),
|
||
m_pMetabase(NULL),
|
||
m_fCleanupInProgress(FALSE),
|
||
m_fShutdownInProgress(FALSE),
|
||
m_hW3Svc ( (HANDLE)NULL ),
|
||
m_dwScheduledId (0),
|
||
m_strRootAppPath("/LM/W3SVC"),
|
||
m_HashTable(LK_DFLT_MAXLOAD, LK_DFLT_INITSIZE, LK_DFLT_NUM_SUBTBLS),
|
||
m_pidInetInfo(0)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::WAM_DICTATOR\n"));
|
||
|
||
InitializeListHead(&m_DyingListHead);
|
||
|
||
INITIALIZE_CRITICAL_SECTION(&m_csWamCreation);
|
||
INITIALIZE_CRITICAL_SECTION(&m_csDyingList);
|
||
|
||
m_PTable.Init();
|
||
//
|
||
// Init wamreq allocation cache
|
||
//
|
||
|
||
DBG_REQUIRE( WAM_REQUEST::InitClass() );
|
||
|
||
}//WAM_DICTATOR::WAM_DICTATOR
|
||
|
||
|
||
/*-----------------------------------------------------------------------------*
|
||
WAM_DICTATOR::~WAM_DICTATOR
|
||
Destructor
|
||
|
||
Arguments:
|
||
None
|
||
// (only interesting if out of process)
|
||
Return Value:
|
||
None
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
WAM_DICTATOR::~WAM_DICTATOR
|
||
(
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::~WAM_DICTATOR\n"));
|
||
|
||
DBG_ASSERT(m_cRef == 0);
|
||
|
||
DeleteCriticalSection(&m_csWamCreation);
|
||
DeleteCriticalSection(&m_csDyingList);
|
||
|
||
m_PTable.UnInit();
|
||
//
|
||
// Uninit wamreq allocation cache
|
||
//
|
||
WAM_REQUEST::CleanupClass();
|
||
}//WAM_DICTATOR::~WAMDICTATOR
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::InitWamDictator
|
||
Initializes Wam dictator
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Value:
|
||
HRESULT
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::InitWamDictator
|
||
(
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::InitWamDictator\n"));
|
||
|
||
HRESULT hr = NOERROR;
|
||
IMDCOM * pMetabase;
|
||
|
||
|
||
DBG_ASSERT(g_pInetSvc->QueryMDObject());
|
||
|
||
m_pMetabase = new MB( (IMDCOM*) g_pInetSvc->QueryMDObject() );
|
||
if (m_pMetabase == NULL)
|
||
{
|
||
hr = E_OUTOFMEMORY;
|
||
goto LExit;
|
||
}
|
||
|
||
// Save the handle of the W3Svc process for use when copying tokens to out of proc Wam's
|
||
// NOTE: this is actually a "pseudo-handle", which is good enough. Note that pseudo-handles
|
||
// do NOT need to be closed. CloseHandle is a no-op on a pseudo-handle.
|
||
m_hW3Svc = GetCurrentProcess();
|
||
|
||
|
||
//
|
||
// Get the process id for inetinfo. Under some circumstances com
|
||
// svcs my get hosed. This causes object activation to happen in
|
||
// process even if the object is registered to be launched in the
|
||
// surrogate. In order to prevent inetinfo from AV'ing we want to
|
||
// prevent these applications from running.
|
||
//
|
||
m_pidInetInfo = GetCurrentProcessId();
|
||
|
||
DBG_REQUIRE( m_ServerVariableMap.Initialize() );
|
||
|
||
// Register the Sink function at WamReg.
|
||
WamReg_RegisterSinkNotify(W3SVC_WamRegSink);
|
||
|
||
LoadNTApis();
|
||
|
||
// Make the reference count to 1.
|
||
Reference();
|
||
LExit:
|
||
return hr;
|
||
}//WAM_DICTATOR::InitWamDictator
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::
|
||
|
||
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
LK_PREDICATE
|
||
WAM_DICTATOR::DeleteInShutdown
|
||
(
|
||
CWamInfo* pWamInfo,
|
||
void* pvState
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::DeleteInShutdown\n"));
|
||
|
||
DWORD dwPriorState;
|
||
|
||
dwPriorState = pWamInfo->ChangeToState(WIS_SHUTDOWN);
|
||
|
||
DBGPRINTF((DBG_CONTEXT, "Start shutdown, change state to WIS_SHUTDOWN\n"));
|
||
DBG_REQUIRE(dwPriorState == WIS_RUNNING || dwPriorState == WIS_PAUSE || dwPriorState == WIS_CPUPAUSE);
|
||
|
||
// remove from the hash table here. and clean up later.
|
||
g_pWamDictator->InsertDyingList(pWamInfo, TRUE);
|
||
|
||
return LKP_PERFORM;
|
||
}//WAM_DICTATOR::DeleteInShutdown
|
||
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::StartShutdown
|
||
Starts to shutdown Wam dictator
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Value:
|
||
HRESULT
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::StartShutdown
|
||
(
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::StartShutdown\n"));
|
||
|
||
HRESULT hr = NOERROR;
|
||
CWamInfo* pWamInfo;
|
||
DWORD dwErr;
|
||
DWORD dwPriorState;
|
||
|
||
InterlockedExchange((LPLONG)&m_fShutdownInProgress, (LONG)TRUE);
|
||
|
||
WamReg_UnRegisterSinkNotify();
|
||
|
||
m_HashTable.DeleteIf(DeleteInShutdown, NULL);
|
||
|
||
return hr;
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------*
|
||
WAM_DICTATOR::UninitWamDictator
|
||
Un-initializes Wam dictator
|
||
|
||
Arguments:
|
||
None
|
||
|
||
Return Value:
|
||
HRESULT
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::UninitWamDictator
|
||
(
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::UninitWamDictator\n"));
|
||
|
||
HRESULT hr = NOERROR;
|
||
|
||
// UNDONE leijin thinks we can get rid of this RemoveWorkItem code???
|
||
ScheduledId_Lock();
|
||
if (m_dwScheduledId != 0)
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT, "remove work item %d\n", m_dwScheduledId));
|
||
// Cancel the ScheduleWorkItem
|
||
RemoveWorkItem(m_dwScheduledId);
|
||
m_dwScheduledId = 0;
|
||
}
|
||
ScheduledId_UnLock();
|
||
DBG_ASSERT(m_dwScheduledId == 0);
|
||
|
||
// Clean up the dying list.
|
||
CleanUpDyingList();
|
||
|
||
// After the CleanUpDyingList() call, this should be an empty list.
|
||
//
|
||
DBG_ASSERT(IsListEmpty(&m_DyingListHead));
|
||
|
||
//
|
||
// Allow all other references to WAM_DICTATOR to drain away.
|
||
// This loop is especially important in shutdown during stress scenario.
|
||
// Unload Application while w3svc is still running, a busy application might
|
||
// still have some outstanding HTTPREQUEST unfinished which hold the reference to
|
||
// this WAM_DICTATOR.
|
||
//
|
||
while (m_cRef != 1)
|
||
{
|
||
DBGPRINTF((DBG_CONTEXT, "Still have out-standing reference(%d) to this WAM_DICTATOR\n",
|
||
m_cRef));
|
||
Sleep(20);
|
||
}
|
||
|
||
// Delete m_pMetabase
|
||
// pMetabase should be there
|
||
DBG_REQUIRE(m_pMetabase);
|
||
delete m_pMetabase;
|
||
m_pMetabase = NULL;
|
||
|
||
UnloadNTApis();
|
||
|
||
//
|
||
// Dereference to balance the reference in InitWamDictator. after
|
||
// this Dereference, ref count of WAM_DICTATOR should be 0.
|
||
//
|
||
Dereference();
|
||
DBGPRINTF((DBG_CONTEXT, "Wam Dictator Exits.\n"));
|
||
return hr;
|
||
}//WAM_DICTATOR::UninitWamDictator
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::MDGetAppVariables
|
||
|
||
Giving a Metabase Path, find out the Application Path, WAM CLSID, and Context of WAM object of
|
||
the application that apply to the metabase path.
|
||
|
||
Argument:
|
||
szMetabasePath: [in] A metabase path.
|
||
pfAllowApptoRun: [out] True, if application is enabled to run.
|
||
pclsidWam: [out] a pointer to the buffer for WAM CLSID
|
||
pfInProcess: [out] a pointer to DWORD for Context
|
||
pfEnableTryExcept [out] a pointer to DWORD for EnableTryExcept flag
|
||
|
||
Return:
|
||
HRESULT
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::MDGetAppVariables
|
||
(
|
||
LPCSTR szMetabasePath,
|
||
BOOL* pfAllowAppToRun,
|
||
CLSID* pclsidWam,
|
||
BOOL* pfInProcess,
|
||
BOOL* pfInPool,
|
||
BOOL* pfEnableTryExcept,
|
||
DWORD *pdwOOPCrashThreshold,
|
||
BOOL* pfJobEnabled,
|
||
WCHAR* wszPackageID,
|
||
DWORD* pdwPeriodicRestartRequests,
|
||
DWORD* pdwPeriodicRestartTime,
|
||
MULTISZ*pmszPeriodicRestartSchedule,
|
||
DWORD* pdwShutdownTimeLimit
|
||
)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
METADATA_RECORD recMetaData;
|
||
DWORD dwRequiredLen;
|
||
CHAR szclsidWam[uSizeCLSIDStr];
|
||
WCHAR wszclsidWam[uSizeCLSIDStr];
|
||
BOOL fKeyOpen = FALSE;
|
||
DWORD dwAppMode = 0;
|
||
BOOL fEnableTryExcept = TRUE;
|
||
DWORD dwAppState = 0;
|
||
|
||
DBG_ASSERT(szMetabasePath);
|
||
DBG_ASSERT(pfAllowAppToRun);
|
||
DBG_ASSERT(pclsidWam);
|
||
DBG_ASSERT(pfInProcess);
|
||
DBG_ASSERT(pfInPool);
|
||
DBG_ASSERT(pfEnableTryExcept);
|
||
DBG_ASSERT(pdwOOPCrashThreshold);
|
||
DBG_ASSERT(pfJobEnabled);
|
||
DBG_ASSERT(m_pMetabase);
|
||
DBG_ASSERT(wszPackageID);
|
||
DBG_ASSERT(pdwPeriodicRestartRequests);
|
||
DBG_ASSERT(pdwPeriodicRestartTime);
|
||
DBG_ASSERT(pmszPeriodicRestartSchedule);
|
||
DBG_ASSERT(pdwShutdownTimeLimit);
|
||
|
||
wszPackageID[0] = L'\0';
|
||
// Open Key
|
||
if (!m_pMetabase->Open(szMetabasePath, METADATA_PERMISSION_READ))
|
||
{
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
goto LErrExit;
|
||
}
|
||
fKeyOpen = TRUE;
|
||
|
||
// if MD_APP_STATE exists, and is defined with a value APPSTATUS_PAUSE,
|
||
// then, fAllowAppToRun is set to FALSE
|
||
// otherwise, fAllowAppToRun is set to TRUE
|
||
if (m_pMetabase->GetDword("", MD_APP_STATE, IIS_MD_UT_WAM, (DWORD *)&dwAppState, METADATA_INHERIT))
|
||
{
|
||
if (dwAppState == APPSTATUS_PAUSE)
|
||
{
|
||
*pfAllowAppToRun = FALSE;
|
||
goto LErrExit;
|
||
}
|
||
}
|
||
|
||
*pfAllowAppToRun = TRUE;
|
||
if (!m_pMetabase->GetDword("", MD_APP_ISOLATED, IIS_MD_UT_WAM, &dwAppMode, METADATA_INHERIT))
|
||
{
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
goto LErrExit;
|
||
}
|
||
|
||
*pfInProcess = ( dwAppMode == eAppInProc) ? TRUE : FALSE;
|
||
*pfInPool = ( dwAppMode == eAppInProc || dwAppMode == eAppOOPPool ) ? TRUE : FALSE;
|
||
|
||
if (dwAppMode == eAppOOPIsolated)
|
||
{
|
||
DWORD dwRet = 0;
|
||
CHAR szPackageID[uSizeCLSIDStr];
|
||
|
||
//
|
||
// Disable job objects for IIS5.1, original code would read the MD_CPU_APP_ENABLED
|
||
// property from metabase
|
||
//
|
||
*pfJobEnabled = FALSE;
|
||
|
||
dwRequiredLen= uSizeCLSIDStr;
|
||
if (!m_pMetabase->GetString("", MD_APP_PACKAGE_ID, IIS_MD_UT_WAM, szPackageID, &dwRequiredLen, METADATA_INHERIT))
|
||
{
|
||
DBG_ASSERT(dwRequiredLen <= uSizeCLSIDStr);
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
goto LErrExit;
|
||
}
|
||
|
||
dwRet = MultiByteToWideChar(CP_ACP, 0, szPackageID, -1, wszPackageID, uSizeCLSIDStr);
|
||
DBG_ASSERT(dwRet != 0);
|
||
}
|
||
else if (dwAppMode == eAppOOPPool)
|
||
{
|
||
wcsncpy(wszPackageID, g_szIISOOPPoolPackageID, sizeof(g_szIISOOPPoolPackageID)/sizeof(WCHAR));
|
||
// Always disable Job object for pool process.
|
||
*pfJobEnabled = FALSE;
|
||
}
|
||
else
|
||
{
|
||
*pfJobEnabled = FALSE;
|
||
}
|
||
|
||
|
||
// If not present assume the default (TRUE) (For Debug builds set default to FALSE)
|
||
if (m_pMetabase->GetDword("", MD_ASP_EXCEPTIONCATCHENABLE, ASP_MD_UT_APP, (DWORD *)&fEnableTryExcept, METADATA_INHERIT))
|
||
{
|
||
*pfEnableTryExcept = fEnableTryExcept ? TRUE : FALSE;
|
||
}
|
||
else
|
||
{
|
||
#if DBG
|
||
*pfEnableTryExcept = FALSE;
|
||
#else
|
||
*pfEnableTryExcept = TRUE;
|
||
#endif
|
||
}
|
||
|
||
DWORD dwThreshold;
|
||
|
||
if (dwAppMode == eAppInProc)
|
||
{
|
||
hr = CLSIDFromString((LPOLESTR) g_szIISInProcWAMCLSID, (LPCLSID)pclsidWam);
|
||
}
|
||
else if (dwAppMode == eAppOOPPool)
|
||
{
|
||
hr = CLSIDFromString((LPOLESTR) g_szIISOOPPoolWAMCLSID, (LPCLSID)pclsidWam);
|
||
|
||
*pdwOOPCrashThreshold = 0XFFFFFFFF;
|
||
}
|
||
else
|
||
{
|
||
if (m_pMetabase->GetDword("", MD_APP_OOP_RECOVER_LIMIT, IIS_MD_UT_WAM, (DWORD *)&dwThreshold, METADATA_INHERIT))
|
||
{
|
||
// It used to be OOP_CRASH_LIMIT (range 1 - 5)
|
||
// Now, the name is changed to RECOVER_LIMIT with range of (0-xxx).
|
||
// 0 means no recovery, same as 1 in crash limit, 1 crash, and it's over, (0 recovery).
|
||
// Add 1 because internally this threshold is implemented in crash_limit concept.
|
||
// 0xFFFFFFFF is unlimited.
|
||
|
||
// Changed to default to unlimited - Bug 240012. The idea of making this time
|
||
// dependent seems much smarter than making it infinite. But no one was willing
|
||
// to step up and decide what the right parameters were.
|
||
if (dwThreshold != 0xFFFFFFFF)
|
||
{
|
||
dwThreshold++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
dwThreshold = APP_OOP_RECOVER_LIMIT_DEFAULT;
|
||
}
|
||
|
||
*pdwOOPCrashThreshold = dwThreshold;
|
||
|
||
dwRequiredLen= uSizeCLSIDStr;
|
||
if (!m_pMetabase->GetString("", MD_APP_WAM_CLSID, IIS_MD_UT_WAM, szclsidWam, &dwRequiredLen, METADATA_INHERIT))
|
||
{
|
||
DBG_ASSERT(dwRequiredLen <= uSizeCLSIDStr);
|
||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
goto LErrExit;
|
||
}
|
||
|
||
MultiByteToWideChar(CP_ACP, 0, szclsidWam, -1, wszclsidWam, uSizeCLSIDStr);
|
||
|
||
hr = CLSIDFromString((LPOLESTR)wszclsidWam, (LPCLSID)pclsidWam);
|
||
}
|
||
|
||
if ( dwAppMode != eAppInProc )
|
||
{
|
||
//
|
||
// Get the application recycle settings
|
||
//
|
||
|
||
//
|
||
// Disable wam recycling for IIS5.1, original code would read these properties
|
||
// from metabase
|
||
//
|
||
*pdwPeriodicRestartTime = PERIODIC_RESTART_TIME_DEFAULT;
|
||
|
||
*pdwPeriodicRestartRequests = PERIODIC_RESTART_REQUESTS_DEFAULT;
|
||
|
||
*pdwShutdownTimeLimit = SHUTDOWN_TIME_LIMIT_DEFAULT;
|
||
|
||
pmszPeriodicRestartSchedule->Reset();
|
||
}
|
||
|
||
if (FAILED(hr))
|
||
goto LErrExit;
|
||
|
||
LErrExit:
|
||
|
||
if (fKeyOpen)
|
||
{
|
||
m_pMetabase->Close();
|
||
}
|
||
|
||
return hr;
|
||
}//WAM_DICTATOR::MDGetAppVariables
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::GetWamInfo
|
||
Returns the interface pointer for a wam, NULL if wam not found
|
||
|
||
Arguments:
|
||
pstrPath [in] wam key: path to extension dll, prog id, etc.
|
||
fInProc [in] run the wam in-proc?
|
||
ppIWam [out] interface pointer for the wam
|
||
|
||
Return Value:
|
||
TRUE or FALSE
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::GetWamInfo
|
||
(
|
||
const STR* pstrAppPath,
|
||
const HTTP_REQUEST * pHttpRequest,
|
||
CWamInfo ** ppWamInfo
|
||
)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
INT AppState;
|
||
CWamInfo* pWamInfo = NULL;
|
||
|
||
DBG_ASSERT(pstrAppPath);
|
||
|
||
AppState = FindWamInfo(pstrAppPath, &pWamInfo);
|
||
if (-1 == AppState)
|
||
{
|
||
//
|
||
// Lock the Creation process
|
||
// to avoid multiple threads try to create the same WAMInfo,
|
||
// (init WAM object, very expensive in out-proc cases)
|
||
//
|
||
CreateWam_Lock();
|
||
|
||
//
|
||
// Try to find it again, in case another thread already created it.
|
||
// This check is better that creating another WamInfo.
|
||
//
|
||
AppState = FindWamInfo(pstrAppPath, &pWamInfo);
|
||
if (-1 == AppState)
|
||
{
|
||
//
|
||
// We are out of luck in our search for a valid Wam Info
|
||
// Let us just create a new one and make it happen.
|
||
// Note: Creation also adds the WamInfo to the hashtable
|
||
//
|
||
DBG_ASSERT(pHttpRequest != NULL);
|
||
hr = CreateWamInfo( *pstrAppPath, &pWamInfo, pHttpRequest->QueryW3Instance());
|
||
}
|
||
CreateWam_UnLock();
|
||
}
|
||
|
||
if (m_fShutdownInProgress && pWamInfo != NULL)
|
||
{
|
||
hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS);
|
||
pWamInfo->Dereference();
|
||
pWamInfo = NULL;
|
||
}
|
||
|
||
*ppWamInfo = pWamInfo;
|
||
return hr;
|
||
}//WAM_DICTATOR::GetWamInfo
|
||
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
|
||
WAM_DICTATOR::CreateWamInfo()
|
||
|
||
Description:
|
||
Creates a new CWamInfo object for the specified application root path.
|
||
On successful creation, it adds the object to the hash table internal
|
||
to the WAM_DICTATOR that contains the active WamInfos.
|
||
Finally, it returns the object via the pointer supplied.
|
||
|
||
Arguments:
|
||
strAppRootPath - string containing the metabase path for for the
|
||
Application Root
|
||
ppWamInfo - pointer to pointer to CWamInfo object. On successful
|
||
return this contains the pointer to the new
|
||
created CWamInfo
|
||
|
||
Returns:
|
||
HRESULT
|
||
NOERROR - on success
|
||
and specific error codes on failure
|
||
|
||
Note:
|
||
This function should be called with the WAM_DICTATOR WamInfo lock held.
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::CreateWamInfo
|
||
(
|
||
const STR & strAppRootPath,
|
||
CWamInfo ** ppWamInfo,
|
||
PW3_SERVER_INSTANCE pwsiInstance
|
||
)
|
||
{
|
||
HRESULT hr = NOERROR;
|
||
CLSID clsidWam;
|
||
BOOL fInProcess;
|
||
BOOL fEnableTryExcept;
|
||
CWamInfo * pWamInfo;
|
||
DWORD dwThreshold; // OOP crash threshold
|
||
BOOL fAllowAppToRun;
|
||
BOOL fJobEnabled;
|
||
BOOL fInPool;
|
||
WCHAR wszPackageID[uSizeCLSIDStr];
|
||
DWORD dwPeriodicRestartRequests;
|
||
DWORD dwPeriodicRestartTime;
|
||
DWORD dwShutdownTimeLimit;
|
||
MULTISZ mzPeriodicRestartSchedule;
|
||
|
||
DBG_ASSERT( NULL != ppWamInfo );
|
||
DBG_ASSERT( NULL == *ppWamInfo);
|
||
|
||
// Get the latest Application path, CLSID, and inproc/out-of-proc flag
|
||
hr = MDGetAppVariables(strAppRootPath.QueryStr(),
|
||
&fAllowAppToRun,
|
||
&clsidWam,
|
||
&fInProcess,
|
||
&fInPool,
|
||
&fEnableTryExcept,
|
||
&dwThreshold,
|
||
&fJobEnabled,
|
||
wszPackageID,
|
||
&dwPeriodicRestartRequests,
|
||
&dwPeriodicRestartTime,
|
||
&mzPeriodicRestartSchedule,
|
||
&dwShutdownTimeLimit
|
||
);
|
||
|
||
if ( SUCCEEDED( hr) && fAllowAppToRun)
|
||
{
|
||
//
|
||
// Create a New CWamInfo
|
||
//
|
||
if (fInProcess)
|
||
{
|
||
pWamInfo = new CWamInfo( strAppRootPath,
|
||
fInProcess,
|
||
fInPool,
|
||
fEnableTryExcept,
|
||
clsidWam
|
||
);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Check to see if we have scheduled restart times. If so,
|
||
// set the restart time to the earlier of the configured
|
||
// restart time, or the earliest scheduled time.
|
||
//
|
||
|
||
if ( mzPeriodicRestartSchedule.QueryStringCount() )
|
||
{
|
||
SYSTEMTIME st;
|
||
DWORD dwTimeOfDayInMinutes;
|
||
DWORD dwScheduleInMinutes;
|
||
LPSTR szHour;
|
||
LPSTR szMinute;
|
||
|
||
GetLocalTime( &st );
|
||
dwTimeOfDayInMinutes = st.wHour * 60 + st.wMinute;
|
||
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"Current Time is %d.\r\n",
|
||
dwTimeOfDayInMinutes
|
||
));
|
||
|
||
szHour = mzPeriodicRestartSchedule.QueryStrA();
|
||
|
||
DBG_ASSERT( szHour );
|
||
|
||
while ( *szHour )
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"Considering recycle at %s.\r\n",
|
||
szHour
|
||
));
|
||
|
||
szMinute = strchr( szHour, ':' );
|
||
|
||
if ( !szMinute )
|
||
{
|
||
//
|
||
// Parsing error - hour and minute not separated
|
||
// by a ':'
|
||
//
|
||
|
||
break;
|
||
}
|
||
|
||
szMinute++;
|
||
|
||
dwScheduleInMinutes = atol( szHour ) * 60;
|
||
dwScheduleInMinutes += atol( szMinute );
|
||
|
||
if ( dwScheduleInMinutes <= dwTimeOfDayInMinutes )
|
||
{
|
||
dwScheduleInMinutes += 24 * 60;
|
||
}
|
||
|
||
dwScheduleInMinutes -= dwTimeOfDayInMinutes;
|
||
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"Scheduled time is %d minutes from now.\r\n",
|
||
dwScheduleInMinutes
|
||
));
|
||
|
||
//
|
||
// If the scheduled time is earlier than the current
|
||
// dwPeriodicRestartTime, then replace the existing
|
||
// value.
|
||
//
|
||
|
||
if ( dwScheduleInMinutes < dwPeriodicRestartTime ||
|
||
dwPeriodicRestartTime == 0 )
|
||
{
|
||
dwPeriodicRestartTime = dwScheduleInMinutes;
|
||
}
|
||
|
||
szHour += strlen( szHour ) + 1;
|
||
}
|
||
}
|
||
|
||
if ( dwPeriodicRestartRequests || dwPeriodicRestartTime )
|
||
{
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"Recycling will occur in %d minutes. or when %d requests have been served.\r\n",
|
||
dwPeriodicRestartTime,
|
||
dwPeriodicRestartRequests
|
||
));
|
||
}
|
||
|
||
pWamInfo = new CWamInfoOutProc(strAppRootPath,
|
||
fInProcess,
|
||
fInPool,
|
||
fEnableTryExcept,
|
||
clsidWam,
|
||
dwThreshold,
|
||
pwsiInstance,
|
||
fJobEnabled,
|
||
dwPeriodicRestartRequests,
|
||
dwPeriodicRestartTime,
|
||
dwShutdownTimeLimit
|
||
);
|
||
}
|
||
|
||
if (pWamInfo)
|
||
{
|
||
//
|
||
// This is WAM_DICTATOR's reference on the CWamInfo. In "normal"
|
||
// operations, this will be the last reference.
|
||
//
|
||
|
||
pWamInfo->Reference();
|
||
|
||
BOOL fInitialize = (fInProcess || !fJobEnabled || !pwsiInstance->AreProcsCPUStopped());
|
||
if (fInitialize)
|
||
{
|
||
//
|
||
//Init the CWamInfo. this call will CoCreateInstance WAM object.
|
||
//
|
||
hr = pWamInfo->Init( wszPackageID, m_pidInetInfo );
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
pWamInfo->ChangeToState(WIS_RUNNING);
|
||
}
|
||
else
|
||
{
|
||
pWamInfo->UnInit();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pWamInfo->ChangeToState(WIS_CPUPAUSE);
|
||
}
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
|
||
if ( LK_SUCCESS != m_HashTable.InsertRecord(pWamInfo))
|
||
{
|
||
if (fInitialize)
|
||
{
|
||
pWamInfo->UnInit();
|
||
}
|
||
pWamInfo->Dereference(); // should be last reference
|
||
//delete pWamInfo;
|
||
hr = E_FAIL; // NYI: What is the right failure code?
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Finally we are successful with a valid WAmInfo.
|
||
// Return this. Will be balanced by a DeleteRecord
|
||
// in CProcessTable::RemoveWamInfoFromProcessTable
|
||
//
|
||
pWamInfo->Reference();
|
||
*ppWamInfo = pWamInfo;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DBG_ASSERT( NOERROR != hr);
|
||
pWamInfo->Dereference();
|
||
//delete pWamInfo;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// pWamInfo == NULL
|
||
hr = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
hr = HRESULT_FROM_WIN32(ERROR_SERVER_DISABLED);
|
||
*ppWamInfo = NULL;
|
||
}
|
||
//
|
||
// NYI: Isn't pstrNewPath going away?
|
||
// Should I bother deleting pstrNewPath ??
|
||
//
|
||
}
|
||
|
||
//
|
||
// Either we should be returning an error or send back the proper pointer
|
||
//
|
||
DBG_ASSERT( (hr != NOERROR) || (*ppWamInfo != NULL));
|
||
|
||
return ( hr);
|
||
} // WAM_DICTATOR::CreateWamInfo()
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::FindWamInfo
|
||
Returns the interface pointer for a wam, NULL if wam not found
|
||
|
||
Arguments:
|
||
pstrPath - [in] wam key: path to extension dll, prog id, etc.
|
||
ppIWam - [out] interface pointer for the wam
|
||
|
||
Return Value:
|
||
TRUE or FALSE
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
INT
|
||
WAM_DICTATOR::FindWamInfo
|
||
(
|
||
const STR* pstrMetabasePath,
|
||
CWamInfo** ppWamInfo
|
||
)
|
||
{
|
||
INT AppState = -1;
|
||
CWamInfo* pWamInfo = NULL;
|
||
char* pszKey;
|
||
|
||
DBG_ASSERT(pstrMetabasePath);
|
||
DBG_ASSERT(ppWamInfo);
|
||
|
||
pszKey = pstrMetabasePath->QueryStr();
|
||
|
||
HashReadLock();
|
||
m_HashTable.FindKey(pszKey, &pWamInfo);
|
||
HashReadUnlock();
|
||
|
||
if (pWamInfo)
|
||
{
|
||
AppState = pWamInfo->QueryState();
|
||
|
||
DBG_ASSERT(AppState != WIS_START || AppState != WIS_END);
|
||
}
|
||
|
||
*ppWamInfo = pWamInfo;
|
||
return AppState;
|
||
}//WAM_DICTATOR::FindWamInfo
|
||
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::UnLoadWamInfo
|
||
Unload an OOP Wam.
|
||
|
||
Arguments:
|
||
pstrWamPath - [in] wam key: path to extension dll, prog id, etc.
|
||
fCPUPause - [in] If true, CPU pauses the WAM. Kills the process
|
||
but keeps the info around.
|
||
pfAppCpuUnloaded - [out] If nonNULL, set to TRUE iff an app was killed.
|
||
|
||
Return Value:
|
||
|
||
HRESULT - Error code.
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::UnLoadWamInfo
|
||
(
|
||
STR *pstrAppPath,
|
||
BOOL fCPUPause,
|
||
BOOL *pfAppCpuUnloaded
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::UnLoadWamInfo\n"));
|
||
|
||
int iAppState;
|
||
CWamInfo* pWamInfo = NULL;
|
||
DWORD eWISPrevState;
|
||
DWORD eWISState;
|
||
HRESULT hr = NOERROR;
|
||
BOOL fInProc;
|
||
BOOL fAppCpuUnloaded = FALSE;
|
||
|
||
CreateWam_Lock();
|
||
|
||
iAppState = FindWamInfo(pstrAppPath,
|
||
&pWamInfo);
|
||
|
||
CreateWam_UnLock();
|
||
|
||
if (iAppState != -1)
|
||
{
|
||
bool fRet = FALSE;
|
||
|
||
CProcessEntry* pProcEntry = NULL;
|
||
|
||
|
||
fInProc = pWamInfo->FInProcess();
|
||
pProcEntry = pWamInfo->QueryProcessEntry();
|
||
DBG_ASSERT(pProcEntry != NULL);
|
||
|
||
pProcEntry->AddRef();
|
||
|
||
while (pWamInfo != NULL)
|
||
{
|
||
eWISState = (fCPUPause == TRUE) ? WIS_CPUPAUSE : WIS_SHUTDOWN;
|
||
eWISPrevState = pWamInfo->ChangeToState(WIS_RUNNING, eWISState);
|
||
//
|
||
// Terminate process and kill off current requests.
|
||
//
|
||
|
||
if (WIS_RUNNING == eWISPrevState)
|
||
{
|
||
DBG_ASSERT(pWamInfo->HWamProcess() != NULL);
|
||
|
||
hr = ShutdownWamInfo(pWamInfo,
|
||
HASH_TABLE_REF + FIND_KEY_REF
|
||
);
|
||
|
||
if (!fCPUPause)
|
||
{
|
||
LK_RETCODE LkReturn;
|
||
|
||
LkReturn = m_HashTable.DeleteKey(
|
||
pWamInfo->QueryApplicationPath().QueryStr());
|
||
DBG_ASSERT(LK_SUCCESS == LkReturn);
|
||
//
|
||
// Release FIND_KEY_REF
|
||
//
|
||
pWamInfo->Dereference();
|
||
if (LK_SUCCESS == LkReturn)
|
||
{
|
||
pWamInfo->Dereference();
|
||
//delete pWamInfo;
|
||
pWamInfo = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Application is running. Kill It
|
||
//
|
||
DBG_ASSERT(!pWamInfo->FInProcess());
|
||
//
|
||
// Get rid of the shutting down flag
|
||
//
|
||
pWamInfo->ClearMembers();
|
||
//
|
||
// Release FIND_KEY_REF
|
||
//
|
||
pWamInfo->Dereference();
|
||
|
||
fAppCpuUnloaded = TRUE;
|
||
|
||
}
|
||
}
|
||
|
||
if (fInProc)
|
||
{
|
||
pWamInfo = NULL;
|
||
}
|
||
else
|
||
{
|
||
fRet = m_PTable.FindWamInfo(pProcEntry,&pWamInfo);
|
||
DBG_ASSERT(fRet == TRUE);
|
||
}
|
||
}
|
||
|
||
pProcEntry->Release();
|
||
}
|
||
|
||
if (pfAppCpuUnloaded != NULL) {
|
||
*pfAppCpuUnloaded = fAppCpuUnloaded;
|
||
}
|
||
return hr;
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::CPUResumeWamInfo
|
||
Resumes a CPU Paused OOP Wam.
|
||
|
||
Arguments:
|
||
pstrWamPath - [in] wam key: path to extension dll, prog id, etc.
|
||
|
||
Return Value:
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
VOID
|
||
WAM_DICTATOR::CPUResumeWamInfo
|
||
(
|
||
STR *pstrWamPath
|
||
)
|
||
{
|
||
int iAppState;
|
||
CWamInfo* pWICurrentApplication = NULL;
|
||
DWORD eWISPrevState;
|
||
CLSID clsidWam;
|
||
BOOL fInProcess;
|
||
BOOL fInPool;
|
||
BOOL fEnableTryExcept;
|
||
DWORD dwThreshold; // OOP crash threshold
|
||
BOOL fAllowAppToRun;
|
||
BOOL fJobEnabled;
|
||
WCHAR wszPackageID[uSizeCLSIDStr];
|
||
DWORD dwPeriodicRestartRequests;
|
||
DWORD dwPeriodicRestartTime;
|
||
DWORD dwShutdownTimeLimit;
|
||
MULTISZ mzPeriodicRestartSchedule;
|
||
HRESULT hr;
|
||
|
||
|
||
CreateWam_Lock();
|
||
|
||
iAppState = FindWamInfo(pstrWamPath,
|
||
&pWICurrentApplication);
|
||
|
||
CreateWam_UnLock();
|
||
|
||
if (iAppState != -1)
|
||
{
|
||
// Application may not be loaded. This method is called for every
|
||
// application defined under the site being paused.
|
||
|
||
// Get the latest Application path, CLSID, and inproc/out-of-proc flag
|
||
hr = MDGetAppVariables(pWICurrentApplication->QueryApplicationPath().QueryStr(),
|
||
&fAllowAppToRun,
|
||
&clsidWam,
|
||
&fInProcess,
|
||
&fInPool,
|
||
&fEnableTryExcept,
|
||
&dwThreshold,
|
||
&fJobEnabled,
|
||
wszPackageID,
|
||
&dwPeriodicRestartRequests,
|
||
&dwPeriodicRestartTime,
|
||
&mzPeriodicRestartSchedule,
|
||
&dwShutdownTimeLimit);
|
||
|
||
|
||
if (iAppState == WIS_CPUPAUSE && SUCCEEDED(hr))
|
||
{
|
||
if (SUCCEEDED(pWICurrentApplication->Init(wszPackageID, m_pidInetInfo)))
|
||
{
|
||
pWICurrentApplication->ChangeToState(WIS_CPUPAUSE, WIS_RUNNING);
|
||
}
|
||
}
|
||
|
||
//
|
||
// FindWamInfo References this, so dereference it.
|
||
//
|
||
pWICurrentApplication->Dereference();
|
||
}
|
||
|
||
}//WAM_DICTATOR::CPUResumeWamInfo
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::ShutdownWamInfo
|
||
This function currently can only call a blocking method of WAM, UnInitWam.
|
||
In the future, this function might support a non-blocking method provided by WAM in
|
||
case of IIS shutdown.
|
||
|
||
Arguments:
|
||
pWamInfo [in] a pointer to WamInfo
|
||
cIgnoreRef [in] The reference count that need to be ignored in StartShutdown.
|
||
|
||
Return Value:
|
||
TRUE or FALSE
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::ShutdownWamInfo
|
||
(
|
||
CWamInfo* pWamInfo,
|
||
INT cIgnoreRefs
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::ShutdownWamInfo\n"));
|
||
|
||
HRESULT hr = NOERROR;
|
||
WCHAR szPackageID[uSizeCLSIDStr];
|
||
|
||
DBG_ASSERT(pWamInfo);
|
||
|
||
LPCSTR pszAppPath = (pWamInfo->QueryApplicationPath()).QueryStr();
|
||
|
||
|
||
// Might create IPackageUtil * for later use.
|
||
DBGPRINTF((DBG_CONTEXT, "Shutting down WamInfo %08p, Inproc(%d), AppRoot(%s).\n",
|
||
pWamInfo,
|
||
pWamInfo->FInProcess(),
|
||
pszAppPath));
|
||
|
||
|
||
hr = pWamInfo->StartShutdown(cIgnoreRefs);
|
||
hr = pWamInfo->UnInit();
|
||
|
||
if (FAILED(hr))
|
||
{
|
||
const CHAR *pszEventLog[2];
|
||
char szErr[20];
|
||
|
||
pszEventLog[0] = pszAppPath;
|
||
wsprintf(szErr, "0x%08X", hr);
|
||
pszEventLog[1] = szErr;
|
||
|
||
// Event login
|
||
g_pInetSvc->LogEvent(W3_EVENT_FAIL_SHUTDOWN,
|
||
2,
|
||
pszEventLog,
|
||
0);
|
||
}
|
||
|
||
//delete pWamInfo;
|
||
//pWamInfo = NULL;
|
||
return hr;
|
||
} // wAM_DICTATOR::ShutdownWamInfo
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::CPUUpdateWamInfo
|
||
Arguments:
|
||
|
||
Return Value:
|
||
TRUE or FALSE
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
void
|
||
WAM_DICTATOR::CPUUpdateWamInfo
|
||
(
|
||
STR *pstrAppPath
|
||
)
|
||
{
|
||
CWamInfo* pWamInfo = NULL;
|
||
INT AppState;
|
||
|
||
DBG_ASSERT(pstrAppPath != NULL);
|
||
|
||
// Find the WamInfo.
|
||
AppState = FindWamInfo(pstrAppPath, &pWamInfo);
|
||
if (-1 != AppState)
|
||
{
|
||
BOOL fWasShutDown = FALSE;
|
||
DWORD eWISPrevState;
|
||
|
||
if ( !pWamInfo->FInProcess() )
|
||
{
|
||
//
|
||
// It's out of process and the job state has changed
|
||
// Shut it down so new value will get picked up
|
||
//
|
||
|
||
//
|
||
// change the state of the WamInfo
|
||
//
|
||
|
||
eWISPrevState = pWamInfo->ChangeToState(WIS_RUNNING, WIS_SHUTDOWN);
|
||
|
||
//
|
||
// Need to shutdown the Application
|
||
// remove from the hash table here. and clean up later.
|
||
if (WIS_RUNNING == eWISPrevState)
|
||
{
|
||
|
||
ShutdownWamInfo(pWamInfo, HASH_TABLE_REF + FIND_KEY_REF);
|
||
|
||
// NoNeed to go through the Dying List.
|
||
// But since we already have the Dying List, we might just used those functions.
|
||
// this means we might release other old WamInfo in the Dying List as well.
|
||
m_HashTable.DeleteKey(pstrAppPath->QueryStr());
|
||
|
||
fWasShutDown = TRUE;
|
||
|
||
}
|
||
}
|
||
pWamInfo->Dereference();
|
||
if (fWasShutDown)
|
||
{
|
||
pWamInfo->Dereference();
|
||
//delete pWamInfo;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
HRESULT
|
||
WAM_DICTATOR::WamRegSink
|
||
Argument:
|
||
szAppPath [in] Application Path.
|
||
dwCommand [in] Delete, Change, Stop..etc.
|
||
|
||
Return:
|
||
HRESULT
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::WamRegSink
|
||
(
|
||
LPCSTR szAppPath,
|
||
const DWORD dwCommand,
|
||
DWORD* pdwResult
|
||
)
|
||
{
|
||
CWamInfo* pWamInfo = NULL;
|
||
INT AppState;
|
||
HRESULT hrReturn = NOERROR;
|
||
|
||
DBG_ASSERT(szAppPath != NULL);
|
||
|
||
*pdwResult = APPSTATUS_UnLoaded;
|
||
|
||
//
|
||
// Set up the Application Path
|
||
//
|
||
STR* pstrAppPath = new STR(szAppPath);
|
||
|
||
if (NULL == pstrAppPath)
|
||
{
|
||
return E_OUTOFMEMORY;
|
||
}
|
||
|
||
Reference();
|
||
DBGPRINTF((DBG_CONTEXT,
|
||
"Wam Dictator received a SinkNotify on MD Path %s, cmd = %d\n",
|
||
szAppPath,
|
||
dwCommand));
|
||
|
||
if (dwCommand == APPCMD_UNLOAD)
|
||
{
|
||
hrReturn = UnLoadWamInfo(pstrAppPath, FALSE);
|
||
*pdwResult = (SUCCEEDED(hrReturn)) ? APPSTATUS_UnLoaded : APPSTATUS_Error;
|
||
}
|
||
else
|
||
{
|
||
// Find the WamInfo.
|
||
AppState = FindWamInfo(pstrAppPath, &pWamInfo);
|
||
if (-1 != AppState)
|
||
{
|
||
LK_RETCODE LkReturn;
|
||
DWORD eWISPrevState;
|
||
|
||
if (dwCommand == APPCMD_DELETE ||
|
||
dwCommand == APPCMD_CHANGETOINPROC ||
|
||
dwCommand == APPCMD_CHANGETOOUTPROC)
|
||
{
|
||
eWISPrevState = pWamInfo->ChangeToState(WIS_RUNNING, WIS_SHUTDOWN);
|
||
|
||
if (WIS_RUNNING == eWISPrevState)
|
||
{
|
||
LkReturn = m_HashTable.DeleteKey(pstrAppPath->QueryStr());
|
||
DBG_ASSERT(LK_SUCCESS == LkReturn);
|
||
|
||
if (LK_SUCCESS == LkReturn)
|
||
{
|
||
DyingList_Lock();
|
||
InsertDyingList(pWamInfo, FALSE);
|
||
DyingList_UnLock();
|
||
|
||
ScheduledId_Lock();
|
||
if (m_dwScheduledId == 0)
|
||
{
|
||
// DebugBreak();
|
||
m_dwScheduledId = ScheduleWorkItem
|
||
(
|
||
WAM_DICTATOR::CleanupScheduled,
|
||
NULL,
|
||
0,
|
||
FALSE
|
||
);
|
||
DBGPRINTF((DBG_CONTEXT, "add schedule item %d\n", m_dwScheduledId));
|
||
DBG_ASSERT(m_dwScheduledId);
|
||
}
|
||
ScheduledId_UnLock();
|
||
|
||
*pdwResult = (SUCCEEDED(hrReturn)) ? APPSTATUS_UnLoaded : APPSTATUS_Error;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Previous state is not running state. Leave it alone.
|
||
//
|
||
pWamInfo->Dereference();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// AppGetStatus
|
||
if (WIS_RUNNING == pWamInfo->QueryState())
|
||
{
|
||
*pdwResult = APPSTATUS_Running;
|
||
}
|
||
else
|
||
{
|
||
*pdwResult = APPSTATUS_Stopped;
|
||
}
|
||
|
||
pWamInfo->Dereference();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// This Application is not loaded.
|
||
*pdwResult = APPSTATUS_NotFoundInW3SVC;
|
||
}
|
||
}
|
||
|
||
Dereference();
|
||
return hrReturn;
|
||
}//WAM_DICTATOR::WamRegSink
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::InsertDyingList
|
||
This function insert an invalid WamInfo into DyingList. No blocking.
|
||
|
||
Arguments:
|
||
pWamInfo [in] a pointer to WamInfo
|
||
fNeedReference [in] if TRUE, then we Rereference the WamInfo. Because we get the WamInfo by
|
||
Hashtable's Interator or LookUp. When we get a WamInfo from Hash Table by
|
||
hash table's interator or LookUp call, the Hash table does a AddRef to
|
||
WamInfo. Therefore, this parameter tells whether we need to balance that
|
||
Addref or not.
|
||
Return Value:
|
||
NOERROR.
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::InsertDyingList
|
||
(
|
||
CWamInfo* pWamInfo,
|
||
BOOL fNeedReference
|
||
)
|
||
{
|
||
DBG_ASSERT(pWamInfo);
|
||
|
||
DyingList_Lock();
|
||
//
|
||
// Note: Delete Dereference WamInfo. This Dereference() within Delete() balances
|
||
// the AddRef() in Insert() call to the hash table.
|
||
//
|
||
InsertHeadList(&m_DyingListHead, &pWamInfo->ListEntry);
|
||
//
|
||
// Unfortunately, I can not move this Dereference() out of Critical Section.
|
||
// If I move the Dereference() after the Critical Section, then, since the WamInfo is
|
||
// already on the DyingList. therefore, any other thread happens to do the CleanUpDyingList()
|
||
// call before this Dereference() will have an unbalanced reference to the CWamInfo.
|
||
//
|
||
if (fNeedReference)
|
||
{
|
||
pWamInfo->Reference();
|
||
}
|
||
|
||
DyingList_UnLock();
|
||
|
||
return NOERROR;
|
||
}//WAM_DICTATOR::InsertDyingList
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::CleanUpDyingList
|
||
This function clean up any remaining WamInfo on the dying list.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
HRESULT
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
HRESULT
|
||
WAM_DICTATOR::CleanUpDyingList
|
||
(
|
||
VOID
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::CleanUpDyingList\n"));
|
||
|
||
CWamInfo * pWamInfo = NULL;
|
||
HRESULT hr = NOERROR;
|
||
PLIST_ENTRY pleTemp;
|
||
BOOL fNeedCleanupAction = FALSE;
|
||
|
||
DyingList_Lock();
|
||
if (!IsListEmpty(&m_DyingListHead))
|
||
{
|
||
if (!m_fCleanupInProgress)
|
||
{
|
||
m_fCleanupInProgress = TRUE;
|
||
fNeedCleanupAction = TRUE;
|
||
}
|
||
}
|
||
|
||
DBGPRINTF((DBG_CONTEXT, "Clean up dying list. (ScheduledId:%d).\n",
|
||
m_dwScheduledId));
|
||
|
||
DyingList_UnLock();
|
||
|
||
if (!fNeedCleanupAction)
|
||
{
|
||
goto Egress;
|
||
}
|
||
|
||
// From now on, only one thread is working on the killing dying list.
|
||
while (!IsListEmpty(&m_DyingListHead))
|
||
{
|
||
DyingList_Lock();
|
||
pleTemp = RemoveHeadList(&m_DyingListHead);
|
||
DyingList_UnLock();
|
||
|
||
DBG_ASSERT(pleTemp);
|
||
pWamInfo = CONTAINING_RECORD(
|
||
pleTemp,
|
||
CWamInfo,
|
||
ListEntry);
|
||
|
||
ShutdownWamInfo(pWamInfo, DYING_LIST_REF);
|
||
|
||
pWamInfo->Dereference();
|
||
|
||
pWamInfo->Dereference();
|
||
//delete pWamInfo;
|
||
pWamInfo = NULL;
|
||
}
|
||
|
||
InterlockedExchange((LPLONG)&m_fCleanupInProgress, (LONG)FALSE);
|
||
|
||
DBGPRINTF((DBG_CONTEXT, "CleanupDyingList done, ScheduledId(%d)\n", m_dwScheduledId));
|
||
|
||
Egress:
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::CleanUpDyingList done\n"));
|
||
|
||
m_dwScheduledId = 0;
|
||
return hr;
|
||
}//WAM_DICTATOR::CleanUpDyingList
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::StopAplicationsByInstance
|
||
|
||
Unload out-proc applications for a particular w3 server instance.
|
||
|
||
Arguments:
|
||
W3_SERVER_INSTANCE *pInstance
|
||
pointer to W3 Server Instance object. Used to query the server instance
|
||
metabase path.
|
||
|
||
Return Value:
|
||
none
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
VOID
|
||
WAM_DICTATOR::StopApplicationsByInstance
|
||
(
|
||
VOID *pContext //W3_SERVER_INSTANCE *pInstance
|
||
)
|
||
{
|
||
IF_DEBUG( WAM_ISA_CALLS )
|
||
DBGPRINTF((DBG_CONTEXT, "WAM_DICTATOR::StopApplicationsByInstance\n"));
|
||
|
||
BUFFER bufDataPaths;
|
||
MB mb( (IMDCOM*) g_pInetSvc->QueryMDObject() );
|
||
LPSTR pszCurrentPath;
|
||
STR strPath;
|
||
W3_SERVER_INSTANCE *pInstance;
|
||
|
||
DBG_ASSERT(pContext != NULL);
|
||
DBG_ASSERT(g_pWamDictator != NULL);
|
||
|
||
pInstance = (W3_SERVER_INSTANCE *)pContext;
|
||
|
||
g_pWamDictator->Reference();
|
||
if (!g_pWamDictator->FIsShutdown())
|
||
{
|
||
if ( mb.Open( pInstance->QueryMDPath(),
|
||
METADATA_PERMISSION_READ ) )
|
||
{
|
||
//
|
||
// First find the OOP Applications
|
||
//
|
||
if (mb.GetDataPaths(NULL,
|
||
MD_APP_WAM_CLSID,
|
||
STRING_METADATA,
|
||
&bufDataPaths))
|
||
{
|
||
//
|
||
// For each OOP Application
|
||
//
|
||
mb.Close();
|
||
for (pszCurrentPath = (LPSTR)bufDataPaths.QueryPtr();
|
||
*pszCurrentPath != '\0';
|
||
pszCurrentPath += (strlen(pszCurrentPath) + 1))
|
||
{
|
||
strPath.Copy(pInstance->QueryMDPath());
|
||
strPath.Append(pszCurrentPath);
|
||
strPath.SetLen(strlen(strPath.QueryStr()) - 1);
|
||
g_pWamDictator->UnLoadWamInfo(&strPath, FALSE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
mb.Close();
|
||
}
|
||
}
|
||
} // WamDictator is in shutdown
|
||
g_pWamDictator->Dereference();
|
||
|
||
}
|
||
|
||
BOOL
|
||
WAM_DICTATOR::DeleteWamInfoFromHashTable
|
||
(
|
||
CWamInfo * pWamInfo
|
||
)
|
||
{
|
||
LK_RETCODE lkReturn;
|
||
const CHAR * szKey;
|
||
|
||
DBG_ASSERT( pWamInfo );
|
||
|
||
szKey = m_HashTable.ExtractKey( pWamInfo );
|
||
|
||
if ( !szKey )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
lkReturn = m_HashTable.DeleteKey( szKey );
|
||
|
||
return ( lkReturn == LK_SUCCESS );
|
||
}
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
WAM_DICTATOR::DumpWamDictatorInfo
|
||
|
||
Description:
|
||
This function dumps the stats on all WAMs for diagnostics
|
||
|
||
Arguments:
|
||
pchBuffer - pointer to buffer that will contain the html results
|
||
lpcchBuffer - pointer to DWORD containing the size of buffer on entry
|
||
On return this contains the # of bytes written out to buffer
|
||
|
||
Return:
|
||
TRUE for success and FALSE for failure
|
||
Look at GetLastError() for the error code.
|
||
-----------------------------------------------------------------------------*/
|
||
BOOL
|
||
WAM_DICTATOR::DumpWamDictatorInfo
|
||
(
|
||
OUT CHAR * pchBuffer,
|
||
IN OUT LPDWORD lpcchBuffer
|
||
)
|
||
{
|
||
LIST_ENTRY * pEntry;
|
||
DWORD iCount, cch;
|
||
BOOL fRet = TRUE;
|
||
|
||
if ( lpcchBuffer == NULL )
|
||
{
|
||
SetLastError( ERROR_INVALID_PARAMETER);
|
||
return ( FALSE);
|
||
}
|
||
|
||
|
||
if ( 200 < *lpcchBuffer )
|
||
{
|
||
// Print the header blob
|
||
cch = wsprintf( pchBuffer,
|
||
" Wam Director Table (%x)<br>"
|
||
"<TABLE BORDER> <TR> "
|
||
"<TH> Wam Instance </TH> "
|
||
"<TH> Total Reqs </TH> "
|
||
"<TH> Current Reqs </TH> "
|
||
"<TH> Max Reqs </TH> "
|
||
" </TR>"
|
||
,
|
||
this
|
||
);
|
||
}
|
||
else
|
||
{
|
||
cch = 200;
|
||
}
|
||
|
||
//
|
||
// For now there is only ONE WAM. Later use a loop to iterate thru WAMs
|
||
//
|
||
|
||
iCount = 0;
|
||
|
||
CWamInfoHash::CIterator iter;
|
||
LK_RETCODE lkReturn = m_HashTable.InitializeIterator(&iter);
|
||
WAM_STATISTICS_INFO wsi;
|
||
CWamInfo* pWamInfo;
|
||
DWORD dwErr;
|
||
HRESULT hr;
|
||
|
||
ZeroMemory( (PVOID ) &wsi, sizeof(wsi));
|
||
|
||
while (LK_SUCCESS == lkReturn)
|
||
{
|
||
CWamInfoHash::Record *pRec = iter.Record();
|
||
|
||
pWamInfo = (CWamInfo *)pRec;
|
||
|
||
hr = pWamInfo->GetStatistics( 0, &wsi);
|
||
|
||
if (SUCCEEDED(hr))
|
||
{
|
||
DBGPRINTF(( DBG_CONTEXT, " Wam(%08x)::GetStatistics( %08x) => %08x\n",
|
||
pWamInfo->QueryIWam(), &wsi, hr));
|
||
|
||
if ( (cch + 150 ) < *lpcchBuffer)
|
||
{
|
||
cch += wsprintf( pchBuffer + cch,
|
||
" <TR> <TD> [%d] %s </TD> "
|
||
" <TD> %4d </TD>"
|
||
" <TD> %4d </TD>"
|
||
" <TD> %4d </TD>"
|
||
" </TR>"
|
||
,
|
||
iCount,
|
||
pWamInfo->QueryKey(),
|
||
wsi.WamStats0.TotalWamRequests,
|
||
wsi.WamStats0.CurrentWamRequests,
|
||
wsi.WamStats0.MaxWamRequests
|
||
);
|
||
iCount++;
|
||
}
|
||
else
|
||
{
|
||
cch += 150;
|
||
}
|
||
}
|
||
|
||
lkReturn = m_HashTable.IncrementIterator(&iter);
|
||
} // while()
|
||
|
||
DBG_ASSERT(lkReturn == LK_NO_MORE_ELEMENTS);
|
||
|
||
lkReturn = m_HashTable.CloseIterator(&iter);
|
||
|
||
DBG_REQUIRE(lkReturn == LK_SUCCESS);
|
||
|
||
//
|
||
// dump the final summary
|
||
//
|
||
if ( (cch + 100 ) < *lpcchBuffer)
|
||
{
|
||
cch += wsprintf( pchBuffer + cch,
|
||
" </TABLE>"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
cch += 100;
|
||
}
|
||
|
||
if ( *lpcchBuffer < cch )
|
||
{
|
||
SetLastError( ERROR_INSUFFICIENT_BUFFER);
|
||
fRet = FALSE;
|
||
}
|
||
|
||
*lpcchBuffer = cch;
|
||
|
||
return (fRet);
|
||
} // WAM_DICTATOR::DumpWamDictatorInfo()
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
Description:
|
||
Thunk so that we can dll export DumpWamDictatorInfo.
|
||
|
||
-----------------------------------------------------------------------------*/
|
||
extern "C"
|
||
BOOL WamDictatorDumpInfo
|
||
(
|
||
OUT CHAR * pch,
|
||
IN OUT LPDWORD lpcchBuff
|
||
)
|
||
{
|
||
return ( g_pWamDictator->DumpWamDictatorInfo( pch, lpcchBuff));
|
||
} // WamDictatorDumpInfo()
|
||
|
||
HRESULT W3SVC_WamRegSink
|
||
(
|
||
LPCSTR szAppPath,
|
||
const DWORD dwCommand,
|
||
DWORD* pdwResult
|
||
)
|
||
{
|
||
return (g_pWamDictator->WamRegSink(szAppPath, dwCommand, pdwResult));
|
||
} // W3SVCDictatorDumpInfo()
|
||
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
Thunks for Fake NT APIs
|
||
-----------------------------------------------------------------------------*/
|
||
CRITICAL_SECTION g_csNonNTAPIs;
|
||
LONG FakeInterlockedCompareExchange(
|
||
LONG *Destination,
|
||
LONG Exchange,
|
||
LONG Comperand
|
||
);
|
||
|
||
LONG
|
||
FakeInterlockedCompareExchange(
|
||
LONG *Destination,
|
||
LONG Exchange,
|
||
LONG Comperand
|
||
)
|
||
/*-----------------------------------------------------------------------------
|
||
Description:
|
||
This function fakes the interlocked compare exchange operation for non NT
|
||
platforms
|
||
See WAMLoadNTApis() for details
|
||
|
||
Returns:
|
||
returns the old value at Destination
|
||
-----------------------------------------------------------------------------*/
|
||
{
|
||
LONG oldValue;
|
||
|
||
EnterCriticalSection( &g_csNonNTAPIs);
|
||
|
||
oldValue = *Destination;
|
||
|
||
if ( oldValue == Comperand ) {
|
||
*Destination = Exchange;
|
||
}
|
||
|
||
LeaveCriticalSection( &g_csNonNTAPIs);
|
||
|
||
return( oldValue);
|
||
} // FakeInterlockedCompareExchange()
|
||
|
||
|
||
static VOID
|
||
LoadNTApis(VOID)
|
||
/*-----------------------------------------------------------------------------
|
||
Description:
|
||
This function loads the entry point for functions from
|
||
Kernel32.dll. If the entry point is missing, the function
|
||
pointer will point to a fake routine which does nothing. Otherwise,
|
||
it will point to the real function.
|
||
|
||
It dynamically loads the kernel32.dll to find the entry ponit and then
|
||
unloads it after getting the address. For the resulting function
|
||
pointer to work correctly one has to ensure that the kernel32.dll is
|
||
linked with the dll/exe which links to this file.
|
||
-----------------------------------------------------------------------------*/
|
||
{
|
||
// Initialize the critical section for non NT API support, in case if we need this
|
||
INITIALIZE_CRITICAL_SECTION( &g_csNonNTAPIs);
|
||
|
||
if ( g_pfnInterlockedCompareExchange == NULL )
|
||
{
|
||
HINSTANCE tmpInstance;
|
||
//
|
||
// load kernel32 and get NT specific entry points
|
||
//
|
||
|
||
tmpInstance = LoadLibrary("kernel32.dll");
|
||
if ( tmpInstance != NULL )
|
||
{
|
||
|
||
// For some reason the original function is _InterlockedCompareExchange!
|
||
g_pfnInterlockedCompareExchange = (PFN_INTERLOCKED_COMPARE_EXCHANGE )
|
||
GetProcAddress( tmpInstance, "InterlockedCompareExchange");
|
||
|
||
if ( g_pfnInterlockedCompareExchange == NULL )
|
||
{
|
||
// the function is not available
|
||
// Just thunk it.
|
||
g_pfnInterlockedCompareExchange = FakeInterlockedCompareExchange;
|
||
}
|
||
|
||
//
|
||
// We can free this because we are statically linked to it
|
||
//
|
||
|
||
FreeLibrary(tmpInstance);
|
||
}
|
||
}
|
||
|
||
return;
|
||
} // WAMLoadNTApis()
|
||
|
||
static void
|
||
UnloadNTApis(VOID)
|
||
{
|
||
DeleteCriticalSection( &g_csNonNTAPIs);
|
||
|
||
return;
|
||
} // WAMUnloadNTApis()
|
||
|
||
VOID
|
||
RecycleCallback(
|
||
VOID * pvContext
|
||
)
|
||
{
|
||
CWamInfo * pWamInfo = (CWamInfo*)pvContext;
|
||
|
||
DBG_ASSERT( pWamInfo );
|
||
|
||
pWamInfo->m_fRecycled = TRUE;
|
||
|
||
if (!g_pWamDictator->m_PTable.RecycleWamInfo( pWamInfo ) )
|
||
{
|
||
DBGPRINTF((
|
||
DBG_CONTEXT,
|
||
"[RecycleCallback] failed to recycle CWamInfo 0x%08x.\r\n"
|
||
));
|
||
}
|
||
|
||
pWamInfo->Dereference();
|
||
|
||
return;
|
||
}
|
||
|
||
/************************ End of File ***********************/
|
||
|