Skip to content

Commit e6e57a8

Browse files
committed
Better handling of wifi disconnect (#231)
When network interface is down, some nasty things happen, for instance tcp_connect returns without ever calling error callback. This change adds some workarounds for that: before doing a tcp connect and DNS resolve we check if there is a route available. Also added a listener for wifi events which stops (aborts) all the WiFiClients and WiFiUDPs when wifi is disconnected. This should help libraries detect disconnect properly.
1 parent 567d401 commit e6e57a8

File tree

7 files changed

+118
-12
lines changed

7 files changed

+118
-12
lines changed

libraries/ESP8266WiFi/src/ESP8266WiFi.cpp

+20-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ extern "C" {
3333
#include "lwip/dns.h"
3434
}
3535

36+
#include "WiFiClient.h"
37+
#include "WiFiUdp.h"
3638

3739
extern "C" void esp_schedule();
3840
extern "C" void esp_yield();
@@ -42,6 +44,7 @@ ESP8266WiFiClass::ESP8266WiFiClass()
4244
, _useClientMode(false)
4345
, _useStaticIp(false)
4446
{
47+
wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback);
4548
}
4649

4750
void ESP8266WiFiClass::mode(WiFiMode m)
@@ -104,8 +107,8 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch
104107
wifi_set_channel(channel);
105108
}
106109

107-
if(!_useStaticIp)
108-
wifi_station_dhcpc_start();
110+
if(!_useStaticIp)
111+
wifi_station_dhcpc_start();
109112
return status();
110113
}
111114

@@ -128,8 +131,8 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
128131

129132
wifi_station_dhcpc_stop();
130133
wifi_set_ip_info(STATION_IF, &info);
131-
132-
_useStaticIp = true;
134+
135+
_useStaticIp = true;
133136
}
134137

135138
void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns)
@@ -146,8 +149,8 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
146149
ip_addr_t d;
147150
d.addr = static_cast<uint32_t>(dns);
148151
dns_setserver(0,&d);
149-
150-
_useStaticIp = true;
152+
153+
_useStaticIp = true;
151154
}
152155

153156
int ESP8266WiFiClass::disconnect()
@@ -588,6 +591,17 @@ void ESP8266WiFiClass::_smartConfigCallback(uint32_t st, void* result)
588591
}
589592
}
590593

594+
void ESP8266WiFiClass::_eventCallback(void* arg)
595+
{
596+
System_Event_t* event = reinterpret_cast<System_Event_t*>(arg);
597+
DEBUGV("wifi evt: %d\r\n", event->event);
598+
599+
if (event->event == EVENT_STAMODE_DISCONNECTED) {
600+
WiFiClient::stopAll();
601+
WiFiUDP::stopAll();
602+
}
603+
}
604+
591605
void ESP8266WiFiClass::printDiag(Print& p)
592606
{
593607
const char* modes[] = {"NULL", "STA", "AP", "STA+AP"};

libraries/ESP8266WiFi/src/ESP8266WiFi.h

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class ESP8266WiFiClass
313313
static void _scanDone(void* result, int status);
314314
void * _getScanInfoByIndex(int i);
315315
static void _smartConfigCallback(uint32_t status, void* result);
316+
static void _eventCallback(void *event);
316317
bool _smartConfigStarted = false;
317318
bool _smartConfigDone = false;
318319

libraries/ESP8266WiFi/src/WiFiClient.cpp

+33-2
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,35 @@ extern "C"
3434
#include "WiFiClient.h"
3535
#include "WiFiServer.h"
3636
#include "lwip/opt.h"
37+
#include "lwip/ip.h"
3738
#include "lwip/tcp.h"
3839
#include "lwip/inet.h"
40+
#include "lwip/netif.h"
3941
#include "cbuf.h"
4042
#include "include/ClientContext.h"
4143
#include "c_types.h"
4244

4345
uint16_t WiFiClient::_localPort = 0;
4446

47+
template<>
48+
WiFiClient* SList<WiFiClient>::_s_first = 0;
49+
50+
4551
WiFiClient::WiFiClient()
4652
: _client(0)
4753
{
54+
WiFiClient::_add(this);
4855
}
4956

5057
WiFiClient::WiFiClient(ClientContext* client) : _client(client)
5158
{
5259
_client->ref();
60+
WiFiClient::_add(this);
5361
}
5462

5563
WiFiClient::~WiFiClient()
5664
{
65+
WiFiClient::_remove(this);
5766
if (_client)
5867
_client->unref();
5968
}
@@ -63,6 +72,7 @@ WiFiClient::WiFiClient(const WiFiClient& other)
6372
_client = other._client;
6473
if (_client)
6574
_client->ref();
75+
WiFiClient::_add(this);
6676
}
6777

6878
WiFiClient& WiFiClient::operator=(const WiFiClient& other)
@@ -88,9 +98,21 @@ int WiFiClient::connect(const char* host, uint16_t port)
8898

