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
202 lines
9.8 KiB
// --------------------------------------------------------------------------
|
|
// Module Name: APIDispatcher.h
|
|
//
|
|
// Copyright (c) 1999-2000, Microsoft Corporation
|
|
//
|
|
// A class that handles API requests in the server on a separate thread. Each
|
|
// thread is dedicated to respond to a single client. This is acceptable for
|
|
// a lightweight server.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
#ifndef _APIDispatcher_
|
|
#define _APIDispatcher_
|
|
|
|
#include "KernelResources.h"
|
|
#include "PortMessage.h"
|
|
#include "Queue.h"
|
|
#include "WorkItem.h"
|
|
|
|
// forward decls
|
|
class CAPIRequest;
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatchSync
|
|
//
|
|
// Purpose [scotthan]:
|
|
//
|
|
// This class encapsulates the events that coordinate service shutdown.
|
|
|
|
// Note: We could have simply synchronized on the respective thread handles,
|
|
// had we launched them ourselves. Our architecture is based on
|
|
// the worker thread pool, however, so we don't have access to thread handles.
|
|
// Hence, this class.
|
|
//
|
|
// In our initial entrypoint, ServiceMain, we:
|
|
// (1) Create the port and start polling it for requests.
|
|
// (2) Once the polling loop exits, we wait for any pending
|
|
// SERVICE_CONTROL_STOP/SHUTDOWN request to complete.
|
|
// (3) Destroy the CService object and the CAPIConnection object.
|
|
//
|
|
// When we get a SERVICE_CONTROL_STOP/SHUTDOWN request to our SCM entrypoint
|
|
// (CService::HandlerEx), we:
|
|
// (1) Set the service status to SERVICE_STOP_PENDING.
|
|
// (2) Signal to all blocking LPC request handler threads that the service
|
|
// is coming down. This should cause them to exit gracefully and
|
|
// come home.
|
|
// (3) Send an API_GENERIC_STOP LPC request down the port telling it to quit.
|
|
// (note: this request succeeds only if it originates from within the service process.).
|
|
// (4) Wait for this API_GENERIC_STOP LPC request to complete, which means the
|
|
// LPC port is shut down and cleaned up
|
|
// (5) Signal that the SERVICE_CONTROL_STOP/SHUTDOWN handler has finished up; it's
|
|
// save to exit ServiceMain
|
|
//
|
|
// In our API_GENERIC_STOP LPC request handler, we
|
|
// (1) Make our port deaf to new LPC requests.
|
|
// (note: this immediately releases the ServiceMain thread,
|
|
// which drops out of its port polling loop and must wait for completion of the
|
|
// SERVICE_CONTROL_STOP/SHUTDOWN request on HandlerEx() before exiting.)
|
|
// (2) Wait for the request queue to empty.
|
|
// (3) Destroy the request queue and the port itself.
|
|
// (4) Signal to the SERVICE_CONTROL_STOP/SHUTDOWN handler that we're done.
|
|
//
|
|
// The three objects that use this class are CService, CAPIConnection, and CAPIDispatcher.
|
|
// The CService instance owns the APIDispatcherSync class instance, and passes its address
|
|
// off to CAPIConnection, who in turn gives the pointer to each CAPIDispatcher it owns.
|
|
// The object expires with its owning CService instance.
|
|
//
|
|
// History: 2002-03-18 scotthan created.
|
|
// --------------------------------------------------------------------------
|
|
class CAPIDispatchSync
|
|
// --------------------------------------------------------------------------
|
|
{
|
|
public:
|
|
CAPIDispatchSync();
|
|
~CAPIDispatchSync();
|
|
|
|
// Signals commencement of service stop sequence.
|
|
static void SignalServiceStopping(CAPIDispatchSync* pds);
|
|
// Reports whether service is in stop sequence.
|
|
static BOOL IsServiceStopping(CAPIDispatchSync* pds);
|
|
// Retrieves the service stopping event.
|
|
static HANDLE GetServiceStoppingEvent(CAPIDispatchSync* pds);
|
|
|
|
// API request dispatch 'anti-semaphore', signals when no more requests
|
|
// are pending. Each time a request is queued, DispatchEnter() is
|
|
// called. Each time a request is unqueued, DispatchLeave() is called
|
|
static void DispatchEnter(CAPIDispatchSync*);
|
|
static void DispatchLeave(CAPIDispatchSync*);
|
|
|
|
// Invoked by the CAPIConnection API_GENERIC_STOP handler to wait for
|
|
// all outstanding LPC requests to come home and be dequeued.
|
|
static DWORD WaitForZeroDispatches(CAPIDispatchSync* pds, DWORD dwTimeout);
|
|
|
|
// The CAPIConnection API_GENERIC_STOP handler calls this to signal
|
|
// that the port has been shut down and cleaned up.
|
|
static void SignalPortShutdown(CAPIDispatchSync* pds);
|
|
|
|
// Invoked by CService::HandlerEx to await port cleanup.
|
|
static DWORD WaitForPortShutdown(CAPIDispatchSync* pds, DWORD dwTimeout);
|
|
|
|
// CService::HandlerEx calls this to signal ServiceMain that the
|
|
// SERVICE_CONTROL_STOP/SHUTDOWN sequence has completed, and its safe to exit.
|
|
static void SignalServiceControlStop(CAPIDispatchSync* pds);
|
|
|
|
// Invoked by ServiceMain (in CService::Start) to wait for completion of
|
|
// the stop control process is done.
|
|
static DWORD WaitForServiceControlStop(CAPIDispatchSync* pds, DWORD dwTimeout);
|
|
|
|
|
|
#define DISPATCHSYNC_TIMEOUT 60000
|
|
|
|
private:
|
|
|
|
void Lock();
|
|
void Unlock();
|
|
|
|
CRITICAL_SECTION _cs; // serializes signalling of events
|
|
LONG _cDispatches; // count of outstanding asynchronous API request dispatches.
|
|
|
|
|
|
// Since we're architected based entirely on nt worker threads,
|
|
// we have no thread handles to wait on. Instead, we rely on the sequential
|
|
// firing of the following events.
|
|
|
|
// In chronologoical order of firing:
|
|
HANDLE _hServiceStopping; // Signaled when service begins stop sequence.
|
|
HANDLE _hZeroDispatches; // This is fired when API request queue is empty.
|
|
// The API_GENERIC_STOP handler shuts down the port and
|
|
// then waits on this before proceeding with queue destruction.
|
|
HANDLE _hPortShutdown; // This is fired when the API_GENERIC_STOP handler is done
|
|
// cleaning up the request queue. The service's control SERVICE_CONTROL_STOP
|
|
// code path in HandlerEx waits on this before signalling
|
|
// _hServiceControlStop and returning to the SCM.
|
|
HANDLE _hServiceControlStop; // ServiceMain waits on this before completing shutdown by
|
|
// destroying the CService instance and exiting.
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CAPIDispatcher
|
|
//
|
|
// Purpose: This class processes requests from a client when signaled to.
|
|
// CAPIDispatcher::QueueRequest is called by a thread which
|
|
// monitors an LPC port. Once the request is queued an event is
|
|
// signaled to wake the thread which processes client requests.
|
|
// The thread processes all queued requests and wait for the
|
|
// event to be signaled again.
|
|
//
|
|
// History: 1999-11-07 vtan created
|
|
// 2000-08-25 vtan moved from Neptune to Whistler
|
|
// --------------------------------------------------------------------------
|
|
|
|
class CAPIDispatcher : public CWorkItem
|
|
{
|
|
private:
|
|
friend class CCatchCorruptor;
|
|
|
|
CAPIDispatcher (void);
|
|
public:
|
|
CAPIDispatcher (HANDLE hClientProcess);
|
|
virtual ~CAPIDispatcher (void);
|
|
|
|
HANDLE GetClientProcess (void) const;
|
|
DWORD GetClientSessionID (void) const;
|
|
void SetPort (HANDLE hPort);
|
|
HANDLE GetSection (void);
|
|
void* GetSectionAddress (void) const;
|
|
NTSTATUS CloseConnection (void);
|
|
NTSTATUS QueueRequest (const CPortMessage& portMessage, CAPIDispatchSync* pAPIDispatchSync);
|
|
NTSTATUS ExecuteRequest (const CPortMessage& portMessage);
|
|
NTSTATUS RejectRequest (const CPortMessage& portMessage, NTSTATUS status) const;
|
|
virtual NTSTATUS CreateAndQueueRequest (const CPortMessage& portMessage) = 0;
|
|
virtual NTSTATUS CreateAndExecuteRequest (const CPortMessage& portMessage) = 0;
|
|
protected:
|
|
virtual void Entry (void);
|
|
NTSTATUS Execute (CAPIRequest *pAPIRequest) const;
|
|
virtual NTSTATUS CreateSection (void);
|
|
|
|
NTSTATUS SignalRequestPending (void);
|
|
private:
|
|
NTSTATUS SendReply (const CPortMessage& portMessage) const;
|
|
#ifdef DEBUG
|
|
static bool ExcludedStatusCodeForDebug (NTSTATUS status);
|
|
#endif /* DEBUG */
|
|
static LONG WINAPI DispatcherExceptionFilter (struct _EXCEPTION_POINTERS *pExceptionInfo);
|
|
protected:
|
|
HANDLE _hSection;
|
|
void* _pSection;
|
|
CQueue _queue;
|
|
CAPIDispatchSync* _pAPIDispatchSync;
|
|
private:
|
|
HANDLE _hProcessClient;
|
|
HANDLE _hPort;
|
|
bool _fRequestsPending,
|
|
_fConnectionClosed;
|
|
CCriticalSection _lock;
|
|
};
|
|
|
|
#endif /* _APIDispatcher_ */
|
|
|