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.

RTOS: NDK sockets

Tool/software: TI-RTOS

Hello,

 I have set up a TCP server and enabled  the socket’s options:  SO_RCVTIMEO , SO_SNDTIMEO.

I called recv() with the flag MSG_WAITALL  and I noticed that there is no timeout on recv() (i.e. after the time defined with SO_RCVTIMEO recv() still blocks())

From what I read I could not find an explicit answer but it sounded like that the timeout option should be in effect, if set ,even with MSG_WAITALL in recv().

I also tried removing the MSG_WAITALL from recv() (setting flags parameter to 0) and still recv() blocks forever without any timeout.

Can you please explain (or help fix)  why the timeout does not hold ?

Thanks 

Guy

  • What values are you using for the timeout? Are you letting the kernel create the default 1ms clock tick? You can look in ROV->Clock to confirm this. Is the clock tick advancing if you run, look at the tick count in ROV, run, and look at the tick count in ROV again.

    Also, what NDK version are you using?
  • Hi,
    I looked at ROV and the clock it ticking.

    as for the timeout the socket option is set as follows:

    struct timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    setsockopt(hSock,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));

    i also check the setsockopt returns without errors.

    NDK version i use - 2.24.2.31

    Thanks
    Guy
  • Thanks. I'll check this out tomorrow when I'm in the office. Sorry, I forgot to ask what device are you on?
  • Hi,
    I am working on TDA3xx (the specific code is on the ARM M4)

    Thanks
    Guy
  • Hi Guy,

    I tried an example with 2.24.02.31 (and again with 2.25.00.09) and it worked fine. I set both SO_RCVTIMEO and SO_SNDTIMEO to 5 seconds. I had my laptop sending a TCP packet (on port 1000)that the target just echo'd back. I had the laptop stop sending for a bit but not close the socket. I checked (via WireShark) that the target closed the socket in 5 seconds.  

    Here is the primary source file that I used for testing.

    tcpEcho.c
    /*
     * Copyright (c) 2014-2015, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     *    ======== tcpEcho.c ========
     *    Contains BSD sockets code.
     */
    
    #include <string.h>
    
    #include <xdc/std.h>
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/System.h>
    
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/drivers/GPIO.h>
    
    /* NDK BSD support */
    #include <sys/socket.h>
    
    /* Example/Board Header file */
    #include "Board.h"
    
    #define TCPPACKETSIZE 256
    #define NUMTCPWORKERS 3
    
    /*
     *  ======== tcpWorker ========
     *  Task to handle TCP connection. Can be multiple Tasks running
     *  this function.
     */
    Void tcpWorker(UArg arg0, UArg arg1)
    {
        int  clientfd = (int)arg0;
        int  bytesRcvd;
        int  bytesSent;
        char buffer[TCPPACKETSIZE];
    
        System_printf("tcpWorker: start clientfd = 0x%x\n", clientfd);
        struct timeval timeout;
            timeout.tv_sec = 5;
            timeout.tv_usec = 0;
    
            if (setsockopt (clientfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
                        sizeof(timeout)) < 0)
                System_printf("Error: setsockopt failed 2\n");
    
            if (setsockopt (clientfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
                        sizeof(timeout)) < 0)
                System_printf("Error: setsockopt failed 3\n");
    
    
        while (1) {
            bytesRcvd = recv(clientfd, buffer, TCPPACKETSIZE, 0);
            if (bytesRcvd <= 0) {
                System_printf("timeout\n");
                break;
            }
    
            bytesSent = send(clientfd, buffer, bytesRcvd, 0);
            if (bytesSent < 0 || bytesSent != bytesRcvd) {
                System_printf("Error: send failed.\n");
                break;
            }
        }
        System_printf("tcpWorker stop clientfd = 0x%x\n", clientfd);
    
        close(clientfd);
    }
    
    /*
     *  ======== tcpHandler ========
     *  Creates new Task to handle new TCP connections.
     */
    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;
        }
    
        optval = 1;
        if (setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
            System_printf("Error: setsockopt failed 1\n");
            goto shutdown;
        }
    
        while (1) {
    
    
            clientfd = accept(server, (struct sockaddr *)&clientAddr, &addrlen);
            if (clientfd == -1) {
                    System_printf("timeout\n");
                    continue;
                }
    
            System_printf("tcpHandler: Creating thread clientfd = %d\n", clientfd);
    
            /* Init the Error_Block */
            Error_init(&eb);
    
            /* Initialize the defaults and set the parameters. */
            Task_Params_init(&taskParams);
            taskParams.arg0 = (UArg)clientfd;
            taskParams.stackSize = 1280;
            taskHandle = Task_create((Task_FuncPtr)tcpWorker, &taskParams, &eb);
            if (taskHandle == NULL) {
                System_printf("Error: Failed to create new Task\n");
                close(clientfd);
            }
    
            /* addrlen is a value-result param, must reset for next accept call */
            addrlen = sizeof(clientAddr);
        }
    
        System_printf("Error: accept failed.\n");
    
    shutdown:
        if (server > 0) {
            close(server);
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions */
        Board_initGeneral();
        Board_initGPIO();
        Board_initEMAC();
    
        System_printf("Starting the TCP Echo example\nSystem provider is set to "
                      "SysMin. Halt the target to view any SysMin contents in"
                      " ROV.\n");
        /* SysMin will only print to the console when you call flush or exit */
        System_flush();
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

    Todd

  • Hi,
    Thanks you for you help.
    It was my mistake - my client was closing the socket before the timeout expiration so the accepted socket on the server side never had a chance to actually timeout. i changed the client and indeed the timeout happens.

    about the code you sent - why have you set the SO_KEEPALIVE option - can you explain a bit about it (from my understanding it just makes the TCP sending keepalive packets after a time (not sure what is this time) when there is no traffic but i am not sure if and/or why it is necessary)

    one more thing - it seems the strerror function does not know the socket error codes (i.e. for the timeout it prints unknown error) - is there an alternative function in NDK to get the string form for the socket's error?

    Thanks
    Guy
  • The SO_KEEPALIVE option was in the example I tweaked. I expect that it was there for testing purposes. The default send time is 2 hours. If there were no timeouts on the recv/send APIs, its useful in making sure things are still alive.

    I don't see an strerror equivalent. I'm pinging one of the NDK engineers.

  • We don't have an equivalent API.
  • Thanks for your help.

    Guy