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

TCP dropping data

I have a simple TCP client application running on the nRF9160. After connection to the server,  recv is called and writes the data over Segger RTT channel 1, where on the host JLinkRTTLogger.exe logs the data to a file.

The server is the unix netcat utility that is sending a binary file of random data (256kB) from stdin.

cat rand.bin | nc -l PORT

If revc is called with no latency, the file is received in its entirety and verified with the original file using the diff utility. However, if a sleep statement is added in the recv loop, simulating processing the chunk of data (like erasing and writing to flash) the stream drops data to the application in 708 byte chunks and the received file is corrupted. The connection is monitored with wireshark on the server and shows the entire file is sent, indicated by the acknowledgment byte count.

My expectation with the TCP would be the flow-control/backpressure mechanism to throttle the connection and the sender would send data when the receiver has availability in its Receive Window. It does seem to be doing this in the modem firmware as I can see the Receive Window for the client shrink and grow dynamically in wireshark. The current behavior through the entire stack to the application violates the TCP protocol of reliable transmission. I can hack around this limitation by adding complexity to the application layer ... but this problem has been solved with the TCP standard. I would also rather the connection be closed than random data in the TCP stream be dropped and not sent to the application.

Is there an option/configuration I am missing that would fix this issue?

Modem firmware: 0.7.0-2.9alpha
SW version: see west.yml

#include <zephyr.h>
#include <net/socket.h>
#include <lte_lc.h>

#include <SEGGER_RTT.h>

static uint8_t rtt_buf[1024];
static uint8_t recv_buf[1024];

#ifdef CONFIG_BSD_LIBRARY

void bsd_recoverable_error_handler(uint32_t err)
{
    printk("bsdlib recoverable error: %u\n", err);
}

void bsd_irrecoverable_error_handler(uint32_t err)
{
    printk("bsdlib irrecoverable error: %u\n", err);

    __ASSERT_NO_MSG(false);
}

#endif

void main(void)
{
    int err;

    printk("tcp_client sample\n");
    printk("Configuring RTT up buffer 1 ... ");
    SEGGER_RTT_ConfigUpBuffer(1, "File", rtt_buf, sizeof(rtt_buf), SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
    printk("done.\n");

    printk("LTE Link Connecting ...\n");
    err = lte_lc_init_and_connect();
    __ASSERT(err == 0, "LTE link could not be established.");
    printk("LTE Link Connected!\n");

    struct addrinfo *res;
    struct addrinfo hints = {
        .ai_family = AF_INET,
        .ai_socktype = SOCK_STREAM};

    err = getaddrinfo(CONFIG_TCP_SERVER_HOST, NULL, &hints, &res);
    __ASSERT(err == 0, "Server hostname could not be resolved, err=%d, errno=%d", err, errno);
    ((struct sockaddr_in *)res->ai_addr)->sin_port = htons(CONFIG_TCP_SERVER_PORT);

    int client_fd;

    for(int i=0; i<16; i++)
    {
        client_fd = socket(AF_INET, SOCK_STREAM, 0);
        printk("client_fd: %d\n\r", client_fd);

        err = connect(client_fd, (struct sockaddr *)res->ai_addr, sizeof(struct sockaddr_in));
        if (err==0)
        {
            break;
        }
        err = close(client_fd);
        printk("Attempt %d: could not connect to server, err=%d, errno=%d\n", i, err, errno);
        k_sleep(1000*i*i); //simple exponential back-off
    }
    __ASSERT(err == 0, "Error, could not connect to server, err=%d, errno=%d", err, errno);
    printk("Connected to server.\n");

    int ret;
    int total_rx_bytes = 0;
    while(1)
    {
        ret = recv(client_fd, recv_buf, sizeof(recv_buf), 0);
        if (ret > 0)
        {
            total_rx_bytes += ret;
            printk("Rx %d bytes, total=%d\n", ret, total_rx_bytes);
            SEGGER_RTT_Write(1, recv_buf, ret);
        }
        else if (ret < 0 && errno == EAGAIN)
        {
            printk("EAGAIN\n");
        }
        else
        {
            printk("Unhandled error, ret=%d, errno=%d\n", ret, errno);
            break;
        }
        k_sleep(4000); //<-- seems to be the culprit for lost data :(
    }

    printk("Closing socket ... ");
    err = close(client_fd);
    __ASSERT(err == 0, "Could not close socket, err=%d.", err);
    printk("goodbye.\n");
}
# General config
CONFIG_TRUSTED_EXECUTION_NONSECURE=y
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_ASSERT=y
CONFIG_REBOOT=y
CONFIG_NO_OPTIMIZATIONS=y
CONFIG_HEAP_MEM_POOL_SIZE=1024

# Logging
CONFIG_LOG=y
CONFIG_PRINTK=y
CONFIG_CONSOLE=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_LOG_BUFFER_SIZE=2048

# Segger RTT
CONFIG_UART_CONSOLE=n
CONFIG_HAS_SEGGER_RTT=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y

# Main thread
CONFIG_MAIN_THREAD_PRIORITY=7
CONFIG_MAIN_STACK_SIZE=4096

# BSD library (nrf)
CONFIG_BSD_LIBRARY=y
CONFIG_BSD_LIBRARY_TRACE_ENABLED=n

# Networking
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_LOG=y

# LTE link control
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_AUTO_INIT_AND_CONNECT=n
CONFIG_LTE_LINK_CONTROL_LOG_LEVEL=4
# The west manifest file for RED firmware

west:
  url: https://github.com/zephyrproject-rtos/west
  revision: v0.5.8

manifest:
  remotes:
    - name: red
      url-base: [email protected]:bbr/red
    - name: ncs
      url-base: https://github.com/NordicPlayground
    - name: zephyrproject
      url-base: https://github.com/zephyrproject-rtos
    - name: throwtheswitch
      url-base: https://github.com/ThrowTheSwitch
    - name: armmbed
      url-base: https://github.com/ARMmbed
  projects:
    - name: fw-nrfconnect-nrf
      path: nrf
      revision: 6ebf0385ddc560d32168ec175d19738135bfb6f3
      remote: ncs
    - name: fw-nrfconnect-zephyr
      path: zephyr
      west-commands: scripts/west-commands.yml
      revision: 3c4f27282002e634d60216f23fb341317a4b199f
      remote: ncs
    - name: fw-nrfconnect-mcuboot
      path: mcuboot
      revision: 4b919890cc848316304b81d9e160fe5a10ce3764
      remote: ncs
    - name: fw-nrfconnect-tinycbor
      path: modules/lib/tinycbor
      revision: ef1f9c3d87474ec3570b1f46e91fd4b54a4fb421
      remote: ncs
    - name: nrfxlib
      path: nrfxlib
      revision: v0.4.0
      remote: ncs
    - name: cmock
      path: test/cmock
      revision: c243b9a7a7b3c471023193992b46cf1bd1910450
      remote: throwtheswitch
    - name: unity
      path: test/cmock/vendor/unity
      revision: 031f3bbe45f8adf504ca3d13e6f093869920b091
      remote: throwtheswitch
    - name: mbedtls
      path: mbedtls
      revision: mbedtls-2.13.1
      remote: armmbed
  self:
    path: fw

Related