Leaked source code of windows server 2003
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.

202 lines
9.8 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: APIDispatcher.h
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // A class that handles API requests in the server on a separate thread. Each
  7. // thread is dedicated to respond to a single client. This is acceptable for
  8. // a lightweight server.
  9. //
  10. // History: 1999-11-07 vtan created
  11. // 2000-08-25 vtan moved from Neptune to Whistler
  12. // --------------------------------------------------------------------------
  13. #ifndef _APIDispatcher_
  14. #define _APIDispatcher_
  15. #include "KernelResources.h"
  16. #include "PortMessage.h"
  17. #include "Queue.h"
  18. #include "WorkItem.h"
  19. // forward decls
  20. class CAPIRequest;
  21. // --------------------------------------------------------------------------
  22. // CAPIDispatchSync
  23. //
  24. // Purpose [scotthan]:
  25. //
  26. // This class encapsulates the events that coordinate service shutdown.
  27. // Note: We could have simply synchronized on the respective thread handles,
  28. // had we launched them ourselves. Our architecture is based on
  29. // the worker thread pool, however, so we don't have access to thread handles.
  30. // Hence, this class.
  31. //
  32. // In our initial entrypoint, ServiceMain, we:
  33. // (1) Create the port and start polling it for requests.
  34. // (2) Once the polling loop exits, we wait for any pending
  35. // SERVICE_CONTROL_STOP/SHUTDOWN request to complete.
  36. // (3) Destroy the CService object and the CAPIConnection object.
  37. //
  38. // When we get a SERVICE_CONTROL_STOP/SHUTDOWN request to our SCM entrypoint
  39. // (CService::HandlerEx), we:
  40. // (1) Set the service status to SERVICE_STOP_PENDING.
  41. // (2) Signal to all blocking LPC request handler threads that the service
  42. // is coming down. This should cause them to exit gracefully and
  43. // come home.
  44. // (3) Send an API_GENERIC_STOP LPC request down the port telling it to quit.
  45. // (note: this request succeeds only if it originates from within the service process.).
  46. // (4) Wait for this API_GENERIC_STOP LPC request to complete, which means the
  47. // LPC port is shut down and cleaned up
  48. // (5) Signal that the SERVICE_CONTROL_STOP/SHUTDOWN handler has finished up; it's
  49. // save to exit ServiceMain
  50. //
  51. // In our API_GENERIC_STOP LPC request handler, we
  52. // (1) Make our port deaf to new LPC requests.
  53. // (note: this immediately releases the ServiceMain thread,
  54. // which drops out of its port polling loop and must wait for completion of the
  55. // SERVICE_CONTROL_STOP/SHUTDOWN request on HandlerEx() before exiting.)
  56. // (2) Wait for the request queue to empty.
  57. // (3) Destroy the request queue and the port itself.
  58. // (4) Signal to the SERVICE_CONTROL_STOP/SHUTDOWN handler that we're done.
  59. //
  60. // The three objects that use this class are CService, CAPIConnection, and CAPIDispatcher.
  61. // The CService instance owns the APIDispatcherSync class instance, and passes its address
  62. // off to CAPIConnection, who in turn gives the pointer to each CAPIDispatcher it owns.
  63. // The object expires with its owning CService instance.
  64. //
  65. // History: 2002-03-18 scotthan created.
  66. // --------------------------------------------------------------------------
  67. class CAPIDispatchSync
  68. // --------------------------------------------------------------------------
  69. {
  70. public:
  71. CAPIDispatchSync();
  72. ~CAPIDispatchSync();
  73. // Signals commencement of service stop sequence.
  74. static void SignalServiceStopping(CAPIDispatchSync* pds);
  75. // Reports whether service is in stop sequence.
  76. static BOOL IsServiceStopping(CAPIDispatchSync* pds);
  77. // Retrieves the service stopping event.
  78. static HANDLE GetServiceStoppingEvent(CAPIDispatchSync* pds);
  79. // API request dispatch 'anti-semaphore', signals when no more requests
  80. // are pending. Each time a request is queued, DispatchEnter() is
  81. // called. Each time a request is unqueued, DispatchLeave() is called
  82. static void DispatchEnter(CAPIDispatchSync*);
  83. static void DispatchLeave(CAPIDispatchSync*);
  84. // Invoked by the CAPIConnection API_GENERIC_STOP handler to wait for
  85. // all outstanding LPC requests to come home and be dequeued.
  86. static DWORD WaitForZeroDispatches(CAPIDispatchSync* pds, DWORD dwTimeout);
  87. // The CAPIConnection API_GENERIC_STOP handler calls this to signal
  88. // that the port has been shut down and cleaned up.
  89. static void SignalPortShutdown(CAPIDispatchSync* pds);
  90. // Invoked by CService::HandlerEx to await port cleanup.
  91. static DWORD WaitForPortShutdown(CAPIDispatchSync* pds, DWORD dwTimeout);
  92. // CService::HandlerEx calls this to signal ServiceMain that the
  93. // SERVICE_CONTROL_STOP/SHUTDOWN sequence has completed, and its safe to exit.
  94. static void SignalServiceControlStop(CAPIDispatchSync* pds);
  95. // Invoked by ServiceMain (in CService::Start) to wait for completion of
  96. // the stop control process is done.
  97. static DWORD WaitForServiceControlStop(CAPIDispatchSync* pds, DWORD dwTimeout);
  98. #define DISPATCHSYNC_TIMEOUT 60000
  99. private:
  100. void Lock();
  101. void Unlock();
  102. CRITICAL_SECTION _cs; // serializes signalling of events
  103. LONG _cDispatches; // count of outstanding asynchronous API request dispatches.
  104. // Since we're architected based entirely on nt worker threads,
  105. // we have no thread handles to wait on. Instead, we rely on the sequential
  106. // firing of the following events.
  107. // In chronologoical order of firing:
  108. HANDLE _hServiceStopping; // Signaled when service begins stop sequence.
  109. HANDLE _hZeroDispatches; // This is fired when API request queue is empty.
  110. // The API_GENERIC_STOP handler shuts down the port and
  111. // then waits on this before proceeding with queue destruction.
  112. HANDLE _hPortShutdown; // This is fired when the API_GENERIC_STOP handler is done
  113. // cleaning up the request queue. The service's control SERVICE_CONTROL_STOP
  114. // code path in HandlerEx waits on this before signalling
  115. // _hServiceControlStop and returning to the SCM.
  116. HANDLE _hServiceControlStop; // ServiceMain waits on this before completing shutdown by
  117. // destroying the CService instance and exiting.
  118. };
  119. // --------------------------------------------------------------------------
  120. // CAPIDispatcher
  121. //
  122. // Purpose: This class processes requests from a client when signaled to.
  123. // CAPIDispatcher::QueueRequest is called by a thread which
  124. // monitors an LPC port. Once the request is queued an event is
  125. // signaled to wake the thread which processes client requests.
  126. // The thread processes all queued requests and wait for the
  127. // event to be signaled again.
  128. //
  129. // History: 1999-11-07 vtan created
  130. // 2000-08-25 vtan moved from Neptune to Whistler
  131. // --------------------------------------------------------------------------
  132. class CAPIDispatcher : public CWorkItem
  133. {
  134. private:
  135. friend class CCatchCorruptor;
  136. CAPIDispatcher (void);
  137. public:
  138. CAPIDispatcher (HANDLE hClientProcess);
  139. virtual ~CAPIDispatcher (void);
  140. HANDLE GetClientProcess (void) const;
  141. DWORD GetClientSessionID (void) const;
  142. void SetPort (HANDLE hPort);
  143. HANDLE GetSection (void);
  144. void* GetSectionAddress (void) const;
  145. NTSTATUS CloseConnection (void);
  146. NTSTATUS QueueRequest (const CPortMessage& portMessage, CAPIDispatchSync* pAPIDispatchSync);
  147. NTSTATUS ExecuteRequest (const CPortMessage& portMessage);
  148. NTSTATUS RejectRequest (const CPortMessage& portMessage, NTSTATUS status) const;
  149. virtual NTSTATUS CreateAndQueueRequest (const CPortMessage& portMessage) = 0;
  150. virtual NTSTATUS CreateAndExecuteRequest (const CPortMessage& portMessage) = 0;
  151. protected:
  152. virtual void Entry (void);
  153. NTSTATUS Execute (CAPIRequest *pAPIRequest) const;
  154. virtual NTSTATUS CreateSection (void);
  155. NTSTATUS SignalRequestPending (void);
  156. private:
  157. NTSTATUS SendReply (const CPortMessage& portMessage) const;
  158. #ifdef DEBUG
  159. static bool ExcludedStatusCodeForDebug (NTSTATUS status);
  160. #endif /* DEBUG */
  161. static LONG WINAPI DispatcherExceptionFilter (struct _EXCEPTION_POINTERS *pExceptionInfo);
  162. protected:
  163. HANDLE _hSection;
  164. void* _pSection;
  165. CQueue _queue;
  166. CAPIDispatchSync* _pAPIDispatchSync;
  167. private:
  168. HANDLE _hProcessClient;
  169. HANDLE _hPort;
  170. bool _fRequestsPending,
  171. _fConnectionClosed;
  172. CCriticalSection _lock;
  173. };
  174. #endif /* _APIDispatcher_ */