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.
387 lines
7.8 KiB
387 lines
7.8 KiB
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name :
|
|
w3conn.cxx
|
|
|
|
Abstract:
|
|
Http Connection management
|
|
|
|
Author:
|
|
Bilal Alam (balam) 6-Jan-2000
|
|
|
|
Environment:
|
|
Win32 - User Mode
|
|
|
|
Project:
|
|
ULW3.DLL
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
ALLOC_CACHE_HANDLER * W3_CONNECTION::sm_pachW3Connections;
|
|
W3_CONNECTION_HASH * W3_CONNECTION::sm_pConnectionTable;
|
|
|
|
W3_CONNECTION::W3_CONNECTION(
|
|
HTTP_CONNECTION_ID connectionId
|
|
)
|
|
: _cRefs( 1 ),
|
|
_pUserContext( NULL ),
|
|
_fConnected( TRUE )
|
|
{
|
|
LK_RETCODE lkrc;
|
|
|
|
_connId = connectionId;
|
|
_dwSignature = W3_CONNECTION_SIGNATURE;
|
|
|
|
ZeroMemory( _rgConnectionState, sizeof( _rgConnectionState ) );
|
|
|
|
IF_DEBUG( CONN )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"New W3_CONNECTION '%p' created\n",
|
|
this ));
|
|
}
|
|
|
|
}
|
|
|
|
W3_CONNECTION::~W3_CONNECTION()
|
|
{
|
|
IF_DEBUG( CONN )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"W3_CONNECTION '%p' deleted\n",
|
|
this ));
|
|
}
|
|
|
|
//
|
|
// Cleanup state associated with connection
|
|
//
|
|
|
|
for ( DWORD i = 0; i < STATE_COUNT; i++ )
|
|
{
|
|
if ( _rgConnectionState[ i ] != NULL )
|
|
{
|
|
_rgConnectionState[ i ]->Cleanup();
|
|
_rgConnectionState[ i ] = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release the user context associated
|
|
//
|
|
|
|
if ( _pUserContext != NULL )
|
|
{
|
|
_pUserContext->DereferenceUserContext();
|
|
_pUserContext = NULL;
|
|
}
|
|
|
|
_dwSignature = W3_CONNECTION_SIGNATURE_FREE;
|
|
}
|
|
|
|
HRESULT
|
|
W3_CONNECTION::Initialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Global W3_CONNECTION initialization
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = NO_ERROR;
|
|
ALLOC_CACHE_CONFIGURATION acConfig;
|
|
|
|
//
|
|
// Initialize allocation lookaside
|
|
//
|
|
|
|
acConfig.nConcurrency = 1;
|
|
acConfig.nThreshold = 100;
|
|
acConfig.cbSize = sizeof( W3_CONNECTION );
|
|
|
|
DBG_ASSERT( sm_pachW3Connections == NULL );
|
|
|
|
sm_pachW3Connections = new ALLOC_CACHE_HANDLER( "W3_CONNECTION",
|
|
&acConfig );
|
|
|
|
if ( sm_pachW3Connections == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
//
|
|
// Allocate table
|
|
//
|
|
|
|
sm_pConnectionTable = new W3_CONNECTION_HASH;
|
|
if ( sm_pConnectionTable == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
VOID
|
|
W3_CONNECTION::Terminate(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroy W3_CONNECTION globals
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( sm_pConnectionTable != NULL )
|
|
{
|
|
delete sm_pConnectionTable;
|
|
sm_pConnectionTable = NULL;
|
|
}
|
|
|
|
delete sm_pachW3Connections;
|
|
sm_pachW3Connections = NULL;
|
|
}
|
|
|
|
HRESULT
|
|
W3_CONNECTION::RetrieveConnection(
|
|
HTTP_CONNECTION_ID ConnectionId,
|
|
BOOL fCreateIfNotFound,
|
|
W3_CONNECTION ** ppConnection
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given, a UL_HTTP_REQUEST (and thus a UL_HTTP_CONNECTION_ID), determine
|
|
whether there is an associated W3_CONNECTION with that ID. If not,
|
|
create a new W3_CONNECTION. This function will also call into ULATQ to
|
|
get an asynchronous notification when the connection goes away.
|
|
|
|
Arguments:
|
|
|
|
ConnectionId - Connection ID
|
|
fCreateIfNotFound - Create if not found in hash table
|
|
ppConnection - Receives a pointer to a W3_CONNECTION for this request
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
{
|
|
W3_CONNECTION * pNewConnection;
|
|
HRESULT hr;
|
|
LK_RETCODE lkrc;
|
|
BOOL fAlreadyDisconnected;
|
|
|
|
DBG_ASSERT( ppConnection != NULL );
|
|
|
|
*ppConnection = NULL;
|
|
|
|
lkrc = sm_pConnectionTable->FindKey( &ConnectionId,
|
|
ppConnection );
|
|
if ( lkrc != LK_SUCCESS )
|
|
{
|
|
if ( !fCreateIfNotFound )
|
|
{
|
|
//
|
|
// Just return out now since the caller doesn't want us to create
|
|
// the connection object
|
|
//
|
|
|
|
return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
|
|
}
|
|
|
|
//
|
|
// Create a new connection object
|
|
//
|
|
|
|
pNewConnection = new W3_CONNECTION( ConnectionId );
|
|
if ( pNewConnection == NULL )
|
|
{
|
|
return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
|
|
}
|
|
|
|
//
|
|
// Insert the object into connection table
|
|
//
|
|
|
|
lkrc = sm_pConnectionTable->InsertRecord( pNewConnection );
|
|
if ( lkrc != LK_SUCCESS )
|
|
{
|
|
delete pNewConnection;
|
|
return HRESULT_FROM_WIN32( lkrc );
|
|
}
|
|
|
|
//
|
|
// Monitor when the connection goes away
|
|
//
|
|
|
|
hr = UlAtqWaitForDisconnect( ConnectionId,
|
|
TRUE,
|
|
pNewConnection,
|
|
&fAlreadyDisconnected );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Error waiting for disconnect of connection '%p'. hr = %x\n",
|
|
pNewConnection,
|
|
hr ));
|
|
|
|
//
|
|
// OK. The connection must have gone away from under us. This
|
|
// is not fatal. It just means that once the state machine has
|
|
// completed, we should immediately destroy the connection
|
|
// object.
|
|
//
|
|
|
|
pNewConnection->RemoveConnection();
|
|
}
|
|
else if ( fAlreadyDisconnected )
|
|
{
|
|
pNewConnection->_fConnected = FALSE;
|
|
}
|
|
|
|
*ppConnection = pNewConnection;
|
|
}
|
|
else
|
|
{
|
|
IF_DEBUG( CONN )
|
|
{
|
|
DBGPRINTF(( DBG_CONTEXT,
|
|
"Request on existing W3_CONNECTION '%p'\n",
|
|
*ppConnection ));
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
VOID
|
|
OnUlDisconnect(
|
|
VOID * pvContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine called when a connection is closed
|
|
|
|
Arguments:
|
|
|
|
pvContext - Points to the W3_CONNECTION which was closed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
W3_CONNECTION * pConnection;
|
|
|
|
DBG_ASSERT( pvContext != NULL );
|
|
|
|
pConnection = (W3_CONNECTION*) pvContext;
|
|
|
|
DBG_ASSERT( pConnection->CheckSignature() );
|
|
|
|
pConnection->RemoveConnection();
|
|
|
|
}
|
|
|
|
VOID
|
|
W3_CONNECTION::ReferenceConnection(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reference the connection (duh)
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
InterlockedIncrement( &_cRefs );
|
|
}
|
|
|
|
VOID
|
|
W3_CONNECTION::DereferenceConnection(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dereference and possibly cleanup the connection
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if ( InterlockedDecrement( &_cRefs ) == 0 )
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
W3_CONNECTION::RemoveConnection(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the connection from the hash table. This will indirectly
|
|
dereference the connection so that it can await final cleanup
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
_fConnected = FALSE;
|
|
sm_pConnectionTable->DeleteRecord( this );
|
|
}
|