Skip to content

Commit efaa628

Browse files
committed
Fix race condition in WiFiGenericClass::hostByName
dns_gethostbyname, as used in hostByName, is required to run in lwIP's TCP/IP context. This can be verified by enabling LWIP_CHECK_THREAD_SAFETY in the sdkconfig. Calling dns_gethostbyname from the Arduino task can trigger race conditions in lwIP or lower layers. One possibility is a corruption of IDF's Ethernet buffers, causing an unstoppable flood of "insufficient TX buffer size" errors, effectively severing all Ethernet connectivity. This patch makes sure to call dns_gethostbyname from lwIP's TCP/IP context.
1 parent 02e31b4 commit efaa628

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

libraries/WiFi/src/WiFiGeneric.cpp

+23-4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extern "C" {
3636
#include <esp_err.h>
3737
#include <esp_wifi.h>
3838
#include <esp_event.h>
39+
#include <esp_netif.h>
3940
#include "lwip/ip_addr.h"
4041
#include "lwip/opt.h"
4142
#include "lwip/err.h"
@@ -1449,6 +1450,22 @@ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, v
14491450
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
14501451
}
14511452

1453+
typedef struct gethostbynameParameters {
1454+
const char *hostname;
1455+
ip_addr_t addr;
1456+
void *callback_arg;
1457+
} gethostbynameParameters_t;
1458+
1459+
/**
1460+
* Callback to execute dns_gethostbyname in lwIP's TCP/IP context
1461+
* @param param Parameters for dns_gethostbyname call
1462+
*/
1463+
static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
1464+
{
1465+
gethostbynameParameters_t *parameters = static_cast<gethostbynameParameters_t *>(param);
1466+
return dns_gethostbyname(parameters->hostname, &parameters->addr, &wifi_dns_found_callback, parameters->callback_arg);
1467+
}
1468+
14521469
/**
14531470
* Resolve the given hostname to an IP address. If passed hostname is an IP address, it will be parsed into IPAddress structure.
14541471
* @param aHostname Name to be resolved or string containing IP address
@@ -1460,13 +1477,15 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
14601477
{
14611478
if (!aResult.fromString(aHostname))
14621479
{
1463-
ip_addr_t addr;
1480+
gethostbynameParameters_t params;
1481+
params.hostname = aHostname;
1482+
params.callback_arg = &aResult;
14641483
aResult = static_cast<uint32_t>(0);
14651484
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
14661485
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
1467-
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
1468-
if(err == ERR_OK && addr.u_addr.ip4.addr) {
1469-
aResult = addr.u_addr.ip4.addr;
1486+
err_t err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, &params);
1487+
if(err == ERR_OK && params.addr.u_addr.ip4.addr) {
1488+
aResult = params.addr.u_addr.ip4.addr;
14701489
} else if(err == ERR_INPROGRESS) {
14711490
waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
14721491
clearStatusBits(WIFI_DNS_DONE_BIT);

0 commit comments

Comments
 (0)