Skip to content

Commit f06710e

Browse files
authored
hostByName timeout fixes (#8787)
* single impl
1 parent 3e357f3 commit f06710e

File tree

5 files changed

+125
-103
lines changed

5 files changed

+125
-103
lines changed

cores/esp8266/IPAddress.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ IPAddress::IPAddress(const IPAddress& from)
2727
ip_addr_copy(_ip, from._ip);
2828
}
2929

30+
IPAddress::IPAddress(IPAddress&& from)
31+
{
32+
ip_addr_copy(_ip, from._ip);
33+
}
34+
3035
IPAddress::IPAddress() {
3136
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
3237
}

cores/esp8266/IPAddress.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ class IPAddress: public Printable {
6666
public:
6767
// Constructors
6868
IPAddress();
69-
IPAddress(const IPAddress& from);
69+
IPAddress(const IPAddress&);
70+
IPAddress(IPAddress&&);
71+
7072
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
7173
IPAddress(uint32_t address) { ctor32(address); }
7274
IPAddress(unsigned long address) { ctor32(address); }

libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp

+91-92
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
2323
*/
2424

25+
#include <cstring>
2526
#include <list>
26-
#include <string.h>
27+
#include <memory>
28+
#include <type_traits>
29+
2730
#include <coredecls.h>
2831
#include <PolledTimeout.h>
2932
#include "ESP8266WiFi.h"
@@ -595,112 +598,105 @@ bool ESP8266WiFiGenericClass::isSleepLevelMax () {
595598
// ------------------------------------------------ Generic Network function ---------------------------------------------
596599
// -----------------------------------------------------------------------------------------------------------------------
597600

598-
void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg);
601+
namespace {
599602

600-
static bool _dns_lookup_pending = false;
603+
struct _dns_found_result {
604+
IPAddress addr;
605+
bool done;
606+
};
601607

602-
/**
603-
* Resolve the given hostname to an IP address.
604-
* @param aHostname Name to be resolved
605-
* @param aResult IPAddress structure to store the returned IP address
606-
* @return 1 if aIPAddrString was successfully converted to an IP address,
607-
* else 0
608-
*/
609-
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
610-
{
611-
return hostByName(aHostname, aResult, 10000);
612608
}
613609

610+
static void _dns_found_callback(const char *, const ip_addr_t *, void *);
614611

615-
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms)
616-
{
617-
ip_addr_t addr;
618-
aResult = static_cast<uint32_t>(INADDR_NONE);
619-
620-
if(aResult.fromString(aHostname)) {
621-
// Host name is a IP address use it!
622-
DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname);
612+
static int hostByNameImpl(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType) {
613+
if (aResult.fromString(aHostname)) {
614+
DEBUG_WIFI_GENERIC("[hostByName] Host: %s is IP!\n", aHostname);
623615
return 1;
624616
}
625617

618+
static_assert(std::is_same_v<uint8_t, std::underlying_type_t<decltype(resolveType)>>, "");
626619
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
627-
#if LWIP_IPV4 && LWIP_IPV6
628-
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult,LWIP_DNS_ADDRTYPE_DEFAULT);
629-
#else
630-
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
631-
#endif
632-
if(err == ERR_OK) {
633-
aResult = IPAddress(&addr);
634-
} else if(err == ERR_INPROGRESS) {
635-
_dns_lookup_pending = true;
636-
// Will resume on timeout or when wifi_dns_found_callback fires.
637-
// The final argument, intvl_ms, to esp_delay influences how frequently
638-
// the scheduled recurrent functions (Schedule.h) are probed; here, to allow
639-
// the ethernet driver perform work.
640-
esp_delay(timeout_ms, []() { return _dns_lookup_pending; }, 1);
641-
_dns_lookup_pending = false;
642-
if(aResult.isSet()) {
643-
err = ERR_OK;
620+
621+
ip_addr_t addr;
622+
auto pending = std::make_unique<_dns_found_result>(
623+
_dns_found_result{
624+
.addr = IPADDR_NONE,
625+
.done = false,
626+
});
627+
628+
err_t err = dns_gethostbyname_addrtype(aHostname,
629+
&addr, &_dns_found_callback, pending.get(),
630+
static_cast<uint8_t>(resolveType));
631+
632+
switch (err) {
633+
// Address already known
634+
case ERR_OK:
635+
aResult = addr;
636+
break;
637+
638+
// We are no longer able to issue requests
639+
case ERR_MEM:
640+
break;
641+
642+
// We need to wait for c/b to fire *or* we exit on our own timeout
643+
// (which also requires us to notify the c/b that it is supposed to delete the pending obj)
644+
case ERR_INPROGRESS:
645+
// Re-check every 10ms, we expect this to happen fast
646+
esp_delay(timeout_ms,
647+
[&]() {
648+
return !pending->done;
649+
}, 10);
650+
651+
if (pending->done) {
652+
if ((pending->addr).isSet()) {
653+
aResult = pending->addr;
654+
err = ERR_OK;
655+
}
656+
} else {
657+
pending->done = true;
658+
pending.release();
659+
err = ERR_TIMEOUT;
644660
}
661+
662+
break;
645663
}
646664

647-
if(err == ERR_OK) {
665+
if (err == ERR_OK) {
648666
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
649667
return 1;
650668
}
651-
652-
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %s (%d)!\n", aHostname, lwip_strerr(err), (int)err);
669+
670+
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %s (%d)!\n",
671+
aHostname,
672+
(err == ERR_TIMEOUT) ? "Timeout" :
673+
(err == ERR_INPROGRESS) ? "No response" :
674+
"Unknown", static_cast<int>(err));
675+
653676
return 0;
654677
}
655678

656-
#if LWIP_IPV4 && LWIP_IPV6
657-
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType)
679+
/**
680+
* Resolve the given hostname to an IP address.
681+
* @param aHostname Name to be resolved
682+
* @param aResult IPAddress structure to store the returned IP address
683+
* @return 1 if aIPAddrString was successfully converted to an IP address,
684+
* else 0
685+
*/
686+
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
658687
{
659-
ip_addr_t addr;
660-
err_t err;
661-
aResult = static_cast<uint32_t>(INADDR_NONE);
662-
663-
if(aResult.fromString(aHostname)) {
664-
// Host name is a IP address use it!
665-
DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname);
666-
return 1;
667-
}
668-
669-
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
670-
switch(resolveType)
671-
{
672-
// Use selected addrtype
673-
case DNSResolveType::DNS_AddrType_IPv4:
674-
case DNSResolveType::DNS_AddrType_IPv6:
675-
case DNSResolveType::DNS_AddrType_IPv4_IPv6:
676-
case DNSResolveType::DNS_AddrType_IPv6_IPv4:
677-
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, (uint8_t) resolveType);
678-
break;
679-
default:
680-
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, LWIP_DNS_ADDRTYPE_DEFAULT); // If illegal type, use default.
681-
break;
682-
}
683-
684-
if(err == ERR_OK) {
685-
aResult = IPAddress(&addr);
686-
} else if(err == ERR_INPROGRESS) {
687-
_dns_lookup_pending = true;
688-
// will resume on timeout or when wifi_dns_found_callback fires
689-
esp_delay(timeout_ms, []() { return _dns_lookup_pending; });
690-
_dns_lookup_pending = false;
691-
// will return here when dns_found_callback fires
692-
if(aResult.isSet()) {
693-
err = ERR_OK;
694-
}
695-
}
688+
return hostByNameImpl(aHostname, aResult, DNSDefaultTimeoutMs, DNSResolveTypeDefault);
689+
}
696690

697-
if(err == ERR_OK) {
698-
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
699-
return 1;
700-
}
691+
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms)
692+
{
693+
return hostByNameImpl(aHostname, aResult, timeout_ms, DNSResolveTypeDefault);
694+
}
701695

702-
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
703-
return 0;
696+
#if LWIP_IPV4 && LWIP_IPV6
697+
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType)
698+
{
699+
return hostByNameImpl(aHostname, aResult, timeout_ms, resolveType);
704700
}
705701
#endif
706702

@@ -710,16 +706,19 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
710706
* @param ipaddr
711707
* @param callback_arg
712708
*/
713-
void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
709+
static void _dns_found_callback(const char*, const ip_addr_t* ipaddr, void* arg)
714710
{
715-
(void) name;
716-
if (!_dns_lookup_pending) {
711+
auto result = reinterpret_cast<_dns_found_result*>(arg);
712+
if (result->done) {
713+
delete result;
717714
return;
718715
}
719-
if(ipaddr) {
720-
(*reinterpret_cast<IPAddress*>(callback_arg)) = IPAddress(ipaddr);
716+
717+
if (ipaddr) {
718+
result->addr = IPAddress(ipaddr);
721719
}
722-
_dns_lookup_pending = false; // resume hostByName
720+
721+
result->done = true;
723722
esp_schedule();
724723
}
725724

libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h

+11-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#define ESP8266WIFIGENERIC_H_
2525

2626
#include "ESP8266WiFiType.h"
27+
28+
#include <IPAddress.h>
29+
#include <lwip/dns.h>
30+
2731
#include <functional>
2832
#include <memory>
2933

@@ -44,12 +48,15 @@ typedef void (*WiFiEventCb)(WiFiEvent_t);
4448

4549
enum class DNSResolveType: uint8_t
4650
{
47-
DNS_AddrType_IPv4 = 0, // LWIP_DNS_ADDRTYPE_IPV4 = 0
48-
DNS_AddrType_IPv6, // LWIP_DNS_ADDRTYPE_IPV6 = 1
49-
DNS_AddrType_IPv4_IPv6, // LWIP_DNS_ADDRTYPE_IPV4_IPV6 = 2
50-
DNS_AddrType_IPv6_IPv4 // LWIP_DNS_ADDRTYPE_IPV6_IPV4 = 3
51+
DNS_AddrType_IPv4 = LWIP_DNS_ADDRTYPE_IPV4,
52+
DNS_AddrType_IPv6 = LWIP_DNS_ADDRTYPE_IPV6,
53+
DNS_AddrType_IPv4_IPv6 = LWIP_DNS_ADDRTYPE_IPV4_IPV6,
54+
DNS_AddrType_IPv6_IPv4 = LWIP_DNS_ADDRTYPE_IPV6_IPV4,
5155
};
5256

57+
inline constexpr auto DNSDefaultTimeoutMs = 10000;
58+
inline constexpr auto DNSResolveTypeDefault = static_cast<DNSResolveType>(LWIP_DNS_ADDRTYPE_DEFAULT);
59+
5360
struct WiFiState;
5461

5562
class ESP8266WiFiGenericClass {

tests/host/common/ClientContextTools.cpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,27 @@
3737

3838
#include <netdb.h> // gethostbyname
3939

40-
err_t dns_gethostbyname(const char* hostname, ip_addr_t* addr, dns_found_callback found,
41-
void* callback_arg)
40+
err_t dns_gethostbyname_addrtype(const char* hostname, ip_addr_t* addr, dns_found_callback, void*,
41+
u8 type)
4242
{
43-
(void)callback_arg;
44-
(void)found;
45-
struct hostent* hbn = gethostbyname(hostname);
43+
auto* hbn = gethostbyname(hostname);
4644
if (!hbn)
4745
return ERR_TIMEOUT;
48-
addr->addr = *(uint32_t*)hbn->h_addr_list[0];
46+
47+
uint32_t tmp;
48+
std::memcpy(&tmp, hbn->h_addr_list[0], sizeof(tmp));
49+
addr->addr = tmp;
50+
4951
return ERR_OK;
5052
}
5153

54+
err_t dns_gethostbyname_addrtype(const char* hostname, ip_addr_t* addr, dns_found_callback found,
55+
void* callback_arg)
56+
{
57+
return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg,
58+
LWIP_DNS_ADDRTYPE_DEFAULT);
59+
}
60+
5261
static struct tcp_pcb mock_tcp_pcb;
5362
tcp_pcb* tcp_new(void)
5463
{

0 commit comments

Comments
 (0)