+TCP - How force a close on a TCP connection on a Remote Server

joehinkle wrote on Saturday, August 20, 2016:

I have a window’s based TCP server that communicates with my +TCP embedded application.

My app comes out of reset and attampts to make a connection with the Window’s based server.

Upon connection, data is passed back and forth.

ISSUE: If the connection is made and then the app does a reset – the app attempts to make a connection with the server again. +TCP gives the same port to the app as in the first connection. The server still has an open connection based on that port number but my app is trying to start a new one.

The RED wireshark line below shows the connection mismatch. This issue of not connecting will continue forever.

I suspect it is the use of the same port number that +TCP assigns to the connection that causes the server to think it was the original connection and not a new one being started.

Looking at the Wireshark data, +TCP replies with a RST, ACK to the server’s ACK.

+TCP is not using the same SEQ that the server provided in the ACK for the RST reply. Is that why the server is ignoring the RST and keeps the connection open?

pcap file attached

Thanks for any insight.

Joe

rtel wrote on Saturday, August 20, 2016:

Hi Joe,

If you look in FreeRTOS_Sockets.c, you will find the implementation of
prvGetPrivatePortNumber(), and there is a comment in the function “This
needs to be randomised” [at least, you will see the comment if you are
using the head revision code rather than the last release code].

The function provides port numbers between
socketAUTO_PORT_ALLOCATION_START_NUMBER and
socketAUTO_PORT_ALLOCATION_MAX_NUMBER, with the first call always
returning port number socketAUTO_PORT_ALLOCATION_START_NUMBER.

You can update this function, and we can do here as well, so that on the
first call it instead chooses a random number between
socketAUTO_PORT_ALLOCATION_START_NUMBER and
socketAUTO_PORT_ALLOCATION_START_NUMBER.

joehinkle wrote on Saturday, August 20, 2016:

Thanks, I’ll do that.

TCP question.

If +TCP had replied with the Server’s SEQ instead of it’s connection SEQ – would THAT have terminated the connection?

If +TCP receives an out of sequence ACK – why not reply to the same SEQ?

The port number change will fix my issue with not connecting, but the server will still have a connection that has to time out. I just wondering if the RST ACK reply was returned with the server’s SEQ if that would fix everything?

Just asking – Hoping I don’t have to dig into the RFC to see.

Thanks.

heinbali01 wrote on Saturday, August 20, 2016:

If +TCP had replied with the Server’s SEQ instead of it’s
connection SEQ – would THAT have terminated the connection?

Tomorrow when I’m not tired I will look at your questions again.

But when a RST is sent, the actual ACK and SEQ numbers do no matter.

A TCP connection is identified by 4 “numbers” : source IP address + port number, and the target IP address and port number. If a sending host receives a RST matching with these 4 numbers, the socket owner must see an error like ECONNRESET

Applications like browsers on any OS will surely behave correctly in this respect.

The correct way to actively shutdown a +TCP connection is as follows:

    FreeRTOS_shutdown( xSocket );
    for( ;; )
    {
        xResult = FreeRTOS_recv( xSocket, ucBuffer, sizeof( ucBuffer ), 0 );
        if( ( xResult < 0 ) && ( xResult != -pdFREERTOS_ERRNO_EWOULDBLOCK ) )
        {
            FreeRTOS_closesocket( xSocket );
            xSocket = NULL;
            break;
        }
    }

Regards.

rtel wrote on Sunday, August 21, 2016:

Correction! My post here https://sourceforge.net/p/freertos/discussion/382005/thread/794f3d82/#3cf0/39ac was not accurate. The first port number used is already a randomly selected port number between socketAUTO_PORT_ALLOCATION_START_NUMBER and socketAUTO_PORT_ALLOCATION_END_NUMBER. This is because FreeRTOS_IPInit() calls vNetworkSocketsInit(), and vNetworkSocketsInit() uses ipconfigRAND32() to randomise the first private port number used. This does however rely on ipconfigRAND32() operating correctly. If you do not define ipconfigRAND32() in FreeRTOSIPConfig.h it will get defaulted to just calling the rand() function provided by your C run time library - but you need to call srand() with appropriate entropy to seed the random number.

joehinkle wrote on Sunday, August 21, 2016:

I implemented rand() for ipconfigRAND32() but had not set srand().

I’ve used an “un-used” ADC channel to acquire a seed for srand() prior to starting the IP thread.

Thanks for your reply

kenchang1 wrote on Friday, November 10, 2017:

I have encountered this issue too. The usage of random ports is a workaround, but the real solution is described in the RFC793 page 34, figure 10.
In this case the SEQ number of the RST packet does matter. It has to be equal to the ACK number of the server’s reply. If you do that the server will close it’s connection and FreeRTOS+TCP can connect (with the same local port) to that remote port again in the next connect attempt.

So, this is my fix in the +TCP stack:
In file FreeRTOS_TCP_IP.c, line 2335, function prvHandleSynReceived(), I have added 1 line of code:
pxTCPWindow->ulOurSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulAckNr );

This seems to work, the server will close it’s connection and I can connect to it again.
Please let me know whether this is the right way to fix it. Could there be side effects? Because ulOurSequenceNumber has suddenly changed?

Addtional comment:
Line 2332: pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST; should be
pxTCPHeader->ucTCPFlags = ipTCP_FLAG_RST;
Correct?

regards,
Ken

heinbali01 wrote on Friday, November 10, 2017:

Ken, thank you very much for noticing and reporting this!

Here below is a patch that sets both the Sequence and the ACK number as expected by the host
( other RST packets are being sent with the correct values. In those cases the SEQ and ACK are just swapped ).

In FreeRTOS_TCP_IP.c, in function prvHandleSynReceived(), around line 2331 :

         FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n",
             pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN",
             usExpect, ucTCPFlags ) );
         vTCPStateChange( pxSocket, eCLOSE_WAIT );
+
+        /* Send RST with the expected sequence numbers, otherwise it will be ignored. */
+        pxTCPWindow->ulOurSequenceNumber = FreeRTOS_htonl( pxTCPHeader->ulAckNr );
+        pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber;
+
-        pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST;
+        pxTCPHeader->ucTCPFlags = ipTCP_FLAG_RST;
         xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength );
         pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 );

Still I would like to urge users to use a random value for srand(), especially while you are testing, experimenting, and doing many reboots.

But with the patch here above, it will be easier to detect the problem: the socket will get the eCLOSE_WAIT status much quicker.

Thanks again.