8999
int WiFiClient::connect(IPAddress ip, uint16_t port)
90100
{
101+
ip_addr_t addr;
102+
addr.addr = ip;
103+
91104
if (_client)
92105
stop();
93106

107+
// if the default interface is down, tcp_connect exits early without
108+
// ever calling tcp_err
109+
// http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
110+
netif* interface = ip_route(&addr);
111+
if (!interface) {
112+
DEBUGV("no route to host\r\n");
113+
return 1;
114+
}
115+
94116
tcp_pcb* pcb = tcp_new();
95117
if (!pcb)
96118
return 0;
@@ -99,8 +121,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
99121
pcb->local_port = _localPort++;
100122
}
101123

102-
ip_addr_t addr;
103-
addr.addr = ip;
104124
tcp_arg(pcb, this);
105125
tcp_err(pcb, &WiFiClient::_s_err);
106126
tcp_connect(pcb, &addr, port, reinterpret_cast<tcp_connected_fn>(&WiFiClient::_s_connected));
@@ -257,3 +277,14 @@ void WiFiClient::_s_err(void* arg, int8_t err)
257277
reinterpret_cast<WiFiClient*>(arg)->_err(err);
258278
}
259279

280+
void WiFiClient::stopAll()
281+
{
282+
for (WiFiClient* it = _s_first; it; it = it->_next) {
283+
ClientContext* c = it->_client;
284+
if (c) {
285+
c->abort();
286+
c->unref();
287+
it->_client = 0;
288+
}
289+
}
290+
}

libraries/ESP8266WiFi/src/WiFiClient.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@
2626
#include "Client.h"
2727
#include "IPAddress.h"
2828
#include <memory>
29+
#include "include/slist.h"
2930

3031
class ClientContext;
3132
class WiFiServer;
3233

33-
class WiFiClient : public Client {
34+
class WiFiClient : public Client, public SList<WiFiClient> {
3435
protected:
3536
WiFiClient(ClientContext* client);
3637

@@ -89,6 +90,8 @@ class WiFiClient : public Client {
8990

9091
using Print::write;
9192

93+
static void stopAll();
94+
9295
private:
9396

9497
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
@@ -99,7 +102,6 @@ class WiFiClient : public Client {
99102

100103
ClientContext* _client;
101104
static uint16_t _localPort;
102-
103105
};
104106

105107

libraries/ESP8266WiFi/src/WiFiUdp.cpp

+18-1
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,22 @@ extern "C"
4040
#include "lwip/mem.h"
4141
#include "include/UdpContext.h"
4242

43+
44+
template<>
45+
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
46+
4347
/* Constructor */
44-
WiFiUDP::WiFiUDP() : _ctx(0) {}
48+
WiFiUDP::WiFiUDP() : _ctx(0)
49+
{
50+
WiFiUDP::_add(this);
51+
}
4552

4653
WiFiUDP::WiFiUDP(const WiFiUDP& other)
4754
{
4855
_ctx = other._ctx;
4956
if (_ctx)
5057
_ctx->ref();
58+
WiFiUDP::_add(this);
5159
}
5260

5361
WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
@@ -60,6 +68,7 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
6068

6169
WiFiUDP::~WiFiUDP()
6270
{
71+
WiFiUDP::_remove(this);
6372
if (_ctx)
6473
_ctx->unref();
6574
}
@@ -258,3 +267,11 @@ uint16_t WiFiUDP::localPort()
258267

259268
return _ctx->getLocalPort();
260269
}
270+
271+
void WiFiUDP::stopAll()
272+
{
273+
for (WiFiUDP* it = _s_first; it; it = it->_next) {
274+
it->stop();
275+
}
276+
}
277+

libraries/ESP8266WiFi/src/WiFiUdp.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@
2323
#define WIFIUDP_H
2424

2525
#include <Udp.h>
26+
#include <include/slist.h>
2627

2728
#define UDP_TX_PACKET_MAX_SIZE 8192
2829

2930
class UdpContext;
3031

31-
class WiFiUDP : public UDP {
32+
class WiFiUDP : public UDP, public SList<WiFiUDP> {
3233
private:
3334
UdpContext* _ctx;
3435

@@ -103,6 +104,8 @@ class WiFiUDP : public UDP {
103104
// Return the local port for outgoing packets
104105
uint16_t localPort();
105106

107+
static void stopAll();
108+
106109
};
107110

108111
#endif //WIFIUDP_H
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef SLIST_H
2+
#define SLIST_H
3+
4+
template<typename T>
5+
class SList {
6+
public:
7+
SList() : _next(0) { }
8+
9+
protected:
10+
11+
static void _add(T* self) {
12+
T* tmp = _s_first;
13+
_s_first = self;
14+
self->_next = tmp;
15+
}
16+
17+
static void _remove(T* self) {
18+
if (_s_first == self) {
19+
_s_first = self->_next;
20+
self->_next = 0;
21+
return;
22+
}
23+
24+
for (T* prev = _s_first; prev->_next; _s_first = _s_first->_next) {
25+
if (prev->_next == self) {
26+
prev->_next = self->_next;
27+
self->_next = 0;
28+
return;
29+
}
30+
}
31+
}
32+
33+
static T* _s_first;
34+
T* _next;
35+
};
36+
37+
38+
#endif //SLIST_H

0 commit comments

Comments
 (0)