static BaseType_t prvTCPHandleState()

in FreeRTOS_TCP_IP.c [3266:3453]


    static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t * pxSocket,
                                         NetworkBufferDescriptor_t ** ppxNetworkBuffer )
    {
        /* Map the buffer onto the ProtocolHeader_t struct for easy access to the fields. */
        ProtocolHeaders_t * pxProtocolHeaders = ipCAST_PTR_TO_TYPE_PTR( ProtocolHeaders_t,
                                                                        &( ( *ppxNetworkBuffer )->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + xIPHeaderSize( *ppxNetworkBuffer ) ] ) );
        TCPHeader_t * pxTCPHeader = &( pxProtocolHeaders->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 );
        UBaseType_t uxIntermediateResult = 0;
        uint32_t ulSum;

        /* 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 >= ( uint8_t ) 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. */
        ulSum = ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber;

        if( ( ( int32_t ) ulSum ) > 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
        {
            eIPTCPState_t eState;

            uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer );

            if( ( pxSocket->u.xTCP.ucTCPState == ( uint8_t ) eSYN_RECEIVED ) && ( ( ucTCPFlags & ( uint8_t ) tcpTCP_FLAG_CTRL ) == ( uint8_t ) tcpTCP_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 & tcpTCP_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;
                }
            }

            eState = pxSocket->u.xTCP.ucTCPState;

            switch( eState )
            {
                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, pxTCPHeader );
                    pxTCPHeader->ucTCPFlags = ( uint8_t ) tcpTCP_FLAG_SYN | ( uint8_t ) tcpTCP_FLAG_ACK;

                    uxIntermediateResult = uxIPHeaderSizeSocket( pxSocket ) + ipSIZE_OF_TCP_HEADER + uxOptionsLength;
                    xSendLength = ( BaseType_t ) uxIntermediateResult;

                    /* 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.ulHighestSequenceNumber = ulSequenceNumber + 1U;
                    pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber + 1U;
                    pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1U;
                    pxTCPWindow->tx.ulCurrentSequenceNumber = 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:
                    /* No more known states. */
                    break;
            }
        }

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

        return xSendLength;
    }