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;
}