|
|
//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1997
//
// File: csrv.cxx
//
// Contents: Contains methods for CIISServer object
//
// History: 21-1-98 SophiaC Created.
//
//----------------------------------------------------------------------------
#include "iisext.hxx"
#pragma hdrstop
//
// Period to sleep while waiting for service to attain desired state
//
#define SLEEP_INTERVAL (500L)
#define MAX_SLEEP_INST (60000) // For an instance
// Class CIISServer
DEFINE_IPrivateDispatch_Implementation(CIISServer) DEFINE_DELEGATING_IDispatch_Implementation(CIISServer) DEFINE_CONTAINED_IADs_Implementation(CIISServer) DEFINE_IADsExtension_Implementation(CIISServer)
CIISServer::CIISServer(): _pUnkOuter(NULL), _pADs(NULL), _pszServerName(NULL), _pszMetaBasePath(NULL), _pAdminBase(NULL), _pDispMgr(NULL), _fDispInitialized(FALSE) { ENLIST_TRACKING(CIISServer); }
HRESULT CIISServer::CreateServer( IUnknown *pUnkOuter, REFIID riid, void **ppvObj ) { CCredentials Credentials; CIISServer FAR * pServer = NULL; HRESULT hr = S_OK; BSTR bstrAdsPath = NULL; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; CLexer * pLexer = NULL; LPWSTR pszIISPathName = NULL;
hr = AllocateServerObject(pUnkOuter, Credentials, &pServer); BAIL_ON_FAILURE(hr);
//
// get ServerName and pszPath
//
hr = pServer->_pADs->get_ADsPath(&bstrAdsPath); BAIL_ON_FAILURE(hr);
pLexer = new CLexer(); hr = pLexer->Initialize(bstrAdsPath); BAIL_ON_FAILURE(hr);
//
// Parse the pathname
//
memset(pObjectInfo, 0, sizeof(OBJECTINFO)); hr = ADsObject(pLexer, pObjectInfo); BAIL_ON_FAILURE(hr); pszIISPathName = AllocADsStr(bstrAdsPath); if (!pszIISPathName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); }
*pszIISPathName = L'\0'; hr = BuildIISPathFromADsPath( pObjectInfo, pszIISPathName ); BAIL_ON_FAILURE(hr);
hr = pServer->InitializeServerObject( pObjectInfo->TreeName, pszIISPathName ); BAIL_ON_FAILURE(hr);
//
// pass non-delegating IUnknown back to the aggregator
//
*ppvObj = (INonDelegatingUnknown FAR *) pServer;
if (bstrAdsPath) { ADsFreeString(bstrAdsPath); }
if (pLexer) { delete pLexer; }
if (pszIISPathName ) { FreeADsStr( pszIISPathName ); }
FreeObjectInfo( &ObjectInfo );
RRETURN(hr);
error:
if (bstrAdsPath) { ADsFreeString(bstrAdsPath); }
if (pLexer) { delete pLexer; }
if (pszIISPathName ) { FreeADsStr( pszIISPathName ); }
FreeObjectInfo( &ObjectInfo );
*ppvObj = NULL;
delete pServer;
RRETURN(hr);
}
CIISServer::~CIISServer( ) {
if (_pszServerName) { FreeADsStr(_pszServerName); }
if (_pszMetaBasePath) { FreeADsStr(_pszMetaBasePath); }
delete _pDispMgr; }
STDMETHODIMP CIISServer::QueryInterface( REFIID iid, LPVOID FAR* ppv ) { HRESULT hr = S_OK;
hr = _pUnkOuter->QueryInterface(iid,ppv);
RRETURN(hr);
}
HRESULT CIISServer::AllocateServerObject( IUnknown *pUnkOuter, CCredentials& Credentials, CIISServer ** ppServer ) { CIISServer FAR * pServer = NULL; IADs FAR * pADs = NULL; CAggregateeDispMgr FAR * pDispMgr = NULL; HRESULT hr = S_OK;
pServer = new CIISServer(); if (pServer == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr);
pDispMgr = new CAggregateeDispMgr; if (pDispMgr == NULL) { hr = E_OUTOFMEMORY; } BAIL_ON_FAILURE(hr);
hr = pDispMgr->LoadTypeInfoEntry( LIBID_ADs, IID_IADsServiceOperations, (IADsServiceOperations *)pServer, DISPID_REGULAR ); BAIL_ON_FAILURE(hr);
//
// Store the IADs Pointer, but again do NOT ref-count
// this pointer - we keep the pointer around, but do
// a release immediately.
//
hr = pUnkOuter->QueryInterface(IID_IADs, (void **)&pADs); pADs->Release(); pServer->_pADs = pADs;
//
// Store the pointer to the pUnkOuter object
// AND DO NOT add ref this pointer
//
pServer->_pUnkOuter = pUnkOuter;
//
// Store the pointer to the internal generic object
// AND add ref this pointer
//
pServer->_Credentials = Credentials; pServer->_pDispMgr = pDispMgr; *ppServer = pServer;
RRETURN(hr);
error:
delete pDispMgr; delete pServer;
RRETURN(hr); }
HRESULT CIISServer::InitializeServerObject( LPWSTR pszServerName, LPWSTR pszPath ) { HRESULT hr = S_OK;
if (pszServerName) { _pszServerName = AllocADsStr(pszServerName);
if (!_pszServerName) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } }
if (pszPath) { _pszMetaBasePath = AllocADsStr(pszPath);
if (!_pszMetaBasePath) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } }
hr = InitServerInfo(pszServerName, &_pAdminBase); BAIL_ON_FAILURE(hr);
error:
RRETURN(hr); }
STDMETHODIMP CIISServer::SetPassword(THIS_ BSTR bstrNewPassword) { RRETURN(E_NOTIMPL); }
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Start
//
// Synopsis: Attempts to start the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/97 SophiaC Created
//
// Notes:
//----------------------------------------------------------------------------
STDMETHODIMP CIISServer::Start(THIS) { RRETURN(IISControlServer(MD_SERVER_COMMAND_START)); }
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Stop
//
// Synopsis: Attempts to stop the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CIISServer::Stop(THIS) { RRETURN(IISControlServer(MD_SERVER_COMMAND_STOP)); }
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Pause
//
// Synopsis: Attempts to pause the service named _bstrServiceName on the
// server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01-04-96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CIISServer::Pause(THIS) { RRETURN(IISControlServer(MD_SERVER_COMMAND_PAUSE)); }
//+---------------------------------------------------------------------------
//
// Function: CIISServer::Continue
//
// Synopsis: Attempts to "unpause" the service specified in _bstrServiceName
// on the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 SophiaC Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CIISServer::Continue(THIS) { RRETURN(IISControlServer(MD_SERVER_COMMAND_CONTINUE)); }
STDMETHODIMP CIISServer::get_Status(THIS_ long FAR* plStatusCode) { HRESULT hr = S_OK; DWORD dwStatus = 0; DWORD dwCurrentState = 0;
if(plStatusCode == NULL){ RRETURN(E_POINTER); }
hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwCurrentState); BAIL_ON_FAILURE(hr);
*plStatusCode = (long) dwCurrentState;
error:
RRETURN(hr); }
//
// Helper Functions
//
HRESULT CIISServer::IISGetServerState( METADATA_HANDLE hObjHandle, PDWORD pdwState ) {
HRESULT hr = S_OK; DWORD dwBufferSize = sizeof(DWORD); METADATA_RECORD mdrMDData; LPBYTE pBuffer = (LPBYTE)pdwState;
MD_SET_DATA_RECORD(&mdrMDData, MD_SERVER_STATE, // server state
METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, dwBufferSize, pBuffer);
hr = _pAdminBase->GetData( hObjHandle, _pszMetaBasePath, &mdrMDData, &dwBufferSize ); if (FAILED(hr)) { if( hr == MD_ERROR_DATA_NOT_FOUND ) { //
// If the data is not there, but the path exists, then the
// most likely cause is that the service is not running and
// this object was just created.
//
// Since MD_SERVER_STATE would be set as stopped if the
// service were running when the key is added, we'll just
// say that it's stopped.
//
// Note: starting the server or service will automatically set
// the MB value.
//
*pdwState = MD_SERVER_STATE_STOPPED; hr = S_FALSE; }
else if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) || ((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) && (HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) || hr == RPC_E_DISCONNECTED) { hr = ReCacheAdminBase(_pszServerName, &_pAdminBase); BAIL_ON_FAILURE(hr);
hr = _pAdminBase->GetData( hObjHandle, _pszMetaBasePath, &mdrMDData, &dwBufferSize ); BAIL_ON_FAILURE(hr); }
else { BAIL_ON_FAILURE(hr); } } error:
RRETURN(hr); }
//
// Helper routine for ExecMethod.
// Gets Win32 error from the metabase
//
HRESULT CIISServer::IISGetServerWin32Error( METADATA_HANDLE hObjHandle, HRESULT* phrError) { DBG_ASSERT(phrError != NULL);
long lWin32Error = 0; DWORD dwLen;
METADATA_RECORD mr = { MD_WIN32_ERROR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, sizeof(DWORD), (unsigned char*)&lWin32Error, 0 }; HRESULT hr = _pAdminBase->GetData( hObjHandle, _pszMetaBasePath, &mr, &dwLen); if(hr == MD_ERROR_DATA_NOT_FOUND) { hr = S_FALSE; }
//
// Set out param
//
*phrError = HRESULT_FROM_WIN32(lWin32Error);
RRETURN(hr); }
HRESULT CIISServer::IISControlServer( DWORD dwControl ) { METADATA_HANDLE hObjHandle = NULL; DWORD dwTargetState; DWORD dwPendingState; DWORD dwState = 0; DWORD dwSleepTotal = 0L;
HRESULT hr = S_OK; HRESULT hrMbNode = S_OK;
switch(dwControl) { case MD_SERVER_COMMAND_STOP: dwTargetState = MD_SERVER_STATE_STOPPED; dwPendingState = MD_SERVER_STATE_STOPPING; break;
case MD_SERVER_COMMAND_START: dwTargetState = MD_SERVER_STATE_STARTED; dwPendingState = MD_SERVER_STATE_STARTING; break;
case MD_SERVER_COMMAND_CONTINUE: dwTargetState = MD_SERVER_STATE_STARTED; dwPendingState = MD_SERVER_STATE_CONTINUING; break;
case MD_SERVER_COMMAND_PAUSE: dwTargetState = MD_SERVER_STATE_PAUSED; dwPendingState = MD_SERVER_STATE_PAUSING; break;
default: hr = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); BAIL_ON_FAILURE(hr); }
hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState); BAIL_ON_FAILURE(hr); if (dwState == dwTargetState) { RRETURN (hr); }
//
// Write the command to the metabase
//
hr = OpenAdminBaseKey( _pszServerName, _pszMetaBasePath, METADATA_PERMISSION_WRITE, &_pAdminBase, &hObjHandle ); BAIL_ON_FAILURE(hr);
hr = IISSetCommand(hObjHandle, dwControl); BAIL_ON_FAILURE(hr);
CloseAdminBaseKey(_pAdminBase, hObjHandle);
while (dwSleepTotal < MAX_SLEEP_INST) { hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState); BAIL_ON_FAILURE(hr);
hrMbNode = 0;
hr = IISGetServerWin32Error(METADATA_MASTER_ROOT_HANDLE, &hrMbNode); BAIL_ON_FAILURE(hr);
// check to see if we hit the target state
if (dwState != dwPendingState) { //
// Done one way or another
//
if (dwState == dwTargetState) { break; } }
// check to see if there was a Win32 error from the server
if (FAILED(hrMbNode)) { hr = hrMbNode; BAIL_ON_FAILURE(hr); }
//
// Still pending...
//
::Sleep(SLEEP_INTERVAL);
dwSleepTotal += SLEEP_INTERVAL; }
if (dwSleepTotal >= MAX_SLEEP_INST) { //
// Timed out. If there is a real error in the metabase
// use it, otherwise use a generic timeout error
//
hr = HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT); }
error :
if (_pAdminBase && hObjHandle) { CloseAdminBaseKey(_pAdminBase, hObjHandle); }
RRETURN (hr); }
HRESULT CIISServer::IISSetCommand( METADATA_HANDLE hObjHandle, DWORD dwControl ) {
HRESULT hr = S_OK; DWORD dwBufferSize = sizeof(DWORD); METADATA_RECORD mdrMDData; LPBYTE pBuffer = (LPBYTE)&dwControl;
MD_SET_DATA_RECORD(&mdrMDData, MD_SERVER_COMMAND, // server command
METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, dwBufferSize, pBuffer);
hr = _pAdminBase->SetData( hObjHandle, L"", &mdrMDData ); BAIL_ON_FAILURE(hr);
error:
RRETURN(hr);
}
STDMETHODIMP CIISServer::ADSIInitializeDispatchManager( long dwExtensionId ) { HRESULT hr = S_OK;
if (_fDispInitialized) {
RRETURN(E_FAIL); }
hr = _pDispMgr->InitializeDispMgr(dwExtensionId);
if (SUCCEEDED(hr)) { _fDispInitialized = TRUE; }
RRETURN(hr); }
STDMETHODIMP CIISServer::ADSIInitializeObject( THIS_ BSTR lpszUserName, BSTR lpszPassword, long lnReserved ) {
CCredentials NewCredentials(lpszUserName, lpszPassword, lnReserved);
_Credentials = NewCredentials;
RRETURN(S_OK); }
STDMETHODIMP CIISServer::ADSIReleaseObject() { delete this; RRETURN(S_OK); }
STDMETHODIMP CIISServer::NonDelegatingQueryInterface( REFIID iid, LPVOID FAR* ppv ) { if (IsEqualIID(iid, IID_IADsServiceOperations)) {
*ppv = (IADsUser FAR *) this;
} else if (IsEqualIID(iid, IID_IADsExtension)) {
*ppv = (IADsExtension FAR *) this;
} else if (IsEqualIID(iid, IID_IUnknown)) {
//
// probably not needed since our 3rd party extension does not stand
// alone and provider does not ask for this, but to be safe
//
*ppv = (INonDelegatingUnknown FAR *) this;
} else {
*ppv = NULL; return E_NOINTERFACE; }
//
// Delegating AddRef to aggregator for IADsExtesnion and IISServer.
// AddRef on itself for IPrivateUnknown. (both tested.)
//
((IUnknown *) (*ppv)) -> AddRef();
return S_OK; }
//
// IADsExtension::Operate()
//
STDMETHODIMP CIISServer::Operate( THIS_ DWORD dwCode, VARIANT varUserName, VARIANT varPassword, VARIANT varFlags ) { RRETURN(E_NOTIMPL); }
|