|
|
//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation
//
// File: ktcontext.cxx
//
// Contents: Kerberos Tunneller, context management routines
//
// History: 28-Jun-2001 t-ryanj Created
//
//------------------------------------------------------------------------
#include "ktcontext.h"
#include "ktmem.h"
//
// We keep track of our contexts in a list, so that we
// can shut down all our connections when we're asked to close.
//
PKTCONTEXT KtContextList = NULL;
//
// This critsec will guarantee mutual exclusion on the context list.
//
BOOL KtContextListCritSecInit = FALSE; CRITICAL_SECTION KtContextListCritSec;
//+-------------------------------------------------------------------------
//
// Function: KtInitContexts
//
// Synopsis: Does anything necessary to make ready to acquire and
// release contexts
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns: Success value. If FALSE, GetLastError() for more info.
//
// Notes:
//
//
//--------------------------------------------------------------------------
BOOL KtInitContexts( VOID ) { BOOL fRet = TRUE;
//
// All we need to do is initialize our critsec
//
__try { InitializeCriticalSectionAndSpinCount( &KtContextListCritSec, 4000 ); KtContextListCritSecInit = TRUE; } __except( EXCEPTION_EXECUTE_HANDLER ) { DebugLog( DEB_ERROR, "%s(%d): InitializeCriticalSectionAndSpinCount raised an exception.\n", __FILE__, __LINE__ ); goto Error; }
Cleanup: return fRet;
Error: fRet = FALSE; goto Cleanup; }
//+-------------------------------------------------------------------------
//
// Function: KtCleanupContexts
//
// Synopsis: Cleans up any trash left by the context routines.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID KtCleanupContexts( VOID ) { //
// As we release the context at the head of the list, it will remove
// itself from the list. Hence, we can free the head of the list until
// the entire list is freed.
//
while( KtContextList ) KtReleaseContext(KtContextList);
if( KtContextListCritSecInit ) DeleteCriticalSection(&KtContextListCritSec); }
//+-------------------------------------------------------------------------
//
// Function: KtAcquireContext
//
// Synopsis: Returns a context for use with the session associated with
// the passed in socket.
//
// Effects:
//
// Arguments: sock - socket on which to communicate with the user
// size - size of the initial buffer
//
// Requires:
//
// Returns: The new context, or NULL on failure.
//
// Notes: If fails, GetLastError() for more info.
//
//--------------------------------------------------------------------------
PKTCONTEXT KtAcquireContext( IN SOCKET sock, IN ULONG size ) { PKTCONTEXT pContext = NULL;
DebugLog( DEB_TRACE, "%s(%d): Creating new context.\n", __FILE__, __LINE__ );
//
// Alloc memory for the structure.
//
pContext = (PKTCONTEXT)KtAlloc(sizeof(KTCONTEXT)); if( !pContext ) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); DebugLog( DEB_ERROR, "%s(%d): Error in KtAlloc while trying to alloc a KTCONTEXT.\n", __FILE__, __LINE__ ); goto Error; } ZeroMemory( pContext, sizeof(KTCONTEXT) ); //
// Associate the socket
//
pContext->sock = sock; //
// Make the first read buffer.
//
pContext->buffers = (PKTBUFFER)KtAlloc( sizeof(KTBUFFER) + size ); if( !pContext->buffers ) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); DebugLog( DEB_ERROR, "%s(%d): Error allocating memory for receive buffer.\n", __FILE__, __LINE__ ); goto Error; } pContext->buffers->buflen = size; pContext->buffers->next = NULL; pContext->emptybuf = pContext->buffers;
//
// Wait for mutual exclusion on the socket list
//
__try { EnterCriticalSection(&KtContextListCritSec); } __except( EXCEPTION_EXECUTE_HANDLER ) { DebugLog( DEB_ERROR, "%s(%d): EnterCriticalSection raised an exception.\n", __FILE__, __LINE__ ); goto Error; }
//
// Add to KtContextList.
//
pContext->prev = NULL; pContext->next = KtContextList; if( KtContextList != NULL ) KtContextList->prev = pContext; KtContextList = pContext;
//
// We're done.
//
LeaveCriticalSection(&KtContextListCritSec);
Cleanup: return pContext;
Error: //
// If something goes wrong, don't allocate any memory.
//
if( pContext ) { if( pContext->buffers ) KtFree( pContext->buffers ); KtFree( pContext ); pContext = NULL; } goto Cleanup; }
//+-------------------------------------------------------------------------
//
// Function: KtReleaseContext
//
// Synopsis: Releases a context, signalling the end of the session.
// All resources associated with the context are freed.
//
// Effects:
//
// Arguments: pContext - The context who's session is complete.
//
// Requires:
//
// Returns:
//
// Notes: If pContext is NULL, the call quietly does nothing.
//
//--------------------------------------------------------------------------
VOID KtReleaseContext( IN PKTCONTEXT pContext ) { if( pContext ) { DebugLog( DEB_TRACE, "%s(%d): Releasing context.\n", __FILE__, __LINE__ );
//
// So first close any open connections.
//
if( pContext->sock ) closesocket( pContext->sock ); if( pContext->hRequest ) InternetCloseHandle( pContext->hRequest ); if( pContext->hConnect ) InternetCloseHandle( pContext->hConnect ); //
// Free any buffers
//
while( pContext->buffers ) { PKTBUFFER car = pContext->buffers; pContext->buffers = car->next; KtFree( car ); }
if( pContext->pbProxies ) KtFree( pContext->pbProxies );
//
// Wait for lock on the socklist.
//
__try { EnterCriticalSection(&KtContextListCritSec); } __except( EXCEPTION_EXECUTE_HANDLER ) { DebugLog( DEB_ERROR, "%s(%d): EnterCriticalSection raised an exception.\n", __FILE__, __LINE__ ); /* TODO: Something must be done, here. */ return; }
//
// Remove the structure from KtContextList.
//
if( pContext->prev == NULL ) KtContextList = pContext->next; else pContext->prev->next = pContext->next; if( pContext->next != NULL ) pContext->next->prev = pContext->prev;
//
// Done with list.
//
LeaveCriticalSection(&KtContextListCritSec);
//
// Free the memory
//
KtFree( pContext ); } }
//+-------------------------------------------------------------------------
//
// Function: KtCoalesceBuffers
//
// Synopsis: Coalesces all data buffers from a context into one.
//
// Effects:
//
// Arguments: pContext - The context that has buffers to coalesce.
//
// Requires:
//
// Returns: Success value. Failure indicates an allocation failure.
//
// Notes: At the beginning of this call, there are 'x' buffers in the
// pContext->buffers list. At the end of this call there is a
// sole buffer in this list, holding all the data from the 'x'
// buffers. The pContext->emptybuffer member is also made to
// point at this new buffer, so that it will be reused as the
// first buffer in the next read transaction.
//
//--------------------------------------------------------------------------
BOOL KtCoalesceBuffers( IN PKTCONTEXT pContext ) { PKTBUFFER blist = pContext->buffers; PKTBUFFER bigbuf = NULL; BOOL fSuccess = TRUE; //
// If there's only one buffer, nothing to do.
//
if( !pContext->buffers->next ) return TRUE; //
// Allocate a buffer of appropriate size to hold everything.
//
bigbuf = (PKTBUFFER)KtAlloc( sizeof(KTBUFFER) + pContext->TotalBytes ); if( !bigbuf ) { DebugLog( DEB_ERROR, "%s(%d): Unable to allocate enough memory to coalesce buffers.\n", __FILE__, __LINE__ ); goto Error; } bigbuf->buflen = pContext->TotalBytes; bigbuf->bytesused = 0; bigbuf->next = NULL; //
// Copy everything in.
//
while( blist = pContext->buffers ) { pContext->buffers = blist->next; RtlCopyMemory( bigbuf->buffer + bigbuf->bytesused, blist->buffer, blist->bytesused ); bigbuf->bytesused += blist->bytesused; KtFree( blist ); } DsysAssert( bigbuf->bytesused == pContext->TotalBytes ); //
// This is now the sole buffer in the bufferlist.
//
pContext->buffers = bigbuf; pContext->emptybuf = bigbuf; Cleanup: return fSuccess;
Error: fSuccess = FALSE; goto Cleanup; }
//+-------------------------------------------------------------------------
//
// Function: KtGetMoreSpace
//
// Synopsis: Adds a new buffer to the end of the pContext->buffers list,
// and points the pContext->emptybuf member at it.
//
// Effects:
//
// Arguments: pContext - The context that needs more space.
// size - Amount of space needed.
//
// Requires:
//
// Returns: Success value. Failure indicates an allocation failure.
//
// Notes: As emptybuf is essentially a pointer to the tail of the
// list, the new buffer is tacked onto the list after emptybuf,
// then emptybuf is made to point to the new buffer.
//
//--------------------------------------------------------------------------
BOOL KtGetMoreSpace( IN PKTCONTEXT pContext, IN ULONG size ) { BOOL fRet = TRUE; PKTBUFFER newbuf = NULL;
//
// Allocate a new, empty buffer.
//
newbuf = (PKTBUFFER)KtAlloc( sizeof(KTBUFFER) + size ); if( !newbuf ) { DebugLog( DEB_ERROR, "%s(%d): Error allocating space for transmission buffer.\n", __FILE__, __LINE__ ); goto Error; } newbuf->buflen = (ULONG)size; newbuf->bytesused = 0; newbuf->next = NULL;
//
// Add it to the buffer list.
//
DsysAssert( pContext->emptybuf ); DsysAssert( !pContext->emptybuf->next ); pContext->emptybuf->next = newbuf; pContext->emptybuf = newbuf; Cleanup: return fRet;
Error: fRet = FALSE; goto Cleanup; }
|