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.

768 lines
21 KiB

  1. /******************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. erswait.cpp
  5. Abstract:
  6. Implementation of DLL Exports.
  7. Revision History:
  8. derekm 02/28/2001 created
  9. ******************************************************************************/
  10. #include "stdafx.h"
  11. #include "stdio.h"
  12. #include "pfrcfg.h"
  13. //////////////////////////////////////////////////////////////////////////////
  14. // Globals
  15. SECURITY_DESCRIPTOR g_rgsd[ertiCount];
  16. SRequestEventType g_rgEvents[ertiCount];
  17. HANDLE g_hmutUser = NULL;
  18. HANDLE g_hmutKrnl = NULL;
  19. HANDLE g_hmutShut = NULL;
  20. //////////////////////////////////////////////////////////////////////////////
  21. // misc stuff
  22. // ***************************************************************************
  23. void InitializeSvcDataStructs(void)
  24. {
  25. ZeroMemory(g_rgsd, ertiCount * sizeof(SECURITY_DESCRIPTOR));
  26. ZeroMemory(g_rgEvents, ertiCount * sizeof(SRequestEventType));
  27. g_rgEvents[ertiHang].pfn = ProcessHangRequest;
  28. g_rgEvents[ertiHang].wszPipeName = c_wszHangPipe;
  29. g_rgEvents[ertiHang].wszRVPipeCount = c_wszRVNumHangPipe;
  30. g_rgEvents[ertiHang].cPipes = c_cMinPipes;
  31. g_rgEvents[ertiHang].fAllowNonLS = FALSE;
  32. g_rgEvents[ertiFault].pfn = ProcessFaultRequest;
  33. g_rgEvents[ertiFault].wszPipeName = c_wszFaultPipe;
  34. g_rgEvents[ertiFault].wszRVPipeCount = c_wszRVNumFaultPipe;
  35. g_rgEvents[ertiFault].cPipes = c_cMinPipes;
  36. g_rgEvents[ertiFault].fAllowNonLS = TRUE;
  37. }
  38. //////////////////////////////////////////////////////////////////////////////
  39. // pipe manager
  40. // ***************************************************************************
  41. BOOL ExecServer(SRequest *pReq)
  42. {
  43. OVERLAPPED ol;
  44. HANDLE rghWait[2] = { NULL, NULL };
  45. HANDLE hPipe = INVALID_HANDLE_VALUE;
  46. DWORD cbBuf, cb, dw;
  47. BOOL fRet, fShutdown = FALSE;
  48. BYTE Buf[ERRORREP_PIPE_BUF_SIZE];
  49. rghWait[0] = g_hevSvcStop;
  50. hPipe = pReq->hPipe;
  51. if (hPipe == INVALID_HANDLE_VALUE || rghWait[0] == NULL ||
  52. pReq->pret->pfn == NULL)
  53. {
  54. SetLastError(ERROR_INVALID_PARAMETER);
  55. goto done;
  56. }
  57. // need another event for waiting on the pipe read
  58. rghWait[1] = CreateEventW(NULL, TRUE, FALSE, NULL);
  59. if (rghWait[1] == NULL)
  60. goto done;
  61. // setup the overlapped structure
  62. ZeroMemory(&ol, sizeof(ol));
  63. ol.hEvent = rghWait[1];
  64. // read the request
  65. ResetEvent(ol.hEvent);
  66. fRet = ReadFile(hPipe, Buf, sizeof(Buf), &cb, &ol);
  67. if (fRet == FALSE && GetLastError() == ERROR_IO_PENDING)
  68. {
  69. // give the client 60s to write the data to us.
  70. // WAIT_OBJECT_0 is the shutdown event
  71. // WAIT_OBJECT_0 + 1 is the overlapped event
  72. dw = WaitForMultipleObjects(2, rghWait, FALSE, 60000);
  73. if (dw == WAIT_OBJECT_0)
  74. fShutdown = TRUE;
  75. else if (dw != WAIT_OBJECT_0 + 1)
  76. goto done;
  77. fRet = TRUE;
  78. }
  79. if (fRet)
  80. fRet = GetOverlappedResult(hPipe, &ol, &cbBuf, FALSE);
  81. // if we got an error, the client might still be waiting for a
  82. // reply, so construct a default one.
  83. // ProcessExecRequest() will always construct a reply and store it
  84. // in Buf, so no special handling is needed if it fails.
  85. if (fShutdown == FALSE && fRet)
  86. {
  87. cbBuf = sizeof(Buf);
  88. fRet = (*(pReq->pret->pfn))(hPipe, Buf, &cbBuf);
  89. }
  90. else
  91. {
  92. SPCHExecServGenericReply esrep;
  93. ZeroMemory(&esrep, sizeof(esrep));
  94. esrep.cb = sizeof(esrep);
  95. esrep.ess = essErr;
  96. esrep.dwErr = GetLastError();
  97. RtlCopyMemory(Buf, &esrep, sizeof(esrep));
  98. cbBuf = sizeof(esrep);
  99. }
  100. // write the reply to the message
  101. ResetEvent(ol.hEvent);
  102. fRet = WriteFile(hPipe, Buf, cbBuf, &cb, &ol);
  103. if (fRet == FALSE && GetLastError() == ERROR_IO_PENDING)
  104. {
  105. // give ourselves 60s to write the data to the pipe.
  106. // WAIT_OBJECT_0 is the shutdown event
  107. // WAIT_OBJECT_0 + 1 is the overlapped event
  108. dw = WaitForMultipleObjects(2, rghWait, FALSE, 60000);
  109. if (dw == WAIT_OBJECT_0)
  110. fShutdown = TRUE;
  111. else if (dw != WAIT_OBJECT_0 + 1)
  112. goto done;
  113. fRet = TRUE;
  114. }
  115. // wait for the client to read the buffer- note that we could use
  116. // FlushFileBuffers() to do this, but that is blocking with no
  117. // timeout, so we try to do a read on the pipe & wait to get an
  118. // error indicating that the client closed it.
  119. // Yup, this is a hack, but this is apparently the way to do this
  120. // when using async pipe communication. Sigh...
  121. if (fShutdown == FALSE && fRet)
  122. {
  123. ResetEvent(ol.hEvent);
  124. fRet = ReadFile(hPipe, Buf, sizeof(Buf), &cb, &ol);
  125. if (fRet == FALSE && GetLastError() == ERROR_IO_PENDING)
  126. {
  127. // give ourselves 60s to read the data from the pipe.
  128. // Except for the shutdown notification, don't really
  129. // care what this routine returns cuz we're just using
  130. // it to wait on the read to finish
  131. // WAIT_OBJECT_0 is the shutdown event
  132. // WAIT_OBJECT_0 + 1 is the overlapped event
  133. dw = WaitForMultipleObjects(2, rghWait, FALSE, 60000);
  134. if (dw == WAIT_OBJECT_0)
  135. fShutdown = TRUE;
  136. }
  137. }
  138. SetLastError(0);
  139. done:
  140. dw = GetLastError();
  141. if (hPipe != INVALID_HANDLE_VALUE)
  142. DisconnectNamedPipe(hPipe);
  143. if (rghWait[1] != NULL)
  144. CloseHandle(rghWait[1]);
  145. SetLastError(dw);
  146. return fShutdown;
  147. }
  148. // ***************************************************************************
  149. DWORD WINAPI threadExecServer(PVOID pvContext)
  150. {
  151. SRequest *pReq = (SRequest *)pvContext;
  152. if (pReq == NULL)
  153. return ERROR_INVALID_PARAMETER;
  154. // this acquires the request CS and holds it until the function exits
  155. CAutoUnlockCS aucs(&pReq->csReq, TRUE);
  156. // make sure we aren't shutting down
  157. if (WaitForSingleObject(g_hevSvcStop, 0) != WAIT_TIMEOUT)
  158. {
  159. SetLastError( ERROR_SUCCESS );
  160. goto done;
  161. }
  162. __try { ExecServer(pReq); }
  163. __except(SetLastError(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER) { }
  164. done:
  165. if (pReq->hModErsvc) FreeLibrary(pReq->hModErsvc);
  166. return GetLastError();
  167. }
  168. //////////////////////////////////////////////////////////////////////////////
  169. // object manager
  170. // ***************************************************************************
  171. void NukeRequestObj(SRequest *pReq, BOOL fFreeEvent)
  172. {
  173. if (pReq == NULL)
  174. return;
  175. // this acquires the request CS and holds it until the function exits
  176. CAutoUnlockCS aucs(&pReq->csReq, TRUE);
  177. // free the pipe
  178. if (pReq->hPipe != INVALID_HANDLE_VALUE)
  179. {
  180. DisconnectNamedPipe(pReq->hPipe);
  181. CloseHandle(pReq->hPipe);
  182. pReq->hPipe = INVALID_HANDLE_VALUE;
  183. }
  184. if (fFreeEvent && pReq->ol.hEvent != NULL)
  185. {
  186. CloseHandle(pReq->ol.hEvent);
  187. ZeroMemory(&pReq->ol, sizeof(pReq->ol));
  188. }
  189. if (pReq->hth != NULL)
  190. {
  191. CloseHandle(pReq->hth);
  192. pReq->hth = NULL;
  193. }
  194. pReq->ers = ersEmpty;
  195. }
  196. // ***************************************************************************
  197. BOOL BuildRequestObj(SRequest *pReq, SRequestEventType *pret)
  198. {
  199. SECURITY_ATTRIBUTES sa;
  200. HANDLE hev = NULL;
  201. HANDLE hPipe = INVALID_HANDLE_VALUE;
  202. BOOL fRet = FALSE;
  203. if (pReq == NULL || pret == NULL)
  204. {
  205. SetLastError(ERROR_INVALID_PARAMETER);
  206. goto done;
  207. }
  208. // if this is empty, then we're building a fresh object, so create an
  209. // event for waiting on the pipe listen
  210. if (pReq->ol.hEvent == NULL)
  211. {
  212. // need an
  213. hev = CreateEventW(NULL, FALSE, FALSE, NULL);
  214. if (hev == NULL)
  215. goto done;
  216. }
  217. // otherwise, store away the existing event
  218. else
  219. {
  220. hev = pReq->ol.hEvent;
  221. ResetEvent(hev);
  222. }
  223. // don't want to nuke the critical section!
  224. ZeroMemory(((PBYTE)pReq + sizeof(pReq->csReq)),
  225. sizeof(SRequest) - sizeof(pReq->csReq));
  226. sa.nLength = sizeof(sa);
  227. sa.bInheritHandle = FALSE;
  228. sa.lpSecurityDescriptor = pret->psd;
  229. // obviously gotta have a pipe
  230. hPipe = CreateNamedPipeW(pret->wszPipeName,
  231. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  232. PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
  233. c_cMaxPipes, ERRORREP_PIPE_BUF_SIZE,
  234. ERRORREP_PIPE_BUF_SIZE, 0, &sa);
  235. if (hPipe == INVALID_HANDLE_VALUE)
  236. goto done;
  237. // make sure we aren't shutting down
  238. if (WaitForSingleObject(g_hevSvcStop, 0) != WAIT_TIMEOUT)
  239. goto done;
  240. pReq->ol.hEvent = hev;
  241. // start waiting on the pipe
  242. fRet = ConnectNamedPipe(hPipe, &pReq->ol);
  243. if (fRet == FALSE && GetLastError() != ERROR_IO_PENDING)
  244. {
  245. // if the pipe is already connected, just set the event cuz
  246. // ConnectNamedPipe doesn't
  247. if (GetLastError() == ERROR_PIPE_CONNECTED)
  248. {
  249. SetEvent(pReq->ol.hEvent);
  250. }
  251. else
  252. {
  253. pReq->ol.hEvent = NULL;
  254. goto done;
  255. }
  256. }
  257. // yay! save off everything.
  258. pReq->ers = ersWaiting;
  259. pReq->pret = pret;
  260. pReq->hPipe = hPipe;
  261. hev = NULL;
  262. hPipe = INVALID_HANDLE_VALUE;
  263. fRet = TRUE;
  264. done:
  265. if (hev != NULL)
  266. CloseHandle(hev);
  267. if (hPipe != INVALID_HANDLE_VALUE)
  268. {
  269. DisconnectNamedPipe(hPipe);
  270. CloseHandle(hPipe);
  271. }
  272. return fRet;
  273. }
  274. // ***************************************************************************
  275. BOOL ResetRequestObj(SRequest *pReq)
  276. {
  277. BOOL fRet = FALSE;
  278. if (pReq == NULL || pReq->ers != ersProcessing)
  279. {
  280. SetLastError(ERROR_INVALID_PARAMETER);
  281. goto done;
  282. }
  283. // clean up the thread handle.
  284. if (pReq->hth != NULL)
  285. {
  286. CloseHandle(pReq->hth);
  287. pReq->hth = NULL;
  288. }
  289. // check and make sure that our object is valid. If it ain't, nuke it
  290. // and rebuild it.
  291. if (pReq->hPipe != NULL && pReq->ol.hEvent != NULL &&
  292. pReq->pret != NULL)
  293. {
  294. // start waiting on the pipe
  295. fRet = ConnectNamedPipe(pReq->hPipe, &pReq->ol);
  296. if (fRet == FALSE)
  297. {
  298. switch(GetLastError())
  299. {
  300. case ERROR_IO_PENDING:
  301. fRet = TRUE;
  302. break;
  303. case ERROR_PIPE_CONNECTED:
  304. SetEvent(pReq->ol.hEvent);
  305. fRet = TRUE;
  306. break;
  307. default:
  308. break;
  309. }
  310. }
  311. }
  312. if (fRet == FALSE)
  313. {
  314. NukeRequestObj(pReq, FALSE);
  315. fRet = BuildRequestObj(pReq, pReq->pret);
  316. if (fRet == FALSE)
  317. goto done;
  318. }
  319. else
  320. {
  321. pReq->ers = ersWaiting;
  322. }
  323. done:
  324. return fRet;
  325. }
  326. // ***************************************************************************
  327. BOOL ProcessRequestObj(SRequest *pReq)
  328. {
  329. HANDLE hth = NULL;
  330. // should do a LoadLibrary on ersvc.dll before entering the thread.
  331. // Then, at the end of the thread, do a FreeLibraryAndExitThread() call.
  332. // This eliminates a very very small chance of a race condition (leading to an AV)
  333. // when shutting the service down.
  334. if (!pReq)
  335. {
  336. return FALSE;
  337. }
  338. pReq->hModErsvc = LoadLibraryExW(L"ersvc.dll", NULL, 0);
  339. if (pReq->hModErsvc == NULL)
  340. {
  341. return FALSE;
  342. }
  343. hth = CreateThread(NULL, 0, threadExecServer, pReq, 0, NULL);
  344. if (hth == NULL)
  345. {
  346. FreeLibrary(pReq->hModErsvc);
  347. return FALSE;
  348. }
  349. pReq->ers = ersProcessing;
  350. pReq->hth = hth;
  351. hth = NULL;
  352. return TRUE;
  353. }
  354. // ***************************************************************************
  355. BOOL ProcessRequests(SRequest *rgReqs, DWORD cReqs)
  356. {
  357. HANDLE *rghWait = NULL;
  358. DWORD iReq, cErrs = 0, dw;
  359. BOOL fRet = FALSE;
  360. if (rgReqs == NULL || cReqs == NULL || cReqs > MAXIMUM_WAIT_OBJECTS)
  361. {
  362. SetLastError(ERROR_INVALID_PARAMETER);
  363. goto done;
  364. }
  365. rghWait = (HANDLE *)MyAlloc((cReqs + 1) * sizeof(HANDLE));
  366. if (rghWait == NULL)
  367. {
  368. SetLastError(ERROR_OUTOFMEMORY);
  369. goto done;
  370. }
  371. // initially, populate all the entries in the wait array with the handles
  372. // to the overlapped events
  373. rghWait[0] = g_hevSvcStop;
  374. for(iReq = 0; iReq < cReqs; iReq++)
  375. {
  376. if (rgReqs[iReq].ol.hEvent != NULL)
  377. rghWait[iReq + 1] = rgReqs[iReq].ol.hEvent;
  378. else
  379. goto done;
  380. }
  381. for(;;)
  382. {
  383. dw = WaitForMultipleObjects(cReqs + 1, rghWait, FALSE, INFINITE);
  384. // if it's the first wait handle, then we're shutting down, so just return
  385. // TRUE
  386. if (dw == WAIT_OBJECT_0)
  387. {
  388. fRet = TRUE;
  389. goto done;
  390. }
  391. // yippy! It's one of the pipes.
  392. else if (dw >= WAIT_OBJECT_0 + 1 && dw <= WAIT_OBJECT_0 + cReqs)
  393. {
  394. SRequest *pReq;
  395. cErrs = 0;
  396. iReq = (dw - WAIT_OBJECT_0) - 1;
  397. pReq = &rgReqs[iReq];
  398. // check first to make sure we aren't shutting down. If we are, just
  399. // bail
  400. if (WaitForSingleObject(g_hevSvcStop, 0) != WAIT_TIMEOUT)
  401. {
  402. fRet = TRUE;
  403. goto done;
  404. }
  405. if (pReq->ers == ersWaiting)
  406. {
  407. fRet = ProcessRequestObj(pReq);
  408. // if we succeeded, then wait for the thread to complete instead
  409. // of the named pipe connect event
  410. if (fRet)
  411. {
  412. rghWait[iReq + 1] = pReq->hth;
  413. continue;
  414. }
  415. else
  416. {
  417. // set this so that we fall thru to the next case & get
  418. // everything cleaned up...
  419. pReq->ers = ersProcessing;
  420. }
  421. }
  422. if (pReq->ers == ersProcessing)
  423. {
  424. fRet = ResetRequestObj(pReq);
  425. if (fRet == FALSE)
  426. {
  427. if (iReq < cReqs - 1)
  428. {
  429. SRequest oReq;
  430. HANDLE hWait;
  431. CopyMemory(&oReq, pReq, sizeof(oReq));
  432. MoveMemory(&rgReqs[iReq], &rgReqs[iReq + 1],
  433. (cReqs - iReq - 1) * sizeof(SRequest));
  434. CopyMemory(&rgReqs[cReqs - 1], &oReq, sizeof(oReq));
  435. // rearrange the rghWait array as well. Otherwise it's out of sync with the object array
  436. hWait = rghWait[iReq + 1];
  437. MoveMemory(&rghWait[iReq + 1], &rghWait[iReq + 2],
  438. (cReqs - iReq - 1));
  439. rghWait[cReqs] = hWait;
  440. }
  441. cReqs--;
  442. }
  443. // ok, time to start waiting on the event to signal that a pipe
  444. // has been connected to...
  445. else
  446. {
  447. rghWait[iReq + 1] = pReq->ol.hEvent;
  448. }
  449. }
  450. }
  451. // um, this is bad.
  452. else
  453. {
  454. if (cErrs > 8)
  455. {
  456. ASSERT(FALSE);
  457. break;
  458. }
  459. cErrs++;
  460. }
  461. }
  462. done:
  463. if (rghWait != NULL)
  464. MyFree(rghWait);
  465. return fRet;
  466. }
  467. //////////////////////////////////////////////////////////////////////////////
  468. // startup & shutdown
  469. // ***************************************************************************
  470. BOOL StartERSvc(SERVICE_STATUS_HANDLE hss, SERVICE_STATUS &ss,
  471. SRequest **prgReqs, DWORD *pcReqs)
  472. {
  473. SECURITY_DESCRIPTOR sd;
  474. SECURITY_ATTRIBUTES sa;
  475. SRequest *rgReqs = NULL;
  476. HANDLE hth, hmut = NULL;
  477. DWORD dw, i, iPipe, dwType, cb, cReqs, iReqs;
  478. BOOL fRet = FALSE;
  479. HKEY hkey = NULL;
  480. ZeroMemory(&sa, sizeof(sa));
  481. if (hss == NULL || prgReqs == NULL || pcReqs == NULL)
  482. {
  483. SetLastError(ERROR_INVALID_PARAMETER);
  484. goto done;
  485. }
  486. *prgReqs = NULL;
  487. *pcReqs = NULL;
  488. if (AllocSD(&sd, ACCESS_ALL, ACCESS_ALL, 0) == FALSE)
  489. goto done;
  490. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  491. sa.lpSecurityDescriptor = &sd;
  492. sa.bInheritHandle = FALSE;
  493. // these two mutexes will intentionally not be free'd even if we stop the
  494. // exec server threads... These need to exist for kernel fault reporting
  495. // to work. Don't want to completely bail if we fail since we could just
  496. // have restarted the server & we don't actually need these for the
  497. // service to work.
  498. hmut = CreateMutexW(&sa, FALSE, c_wszMutKrnlName);
  499. if (hmut != NULL)
  500. {
  501. if (GetLastError() != ERROR_ALREADY_EXISTS)
  502. g_hmutKrnl = hmut;
  503. else
  504. CloseHandle(hmut);
  505. hmut = NULL;
  506. }
  507. hmut = CreateMutexW(&sa, FALSE, c_wszMutUserName);
  508. if (hmut != NULL)
  509. {
  510. if (GetLastError() != ERROR_ALREADY_EXISTS)
  511. g_hmutKrnl = hmut;
  512. else
  513. CloseHandle(hmut);
  514. hmut = NULL;
  515. }
  516. hmut = CreateMutexW(&sa, FALSE, c_wszMutShutName);
  517. if (hmut != NULL)
  518. {
  519. if (GetLastError() != ERROR_ALREADY_EXISTS)
  520. g_hmutShut = hmut;
  521. else
  522. CloseHandle(hmut);
  523. hmut = NULL;
  524. }
  525. dw = RegOpenKeyExW(HKEY_LOCAL_MACHINE, c_wszRPCfg, 0, KEY_READ, &hkey);
  526. if (dw != ERROR_SUCCESS)
  527. hkey = NULL;
  528. // find out how many pipes we're gonna create
  529. cReqs = 0;
  530. for(i = 0; i < ertiCount; i++)
  531. {
  532. if (hkey != NULL)
  533. {
  534. cb = sizeof(g_rgEvents[i].cPipes);
  535. dw = RegQueryValueExW(hkey, g_rgEvents[i].wszRVPipeCount, 0,
  536. &dwType, (LPBYTE)&g_rgEvents[i].cPipes, &cb);
  537. if (dwType != REG_DWORD || g_rgEvents[i].cPipes < c_cMinPipes)
  538. g_rgEvents[i].cPipes = c_cMinPipes;
  539. else if (g_rgEvents[i].cPipes > c_cMaxPipes)
  540. g_rgEvents[i].cPipes = c_cMaxPipes;
  541. }
  542. cReqs += g_rgEvents[i].cPipes;
  543. ss.dwCheckPoint++;
  544. SetServiceStatus(hss, &ss);
  545. }
  546. if (cReqs >= MAXIMUM_WAIT_OBJECTS)
  547. {
  548. SetLastError(ERROR_INVALID_PARAMETER);
  549. goto done;
  550. }
  551. // allocate the array that will hold the request info
  552. rgReqs = (SRequest *)MyAlloc(cReqs * sizeof(SRequest));
  553. if (rgReqs == NULL)
  554. {
  555. SetLastError(ERROR_OUTOFMEMORY);
  556. goto done;
  557. }
  558. // build our array of request objects
  559. fRet = TRUE;
  560. iReqs = 0;
  561. for (i = 0; i < ertiCount; i++)
  562. {
  563. dw = (g_rgEvents[i].fAllowNonLS) ? ACCESS_RW : 0;
  564. fRet = AllocSD(&g_rgsd[i], ACCESS_ALL, dw, dw);
  565. if (fRet == FALSE)
  566. break;
  567. g_rgEvents[i].psd = &g_rgsd[i];
  568. // allocate request objects
  569. for (iPipe = 0; iPipe < g_rgEvents[i].cPipes; iPipe++)
  570. {
  571. rgReqs[iReqs].hPipe = INVALID_HANDLE_VALUE;
  572. InitializeCriticalSection(&rgReqs[iReqs].csReq);
  573. fRet = BuildRequestObj(&rgReqs[iReqs], &g_rgEvents[i]);
  574. if (fRet == FALSE)
  575. break;
  576. iReqs++;
  577. }
  578. if (fRet == FALSE)
  579. break;
  580. // need to update service status
  581. ss.dwCheckPoint++;
  582. SetServiceStatus(hss, &ss);
  583. }
  584. if (fRet == FALSE)
  585. {
  586. ss.dwCheckPoint++;
  587. ss.dwCurrentState = SERVICE_STOP_PENDING;
  588. SetServiceStatus(hss, &ss);
  589. StopERSvc(hss, ss, rgReqs, cReqs);
  590. }
  591. else
  592. {
  593. *prgReqs = rgReqs;
  594. *pcReqs = cReqs;
  595. rgReqs = NULL;
  596. cReqs = 0;
  597. }
  598. done:
  599. if (sa.lpSecurityDescriptor != NULL)
  600. FreeSD((SECURITY_DESCRIPTOR *)sa.lpSecurityDescriptor);
  601. if (rgReqs != NULL)
  602. MyFree(rgReqs);
  603. if (hkey != NULL)
  604. RegCloseKey(hkey);
  605. return fRet;
  606. }
  607. // ***************************************************************************
  608. BOOL StopERSvc(SERVICE_STATUS_HANDLE hss, SERVICE_STATUS &ss,
  609. SRequest *rgReqs, DWORD cReqs)
  610. {
  611. DWORD i;
  612. if (hss == NULL || rgReqs == NULL || cReqs == 0)
  613. {
  614. SetLastError(ERROR_INVALID_PARAMETER);
  615. return FALSE;
  616. }
  617. if (g_hevSvcStop == NULL)
  618. goto done;
  619. SetEvent(g_hevSvcStop);
  620. // update service status
  621. ss.dwCheckPoint++;
  622. SetServiceStatus(hss, &ss);
  623. for (i = 0; i < cReqs; i++)
  624. {
  625. NukeRequestObj(&rgReqs[i], TRUE);
  626. DeleteCriticalSection(&rgReqs[i].csReq);
  627. }
  628. for (i = 0; i < ertiCount; i++)
  629. {
  630. if (g_rgEvents[i].psd != NULL)
  631. FreeSD(g_rgEvents[i].psd);
  632. }
  633. // update service status
  634. ss.dwCheckPoint++;
  635. SetServiceStatus(hss, &ss);
  636. done:
  637. return TRUE;
  638. }