|
|
#ifndef _WORKERREQUEST_HXX_
#define _WORKERREQUEST_HXX_
#include "asynccontext.hxx"
#include <reftrace.h>
#include <acache.hxx>
//
// We are either reading a new request, or are processing the request
//
enum NREQ_STATE { NREQ_STATE_START = 0, NREQ_STATE_READ, NREQ_STATE_PROCESS, NREQ_STATE_ERROR, NREQ_STATE_CLIENT_CERT };
enum NREQ_STATUS { NSTATUS_NEXT = 0, NSTATUS_PENDING };
#define INLINE_REQUEST_BUFFER_LEN (sizeof(HTTP_REQUEST)+2048)
#ifdef _WIN64
#define INLINE_ALLOCATION_BUFFER_LEN (8192)
#else
#define INLINE_ALLOCATION_BUFFER_LEN (5120)
#endif
#define UL_NATIVE_REQUEST_CS_SPINS (200)
#define DESIRED_PENDING_REQUESTS (20)
#define DEFAULT_MAX_FREE_REQUESTS (250)
//
// When we're getting a client cert, the initialize buffer size we'll use
//
#define INITIAL_CERT_INFO_SIZE (1500)
//
// UL_NATIVE_REQUEST. Each object represents the context of handling a
// single HTTP_REQUEST
//
#define UL_NATIVE_REQUEST_SIGNATURE CREATE_SIGNATURE( 'NREQ')
#define UL_NATIVE_REQUEST_SIGNATURE_FREE CREATE_SIGNATURE( 'nreq')
class UL_NATIVE_REQUEST : public ASYNC_CONTEXT { public:
UL_NATIVE_REQUEST( VOID );
~UL_NATIVE_REQUEST( VOID );
VOID * operator new( size_t size ) { if ( size != sizeof( UL_NATIVE_REQUEST ) ) { DBG_ASSERT( size == sizeof( UL_NATIVE_REQUEST ) ); return NULL; } DBG_ASSERT( sm_pachNativeRequests != NULL ); return sm_pachNativeRequests->Alloc(); } VOID operator delete( VOID * pNativeRequest ) { DBG_ASSERT( pNativeRequest != NULL ); DBG_ASSERT( sm_pachNativeRequests != NULL ); DBG_REQUIRE( sm_pachNativeRequests->Free( pNativeRequest ) ); }
//
// The state machine advancer
//
VOID DoWork( DWORD cbData, DWORD dwError, LPOVERLAPPED lpo ); //
// Global list of worker requests
//
VOID RemoveFromRequestList( VOID );
VOID AddToRequestList( VOID );
//
// Reference counting
//
VOID ReferenceWorkerRequest( VOID ); VOID DereferenceWorkerRequest( VOID ); //
// Configure # of requests to serve
//
static VOID SetRestartCount( ULONG cRequests ) { sm_cRestart = cRequests; } HTTP_REQUEST * QueryHttpRequest( VOID ) const { return (HTTP_REQUEST *) _pbBuffer; }
VOID ResetContext( VOID );
VOID SetContext( PVOID pvContext ) { _pvContext = pvContext; }
HRESULT SendResponse( BOOL fAsync, DWORD dwFlags, HTTP_RESPONSE *pResponse, HTTP_CACHE_POLICY *pCachePolicy, DWORD *pcbSent, HTTP_LOG_FIELDS_DATA *pUlLogData );
HRESULT SendEntity( BOOL fAsync, DWORD dwFlags, USHORT cChunks, HTTP_DATA_CHUNK * pChunks, DWORD *pcbSent, HTTP_LOG_FIELDS_DATA *pUlLogData );
HRESULT ReceiveEntity( BOOL fAsync, DWORD dwFlags, VOID * pBuffer, DWORD cbBuffer, DWORD * pBytesReceived );
HRESULT ReceiveClientCertificate( BOOL fAsync, BOOL fDoCertMap, HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo );
BOOL CheckSignature( VOID ) const { return _dwSignature == UL_NATIVE_REQUEST_SIGNATURE; }
//
// Allocate some per-request memory
//
VOID * AllocateMemory( DWORD cbSize );
//
// Global UL_NATIVE_REQUEST methods
//
static HRESULT Initialize( VOID );
static VOID StopListening( VOID );
static VOID Terminate( VOID );
static HRESULT AddPendingRequests( DWORD cItems );
static HRESULT ReleaseAllWorkerRequests( VOID );
static HRESULT StartPendingRequestsMonitor( VOID );
static VOID StopPendingRequestsMonitor( VOID );
static VOID WINAPI PendingRequestsMonitorHandler( PVOID, BOOLEAN );
static DWORD QueryCurrentRequests( VOID ) { return sm_cRequests - sm_cRequestsPending; } static VOID FreeWorkerRequest( UL_NATIVE_REQUEST * pWorkerRequest ); static UL_NATIVE_REQUEST * AllocateWorkerRequest( VOID ); static VOID PushFreeList( UL_NATIVE_REQUEST * pWorkerRequest ) { #ifdef _WIN64
sm_FreeListLock.WriteLock(); PushEntryList( &sm_FreeList, &pWorkerRequest->_FreeListEntry ); sm_FreeListLock.WriteUnlock(); #else
RtlInterlockedPushEntrySList( &sm_FreeList, &pWorkerRequest->_FreeListEntry ); #endif
} static UL_NATIVE_REQUEST * PopFreeList( VOID ) { SINGLE_LIST_ENTRY * pListEntry; UL_NATIVE_REQUEST * pRequest = NULL; #ifdef _WIN64
sm_FreeListLock.WriteLock(); pListEntry = PopEntryList( &sm_FreeList ); sm_FreeListLock.WriteUnlock(); #else
pListEntry = RtlInterlockedPopEntrySList( &sm_FreeList ); #endif
if ( pListEntry != NULL ) { pRequest = CONTAINING_RECORD( pListEntry, UL_NATIVE_REQUEST, _FreeListEntry ); } return pRequest; } private:
HTTP_CONNECTION_ID QueryConnectionId( VOID ) const { return QueryHttpRequest()->ConnectionId; }
HTTP_REQUEST_ID QueryRequestId( VOID ) const { return QueryHttpRequest()->RequestId; }
//
// private helper for destructor and Reset()
//
VOID Cleanup( VOID ); //
// Reset the worker process to its pristine state
//
VOID Reset( VOID ); //
// State implementors
//
NREQ_STATUS DoStateStart( VOID );
NREQ_STATUS DoStateRead( VOID ); NREQ_STATUS DoStateProcess( VOID ); NREQ_STATUS DoStateClientCertificate( VOID );
//
// Determine if we need to send a "restart count reached" message to
// the admin process. Note that we want to send this once, thus the
// use of InterlockedExchange() on the static member. Note also that
// we first test the flag with non-interlocked access to avoid bus
// thrash.
//
static BOOL NeedToSendRestartMsg( VOID ) { if( sm_RestartMsgSent == 1 ) { return FALSE; }
return InterlockedExchange( &sm_RestartMsgSent, 1 ) == 0; }
DWORD _dwSignature; LONG _cRefs; SINGLE_LIST_ENTRY _FreeListEntry; NREQ_STATE _ExecState; LIST_ENTRY _ListEntry; PVOID _pvContext; DWORD _cbAsyncIOData; // Data transferred in the last Async IO
DWORD _dwAsyncIOError; // Error code from the last Async IO
UCHAR _achBuffer[ INLINE_REQUEST_BUFFER_LEN ]; UCHAR * _pbBuffer; DWORD _cbBuffer; BUFFER _buffClientCertInfo; DWORD _dwClientCertFlags; HTTP_SSL_CLIENT_CERT_INFO * _pClientCertInfo; BYTE _abAllocateMemory[ INLINE_ALLOCATION_BUFFER_LEN ]; DWORD _cbAllocateMemoryOffset;
//
// static members
//
static ULONG sm_cRequestsServed; static ULONG sm_cRestart; static LONG sm_RestartMsgSent; static LIST_ENTRY sm_RequestListHead; static CRITICAL_SECTION sm_csRequestList; static DWORD sm_cRequests; static PTRACE_LOG sm_pTraceLog;
#ifdef _WIN64
static SINGLE_LIST_ENTRY sm_FreeList; static CSpinLock sm_FreeListLock; #else
static SLIST_HEADER sm_FreeList; #endif
static DWORD sm_cFreeRequests; static DWORD sm_cMaxFreeRequests; static DWORD sm_cRequestsPending; static DWORD sm_cDesiredPendingRequests; static BOOL sm_fAddingRequests; static ALLOC_CACHE_HANDLER * sm_pachNativeRequests; // timer for the pending requests monitor
static HANDLE sm_hPendingRequestsTimer; };
#endif
|