Modem error 122 (EMSGSIZE) when downloading file over ~50KB via HTTP/TCP/IPv6/LTE-M

I'm trying to download a largish file (~167KB) via HTTP/TCP/IPv6 but the modem crashes every time around the same point during the download. It's spits out error 122, which I believe is EMSGSIZE. That would imply that the supplied buffer is too small or NULL. This happens regardless of the size of the buffer I give it. Sockets are offloaded to the modem and net native is set to no. I've tried to increase the size for just about every related Kconfig setting I can find with no change. Maybe it's MTU related?

I am writing the `recv()` bytes directly to flash, but I don't see any errors there.

Error log:

D: addrinfo @0x200302e0: ai_family=2, ai_socktype=1, ai_protocol=6, sa_family=2, sin_port=bb01

D: Total: 49176
I: lib free  0x200187dc, size 20
I: lib alloc 0x200187dc, size 20
I: lib alloc 0x2001883c, size 20
I: lib free  0x200187f4, size 20
I: lib free  0x2001880c, size 20
I: lib free  0x20018824, size 20
I: lib free  0x200187dc, size 20
D: recv bytes: 4096
D: Total: 50545
I: lib free  0x2001883c, size 20
D: recv bytes: 11
D: Total: 54641
E: recv() body failed, err 122

E: EOF or error in response headers.
I: Closing socket 0
D: (main): close: ctx=0x200136b0, fd=0
I: lib free  0x200187c4, size 20

Testing conf:

# General
CONFIG_STACK_SENTINEL=y

# NRF Modem
CONFIG_MODEM_INFO=y
CONFIG_NRF_MODEM_LIB=y
CONFIG_MODEM_KEY_MGMT=y
CONFIG_PDN=y
CONFIG_NRF_MODEM_LIB_ON_FAULT_DO_NOTHING=y
# CONFIG_NRF_MODEM_LIB_SHMEM_RX_SIZE=8192
# CONFIG_NRF_MODEM_LIB_HEAP_SIZE=1024
CONFIG_NRF_MODEM_LIB_SHMEM_RX_SIZE=32768
CONFIG_NRF_MODEM_LIB_HEAP_SIZE=4096
CONFIG_NRF_MODEM_LIB_SENDMSG_BUF_SIZE=256

# Align the max FD entry to NRF_MODEM_MAX_SOCKET_COUNT(8)
CONFIG_POSIX_MAX_FDS=8

# NRF net options
CONFIG_NET_NATIVE=n
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_SOCKETS_OFFLOAD=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_BUF_RX_COUNT=56

# Disable Duplicate Address Detection (DAD)
# due to not being properly implemented for offloaded interfaces.
CONFIG_NET_IPV6_NBR_CACHE=n
CONFIG_NET_IPV6_MLD=n

# Setup LTE
CONFIG_LTE_LINK_CONTROL=y
CONFIG_LTE_PSM_REQ=y
# Active time set to 0 so we can go right to PSM
CONFIG_LTE_PSM_REQ_RAT="00000000"
CONFIG_LTE_EDRX_REQ=y
# PTW set to the minimum value, 1.27s, to conserve power
CONFIG_LTE_PTW_VALUE_LTE_M="0000"
# RAI is only supported for NBIoT currently
# CONFIG_LTE_RAI_REQ=y

# Allow writing to the flash at runtime
CONFIG_MPU_ALLOW_FLASH_WRITE=y

# Debugging
CONFIG_NRF_MODEM_LIB_LOG_LEVEL_DBG=y
CONFIG_NRF_MODEM_LIB_MEM_DIAG=y
CONFIG_LTE_LINK_CONTROL_LOG_LEVEL_DBG=y
CONFIG_NVS_LOG_LEVEL_DBG=y
CONFIG_NRF_MODEM_LIB_FAULT_STRERROR=y
CONFIG_NRF_MODEM_LIB_MEM_DIAG_ALLOC=y

# Set Stack Size
CONFIG_MAIN_STACK_SIZE=82432
# Increase heap size for networking operations
CONFIG_HEAP_MEM_POOL_SIZE=8192

# Compiler size optimizations
CONFIG_SIZE_OPTIMIZATIONS=n

# Some MCUmgr command handlers require a large stack.
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304

# Networking Logging
CONFIG_NET_LOG=y
CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y
CONFIG_NET_HTTP_LOG_LEVEL_DBG=y

# Debugging
CONFIG_DEBUG=y
CONFIG_DEBUG_OPTIMIZATIONS=n
# CONFIG_DEBUG_INFO=n

CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_THREAD_NAME=y

Relevant code:

/***** Out of file *****/
char write_buf[4096];
 
int write_buffer_to_flash(char *data, size_t len, size_t offset) {
  if (len % write_block_size == 0) {
    // LOG_DBG("Writing to flash");
    if (flash_write(external_flash, offset, data, len)) {
      return -1;
    }
  } else {
    return len;
  }

  return 0;
}
/***********************/

static int parse_response(
    int *sock, char *recv_body_buf, int recv_body_buf_size, _Bool write_nvs
) {
  int rc = 0;
  int state = 0;
  int bytes;
  size_t offset = 0;
  bool headers = true;
  int status;
  size_t headers_size = 0;

  do {
    if (headers) {
      bytes = recv(*sock, &headers_buf[offset], 1, 0);
      if (bytes < 0) {
        LOG_ERR("recv() headers failed, err %d\n", errno);
        return bytes;
      }

      if ((state == 0 || state == 2) && headers_buf[offset] == '\r') {
        state++;
      } else if (state == 1 && headers_buf[offset] == '\n') {
        state++;
      } else if (state == 3) {
        headers_size = offset;
        LOG_INF("Received Headers. Size: %d bytes", offset);

        headers = false;
        headers_buf[offset + 1] = '\0';
        offset = 0;

        status = parse_status();
        switch (status) {
          case HTTP_REDIRECT:
            return 1;
          case HTTP_CLIENT_ERROR:
            return -1;
          case HTTP_SERVER_ERROR:
            return -1;
          case HTTP_NULL:
            return -1;
          default:
            break;
        }
        continue;
      } else {
        state = 0;
      }
    } else {
      if (write_nvs) {
        if (rc > 0) {
          bytes =
              recv(*sock, (recv_body_buf + rc), (recv_body_buf_size - rc), 0);
          if (bytes < 0) {
            LOG_ERR("recv() body failed, err %d\n", errno);
            return bytes;
          }
          bytes += rc;
          LOG_DBG("recv + rc bytes: %d", bytes);
        } else {
          bytes = recv(*sock, recv_body_buf, recv_body_buf_size, 0);
          if (bytes < 0) {
            LOG_ERR("recv() body failed, err %d\n", errno);
            return bytes;
          }
          LOG_DBG("recv bytes: %d", bytes);
        }
        rc = write_buffer_to_flash(recv_body_buf, bytes, offset);
        LOG_DBG("Total: %d", offset);
        if (rc < 0) {
          LOG_DBG("rc: %d, error: %d", rc, errno);
          return -1;
        }
      } else {
        bytes = recv(
            *sock, (recv_body_buf + offset), (recv_body_buf_size - offset), 0
        );
      }
    }
    offset += bytes;
  } while (bytes != 0); /* peer closed connection */

Parents Reply
  • I didn't get the download client working due to other errors, 118 & 116 I think it was. I don't have too much time to work on that though. For now I got things working by fragmenting and retrying until the download is complete.

    I have to close the socket and create a new one to stop the issue from happening again immediately. Is there a way to manually clear the offloaded socket receive buffers?

Children
Related