Skip to content

Configurable timeout for WiFiClient connect and write operations #3257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,23 @@ 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
* @param aResult IPAddress structure to store the returned IP address
* @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<uint32_t>(0);

Expand All @@ -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;
Expand Down Expand Up @@ -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<IPAddress*>(callback_arg)) = ipaddr->addr;
}
Expand Down
1 change: 1 addition & 0 deletions libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
60 changes: 20 additions & 40 deletions libraries/ESP8266WiFi/src/WiFiClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ WiFiClient* SList<WiFiClient>::_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);
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);
}
Expand Down Expand Up @@ -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<tcp_connected_fn>(&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<tcp_pcb*>(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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -196,6 +184,7 @@ size_t WiFiClient::write(Stream& stream)
{
return 0;
}
_client->setTimeout(_timeout);
return _client->write(stream);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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<WiFiClient*>(arg)->_connected(tpcb, err);
}

void WiFiClient::_s_err(void* arg, int8_t err)
{
reinterpret_cast<WiFiClient*>(arg)->_err(err);
}

void WiFiClient::stopAll()
{
for (WiFiClient* it = _s_first; it; it = it->_next) {
Expand Down
70 changes: 55 additions & 15 deletions libraries/ESP8266WiFi/src/include/ClientContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<tcp_connected_fn>(&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;
}
Expand All @@ -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()
Expand Down Expand Up @@ -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();
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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*)
Expand Down Expand Up @@ -485,6 +518,11 @@ class ClientContext
return reinterpret_cast<ClientContext*>(arg)->_sent(tpcb, len);
}

static int8_t _s_connected(void* arg, void* pcb, int8_t err)
{
return reinterpret_cast<ClientContext*>(arg)->_connected(pcb, err);
}

private:
tcp_pcb* _pcb;

Expand All @@ -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