MBED crash on multiple connections

Hello all,
I have a project, which is running Web server ,UDP client and few GPOs on threads.
The webserver has automatic data refresh on every 5 seconds. When its running on 1 tab it works fine. But when I open multiple tabs (3-4), it crashes. here is part of my code.

Thanks
Best regards
Dan

int main()
{    printf("Basic HTTP server example\n");// for testing only
    iap.init();

    //test_iap();
    serial_load();
    read_iap();
    set_IP_address();
   ethlink.mode(PullNone); 
   ethspd.mode(PullNone); 
   
    // Crete Threads
    Thread UDPtx_rx; // Crete UDP tread
    Thread TCPweb;
    Thread ethled;
  
   //UDP send receive
    UDPtx_rx.start(UDP_rx);
    TCPweb.start(webpage_load);
    ethled.start(eth_led);

         while (true) {
      }
}
/*********************TCPServer srv/TCP socket******** */
TCPSocket srv;
TCPSocket *client_sock;
SocketAddress client_addr;

 
void webpage_load(){

    char  *web_recv_buf=new char[1024];//[1024];
    printf("TCP WEB server\n");// for testing only
        
    /* Open the server on ethernet stack */
    srv.open(&eth);
    /* Bind the HTTP port (TCP 80) to the server */
    srv.bind(eth.get_ip_address(), 80);
    /* Can handle x simultaneous connections */
    srv.listen(10);
      
    while(true)
    {
        client_sock = srv.accept();  //return pointer of a client socket
        client_sock->getpeername(&client_addr);  //this will fill address of client to the SocketAddress object
               
            nsapi_size_or_error_t size = client_sock->recv(web_recv_buf, 1024);
          // printf("web recv 1==%d\n",size);// for testing only
           if (size==536) {
            nsapi_size_or_error_t size = client_sock->recv(web_recv_buf + 536, 1024);
          //printf("web recv 2==%d\n",size);// for testing only
                }

         if(size>0){  
         std::string web_recv_str=web_recv_buf;

          //**********check recved******** */
         string web_chk_str=web_recv_str.substr(0,14);
         char buf1[16];// for testing only
         if (web_chk_str=="GET / HTTP/1.1")
         {
            http_response();
            page_load();
          
             led1=1;
             led2=0;
         }
        else if (web_chk_str=="GET /tlystatus") {
              http_response();
              char *tly_send=new char[128];
              sprintf(tly_send,"{\"tly_sts\":[%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"]}",tly_status[0],
              tly_status[1],tly_status[2],tly_status[3],tly_status[4],tly_status[5],tly_status[6],tly_status[7],tly_status[8],tly_status[9],tly_status[10],tly_status[11],tly_status[12],tly_status[13],tly_status[14],
              tly_status[15],UMD_WEB[0],UMD_WEB[1],UMD_WEB[2],UMD_WEB[3],UMD_WEB[4],UMD_WEB[5], UMD_WEB[6],UMD_WEB[7],UMD_WEB[8],UMD_WEB[9],UMD_WEB[10],UMD_WEB[11],UMD_WEB[12],UMD_WEB[13],UMD_WEB[14],UMD_WEB[15]);
              client_sock->send(tly_send,strlen(tly_send));
          delete [] tly_send;
          }

         }// end sze IF
         //************************close socket clear buffer******************************
         client_sock->close();
        /*********Clear Buffers**********/
      
         for(int i=0;i<1024;i++){
                web_recv_buf[i]='\0';
             } 
                     
    } //end while    
 } // end main

JS code on web page

window.setInterval(function(){
nocache = "&nocache=" + Math.random() * 10;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseText != null) {
var obj = JSON.parse(this.responseText)
//document.getElementById("testdata2").innerHTML = this.responseText;
var chkbox=document.getElementsByName("chkbox");
var chkbx=[];var i=0;var j=0;
for(;i<64;i++){
chkbx[i]=obj.tly_sts[j]&1;
chkbx[i+1]=obj.tly_sts[j]&2;
chkbx[i+2]=obj.tly_sts[j]&4;
chkbx[i+3]=obj.tly_sts[j]&8;
i=i+3;j=j+1;}
for (var j=0; j<64; j++){
if(0<(chkbx[j])){chkbox[j].style.outlineColor="red"}
else{chkbox[j].style.outlineColor="grey"}
if(0<(chkbx[j+1])){chkbox[j+1].style.outlineColor="lime"}
else{chkbox[j+1].style.outlineColor="grey"}
if(0<(chkbx[j+2])){chkbox[j+2].style.outlineColor="orange"}
else{chkbox[j+2].style.outlineColor="grey"}
if(0<(chkbx[j+3])){chkbox[j+3].style.outlineColor="blue"}
else{chkbox[j+3].style.outlineColor="grey"}
j=j+3;}
document.getElementById("U1").value=obj.tly_sts[16];
document.getElementById("U2").value=obj.tly_sts[17];
document.getElementById("U3").value=obj.tly_sts[18];
document.getElementById("U4").value=obj.tly_sts[19];
document.getElementById("U5").value=obj.tly_sts[20];
document.getElementById("U6").value=obj.tly_sts[21];
document.getElementById("U7").value=obj.tly_sts[22];
document.getElementById("U8").value=obj.tly_sts[23];
document.getElementById("U9").value=obj.tly_sts[24];
document.getElementById("U10").value=obj.tly_sts[25];
document.getElementById("U11").value=obj.tly_sts[26];
document.getElementById("U12").value=obj.tly_sts[27];
document.getElementById("U13").value=obj.tly_sts[28];
document.getElementById("U14").value=obj.tly_sts[29];
document.getElementById("U15").value=obj.tly_sts[30];
document.getElementById("U16").value=obj.tly_sts[31];
}}}}
request.open("GET", "tlystatus=?"+nocache, true);
request.send(null);
}, 5000);

