📄 stream.c
字号:
return( CRYPT_OK );
case STREAM_TYPE_FILE:
{
const BYTE *bufPtr = buffer;
int dataLength = length;
assert( !( stream->flags & ~STREAM_FFLAG_MASK ) );
/* Write the data to the file */
while( dataLength > 0 )
{
const int bytesToCopy = \
min( dataLength, stream->bufSize - stream->bufPos );
if( bytesToCopy > 0 )
{
memcpy( stream->buffer + stream->bufPos, bufPtr,
bytesToCopy );
stream->bufPos += bytesToCopy;
bufPtr += bytesToCopy;
dataLength -= bytesToCopy;
}
if( stream->bufPos >= stream->bufSize )
{
int status;
status = emptyStream( stream, FALSE );
if( cryptStatusError( stream ) )
return( status );
}
}
stream->flags |= STREAM_FFLAG_DIRTY;
return( CRYPT_OK );
}
#ifdef USE_TCP
case STREAM_TYPE_NETWORK:
assert( !( stream->flags & ~STREAM_NFLAG_MASK ) );
assert( stream->writeFunction != NULL );
assert( ( stream->flags & STREAM_NFLAG_ISSERVER ) || \
stream->host != NULL || \
stream->netSocket != CRYPT_ERROR );
/* Write the data to the network */
return( stream->writeFunction( stream, buffer, length ) );
#endif /* USE_TCP */
}
assert( NOTREACHED );
return( CRYPT_ERROR_WRITE ); /* Get rid of compiler warning */
}
/* Commit data in a stream to backing storage */
int sflush( STREAM *stream )
{
int status = CRYPT_OK, flushStatus;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_FILE );
assert( isReadPtr( stream->buffer, stream->bufSize ) );
assert( !( stream->flags & STREAM_FLAG_READONLY ) );
/* 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 );
/* If the data is unchanged, there's nothing to do */
if( !( stream->flags & STREAM_FFLAG_DIRTY ) )
return( CRYPT_OK );
/* If there's data still in the stream buffer, write it to disk */
if( stream->bufPos > 0 )
status = emptyStream( stream, TRUE );
/* Commit the data */
flushStatus = fileFlush( stream );
stream->flags &= ~STREAM_FFLAG_DIRTY;
return( cryptStatusOK( status ) ? flushStatus : status );
}
/****************************************************************************
* *
* Meta-data Functions *
* *
****************************************************************************/
/* Move to an absolute position in a stream */
int sseek( STREAM *stream, const long position )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_NULL || \
stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE );
assert( position >= 0 );
switch( stream->type )
{
case STREAM_TYPE_NULL:
assert( !stream->flags );
/* Move to the position in the stream buffer. We never get
called directly with an sseek on a memory stream, but end up
here via a translated sSkip() call */
stream->bufPos = ( int ) position;
return( CRYPT_OK );
case STREAM_TYPE_MEMORY:
assert( !( stream->flags & ~STREAM_FLAG_MASK ) );
/* Move to the position in the stream buffer */
if( stream->bufSize != STREAMSIZE_UNKNOWN && \
( int ) position > stream->bufSize )
{
stream->bufPos = stream->bufSize;
stream->status = CRYPT_ERROR_UNDERFLOW;
return( CRYPT_ERROR_UNDERFLOW );
}
stream->bufPos = ( int ) position;
return( CRYPT_OK );
case STREAM_TYPE_FILE:
{
int newBufCount;
assert( !( stream->flags & ~STREAM_FFLAG_MASK ) );
/* If it's a currently-disconnected file stream, all that we can
do is rewind the stream. This occurs when we're doing an
atomic flush of data to disk and we rewind the stream prior
to writing the new/updated data. The next buffer-connect
operation will reset the stream state, so there's nothing to
do at this point */
if( stream->bufSize <= 0 )
{
assert( position == 0 );
return( CRYPT_OK );
}
/* It's a file stream, remember the new position in the file */
newBufCount = position / stream->bufSize;
if( newBufCount != stream->bufCount )
{
/* We're not within the current buffer any more, remember
that we have to explicitly update the file position on
the next read */
stream->flags |= STREAM_FFLAG_POSCHANGED;
/* If we're already positioned to read the next bufferful
of data, we don't have to explicitly skip ahead to it */
if( newBufCount == stream->bufCount + 1 )
stream->flags |= STREAM_FFLAG_POSCHANGED_NOSKIP ;
stream->bufCount = newBufCount;
}
stream->bufPos = position % stream->bufSize;
return( CRYPT_OK );
}
}
assert( NOTREACHED );
return( CRYPT_ERROR_WRITE ); /* Get rid of compiler warning */
}
/* Peek at the next data value in a stream */
int sPeek( STREAM *stream )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( stream->type == STREAM_TYPE_MEMORY || \
stream->type == STREAM_TYPE_FILE );
assert( isReadPtr( stream->buffer, stream->bufSize ) );
assert( stream->bufPos >= 0 && stream->bufPos <= stream->bufEnd );
/* 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->bufSize != STREAMSIZE_UNKNOWN && \
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 && \
type != STREAM_IOCTL_PARTIALREAD ) );
assert( type > STREAM_IOCTL_NONE && type < STREAM_IOCTL_LAST );
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_FFLAG_PARTIALREAD;
break;
#ifdef USE_TCP
case STREAM_IOCTL_TIMEOUT:
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,
CRYPT_OPTION_NET_TIMEOUT );
}
break;
case STREAM_IOCTL_HANDSHAKETIMEOUT:
{
int value;
assert( data == NULL );
assert( dataLen == 0 );
/* We're overriding the standard stream timeout to allow the
handshake to proceed correctly even if the user has selected
nonblocking reads. This is done by swapping the actual and
saved timeout, and undone by swapping them back again */
value = stream->savedTimeout;
stream->savedTimeout = stream->timeout;
stream->timeout = value;
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( isWritePtr( data, dataLen ) );
assert( dataLen > 0 && dataLen < CRYPT_MAX_TEXTSIZE );
/* 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_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 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -