windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/w3/server/conn.hxx

617 lines
15 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/**********************************************************************/
/** Microsoft Windows NT **/
/** Copyright(c) Microsoft Corp., 1994 **/
/**********************************************************************/
/*
conn.hxx
This module contains the connection class
FILE HISTORY:
Johnl 15-Aug-1994 Created
*/
#ifndef _CONN_HXX_
#define _CONN_HXX_
# include "w3inst.hxx"
# include "rdns.hxx"
# include <reftrace.h>
//
// Determines if client connection reference count tracking is enabled
//
#if DBG && !defined(_WIN64)
#define CC_REF_TRACKING 1
#else
#define CC_REF_TRACKING 0
#endif
//
// The default timeout to wait for the completion of an Atq IO request (in sec)
//
#define W3_IO_TIMEOUT (5*60)
//
// The initial size of the buffer to receive the client request
//
#define W3_DEFAULT_BUFFSIZE 4096
//
// The end of a line is considered to be the linefeed character
//
#define W3_EOL 0x0A
//
// Valid signature of a CLIENT_CONN_STATE
//
#define CLIENT_CONN_SIGNATURE ((DWORD) ' SCC')
//
// Invalid signature of a CLIENT_CONN_STATE
//
#define CLIENT_CONN_SIGNATURE_FREE ((DWORD) 'xssc')
//
// The various states a CLIENT_CONN object can be in
//
enum CLIENT_CONN_STATE
{
//
// We've just accepted the TCP connection from the client but we have
// no other information.
//
CCS_STARTUP = 0,
//
// We are in the process of receiving the client's HTTP request buffer
//
CCS_GETTING_CLIENT_REQ,
//
// We are reading data from the client socket meant for a gateway
//
CCS_GATHERING_GATEWAY_DATA,
//
// We're executing the clients HTTP request
//
CCS_PROCESSING_CLIENT_REQ,
//
// The server or client has initiated a disconnect. We have to
// wait till all outstanding IO requests are completed before
// cleaning up
//
CCS_DISCONNECTING,
//
// All pending requests have been completed. Finish cleaning
// up.
//
CCS_SHUTDOWN
};
//
// parameter block used to initialize connections
//
typedef struct _CLIENT_CONN_PARAMS
{
SOCKET sClient;
PSOCKADDR pAddrLocal;
PSOCKADDR pAddrRemote;
PATQ_CONTEXT pAtqContext;
PVOID pEndpointObject;
PIIS_ENDPOINT pEndpoint;
PVOID pvInitialBuff;
DWORD cbInitialBuff;
} CLIENT_CONN_PARAMS, *PCLIENT_CONN_PARAMS;
class CLIENT_CONN
{
public:
BOOL IsValid( VOID )
{ return _fIsValid; }
//
// This is the work entry point that is driven by the completion of the
// async IO.
//
BOOL DoWork( DWORD BytesWritten,
DWORD CompletionStatus,
BOOL fIOCompletion);
#if CC_REF_TRACKING
//
// ATQ notification trace
//
// Notification of ATQ completion, for debugging purpose only.
//
VOID NotifyAtqProcessContext( DWORD BytesWritten,
DWORD CompletionStatus,
DWORD dwSig );
#endif
//
// Optionally sends a status response then initiates the disconnect
//
// HTResponse - HTTP status code
// ErrorResponse - System error or resource ID of response
//
// If this function fails, then the connection will be aborted
//
dllexp
VOID Disconnect( HTTP_REQ_BASE * pRequest = NULL,
DWORD HTResponse = 0,
DWORD ErrorResponse = NO_ERROR,
BOOL fDoShutdown = TRUE,
LPBOOL pfFinished =NULL );
dllexp
BOOL OnSessionStartup( BOOL *pfDoAgain,
PVOID pvInitial = NULL,
DWORD cbInitial = 0,
BOOL fFirst = FALSE);
//
// Walks the connection list and calls disconnect on each connection
//
static VOID DisconnectAllUsers( PIIS_SERVER_INSTANCE Instance = NULL );
//
// Increments and decrements the reference count
//
UINT Reference( VOID );
UINT Dereference( VOID );
UINT QueryRefCount( VOID ) const
{ return _cRef; }
PIIS_ENDPOINT QueryW3Endpoint( VOID ) const
{ return m_pW3Endpoint; }
PW3_SERVER_INSTANCE QueryW3Instance( VOID ) const
{ return m_pInstance; }
BOOL IsW3Instance( VOID ) const
{ return m_pInstance != NULL; }
VOID SetW3Instance( IN PW3_SERVER_INSTANCE pInstance )
{ DBG_ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }
W3_SERVER_STATISTICS * QueryW3StatsObj( VOID ) const
{ return m_pW3Stats; }
VOID SetW3StatsObj( IN LPW3_SERVER_STATISTICS pW3Stats )
{ m_pW3Stats = pW3Stats; }
DWORD QueryLocalIPAddress( VOID ) const
{ return m_localIpAddress; }
DWORD QueryRemoteIPAddress( VOID ) const
{ return m_remoteIpAddress; }
BOOL RequestAbortiveClose( VOID );
BOOL CloseConnection( VOID );
//
// Simple wrappers to the corresponding Atq functions
//
BOOL ReadFile( LPVOID lpBuffer,
DWORD nBytesToRead );
BOOL WriteFile( LPVOID lpBuffer,
DWORD nBytesToRead );
BOOL SyncWsaSend( WSABUF * rgWsaBuffers,
DWORD cWsaBuffers,
LPDWORD pcbWritten );
BOOL TransmitFile( HANDLE hFile,
DWORD Offset,
DWORD BytesToWrite,
DWORD dwFlags,
PVOID pHead = NULL,
DWORD HeadLength = 0,
PVOID pTail = NULL,
DWORD TailLength = 0 );
BOOL TransmitFileAndRecv( HANDLE hFile,
DWORD Offset,
DWORD BytesToWrite,
DWORD dwFlags,
PVOID pHead = NULL,
DWORD HeadLength = 0,
PVOID pTail = NULL,
DWORD TailLength = 0,
LPVOID lpBuffer = NULL,
DWORD BytesToRead = 0);
BOOL WriteFileAndRecv( LPVOID lpSendBuffer,
DWORD BytesToWrite,
LPVOID lpRecvBuffer = NULL,
DWORD BytesToRead = 0);
BOOL PostCompletionStatus( DWORD BytesTransferred );
//
// This list entry is put on the client connection list
//
LIST_ENTRY ListEntry;
SOCKET QuerySocket( VOID ) const
{ return _sClient; }
PATQ_CONTEXT QueryAtqContext( VOID ) const
{ return _AtqContext; }
USHORT QueryPort( VOID ) const
{ return _sPort; }
USHORT QueryRemotePort( VOID ) const
{ return _sRemotePort; }
BOOL IsSecurePort( VOID ) const
{ return _fSecurePort; }
//
// Make sure the next state is set before an async IO call is made
//
enum CLIENT_CONN_STATE QueryState( VOID ) const
{ return _ccState; }
VOID SetState( CLIENT_CONN_STATE ccState )
{ _ccState = ccState; }
BOOL CheckSignature( VOID ) const
{ return _Signature == CLIENT_CONN_SIGNATURE; }
TCHAR * QueryRemoteAddr( VOID ) const
{ return (TCHAR *) _achRemoteAddr; }
TCHAR * QueryLocalAddr( VOID ) const
{ return (TCHAR *) _achLocalAddr; }
VOID SetAtqReuseContextFlag( BOOL fReuseContext )
{ _fReuseContext = fReuseContext; }
static DWORD QueryFreeListSize( VOID )
{ return _cFree; }
static DWORD Initialize( VOID );
static VOID Terminate( VOID );
static CLIENT_CONN * Alloc( PCLIENT_CONN_PARAMS );
dllexp static VOID Free( CLIENT_CONN * pConn );
static VOID TrimFreeList( VOID );
BOOL QueryDnsName(
LPBOOL pfSync,
ADDRCHECKFUNCEX pFunc,
ADDRCHECKARG pArg,
LPSTR * ppName
)
{
return _acCheck.QueryDnsName( pfSync, pFunc, pArg, ppName );
}
AC_RESULT CheckIpAccess( LPBOOL pfNeedDns )
{ return _acCheck.CheckIpAccess( pfNeedDns ); }
AC_RESULT CheckDnsAccess()
{ return _acCheck.CheckDnsAccess(); }
BOOL BindAccessCheckList( LPBYTE p, DWORD dw )
{ return _acCheck.BindCheckList( p, dw ); }
VOID UnbindAccessCheckList()
{ _acCheck.UnbindCheckList(); }
LPSTR QueryResolvedDnsName()
{ return _acCheck.QueryResolvedDnsName(); }
BOOL IsDnsResolved()
{ return _acCheck.IsDnsResolved(); }
HTTP_REQ_BASE * QueryHttpReq( VOID) const
{ return (_phttpReq); }
protected:
//
// Constructor and destructor
//
CLIENT_CONN( PCLIENT_CONN_PARAMS );
VOID Initialize( PCLIENT_CONN_PARAMS );
~CLIENT_CONN( VOID );
VOID Reset( VOID );
BOOL IsCleaningUp( VOID ) const
{ return QueryState() == CCS_DISCONNECTING ||
QueryState() == CCS_SHUTDOWN;
}
private:
//
// Contains the CLIENT_CONN signature
//
ULONG _Signature;
//
// Construction success indicator
//
BOOL _fIsValid;
//
// Contains the client socket connection openned by the connection thread
//
SOCKET _sClient;
enum CLIENT_CONN_STATE _ccState;
//
// Reference count. Can't go away until the count reaches 0
//
LONG _cRef;
//
// Contains an ASCII representation of the client's remote address
// and the adapter local address
//
CHAR _achRemoteAddr[20];
CHAR _achLocalAddr[20];
//
// Port this connection is on
//
USHORT _sPort;
//
// Remote port
//
USHORT _sRemotePort;
//
// This request came in through the secure port
//
BOOL _fSecurePort;
//
// Parses the data and determines the appropriate action
//
HTTP_REQ_BASE * _phttpReq;
//
// server instance. Both are referenced.
//
PW3_SERVER_INSTANCE m_pInstance;
PIIS_ENDPOINT m_pW3Endpoint;
//
// server instance - statistics object.
//
LPW3_SERVER_STATISTICS m_pW3Stats;
//
// local ip address
//
DWORD m_localIpAddress;
//
// remote sockaddr
//
DWORD m_remoteIpAddress;
//
// context returned on a non-acceptex completion
//
PVOID m_atqEndpointObject;
//
// Initial receive buffer if we're doing AcceptEx processing
//
PVOID _pvInitial;
DWORD _cbInitial;
PATQ_CONTEXT _AtqContext;
//
// If FALSE, the Atq Context should not be reused because the calling
// thread will be exiting soon
//
BOOL _fReuseContext:1;
BOOL _fAbortiveClose:1;
//
// Response string for disconnect notifications.
//
// NOTE: If the server handles non-serial requests, then two request completing at
// the same time could use this string
//
STR _strResponse;
//
// These are for the lookaside buffer list
//
static CRITICAL_SECTION _csBuffList;
static LIST_ENTRY _BuffListHead;
static BOOL _fGlobalInit;
static DWORD _cFree;
static DWORD _FreeListScavengerCookie;
LIST_ENTRY _BuffListEntry;
//
// Address check object for IP / DNS
//
ADDRESS_CHECK _acCheck;
#if CC_REF_TRACKING
public:
//
// For object local refcount tracing
//
PTRACE_LOG _pDbgCCRefTraceLog;
private:
#endif
};
//
// Functions for connection reference counts
//
inline VOID ReferenceConn( CLIENT_CONN * pConn )
{
pConn->Reference();
}
inline VOID DereferenceConn( CLIENT_CONN * pConn )
{
if ( !pConn->Dereference() ) {
CLIENT_CONN::Free( pConn );
}
}
/*******************************************************************
Support for CLIENT_CONN debug ref trace logging
SYNOPSIS: Macro for writing to debug ref trace log.
HISTORY:
DaveK 10-Sep-1997 Created
********************************************************************/
//
// NOTE we avoid compile failure by hokey double typecast, below
// (since htrState is an enum, we must first cast it to int).
//
#define SHARED_LOG_REF_COUNT( \
cRefs \
, pClientConn \
, pHttpRequest \
, pWamRequest \
, htrState \
) \
\
if( g_pDbgCCRefTraceLog != NULL ) { \
\
ULONG_PTR i = (ULONG_PTR)htrState; \
PVOID pv = (PVOID) i; \
\
WriteRefTraceLogEx( \
g_pDbgCCRefTraceLog \
, cRefs \
, pClientConn \
, pHttpRequest \
, pWamRequest \
, pv \
); \
} \
//
// This macro logs the CLIENT_CONN specific ref trace log
//
#define LOCAL_LOG_REF_COUNT( \
cRefs \
, pClientConn \
, pHttpRequest \
, pWamRequest \
, htrState \
) \
\
if( _pDbgCCRefTraceLog != NULL ) { \
\
ULONG_PTR i = (ULONG_PTR)htrState; \
PVOID pv = (PVOID) i; \
\
WriteRefTraceLogEx( \
_pDbgCCRefTraceLog \
, cRefs \
, pClientConn \
, pHttpRequest \
, pWamRequest \
, pv \
); \
} \
#if CC_REF_TRACKING
inline
VOID
LogRefCountCCLocal(
IN LONG cRefs
, IN PVOID pClientConn
, IN PVOID pHttpRequest
, IN PVOID pWamRequest
, IN int htrState
)
{
if( pClientConn && ((CLIENT_CONN *)pClientConn)->_pDbgCCRefTraceLog )
{
WriteRefTraceLogEx(
((CLIENT_CONN *) pClientConn)->_pDbgCCRefTraceLog
, cRefs
, pClientConn
, pHttpRequest
, pWamRequest
, (PVOID) htrState
);
}
}
#endif
#if DBG
VOID DBG_CHECK_UnbalancedThreadToken(
IN const char * pszFilePath,
IN int nLineNum
);
#endif //DBG
#endif // !_CONN_HXX_