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

📄 net.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
*																			*
*						Network Stream I/O Functions						*
*						Copyright Peter Gutmann 1993-2005					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "stream.h"
#elif defined( INC_CHILD )
  #include "stream.h"
#else
  #include "io/stream.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 many 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 problem, 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

   When we allocate the readahead/write buffers we try and make them an 
   optimal size to minimise unnecessary copying and not negatively affect 
   network I/O.  If we make them too big, we'll have to move too much data 
   around when we partially empty them.  If we make them too small, the 
   buffering effect is suboptimal.  Since what we're buffering is PKI 
   traffic, a 4K buffer should get most messages in one go.  This also 
   matches many network stacks that use 4K I/O buffers, the BSD default */

#define NETWORK_BUFFER_SIZE		4096

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

/* Copy error information from a cryptlib transport-layer session into a 
   stream */

static int getSessionErrorInfo( STREAM *stream, const int errorStatus )
	{
	RESOURCE_DATA msgData;
	int status;

	status = krnlSendMessage( stream->iTransportSession,
							  IMESSAGE_GETATTRIBUTE, &stream->errorCode,
							  CRYPT_ATTRIBUTE_INT_ERRORCODE );
	if( cryptStatusError( status ) )
		stream->errorCode = CRYPT_OK;
	setMessageData( &msgData, stream->errorMessage, MAX_ERRMSG_SIZE );
	krnlSendMessage( stream->iTransportSession, IMESSAGE_GETATTRIBUTE, 
					 &msgData, CRYPT_ATTRIBUTE_INT_ERRORMESSAGE );
	return( errorStatus );
	}

/****************************************************************************
*																			*
*							URL Processing Functions						*
*																			*
****************************************************************************/

/* Perform various string-processing operations */

static int strFindCh( const char *str, const int strLen, const char findCh )
	{
	int i;

	for( i = 0; i < strLen; i++ )
		if( str[ i ] == findCh )
			return( i );

	return( -1 );
	}

static int strFindStr( const char *str, const int strLen, 
					   const char *findStr, const int findStrLen )
	{
	const char findCh = *findStr;
	int i;

	for( i = 0; i < strLen - findStrLen; i++ )
		if( str[ i ] == findCh && \
			!strCompare( str + i, findStr, findStrLen ) )
			return( i );

	return( -1 );
	}

static int strStripWhitespace( char **newStringPtr, const char *string, 
							   const int stringLen )
	{
	int startPos, endPos;

	/* Skip leading and trailing whitespace */
	for( startPos = 0; 
		 startPos < stringLen && string[ startPos ] <= ' '; 
		 startPos++ );
	*newStringPtr = ( char * ) string + startPos;
	for( endPos = stringLen; 
		 endPos > startPos && string[ endPos - 1 ] <= ' ';
		 endPos-- );
	return( endPos - startPos );
	}

/* Parse a URI into <schema>://<host>[:<port>]/<path>[?<query>] components */

static int parseURL( URL_INFO *urlInfo, const char *url, const int urlLen,
					 const int defaultPort )
	{
	static const FAR_BSS struct {
		const char *schema;
		const int schemaLength;
		const URL_TYPE type;
		} urlSchemaInfo[] = {
		{ "http://", 7, URL_TYPE_HTTP },
		{ "https://", 8, URL_TYPE_HTTPS },
		{ "ssh://", 6, URL_TYPE_SSH },
		{ "scp://", 6, URL_TYPE_SSH },
		{ "sftp://", 7, URL_TYPE_SSH },
		{ "cmp://", 6, URL_TYPE_CMP },
		{ "tsp://", 6, URL_TYPE_TSP },
		{ NULL, 0, URL_TYPE_NONE }
		};
	char *strPtr;
	int offset, length;

	/* Clear return values */
	memset( urlInfo, 0, sizeof( URL_INFO ) );
	if( defaultPort != CRYPT_UNUSED )
		urlInfo->port = defaultPort;

	/* Skip leading and trailing whitespace and syntactic sugar */
	length = strStripWhitespace( &strPtr, url, urlLen );
	if( length <= 0 )
		return( CRYPT_ERROR_BADDATA );
	if( length >= MAX_URL_SIZE )
		return( CRYPT_ERROR_OVERFLOW );
	if( ( offset = strFindStr( strPtr, length, "://", 3 ) ) >= 0 )
		{
		int i;

		/* Extract the URI schema */
		urlInfo->schema = strPtr;
		urlInfo->schemaLen = offset + 3;
		length -= offset + 3;
		if( length <= 0 )
			return( CRYPT_ERROR_BADDATA );
		strPtr += offset + 3;
		length = strStripWhitespace( &strPtr, strPtr, length );
		if( length <= 0 )
			return( CRYPT_ERROR_BADDATA );

		/* Check whether the schema is one that we recognise */
		for( i = 0; urlSchemaInfo[ i ].type != URL_TYPE_NONE; i++ )
			if( urlSchemaInfo[ i ].schemaLength == urlInfo->schemaLen && \
				!strCompare( urlSchemaInfo[ i ].schema, urlInfo->schema,
							 urlInfo->schemaLen ) )
				break;
		urlInfo->type = urlSchemaInfo[ i ].type;
		}

	/* Check for user info before an '@' sign */
	if( ( offset = strFindCh( strPtr, length, '@' ) ) >= 0 )
		{
		/* Extract the user info */
		urlInfo->userInfoLen = \
					strStripWhitespace( ( char ** ) &urlInfo->userInfo, 
										strPtr, offset );
		length -= offset + 1;
		if( length <= 0 || urlInfo->userInfoLen <= 0 )
			return( CRYPT_ERROR_BADDATA );
		strPtr += offset + 1;
		length = strStripWhitespace( &strPtr, strPtr, length );
		if( length <= 0 )
			return( CRYPT_ERROR_BADDATA );
		}

	/* IPv6 addresses use colons in their string representation, RFC 2732 
	   requires that IPv6 addresses in URLs be delimited by square brackets 
	   so if we find one at the start of the URI we treat it as an IPv6 
	   address */
	if( *strPtr == '[' && \
		( length != 12 || strCompareZ( strPtr, "[Autodetect]" ) ) )
		{
		/* Strip the leading '[' delimiter */
		length = strStripWhitespace( &strPtr, strPtr + 1, length - 1 );
		if( length <= 0 )
			return( CRYPT_ERROR_BADDATA );

		/* Locate the end of the RFC 2732 IPv6 address.  Trailing whitespace
		   will be stripped later */
		if( ( offset = strFindCh( strPtr, length, ']' ) ) <= 0 )
			return( CRYPT_ERROR_BADDATA );
		urlInfo->host = strPtr;
		urlInfo->hostLen = offset;
		strPtr += offset + 1;
		length -= offset + 1;
		}
	else
		{
		int offset2;

		/* It's a non-IPv6 host name, check whether there's anything 
		   following the name */
		urlInfo->host = strPtr;
		offset = strFindCh( strPtr, length, ':' );
		offset2 = strFindCh( strPtr, length, '/' );
		if( offset < 0 )
			offset = offset2;
		else
			{
			assert( offset >= 0 );
			if( offset2 >= 0 )
				offset = min( offset, offset2 );
			}
		if( offset <= 0 )
			{
			/* It's a standalone server name, we're done */
			urlInfo->hostLen = length;
			return( CRYPT_OK );
			}

		/* There's port/location info following the server name.  Trailing 
		   whitespace will be stripped later */
		urlInfo->hostLen = offset;
		strPtr += offset;
		length -= offset;
		}
	urlInfo->hostLen = strStripWhitespace( ( char ** ) &urlInfo->host, 
										   urlInfo->host, urlInfo->hostLen );
	if( urlInfo->hostLen <= 0 )
		return( CRYPT_ERROR_BADDATA );

	/* If there's nothing beyond the host name, we're done */
	if( length <= 0 )
		return( CRYPT_OK );
	length = strStripWhitespace( &strPtr, strPtr, length );
	if( length <= 0 )
		return( CRYPT_ERROR_BADDATA );

	/* Parse the remainder of the URI into port/location */
	if( *strPtr == ':' )
		{
		char portBuffer[ 16 ];
		const int portStrLen = min( length - 1, 15 );
		int port;

		/* Get the port to connect to.  If it's an invalid port we ignore it
		   and use the default one, which was set earlier */
		if( portStrLen <= 0 )
			return( CRYPT_ERROR_BADDATA );
		memcpy( portBuffer, strPtr + 1, portStrLen );
		portBuffer[ portStrLen ] = '\0';
		port = aToI( portBuffer );
		if( port >= 22 && port < 65535 )
			urlInfo->port = port;
		}
	if( ( offset = strFindCh( strPtr, length, '/' ) ) >= 0 )
		{
		const int locationLength = length - offset;

		if( locationLength <= 0 )
			return( CRYPT_ERROR_BADDATA );
		urlInfo->locationLen = \
					strStripWhitespace( ( char ** ) &urlInfo->location, 
										strPtr + offset, locationLength );
		if( urlInfo->locationLen <= 0 )
			return( CRYPT_ERROR_BADDATA );
		}

	return( CRYPT_OK );
	}

/* Copy parsed URL info to a stream structure */

static int copyUrlToStream( STREAM *stream, const URL_INFO *urlInfo )
	{
	if( ( stream->host = clAlloc( "copyUrlToStream", \
								  urlInfo->hostLen + 1 ) ) == NULL )
		return( CRYPT_ERROR_MEMORY );
	memcpy( stream->host, urlInfo->host, urlInfo->hostLen );
	stream->host[ urlInfo->hostLen ] = '\0';
	if( urlInfo->location != NULL )
		{
		if( ( stream->path = \
				clAlloc( "copyUrlToStream", urlInfo->locationLen + 1 ) ) == NULL )
			{
			clFree( "copyUrlToStream", stream->host );
			return( CRYPT_ERROR_MEMORY );
			}
		memcpy( stream->path, urlInfo->location, urlInfo->locationLen );
		stream->path[ urlInfo->locationLen ] = '\0';
		}
	stream->port = urlInfo->port;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Transport-layer 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 */

⌨️ 快捷键说明

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