Skip to content

Commit 51cb927

Browse files
authored
Fix race condition in WiFiGenericClass::hostByName (#8672)
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 8520725 commit 51cb927

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

Diff for: libraries/WiFi/src/WiFiGeneric.cpp

+23-4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ extern "C" {
3737
#include <esp_wifi.h>
3838
#include <esp_event.h>
3939
#include <esp_mac.h>
40+
#include <esp_netif.h>
4041
#include "lwip/ip_addr.h"
4142
#include "lwip/opt.h"
4243
#include "lwip/err.h"
@@ -1559,6 +1560,22 @@ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, v
15591560
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
15601561
}
15611562

1563+
typedef struct gethostbynameParameters {
1564+
const char *hostname;
1565+
ip_addr_t addr;
1566+
void *callback_arg;
1567+
} gethostbynameParameters_t;
1568+
1569+
/**
1570+
* Callback to execute dns_gethostbyname in lwIP's TCP/IP context
1571+
* @param param Parameters for dns_gethostbyname call
1572+
*/
1573+
static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
1574+
{
1575+
gethostbynameParameters_t *parameters = static_cast<gethostbynameParameters_t *>(param);
1576+
return dns_gethostbyname(parameters->hostname, &parameters->addr, &wifi_dns_found_callback, parameters->callback_arg);
1577+
}
1578+
15621579
/**
15631580
* Resolve the given hostname to an IP address. If passed hostname is an IP address, it will be parsed into IPAddress structure.
15641581
* @param aHostname Name to be resolved or string containing IP address
@@ -1570,13 +1587,15 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
15701587
{
15711588
if (!aResult.fromString(aHostname))
15721589
{
1573-
ip_addr_t addr;
1590+
gethostbynameParameters_t params;
1591+
params.hostname = aHostname;
1592+
params.callback_arg = &aResult;
15741593
aResult = static_cast<uint32_t>(0);
15751594
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
15761595
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
1577-
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
1578-
if(err == ERR_OK && addr.u_addr.ip4.addr) {
1579-
aResult = addr.u_addr.ip4.addr;
1596+
err_t err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, &params);
1597+
if(err == ERR_OK && params.addr.u_addr.ip4.addr) {
1598+
aResult = params.addr.u_addr.ip4.addr;
15801599
} else if(err == ERR_INPROGRESS) {
15811600
waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s]
15821601
clearStatusBits(WIFI_DNS_DONE_BIT);

0 commit comments

Comments
 (0)