I am not familiar with web stuff. But maybe you are getting stack overflow? Have you tried to increase the stack size for your thread?

Thread t(osPriorityNormal, 8 * 1024 /* 8K stack */);

https://os.mbed.com/docs/mbed-os/v5.15/mbed-os-api-doxy/classrtos_1_1_thread.html#acd57cc8e3c47a4c0e400f80005426ade

Hi @lonesometraveler,

I added below line when I creating the threads but still the same

Thread TCPweb(osPriorityNormal, 8 * 1024);

In my understanding once server accept the connection it can’t accept another connection until close the socket. what if client close the connection before server close the socket??(such as closing the web page before complete the transfer or loss packets during the transfer)

Thanks
Best Regards
Dan

When the client closes the connection, client_sock->recv() returns 0. You can call client_sock->close().

I now understand you are serving one by one. (I was assuming that this question was about simultaneous multiple connections.) Do you get any error messages? Can you debug and narrow down the possible location of the problem?

I am not sure if this is related to the issue. But this code below looks scary to me. If size == 536, you read more data into the buffer. If the second recv() reads data bigger than 488 (1024 - 536) bytes, the buffer overflow happens. Maybe you know what data you are dealing with and this is not a problem. But I just wanted to point out.

nsapi_size_or_error_t size = client_sock->recv(web_recv_buf, 1024);
if (size == 536) {
    nsapi_size_or_error_t size = client_sock->recv(web_recv_buf + 536, 1024);
}

Hi,
Yes Im serving 1 message at a time. Basically on the web page sends a request to server in every 5 seconds to update a status web page. If I open multiple tabs I think they sends requests asynchronously. Thats where it starts crashing.
I done a test using different terminal softwares. When they works individual no issues.

Here when I stay connected on HERCULES and send data on PACKET SENDER ,mBED returns nothing.Thats correct as well according to my code. When I press disconnect on HERCULES ,then mbed crashes. As you can see I’m just sending 14 characters.

The(size == 536) I had to use, coz If mbed receives more than 536 bytes the size says 536.I think my complete packet is about 700 bytes

Thanks
Best Regads
Dan

Dan, I did something similar to what you are doing here, a few tips may help save you hours of time wasting.

What target and interface are you using?
Nucleo-F767ZI with Ethernet or ESP8266 interface is a good platform for this.

Also try a none-thread approach first with a receive buffer of 1024.
This is enough for most web browser requests.
Initial web requests are around 680 bytes.
If you are using standard web browsers (Chrome or similar) you will need to handle and return a Favicon image request after the first page is sent, something like this:

if (web_chk_str=="GET /favicon.ico")

You don’t have to do this but you will find several requests coming in if you don’t and can screw things up a bit with that increased data traffic.

Worked fine for me after I did that.

Looks like you are only serving small chunks of data.
You shouldn’t have a problem using multiple simultaneous connections where the connected web pages are requesting updates every few seconds. I use Google gauges with 1 second requests.
But your connections are limited mainly by the interface (ESP8266 is maximum 5) and target resources.

If you are hosting your own web site using JS or PHP then even better, some web hosting sites will give you database storage, or you can use something like Firebase as a ‘middle man’.
I think Pellion does this to but found Firebase an instant solution.
Send data as and when you want from your Mbed to the database, then your web site would be able to handle hundreds of connections.
You don’t need a DNS server or fixed IP either.

Mbed’s TLS works fine on Firebase.
Here’s an example:
https://os.mbed.com/users/star297/code/Firebase-Example/

This a web example where the Mbed sends data every 30 seconds using a TLS socket reuse https connection to Firebase and a hosted website elsewhere that picks up the data, looks like this:
https://milldashboard.netlify.app/

Hi Paul,
Thanks for your information.
I’m working with MBED LPC1768. In my application ,the web server I’m using for some configurations and monitoring of the unit. The the device just connecting to a LAN only.

As you said I just tried following TCP server code without using threads. Still the same issue. Its crashing on if I connect more than 3 connections simultaneously. Even without sending any data to MBED.It works fine with single connection. The srv.listen(5); doesnt make any different .
Here is a video how im tesing the setup.


