This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC3000 how to detect TCP connection is closed

Other Parts Discussed in Thread: MSP430F5529

Hello, I'm writing a simple echo server with a CC3000 and am running into difficulty detecting when a connection is closed.  Here's what I've tried:

- Be notified by select() that the closed socket is available for reading, then getting 0 bytes back from recv(). I.e. normal BSD socket behavior. Unfortunately it looks like TI's firmware explicitly does not support this behavior, at least according to the answer here: http://e2e.ti.com/support/low_power_rf/f/851/t/200366.aspx

Be notified by select() that the closed socket is in an exception state through the exceptsds result. The TI docs claim a closed socket will be in an error state, but I can't see closed sockets getting returned from select in the exceptsds result. This thread seems to corroborate the behavior I see: http://e2e.ti.com/support/low_power_rf/f/851/t/259746.aspx 

Try sending 0 bytes of data and catching the error that the socket is closed. This is suggested as a workaround in the above thread, but when I try to call send with a size of zero bytes my MCU appears to be resetting itself (not sure what's going on, maybe some undefined behavior with the CC3000?)

I wanted to check, what's the right way to detect that a TCP connection has been closed?  Is actually sending data with send (as opposed to faking it with a 0 byte size send) and detecting an error the only way?

  • Hrm I'm also seeing some odd behavior when trying to implement a workaround to send some data (a string of text like 'Keep Alive' periodically) to detect a closed connection.  After a connection is closed by a client, my periodic send() command is still succeeding and claiming it sent some number of bytes.  This seems unexpected as the connection is closed.

    Can anyone shed some light on how you can detect a connection is closed with the CC3000?

  • I would also love to hear the answer to this. Writing robust firmware is hard enough with all the blocking API calls, but to have your whole application halt to a grind because of a closed socket is much worse. I see that there is an asynchronous notification HCI_EVNT_BSD_TCP_CLOSE_WAIT, but it has no arguments. How should we determine what TCP socket was closed?

  • Hi Vishal,

    In the callback 'CC3000_UsynchCallback', the argument char *data would help you to get the remote socket that was closed.

    You can access data[0] to get the remote socket that was closed. You can take reference from the HTTPServer application provided in the SDK. This sample code would help you understand handling of 'HCI_EVNT_BSD_TCP_CLOSE_WAIT' better.

    Thanks & Regards,

    Raghavendra

  • Hi Raghavendra,

    as far as I remember the data[0] is only 1 byte instead of 4 bytes which is used by socket at all other places. I assume it is the same number (no matter of 1 or 4 bytes) and must be "prefixed" by "0x000000 + data[0]" (just number conversion). Is it correct, it is not an index or similar?

    (Theoretical!) Example (just for my understanding):

    Socket 0x00000001 and 0x00000003 are used (not yet closed nor not yet opened).

    Second socket (0x00000003) wants to signal HCI_EVNT_BSD_TCP_CLOSE_WAIT.

    I assume to get data[0] as 0x03, not something like index 0x02 (second active connection).

    Why was only used 1 byte instead of 4 like on other places for socket?

    Due to using only 1 byte, is it correct to assume that socket number would never be outside 0 to x (I think x was 3, meaning 4 open sockets supported...but just tried, seems to be going up to 7), so is it secure to store socket everywhere as 1 byte, otherwise it would break HCI_EVNT_BSD_TCP_CLOSE_WAIT mechanism (because sockets don't match anymore)?

    BTW: Is a description of HCI_EVNT_BSD_TCP_CLOSE_WAIT somewhere in API description? I think it is missing here

    http://software-dl.ti.com/ecs/simplelink/cc3000/public/doxygen_API/v1.11.1/html/d0/d5e/group__wlan__api.html#ga9f6c43e4bb38b61581cf6481ca3efaa6

    and Google has not found pages in API about this event at all...

    Thanks for clarifying!

    Best regards,

    Martin

  • Hi Martin,

    Yes, you are right. The data[0] does not directly give you the socket descriptor. To be more clear, it just points you to the socket that was closed. It is implementation specific, where one maintains the index and implements the action based on the index corresponding to the event (Reset the descriptor for example). Perhaps, the HTTP Server is the right example to just check the handling.

    Regarding the API documentation, I will take note of this, and look at what I can do to improve it.

    Thanks & Regards,

    Raghavendra

     

  • Hi Raghavendra,

    thanks for the quick reply!

    Can you give more details how value in data[0] is calculated inside CC3000?

    There is some code outside CC3000 which calculates this value data[0] and some calculation of a value inside data[0]. As far as i have seen there is no description at all. If both implementation don't match, it does not work, because if one side is reporting value x (meaning socket y) and host meaning socket z, it is closing the wrong socket...

    Re-engineering the implementation from HTTP example is not what I think is an accurate way to do implementation.

    See following code, "sd" can store 9 entries. Why 9 not more not less?

    Is it counted up each time, when an outgoing or incoming TCP connection is established?

    What about race conditions, when outgoing connection and incoming TCP connection is done at the same time. Host counts up for one connection, whereas CC3000 has some value for different connection?

    Why not return socket (keep it simple)? Would it not still be possible (because it is backward compatible) to return socket behind data[0] (e.g. as 4 bytes starting in data[1] or data[4] if alignment needed)?

    Looking into

    C:\ti\CC3000SDK\CC3000 SDK\MSP430F5529\HTTP Server Application\HTTP Server Source\Source\WebServer Application

    cc3000.c

    char CheckSocket = 0;
    signed char sd[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0};

        if (lEventType == HCI_EVNT_BSD_TCP_CLOSE_WAIT)
        {
          sd[data[0]] = 1;
          CheckSocket = 1;
        }

    In HttpCore.c

            // Client socket is closed, close socket

            if(CheckSocket == 1)
            {
              for(count = 0; count<9 ; count++)
              {
                if(sd[count] == 1)
                {
                  HttpCore_CloseConnection(count);
                  sd[count] = 0;
                }
              }
              for(uConnection = 0; uConnection < HTTP_CORE_MAX_CONNECTIONS; ++uConnection)
              {
                if (g_state.connections[uConnection].connectionState != Inactive)
                {
                // Check for socket timeouts
                  curSocket =  getsockopt(g_state.connections[uConnection].dataSocket, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK  , &optval, (socklen_t*)&optlen);
                  if (curSocket == -57)
                  {
                    HttpCore_CloseConnection(uConnection);
                  }
                }
              }
              CheckSocket = 0;
            }

    /**
     * Close a connection and clean up its state
     */
    static void HttpCore_CloseConnection(uint16 uConnection)
    {
        HttpDebug("Close connection");

        closesocket(g_state.connections[uConnection].dataSocket);

        g_state.connections[uConnection].connectionState = Inactive;
        g_state.connections[uConnection].dataSocket = INVALID_SOCKET;
        g_state.connections[uConnection].HttpAuth = 0;
        HttpCore_ResetConnection(uConnection);
        if(g_state.uOpenConnections > 0)
          g_state.uOpenConnections--;
    }

    From first point of view this looks more complicated, than first thought. Can you please clarify this in a bit more detail?

    Many thanks!

    Best regards,

    Martin

  • Thanks, Raghavendra. Your post made me realize I was using an older version of the service pack and host driver that didn't send and encode the socket descriptor in the callback arguments. I updated and got it working, thanks!