1736 lines
41 KiB
C++
1736 lines
41 KiB
C++
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name :
|
|
ulcontext.cxx
|
|
|
|
Abstract:
|
|
Implementation of UL_CONTEXT. One such object for every connection
|
|
|
|
Author:
|
|
Bilal Alam (BAlam) 29-March-2000
|
|
|
|
Environment:
|
|
Win32 - User Mode
|
|
|
|
Project:
|
|
Stream Filter Worker Process
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
#define DEFAULT_RAW_READ_SIZE 32768
|
|
#define DEFAULT_APP_READ_SIZE 32768
|
|
|
|
|
|
|
|
LIST_ENTRY UL_CONTEXT::sm_ListHead;
|
|
CRITICAL_SECTION UL_CONTEXT::sm_csUlContexts;
|
|
DWORD UL_CONTEXT::sm_cUlContexts;
|
|
HANDLE UL_CONTEXT::sm_hFilterHandle = NULL;
|
|
THREAD_POOL * UL_CONTEXT::sm_pThreadPool = NULL;
|
|
LONG UL_CONTEXT::sm_cDesiredOutstanding;
|
|
LONG UL_CONTEXT::sm_cOutstandingContexts;
|
|
PTRACE_LOG UL_CONTEXT::sm_pTraceLog;
|
|
|
|
UL_CONTEXT::UL_CONTEXT()
|
|
: _RawWriteOverlapped( OVERLAPPED_CONTEXT_RAW_WRITE ),
|
|
_RawReadOverlapped( OVERLAPPED_CONTEXT_RAW_READ ),
|
|
_AppWriteOverlapped( OVERLAPPED_CONTEXT_APP_WRITE ),
|
|
_AppReadOverlapped( OVERLAPPED_CONTEXT_APP_READ ),
|
|
_buffConnectionInfo( _abConnectionInfo, sizeof( _abConnectionInfo ) ),
|
|
_fCloseConnection( FALSE ),
|
|
_cRefs( 1 ),
|
|
_cbReadData( 0 ),
|
|
_fNewConnection( TRUE ),
|
|
_pSSLContext( NULL ),
|
|
#ifdef ISAPI
|
|
_pISAPIContext( NULL ),
|
|
#endif
|
|
_cbNextRawReadSize( DEFAULT_RAW_READ_SIZE ),
|
|
_ulFilterBufferType( (HTTP_FILTER_BUFFER_TYPE) -1 )
|
|
{
|
|
_RawWriteOverlapped.SetContext( this );
|
|
_RawReadOverlapped.SetContext( this );
|
|
_AppWriteOverlapped.SetContext( this );
|
|
_AppReadOverlapped.SetContext( this );
|
|
|
|
EnterCriticalSection( &sm_csUlContexts );
|
|
InsertHeadList( &sm_ListHead, &_ListEntry );
|
|
sm_cUlContexts++;
|
|
LeaveCriticalSection( &sm_csUlContexts );
|
|
|
|
_pConnectionInfo = (HTTP_RAW_CONNECTION_INFO*) _buffConnectionInfo.QueryPtr();
|
|
_pConnectionInfo->pInitialData = (PBYTE)_pConnectionInfo +
|
|
sizeof(HTTP_RAW_CONNECTION_INFO);
|
|
_pConnectionInfo->InitialDataSize = _buffConnectionInfo.QuerySize() -
|
|
sizeof(HTTP_RAW_CONNECTION_INFO);
|
|
|
|
_dwSignature = UL_CONTEXT_SIGNATURE;
|
|
}
|
|
|
|
UL_CONTEXT::~UL_CONTEXT()
|
|
{
|
|
_dwSignature = UL_CONTEXT_SIGNATURE_FREE;
|
|
|
|
//
|
|
// Cleanup any attached stream context
|
|
//
|
|
|
|
#ifdef ISAPI
|
|
if ( _pISAPIContext != NULL )
|
|
{
|
|
delete _pISAPIContext;
|
|
_pISAPIContext = NULL;
|
|
}
|
|
#endif
|
|
|
|
if ( _pSSLContext != NULL )
|
|
{
|
|
delete _pSSLContext;
|
|
_pSSLContext = NULL;
|
|
}
|
|
|
|
//
|
|
// Manage the list of active UL_CONTEXTs
|
|
//
|
|
|
|
EnterCriticalSection( &sm_csUlContexts );
|
|
sm_cUlContexts--;
|
|
RemoveEntryList( &_ListEntry );
|
|
LeaveCriticalSection( &sm_csUlContexts );
|
|
}
|
|
|
|
VOID
|
|
UL_CONTEXT::ReferenceUlContext(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reference the UL_CONTEXT
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
LONG cRefs;
|
|
|
|
cRefs = InterlockedIncrement( &_cRefs );
|
|
|
|
//
|
|
// Log the reference ( sm_pTraceLog!=NULL if DBG=1)
|
|
//
|
|
|
|
if ( sm_pTraceLog != NULL )
|
|
{
|
|
WriteRefTraceLog( sm_pTraceLog,
|
|
cRefs,
|
|
this );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UL_CONTEXT::DereferenceUlContext(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dereference (and possible destroy) the UL_CONTEXT
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
LONG cRefs;
|
|
|
|
cRefs = InterlockedDecrement( &_cRefs );
|
|
|
|
if ( sm_pTraceLog != NULL )
|
|
{
|
|
WriteRefTraceLog( sm_pTraceLog,
|
|
cRefs,
|
|
this );
|
|
}
|
|
|
|
if ( cRefs == 0 )
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::OnAppReadCompletion(
|
|
DWORD cbCompletion,
|
|
DWORD dwCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion for reads from an application
|
|
|
|
Arguments:
|
|
|
|
cbCompletion - Bytes of completion
|
|
dwCompletionStatus - Completion error
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HTTP_FILTER_BUFFER * pFilterBuffer;
|
|
HRESULT hr;
|
|
RAW_STREAM_INFO rawStreamInfo;
|
|
BOOL fComplete = FALSE;
|
|
|
|
//
|
|
// Just bail on errors
|
|
//
|
|
|
|
if ( dwCompletionStatus != NO_ERROR )
|
|
{
|
|
return HRESULT_FROM_WIN32( dwCompletionStatus );
|
|
}
|
|
|
|
pFilterBuffer = (HTTP_FILTER_BUFFER *) _ulFilterBuffer.pBuffer;
|
|
_ulFilterBufferType = pFilterBuffer->BufferType;
|
|
|
|
DBG_ASSERT( !_fNewConnection );
|
|
|
|
//
|
|
// If UL is telling us to close the connection, then do so now
|
|
//
|
|
|
|
if ( _ulFilterBufferType == HttpFilterBufferCloseConnection )
|
|
{
|
|
StartClose();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Setup raw stream descriptor
|
|
//
|
|
|
|
rawStreamInfo.pbBuffer = (PBYTE) pFilterBuffer->pBuffer;
|
|
rawStreamInfo.cbBuffer = pFilterBuffer->BufferSize;
|
|
rawStreamInfo.cbData = pFilterBuffer->BufferSize;
|
|
|
|
#ifdef ISAPI
|
|
//
|
|
// First notify ISAPI filters if this is a stream from the application
|
|
//
|
|
|
|
DBG_ASSERT( g_pStreamFilter != NULL );
|
|
|
|
if ( _ulFilterBufferType == HttpFilterBufferHttpStream &&
|
|
g_pStreamFilter->QueryNotifyISAPIFilters() )
|
|
{
|
|
DBG_ASSERT( _pISAPIContext != NULL );
|
|
|
|
hr = _pISAPIContext->ProcessRawWriteData( &rawStreamInfo,
|
|
&fComplete );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ( fComplete )
|
|
{
|
|
StartClose();
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Next notify SSL filter always
|
|
//
|
|
|
|
DBG_ASSERT( _pSSLContext != NULL );
|
|
|
|
hr = _pSSLContext->ProcessRawWriteData( &rawStreamInfo,
|
|
&fComplete );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ( fComplete )
|
|
{
|
|
StartClose();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// If there is data to send to the client, then do so now.
|
|
// This check is done because the filter may decide to eat up all the
|
|
// data to be sent
|
|
//
|
|
|
|
if ( _ulFilterBufferType == HttpFilterBufferHttpStream &&
|
|
rawStreamInfo.pbBuffer != NULL &&
|
|
rawStreamInfo.cbData != 0 )
|
|
{
|
|
//
|
|
// If we got to here, then we have processed data to send to the client
|
|
//
|
|
|
|
hr = DoRawWrite( UL_CONTEXT_FLAG_ASYNC,
|
|
rawStreamInfo.pbBuffer,
|
|
rawStreamInfo.cbData,
|
|
NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// New app read will be kicked off in OnRawWriteCompletion
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Kick off another app read
|
|
//
|
|
|
|
_ulFilterBuffer.pBuffer = (PBYTE) _buffAppReadData.QueryPtr();
|
|
_ulFilterBuffer.BufferSize = _buffAppReadData.QuerySize();
|
|
|
|
return DoAppRead( UL_CONTEXT_FLAG_ASYNC,
|
|
&_ulFilterBuffer,
|
|
NULL );
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::OnRawReadCompletion(
|
|
DWORD cbCompletion,
|
|
DWORD dwCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get read completions off the wire. This includes the initial
|
|
completion for the UlFilterAccept()
|
|
|
|
Arguments:
|
|
|
|
cbCompletion - Bytes of completion
|
|
dwCompletionStatus - Completion error
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HTTP_NETWORK_ADDRESS_IPV4 * pLocalAddress;
|
|
HTTP_NETWORK_ADDRESS_IPV4 * pRemoteAddress;
|
|
HRESULT hr;
|
|
BOOL fReadMore = FALSE;
|
|
BOOL fComplete = FALSE;
|
|
HTTP_FILTER_BUFFER ulFilterBuffer;
|
|
DWORD cbWritten;
|
|
RAW_STREAM_INFO rawStreamInfo;
|
|
|
|
//
|
|
// Handle errors
|
|
//
|
|
|
|
if ( dwCompletionStatus != NO_ERROR )
|
|
{
|
|
if ( _fNewConnection )
|
|
{
|
|
InterlockedDecrement( &sm_cOutstandingContexts );
|
|
}
|
|
return HRESULT_FROM_WIN32( dwCompletionStatus );
|
|
}
|
|
|
|
//
|
|
// If this is a new connection, then grok connection information, and
|
|
// maintain pending count
|
|
//
|
|
|
|
if ( _fNewConnection )
|
|
{
|
|
_fNewConnection = FALSE;
|
|
|
|
//
|
|
// This is a new connection. We have one less UL_CONTEXT to
|
|
// listen for incoming requests. Correct that if necessary.
|
|
//
|
|
|
|
InterlockedDecrement( &sm_cOutstandingContexts );
|
|
|
|
ManageOutstandingContexts();
|
|
|
|
//
|
|
// Convert the UL addresses into something nicer!
|
|
//
|
|
|
|
HTTP_TRANSPORT_ADDRESS *pAddress = &_pConnectionInfo->Address;
|
|
|
|
DBG_ASSERT( pAddress->LocalAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
|
|
pLocalAddress = (HTTP_NETWORK_ADDRESS_IPV4 *)pAddress->pLocalAddress;
|
|
|
|
_connectionContext.LocalAddress = pLocalAddress->IpAddress;
|
|
_connectionContext.LocalPort = pLocalAddress->Port;
|
|
|
|
DBG_ASSERT( pAddress->RemoteAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
|
|
pRemoteAddress = (HTTP_NETWORK_ADDRESS_IPV4 *) pAddress->pRemoteAddress;
|
|
|
|
_connectionContext.RemoteAddress = pRemoteAddress->IpAddress;
|
|
_connectionContext.RemotePort = pRemoteAddress->Port;
|
|
_connectionContext.fIsSecure = FALSE;
|
|
_connectionContext.RawConnectionId = _pConnectionInfo->ConnectionId;
|
|
#ifdef ISAPI
|
|
_connectionContext.pfnSendDataBack = ISAPI_STREAM_CONTEXT::SendDataBack;
|
|
#endif
|
|
_connectionContext.pvStreamContext = this;
|
|
|
|
//
|
|
// copy out the server name.
|
|
//
|
|
_connectionContext.ServerNameLength =
|
|
_pConnectionInfo->ServerNameLength;
|
|
_connectionContext.pServerName = _pConnectionInfo->pServerName;
|
|
|
|
//
|
|
// Fill in our read buffer (as if we had read it in directly)
|
|
//
|
|
|
|
_cbReadData = _pConnectionInfo->InitialDataSize;
|
|
|
|
if ( !_buffReadData.Resize( max( _pConnectionInfo->InitialDataSize,
|
|
QueryNextRawReadSize() ) ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
memcpy( _buffReadData.QueryPtr(),
|
|
_pConnectionInfo->pInitialData,
|
|
_pConnectionInfo->InitialDataSize );
|
|
|
|
//
|
|
// First indicate a new connection
|
|
//
|
|
|
|
DBG_ASSERT( _pSSLContext != NULL );
|
|
|
|
hr = _pSSLContext->ProcessNewConnection( &_connectionContext );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
#ifdef ISAPI
|
|
|
|
if ( g_pStreamFilter->QueryNotifyISAPIFilters() )
|
|
{
|
|
DBG_ASSERT( _pISAPIContext != NULL );
|
|
|
|
hr = _pISAPIContext->ProcessNewConnection( &_connectionContext );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Kick off an app read now.
|
|
//
|
|
|
|
if ( !_buffAppReadData.Resize( DEFAULT_APP_READ_SIZE ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
_ulFilterBuffer.pBuffer = (PBYTE) _buffAppReadData.QueryPtr();
|
|
_ulFilterBuffer.BufferSize = _buffAppReadData.QuerySize();
|
|
|
|
hr = DoAppRead( UL_CONTEXT_FLAG_ASYNC,
|
|
&_ulFilterBuffer,
|
|
NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_cbReadData += cbCompletion;
|
|
}
|
|
|
|
//
|
|
// reset default raw read size
|
|
//
|
|
|
|
SetNextRawReadSize( DEFAULT_RAW_READ_SIZE );
|
|
|
|
|
|
rawStreamInfo.pbBuffer = (PBYTE) _buffReadData.QueryPtr();
|
|
rawStreamInfo.cbBuffer = _buffReadData.QuerySize();
|
|
rawStreamInfo.cbData = _cbReadData;
|
|
|
|
//
|
|
// First, we will notify SSL
|
|
//
|
|
|
|
DBG_ASSERT( _pSSLContext != NULL );
|
|
|
|
hr = _pSSLContext->ProcessRawReadData( &rawStreamInfo,
|
|
&fReadMore,
|
|
&fComplete );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
_cbReadData = rawStreamInfo.cbData;
|
|
|
|
//
|
|
// If we need to read more data, then do so now
|
|
//
|
|
|
|
if ( fReadMore )
|
|
{
|
|
|
|
//
|
|
// rawStreamInfo.pbBuffer may have been replaced by different buffer
|
|
// in ProcessRawReadData() call.
|
|
// copy data back to _buffReadData
|
|
//
|
|
|
|
if ( rawStreamInfo.pbBuffer != _buffReadData.QueryPtr() )
|
|
{
|
|
DBG_ASSERT( rawStreamInfo.cbData <= _buffReadData.QuerySize() );
|
|
|
|
memmove( _buffReadData.QueryPtr(),
|
|
rawStreamInfo.pbBuffer,
|
|
rawStreamInfo.cbData
|
|
);
|
|
}
|
|
|
|
if ( !_buffReadData.Resize( rawStreamInfo.cbData +
|
|
QueryNextRawReadSize() ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return DoRawRead( UL_CONTEXT_FLAG_ASYNC,
|
|
(PBYTE) _buffReadData.QueryPtr() + _cbReadData,
|
|
QueryNextRawReadSize(),
|
|
NULL );
|
|
}
|
|
|
|
if ( fComplete )
|
|
{
|
|
StartClose();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Reset the next read size before calling into filters since SSL may
|
|
// have done a really small read, just previous to this.
|
|
//
|
|
|
|
SetNextRawReadSize( DEFAULT_RAW_READ_SIZE );
|
|
|
|
#ifdef ISAPI
|
|
//
|
|
// Now we can start notifying ISAPI filters if needed (and there is
|
|
// data to process)
|
|
//
|
|
|
|
DBG_ASSERT( g_pStreamFilter != NULL );
|
|
if ( g_pStreamFilter->QueryNotifyISAPIFilters() )
|
|
{
|
|
fComplete = FALSE;
|
|
fReadMore = FALSE;
|
|
|
|
DBG_ASSERT( _pISAPIContext != NULL );
|
|
|
|
hr = _pISAPIContext->ProcessRawReadData( &rawStreamInfo,
|
|
&fReadMore,
|
|
&fComplete );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
_cbReadData = rawStreamInfo.cbData;
|
|
|
|
//
|
|
// If we need to read more data, then do so now
|
|
//
|
|
|
|
if ( fReadMore )
|
|
{
|
|
//
|
|
// rawStreamInfo may have been replaced by different buffer
|
|
// in ProcessRawReadData() call.
|
|
// copy data back to _buffReadData
|
|
//
|
|
|
|
if ( rawStreamInfo.pbBuffer != _buffReadData.QueryPtr() )
|
|
{
|
|
DBG_ASSERT( rawStreamInfo.cbData <= _buffReadData.QuerySize() );
|
|
|
|
memmove( _buffReadData.QueryPtr(),
|
|
rawStreamInfo.pbBuffer,
|
|
rawStreamInfo.cbData
|
|
);
|
|
}
|
|
|
|
if ( !_buffReadData.Resize( rawStreamInfo.cbData +
|
|
QueryNextRawReadSize() ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
|
|
return DoRawRead( UL_CONTEXT_FLAG_ASYNC,
|
|
(PBYTE) _buffReadData.QueryPtr() + _cbReadData,
|
|
QueryNextRawReadSize(),
|
|
NULL );
|
|
}
|
|
|
|
if ( fComplete )
|
|
{
|
|
StartClose();
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If after filtering there is data remaining in our buffer, then that
|
|
// data is destined to the application. Send it asynchronously because
|
|
// there is a risk that synchronous call gets blocked for a long time
|
|
//
|
|
|
|
_cbReadData = 0;
|
|
|
|
if ( rawStreamInfo.cbData != 0 )
|
|
{
|
|
ulFilterBuffer.BufferType = HttpFilterBufferHttpStream;
|
|
ulFilterBuffer.BufferSize = rawStreamInfo.cbData;
|
|
ulFilterBuffer.pBuffer = rawStreamInfo.pbBuffer;
|
|
|
|
hr = DoAppWrite( UL_CONTEXT_FLAG_ASYNC,
|
|
&ulFilterBuffer,
|
|
&cbWritten );
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// new raw read will be kicked off in OnAppWriteCompletion()
|
|
//
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Kick off another raw read
|
|
//
|
|
|
|
//
|
|
// reset default raw read size
|
|
//
|
|
SetNextRawReadSize( DEFAULT_RAW_READ_SIZE );
|
|
|
|
if ( !_buffReadData.Resize( QueryNextRawReadSize() ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
hr = DoRawRead( UL_CONTEXT_FLAG_ASYNC,
|
|
_buffReadData.QueryPtr(),
|
|
QueryNextRawReadSize() ,
|
|
NULL );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::OnRawWriteCompletion(
|
|
DWORD cbCompletion,
|
|
DWORD dwCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
after raw write completes, this routine has to assure that new asynchronous AppRead request is
|
|
made to continue properly in communication
|
|
|
|
Note: This completion should be caused only by asynchronous DoRawWrite started in completion routine
|
|
of AppRead (OnAppReadCompletion()).
|
|
Please assure that NO RawWrite that is initiated by data coming from RawRead (SSL handshake)
|
|
will be called asynchronously. That could cause race condition (multiple threads using the same buffer
|
|
eg. for SSL data encryption)
|
|
|
|
|
|
Arguments:
|
|
|
|
cbCompletion - Bytes of completion
|
|
dwCompletionStatus - Completion error
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
if ( dwCompletionStatus != NO_ERROR )
|
|
{
|
|
return HRESULT_FROM_WIN32( dwCompletionStatus );
|
|
}
|
|
|
|
//
|
|
// Kick off another app read
|
|
//
|
|
|
|
_ulFilterBuffer.pBuffer = (PBYTE) _buffAppReadData.QueryPtr();
|
|
_ulFilterBuffer.BufferSize = _buffAppReadData.QuerySize();
|
|
|
|
return DoAppRead( UL_CONTEXT_FLAG_ASYNC,
|
|
&_ulFilterBuffer,
|
|
NULL );
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
UL_CONTEXT::OnAppWriteCompletion(
|
|
DWORD cbCompletion,
|
|
DWORD dwCompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
after app write completes we need to make another RawRead that is
|
|
the source of data for another asynchronous AppWrite.
|
|
|
|
Note: AppWrite should be called asynchronously only from OnRawReadCompletion()
|
|
Otherwise it would be necessary to change logic of this function
|
|
|
|
Arguments:
|
|
|
|
cbCompletion - Bytes of completion
|
|
dwCompletionStatus - Completion error
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if ( dwCompletionStatus != NO_ERROR )
|
|
{
|
|
return HRESULT_FROM_WIN32( dwCompletionStatus );
|
|
}
|
|
|
|
//
|
|
// Kick off another raw read
|
|
//
|
|
|
|
//
|
|
// reset default raw read size
|
|
//
|
|
SetNextRawReadSize( DEFAULT_RAW_READ_SIZE );
|
|
|
|
if ( !_buffReadData.Resize( QueryNextRawReadSize() ) )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
hr = DoRawRead( UL_CONTEXT_FLAG_ASYNC,
|
|
_buffReadData.QueryPtr(),
|
|
QueryNextRawReadSize() ,
|
|
NULL );
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::DoRawWrite(
|
|
DWORD dwFlags,
|
|
PVOID pvBuffer,
|
|
DWORD cbBuffer,
|
|
DWORD * pcbWritten
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write some bytes to the wire
|
|
|
|
Arguments:
|
|
|
|
dwFlags - UL_CONTEXT_ASYNC for async
|
|
pvBuffer - Buffer to send
|
|
cbBuffer - bytes in buffer
|
|
pcbWritten - Bytes written
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL fAsync = !!( dwFlags & UL_CONTEXT_FLAG_ASYNC );
|
|
ULONG ulRet = ERROR_SUCCESS;
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER DoRawWrite( async:%d, bytes:%d )\n",
|
|
fAsync,
|
|
cbBuffer
|
|
));
|
|
}
|
|
|
|
if ( fAsync )
|
|
{
|
|
ReferenceUlContext();
|
|
}
|
|
|
|
ulRet = HttpFilterRawWrite( sm_hFilterHandle,
|
|
_pConnectionInfo->ConnectionId,
|
|
pvBuffer,
|
|
cbBuffer,
|
|
pcbWritten,
|
|
fAsync ? QueryRawWriteOverlapped() : NULL );
|
|
|
|
if ( fAsync )
|
|
{
|
|
if ( ulRet != ERROR_IO_PENDING )
|
|
{
|
|
DereferenceUlContext();
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ulRet != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE DoRawWrite( async:%d, bytes:%d ) hr=0x%x\n",
|
|
fAsync,
|
|
cbBuffer,
|
|
hr
|
|
));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::DoAppRead(
|
|
DWORD dwFlags,
|
|
HTTP_FILTER_BUFFER * pFilterBuffer,
|
|
DWORD * pcbRead
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read data from application
|
|
|
|
Arguments:
|
|
|
|
dwFlags - UL_CONTEXT_ASYNC for async
|
|
pFilterBuffer - Filter buffer
|
|
pcbRead - Bytes read
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL fAsync = !!( dwFlags & UL_CONTEXT_FLAG_ASYNC );
|
|
ULONG ulRet = ERROR_SUCCESS;
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER DoAppRead( async:%d )\n",
|
|
fAsync
|
|
));
|
|
}
|
|
|
|
if ( fAsync )
|
|
{
|
|
ReferenceUlContext();
|
|
}
|
|
|
|
ulRet = HttpFilterAppRead( sm_hFilterHandle,
|
|
_pConnectionInfo->ConnectionId,
|
|
pFilterBuffer,
|
|
pFilterBuffer->BufferSize,
|
|
pcbRead,
|
|
fAsync ? QueryAppReadOverlapped() : NULL );
|
|
|
|
if ( fAsync )
|
|
{
|
|
if ( ulRet != ERROR_IO_PENDING )
|
|
{
|
|
DereferenceUlContext();
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ulRet != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE DoAppRead( async:%d )\n",
|
|
fAsync
|
|
));
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::DoAppWrite(
|
|
DWORD dwFlags,
|
|
HTTP_FILTER_BUFFER * pFilterBuffer,
|
|
DWORD * pcbWritten
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write data to the application
|
|
|
|
Arguments:
|
|
|
|
dwFlags - UL_CONTEXT_ASYNC for async
|
|
pFilterBuffer - Filter buffer
|
|
pcbWritten - Bytes written
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL fAsync = !!( dwFlags & UL_CONTEXT_FLAG_ASYNC );
|
|
ULONG ulRet = ERROR_SUCCESS;
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
DBG_ASSERT( pFilterBuffer != NULL );
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER DoAppWrite( async:%d, bytes:%d, buffertype:%d )\n",
|
|
fAsync,
|
|
pFilterBuffer->BufferSize,
|
|
pFilterBuffer->BufferType
|
|
));
|
|
}
|
|
|
|
if ( fAsync )
|
|
{
|
|
ReferenceUlContext();
|
|
}
|
|
|
|
ulRet = HttpFilterAppWrite( sm_hFilterHandle,
|
|
_pConnectionInfo->ConnectionId,
|
|
pFilterBuffer,
|
|
pFilterBuffer->BufferSize,
|
|
pcbWritten,
|
|
fAsync ? QueryAppWriteOverlapped() : NULL );
|
|
|
|
if ( fAsync )
|
|
{
|
|
if ( ulRet != ERROR_IO_PENDING )
|
|
{
|
|
DereferenceUlContext();
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ulRet != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE DoAppWrite( async:%d, bytes:%d, buffertype:%d ) hr=0x%x\n",
|
|
fAsync,
|
|
pFilterBuffer->BufferSize,
|
|
pFilterBuffer->BufferType,
|
|
hr
|
|
));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::DoRawRead(
|
|
DWORD dwFlags,
|
|
PVOID pvBuffer,
|
|
DWORD cbBuffer,
|
|
DWORD * pcbWritten
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read some bytes from the wire
|
|
|
|
Arguments:
|
|
|
|
dwFlags - UL_CONTEXT_ASYNC for async
|
|
pvBuffer - buffer
|
|
cbBuffer - bytes in buffer
|
|
pcbWritten - Bytes written
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
BOOL fAsync = !!( dwFlags & UL_CONTEXT_FLAG_ASYNC );
|
|
ULONG ulRet = ERROR_SUCCESS;
|
|
HRESULT hr = NO_ERROR;
|
|
DWORD cbImmediate = 0;
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER DoRawRead( async:%d )\n",
|
|
fAsync
|
|
));
|
|
}
|
|
|
|
if ( fAsync )
|
|
{
|
|
ReferenceUlContext();
|
|
}
|
|
|
|
ulRet = HttpFilterRawRead( sm_hFilterHandle,
|
|
_pConnectionInfo->ConnectionId,
|
|
pvBuffer,
|
|
cbBuffer,
|
|
pcbWritten,
|
|
fAsync ? QueryRawReadOverlapped() : NULL );
|
|
|
|
if ( fAsync )
|
|
{
|
|
if ( ulRet != ERROR_IO_PENDING )
|
|
{
|
|
DereferenceUlContext();
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ulRet != NO_ERROR )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
}
|
|
}
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE DoRawRead( async:%d )\n",
|
|
fAsync
|
|
));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
UL_CONTEXT::StartClose(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start the process of closing the connection (and cleaning up UL_CONTEXT)
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
BOOL fOld;
|
|
|
|
fOld = (BOOL) InterlockedCompareExchange( (PLONG) &_fCloseConnection,
|
|
TRUE,
|
|
FALSE );
|
|
|
|
if ( fOld == FALSE )
|
|
{
|
|
HttpFilterClose( sm_hFilterHandle,
|
|
_pConnectionInfo->ConnectionId,
|
|
NULL );
|
|
|
|
#ifdef ISAPI
|
|
//
|
|
// Notify ISAPIs of the close
|
|
//
|
|
|
|
if ( g_pStreamFilter->QueryNotifyISAPIFilters() )
|
|
{
|
|
DBG_ASSERT( _pISAPIContext != NULL );
|
|
|
|
_pISAPIContext->ProcessConnectionClose();
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// We were the ones to set the flag. Do the final dereference
|
|
//
|
|
|
|
DereferenceUlContext();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Someone else has set the flag. Let them dereference
|
|
//
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::Create(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a UL_CONTEXT
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
DBG_ASSERT( _pSSLContext == NULL );
|
|
#ifdef ISAPI
|
|
DBG_ASSERT( _pISAPIContext == NULL );
|
|
#endif
|
|
|
|
_pSSLContext = new SSL_STREAM_CONTEXT( this );
|
|
if ( _pSSLContext == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
#ifdef ISAPI
|
|
DBG_ASSERT( g_pStreamFilter != NULL );
|
|
if ( g_pStreamFilter->QueryNotifyISAPIFilters() )
|
|
{
|
|
_pISAPIContext = new ISAPI_STREAM_CONTEXT( this );
|
|
if ( _pISAPIContext == NULL )
|
|
{
|
|
delete _pSSLContext;
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::DoAccept(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Accept an incoming connection by calling UlFilterAccept()
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ULONG ulRet;
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
ReferenceUlContext();
|
|
|
|
ulRet = HttpFilterAccept( sm_hFilterHandle,
|
|
_pConnectionInfo,
|
|
_buffConnectionInfo.QuerySize(),
|
|
NULL,
|
|
QueryRawReadOverlapped() );
|
|
|
|
if ( ulRet != ERROR_IO_PENDING )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
|
|
DereferenceUlContext();
|
|
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Error calling UlFilterAccept(). hr = %x\n",
|
|
hr ));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Another outstanding context available!
|
|
//
|
|
|
|
InterlockedIncrement( &sm_cOutstandingContexts );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UL_CONTEXT::SendDataBack(
|
|
RAW_STREAM_INFO * pRawStreamInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sends given data back to client, while going with the ssl filter
|
|
if necessary
|
|
|
|
Arguments:
|
|
|
|
pRawStreamInfo - Raw data to send back
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr;
|
|
BOOL fComplete;
|
|
|
|
if ( pRawStreamInfo == NULL )
|
|
{
|
|
DBG_ASSERT( FALSE );
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
DBG_ASSERT( _pSSLContext != NULL );
|
|
|
|
//
|
|
// ISAPI filter has sent back some data in a raw notification.
|
|
// Have SSL process it and then send it here
|
|
//
|
|
|
|
return _pSSLContext->SendDataBack( pRawStreamInfo );
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
UL_CONTEXT::Initialize(
|
|
LPWSTR SslFilterChannelName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Global Initialization
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
ULONG ulRet = ERROR_SUCCESS;
|
|
HRESULT hr = NO_ERROR;
|
|
BOOL fRet = FALSE;
|
|
//
|
|
// Get a UL handle to the RawStreamPool (or whatever)
|
|
//
|
|
|
|
ulRet = HttpCreateFilter( &sm_hFilterHandle,
|
|
SslFilterChannelName,
|
|
NULL,
|
|
HTTP_OPTION_OVERLAPPED );
|
|
if ( ulRet != ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// W3SSL service may have created Filter already
|
|
// try just open it then
|
|
//
|
|
ulRet = HttpOpenFilter( &sm_hFilterHandle,
|
|
SslFilterChannelName,
|
|
HTTP_OPTION_OVERLAPPED );
|
|
if ( ulRet != ERROR_SUCCESS )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ulRet );
|
|
goto Finished;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create private thread pool for streamfilt
|
|
//
|
|
|
|
fRet = THREAD_POOL::CreateThreadPool(&sm_pThreadPool);
|
|
if (FALSE == fRet)
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Failed to create ThreadPool for Streamfilt\n" ));
|
|
|
|
hr = E_FAIL;
|
|
goto Finished;
|
|
}
|
|
|
|
DBG_ASSERT( sm_pThreadPool != NULL );
|
|
|
|
//
|
|
// Associate a completion routine with the thread pool
|
|
//
|
|
|
|
DBG_ASSERT( sm_hFilterHandle != INVALID_HANDLE_VALUE );
|
|
DBG_ASSERT( sm_hFilterHandle != NULL );
|
|
|
|
if ( !sm_pThreadPool->BindIoCompletionCallback( sm_hFilterHandle,
|
|
OverlappedCompletionRoutine,
|
|
0 ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
goto Finished;
|
|
}
|
|
|
|
INITIALIZE_CRITICAL_SECTION( &sm_csUlContexts );
|
|
InitializeListHead( &sm_ListHead );
|
|
|
|
//
|
|
// Keep a set number of filter accepts outstanding
|
|
//
|
|
|
|
sm_cDesiredOutstanding = UL_CONTEXT_DESIRED_OUTSTANDING;
|
|
|
|
#if DBG
|
|
sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
|
|
#endif
|
|
|
|
Finished:
|
|
if ( FAILED( hr ) )
|
|
{
|
|
if ( sm_hFilterHandle != NULL )
|
|
{
|
|
CloseHandle( sm_hFilterHandle );
|
|
sm_hFilterHandle = NULL;
|
|
}
|
|
if ( sm_pThreadPool != NULL )
|
|
{
|
|
sm_pThreadPool->TerminateThreadPool();
|
|
sm_pThreadPool = NULL;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
UL_CONTEXT::Terminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Global termination
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( sm_pTraceLog != NULL )
|
|
{
|
|
DestroyRefTraceLog( sm_pTraceLog );
|
|
sm_pTraceLog = NULL;
|
|
}
|
|
|
|
if ( sm_hFilterHandle != NULL )
|
|
{
|
|
CloseHandle( sm_hFilterHandle );
|
|
sm_hFilterHandle = NULL;
|
|
}
|
|
|
|
if ( sm_pThreadPool != NULL )
|
|
{
|
|
sm_pThreadPool->TerminateThreadPool();
|
|
sm_pThreadPool = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection( &sm_csUlContexts );
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
UL_CONTEXT::WaitForContextDrain(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait for all contexts to go away
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
while ( sm_cUlContexts != 0 )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Waiting for %d UL_CONTEXTs to drain\n",
|
|
sm_cUlContexts ));
|
|
|
|
Sleep( 1000 );
|
|
}
|
|
|
|
//
|
|
// there should be no outstanding contexts left
|
|
//
|
|
|
|
DBG_ASSERT( sm_cOutstandingContexts == 0 );
|
|
|
|
}
|
|
|
|
//static
|
|
VOID
|
|
UL_CONTEXT::StopListening(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop listening and wait for contexts to drain
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CloseHandle( sm_hFilterHandle );
|
|
sm_hFilterHandle = NULL;
|
|
|
|
WaitForContextDrain();
|
|
}
|
|
|
|
//static
|
|
HRESULT
|
|
UL_CONTEXT::ManageOutstandingContexts(
|
|
VOID
|
|
)
|
|
{
|
|
LONG cRequired;
|
|
UL_CONTEXT * pContext;
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
if ( sm_cOutstandingContexts < sm_cDesiredOutstanding )
|
|
{
|
|
cRequired = sm_cDesiredOutstanding - sm_cOutstandingContexts;
|
|
|
|
//
|
|
// Make sure the value is not negative
|
|
//
|
|
|
|
cRequired = max( 0, cRequired );
|
|
|
|
for ( LONG i = 0; i < cRequired; i++ )
|
|
{
|
|
pContext = new UL_CONTEXT();
|
|
if ( pContext == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
break;
|
|
}
|
|
|
|
hr = pContext->Create();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pContext->DereferenceUlContext();
|
|
break;
|
|
}
|
|
|
|
hr = pContext->DoAccept();
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pContext->DereferenceUlContext();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
OverlappedCompletionRoutine(
|
|
DWORD dwErrorCode,
|
|
DWORD dwNumberOfBytesTransfered,
|
|
LPOVERLAPPED lpOverlapped
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Magic completion routine
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
OVERLAPPED_CONTEXT * pContextOverlapped = NULL;
|
|
HRESULT hr;
|
|
|
|
DBG_ASSERT( lpOverlapped != NULL );
|
|
|
|
pContextOverlapped = CONTAINING_RECORD( lpOverlapped,
|
|
OVERLAPPED_CONTEXT,
|
|
_Overlapped );
|
|
|
|
DBG_ASSERT( pContextOverlapped != NULL );
|
|
|
|
pContextOverlapped->QueryContext()->ReferenceUlContext();
|
|
|
|
//
|
|
// Make up for reference which posted async operation in first place
|
|
//
|
|
|
|
pContextOverlapped->QueryContext()->DereferenceUlContext();
|
|
|
|
//
|
|
// Call the appropriate completion routine
|
|
//
|
|
|
|
switch( pContextOverlapped->QueryType() )
|
|
{
|
|
case OVERLAPPED_CONTEXT_RAW_READ:
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER OnRawReadCompletion( bytes:%d, dwErr:%d )\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode
|
|
));
|
|
}
|
|
|
|
hr = pContextOverlapped->QueryContext()->OnRawReadCompletion(
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode );
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE OnRawReadCompletion( bytes:%d, dwErr:%d ) hr=0x%x\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode,
|
|
hr
|
|
));
|
|
}
|
|
break;
|
|
|
|
case OVERLAPPED_CONTEXT_RAW_WRITE:
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER OnRawWriteCompletion( bytes:%d, dwErr:%d )\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode
|
|
));
|
|
}
|
|
|
|
hr = pContextOverlapped->QueryContext()->OnRawWriteCompletion(
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode );
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE OnRawWriteCompletion( bytes:%d, dwErr:%d ) hr=0x%x\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode,
|
|
hr
|
|
));
|
|
}
|
|
break;
|
|
|
|
case OVERLAPPED_CONTEXT_APP_READ:
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER OnAppReadCompletion( bytes:%d, dwErr:%d )\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode
|
|
));
|
|
}
|
|
|
|
hr = pContextOverlapped->QueryContext()->OnAppReadCompletion(
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode );
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE OnAppReadCompletion ( bytes:%d, dwErr:%d ) hr=0x%x\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode,
|
|
hr
|
|
));
|
|
}
|
|
|
|
break;
|
|
|
|
case OVERLAPPED_CONTEXT_APP_WRITE:
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"ENTER OnAppWriteCompletion( bytes:%d, dwErr:%d )\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode
|
|
));
|
|
}
|
|
|
|
hr = pContextOverlapped->QueryContext()->OnAppWriteCompletion(
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode );
|
|
|
|
IF_DEBUG( APP_RAW_READWRITE )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"LEAVE OnAppWriteCompletion( bytes:%d, dwErr:%d ) hr=0x%x\n",
|
|
dwNumberOfBytesTransfered,
|
|
dwErrorCode,
|
|
hr
|
|
));
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
|
|
DBG_ASSERT( FALSE );
|
|
}
|
|
|
|
//
|
|
// As long as completion routine returned success, just bail. However,
|
|
// if not then we should begin the process of closing connection
|
|
//
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
pContextOverlapped->QueryContext()->StartClose();
|
|
}
|
|
|
|
pContextOverlapped->QueryContext()->DereferenceUlContext();
|
|
}
|
|
|