📄 stream.c
字号:
{
assert( NOTREACHED );
return( sSetError( stream, CRYPT_ERROR_READ ) );
}
/* If there's a problem with the stream, don't try to do anything until
the error is cleared */
if( cryptStatusError( stream->status ) )
return( stream->status );
/* Read the data from the buffer, but without advancing the read pointer
like sgetc() does */
switch( stream->type )
{
case STREAM_TYPE_MEMORY:
assert( !( stream->flags & ~STREAM_FLAG_MASK ) );
/* Read the data from the stream buffer */
if( stream->bufPos >= stream->bufEnd )
{
stream->status = CRYPT_ERROR_UNDERFLOW;
return( CRYPT_ERROR_UNDERFLOW );
}
return( stream->buffer[ stream->bufPos ] );
case STREAM_TYPE_FILE:
assert( !( stream->flags & ~STREAM_FFLAG_MASK ) );
/* Read the data from the file */
if( stream->bufPos >= stream->bufEnd || \
( stream->flags & STREAM_FFLAG_POSCHANGED ) )
{
int status = refillStream( stream );
if( cryptStatusError( status ) )
return( ( status == OK_SPECIAL ) ? 0 : status );
}
return( stream->buffer[ stream->bufPos ] );
}
assert( NOTREACHED );
return( CRYPT_ERROR_READ ); /* Get rid of compiler warning */
}
/****************************************************************************
* *
* IOCTL Functions *
* *
****************************************************************************/
/* Perform an IOCTL on a stream */
int sioctl( STREAM *stream, const STREAM_IOCTL_TYPE type, void *data,
const int dataLen )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( ( stream->type == STREAM_TYPE_FILE && \
( type == STREAM_IOCTL_IOBUFFER || \
type == STREAM_IOCTL_PARTIALREAD ) ) || \
( stream->type == STREAM_TYPE_NETWORK ) );
assert( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
/* Check that the input parameters are in order */
if( !isWritePtr( stream, sizeof( STREAM ) ) )
{
assert( NOTREACHED );
return( CRYPT_ERROR_READ );
}
switch( type )
{
case STREAM_IOCTL_IOBUFFER:
assert( ( data == NULL && dataLen == 0 ) || \
isWritePtr( data, dataLen ) );
assert( dataLen == 0 || \
dataLen == 512 || dataLen == 1024 || \
dataLen == 2048 || dataLen == 4096 || \
dataLen == 8192 || dataLen == 16384 );
stream->buffer = data;
stream->bufSize = dataLen;
/* We've switched to a new I/O buffer, reset all buffer- and
stream-state related variables and remember that we have to
reset the stream position, since there may be a position-
change pending that hasn't been reflected down to the
underlying file yet (if it was within the same buffer, the
POSCHANGED flag won't have been set since only the bufPos is
changed) */
stream->bufPos = stream->bufEnd = stream->bufCount = 0;
stream->status = CRYPT_OK;
stream->flags &= ~( STREAM_FFLAG_EOF | \
STREAM_FFLAG_POSCHANGED_NOSKIP );
stream->flags |= STREAM_FFLAG_POSCHANGED;
break;
case STREAM_IOCTL_PARTIALREAD:
assert( data == NULL && dataLen == 0 );
stream->flags |= STREAM_FLAG_PARTIALREAD;
break;
case STREAM_IOCTL_PARTIALWRITE:
assert( data == NULL && dataLen == 0 );
stream->flags |= STREAM_FLAG_PARTIALWRITE;
break;
#ifdef USE_TCP
case STREAM_IOCTL_READTIMEOUT:
case STREAM_IOCTL_WRITETIMEOUT:
/* These two values are stored as a shared timeout value
which is updated on each data read or write by the
caller, so there's no need to maintain distinct values */
if( data != NULL )
{
assert( dataLen == 0 );
*( ( int * ) data ) = stream->timeout;
}
else
{
assert( dataLen >= 0 );
stream->timeout = dataLen;
if( stream->iTransportSession != CRYPT_ERROR )
krnlSendMessage( stream->iTransportSession,
IMESSAGE_SETATTRIBUTE, &stream->timeout,
( type == STREAM_IOCTL_READTIMEOUT ) ? \
CRYPT_OPTION_NET_READTIMEOUT : \
CRYPT_OPTION_NET_WRITETIMEOUT );
}
break;
case STREAM_IOCTL_HANDSHAKECOMPLETE:
{
assert( data == NULL );
assert( dataLen == 0 );
assert( stream->timeout > 0 );
assert( stream->savedTimeout >= 0 );
/* The security protocol handshake has completed, change the
stream timeout value from the connect/handshake timeout to
the standard data transfer timeout */
stream->timeout = stream->savedTimeout;
stream->savedTimeout = CRYPT_ERROR;
if( stream->iTransportSession != CRYPT_ERROR )
krnlSendMessage( stream->iTransportSession,
IMESSAGE_SETATTRIBUTE, &stream->timeout,
CRYPT_OPTION_NET_CONNECTTIMEOUT );
break;
}
case STREAM_IOCTL_CONNSTATE:
if( data != NULL )
{
assert( dataLen == 0 );
*( ( int * ) data ) = \
( stream->flags & STREAM_NFLAG_LASTMSG ) ? \
FALSE : TRUE;
}
else
{
assert( dataLen == TRUE || dataLen == FALSE );
if( dataLen )
stream->flags &= ~STREAM_NFLAG_LASTMSG;
else
stream->flags |= STREAM_NFLAG_LASTMSG;
}
break;
case STREAM_IOCTL_GETCLIENTNAME:
assert( data != NULL );
assert( dataLen == 0 );
strcpy( data, stream->clientAddress );
break;
case STREAM_IOCTL_GETCLIENTPORT:
assert( data != NULL );
assert( dataLen == 0 );
*( ( int * ) data ) = stream->clientPort;
break;
case STREAM_IOCTL_CONTENTTYPE:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( isWritePtr( data, dataLen ) );
assert( dataLen > 0 && dataLen < CRYPT_MAX_TEXTSIZE );
memcpy( stream->contentType, data, dataLen );
stream->contentType[ dataLen ] = '\0';
break;
case STREAM_IOCTL_QUERY:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( ( data == NULL && dataLen == 0 ) || \
( isWritePtr( data, dataLen ) && \
dataLen > 0 && dataLen < CRYPT_MAX_TEXTSIZE ) );
/* If we're resetting the value, clear the buffer and exit */
if( data == NULL )
{
if( stream->queryLen > 0 )
memset( stream->query, 0, stream->queryLen );
break;
}
/* Set up the buffer to contain the query if necessary */
if( stream->queryLen <= dataLen + 1 )
{
if( stream->query != NULL )
{
clFree( "sioctl", stream->query );
stream->queryLen = 0;
}
if( ( stream->query = \
clAlloc( "sioctl", max( CRYPT_MAX_TEXTSIZE, \
dataLen + 1 ) ) ) == NULL )
{
stream->status = CRYPT_ERROR_MEMORY;
return( CRYPT_ERROR_MEMORY );
}
stream->queryLen = dataLen;
}
/* Copy in the query */
memcpy( stream->query, data, dataLen );
stream->query[ dataLen ] = '\0';
break;
case STREAM_IOCTL_IDEMPOTENT:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
if( data != NULL )
{
assert( dataLen == 0 );
*( ( int * ) data ) = \
( stream->flags & STREAM_NFLAG_IDEMPOTENT ) ? \
TRUE : FALSE;
}
else
{
assert( data == NULL );
assert( dataLen == TRUE || dataLen == FALSE );
if( dataLen )
stream->flags |= STREAM_NFLAG_IDEMPOTENT;
else
stream->flags &= ~STREAM_NFLAG_IDEMPOTENT;
}
break;
case STREAM_IOCTL_LASTMESSAGE:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION || \
stream->protocol == STREAM_PROTOCOL_CMP );
assert( data == NULL );
assert( dataLen == TRUE );
stream->flags |= STREAM_NFLAG_LASTMSG;
break;
case STREAM_IOCTL_CALLBACKFUNCTION:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen == 0 );
stream->callbackFunction = ( CALLBACKFUNCTION ) data;
break;
case STREAM_IOCTL_CALLBACKPARAMS:
assert( stream->protocol == STREAM_PROTOCOL_HTTP || \
stream->protocol == STREAM_PROTOCOL_HTTP_TRANSACTION );
assert( data != NULL );
assert( dataLen == 0 );
stream->callbackParams = data;
break;
case STREAM_IOCTL_CLOSESENDCHANNEL:
assert( data == NULL );
assert( dataLen == 0 );
assert( !( stream->flags & STREAM_NFLAG_USERSOCKET ) );
/* If this is a user-supplied socket, we can't perform a partial
close without affecting the socket as seen by the user, so we
only perform the partial close if it's a cryptlib-controlled
socket */
if( !( stream->flags & STREAM_NFLAG_USERSOCKET ) )
stream->transportDisconnectFunction( stream, FALSE );
break;
#endif /* USE_TCP */
default:
assert( NOTREACHED );
}
return( CRYPT_OK );
}
/****************************************************************************
* *
* Misc Functions *
* *
****************************************************************************/
/* Convert a file stream to a memory stream. Usually this allocates a
buffer and reads the stream into it, however if it's a read-only memory-
mapped file it just creates a second reference to the data to save
memory */
int sFileToMemStream( STREAM *memStream, STREAM *fileStream,
void **bufPtrPtr, const int length )
{
void *bufPtr;
int status;
assert( isWritePtr( memStream, sizeof( STREAM ) ) );
assert( isWritePtr( fileStream, sizeof( STREAM ) ) );
assert( isWritePtr( *bufPtrPtr, sizeof( void * ) ) );
assert( length > 0 );
/* Check that the input parameters are in order */
if( !isWritePtr( memStream, sizeof( STREAM ) ) || \
!isWritePtr( fileStream, sizeof( STREAM ) ) || \
length <= 0 )
{
assert( NOTREACHED );
return( CRYPT_ERROR_READ );
}
/* Clear return value */
memset( memStream, 0, sizeof( STREAM ) );
*bufPtrPtr = NULL;
/* If it's a read-only memory-mapped file stream, create the memory
stream as a reference to the file stream */
if( ( fileStream->flags & \
( STREAM_FLAG_READONLY | STREAM_FFLAG_MMAPPED ) ) == \
( STREAM_FLAG_READONLY | STREAM_FFLAG_MMAPPED ) )
{
/* Make sure that there's enough data left in the memory-mapped
stream to reference it as a file stream */
if( length > sMemDataLeft( fileStream ) )
return( CRYPT_ERROR_UNDERFLOW );
/* Create a second reference to the memory-mapped stream */
status = sMemConnect( memStream, fileStream->buffer + \
fileStream->bufPos, length );
if( cryptStatusError( status ) )
return( status );
status = sSkip( fileStream, length );
if( cryptStatusError( status ) )
{
sMemDisconnect( memStream );
return( status );
}
return( CRYPT_OK );
}
/* It's a file stream, allocate a buffer for the data and read it in as
a memory stream */
if( ( bufPtr = clAlloc( "sFileToMemStream", length ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
status = sread( fileStream, bufPtr, length );
if( cryptStatusOK( status ) )
status = sMemConnect( memStream, bufPtr, length );
if( cryptStatusError( status ) )
{
clFree( "sFileToMemStream", bufPtr );
return( status );
}
*bufPtrPtr = bufPtr;
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -