Help with LWIP, TCP, and IPV4

Hi everybody

I have a problem with my IPV4 use or configuration. I used the code from the test files for tcp ipv4 and LWIP. But if my frontend sends quickly messages in sequence with the responses it starts to blocking, until the timeout from the frontend is running through. If the test is running on postman I have a similar behaviour that some messages generate like a blocking. The system recognize the message and connects to the frontend, but it doesn’t process the message. It doesn’t procedure to the flag SOCK_ASYNC_MSG_RECV until the message is cancelled. I have the same issue with the test/lwip if I start a server on port 8080, the message gets printed after I close the connection to the Microcontroller.

Do you have a better example how to treat a TCP IPV4 connection?

Thanks in advance Pava

PS the frontend communication is tested with a RPI which has a Python script running that has a network comm handling over Flask.

I wouldn’t count too much on getting support on the legacy IP front. May I ask why you don’t just use IPv6? What MCU/board are we talking here about? From your Raspberry Pi and Python this shouldn’t be too much of a difference. Besides the point of using the current standard and not an outdated one. There are also some known issues when using lwip with IPv4 and IPv6.

Hi citrullin

Our School doesn’t support IPV6 yet, because of that I’m working on the legacy IP front. I’m using a Nucleo F429ZI. I didn’t enable both IPV4 and IPV6, there is only IPV4 active on my side.

LwIP uses dynamic memory allocation and after netconn_delete(), the memory is not freed until the LAST WAIT timer has expired (2 * TCP_MSL or 120 seconds), which causes blockages when the memory is full.

According to RFC 9293, MSL stands for Maximum Segment Lifetime, which is the time a TCP segment can exist in the internetwork system. It was arbitrarily defined to be 2 minutes.

This arbitrary value comes from another era, when connections were slow and unreliable, so it can be reduced without any concern. It is defined in RIOT/build/pkg/lwip/src/include/lwip/priv/tcp_priv.h: #define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */.

It can be modified in the Makefile: CFLAGS += -DTCP_MSL=1000

I used a value of 1000 (1 second) because the frontend was making a request every 2 seconds in my application: GitHub - hugueslarrive/riot_lwip_httpd

Hi hugueslarrive

Thanks for your help, but your correction didn’t improved the behaviour, nor in my code or in the testing code.

Maybe this is concludes also to the Problem, after a while, this message arrives after a tcp call from some random people:

2023-05-15 11:30:50,551 # *** RIOT kernel panic:
2023-05-15 11:30:50,553 # MEM MANAGE HANDLER
2023-05-15 11:30:50,553 # 
2023-05-15 11:30:50,562 # 	pid | name                 | state    Q | pri | stack  ( used) ( free) | base addr  | current     
2023-05-15 11:30:50,570 # 	  - | isr_stack            | -        - |   - |    512 (  448) (   64) | 0x20000000 | 0x20000160
2023-05-15 11:30:50,579 # 	  1 | main                 | bl mutex _ |   7 |   1536 (  592) (  944) | 0x2000143c | 0x200018ec 
2023-05-15 11:30:50,588 # 	  2 | lwip_netdev_mux      | bl rx    _ |   3 |   1024 (  504) (  520) | 0x200039a8 | 0x20003cfc 
2023-05-15 11:30:50,596 # 	  3 | tcpip_thread         | bl mbox  _ |   1 |   1024 (  604) (  420) | 0x20001c10 | 0x20001f24 
2023-05-15 11:30:50,605 # 	  4 | TCP server           | running  Q |   6 |   1024 (  616) (  408) | 0x200009d0 | 0x20000c7c 
2023-05-15 11:30:50,611 # 	    | SUM                  |            |     |   5120 ( 2764) ( 2356)
2023-05-15 11:30:50,611 # 
2023-05-15 11:30:50,613 # *** halted.
2023-05-15 11:30:50,613 # 
2023-05-15 11:30:50,614 # Inside isr -12

In my Makefile I have also :

# lwip_netdev_mux will need more than the default 1024 bytes
CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=2048

and CFLAGS += -DMEM_DEBUG=LWIP_DBG_ON can help you to understand memory issues.

Hi hugueslarrive

Thanks for your input, in my main programm I changed the stacksize to 4096, but had still the same error. I tried it now in the test programm, still the same Issue. LWIP_DBG_ON didnt print anything neither…

This is my code I added to the _tcp_recv function to get the minimum Communication with my frontend:

#define HTTP_MESSAGE_BUFF_SIZE (10*SOCK_INBUF_SIZE)

static int emptyCstring(char *dest, size_t element_count){
    int answer = EXIT_SUCCESS;
    memset(dest,0,element_count);
    if(strlen(dest)>0){
        answer = EXIT_FAILURE;
    }
    return answer;
}
static int getHttpMethod(char *src, char *http_method_str){
    return sscanf(src, "%7s", http_method_str);
}
static int getHttpOrigin(char *src, char *http_origin_str){
    char * origin_place = strstr(src, "Origin");
    return sscanf(origin_place+strlen("Origin:"), "%256s", http_origin_str);
}
static int getHttpMethodAndOrigin(char *src, char *http_method_str, char *http_origin_str){
        /* Parse the HTTP request */
    int status = EXIT_SUCCESS;
    int n = getHttpMethod(src, http_method_str);
    n +=  getHttpOrigin(src, http_origin_str);
    if (n != 2) {
        status = EXIT_FAILURE;
    }
    return status;
}

static void _tcp_recv(sock_tcp_t *sock, sock_async_flags_t flags, void *arg)
{
    sock_tcp_ep_t client;
    uint16_t port;
    printf("\n\n************** the flag is 0x%04x **************\n\n",flags);
    expect(strcmp(arg, "test") == 0);
    if (sock_tcp_get_remote(sock, &client) < 0) {
        /* socket was disconnected between event firing and this handler */
        return;
    }
    sock_tcp_ep_fmt(&client, _addr_str, &port);
    if (flags & SOCK_ASYNC_MSG_RECV) {
        static char http_message[HTTP_MESSAGE_BUFF_SIZE];
        char method[8];
        char origin[256];
        int res;
        emptyCstring(method,8);
        emptyCstring(origin,256);
        emptyCstring(http_message,HTTP_MESSAGE_BUFF_SIZE);
        emptyCstring(sock_inbuf,SOCK_INBUF_SIZE);
        /* we don't use timeouts so all errors should be related to a lost
         * connection */
        puts(http_message);
        while (((res = sock_tcp_read(sock, sock_inbuf, sizeof(sock_inbuf),
                                    50)) >= 0)) {
            printf("Received TCP data from client [%s]:%u\n", _addr_str, port);
            if (res > 0) {
                printf("\nNumber of bytes arrived: %d\n\n",res);
                strncat(http_message,sock_inbuf,SOCK_INBUF_SIZE);
                emptyCstring(sock_inbuf,SOCK_INBUF_SIZE);
                 if(res<SOCK_INBUF_SIZE){
                    break;
                }
            }
            else {
                puts("(nul)");
            }
        }
        printf("\nthe flag is 0x%04x\n\n",flags);
        printf("\nthe number of res is %d\n\n",res);
        getHttpMethodAndOrigin(http_message,method,origin);
        puts(http_message);
        puts(method);
        if(strncmp(method,"OPTIONS",strlen("OPTIONS"))==0){
            puts("enterd options");
            char *message="HTTP/1.0 200 OK\r\nAccess-Control-Allow-Headers: authorization, content-type, timeout\r\nAccess-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT\r\nAccess-Control-Allow-Origin: http://localhost:8081\r\nAllow: OPTIONS, POST\r\nContent-Length: 0\r\nContent-Type: text/html; charset=utf-8\r\nVary: Origin\r\n\r\n";
            sock_tcp_write(sock,message,strlen(message));
        }else if(strncmp(method,"POST",strlen("POST"))==0){
            puts("enterd POST");
            char *message2="HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin: http://localhost:8081\r\nContent-Length: 58\r\nContent-Type: application/json\r\nVary: Origin\r\n\r\n{\"id\":\"1\",\"jsonrpc\":\"2.0\",\"result\": \"{\\\"status\\\":\\\"OK\\\"}\"}";
            sock_tcp_write(sock,message2,strlen(message2));
            puts("message sent");
        }       
    }
    if (flags & SOCK_ASYNC_CONN_FIN) {
        printf("TCP connection to [%s]:%u reset\n", _addr_str, port);
        sock_tcp_disconnect(sock);
    }
}