@@ -16,50 +16,88 @@ class AsyncDNS {
1616 // with the IDF V4 bug external error handling is required anyway or dns can just stay stuck
1717 enum class result { Idle, Busy, Success, Error };
1818
19+ private:
20+ struct state_t {
21+ ip_addr_t raw_addr;
22+ std::atomic<result> status { result::Idle };
23+ uint16_t errorcount = 0 ;
24+ };
25+ std::shared_ptr<state_t > _state;
26+
27+ // callback for dns_gethostbyname(), called when lookup is complete or timed out
28+ static void _dns_callback (const char *name, const ip_addr_t *ipaddr, void *arg) {
29+ std::shared_ptr<state_t >* state_ptr = reinterpret_cast <std::shared_ptr<state_t >*>(arg);
30+ state_t & state = **state_ptr;
31+
32+ if (ipaddr) {
33+ state.raw_addr = *ipaddr;
34+ state.status = result::Success;
35+ } else {
36+ state.status = result::Error; // note: if query timed out (~5s), DNS lookup is broken until WiFi connection is reset (IDF V4 bug)
37+ state.errorcount ++;
38+ }
39+
40+ delete state_ptr;
41+ }
42+
43+ public:
44+ AsyncDNS () : _state(std::make_shared<state_t >()) {};
45+ AsyncDNS (const AsyncDNS&) = delete ; // noncopyable
46+ AsyncDNS& operator =(const AsyncDNS&) = delete ; // noncopyable
47+
1948 // non-blocking query function to start DNS lookup
2049 result query (const char * hostname) {
21- if (_status == result::Busy) return result::Busy; // in progress, waiting for callback
50+ if (_state->status == result::Busy) return result::Busy; // in progress, waiting for callback
51+
52+ std::shared_ptr<state_t >* callback_context = new std::shared_ptr<state_t >(_state);
53+ if (!callback_context) {
54+ _state->status = result::Error;
55+ _state->errorcount ++;
56+ return result::Error;
57+ }
2258
23- _status = result::Busy;
24- err_t err = dns_gethostbyname (hostname, &_raw_addr , _dns_callback, this );
59+ _state-> status = result::Busy;
60+ err_t err = dns_gethostbyname (hostname, &_state-> raw_addr , _dns_callback, callback_context );
2561 if (err == ERR_OK) {
26- _status = result::Success; // result already in cache
62+ _state-> status = result::Success; // result already in cache
2763 } else if (err != ERR_INPROGRESS) {
28- _status = result::Error;
29- _errorcount ++;
64+ _state-> status = result::Error;
65+ _state-> errorcount ++;
3066 }
31- return _status ;
67+ return _state-> status ;
3268 }
3369
3470 // get the IP once Success is returned
35- const IPAddress getIP () {
36- if (_status != result::Success) return IPAddress (0 ,0 ,0 ,0 );
71+ IPAddress getIP () const {
72+ if (_state-> status != result::Success) return IPAddress (0 ,0 ,0 ,0 );
3773 #ifdef ARDUINO_ARCH_ESP32
38- return IPAddress (_raw_addr .u_addr .ip4 .addr );
74+ return IPAddress (_state-> raw_addr .u_addr .ip4 .addr );
3975 #else
40- return IPAddress (_raw_addr .addr );
76+ return IPAddress (_state-> raw_addr .addr );
4177 #endif
4278 }
4379
44- void renew () { _status = result::Idle; } // reset status to allow re-query
45- void reset () { _status = result::Idle; _errorcount = 0 ; } // reset status and error count
46- const result status () { return _status; }
47- const uint16_t getErrorCount () { return _errorcount; }
48-
49- private:
50- ip_addr_t _raw_addr;
51- std::atomic<result> _status { result::Idle };
52- uint16_t _errorcount = 0 ;
80+ void renew () { // reset status to allow re-query
81+ if (_state->status == result::Busy) {
82+ // Abandon old state, but keep error count
83+ uint16_t ec = _state->errorcount ;
84+ _state = std::make_shared<state_t >();
85+ _state->errorcount = ec;
86+ } else {
87+ _state->status = result::Idle;
88+ }
89+ }
5390
54- // callback for dns_gethostbyname(), called when lookup is complete or timed out
55- static void _dns_callback (const char *name, const ip_addr_t *ipaddr, void *arg) {
56- AsyncDNS* instance = reinterpret_cast <AsyncDNS*>(arg);
57- if (ipaddr) {
58- instance->_raw_addr = *ipaddr;
59- instance->_status = result::Success;
91+ void reset () { // reset status and error count
92+ if (_state->status == result::Busy) {
93+ // Abandon old state
94+ _state = std::make_shared<state_t >();
6095 } else {
61- instance-> _status = result::Error; // note: if query timed out (~5s), DNS lookup is broken until WiFi connection is reset (IDF V4 bug)
62- instance-> _errorcount ++ ;
96+ _state-> status = result::Idle;
97+ _state-> errorcount = 0 ;
6398 }
6499 }
100+
101+ result status () const { return _state->status ; }
102+ uint16_t getErrorCount () const { return _state->errorcount ; }
65103};
0 commit comments