static BaseType_t prvTCPHandleState()

in amazon-freertos/lib/FreeRTOS-Plus-TCP/source/FreeRTOS_TCP_IP.c [2670:2840]


static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer )
{
TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer );
TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader );
BaseType_t xSendLength = 0;
uint32_t ulReceiveLength;	/* Number of bytes contained in the TCP message. */
uint8_t *pucRecvData;
uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber);

	/* uxOptionsLength: the size of the options to be sent (always a multiple of
	4 bytes)
	1. in the SYN phase, we shall communicate the MSS
	2. in case of a SACK, Selective ACK, ack a segment which comes in
	out-of-order. */
UBaseType_t uxOptionsLength = 0u;
uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags;
TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow );

	/* First get the length and the position of the received data, if any.
	pucRecvData will point to the first byte of the TCP payload. */
	ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData );

	if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
	{
		if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u )
		{
			/* This is most probably a keep-alive message from peer.  Setting
			'bWinChange' doesn't cause a window-size-change, the flag is used
			here to force sending an immediate ACK. */
			pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
		}
	}

	/* Keep track of the highest sequence number that might be expected within
	this connection. */
	if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 )
	{
		pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength;
	}

	/* Storing data may result in a fatal error if malloc() fails. */
	if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 )
	{
		xSendLength = -1;
	}
	else
	{
		uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );

		if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) )
		{
			FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) );

			/* In eSYN_RECEIVED a simple ACK is expected, but apparently the
			'SYN+ACK' didn't arrive.  Step back to the previous state in which
			a first incoming SYN is handled.  The SYN was counted already so
			decrease it first. */
			vTCPStateChange( pxSocket, eSYN_FIRST );
		}

		if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) )
		{
			/* It's the first time a FIN has been received, remember its
			sequence number. */
			pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength;
			pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED;

			/* Was peer the first one to send a FIN? */
			if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED )
			{
				/* If so, don't send the-last-ACK. */
				pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED;
			}
		}

		switch (pxSocket->u.xTCP.ucTCPState)
		{
		case eCLOSED:		/* (server + client) no connection state at all. */
			/* Nothing to do for a closed socket, except waiting for the
			owner. */
			break;

		case eTCP_LISTEN:	/* (server) waiting for a connection request from
							any remote TCP and port. */
			/* The listen state was handled in xProcessReceivedTCPPacket().
			Should not come here. */
			break;

		case eSYN_FIRST:	/* (server) Just received a SYN request for a server
							socket. */
			{
				/* A new socket has been created, reply with a SYN+ACK.
				Acknowledge with seq+1 because the SYN is seen as pseudo data
				with len = 1. */
				uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket );
				pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK;

				xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );

				/* Set the TCP offset field:  ipSIZE_OF_TCP_HEADER equals 20 and
				uxOptionsLength is a multiple of 4.  The complete expression is:
				ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */
				pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );
				vTCPStateChange( pxSocket, eSYN_RECEIVED );

				pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u;
				pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */
			}
			break;

		case eCONNECT_SYN:	/* (client) also called SYN_SENT: we've just send a
							SYN, expect	a SYN+ACK and send a ACK now. */
			/* Fall through */
		case eSYN_RECEIVED:	/* (server) we've had a SYN, replied with SYN+SCK
							expect a ACK and do nothing. */
			xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
			break;

		case eESTABLISHED:	/* (server + client) an open connection, data
							received can be	delivered to the user. The normal
							state for the data transfer phase of the connection
							The closing states are also handled here with the
							use of some flags. */
			xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength );
			break;

		case eLAST_ACK:		/* (server + client) waiting for an acknowledgement
							of the connection termination request previously
							sent to the remote TCP (which includes an
							acknowledgement of its connection termination
							request). */
			/* Fall through */
		case eFIN_WAIT_1:	/* (server + client) waiting for a connection termination request from the remote TCP,
							 * or an acknowledgement of the connection termination request previously sent. */
			/* Fall through */
		case eFIN_WAIT_2:	/* (server + client) waiting for a connection termination request from the remote TCP. */
			xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer );
			break;

		case eCLOSE_WAIT:	/* (server + client) waiting for a connection
							termination request from the local user.  Nothing to
							do, connection is closed, wait for owner to close
							this socket. */
			break;

		case eCLOSING:		/* (server + client) waiting for a connection
							termination request acknowledgement from the remote
							TCP. */
			break;

		case eTIME_WAIT:	/* (either server or client) waiting for enough time
							to pass to be sure the remote TCP received the
							acknowledgement of its connection termination
							request. [According to RFC 793 a connection can stay
							in TIME-WAIT for a maximum of four minutes known as
							a MSL (maximum segment lifetime).]  These states are
							implemented implicitly by settings flags like
							'bFinSent', 'bFinRecv', and 'bFinAcked'. */
			break;
		default:
			break;
		}
	}

	if( xSendLength > 0 )
	{
		xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength );
	}

	return xSendLength;
}