WindowsXP-SP1/inetsrv/iis/svcs/infocomm/atq/atqtypes.hxx
2020-09-30 16:53:49 +02:00

904 lines
24 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name :
atqtypes.hxx
Abstract:
Declares constants, types and functions for bandwidth throttling.
Author:
Murali R. Krishnan ( MuraliK ) 1-June-1995
Environment:
User Mode -- Win32
Project:
Internet Services Common DLL
Revision History:
--*/
#ifndef _ATQTYPES_H_
#define _ATQTYPES_H_
/************************************************************
* Include Headers
************************************************************/
# include <atq.h>
# include <uspud.h>
# include <wmistr.h>
# include <evntrace.h>
# include <iscaptrc.h>
# include "atqbmon.hxx"
/************************************************************
* Constants and Macros
************************************************************/
#if DBG && !defined(_WIN64)
#define CC_REF_TRACKING 1
#else
#define CC_REF_TRACKING 0
#endif
# define ATQ_ASSERT DBG_ASSERT
# define ATQ_PRINTF DBGPRINTF
# define ATQ_REQUIRE DBG_REQUIRE
//
// Indicate infinite timeout
//
#define ATQ_INFINITE 0x80000000
//
// number of ATQ context to cache
//
#define ATQ_CACHE_LIMIT_NTS INFINITE
#define ATQ_CACHE_LIMIT_NTW INFINITE // 16
#define ATQ_CACHE_LIMIT_W95 2 // 2
//
// Number of list of active context
//
#define ATQ_NUM_CONTEXT_LIST 4
#define ATQ_NUM_CONTEXT_LIST_W95 1
//
// Max number of threads
//
#define ATQ_MAX_THREAD_LIMIT_W95 2
//
// Indicates the initial thread
//
#define ATQ_INITIAL_THREAD ((ULONG_PTR)0xabcdef01)
#define ATQ_DEBUG_THREAD ((ULONG_PTR)0xfaceface)
//
// The interval (in seconds) the timeout thread sleeps between checking
// for timed out async requests
//
#define ATQ_TIMEOUT_INTERVAL (30)
//
// The time interval between samples for estimating bandwidth and
// using our feedback to tune the Bandwidth throttle entry point.
// We will use a histogram to sample and store the bytes sent over a minute
// and perform histogram averaging for the last 1 minute.
//
# define ATQ_SAMPLE_INTERVAL_IN_SECS (10) // time in seconds
# define NUM_SAMPLES_PER_TIMEOUT_INTERVAL \
(ATQ_TIMEOUT_INTERVAL/ ATQ_SAMPLE_INTERVAL_IN_SECS)
// Calculate timeout in milliseconds from timeout in seconds.
# define TimeToWait(Timeout) (((Timeout) == INFINITE) ?INFINITE: \
(Timeout) * 1000)
// Normalized to find the number of entries required for a minute of samples
# define ATQ_AVERAGING_PERIOD ( 60) // 1 minute = 60 secs
# define ATQ_HISTOGRAM_SIZE \
(ATQ_AVERAGING_PERIOD / (ATQ_SAMPLE_INTERVAL_IN_SECS))
//
// Rounds the bandwidth throttle to nearest 1K block
//
#define ATQ_ROUNDUP_BANDWIDTH( bw ) ( (((bw) + 512)/1024) * 1024)
//# define INC_ATQ_COUNTER( dwCtr) InterlockedIncrement((LPLONG ) &dwCtr)
#define INC_ATQ_COUNTER( dwCtr) (++dwCtr)
//# define DEC_ATQ_COUNTER( dwCtr) InterlockedDecrement((LPLONG ) &dwCtr)
#define DEC_ATQ_COUNTER( dwCtr) (--dwCtr)
//
// Minimum number of increments for acceptex context allocations
//
#define ATQ_MIN_CTX_INC (5)
//
// Returns TRUE if the Atq context is the context containing *the* single
// socket, or FALSE if the context contains a regular client socket
//
// pfnConnComp is NULL if the IO handle was added using AtqAddAsyncHandle
// pEndpoint is NULL if this context was added using AtqAddAsyncHandle or
// this is *the* listen socket
//
#define IS_ACCEPT_EX_CONTEXT( pContext ) \
((pContext)->pfnConnComp && !(pContext)->pEndpoint )
//
//
// Time to wait for the Timeout thread to die
//
#define ATQ_WAIT_FOR_THREAD_DEATH (10 * 1000) // in milliseconds
# define ATQ_WAIT_FOR_TIMEOUT_PROCESSING (10) // milliseconds
//
// This is the number of bytes to reserver for the AcceptEx address
// information structure
//
#define MIN_SOCKADDR_SIZE (sizeof(struct sockaddr_in) + 16)
//
// Ref count trace log size (used for debugging ref count problems).
//
#define TRACE_LOG_SIZE 256
//
// Macros
//
#define AcquireLock( _l ) EnterCriticalSection( _l )
#define ReleaseLock( _l ) LeaveCriticalSection( _l )
#define I_SetNextTimeout( _c ) { \
(_c)->NextTimeout = AtqGetCurrentTick() + (_c)->TimeOut; \
if ( (_c)->NextTimeout < (_c)->ContextList->LatestTimeout ) { \
(_c)->ContextList->LatestTimeout = (_c)->NextTimeout; \
} \
}
#define AtqGetCurrentTick( ) g_AtqCurrentTick
/************************************************************
* Type Definitions
************************************************************/
typedef enum {
StatusAllowOperation = 0,
StatusBlockOperation = 1,
StatusRejectOperation = 2,
StatusMaxOp
} OPERATION_STATUS;
typedef enum {
AtqIoNone = 0,
AtqIoRead,
AtqIoWrite,
AtqIoXmitFile,
AtqIoXmitFileRecv,
AtqIoSendRecv,
AtqIoMaxOp
} ATQ_OPERATION;
# define IsValidAtqOp(atqOp) \
(((atqOp) >= AtqIoRead) && ((atqOp) <= AtqIoSendRecv))
//
// Active context structure
//
class ATQ_CONTEXT_LISTHEAD {
public:
ATQ_CONTEXT_LISTHEAD(VOID)
: m_fValid ( FALSE)
{ Initialize(); }
~ATQ_CONTEXT_LISTHEAD(VOID) { Cleanup(); }
//
// List heads
// 1. ActiveListHead - list of all active contexts (involved in IO)
// 2. PendingAcceptExListHead - list of all Pending AcceptEx contexts
//
LIST_ENTRY ActiveListHead;
LIST_ENTRY PendingAcceptExListHead;
//
// Value set to the latest timeout in the list. Allows us
// to skip a list for processing if no timeout has occurred
//
DWORD LatestTimeout;
VOID Lock(VOID) { EnterCriticalSection( &m_csLock); }
VOID Unlock(VOID) { LeaveCriticalSection( &m_csLock); }
VOID Initialize(VOID)
{
if ( !m_fValid) {
InitializeListHead( &ActiveListHead );
InitializeListHead( &PendingAcceptExListHead );
LatestTimeout = ATQ_INFINITE;
INITIALIZE_CRITICAL_SECTION( &m_csLock );
m_fValid = TRUE;
}
} // Initialize()
VOID Cleanup(VOID)
{
if ( m_fValid) {
ATQ_ASSERT( IsListEmpty( &ActiveListHead));
ATQ_ASSERT( IsListEmpty( &PendingAcceptExListHead));
DeleteCriticalSection( &m_csLock );
m_fValid = FALSE;
}
} // Cleanup()
VOID InsertIntoPendingList( IN OUT PLIST_ENTRY pListEntry)
{
Lock();
DBG_ASSERT( pListEntry->Flink == NULL);
DBG_ASSERT( pListEntry->Blink == NULL);
InsertTailList( &PendingAcceptExListHead, pListEntry );
Unlock();
} // InsertIntoPendingList()
VOID InsertIntoActiveList( IN OUT PLIST_ENTRY pListEntry)
{
Lock();
DBG_ASSERT( pListEntry->Flink == NULL);
DBG_ASSERT( pListEntry->Blink == NULL);
InsertTailList( &ActiveListHead, pListEntry );
Unlock();
} // InsertIntoActiveList()
VOID MoveToActiveList( IN OUT PLIST_ENTRY pListEntry)
{
Lock();
//
// Assume that this is currently in pending list!
// Remove from pending list and add it to active list
//
RemoveEntryList( pListEntry );
DBG_CODE( {
pListEntry->Flink = NULL;
pListEntry->Blink = NULL;
});
InsertTailList( &ActiveListHead, pListEntry );
Unlock();
} // MoveToActiveList()
VOID RemoveFromList(IN OUT PLIST_ENTRY pListEntry)
{
Lock();
RemoveEntryList( pListEntry );
pListEntry->Flink = pListEntry->Blink = NULL;
Unlock();
} // RemoveFromList()
private:
DWORD m_fValid;
CRITICAL_SECTION m_csLock;
};
typedef ATQ_CONTEXT_LISTHEAD * PATQ_CONTEXT_LISTHEAD;
//
// Signatures for allocated and free acceptex listen structures
//
#define ATQ_ENDPOINT_SIGNATURE_FREE (DWORD)'EQTX'
#define ATQ_ENDPOINT_SIGNATURE (DWORD)'EQTA'
//
// ATQ Block State
//
typedef enum {
AtqStateInit,
AtqStateActive,
AtqStateClosed,
AtqStateMax
} ATQ_BLOCK_STATE;
#define IS_BLOCK_ACTIVE(_b) ((_b)->State == AtqStateActive)
#define SET_BLOCK_STATE(_b,_s) ((_b)->State = (_s))
//
// forward of ATQ_ENDPOINT_BMON
//
class ATQ_ENDPOINT_BMON;
//
// ATQ_ENDPOINT per instance structure
//
struct ATQ_ENDPOINT {
DWORD Signature;
LONG m_refCount;
ATQ_BLOCK_STATE State; // Endpoint state
BOOL UseAcceptEx; // are we using AcceptEx
LONG nSocketsAvail; // # available sockets
DWORD InitialRecvSize; // Initial AcceptEx Recv buffer size
SOCKET ListenSocket; // our listen socket
ATQ_ENDPOINT_BMON * pBacklogMon; // Backlog monitor
ATQ_CONNECT_CALLBACK ConnectCompletion; // PFN Connection Completion
ATQ_COMPLETION ConnectExCompletion; // PFN ConnectionEx Compl.
ATQ_COMPLETION IoCompletion; // PFN I/O completion
BOOL EnableBw; // Do we support Bandwidth throttling
PVOID Context; // Client Context
LIST_ENTRY ListEntry; // list of server entities
LPTHREAD_START_ROUTINE ShutdownCallback; // callback on shutdown compl.
PVOID ShutdownCallbackContext;
PATQ_CONTEXT pListenAtqContext; // ATQ context for the listen socket
HANDLE hListenThread; // listen thread for non-acceptex sockets
USHORT Port; // port we listen on
DWORD IpAddress; // IP address we're bound to
// stores the specified canonical timeout b/w connect and receive
DWORD AcceptExTimeout;
DWORD nAcceptExOutstanding; // # initial outstanding sockets
BOOL fAddingSockets; // Are we adding sockets ...
DWORD nAvailDuringTimeOut;// # counter used by timeout processor
#if DBG
PTRACE_LOG RefTraceLog;
#endif
VOID Reference(VOID);
VOID Dereference(VOID);
BOOL ActivateEndpoint( VOID);
DWORD CloseAtqContexts( IN BOOL fPendingOnly = FALSE);
VOID CleanupEndpoint( VOID);
};
typedef ATQ_ENDPOINT * PATQ_ENDPOINT;
//
// ATQ_ENDPOINT_BMON
//
// This is a backlog monitor class that
// ATQ_ENDPOINTs use to make sure there
// are always AcceptEx contexts available.
//
class ATQ_ENDPOINT_BMON : public ATQ_BMON_ENTRY {
public:
ATQ_ENDPOINT_BMON(
SOCKET s,
PATQ_ENDPOINT pEndpoint)
: ATQ_BMON_ENTRY(s),
m_pEndpoint(pEndpoint),
m_nActivations(0),
m_dwForceCookie(0),
m_nSocketsReset(0) {}
virtual ~ATQ_ENDPOINT_BMON();
virtual BOOL Callback();
static VOID ForceCompletion( PVOID pvContext );
private:
PATQ_ENDPOINT m_pEndpoint;
DWORD m_nActivations;
DWORD m_dwForceCookie;
DWORD m_nSocketsReset;
};
inline VOID
ATQ_ENDPOINT::Reference(VOID)
{
LONG result = InterlockedIncrement( &this->m_refCount );
#if DBG
if( this->RefTraceLog != NULL ) {
WriteRefTraceLog(
this->RefTraceLog,
result,
(PVOID) this
);
}
#endif
return;
} // ATQ_ENDPOINT::Reference()
inline VOID
ATQ_ENDPOINT::Dereference(VOID)
{
LONG result;
//
// Write the trace log way before the decrement operation :(
// If we write it after the decrement, we will run into potential
// race conditions in this object getting freed up accidentally
// by another thread
//
#if DBG
if( this->RefTraceLog != NULL ) {
WriteRefTraceLog(
this->RefTraceLog,
this->m_refCount,
(PVOID) this
);
}
#endif
result = InterlockedDecrement( &this->m_refCount );
if ( result == 0 ) {
this->CleanupEndpoint();
LocalFree( this);
}
} // ATQ_ENDPOINT::Dereference()
typedef struct _OPLOCK_INFO {
ATQ_OPLOCK_COMPLETION pfnOplockCompletion;
PVOID Context;
} OPLOCK_INFO, *POPLOCK_INFO;
/*++
ATQ_CONTEXT:
This structure contains the context used by clients of ATQ module.
A pointer to this context information is used in accessing ATQ functions
for performing I/O operations.
--*/
//
// Signatures for ATQ structure
//
#define ATQ_CONTEXT_SIGNATURE ((DWORD)'CQTA') // valid when in use
#define ATQ_FREE_CONTEXT_SIGNATURE ((DWORD)'CQTX') // after freed
//
// transmit file state (Chicago)
//
typedef enum {
ATQ_XMIT_NONE=0,
ATQ_XMIT_START,
ATQ_XMIT_HEADR_SENT,
ATQ_XMIT_TRANSMITTING_FILE,
ATQ_XMIT_FILE_DONE,
ATQ_XMIT_TAIL_SENT
} ATQ_XMIT_STATE;
//
// ATQ Context State information bits ...
//
# define ACS_SOCK_CLOSED 0x00000001
# define ACS_SOCK_UNCONNECTED 0x00000002
# define ACS_SOCK_LISTENING 0x00000004
# define ACS_SOCK_CONNECTED 0x00000008
# define ACS_SOCK_TOBE_FREED 0x00000010
# define ACS_STATE_BITS ( \
ACS_SOCK_CLOSED | \
ACS_SOCK_UNCONNECTED | \
ACS_SOCK_LISTENING | \
ACS_SOCK_CONNECTED | \
ACS_SOCK_TOBE_FREED \
)
// Following are flags stored in the state of ATQ context
# define ACF_ACCEPTEX_ROOT_CONTEXT 0x00001000
# define ACF_CONN_INDICATED 0x00002000
# define ACF_IN_TIMEOUT 0x00004000 // Context is in timeout
# define ACF_BLOCKED 0x00008000 // blocked by B/w throttler
# define ACF_REUSE_CONTEXT 0x00010000
# define ACF_RECV_ISSUED 0x00020000 // For Use by the ATQ driver
# define ACF_ABORTIVE_CLOSE 0x00040000 // request abortive close on closesocket
# define ACF_RECV_CALLED 0x00080000 // ReadSocket Called
# define ACF_WINSOCK_CONNECTED 0x00100000 // Checked as connected using getsockopt(SO_CONNECT_TIME)
# define ACF_TCP_NODELAY 0x00200000 // TCP_NODELAY flag is set
/*++
ATQ_REQUEST_INFO
This structure contains information that contains information for
restarting a blocked Atq Io operation.
It contains:
operation to be performed;
parameters required for the operation
pointer to overlapped structure passed in.
This information is to be embedded in the atq context maintained.
--*/
typedef struct _ATQ_REQUEST_INFO {
ATQ_OPERATION atqOp; // operation that is blocked
LPOVERLAPPED lpOverlapped; // pointer to overlapped structure to be used
DWORD dwTotalBytesTransferred;
DWORD dwLastIOError;
union {
struct {
WSABUF buf1;
DWORD dwBufferCount;
//
// used only if dwBufferCount > 1, dynamically allocated
//
LPWSABUF pBufAll;
//
// Temporary buffer if send from r/o memory detected on win95
//
PCHAR pWin95CopyBuffer;
} opReadWrite;
struct {
HANDLE hFile;
DWORD dwBytesInFile;
LPTRANSMIT_FILE_BUFFERS lpXmitBuffers;
DWORD dwFlags;
} opXmit;
struct {
PCHAR pBuffer; // temp io buffer
ATQ_COMPLETION pfnCompletion; // actual completion
PVOID ClientContext; // actual client context
HANDLE hFile;
DWORD FileOffset;
DWORD BytesLeft;
DWORD BytesWritten;
TRANSMIT_FILE_BUFFERS TransmitBuffers;
//
// Chicago
//
ATQ_XMIT_STATE CurrentState;
LPVOID pvLastSent;
DWORD cbBuffer;
} opFakeXmit;
struct {
HANDLE hFile;
DWORD dwBytesInFile;
LPTRANSMIT_FILE_BUFFERS lpXmitBuffers;
DWORD dwTFFlags;
WSABUF buf1;
LPWSABUF pBufAll;
DWORD dwBufferCount;
} opXmitRecv;
struct {
WSABUF sendbuf1;
WSABUF recvbuf1;
LPWSABUF pSendBufAll;
LPWSABUF pRecvBufAll;
DWORD dwSendBufferCount;
DWORD dwRecvBufferCount;
} opSendRecv;
} uop;
} ATQ_REQUEST_INFO;
class BANDWIDTH_INFO;
struct ATQ_CONTEXT {
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// These must come first and must match whatever
// ATQ_CONTEXT_PUBLIC is defined as in atq.h
//
HANDLE hAsyncIO; // handle for async i/o object: socket/file
OVERLAPPED Overlapped; // Overlapped structure used for IO
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
DWORD Signature;
//
// will there be a race in updating the flags/state ... - NYI: Check on MP
//
DWORD m_acState; // ATQ Context State
DWORD m_acFlags; // ATQ Context Flags
//
// link to add the element to timeout lists
//
LIST_ENTRY m_leTimeout;
//
// These are used when we are in AcceptEx mode
//
PATQ_ENDPOINT pEndpoint;
//
// Points to the list head this belongs to
//
PATQ_CONTEXT_LISTHEAD ContextList;
PVOID ClientContext; // call back context
//
// Called at I/O completion
//
ATQ_COMPLETION pfnCompletion; // function to be called at i/o completion.
//
// ATQ_SYNC_TIMEOUT value for synchronizing timeout processing
// This should be composed into aTQ context state later on!
//
LONG lSyncTimeout;
DWORD TimeOut; // time for each transaction.
DWORD NextTimeout; // time that this context times out
DWORD TimeOutScanID;
DWORD BytesSent;
//
// the buffer pvBuff actually should be of size
// (pContext->pEndpoint->InitialRecvSize + 2*MIN_SOCKADDR_SIZE)
//
PVOID pvBuff; // Initial recv buff if using AcceptEx
// Count the references --- for IO
LONG m_nIO;
// ------------------------------------------------------------
// Win95 related stuff
// ------------------------------------------------------------
// Mirrored copy of handle with high bit set(hAsyncIO)
ULONG_PTR hJraAsyncIO;
LIST_ENTRY SIOListEntry; // for fake IO Completion port (win95)
DWORD dwSIOFlags; // for fake IO Completion port (win95)
// ------------------------------------------------------------
// Bandwidth throttling stuff - data specific for b/w control
// ------------------------------------------------------------
ATQ_REQUEST_INFO arInfo;
LIST_ENTRY BlockedListEntry; // link to add it to blocked list
BANDWIDTH_INFO* m_pBandwidthInfo; // bandwidth info object
//
// For use by ATQ Driver
//
SPUD_REQ_CONTEXT spudContext;
//
// Context for capacity planning trace
//
IIS_CAP_TRACE_INFO m_CapTraceInfo;
//
// Should we force closure of the socket?
//
BOOL m_fForceClose;
// ------------------------------------------------------------
// Member Functions
// ------------------------------------------------------------
private:
VOID InitTimeoutListEntry( VOID)
{
m_leTimeout.Flink = m_leTimeout.Blink = NULL;
}
public:
VOID
InitWithDefaults(IN ATQ_COMPLETION pfnCompletion,
IN DWORD TimeOut,
IN HANDLE hAsyncIO
);
VOID
InitNonAcceptExState(IN PVOID pClientContext);
inline VOID
SetAcceptExBuffer(IN PVOID pvBuff);
VOID
InitAcceptExState(IN DWORD NextTimeOut);
BOOL
PrepareAcceptExContext(IN PATQ_ENDPOINT pEndpoint);
VOID
CleanupAndRelease( VOID);
void Print( void) const;
VOID SetFlag( IN DWORD dwBits) { m_acFlags |= dwBits; }
VOID ResetFlag( IN DWORD dwBits) { m_acFlags &= ~dwBits; }
DWORD IsFlag( DWORD dwBits) const { return ( m_acFlags & dwBits); }
DWORD IsState( DWORD dwBits) const { return ( m_acState & dwBits); }
BOOL IsAcceptExRootContext(VOID) const
{ return ( m_acFlags & ACF_ACCEPTEX_ROOT_CONTEXT); }
BOOL IsBlocked(VOID) const
{ return ( m_acFlags & ACF_BLOCKED); }
// assumes that only one bit is set in the dwBit!
VOID SetState( IN DWORD dwBit) { m_acState |= dwBit; }
// Moves from one state to another using bit-masks
VOID MoveState( IN DWORD dwBits)
{ m_acState = ((m_acState & ~(ACS_STATE_BITS)) | dwBits); }
VOID ResetState( IN DWORD dwBits) { m_acState &= ~dwBits; }
VOID ConnectionCompletion( IN DWORD cbWritten, IN LPOVERLAPPED lpo)
{
DBG_ASSERT( pEndpoint != NULL);
DBG_ASSERT( pEndpoint->ConnectExCompletion != NULL);
// set state so that the timeout thread will know
SetFlag( ACF_CONN_INDICATED);
pEndpoint->ConnectExCompletion( this, cbWritten, NO_ERROR, lpo);
}
VOID IOCompletion( IN DWORD cbWritten, IN DWORD dwError,
IN LPOVERLAPPED lpo)
{
DBG_ASSERT( pfnCompletion != NULL);
pfnCompletion( ClientContext, cbWritten, dwError, lpo);
}
#if CC_REF_TRACKING
//
// ATQ notification trace
//
// Called only if the client context points to a W3 context
//
VOID NotifyIOCompletion( IN DWORD cbWritten, IN DWORD dwError, IN DWORD dwSig )
{
if ( (pfnCompletion != NULL ) &&
ClientContext &&
((LPDWORD)ClientContext)[2] == ((DWORD) ' SCC') )
{
pfnCompletion( ClientContext, cbWritten, dwError, (LPOVERLAPPED)dwSig);
}
}
#endif
VOID HardCloseSocket( VOID);
PIIS_CAP_TRACE_INFO GetCapTraceInfo()
{
return &m_CapTraceInfo;
}
BOOL ForceClose( VOID ) const
{
return m_fForceClose;
}
VOID SetForceClose( BOOL f )
{
m_fForceClose = f;
}
};
typedef ATQ_CONTEXT * PATQ_CONT;
inline VOID
ATQ_CONTEXT::SetAcceptExBuffer(IN PVOID pvBuff)
{
//
// the buffer actually should be of size
// (this->pEndpoint->InitialRecvSize + 2*MIN_SOCKADDR_SIZE)
//
this->pvBuff = pvBuff;
return;
} // ATQ_CONTEXT::SetAcceptExBuffer();
#endif // _ATQTYPES_H_