⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_trans.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						Network Stream Transport Functions					*
*						Copyright Peter Gutmann 1993-2007					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "stream_int.h"
#else
  #include "io/stream_int.h"
#endif /* Compiler-specific includes */

#ifdef USE_TCP

/* Network streams can work on multiple levels.  At the lowest level we have
   the raw network I/O layer, handled by calling setAccessMethodXXX(), which
   hooks up the transport-level I/O functions.  If there's a requirement to
   replace the built-in network I/O it can be done by replacing the
   functionality at this level.

   Layered on top of the transport-level I/O via setStreamLayerXXX() is an
   optional higher layer protocol such as HTTP which is added by calling
   the appropriate function to layer the higher-level protocol over the
   transport-level I/O.  Alternatively, we can use setStreamLayerDirect()
   to just pass the call straight down to the transport layer.

   In addition to these two layers the higher level read requires an extra
   buffering layer in order to avoid making repeated calls to the transport-
   level I/O function, which is a particular problem for HTTP which has to
   take input a character at a time.  To avoid this issue we use the
   bufferedRead layer which reads ahead as far as it can and then feeds the
   buffered result back to the caller as required.  We also need to use write
   buffering to avoid potential problems with interactions with some
   transport layers, details are given in the comment for the buffered write
   function.

   The layering looks as follows:

	--- httpRead ---+-- bufferedRead ---+--- tcpRead
		cmpRead							|
										+--- clibRead
										|
	------------------------------------+--- otherRead

	--- httpWrite --+-- bufferedWrite --+---- tcpWrite
		cmpWrite						|
										+---- clibWrite
										|
	------------------------------------+---- otherWrite */

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Sanity-check the stream state */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheckFunction( const STREAM *stream )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	/* Make sure that it's an initialised network stream with valid 
	   parameters */
	if( stream->type != STREAM_TYPE_NETWORK || \
		stream->netStreamInfo == NULL )
		return( FALSE );
	if( netStream->timeout < 0 || netStream->timeout > 300 )
		return( FALSE );

	/* It's an unbuffered network stream, all buffer values must be zero */
	if( stream->buffer != NULL || stream->bufPos != 0 || \
		stream->bufSize != 0 || stream->bufEnd != 0 )
		return( FALSE );
	if( netStream->writeBuffer != NULL || netStream->writeBufSize != 0 || \
		netStream->writeBufEnd != 0 )
		return( FALSE );

	return( TRUE );
	}

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN sanityCheckBufferedFunction( const STREAM *stream )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isReadPtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	/* Make sure that it's an initialised network stream with valid 
	   parameters */
	if( stream->type != STREAM_TYPE_NETWORK || \
		stream->netStreamInfo == NULL )
		return( FALSE );
	if( netStream->timeout < 0 || netStream->timeout > 300 )
		return( FALSE );

	/* Make sure that the buffer position is within bounds:

								 bufSize
									|
			<------ buffer ------>	v
		+---------------------------+
		|						|	|
		+---------------------------+
				^				^
				|				|
			 bufPos			 bufEnd */
	if( stream->bufPos < 0 || stream->bufPos > stream->bufEnd || \
		stream->bufEnd < 0 || stream->bufEnd > stream->bufSize || \
		stream->bufSize <= 0 || stream->bufSize >= MAX_INTLENGTH )
		return( FALSE );

	/* Network streams have a second buffer used for writes, make sure that 
	   the write buffer position is within bounds */
	if( netStream->writeBuffer == NULL || \
		netStream->writeBufSize <= 0 || \
		netStream->writeBufSize >= MAX_INTLENGTH )
		return( FALSE );
	if( netStream->writeBufEnd < 0 || \
		netStream->writeBufEnd > netStream->writeBufSize )
		return( FALSE );

	return( TRUE );
	}

/****************************************************************************
*																			*
*					Transport-layer Direct Access Functions					*
*																			*
****************************************************************************/

