TCPSocket::accept() sometimes returns NSAPI_ERROR_NO_SOCKET

Why does an outward-facing “server” socket close?
It is bound to a port and should continue listening indefinitely.

What are the reasons for NSAPI_ERROR_NO_SOCKET?
Is there an underlying problem?
Should I just reconnect?

   server_socket.open(iface);
    server_socket.bind(port);
    server_socket.listen(5);
   server_ socket.set_blocking(true);   

nsapi_error_t accept_res;
while (is_connected) {
    accept_res = NSAPI_ERROR_BUSY;                                  // Assume failure
    TCPSocket *incoming_socket = server_socket.accept(&accept_res); // Block until incoming connection

   switch(accept_res) {
        case NSAPI_ERROR_NO_SOCKET:
                  // Why did my server_socket close ???
                  break;
        case NSAPI_ERROR_OK:
                  // I was expecting to keep accepting connections
                  break;
   }
}

Maybe try increasing the lwip.tcp-socket-max option in mbed_app.json?

OK great it seems to be behaving a little better.

How can I manage the sockets so that I never reach the max value defined in mbed_app.json ?
Theoretically a malicious user can keep opening connections until my server crashes.

Where can I find the counter in LWIP/Mbed that this parameter relates to ?

Do you know where I can find a good doc of all options available in mbed_app.json ?
Thanks !

{
    "target_overrides": {
        "*": {
            "lwip.tcp-socket-max": 30,
        }
    }
}

OK I think I figured out a hacky way to make it work. You’ll have to be using MBed CLI or studio though (or mbed-cmake), not the online compiler.

First, go to mbed-os/features/lwipstack/LWIPStack.h and do a find and replace for “private:” with “public:”. Now that the data is accessible, we can do it this way:

#include <LWIPStack.h>
size_t getNumFreeSockets()
{
	LWIP & netStack = reinterpret_cast<LWIP &>(OnboardNetworkStack::get_default_instance());

	netStack.adaptation.lock();
	size_t freeCount = 0;

	for (int i = 0; i < MEMP_NUM_NETCONN; i++) {
		if (!netStack.arena[i].in_use) {
			++freeCount;
		}
	}
	netStack.adaptation.unlock();

	return freeCount;
}

These options are documented on this page and its subpages (though I agree these are difficult to find).

Thanks! But it’s not my style to go in and change library files, i’ll try and find another way.

I had to set three params in mbed_app.json :

"lwip.socket-max": 60,
"lwip.tcp-server-max": 40,
"lwip.tcp-socket-max": 60,

Looking into it more, you could actually use something like this library to implement this without changing the header.

Mbed compile—config
https://os.mbed.com/docs/mbed-os/v6.2/program-setup/advanced-configuration.html

Do you close your incoming_socket when it is no longer needed? The c++ object will be automatically destroyed when closed.

And reusing a socket is blocked for a few minutes, that is recommended behavior. You can set a socket option to reuse a socket immediately.

The large number reserves RAM, I think it is something about 500 Bytes per socket.

I have played with some async handling, maybe it helps. https://github.com/JojoS62/testTCPServer

I found it. You can use SocketStats to get the number of open/closed sockets:

mbed_stats_socket_t stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
mbed_stats_socket_get_each(stats, MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT);