Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

773 lines
16 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1997
  5. //
  6. // File: csrv.cxx
  7. //
  8. // Contents: Contains methods for CIISServer object
  9. //
  10. // History: 21-1-98 SophiaC Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "iisext.hxx"
  14. #pragma hdrstop
  15. //
  16. // Period to sleep while waiting for service to attain desired state
  17. //
  18. #define SLEEP_INTERVAL (500L)
  19. #define MAX_SLEEP_INST (60000) // For an instance
  20. // Class CIISServer
  21. DEFINE_IPrivateDispatch_Implementation(CIISServer)
  22. DEFINE_DELEGATING_IDispatch_Implementation(CIISServer)
  23. DEFINE_CONTAINED_IADs_Implementation(CIISServer)
  24. DEFINE_IADsExtension_Implementation(CIISServer)
  25. CIISServer::CIISServer():
  26. _pUnkOuter(NULL),
  27. _pADs(NULL),
  28. _pszServerName(NULL),
  29. _pszMetaBasePath(NULL),
  30. _pAdminBase(NULL),
  31. _pDispMgr(NULL),
  32. _fDispInitialized(FALSE)
  33. {
  34. ENLIST_TRACKING(CIISServer);
  35. }
  36. HRESULT
  37. CIISServer::CreateServer(
  38. IUnknown *pUnkOuter,
  39. REFIID riid,
  40. void **ppvObj
  41. )
  42. {
  43. CCredentials Credentials;
  44. CIISServer FAR * pServer = NULL;
  45. HRESULT hr = S_OK;
  46. BSTR bstrAdsPath = NULL;
  47. OBJECTINFO ObjectInfo;
  48. POBJECTINFO pObjectInfo = &ObjectInfo;
  49. CLexer * pLexer = NULL;
  50. LPWSTR pszIISPathName = NULL;
  51. hr = AllocateServerObject(pUnkOuter, Credentials, &pServer);
  52. BAIL_ON_FAILURE(hr);
  53. //
  54. // get ServerName and pszPath
  55. //
  56. hr = pServer->_pADs->get_ADsPath(&bstrAdsPath);
  57. BAIL_ON_FAILURE(hr);
  58. pLexer = new CLexer();
  59. hr = pLexer->Initialize(bstrAdsPath);
  60. BAIL_ON_FAILURE(hr);
  61. //
  62. // Parse the pathname
  63. //
  64. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  65. hr = ADsObject(pLexer, pObjectInfo);
  66. BAIL_ON_FAILURE(hr);
  67. pszIISPathName = AllocADsStr(bstrAdsPath);
  68. if (!pszIISPathName) {
  69. hr = E_OUTOFMEMORY;
  70. BAIL_ON_FAILURE(hr);
  71. }
  72. *pszIISPathName = L'\0';
  73. hr = BuildIISPathFromADsPath(
  74. pObjectInfo,
  75. pszIISPathName
  76. );
  77. BAIL_ON_FAILURE(hr);
  78. hr = pServer->InitializeServerObject(
  79. pObjectInfo->TreeName,
  80. pszIISPathName );
  81. BAIL_ON_FAILURE(hr);
  82. //
  83. // pass non-delegating IUnknown back to the aggregator
  84. //
  85. *ppvObj = (INonDelegatingUnknown FAR *) pServer;
  86. if (bstrAdsPath)
  87. {
  88. ADsFreeString(bstrAdsPath);
  89. }
  90. if (pLexer) {
  91. delete pLexer;
  92. }
  93. if (pszIISPathName ) {
  94. FreeADsStr( pszIISPathName );
  95. }
  96. FreeObjectInfo( &ObjectInfo );
  97. RRETURN(hr);
  98. error:
  99. if (bstrAdsPath)
  100. {
  101. ADsFreeString(bstrAdsPath);
  102. }
  103. if (pLexer) {
  104. delete pLexer;
  105. }
  106. if (pszIISPathName ) {
  107. FreeADsStr( pszIISPathName );
  108. }
  109. FreeObjectInfo( &ObjectInfo );
  110. *ppvObj = NULL;
  111. delete pServer;
  112. RRETURN(hr);
  113. }
  114. CIISServer::~CIISServer( )
  115. {
  116. if (_pszServerName) {
  117. FreeADsStr(_pszServerName);
  118. }
  119. if (_pszMetaBasePath) {
  120. FreeADsStr(_pszMetaBasePath);
  121. }
  122. delete _pDispMgr;
  123. }
  124. STDMETHODIMP
  125. CIISServer::QueryInterface(
  126. REFIID iid,
  127. LPVOID FAR* ppv
  128. )
  129. {
  130. HRESULT hr = S_OK;
  131. hr = _pUnkOuter->QueryInterface(iid,ppv);
  132. RRETURN(hr);
  133. }
  134. HRESULT
  135. CIISServer::AllocateServerObject(
  136. IUnknown *pUnkOuter,
  137. CCredentials& Credentials,
  138. CIISServer ** ppServer
  139. )
  140. {
  141. CIISServer FAR * pServer = NULL;
  142. IADs FAR * pADs = NULL;
  143. CAggregateeDispMgr FAR * pDispMgr = NULL;
  144. HRESULT hr = S_OK;
  145. pServer = new CIISServer();
  146. if (pServer == NULL) {
  147. hr = E_OUTOFMEMORY;
  148. }
  149. BAIL_ON_FAILURE(hr);
  150. pDispMgr = new CAggregateeDispMgr;
  151. if (pDispMgr == NULL) {
  152. hr = E_OUTOFMEMORY;
  153. }
  154. BAIL_ON_FAILURE(hr);
  155. hr = pDispMgr->LoadTypeInfoEntry(
  156. LIBID_ADs,
  157. IID_IADsServiceOperations,
  158. (IADsServiceOperations *)pServer,
  159. DISPID_REGULAR
  160. );
  161. BAIL_ON_FAILURE(hr);
  162. //
  163. // Store the IADs Pointer, but again do NOT ref-count
  164. // this pointer - we keep the pointer around, but do
  165. // a release immediately.
  166. //
  167. hr = pUnkOuter->QueryInterface(IID_IADs, (void **)&pADs);
  168. pADs->Release();
  169. pServer->_pADs = pADs;
  170. //
  171. // Store the pointer to the pUnkOuter object
  172. // AND DO NOT add ref this pointer
  173. //
  174. pServer->_pUnkOuter = pUnkOuter;
  175. //
  176. // Store the pointer to the internal generic object
  177. // AND add ref this pointer
  178. //
  179. pServer->_Credentials = Credentials;
  180. pServer->_pDispMgr = pDispMgr;
  181. *ppServer = pServer;
  182. RRETURN(hr);
  183. error:
  184. delete pDispMgr;
  185. delete pServer;
  186. RRETURN(hr);
  187. }
  188. HRESULT
  189. CIISServer::InitializeServerObject(
  190. LPWSTR pszServerName,
  191. LPWSTR pszPath
  192. )
  193. {
  194. HRESULT hr = S_OK;
  195. if (pszServerName) {
  196. _pszServerName = AllocADsStr(pszServerName);
  197. if (!_pszServerName) {
  198. hr = E_OUTOFMEMORY;
  199. BAIL_ON_FAILURE(hr);
  200. }
  201. }
  202. if (pszPath) {
  203. _pszMetaBasePath = AllocADsStr(pszPath);
  204. if (!_pszMetaBasePath) {
  205. hr = E_OUTOFMEMORY;
  206. BAIL_ON_FAILURE(hr);
  207. }
  208. }
  209. hr = InitServerInfo(pszServerName, &_pAdminBase);
  210. BAIL_ON_FAILURE(hr);
  211. error:
  212. RRETURN(hr);
  213. }
  214. STDMETHODIMP
  215. CIISServer::SetPassword(THIS_ BSTR bstrNewPassword)
  216. {
  217. RRETURN(E_NOTIMPL);
  218. }
  219. //+---------------------------------------------------------------------------
  220. //
  221. // Function: CIISServer::Start
  222. //
  223. // Synopsis: Attempts to start the service specified in _bstrServiceName on
  224. // the server named in _bstrPath.
  225. //
  226. // Arguments:
  227. //
  228. // Returns: HRESULT.
  229. //
  230. // Modifies:
  231. //
  232. // History: 01/04/97 SophiaC Created
  233. //
  234. // Notes:
  235. //----------------------------------------------------------------------------
  236. STDMETHODIMP
  237. CIISServer::Start(THIS)
  238. {
  239. RRETURN(IISControlServer(MD_SERVER_COMMAND_START));
  240. }
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Function: CIISServer::Stop
  244. //
  245. // Synopsis: Attempts to stop the service specified in _bstrServiceName on
  246. // the server named in _bstrPath.
  247. //
  248. // Arguments:
  249. //
  250. // Returns: HRESULT.
  251. //
  252. // Modifies:
  253. //
  254. // History: 01/04/96 SophiaC Created
  255. //
  256. //----------------------------------------------------------------------------
  257. STDMETHODIMP
  258. CIISServer::Stop(THIS)
  259. {
  260. RRETURN(IISControlServer(MD_SERVER_COMMAND_STOP));
  261. }
  262. //+---------------------------------------------------------------------------
  263. //
  264. // Function: CIISServer::Pause
  265. //
  266. // Synopsis: Attempts to pause the service named _bstrServiceName on the
  267. // server named in _bstrPath.
  268. //
  269. // Arguments:
  270. //
  271. // Returns: HRESULT.
  272. //
  273. // Modifies:
  274. //
  275. // History: 01-04-96 SophiaC Created
  276. //
  277. //----------------------------------------------------------------------------
  278. STDMETHODIMP
  279. CIISServer::Pause(THIS)
  280. {
  281. RRETURN(IISControlServer(MD_SERVER_COMMAND_PAUSE));
  282. }
  283. //+---------------------------------------------------------------------------
  284. //
  285. // Function: CIISServer::Continue
  286. //
  287. // Synopsis: Attempts to "unpause" the service specified in _bstrServiceName
  288. // on the server named in _bstrPath.
  289. //
  290. // Arguments:
  291. //
  292. // Returns: HRESULT.
  293. //
  294. // Modifies:
  295. //
  296. // History: 01/04/96 SophiaC Created
  297. //
  298. //----------------------------------------------------------------------------
  299. STDMETHODIMP
  300. CIISServer::Continue(THIS)
  301. {
  302. RRETURN(IISControlServer(MD_SERVER_COMMAND_CONTINUE));
  303. }
  304. STDMETHODIMP
  305. CIISServer::get_Status(THIS_ long FAR* plStatusCode)
  306. {
  307. HRESULT hr = S_OK;
  308. DWORD dwStatus = 0;
  309. DWORD dwCurrentState = 0;
  310. if(plStatusCode == NULL){
  311. RRETURN(E_POINTER);
  312. }
  313. hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwCurrentState);
  314. BAIL_ON_FAILURE(hr);
  315. *plStatusCode = (long) dwCurrentState;
  316. error:
  317. RRETURN(hr);
  318. }
  319. //
  320. // Helper Functions
  321. //
  322. HRESULT
  323. CIISServer::IISGetServerState(
  324. METADATA_HANDLE hObjHandle,
  325. PDWORD pdwState
  326. )
  327. {
  328. HRESULT hr = S_OK;
  329. DWORD dwBufferSize = sizeof(DWORD);
  330. METADATA_RECORD mdrMDData;
  331. LPBYTE pBuffer = (LPBYTE)pdwState;
  332. MD_SET_DATA_RECORD(&mdrMDData,
  333. MD_SERVER_STATE, // server state
  334. METADATA_NO_ATTRIBUTES,
  335. IIS_MD_UT_SERVER,
  336. DWORD_METADATA,
  337. dwBufferSize,
  338. pBuffer);
  339. hr = _pAdminBase->GetData(
  340. hObjHandle,
  341. _pszMetaBasePath,
  342. &mdrMDData,
  343. &dwBufferSize
  344. );
  345. if (FAILED(hr)) {
  346. if( hr == MD_ERROR_DATA_NOT_FOUND )
  347. {
  348. //
  349. // If the data is not there, but the path exists, then the
  350. // most likely cause is that the service is not running and
  351. // this object was just created.
  352. //
  353. // Since MD_SERVER_STATE would be set as stopped if the
  354. // service were running when the key is added, we'll just
  355. // say that it's stopped.
  356. //
  357. // Note: starting the server or service will automatically set
  358. // the MB value.
  359. //
  360. *pdwState = MD_SERVER_STATE_STOPPED;
  361. hr = S_FALSE;
  362. }
  363. else if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) ||
  364. ((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) &&
  365. (HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) ||
  366. hr == RPC_E_DISCONNECTED) {
  367. hr = ReCacheAdminBase(_pszServerName, &_pAdminBase);
  368. BAIL_ON_FAILURE(hr);
  369. hr = _pAdminBase->GetData(
  370. hObjHandle,
  371. _pszMetaBasePath,
  372. &mdrMDData,
  373. &dwBufferSize
  374. );
  375. BAIL_ON_FAILURE(hr);
  376. }
  377. else
  378. {
  379. BAIL_ON_FAILURE(hr);
  380. }
  381. }
  382. error:
  383. RRETURN(hr);
  384. }
  385. //
  386. // Helper routine for ExecMethod.
  387. // Gets Win32 error from the metabase
  388. //
  389. HRESULT
  390. CIISServer::IISGetServerWin32Error(
  391. METADATA_HANDLE hObjHandle,
  392. HRESULT* phrError)
  393. {
  394. DBG_ASSERT(phrError != NULL);
  395. long lWin32Error = 0;
  396. DWORD dwLen;
  397. METADATA_RECORD mr = {
  398. MD_WIN32_ERROR,
  399. METADATA_NO_ATTRIBUTES,
  400. IIS_MD_UT_SERVER,
  401. DWORD_METADATA,
  402. sizeof(DWORD),
  403. (unsigned char*)&lWin32Error,
  404. 0
  405. };
  406. HRESULT hr = _pAdminBase->GetData(
  407. hObjHandle,
  408. _pszMetaBasePath,
  409. &mr,
  410. &dwLen);
  411. if(hr == MD_ERROR_DATA_NOT_FOUND)
  412. {
  413. hr = S_FALSE;
  414. }
  415. //
  416. // Set out param
  417. //
  418. *phrError = HRESULT_FROM_WIN32(lWin32Error);
  419. RRETURN(hr);
  420. }
  421. HRESULT
  422. CIISServer::IISControlServer(
  423. DWORD dwControl
  424. )
  425. {
  426. METADATA_HANDLE hObjHandle = NULL;
  427. DWORD dwTargetState;
  428. DWORD dwPendingState;
  429. DWORD dwState = 0;
  430. DWORD dwSleepTotal = 0L;
  431. HRESULT hr = S_OK;
  432. HRESULT hrMbNode = S_OK;
  433. switch(dwControl)
  434. {
  435. case MD_SERVER_COMMAND_STOP:
  436. dwTargetState = MD_SERVER_STATE_STOPPED;
  437. dwPendingState = MD_SERVER_STATE_STOPPING;
  438. break;
  439. case MD_SERVER_COMMAND_START:
  440. dwTargetState = MD_SERVER_STATE_STARTED;
  441. dwPendingState = MD_SERVER_STATE_STARTING;
  442. break;
  443. case MD_SERVER_COMMAND_CONTINUE:
  444. dwTargetState = MD_SERVER_STATE_STARTED;
  445. dwPendingState = MD_SERVER_STATE_CONTINUING;
  446. break;
  447. case MD_SERVER_COMMAND_PAUSE:
  448. dwTargetState = MD_SERVER_STATE_PAUSED;
  449. dwPendingState = MD_SERVER_STATE_PAUSING;
  450. break;
  451. default:
  452. hr = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER);
  453. BAIL_ON_FAILURE(hr);
  454. }
  455. hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState);
  456. BAIL_ON_FAILURE(hr);
  457. if (dwState == dwTargetState) {
  458. RRETURN (hr);
  459. }
  460. //
  461. // Write the command to the metabase
  462. //
  463. hr = OpenAdminBaseKey(
  464. _pszServerName,
  465. _pszMetaBasePath,
  466. METADATA_PERMISSION_WRITE,
  467. &_pAdminBase,
  468. &hObjHandle
  469. );
  470. BAIL_ON_FAILURE(hr);
  471. hr = IISSetCommand(hObjHandle, dwControl);
  472. BAIL_ON_FAILURE(hr);
  473. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  474. while (dwSleepTotal < MAX_SLEEP_INST) {
  475. hr = IISGetServerState(METADATA_MASTER_ROOT_HANDLE, &dwState);
  476. BAIL_ON_FAILURE(hr);
  477. hrMbNode = 0;
  478. hr = IISGetServerWin32Error(METADATA_MASTER_ROOT_HANDLE, &hrMbNode);
  479. BAIL_ON_FAILURE(hr);
  480. // check to see if we hit the target state
  481. if (dwState != dwPendingState)
  482. {
  483. //
  484. // Done one way or another
  485. //
  486. if (dwState == dwTargetState)
  487. {
  488. break;
  489. }
  490. }
  491. // check to see if there was a Win32 error from the server
  492. if (FAILED(hrMbNode))
  493. {
  494. hr = hrMbNode;
  495. BAIL_ON_FAILURE(hr);
  496. }
  497. //
  498. // Still pending...
  499. //
  500. ::Sleep(SLEEP_INTERVAL);
  501. dwSleepTotal += SLEEP_INTERVAL;
  502. }
  503. if (dwSleepTotal >= MAX_SLEEP_INST)
  504. {
  505. //
  506. // Timed out. If there is a real error in the metabase
  507. // use it, otherwise use a generic timeout error
  508. //
  509. hr = HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT);
  510. }
  511. error :
  512. if (_pAdminBase && hObjHandle) {
  513. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  514. }
  515. RRETURN (hr);
  516. }
  517. HRESULT
  518. CIISServer::IISSetCommand(
  519. METADATA_HANDLE hObjHandle,
  520. DWORD dwControl
  521. )
  522. {
  523. HRESULT hr = S_OK;
  524. DWORD dwBufferSize = sizeof(DWORD);
  525. METADATA_RECORD mdrMDData;
  526. LPBYTE pBuffer = (LPBYTE)&dwControl;
  527. MD_SET_DATA_RECORD(&mdrMDData,
  528. MD_SERVER_COMMAND, // server command
  529. METADATA_NO_ATTRIBUTES,
  530. IIS_MD_UT_SERVER,
  531. DWORD_METADATA,
  532. dwBufferSize,
  533. pBuffer);
  534. hr = _pAdminBase->SetData(
  535. hObjHandle,
  536. L"",
  537. &mdrMDData
  538. );
  539. BAIL_ON_FAILURE(hr);
  540. error:
  541. RRETURN(hr);
  542. }
  543. STDMETHODIMP
  544. CIISServer::ADSIInitializeDispatchManager(
  545. long dwExtensionId
  546. )
  547. {
  548. HRESULT hr = S_OK;
  549. if (_fDispInitialized) {
  550. RRETURN(E_FAIL);
  551. }
  552. hr = _pDispMgr->InitializeDispMgr(dwExtensionId);
  553. if (SUCCEEDED(hr)) {
  554. _fDispInitialized = TRUE;
  555. }
  556. RRETURN(hr);
  557. }
  558. STDMETHODIMP
  559. CIISServer::ADSIInitializeObject(
  560. THIS_ BSTR lpszUserName,
  561. BSTR lpszPassword,
  562. long lnReserved
  563. )
  564. {
  565. CCredentials NewCredentials(lpszUserName, lpszPassword, lnReserved);
  566. _Credentials = NewCredentials;
  567. RRETURN(S_OK);
  568. }
  569. STDMETHODIMP
  570. CIISServer::ADSIReleaseObject()
  571. {
  572. delete this;
  573. RRETURN(S_OK);
  574. }
  575. STDMETHODIMP
  576. CIISServer::NonDelegatingQueryInterface(
  577. REFIID iid,
  578. LPVOID FAR* ppv
  579. )
  580. {
  581. if (IsEqualIID(iid, IID_IADsServiceOperations)) {
  582. *ppv = (IADsUser FAR *) this;
  583. } else if (IsEqualIID(iid, IID_IADsExtension)) {
  584. *ppv = (IADsExtension FAR *) this;
  585. } else if (IsEqualIID(iid, IID_IUnknown)) {
  586. //
  587. // probably not needed since our 3rd party extension does not stand
  588. // alone and provider does not ask for this, but to be safe
  589. //
  590. *ppv = (INonDelegatingUnknown FAR *) this;
  591. } else {
  592. *ppv = NULL;
  593. return E_NOINTERFACE;
  594. }
  595. //
  596. // Delegating AddRef to aggregator for IADsExtesnion and IISServer.
  597. // AddRef on itself for IPrivateUnknown. (both tested.)
  598. //
  599. ((IUnknown *) (*ppv)) -> AddRef();
  600. return S_OK;
  601. }
  602. //
  603. // IADsExtension::Operate()
  604. //
  605. STDMETHODIMP
  606. CIISServer::Operate(
  607. THIS_ DWORD dwCode,
  608. VARIANT varUserName,
  609. VARIANT varPassword,
  610. VARIANT varFlags
  611. )
  612. {
  613. RRETURN(E_NOTIMPL);
  614. }