Thanks
Best Regards
Dan
#include "mbed.h"
#include "EthernetInterface.h"
//#include "TCPServer.h" // not needed anymore
//#include "TCPSocket.h" // not needed anymore
char mbedIP[15];
char mbedMASK [15];
char mbedGATEWAY [15];
int main()
{
    printf("TCP server example\n");
    
    EthernetInterface eth;
    printf("Ethernet socket example\n");
    sprintf(mbedIP,"192.168.10.50");  
    sprintf(mbedMASK,"255.255.255.0");  
    sprintf(mbedGATEWAY,"192.168.1.0");     
    nsapi_error_t set_network=eth.set_network(mbedIP,mbedMASK,mbedGATEWAY);
    eth.connect();
    
    printf("The Server IP address is '%s'\n", eth.get_ip_address());
    
    //TCPServer srv;  //TCPServer was migrate to TCPSocket
    TCPSocket srv;
    TCPSocket *client_sock;  // srv.accept() will return pointer to socket
    SocketAddress client_addr;
    char *txbuffer = new char[256];
    char *rxbuffer = new char[256];
    for(int i=0;i<256;i++){
    txbuffer[i]=NULL;
    rxbuffer[i]=NULL;
    }
    /* Open the server on ethernet stack */
    srv.open(&eth);
    
    /* Bind the HTTP port (TCP 80) to the server */
    srv.bind(eth.get_ip_address(), 80);
    
    /* Can handle x simultaneous connections */
    srv.listen(5);
  
 while(true){
    client_sock = srv.accept();  //return pointer of a client socket
    
    client_sock->getpeername(&client_addr);  //this will fill address of client to the SocketAddress object
    printf("Accepted %s:%d\n", client_addr.get_ip_address(), client_addr.get_port());
    strcpy(txbuffer, "Hello \n\r");
    client_sock->send(txbuffer, strlen(txbuffer));
    client_sock->recv(rxbuffer, 256);
    printf("Received Msg: %s\n", rxbuffer);  //this was missing in original example. 
    client_sock->close();
 }
    //delete[] txbuffer;
    // delete[] rxbuffer;
 }

Hi Dan,
Looking at the video the IP’s look the same 192.168.10.201 ? with your server IP at 192.168.10.50
I maybe wrong but I think you may have to close on that IP before you can connect again on the same IP or perhaps try to set different port numbers, not sure if that will help.
In the real world you would have one connection on one IP and the link ID should relate to the IP address and perhaps resolve down to a port number.
But I’m not an expert here.
Can you try this using 3 different IP’s or if you haven’t already, specify different ports ?
I know I connect in my local network simultaneously but all devices have different IP’s on port 80 simply for ease of connection on a web browser, if you use 80 you don’t have to set the port number in web browser, so hence I use different IP’s on port 80.
Paul

Hi Paul,
Yes I’m using same IP (201) but different source port numbers.You can see that on video .TCP server should work on different source port numbers. I tried 3 different IPs still the same. I think the issue is handling the session layer on ethernet library.
I started MBED and programming just a month ago, still i’m a newbie :slight_smile:

Cheers
Dan

Dan, I think you have to handle all incoming connections, respond and close.
But first try client_sock->recv before client_sock->send and increase your rxbuffer to 1024

This is what you will receive on your mbed if a Chrome web page try’s to connect.

Accepted 192.168.1.45:50941

Received Msg:
GET / HTTP/1.1
Host: 192.168.1.180
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

Accepted 192.168.1.45:50936

Received Msg:
GET /favicon.ico HTTP/1.1
Host: 192.168.1.180
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Accept: image/webp,image/apng,image/,/*;q=0.8
Referer: http://192.168.1.180/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

The second message that comes in quick GET /favicon.ico HTTP/1.1 needs to be handled.
Part of my server code has something like this…

client_sock->recv(rxbuffer,1024);  // sure this buffer is big enough
sscanf(rxbufffer,"%s %s",requestType,request);
if(strcmp(request,"/favicon.ico")==0){
               client.send((char*)favicon_ico,sizeof(favicon_ico)); 
//    or send anything, just respond.
//     client.send((char*)"hello",5);       
            }

I’m using the ‘depreciated’ socket library that works, I will update it and double check a bug hasn’t crept in.

Hi ! Maybe a bit late, but here is your answer : why did it crash after 3 connections .

Mbed-OS 6 is using LwIP as network stack. LwIP can only handle 4 Sockets.

You use 1 Socket for the server and 3 for clients… 1+3 = 4 => you’ve used the full capacity of LwIP.

I guess it’s the reason: You cannot create more than 4 Sockets.

Try reusing sockets (like in a circular buffer) and I guess you will be able to manage all the connections you want.

The number of pending connection you give to the listen method does not have any role in it (you can keep as many pending connection as you want, they are not connected, it’s like a waiting queue…)

Hello,

from my point of view it is depend on available resources (memory and performance) and settings.

BR, Jan