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

📄 sess_rw.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
	BYTE *dataPtr = data;
	int dataLength = dataMaxLength, iterationCount = 0, status = CRYPT_OK;

	/* Clear return value */
	*bytesCopied = 0;

	/* If there's an error pending (which will always be fatal, see the
	   comment after the tryRead() call in getData()), set the current error 
	   state to the pending state and return */
	if( cryptStatusError( sessionInfoPtr->pendingReadErrorState ) )
		{
		assert( sessionInfoPtr->receiveBufPos == 0 );

		status = sessionInfoPtr->readErrorState = \
						sessionInfoPtr->pendingReadErrorState;
		sessionInfoPtr->pendingReadErrorState = CRYPT_OK;
		return( status );
		}

	/* Update the stream read timeout to the current user-selected read 
	   timeout in case the user has changed the timeout setting */
	sioctl( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT, NULL,
			sessionInfoPtr->readTimeout );

	while( cryptStatusOK( status ) && dataLength > 0 && \
		   iterationCount++ < FAILSAFE_ITERATIONS_MAX )
		{
		int count;

		/* Get the next packets-worth of data.  This can return one of three
		   classes of values:

			1. An error code.
			2. OK_SPECIAL to indicate that some data was read but no more is
			   available.
			3. CRYPT_OK to indicate that data was read and more may be 
			   available.
		
		   Note that we can have data available even if an error status is 
		   returned since it can successfully read data before encountering 
		   the error, so we update the byte count no matter what the return 
		   status */
		status = getData( sessionInfoPtr, dataPtr, dataLength, &count );
		if( count > 0 )
			{
			*bytesCopied += count;
			dataPtr += count;
			dataLength -= count;
			}

		assert( sessionInfoPtr->receiveBufEnd <= \
				sessionInfoPtr->receiveBufSize );
		assert( sessionInfoPtr->receiveBufPos <= \
				sessionInfoPtr->receiveBufEnd );
		}
	if( iterationCount >= FAILSAFE_ITERATIONS_MAX )
		retIntError();

	/* If we got at least some data or encountered a soft timeout, the 
	   operation was (nominally) successful, otherwise it's an error */
	return( ( *bytesCopied > 0 || status == OK_SPECIAL ) ? \
			CRYPT_OK : status );
	}

/* Read a fixed-size packet header, called by the secure data session
   routines to read the fixed header on a data packet.  There are two
   variations of this, an atomic read readFixedHeaderAtomic() used during 
   the handshake phase that requires all data to be read and treats timeouts 
   as hard errors, and a partial read readFixedHeader() used during the 
   data-transfer phase that treats timeouts as soft errors.

   Buffer handling for the soft-timeout version is as follows:

		| <- hdrSize ->	|
		+---------------+
		|///////|		|
		+---------------+
				|<--+-->|
					|
			  partialHdrRem

   The data is read into the header buffer until partialHeaderRemaining
   drops to zero.  The function returns OK_SPECIAL until this happens */

#if 0

int readFixedHeaderOld( SESSION_INFO *sessionInfoPtr, const int headerSize )
	{
	BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
				   sessionInfoPtr->receiveBufEnd;
	int status;

	/* If it's the first attempt at reading the header, set the total byte
	   count */
	if( sessionInfoPtr->partialHeaderRemaining <= 0 )
		sessionInfoPtr->partialHeaderRemaining = headerSize;
	else
		bufPtr += headerSize - sessionInfoPtr->partialHeaderRemaining;

	assert( sessionInfoPtr->partialHeaderRemaining > 0 && \
			sessionInfoPtr->partialHeaderRemaining <= headerSize );

	/* Clear the first few bytes of returned data to make sure that the
	   higher-level code always bails out if the read fails for some reason
	   without returning an error status */
	memset( bufPtr, 0, min( headerSize, \
							sessionInfoPtr->partialHeaderRemaining ) );

	/* Try and read the remaining header bytes */
	status = sread( &sessionInfoPtr->stream, bufPtr,
					sessionInfoPtr->partialHeaderRemaining );
	if( cryptStatusError( status ) )
		{
		/* We could be trying to read an ack for a close packet sent in 
		   response to an earlier error, in which case we don't want the
		   already-present error information overwritten by network
		   error info, so if the no-report-error flag is set we don't
		   update the extended error info */
		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
			return( status );

		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  &sessionInfoPtr->errorInfo );
		return( status );
		}

	/* If we didn't get the whole header, treat it as a timeout error */
	if( status < sessionInfoPtr->partialHeaderRemaining )
		{
		/* If we timed out during the handshake phase, treat it as a hard
		   timeout error */
		if( !( sessionInfoPtr->flags & SESSION_ISOPEN ) )
			{
			if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
				return( status );
			retExt( CRYPT_ERROR_TIMEOUT,
					( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO, 
					  "Timeout during packet header read, only got %d of %d "
					  "bytes", status, headerSize ) );
			}

		/* We're in the data-processing stage, it's a soft timeout error */
		sessionInfoPtr->partialHeaderRemaining -= status;
		return( 0 );
		}

	/* We've got the whole header ready to process */
	assert( sessionInfoPtr->partialHeaderRemaining == status );
	sessionInfoPtr->partialHeaderRemaining = 0;
	return( headerSize );
	}
#endif /* 0 */

