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

📄 stream.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:

			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 + -