diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp index 1fc13a116e..7b90dc310f 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -426,6 +426,8 @@ void wifi_dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg); #endif +static bool _dns_lookup_pending = false; + /** * Resolve the given hostname to an IP address. * @param aHostname Name to be resolved @@ -433,7 +435,14 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca * @return 1 if aIPAddrString was successfully converted to an IP address, * else error code */ -int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) { +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return hostByName(aHostname, aResult, 10000); +} + + +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) +{ ip_addr_t addr; aResult = static_cast(0); @@ -448,7 +457,9 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul if(err == ERR_OK) { aResult = addr.addr; } else if(err == ERR_INPROGRESS) { - esp_yield(); + _dns_lookup_pending = true; + delay(timeout_ms); + _dns_lookup_pending = false; // will return here when dns_found_callback fires if(aResult != 0) { err = ERR_OK; @@ -477,6 +488,9 @@ void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *ca #endif { (void) name; + if (!_dns_lookup_pending) { + return; + } if(ipaddr) { (*reinterpret_cast(callback_arg)) = ipaddr->addr; } diff --git a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h index 3ece467b05..668c9223da 100644 --- a/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h +++ b/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h @@ -98,6 +98,7 @@ class ESP8266WiFiGenericClass { public: int hostByName(const char* aHostname, IPAddress& aResult); + int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms); protected: diff --git a/libraries/ESP8266WiFi/src/WiFiClient.cpp b/libraries/ESP8266WiFi/src/WiFiClient.cpp index 144cf194b5..7809218703 100644 --- a/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -48,12 +48,13 @@ WiFiClient* SList::_s_first = 0; WiFiClient::WiFiClient() -: _client(0) +: _client(0), _timeout(5000) { WiFiClient::_add(this); } -WiFiClient::WiFiClient(ClientContext* client) : _client(client) +WiFiClient::WiFiClient(ClientContext* client) +: _client(client), _timeout(5000) { _client->ref(); WiFiClient::_add(this); @@ -69,6 +70,8 @@ WiFiClient::~WiFiClient() WiFiClient::WiFiClient(const WiFiClient& other) { _client = other._client; + _timeout = other._timeout; + _localPort = other._localPort; if (_client) _client->ref(); WiFiClient::_add(this); @@ -79,6 +82,8 @@ WiFiClient& WiFiClient::operator=(const WiFiClient& other) if (_client) _client->unref(); _client = other._client; + _timeout = other._timeout; + _localPort = other._localPort; if (_client) _client->ref(); return *this; @@ -88,7 +93,7 @@ WiFiClient& WiFiClient::operator=(const WiFiClient& other) int WiFiClient::connect(const char* host, uint16_t port) { IPAddress remote_addr; - if (WiFi.hostByName(host, remote_addr)) + if (WiFi.hostByName(host, remote_addr, _timeout)) { return connect(remote_addr, port); } @@ -122,37 +127,19 @@ int WiFiClient::connect(IPAddress ip, uint16_t port) pcb->local_port = _localPort++; } - tcp_arg(pcb, this); - tcp_err(pcb, &WiFiClient::_s_err); - tcp_connect(pcb, &addr, port, reinterpret_cast(&WiFiClient::_s_connected)); - - esp_yield(); - if (_client) - return 1; - - // if tcp_error was called, pcb has already been destroyed. - // tcp_abort(pcb); - return 0; -} - -int8_t WiFiClient::_connected(void* pcb, int8_t err) -{ - (void) err; - tcp_pcb* tpcb = reinterpret_cast(pcb); - _client = new ClientContext(tpcb, 0, 0); + _client = new ClientContext(pcb, nullptr, nullptr); _client->ref(); - esp_schedule(); - return ERR_OK; -} + _client->setTimeout(_timeout); + int res = _client->connect(&addr, port); + if (res == 0) { + _client->unref(); + _client = nullptr; + return 0; + } -void WiFiClient::_err(int8_t err) -{ - (void) err; - DEBUGV(":err %d\r\n", err); - esp_schedule(); + return 1; } - void WiFiClient::setNoDelay(bool nodelay) { if (!_client) return; @@ -181,6 +168,7 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size) { return 0; } + _client->setTimeout(_timeout); return _client->write(buf, size); } @@ -196,6 +184,7 @@ size_t WiFiClient::write(Stream& stream) { return 0; } + _client->setTimeout(_timeout); return _client->write(stream); } @@ -205,6 +194,7 @@ size_t WiFiClient::write_P(PGM_P buf, size_t size) { return 0; } + _client->setTimeout(_timeout); return _client->write_P(buf, size); } @@ -331,16 +321,6 @@ uint16_t WiFiClient::localPort() return _client->getLocalPort(); } -int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err) -{ - return reinterpret_cast(arg)->_connected(tpcb, err); -} - -void WiFiClient::_s_err(void* arg, int8_t err) -{ - reinterpret_cast(arg)->_err(err); -} - void WiFiClient::stopAll() { for (WiFiClient* it = _s_first; it; it = it->_next) { diff --git a/libraries/ESP8266WiFi/src/include/ClientContext.h b/libraries/ESP8266WiFi/src/include/ClientContext.h index c7d5bde00c..82e0594679 100644 --- a/libraries/ESP8266WiFi/src/include/ClientContext.h +++ b/libraries/ESP8266WiFi/src/include/ClientContext.h @@ -124,7 +124,25 @@ class ClientContext } } - size_t availableForWrite () + int connect(ip_addr_t* addr, uint16_t port) + { + err_t err = tcp_connect(_pcb, addr, port, reinterpret_cast(&ClientContext::_s_connected)); + if (err != ERR_OK) { + return 0; + } + _connect_pending = 1; + _op_start_time = millis(); + // This delay will be interrupted by esp_schedule in the connect callback + delay(_timeout_ms); + _connect_pending = 0; + if (state() != ESTABLISHED) { + abort(); + return 0; + } + return 1; + } + + size_t availableForWrite() { return _pcb? tcp_sndbuf(_pcb): 0; } @@ -149,14 +167,14 @@ class ClientContext return tcp_nagle_disabled(_pcb); } - void setNonBlocking(bool nonblocking) + void setTimeout(int timeout_ms) { - _noblock = nonblocking; + _timeout_ms = timeout_ms; } - bool getNonBlocking() + int getTimeout() { - return _noblock; + return _timeout_ms; } uint32_t getRemoteAddress() @@ -315,9 +333,14 @@ class ClientContext protected: - void _cancel_write() + bool _is_timeout() + { + return millis() - _op_start_time > _timeout_ms; + } + + void _notify_error() { - if (_send_waiting) { + if (_connect_pending || _send_waiting) { esp_schedule(); } } @@ -328,10 +351,11 @@ class ClientContext assert(_send_waiting == 0); _datasource = ds; _written = 0; + _op_start_time = millis(); do { _write_some(); - if (!_datasource->available() || _noblock || state() == CLOSED) { + if (!_datasource->available() || _is_timeout() || state() == CLOSED) { delete _datasource; _datasource = nullptr; break; @@ -431,7 +455,7 @@ class ClientContext (void) err; if(pb == 0) { // connection closed DEBUGV(":rcl\r\n"); - _cancel_write(); + _notify_error(); abort(); return ERR_ABRT; } @@ -456,7 +480,16 @@ class ClientContext tcp_recv(_pcb, NULL); tcp_err(_pcb, NULL); _pcb = NULL; - _cancel_write(); + _notify_error(); + } + + int8_t _connected(void* pcb, int8_t err) + { + (void) err; + assert(pcb == _pcb); + assert(_connect_pending); + esp_schedule(); + return ERR_OK; } err_t _poll(tcp_pcb*) @@ -485,6 +518,11 @@ class ClientContext return reinterpret_cast(arg)->_sent(tpcb, len); } + static int8_t _s_connected(void* arg, void* pcb, int8_t err) + { + return reinterpret_cast(arg)->_connected(pcb, err); + } + private: tcp_pcb* _pcb; @@ -494,14 +532,16 @@ class ClientContext discard_cb_t _discard_cb; void* _discard_cb_arg; - int _refcnt; - ClientContext* _next; - DataSource* _datasource = nullptr; size_t _written = 0; size_t _write_chunk_size = 256; - bool _noblock = false; - int _send_waiting = 0; + uint32_t _timeout_ms = 5000; + uint32_t _op_start_time = 0; + uint8_t _send_waiting = 0; + uint8_t _connect_pending = 0; + + int8_t _refcnt; + ClientContext* _next; }; #endif//CLIENTCONTEXT_H