📄 net.c
字号:
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 + -