int readFixedHeaderAtomic( SESSION_INFO *sessionInfoPtr, void *headerBuffer, 
						   const int headerLength )
	{
	int length, status;

	/* Clear the returned data to make sure that the higher-level code 
	   always bails out if the read fails for some reason without returning 
	   an error status */
	memset( headerBuffer, 0, headerLength );

	/* Try and read the remaining header bytes */
	status = length = \
		sread( &sessionInfoPtr->stream, headerBuffer, headerLength );
	if( cryptStatusError( status ) )
		{
		/* We could be trying to read an ack for a close packet sent in 
		   response to an earlier error, in which case we don't want the
		   already-present error information overwritten by network
		   error info, so if the no-report-error flag is set we don't
		   update the extended error info */
		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
			return( status );

		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  &sessionInfoPtr->errorInfo );
		return( status );
		}

	/* We've timed out during the handshake phase, it's a hard timeout 
	   error */
	if( length < headerLength )
		{
		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
			return( status );
		retExt( CRYPT_ERROR_TIMEOUT,
				( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO, 
				  "Timeout during packet header read, only got %d of %d "
				  "bytes", length, headerLength ) );
		}

	return( CRYPT_OK );
	}

int readFixedHeader( SESSION_INFO *sessionInfoPtr, void *headerBuffer, 
					 const int headerLength )
	{
	BYTE *bufPtr = headerBuffer;
	int bytesToRead, length, status;

	/* If it's the first attempt at reading the header, set the total byte
	   count */
	if( sessionInfoPtr->partialHeaderRemaining <= 0 )
		{
		sessionInfoPtr->partialHeaderRemaining = headerLength;
		bytesToRead = headerLength;
		}
	else
		{
		/* We've already got a partial header present in the buffer, read 
		   the remaining header data.  
		   
		   Note that the existing partial header size may be zero (i.e. 
		   partialHeaderRemaining == headerLength ) if we got a soft-timeout 
		   on a previous call to readFixedHeader().  This happens on any
		   read in which the peer has sent only a single packet and the 
		   packet fits entirely in the read buffer because we follow up 
		   every full packet read with a zero-timeout second read to check 
		   if further packets are pending */
		bufPtr += headerLength - sessionInfoPtr->partialHeaderRemaining;
		bytesToRead = sessionInfoPtr->partialHeaderRemaining;
		}
	assert( bytesToRead > 0 && bytesToRead <= headerLength );
	assert( sessionInfoPtr->partialHeaderRemaining > 0 && \
			sessionInfoPtr->partialHeaderRemaining <= headerLength );

	/* Clear the first few bytes of returned data to make sure that the
	   higher-level code always bails out if the read fails for some reason
	   without returning an error status */
	memset( bufPtr, 0, bytesToRead );

	/* Try and read the remaining header bytes */
	status = length = \
		sread( &sessionInfoPtr->stream, bufPtr, bytesToRead );
	if( cryptStatusError( status ) )
		{
		/* We could be trying to read an ack for a close packet sent in 
		   response to an earlier error, in which case we don't want the
		   already-present error information overwritten by network
		   error info, so if the no-report-error flag is set we don't
		   update the extended error info */
		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
			return( status );

		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  &sessionInfoPtr->errorInfo );
		return( status );
		}
	sessionInfoPtr->partialHeaderRemaining -= length;

	/* If we didn't get the whole header, treat it as a soft timeout error */
	if( sessionInfoPtr->partialHeaderRemaining > 0 )
		return( OK_SPECIAL );

	/* We've got the whole header ready to process */
	assert( sessionInfoPtr->partialHeaderRemaining == 0 );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						Secure Session Data Write Functions					*
*																			*
****************************************************************************/

/* Send data to the remote system.  There are two strategies for handling 
   buffer filling and partial writes, either to fill the buffer as full as 
   possible and write it all at once, or to write complete packets as soon 
   as they're available.  We use the latter strategy here, both because it 
   considerably simplifies buffer management and because interleaving 
   (asynchronous) writes and packet processing increases the chances that 
   the current packet will be successfully dispatched across the network 
   while the next one is being encrypted - trying to asynchronously write a 
   large amount of data in one go practically guarantees that the write 
   won't complete.

   Session buffer management is handled as follows: The startOfs index 
   points to the start of the payload space in the buffer (everything before 
   this is header data).  The maxPacketSize value indicates the end of the 
   payload space relative to the startOfs:

	<- hdr->|<-- payload -->|
	+-------+---------------+---+
	|		|///////////////|	|
	+-------+---------------+---+
			^				^
			|				|
		startOfs	  maxPacketSize

   The bPos index moves from startsOfs to maxPacketSize, after which the 
   data is wrapped up by the protocol-specific code.  At this point bPos
   usually points past the end of maxPacketSize due to the addition of
   trailer data such as encryption block padding and a MAC.  Once the
   packet is assembled, the data is flushed and the bPos index reset:

		startOfs	  maxPacketSize
			|				|
			v				v
	+-------+-------+-------+---+
	|.......|.......|///////|///|
	+-------+-------+-------+---+
					^<--- to -->^
					|	write	|
			  partialBufPos	  bufPos

   As with reads, writes can be non-atomic, although on a more restrictive 
   scale than reads: Once an encrypted packet has been assembled in the 
   write buffer, the entire contents must be written before a new packet can 
   be assembled.  This guarantees that when the caller flushes data through 
   to the other side, all of the data will be sent (and the other side will 
   have a chance to react to it) before the next load of data can be flushed 
   through.

   Once we have partial data in the send buffer, all further attempts to
   add more data fail until the remainder of the partially-written data
   has been flushed.  This is handled by setting sendBufPartialBufPos to
   point to the first byte of unwritten data, so that 
   sendBufPartialBufPos ... sendBufPos remains to be written */

static int flushData( SESSION_INFO *sessionInfoPtr )
	{
	int length, status;

	/* If there's no data to flush, exit */
	if( sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufStartOfs )
		return( CRYPT_OK );	

	/* If there's no unwritten data from a previous write attempt still 
	   present, prepare to send the new data */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -