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.
466 lines
11 KiB
466 lines
11 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|