Leaked source code of windows server 2003
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.
 
 
 
 
 
 

359 lines
8.8 KiB

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation
//
// File: ktcore.cxx
//
// Contents: Kerberos Tunneller, core service thread routines
//
// History: 28-Jun-2001 t-ryanj Created
//
//------------------------------------------------------------------------
#include "ktdebug.h"
#include "ktcore.h"
#include "ktcontrol.h"
#include "ktcontext.h"
#include "ktsock.h"
#include "kthttp.h"
#include "ktkerb.h"
VOID
KtDispatchPerContext(
PKTCONTEXT pContext
);
//+-------------------------------------------------------------------------
//
// Function: KtThreadCore
//
// Synopsis: Main loop for service threads.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
VOID
KtThreadCore(
VOID
)
{
ULONG_PTR CompKey;
LPOVERLAPPED pOverlapped = NULL;
PKTCONTEXT pContext = NULL;
DWORD IocpBytes;
BOOL IocpSuccess;
DWORD IocpError;
//
// Here's the main service loop. It ends when the service is stopped.
//
while( !KtIsStopped() )
{
//
// Wait for a task to queue on the completion port.
//
IocpSuccess = GetQueuedCompletionStatus( KtIocp,
&IocpBytes,
&CompKey,
&pOverlapped,
INFINITE );
//
// Extrapolate the address of the context from the address of the
// overlapped struct.
//
if( pOverlapped )
{
pContext = CONTAINING_RECORD( pOverlapped,
KTCONTEXT,
ol );
}
//
// If there's an error on the Iocp, release any associated context if possible.
//
if( !IocpSuccess )
{
/* TODO: Event Log. */
DebugLog( DEB_ERROR, "%s(%d): Error from GetQueuedCompletionStatus: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
if( pContext )
{
DebugLog( DEB_TRACE, "%s(%d): Releasing context due to GQCS error.\n", __FILE__, __LINE__ );
KtReleaseContext( pContext );
}
else
{
DebugLog( DEB_TRACE, "%s(%d): No completion packet dequeued.\n", __FILE__, __LINE__ );
}
//
// Any completion key we have is invalid, so skip back to top of loop.
//
continue;
}
//
// Dispatch the task to the appropriate routine.
//
switch( CompKey )
{
case KTCK_SERVICE_CONTROL:
//
// The specific control event was passed on the bytes argument.
//
KtServiceControlEvent(IocpBytes);
break;
case KTCK_CHECK_CONTEXT:
//
// The context may not exist. If the service is shutting down, it closes
// all pending connections, which will cause completion to be posted,
// but since the context has already been destroyed, there's nothing to do.
//
if( pContext )
KtDispatchPerContext(pContext);
break;
default:
DebugLog( DEB_WARN, "%s(%d): Unhandled case: 0x%x.\n", __FILE__, __LINE__, CompKey );
break;
}
}
}
//+-------------------------------------------------------------------------
//
// Function: KtDispatchPerContext
//
// Synopsis: This routine handles the sequence of events that happen
// over the lifetime of a connection.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
VOID
KtDispatchPerContext(
PKTCONTEXT pContext
)
{
switch( pContext->Status )
{
case KT_SOCK_CONNECT:
//
// First we need to prepare to accept other connections.
// If we can't accept more incoming connections, this will
// impact the entire service.
//
DebugLog( DEB_TRACE, "----==== Preparing to accept new connection ====----\n" );
if( !KtSockAccept() )
goto SvcError;
//
// Now we can complete the acceptance of the socket that
// connected, then issue a read on that socket. If something
// goes wrong here, we'll close the session.
//
if( !KtSockCompleteAccept(pContext) )
goto SessError;
if( !KtSockRead(pContext) )
goto SessError;
break;
case KT_SOCK_READ:
//
// pContext->ol.InternalHigh holds the bytes transferred after a
// socket operation. If it's zero, the other side has closed the
// connection.
//
if( !pContext->ol.InternalHigh )
goto SessError;
pContext->emptybuf->bytesused = (ULONG)pContext->ol.InternalHigh;
DebugLog( DEB_PEDANTIC, "%s(%d): %d bytes read from loopback.\n", __FILE__, __LINE__, pContext->emptybuf->bytesused );
//
// If we don't know how many bytes to look for yet, figure it out.
//
if( pContext->ExpectedLength == 0 )
{
if( !KtParseExpectedLength( pContext ) )
goto SessError;
DebugLog( DEB_TRACE, "%s(%d): Expected message length: %d.\n", __FILE__, __LINE__, pContext->ExpectedLength );
}
pContext->TotalBytes += pContext->emptybuf->bytesused;
//
// If there might be more to read, get more space and try to read more,
// otherwise, coalesce everything we've read into one mammoth buffer,
// then send that.
//
if( pContext->ExpectedLength > pContext->TotalBytes )
{
if( !KtGetMoreSpace( pContext, KTCONTEXT_BUFFER_LENGTH ) )
goto SessError;
if( !KtSockRead(pContext) )
goto SessError;
}
else
{
DebugLog( DEB_TRACE, "%s(%d): %d bytes total read from loopback.\n", __FILE__, __LINE__, pContext->TotalBytes );
if( !KtCoalesceBuffers( pContext ) )
goto SessError;
if( !KtFindProxy(pContext) )
goto SessError;
if( !KtHttpWrite(pContext) )
goto SessError;
}
break;
case KT_HTTP_WRITE:
//
// And now we read the response to our request.
//
pContext->ExpectedLength = 0;
pContext->TotalBytes = 0;
if( !KtHttpRead(pContext) )
goto SessError;
break;
case KT_HTTP_READ:
DebugLog( DEB_PEDANTIC, "%s(%d): %d bytes read from http.\n", __FILE__, __LINE__, pContext->emptybuf->bytesused );
if( pContext->emptybuf->bytesused == 0 )
{
DebugLog( DEB_TRACE, "%s(%d): Data incomplete. Dropping connection.\n", __FILE__, __LINE__ );
goto SessError;
}
//
// If we don't know how many bytes to look for yet, figure it out.
//
if( pContext->ExpectedLength == 0 )
{
if( !KtParseExpectedLength( pContext ) )
goto SessError;
DebugLog( DEB_TRACE, "%s(%d): Expected message length: %d.\n", __FILE__, __LINE__, pContext->ExpectedLength );
}
//
// Update the byte count
//
pContext->TotalBytes += pContext->emptybuf->bytesused;
//
// If we're expecting more, get more space and try to read more,
// otherwise, coalesce everything we've read into one mammoth buffer,
// relay that response back to our client.
//
if( pContext->ExpectedLength > pContext->TotalBytes )
{
if( !KtGetMoreSpace( pContext, KTCONTEXT_BUFFER_LENGTH ) )
goto SessError;
if( !KtHttpRead(pContext) )
goto SessError;
}
else
{
DebugLog( DEB_TRACE, "%s(%d): %d total bytes read from http.\n", __FILE__, __LINE__, pContext->TotalBytes );
if( !KtCoalesceBuffers(pContext) )
goto SessError;
//
// If this is a debug build, let's generate some debug spew if
// we get a kerb-error as a reply to one of our requests.
//
#if DBG
KtParseKerbError(pContext);
#endif
if( !KtSockWrite(pContext) )
goto SessError;
}
break;
case KT_SOCK_WRITE:
//
// Once we've finished relaying our whole request-reponse pair,
// we're done with this session.
//
DebugLog( DEB_TRACE, "%s(%d): %d bytes written to loopback.\n", __FILE__, __LINE__, pContext->ol.InternalHigh );
KtReleaseContext(pContext);
break;
default:
DebugLog( DEB_WARN, "%s(%d): Unhandled case: 0x%x.\n", __FILE__, __LINE__, pContext->Status );
DsysAssert( pContext->Status == KT_SOCK_CONNECT ||
pContext->Status == KT_SOCK_READ ||
pContext->Status == KT_HTTP_WRITE ||
pContext->Status == KT_HTTP_READ ||
pContext->Status == KT_SOCK_WRITE );
break;
}
return;
SessError:
DebugLog( DEB_TRACE, "%s(%d): Dropping connection due to session error.\n", __FILE__, __LINE__ );
KtReleaseContext(pContext);
return;
SvcError:
/* TODO: Event log. Pause service??? */
return;
}