Skip to content

Commit eebcc65

Browse files
committed
WiFiClient: add support for connect timeout
1 parent 2aeac91 commit eebcc65

File tree

2 files changed

+65
-53
lines changed

2 files changed

+65
-53
lines changed

libraries/ESP8266WiFi/src/WiFiClient.cpp

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ WiFiClient& WiFiClient::operator=(const WiFiClient& other)
8888
int WiFiClient::connect(const char* host, uint16_t port)
8989
{
9090
IPAddress remote_addr;
91-
if (WiFi.hostByName(host, remote_addr))
91+
if (WiFi.hostByName(host, remote_addr, _timeout))
9292
{
9393
return connect(remote_addr, port);
9494
}
@@ -122,37 +122,19 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
122122
pcb->local_port = _localPort++;
123123
}
124124

125-
tcp_arg(pcb, this);
126-
tcp_err(pcb, &WiFiClient::_s_err);
127-
tcp_connect(pcb, &addr, port, reinterpret_cast<tcp_connected_fn>(&WiFiClient::_s_connected));
128-
129-
esp_yield();
130-
if (_client)
131-
return 1;
132-
133-
// if tcp_error was called, pcb has already been destroyed.
134-
// tcp_abort(pcb);
135-
return 0;
136-
}
137-
138-
int8_t WiFiClient::_connected(void* pcb, int8_t err)
139-
{
140-
(void) err;
141-
tcp_pcb* tpcb = reinterpret_cast<tcp_pcb*>(pcb);
142-
_client = new ClientContext(tpcb, 0, 0);
125+
_client = new ClientContext(pcb, nullptr, nullptr);
143126
_client->ref();
144-
esp_schedule();
145-
return ERR_OK;
146-
}
127+
_client->setTimeout(_timeout);
128+
int res = _client->connect(&addr, port);
129+
if (res == 0) {
130+
_client->unref();
131+
_client = nullptr;
132+
return 0;
133+
}
147134

148-
void WiFiClient::_err(int8_t err)
149-
{
150-
(void) err;
151-
DEBUGV(":err %d\r\n", err);
152-
esp_schedule();
135+
return 1;
153136
}
154137

155-
156138
void WiFiClient::setNoDelay(bool nodelay) {
157139
if (!_client)
158140
return;
@@ -331,16 +313,6 @@ uint16_t WiFiClient::localPort()
331313
return _client->getLocalPort();
332314
}
333315

334-
int8_t WiFiClient::_s_connected(void* arg, void* tpcb, int8_t err)
335-
{
336-
return reinterpret_cast<WiFiClient*>(arg)->_connected(tpcb, err);
337-
}
338-
339-
void WiFiClient::_s_err(void* arg, int8_t err)
340-
{
341-
reinterpret_cast<WiFiClient*>(arg)->_err(err);
342-
}
343-
344316
void WiFiClient::stopAll()
345317
{
346318
for (WiFiClient* it = _s_first; it; it = it->_next) {

libraries/ESP8266WiFi/src/include/ClientContext.h

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,25 @@ class ClientContext
124124
}
125125
}
126126

127-
size_t availableForWrite ()
127+
int connect(ip_addr_t* addr, uint16_t port)
128+
{
129+
err_t err = tcp_connect(_pcb, addr, port, reinterpret_cast<tcp_connected_fn>(&ClientContext::_s_connected));
130+
if (err != ERR_OK) {
131+
return 0;
132+
}
133+
_connect_pending = 1;
134+
_op_start_time = millis();
135+
// This delay will be interrupted by esp_schedule in the connect callback
136+
delay(_timeout_ms);
137+
_connect_pending = 0;
138+
if (state() != ESTABLISHED) {
139+
abort();
140+
return 0;
141+
}
142+
return 1;
143+
}
144+
145+
size_t availableForWrite()
128146
{
129147
return _pcb? tcp_sndbuf(_pcb): 0;
130148
}
@@ -149,14 +167,14 @@ class ClientContext
149167
return tcp_nagle_disabled(_pcb);
150168
}
151169

152-
void setNonBlocking(bool nonblocking)
170+
void setTimeout(int timeout_ms)
153171
{
154-
_noblock = nonblocking;
172+
_timeout_ms = timeout_ms;
155173
}
156174

157-
bool getNonBlocking()
175+
int getTimeout()
158176
{
159-
return _noblock;
177+
return _timeout_ms;
160178
}
161179

162180
uint32_t getRemoteAddress()
@@ -315,9 +333,14 @@ class ClientContext
315333

316334
protected:
317335

318-
void _cancel_write()
336+
bool _is_timeout()
337+
{
338+
return millis() - _op_start_time > _timeout_ms;
339+
}
340+
341+
void _notify_error()
319342
{
320-
if (_send_waiting) {
343+
if (_connect_pending || _send_waiting) {
321344
esp_schedule();
322345
}
323346
}
@@ -328,10 +351,11 @@ class ClientContext
328351
assert(_send_waiting == 0);
329352
_datasource = ds;
330353
_written = 0;
354+
_op_start_time = millis();
331355
do {
332356
_write_some();
333357

334-
if (!_datasource->available() || _noblock || state() == CLOSED) {
358+
if (!_datasource->available() || _is_timeout() || state() == CLOSED) {
335359
delete _datasource;
336360
_datasource = nullptr;
337361
break;
@@ -431,7 +455,7 @@ class ClientContext
431455
(void) err;
432456
if(pb == 0) { // connection closed
433457
DEBUGV(":rcl\r\n");
434-
_cancel_write();
458+
_notify_error();
435459
abort();
436460
return ERR_ABRT;
437461
}
@@ -456,7 +480,16 @@ class ClientContext
456480
tcp_recv(_pcb, NULL);
457481
tcp_err(_pcb, NULL);
458482
_pcb = NULL;
459-
_cancel_write();
483+
_notify_error();
484+
}
485+
486+
int8_t _connected(void* pcb, int8_t err)
487+
{
488+
(void) err;
489+
assert(pcb == _pcb);
490+
assert(_connect_pending);
491+
esp_schedule();
492+
return ERR_OK;
460493
}
461494

462495
err_t _poll(tcp_pcb*)
@@ -485,6 +518,11 @@ class ClientContext
485518
return reinterpret_cast<ClientContext*>(arg)->_sent(tpcb, len);
486519
}
487520

521+
static int8_t _s_connected(void* arg, void* pcb, int8_t err)
522+
{
523+
return reinterpret_cast<ClientContext*>(arg)->_connected(pcb, err);
524+
}
525+
488526
private:
489527
tcp_pcb* _pcb;
490528

@@ -494,14 +532,16 @@ class ClientContext
494532
discard_cb_t _discard_cb;
495533
void* _discard_cb_arg;
496534

497-
int _refcnt;
498-
ClientContext* _next;
499-
500535
DataSource* _datasource = nullptr;
501536
size_t _written = 0;
502537
size_t _write_chunk_size = 256;
503-
bool _noblock = false;
504-
int _send_waiting = 0;
538+
uint32_t _timeout_ms = 5000;
539+
uint32_t _op_start_time = 0;
540+
uint8_t _send_waiting = 0;
541+
uint8_t _connect_pending = 0;
542+
543+
int8_t _refcnt;
544+
ClientContext* _next;
505545
};
506546

507547
#endif//CLIENTCONTEXT_H

0 commit comments

Comments
 (0)