/* Map the upper-layer I/O functions directly to the transport-layer
   equivalent.  This is used if we're performing raw I/O without any
   intermediate protocol layers or buffering */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int transportDirectReadFunction( INOUT STREAM *stream, 
										OUT_BUFFER( maxLength, *length ) \
											void *buffer, 
										IN_LENGTH const int maxLength, 
										OUT_LENGTH_Z int *length )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( buffer, maxLength ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_S( netStream->sanityCheckFunction( stream ) );
	REQUIRES_S( maxLength > 0 && maxLength < MAX_INTLENGTH );

	return( netStream->transportReadFunction( stream, buffer, maxLength, 
											  length,
											  TRANSPORT_FLAG_NONE ) );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int transportDirectWriteFunction( INOUT STREAM *stream, 
										 IN_BUFFER( length ) const void *buffer, 
										 IN_LENGTH const int maxLength,
										 OUT_LENGTH_Z int *length )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( buffer, maxLength ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_S( netStream->sanityCheckFunction( stream ) );
	REQUIRES_S( maxLength > 0 && maxLength < MAX_INTLENGTH );

	return( netStream->transportWriteFunction( stream, buffer, maxLength, 
											   length,
											   TRANSPORT_FLAG_NONE ) );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void setStreamLayerDirect( INOUT NET_STREAM_INFO *netStream )
	{
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	netStream->writeFunction = transportDirectWriteFunction;
	netStream->readFunction = transportDirectReadFunction;
	}

/****************************************************************************
*																			*
*					Transport-layer Session Access Functions				*
*																			*
****************************************************************************/

/* This facility is currently unused so we disable it to avoid inadvertent 
   use by users who try to play with undocumented features.  Note that when
   enabling it it'll be necessary to change the annotation for the connect
   function in stream.h since the parameters are currently marked as
   STDC_NONNULL_ARG */

#if 0

/* Send and receive data with a cryptlib session as the transport layer */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int transportSessionConnectFunction( INOUT STREAM *stream,
											STDC_UNUSED const char *host, 
											STDC_UNUSED const int hostLen,
											STDC_UNUSED const int port )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
	int isActive, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
	
	REQUIRES_S( netStream->sanityCheckFunction( stream ) );
	REQUIRES_S( host == NULL && hostLen == 0 );
	REQUIRES_S( port == 0 );

	/* If the transport session hasn't been activated yet, activate it now */
	status = krnlSendMessage( netStream->iTransportSession,
							  IMESSAGE_GETATTRIBUTE, &isActive,
							  CRYPT_SESSINFO_ACTIVE );
	if( cryptStatusOK( status ) && isActive )
		{
		/* The session has been activated, there's nothing to do */
		return( CRYPT_OK );
		}
	status = krnlSendMessage( netStream->iTransportSession,
							  IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_TRUE,
							  CRYPT_SESSINFO_ACTIVE );
	if( cryptStatusError( status ) )
		return( getSessionErrorInfo( stream, status ) );
	return( CRYPT_OK );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
static void transportSessionDisconnectFunction( INOUT STREAM *stream,
												const BOOLEAN fullDisconnect )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_V( netStream->sanityCheckFunction( stream ) );

	krnlSendNotifier( netStream->iTransportSession, IMESSAGE_DECREFCOUNT );
	}

CHECK_RETVAL_BOOL \
static BOOLEAN transportSessionOKFunction( void )
	{
	return( TRUE );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int transportSessionReadFunction( INOUT STREAM *stream, 
										 OUT_BUFFER( maxLength, *length ) \
											BYTE *buffer, 
										 IN_LENGTH const int maxLength, 
										 OUT_LENGTH_Z int *length, 
										 IN_FLAGS_Z( TRANSPORT ) const int flags )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
	MESSAGE_DATA msgData;
	int newTimeout = CRYPT_UNUSED, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( buffer, maxLength ) );
	assert( isWritePtr( length, sizeof( int ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_S( stream->sanityCheckFunction( stream ) );
	REQUIRES_S( maxLength > 0 && maxLength < MAX_INTLENGTH );
	REQUIRES_S( flags >= TRANSPORT_FLAG_NONE && \
				flags <= TRANSPORT_FLAG_MAX );

	/* Clear return value */
	*length = 0;

	/* Read data from the session, overriding the timeout handling if
	   requested */
	if( ( flags & TRANSPORT_FLAG_NONBLOCKING ) && netStream->timeout > 0 )
		newTimeout = 0;
	else
		{
		if( ( flags & TRANSPORT_FLAG_BLOCKING ) && netStream->timeout == 0 )
			newTimeout = 30;
		}
	if( newTimeout != CRYPT_UNUSED )
		( void ) krnlSendMessage( netStream->iTransportSession, 
								  IMESSAGE_SETATTRIBUTE, &newTimeout, 
								  CRYPT_OPTION_NET_READTIMEOUT );
	setMessageData( &msgData, buffer, maxLength );
	status = krnlSendMessage( netStream->iTransportSession, 
							  IMESSAGE_ENV_POPDATA, &msgData, 0 );
	if( newTimeout != CRYPT_UNUSED )
		( void ) krnlSendMessage( netStream->iTransportSession, 
								  IMESSAGE_SETATTRIBUTE, &stream->timeout, 
								  CRYPT_OPTION_NET_READTIMEOUT );
	if( cryptStatusError( status ) )
		return( getSessionErrorInfo( stream, status ) );
	if( msgData.length < maxLength )
		{
		retExt( CRYPT_ERROR_READ,
				( CRYPT_ERROR_READ, NETSTREAM_ERRINFO, 
				  "Only read %d out of %d bytes via cryptlib session "
				  "object", msgData.length, maxLength ) );
		}
	*length = maxLength;

	return( CRYPT_OK );
	}

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int transportSessionWriteFunction( INOUT STREAM *stream, 
										  IN_BUFFER( length ) const BYTE *buffer, 
										  IN_LENGTH const int maxLength, 
										  OUT_LENGTH_Z int *length,
										  IN_FLAGS_Z( TRANSPORT ) \
											const int flags )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
	MESSAGE_DATA msgData;
	int status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( buffer, maxLength ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_S( netStream->sanityCheckFunction( stream ) );
	REQUIRES_S( maxLength > 0 && maxLength < MAX_INTLENGTH );
	REQUIRES_S( flags >= TRANSPORT_FLAG_NONE && \
				flags <= TRANSPORT_FLAG_MAX );

	/* Clear return value */
	*length = 0;

	setMessageData( &msgData, ( void * ) buffer, maxLength );
	status = krnlSendMessage( netStream->iTransportSession,
							  IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
	if( cryptStatusOK( status ) )
		{
		setMessageData( &msgData, NULL, 0 );
		status = krnlSendMessage( netStream->iTransportSession,
								  IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
		}
	if( cryptStatusError( status ) )
		return( getSessionErrorInfo( stream, status ) );
	*length = maxLength;

	return( CRYPT_OK );
	}

void setAccessMethodTransportSession( INOUT STREAM *stream )
	{
	NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );

	REQUIRES_V( stream->type == STREAM_TYPE_NETWORK );

	netStream->transportConnectFunction = transportSessionConnectFunction;
	netStream->transportDisconnectFunction = transportSessionDisconnectFunction;
	netStream->transportWriteFunction = transportSessionWriteFunction;
	netStream->transportReadFunction = transportSessionReadFunction;
	netStream->transportOKFunction = transportSessionOKFunction;
	}
#endif /* 0 */

/****************************************************************************
*																			*
*								Buffering Functions							*
*																			*
****************************************************************************/

/* Buffered transport-layer read function.  This sits on top of the
   transport-layer read function and performs speculative read-ahead
   buffering to improve performance in protocols such as HTTP that have to
   read a byte at a time in places:

		   bPos		   bEnd
			|			|
			v			v
	+-------+-----------+-------+

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -