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.

SO_KEEPALIVE usage

Hello,

I am running a tcp socket server on TM4C129EXL LP and also have multiple LabVIEW tcp clients to communicate with it. I have a router with dhcp enabled ( uC is in auto obtain IP address). 

I would like to prepare server side code is to detect if any client is disconnected but not in a conventional way. I mean link layer failure of if the client is out of wifi range and so on. 

I made some tests to detect client side connection loss, such as ethernet cable removal btw. the uC and the router, but the following code:

bytesSent = send(clientfd,tcpPacket,HCOM_PACKET_SIZE_1024,0);

executes without any error, bytesSent is a valid number. I read about SO_KEEPALIVE that may help : 

Here is my server side code:

void tcpHandler(UArg arg0, UArg arg1)
{

    int                status;
    int                clientfd;
    int                server;
    struct sockaddr_in localAddr;
    struct sockaddr_in clientAddr;
    int                optval;
    int                optlen = sizeof(optval);
    socklen_t          addrlen = sizeof(clientAddr);
    Task_Handle        taskHandle;
    Task_Params        taskParams;
    Error_Block        eb;

    server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (server == -1) {
        System_printf("Error: socket not created.\n");
        goto shutdown;
    }


    memset(&localAddr, 0, sizeof(localAddr));
    localAddr.sin_family = AF_INET;
    localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    localAddr.sin_port = htons(arg0);

    status = bind(server, (struct sockaddr *)&localAddr, sizeof(localAddr));
    if (status == -1) {
        System_printf("Error: bind failed.\n");
        goto shutdown;
    }

    status = listen(server, NUMTCPWORKERS);
    if (status == -1) {
        System_printf("Error: listen failed.\n");
        goto shutdown;
    }

    // Set KEEPALIVE option to 1
    optval = 1;
    if (setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0)
    {
        System_printf("Error: setsockopt failed\n");
        goto shutdown;
    }


    if(getsockopt(server, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0)
    {
    	System_printf("Error: setsockopt failed\n");
		goto shutdown;
    }
    System_printf("Keepalive value: %d\r\n",optval);
    System_flush();


    while ((clientfd = accept(server, (struct sockaddr *)&clientAddr, &addrlen)) != -1)
    {
        System_printf("tcpHandler: Creating thread clientfd = %d\n", clientfd);

        /* Init the Error_Block */
        Error_init(&eb);

        Mailbox_Handle clientmb = lockMailbox();

        if(clientmb == NULL)
        {
        	System_printf("Unable to get mailbox\r\n");
        }

        /* Initialize the defaults and set the parameters. */
        Task_Params_init(&taskParams);
        taskParams.arg0 = (UArg)clientfd;
        taskParams.arg1 = (UArg) clientmb;
        //taskParams.arg1 = (UArg)TCP_Mailbox_Transmit;				// here we use the static mailbox created in XCONF
        taskParams.priority = 1;
        taskParams.stackSize = 2048;

        taskHandle = Task_create((Task_FuncPtr)TCP_Receive_Task, &taskParams, &eb);
        if (taskHandle == NULL)
        {
            System_printf("Error: Failed to create new Task\n");
            System_flush();
            close(clientfd);
        }

        taskParams.stackSize = 4096;
        taskHandle = Task_create((Task_FuncPtr)TCP_Transmit_Task, &taskParams, &eb);
		if (taskHandle == NULL)
		{
			System_printf("Error: Failed to create new Task\n");
			System_flush();
			close(clientfd);
		}

        /* addrlen is a value-result param, must reset for next accept call */
        addrlen = sizeof(clientAddr);

        System_flush();


    }

    System_printf("Error: accept failed.\n");

shutdown:
    if (server > 0) {
        close(server);
    }


}

When I start the server with wireshark I don't see any keepalive message btw the nodes. In the ndk\inc\stack\inc\resif.h I made the following changes:

#define DEF_TCP_KEEP_IDLE           600//72000   /* 2 hours */
#define DEF_TCP_KEEP_INTVL          750     /* 75 seconds */
#define DEF_TCP_KEEP_MAXIDLE        600//6000    /* 10 minutes */

But doen't have any effect on keepalive. 

My question is what is the proper way to use keepalive and how to configure the IDLE,INTVL,etc. values?

  • Hi Daniel,
    I'm currently looking into this and will touch base with you tomorrow on how to resolve this.

    Thanks for your patience,
    Moses
  • Hello Moses, 

    Thank you for your reply, I will waiting for the result.

  • Hi Daniel,

        Making changes to the header file doesn't have any effect unless you rebuild the entire NDK. The right way to configure this is in your *.cfg file using the TCP module. Here's sample code you can add to your cfg file instead:

    var Tcp = xdc.useModule(‘ti.ndk.config.Tcp’);
    Tcp.keepIdleTime = 600; // 72000
    Tcp.keepProbeInterval = 750; // unchanged
    Tcp.keepProbeTimeout = 600; // 6000

    Here's also the lines in the TCP config module that explains the config options used above:

        /*!
         *  Amount of time to allow socket to idle. Only affects sockets
         *  specified with SO_KEEPALIVE value.
         *
         *  Time units for this value are in 0.1 seconds.
         */
        config Int keepIdleTime = defaultKeepIdleTime;
     
        /*!
         *  Time interval specifying the amount of time in between TCP KEEP probes
         *  Only affects sockets specified with SO_KEEPALIVE value.
         *
         *  Used to determine if socket should be kept open. Time units for this
         *  value are in 0.1 seconds.
         */
        config Int keepProbeInterval = defaultKpProbIntv;
     
        /*!
         *  Time TCP will continue to send unanswered KEEP probes before timing out
         *  the connection.
         *
         *  Time units for this value are in 0.1 seconds.
         */
        config Int keepProbeTimeout = defaultKpProbTimeout;

    Let me know if this helps,

    Moses

  • Hello Moses,

    Thank you for your help. It works fine.

    Where can I find more info about this configuration procedure that you suggested? 

    Since, the keepalive works well, how to use this option to close the socket from the server side? I mean, how to know that keep_alive not acknowledged in NDK? I have a blocking recv() function

  • Hi Daniel,

        I'll recommend taking a look at the NDK Users guide for more information. Also in your NDK product, under docs/cdoc/index.html you can navigate to ti.ndk.config.Tcp to read about the configuration and settings for the TCP module.

        In your wireshark screen capture, which is the client and which is the server. When you take the client down are you still seeing the keep-alives getting ACKed?

    Thanks,

    Moses