Hello, I came across this post and tried your code. It works fine as is, but if I try to use it in a thread it keeps getting stuck due to a NSAPI_ERROR_WOULD_BLOCK condition in the recv() function. Strangely enough this only happens after the webpage is reloaded after the first time. So in other words, it works for the first time but gives issues after that. As far as I can find online the socket should be blocking by default and manually setting it to blocking also doesnât fix it. Do you have any clue why this would happen?
/** Accepts a connection on a socket.
*
* The server socket must be bound and set to listen for connections.
* On a new connection, returns connected network socket which user is expected to call close()
* and that deallocates the resources. Referencing a returned pointer after a close()
* call is not allowed and leads to undefined behavior.
*
* By default, accept blocks until incoming connection occurs. If socket is set to
* non-blocking or times out, error is set to NSAPI_ERROR_WOULD_BLOCK.
*
* @param error pointer to storage of the error value or NULL:
* NSAPI_ERROR_OK on success
* NSAPI_ERROR_WOULD_BLOCK if socket is set to non-blocking and would block
* NSAPI_ERROR_NO_SOCKET if the socket was not open
* @return pointer to a socket
*/
TCPSocket *accept(nsapi_error_t *error = NULL) override;
By using it in a thread I meant that I put all the code from the main function inside a new function called âweb_serverâ. The main function is replaced by an almost empty one which is used to start a new thread that executes this new âweb_serverâ function. Apart from starting the âweb_serverâ thread, the main only has the infinite while loop left. I also tried adding a blinky thread and that kept running fine.
The accept function seems to be working fine. Itâs the recv function that is causing the issues and hangs at the NSAPI_ERROR_WOULD_BLOCK condition.
I moved the web server to a webServerTask running in a webServerThread. At the same time, an LED is toggled in the main task (which is running in the main thread).
No errors were reported when trying to connect to the web server multiple times:
#include "mbed.h"
#include "EthernetInterface.h"
#include "TCPSocket.h"
#define IP "192.168.1.181"
#define GATEWAY "192.168.1.1"
#define NETMASK "255.255.255.0"
#define PORT 80
DigitalOut led1(LED1);
EthernetInterface* net;
TCPSocket server;
TCPSocket* clientSocket;
SocketAddress clientAddress;
char rxBuf[512] = { 0 };
char txBuf[512] = { 0 };
Thread webServerThread;
void webServerTask();
/**
* @brief
* @note
* @param
* @retval
*/
void webServerTask()
{
net = new EthernetInterface;
if (!net) {
printf("Error! No network inteface found.\n");
return;
}
//net->set_network (IP, NETMASK, GATEWAY); // include to use static IP address
nsapi_size_or_error_t r = net->connect();
if (r != 0) {
printf("Error! net->connect() returned: %d\n", r);
return;
}
// Show the network address
SocketAddress ip;
SocketAddress netmask;
SocketAddress gateway;
net->get_ip_address(&ip);
net->get_netmask(&netmask);
net->get_gateway(&gateway);
ip.set_port(PORT);
const char* ipAddr = ip.get_ip_address();
const char* netmaskAddr = netmask.get_ip_address();
const char* gatewayAddr = gateway.get_ip_address();
printf("IP address: %s\r\n", ipAddr ? ipAddr : "None");
printf("Netmask: %s\r\n", netmaskAddr ? netmaskAddr : "None");
printf("Gateway: %s\r\n\r\n", gatewayAddr ? gatewayAddr : "None");
/* Open the server on ethernet stack */
server.open(net);
/* Bind the HTTP port (TCP 80) to the server */
server.bind(ip);
/* Can handle 5 simultaneous connections */
server.listen(5);
//listening for http GET request
while (true) {
printf("=========================================\r\n");
nsapi_error_t error = 0;
clientSocket = server.accept(&error);
if (error != 0) {
printf("Connection failed!\r\n");
}
else {
//clientSocket->set_timeout(200);
clientSocket->getpeername(&clientAddress);
printf("Client with IP address %s connected.\r\n\r\n", clientAddress.get_ip_address());
error = clientSocket->recv(rxBuf, sizeof(rxBuf));
switch (error) {
case 0:
printf("Recieved buffer is empty.\r\n");
break;
case -1:
printf("Failed to read data from client.\r\n");
break;
default:
printf("Recieved Data: %d\n\r\n\r%.*s\r\n\n\r", strlen(rxBuf), strlen(rxBuf), rxBuf);
if (rxBuf[0] == 'G' && rxBuf[1] == 'E' && rxBuf[2] == 'T') {
//setup http response header & data
sprintf
(
txBuf,
"HTTP/1.1 200 OK\nContent-Length: %d\r\nContent-Type: text\r\nConnection: Close\r\n\r\n",
strlen(rxBuf)
);
strcat(txBuf, rxBuf);
clientSocket->send(txBuf, strlen(txBuf));
// printf("------------------------------------\r\n");
// printf("Sent:\r\n%s\r\n", txBuf);
printf("echo done.\r\n");
}
break;
}
}
clientSocket->close();
printf("Client socket closed\r\n");
}
}
/**
* @brief
* @note
* @param
* @retval
*/
int main(void)
{
printf("Starting\r\n");
webServerThread.start(callback(webServerTask));
while (true) {
led1 = !led1;
ThisThread::sleep_for(200ms);
}
}
Your code is very similar to the code that I used. I only uncommented the line that gives the server a static IP . Unfortunately it still hangs occasionally (browser keeps showing the spinning loading icon). I tried the version with only the main function again and I noticed that that also has it, so itâs not just this additional thread thatâs causing it like I previously thought. It didnât occur when testing this version previously, so sorry for that⊠So in other words, both versions have it. However, setting the timeout to 200 (uncommenting the line) makes the issue almost a non-issue. Without this line uncommented the user has to refresh the page if it gets stuck or wait like 90 seconds.
Unfortunately I started to notice a worse problem. Whenever the user refreshes too fast (so for example spams the F5 key) it will result in a HardFault which makes the server unavailable until the board is reset. This happens on my STM32F746ZG board at least. Do you also experience this on your board?
No matter how hard I was trying to reproduce the failure on my LPC1768 the server always worked correctly. It seems to be something specific to the STM32F746ZG (or maybe STM targets).
Starting
Error! net->connect() returned: -3004 (oops, I had unplugged the cable)
Error! net->connect() returned: -3010 (with the cable plugged in)
Environment:
I dropped mbed OS to 5.14.2 (which is about the time of your post), but this one doesnât compile.
compile main.cpp
/src/main.cpp:49:25: error: too many arguments to function call, expected 0, have 1
net->get_ip_address(&ip);
~~~~~~~~~~~~~~~~~~~ ^~~
/extras/mbed-os.lib/features/netsocket/EMACInterface.h:104:25: note: 'get_ip_address' declared here
virtual const char *get_ip_address();
^
/src/main.cpp:50:22: error: too many arguments to function call, expected 0, have 1
net->get_netmask(&netmask);
~~~~~~~~~~~~~~~~ ^~~~~~~~
/extras/mbed-os.lib/features/netsocket/EMACInterface.h:118:25: note: 'get_netmask' declared here
virtual const char *get_netmask();
^
/src/main.cpp:51:22: error: too many arguments to function call, expected 0, have 1
net->get_gateway(&gateway);
~~~~~~~~~~~~~~~~ ^~~~~~~~
/extras/mbed-os.lib/features/netsocket/EMACInterface.h:125:25: note: 'get_gateway' declared here
virtual const char *get_gateway();
^
3 errors generated.
Internal error.
Build failed
Build failed
LPC1768 module on the MBED Application Board (and on another board w/Ethernet)
When I build for the LPC1768, drag-n-drop program and reboot, it takes about 1 minute, and then I get:
Error! net->connect() returned: -3010
The example code (in Zoltanâs text) in main continues to blink the LED as expected.
My test used two different Ethernet boards - the MBED Application Board and a board of my own design. I have an old binary for my own board, and it works with its Ethernet, thus verifying the Ethernet interface.
I tried different firmware:
firmware=141212 // this is the latest, and it failed to connect
firmware=16457 // this is quite old - and the blink-rate is very slow, so I donât trust it.
firmware=21164 // an âintermediateâ version, it blinks as expected, but fails to connect.
Success with a FRDM-K66F - and the exact same source code
I swapped my LPC1768 for a FRDM-K66F board.
I retargeted Keil [online] studio to this target.
I built the exact same code.
On boot, this connected successfully to the network after about 12s.
The root cause is a failed Ethernet on an LPC1768 Module!
For a specific mbed on the application board - I tested several of the IO (display, LEDs, and the RGB LED. All function. This is the module where Ethernet fails to connect, always returning -3010.
I have several other LPC1768 modules Ethernet-worked into various devices (that are active) and did not have this problem with them - so taking one out of service to swap modules was my last resort (in large part because of disbelief that I had a failed module).
Toyo, thanks for the binaries, with these I confirmed all three binaries as not working (with my failed module) and working (with an alternate module).