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.
 
 
 
 
 
 

469 lines
9.5 KiB

#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