This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

recv() blocks forever

Dear community

In an attempt to implement an LTE TCP client, I'm stuck at the problem, that `recv()` doesn't return after the server has closed the connection.

My test implementation does a simple http request (source code attached at the end of the message):

  1. Connect to a web server
  2. Send "GET / HTTP/1.0\r\n\r\n"
  3. Shutdown (SHUT_WR)
  4. Receive while return value of `recv()` > 0.
  5. Close

It does everything nicely except it never arrives at stage 5.

According to https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html I would expect it to return '0' after the server has shut down the connection.

Any suggestions on what could be the problem here would be greatly appreciated!

Environment:
-- Zephyr version: 2.3.0-rc1
-- Board: nrf9160dk_nrf9160
-- West version: 0.7.2
-- DTC version: 1.4.7
-- Toolchain: gcc-arm-none-eabi-7-2018q2

Code used for testing:

int test_tcp(void) {    
    int ret = -1;
    int fd = -1;
    struct addrinfo *addr_res;
    char recv_buf[10];

    /** 
     * Init modem & link control
     */
    ret = at_cmd_write("AT+CMEE=1", NULL, 0, NULL);
    if (ret != 0) {
        printk("at_cmd_write(AT+CMEE=1) failed with %d\n", ret);
        return 0;
    }
    ret = lte_lc_init();
    if (ret != 0) {
        printk("lte_lc_init() failed with %d\n", ret);
        return 0;
    }

    /**
     * Connect to LTE network 
     */
    ret = lte_lc_connect();
    if (ret != 0) {
        printk("lte_lc_connect() failed with %d\n", ret);
        return 0;
    }

    printk("--------- LTE CONNECTED ---------\n");

    /**
     * Connect to TCP host
     */
    struct addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_STREAM};
    ret = getaddrinfo("petstore.swagger.io", NULL, &hints, &addr_res);
    if(ret != 0) {
        printk("getaddrinfo() failed with %d\n", errno);
        return 0;
    }

    ((struct sockaddr_in*)addr_res->ai_addr)->sin_port = htons(80);

    fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (fd < 0) {
        printk("socket() failed with %d\n", errno);
        return 0;
    }

    ret = connect(fd, addr_res->ai_addr, sizeof(struct sockaddr_in));
    if (ret < 0) {
        printk("connect() failed with %d\n", errno);
        return 0;
    } else {
        printk("--------- TCP CONNECTED ---------\n");
    }

    char *query = "GET / HTTP/1.0\r\n\r\n";

    ret = send(fd, query, strlen(query), 0);
    if (ret < 0) {
        printk("send() failed with %d\n", errno);
        return 0;
    }

    ret = shutdown(fd, SHUT_WR);
    if (ret < 0) {
        printk("shutdown() failed with %d\n", errno);
        return 0;
    }

    printk("--------- START RECEIVING ---------\n");

    do {
        ret = recv(fd, recv_buf, sizeof(recv_buf-1), 0);
        if (ret > 0) {
            recv_buf[ret] = '\0';
            printk("%s", recv_buf);
        }
    } while (ret > 0);

    if (ret < 0) {
        printk("recv() failed with %d\n", errno);
        return 0;
    }

    printk("--------- END RECEIVING ---------\n");

    close(fd);
    
    return 0;
}

Output:

*** Booting Zephyr OS build v2.3.0-rc1-ncs1 ***
+CEREG: 2,"9D08","013A2305",7,0,0,"11100000","11100000"
+CEREG: 5,"9D08","013A2305",7,,,"11100000","11100000"
--------- LTE CONNECTED ---------
--------- TCP CONNECTED ---------
--------- START RECEIVING ---------
HTTP/1.1 302 Moved Temporarily
Server: awselb/2.0
Date: Fri, 07 Aug 2020 17:31:50 GMT
Content-Type: text/html
Content-Length: 126
Connection: close
Location: prod-swagger-oss-1833484297.us-east-1.elb.amazonaws.com:443/

<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
</body>
</html>

Related