📄 stream.c
字号:
REQUIRES_S( stream->flags & STREAM_FFLAG_BUFFERSET );
/* 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 ] );
}
retIntError_Stream( stream );
}
/****************************************************************************
* *
* IOCTL Functions *
* *
****************************************************************************/
/* Perform an IOCTL on a stream */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int sioctl( INOUT STREAM *stream, \
IN_ENUM( STREAM_IOCTL ) const STREAM_IOCTL_TYPE type,
IN_OPT void *data, IN_INT const int dataLen )
{
#ifdef USE_TCP
NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
#endif /* USE_TCP */
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Check that the input parameters are in order */
if( !isWritePtr( stream, sizeof( STREAM ) ) )
retIntError();
REQUIRES_S( sanityCheck( stream ) );
REQUIRES_S( ( ( stream->type == STREAM_TYPE_FILE || \
sIsVirtualFileStream( stream ) ) && \
( type == STREAM_IOCTL_IOBUFFER || \
type == STREAM_IOCTL_PARTIALREAD ) ) || \
( stream->type == STREAM_TYPE_NETWORK ) );
REQUIRES_S( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
switch( type )
{
case STREAM_IOCTL_IOBUFFER:
assert( ( data == NULL && dataLen == 0 ) || \
isWritePtr( data, dataLen ) );
REQUIRES_S( ( data == NULL && dataLen == 0 ) || \
( data != NULL && \
dataLen > 0 && dataLen < MAX_INTLENGTH ) );
REQUIRES_S( dataLen == 0 || \
dataLen == 512 || dataLen == 1024 || \
dataLen == 2048 || dataLen == 4096 || \
dataLen == 8192 || dataLen == 16384 );
#ifdef VIRTUAL_FILE_STREAM
/* If it's a virtual file stream emulated in memory, don't do
anything */
if( sIsVirtualFileStream( stream ) )
return( CRYPT_OK );
#endif /* VIRTUAL_FILE_STREAM */
/* Set up the buffer variables. File streams don't make use of
the bufEnd indicator so we set it to the same value as
bufSize to ensure that the stream passes the sanity checks */
stream->buffer = data;
stream->bufSize = stream->bufEnd = 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 the position change was within the
same buffer then the POSCHANGED flag won't have been set
since only the bufPos will have changed) */
stream->bufPos = stream->bufCount = 0;
sClearError( stream );
stream->flags &= ~( STREAM_FFLAG_BUFFERSET | \
STREAM_FFLAG_EOF | \
STREAM_FFLAG_POSCHANGED_NOSKIP );
stream->flags |= STREAM_FFLAG_POSCHANGED;
if( data != NULL )
stream->flags |= STREAM_FFLAG_BUFFERSET;
return( CRYPT_OK );
case STREAM_IOCTL_PARTIALREAD:
REQUIRES_S( data == NULL );
REQUIRES_S( dataLen == FALSE || dataLen == TRUE );
if( dataLen )
stream->flags |= STREAM_FLAG_PARTIALREAD;
else
stream->flags &= ~STREAM_FLAG_PARTIALREAD;
return( CRYPT_OK );
case STREAM_IOCTL_PARTIALWRITE:
REQUIRES_S( data == NULL );
REQUIRES_S( dataLen == FALSE || dataLen == TRUE );
if( dataLen )
stream->flags |= STREAM_FLAG_PARTIALWRITE;
else
stream->flags &= ~STREAM_FLAG_PARTIALWRITE;
return( CRYPT_OK );
case STREAM_IOCTL_ERRORINFO:
assert( isReadPtr( data, sizeof( ERROR_INFO ) ) );
REQUIRES( data != NULL && dataLen == 0 );
/* If this stream type doesn't record extended error information,
there's nothing to do */
if( stream->type != STREAM_TYPE_NETWORK )
return( CRYPT_OK );
/* Copy the error information to the stream */
copyErrorInfo( NETSTREAM_ERRINFO, data );
return( CRYPT_OK );
#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 )
{
REQUIRES_S( dataLen == 0 );
*( ( int * ) data ) = netStream->timeout;
}
else
{
REQUIRES_S( dataLen >= 0 && dataLen < MAX_INTLENGTH );
netStream->timeout = dataLen;
if( netStream->iTransportSession != CRYPT_ERROR )
{
status = krnlSendMessage( netStream->iTransportSession,
IMESSAGE_SETATTRIBUTE, &netStream->timeout,
( type == STREAM_IOCTL_READTIMEOUT ) ? \
CRYPT_OPTION_NET_READTIMEOUT : \
CRYPT_OPTION_NET_WRITETIMEOUT );
if( cryptStatusError( status ) )
return( status );
}
}
return( CRYPT_OK );
case STREAM_IOCTL_HANDSHAKECOMPLETE:
REQUIRES_S( data == NULL && dataLen == 0 );
REQUIRES_S( netStream->timeout > 0 && \
netStream->timeout < MAX_INTLENGTH );
REQUIRES_S( netStream->savedTimeout >= 0 && \
netStream->savedTimeout < MAX_INTLENGTH );
/* The security protocol handshake has completed, change the
stream timeout value from the connect/handshake timeout to
the standard data transfer timeout */
netStream->timeout = netStream->savedTimeout;
netStream->savedTimeout = CRYPT_ERROR;
if( netStream->iTransportSession != CRYPT_ERROR )
{
status = krnlSendMessage( netStream->iTransportSession,
IMESSAGE_SETATTRIBUTE, &netStream->timeout,
CRYPT_OPTION_NET_CONNECTTIMEOUT );
if( cryptStatusError( status ) )
return( status );
}
return( CRYPT_OK );
case STREAM_IOCTL_CONNSTATE:
if( data != NULL )
{
REQUIRES_S( dataLen == 0 );
*( ( int * ) data ) = \
( netStream->nFlags & STREAM_NFLAG_LASTMSG ) ? FALSE : TRUE;
}
else
{
REQUIRES_S( dataLen == TRUE || dataLen == FALSE );
if( dataLen )
netStream->nFlags &= ~STREAM_NFLAG_LASTMSG;
else
netStream->nFlags |= STREAM_NFLAG_LASTMSG;
}
return( CRYPT_OK );
case STREAM_IOCTL_GETCLIENTNAME:
{
assert( isWritePtr( data, dataLen ) );
REQUIRES_S( data != NULL && \
dataLen > 8 && dataLen < MAX_INTLENGTH );
if( netStream->clientAddressLen <= 0 )
return( CRYPT_ERROR_NOTFOUND );
if( netStream->clientAddressLen > dataLen )
return( CRYPT_ERROR_OVERFLOW );
memcpy( data, netStream->clientAddress, netStream->clientAddressLen );
return( CRYPT_OK );
}
case STREAM_IOCTL_GETCLIENTNAMELEN:
REQUIRES_S( data != NULL && dataLen == 0 );
if( netStream->clientAddressLen <= 0 )
return( CRYPT_ERROR_NOTFOUND );
*( ( int * ) data ) = netStream->clientAddressLen;
return( CRYPT_OK );
case STREAM_IOCTL_GETCLIENTPORT:
REQUIRES_S( data != NULL && dataLen == 0 );
if( netStream->clientPort <= 0 )
return( CRYPT_ERROR_NOTFOUND );
*( ( int * ) data ) = netStream->clientPort;
return( CRYPT_OK );
case STREAM_IOCTL_HTTPREQTYPES:
REQUIRES_S( netStream->protocol == STREAM_PROTOCOL_HTTP );
REQUIRES_S( data == NULL );
REQUIRES_S( dataLen > STREAM_HTTPREQTYPE_NONE && \
dataLen < STREAM_HTTPREQTYPE_LAST );
netStream->nFlags &= ~STREAM_NFLAG_HTTPREQMASK;
switch( dataLen )
{
case STREAM_HTTPREQTYPE_GET:
netStream->nFlags |= STREAM_NFLAG_HTTPGET;
break;
case STREAM_HTTPREQTYPE_POST:
netStream->nFlags |= STREAM_NFLAG_HTTPPOST;
break;
case STREAM_HTTPREQTYPE_ANY:
netStream->nFlags |= STREAM_NFLAG_HTTPGET | \
STREAM_NFLAG_HTTPPOST;
break;
default:
retIntError();
}
/* If only an HTTP GET is possible and it's a client-side
stream, it's read-only */
if( dataLen == STREAM_HTTPREQTYPE_GET && \
!( netStream->nFlags & STREAM_NFLAG_ISSERVER ) )
stream->flags = STREAM_FLAG_READONLY;
else
{
/* Reset the read-only flag if we're changing the HTTP
operation type to one that allows writes */
stream->flags &= ~STREAM_FLAG_READONLY;
}
return( CRYPT_OK );
case STREAM_IOCTL_LASTMESSAGE:
REQUIRES_S( netStream->protocol == STREAM_PROTOCOL_HTTP || \
netStream->protocol == STREAM_PROTOCOL_CMP );
REQUIRES_S( data == NULL && dataLen == TRUE );
netStream->nFlags |= STREAM_NFLAG_LASTMSG;
return( CRYPT_OK );
case STREAM_IOCTL_CLOSESENDCHANNEL:
REQUIRES_S( data == NULL && dataLen == 0 );
REQUIRES_S( !( netStream->nFlags & 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( !( netStream->nFlags & STREAM_NFLAG_USERSOCKET ) )
netStream->transportDisconnectFunction( netStream, FALSE );
return( CRYPT_OK );
#endif /* USE_TCP */
}
retIntError_Stream( stream );
}
/****************************************************************************
* *
* 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 */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int sFileToMemStream( INOUT STREAM *memStream, INOUT STREAM *fileStream,
OUT_BUFFER_ALLOC( length ) void **bufPtrPtr,
IN_LENGTH const int length )
{
void *bufPtr;
int status;
assert( isWritePtr( memStream, sizeof( STREAM ) ) );
assert( isWritePtr( fileStream, sizeof( STREAM ) ) );
assert( isWritePtr( bufPtrPtr, sizeof( void * ) ) );
/* Check that the input parameters are in order */
if( !isWritePtr( memStream, sizeof( STREAM ) ) || \
!isWritePtr( fileStream, sizeof( STREAM ) ) || \
!isWritePtr( bufPtrPtr, sizeof( void * ) ) )
retIntError_Stream( memStream );
/* We have to use REQUIRES() here rather than REQUIRES_S() since it's
not certain which of the two streams to set the status for */
REQUIRES( sanityCheck( fileStream ) && \
fileStream->flags & STREAM_FFLAG_BUFFERSET );
REQUIRES( fileStream->type == STREAM_TYPE_FILE );
REQUIRES( length > 0 && length < MAX_INTLENGTH );
/* Clear return value */
memset( memStream, 0, sizeof( STREAM ) );
*bufPtrPtr = NULL;
#ifdef VIRTUAL_FILE_STREAM
/* 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 > fileStream->bufSize - fileStream->bufPos )
return( CRYPT_ERROR_UNDERFLOW );
/* Create a second reference to the memory-mapped stream and advance
the read pointer in the memory-mapped file stream to mimic the
behaviour of a read from it to the memory 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 );
}
#endif /* VIRTUAL_FILE_STREAM */
/* 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 + -