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

📄 net.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 5 页
字号:
	assert( length > 0 );

	/* If it's not a flush and the buffer can absorb the data, copy it in and
	   exit */
	if( !( flags & TRANSPORT_FLAG_FLUSH ) && \
		stream->writeBufEnd + length <= stream->writeBufSize )
		{
		memcpy( stream->writeBuffer + stream->writeBufEnd, buffer, length );
		stream->writeBufEnd += length;
		assert( stream->writeBufEnd <= stream->writeBufSize );

		return( length );
		}

	/* It's a flush or too much data to buffer, assemble a complete buffer 
	   and write it */
	if( stream->writeBufEnd > 0 )
		{
		const int bytesToCopy = min( byteCount, \
									 stream->writeBufSize - stream->writeBufEnd );
		const int bytesToWrite = stream->writeBufEnd + bytesToCopy;

		if( bytesToCopy > 0 )
			memcpy( stream->writeBuffer + stream->writeBufEnd, buffer, 
					bytesToCopy );
		status = stream->transportWriteFunction( stream, stream->writeBuffer, 
												 bytesToWrite, 
												 TRANSPORT_FLAG_FLUSH );
		if( cryptStatusError( status ) || status < bytesToWrite )
			return( status );
		stream->writeBufEnd = 0;
		bufPtr += bytesToCopy;
		byteCount -= bytesToCopy;
		if( byteCount <= 0 )
			/* We've written everything, exit */
			return( length );
		}

	/* Write anything that's left directly */
	status = stream->transportWriteFunction( stream, bufPtr, byteCount,
											 TRANSPORT_FLAG_FLUSH );
	if( cryptStatusError( status ) || status < byteCount )
		return( status );
	return( length );
	}

/****************************************************************************
*																			*
*							Network Stream Functions						*
*																			*
****************************************************************************/

/* Initialise the network stream */

static int initStream( STREAM *stream, const STREAM_PROTOCOL_TYPE protocol,
					   const NET_CONNECT_INFO *connectInfo, 
					   const BOOLEAN isServer )
	{
	int timeout;

	/* Set up the basic network stream info */
	memset( stream, 0, sizeof( STREAM ) );
	stream->type = STREAM_TYPE_NETWORK;
	stream->protocol = protocol;
	stream->port = connectInfo->port;
	stream->netSocket = stream->listenSocket = CRYPT_ERROR;
	stream->iTransportSession = CRYPT_ERROR;
	if( isServer )
		stream->flags = STREAM_NFLAG_ISSERVER;

	/* Set up the stream timeout information.  While we're connecting, the 
	   stream timeout is the connect timeout.  Once we've connected it's set 
	   to the data transfer timeout, so initially we set the stream timeout
	   to the connect timeout and the saved timeout to the data transfer 
	   timeout */
	if( connectInfo->connectTimeout != CRYPT_ERROR )
		/* There's an explicit timeout specified, use that */
		timeout = connectInfo->connectTimeout;
	else
		/* Get the default timeout from the user object */
		if( cryptStatusError( \
				krnlSendMessage( connectInfo->iUserObject, IMESSAGE_GETATTRIBUTE, 
								 &timeout, CRYPT_OPTION_NET_CONNECTTIMEOUT ) ) )
			timeout = 30;
	if( timeout < 5 )
		{
		/* Enforce the same minimum connect timeout as the kernel ACLs */
		assert( NOTREACHED );
		timeout = 5;
		}
	stream->timeout = timeout;
	if( connectInfo->timeout != CRYPT_ERROR )
		/* There's an explicit timeout specified, use that */
		timeout = connectInfo->timeout;
	else
		/* Get the default timeout from the user object */
		if( cryptStatusError( \
				krnlSendMessage( connectInfo->iUserObject, IMESSAGE_GETATTRIBUTE, 
								 &timeout, CRYPT_OPTION_NET_READTIMEOUT ) ) )
			timeout = 30;
	stream->savedTimeout = timeout;

	return( CRYPT_OK );
	}

/* Connect a stream */

static int openConnection( STREAM *stream,
						   const NET_OPTION_TYPE options,
						   const char *proxyURL )
	{
	URL_INFO urlInfo;
	char urlBuffer[ MAX_DNS_SIZE + 1 ];
	int status;

	/* If we're using an already-active network socket supplied by the 
	   user, there's nothing to do */
	if( stream->flags & STREAM_NFLAG_USERSOCKET )
		{
		/* If it's a dummy open to check parameters that can't be validated 
		   at a higher level, pass the info on down to the low-level 
		   checking routines */
		if( options == NET_OPTION_NETWORKSOCKET_DUMMY )
			return( stream->transportCheckFunction( stream ) );

		return( CRYPT_OK );
		}

	/* If we're not going via a proxy, perform a direct open */
	if( proxyURL == NULL )
		return( stream->transportConnectFunction( stream, stream->host,
												  stream->port ) );

	/* We're going via a proxy.  If the user has specified automatic proxy 
	   detection, try and locate the proxy information */
	if( !strCompareZ( proxyURL, "[Autodetect]" ) )
		{
		status = findProxyURL( urlBuffer, stream->host );
		if( cryptStatusError( status ) )
			{
			/* The proxy URL was invalid, provide more information for the 
			   caller */
			stream->errorCode = CRYPT_ERROR_NOTFOUND;
			strcpy( stream->errorMessage, "Couldn't auto-detect HTTP proxy" );
			return( CRYPT_ERROR_OPEN );
			}
		proxyURL = urlBuffer;
		}

	/* Process the proxy details.  Since this is an HTTP proxy, we specify 
	   the default port as port 80 */
	status = parseURL( &urlInfo, proxyURL, strlen( proxyURL ), 80 );
	if( cryptStatusError( status ) )
		{
		/* The proxy URL was invalid, provide more information for the 
		   caller */
		stream->errorCode = CRYPT_ERROR_BADDATA;
		strcpy( stream->errorMessage, "Invalid HTTP proxy URL" );
		return( CRYPT_ERROR_OPEN );
		}
	memcpy( urlBuffer, urlInfo.host, urlInfo.hostLen );
	urlBuffer[ urlInfo.hostLen ] = '\0';

	/* Since we're going via a proxy, open the connection to the proxy 
	   rather than directly to the target system.  */
	return( stream->transportConnectFunction( stream, urlBuffer, 
											  urlInfo.port ) );
	}

/* Clean up a stream to shut it down */

static void cleanupStream( STREAM *stream, const BOOLEAN cleanupTransport,
						   const BOOLEAN cleanupBuffers )
	{
	assert( stream != NULL && stream->type == STREAM_TYPE_NETWORK );

	/* Clean up the transport system if necessary */
	if( cleanupTransport && !( stream->flags & STREAM_NFLAG_USERSOCKET ) )
		stream->transportDisconnectFunction( stream, TRUE );

	/* Clean up stream-related buffers if necessary */
	if( cleanupBuffers )
		{
		assert( stream->errorMessage != NULL );

		if( stream->bufSize > 0 )
			{
			zeroise( stream->buffer, stream->bufSize );
			clFree( "cleanupStream", stream->buffer );
			}
		if( stream->writeBufSize > 0 )
			{
			zeroise( stream->writeBuffer, stream->writeBufSize );
			clFree( "cleanupStream", stream->writeBuffer );
			}
		clFree( "cleanupStream", stream->errorMessage );
		}

	/* Clean up static stream data */
	if( stream->host != NULL )
		clFree( "cleanupStream", stream->host );
	if( stream->path != NULL )
		clFree( "cleanupStream", stream->path );
	if( stream->query != NULL )
		clFree( "cleanupStream", stream->query );

	zeroise( stream, sizeof( STREAM ) );
	}

/* Check for the use of a proxy when opening a stream */

static BOOLEAN checkForProxy( STREAM *stream, 
							  const STREAM_PROTOCOL_TYPE protocol,
							  const NET_CONNECT_INFO *connectInfo,
							  char *proxyUrlBuffer )
	{
	RESOURCE_DATA msgData;
	int status;

	/* Check for a local connection, which always bypasses the proxy.  We 
	   only use the case-insensitive string compares for the text-format 
	   host names, since the numeric forms don't need this. */
	if( !strcmp( stream->host, "127.0.0.1" ) || \
		!strcmp( stream->host, "::1" ) && \
		!strCompareZ( stream->host, "localhost" ) && \
		!strCompare( stream->host, "localhost.", 10 ) )	/* Are you local? */
		/* This is a local socket! We'll have no proxies here! */
		return( FALSE );

	/* Check to see whether we're going through a proxy.  First we check for
	   a protocol-specific HTTP proxy (if appropriate), if there's none we 
	   check for the more generic case of a SOCKS proxy.  In addition to the 
	   obvious use of an HTTP proxy for HTTP, we also check for an HTTP URL 
	   specified for use with other protocols (specifcally SSL/TLS), since 
	   these can also go via a proxy even if the they're not an explicit use 
	   of HTTP */
	if( ( protocol == STREAM_PROTOCOL_HTTP || \
		  protocol == STREAM_PROTOCOL_HTTP_TRANSACTION || \
		  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) )
		{
		/* Check whether there's an HTTP proxy configured */
		setMessageData( &msgData, proxyUrlBuffer, MAX_DNS_SIZE );
		status = krnlSendMessage( connectInfo->iUserObject, 
								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_OPTION_NET_HTTP_PROXY );
		if( cryptStatusOK( status ) )
			{
			proxyUrlBuffer[ msgData.length ] = '\0';
			stream->flags |= \
				( connectInfo->options == NET_OPTION_HOSTNAME ) ? \
				STREAM_NFLAG_HTTPPROXY : STREAM_NFLAG_HTTPTUNNEL;
			return( TRUE );
			}
		}

	/* Check whether there's a SOCKS proxy configured */
	setMessageData( &msgData, proxyUrlBuffer, MAX_DNS_SIZE );
	status = krnlSendMessage( connectInfo->iUserObject, 
							  IMESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_OPTION_NET_SOCKS_SERVER );
	if( cryptStatusOK( status ) )
		{
		proxyUrlBuffer[ msgData.length ] = '\0';
		return( TRUE );
		}

	/* There's no proxy configured */
	return( FALSE );
	}

/* Complete a network connection after the client- or server-specific
   portions have been handled */

static int completeConnect( STREAM *stream,
							const STREAM_PROTOCOL_TYPE protocol,
							const NET_OPTION_TYPE options,
							const char *proxyURL, 
							const CRYPT_USER iUserObject, 
							char *errorMessage, int *errorCode )
	{
	const BOOLEAN useTransportBuffering = \
						( options == NET_OPTION_TRANSPORTSESSION || \
						  protocol == STREAM_PROTOCOL_TCPIP ) ? \
						FALSE : TRUE;
	int status = CRYPT_OK;

	/* Set up the access method pointers.  We can use either direct TCP/IP
	   access or a cryptlib stream for transport, and layered over that
	   either HTTP, the CMP socket protocol, or direct access to the
	   transport layer */
	if( options == NET_OPTION_TRANSPORTSESSION )
		{
		stream->transportConnectFunction = transportSessionConnectFunction;
		stream->transportDisconnectFunction = transportSessionDisconnectFunction;
		stream->transportWriteFunction = transportSessionWriteFunction;
		stream->transportReadFunction = transportSessionReadFunction;
		stream->transportOKFunction = transportSessionOKFunction;
		}
	else
		setAccessMethodTCP( stream );
	switch( protocol )
		{
		case STREAM_PROTOCOL_HTTP:
		case STREAM_PROTOCOL_HTTP_TRANSACTION:
#ifdef USE_HTTP
			setStreamLayerHTTP( stream );
#else
			return( CRYPT_ERROR_NOTAVAIL );
#endif /* USE_HTTP */
			break;

		case STREAM_PROTOCOL_CMP:
#ifdef USE_CMP
			setStreamLayerCMP( stream );
#else
			return( CRYPT_ERROR_NOTAVAIL );
#endif /* USE_CMP */
			break;

		case STREAM_PROTOCOL_TCPIP:
			setStreamLayerDirect( stream );
			break;

		default:
			assert( NOTREACHED );
		}
	if( useTransportBuffering )
		{
		stream->bufferedTransportReadFunction = bufferedTransportReadFunction;
		stream->bufferedTransportWriteFunction = bufferedTransportWriteFunction;
		}
	else
		{
		stream->bufferedTransportReadFunction = stream->transportReadFunction;
		stream->bufferedTransportWriteFunction = stream->transportWriteFunction;
		}

	/* If we're running over a cryptlib session, make sure that we wait around 
	   for a minimum amount of time during network comms in case the user has
	   specified nonblocking behaviour or quick timeouts */
	if( options == NET_OPTION_TRANSPORTSESSION )
		{
		static const int fixedTimeout = 30;

⌨️ 快捷键说明

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