1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-22 21:23:07 +03:00

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.
This commit is contained in:
Ivan Grokhotkov 2015-06-11 18:01:08 +03:00
parent 567d401ed3
commit e6e57a8b81
7 changed files with 118 additions and 12 deletions

View File

@ -33,6 +33,8 @@ extern "C" {
#include "lwip/dns.h" #include "lwip/dns.h"
} }
#include "WiFiClient.h"
#include "WiFiUdp.h"
extern "C" void esp_schedule(); extern "C" void esp_schedule();
extern "C" void esp_yield(); extern "C" void esp_yield();
@ -42,6 +44,7 @@ ESP8266WiFiClass::ESP8266WiFiClass()
, _useClientMode(false) , _useClientMode(false)
, _useStaticIp(false) , _useStaticIp(false)
{ {
wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback);
} }
void ESP8266WiFiClass::mode(WiFiMode m) void ESP8266WiFiClass::mode(WiFiMode m)
@ -104,8 +107,8 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch
wifi_set_channel(channel); wifi_set_channel(channel);
} }
if(!_useStaticIp) if(!_useStaticIp)
wifi_station_dhcpc_start(); wifi_station_dhcpc_start();
return status(); return status();
} }
@ -128,8 +131,8 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
wifi_station_dhcpc_stop(); wifi_station_dhcpc_stop();
wifi_set_ip_info(STATION_IF, &info); wifi_set_ip_info(STATION_IF, &info);
_useStaticIp = true; _useStaticIp = true;
} }
void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns) 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
ip_addr_t d; ip_addr_t d;
d.addr = static_cast<uint32_t>(dns); d.addr = static_cast<uint32_t>(dns);
dns_setserver(0,&d); dns_setserver(0,&d);
_useStaticIp = true; _useStaticIp = true;
} }
int ESP8266WiFiClass::disconnect() int ESP8266WiFiClass::disconnect()
@ -588,6 +591,17 @@ void ESP8266WiFiClass::_smartConfigCallback(uint32_t st, void* result)
} }
} }
void ESP8266WiFiClass::_eventCallback(void* arg)
{
System_Event_t* event = reinterpret_cast<System_Event_t*>(arg);
DEBUGV("wifi evt: %d\r\n", event->event);
if (event->event == EVENT_STAMODE_DISCONNECTED) {
WiFiClient::stopAll();
WiFiUDP::stopAll();
}
}
void ESP8266WiFiClass::printDiag(Print& p) void ESP8266WiFiClass::printDiag(Print& p)
{ {
const char* modes[] = {"NULL", "STA", "AP", "STA+AP"}; const char* modes[] = {"NULL", "STA", "AP", "STA+AP"};

View File

@ -313,6 +313,7 @@ protected:
static void _scanDone(void* result, int status); static void _scanDone(void* result, int status);
void * _getScanInfoByIndex(int i); void * _getScanInfoByIndex(int i);
static void _smartConfigCallback(uint32_t status, void* result); static void _smartConfigCallback(uint32_t status, void* result);
static void _eventCallback(void *event);
bool _smartConfigStarted = false; bool _smartConfigStarted = false;
bool _smartConfigDone = false; bool _smartConfigDone = false;

View File

@ -34,26 +34,35 @@ extern "C"
#include "WiFiClient.h" #include "WiFiClient.h"
#include "WiFiServer.h" #include "WiFiServer.h"
#include "lwip/opt.h" #include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/tcp.h" #include "lwip/tcp.h"
#include "lwip/inet.h" #include "lwip/inet.h"
#include "lwip/netif.h"
#include "cbuf.h" #include "cbuf.h"
#include "include/ClientContext.h" #include "include/ClientContext.h"
#include "c_types.h" #include "c_types.h"
uint16_t WiFiClient::_localPort = 0; uint16_t WiFiClient::_localPort = 0;
template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;
WiFiClient::WiFiClient() WiFiClient::WiFiClient()
: _client(0) : _client(0)
{ {
WiFiClient::_add(this);
} }
WiFiClient::WiFiClient(ClientContext* client) : _client(client) WiFiClient::WiFiClient(ClientContext* client) : _client(client)
{ {
_client->ref(); _client->ref();
WiFiClient::_add(this);
} }
WiFiClient::~WiFiClient() WiFiClient::~WiFiClient()
{ {
WiFiClient::_remove(this);
if (_client) if (_client)
_client->unref(); _client->unref();
} }
@ -63,6 +72,7 @@ WiFiClient::WiFiClient(const WiFiClient& other)
_client = other._client; _client = other._client;
if (_client) if (_client)
_client->ref(); _client->ref();
WiFiClient::_add(this);
} }
WiFiClient& WiFiClient::operator=(const WiFiClient& other) WiFiClient& WiFiClient::operator=(const WiFiClient& other)
@ -88,9 +98,21 @@ int WiFiClient::connect(const char* host, uint16_t port)
int WiFiClient::connect(IPAddress ip, uint16_t port) int WiFiClient::connect(IPAddress ip, uint16_t port)
{ {
ip_addr_t addr;
addr.addr = ip;
if (_client) if (_client)
stop(); stop();
// if the default interface is down, tcp_connect exits early without
// ever calling tcp_err
// http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
netif* interface = ip_route(&addr);
if (!interface) {
DEBUGV("no route to host\r\n");
return 1;
}
tcp_pcb* pcb = tcp_new(); tcp_pcb* pcb = tcp_new();
if (!pcb) if (!pcb)
return 0; return 0;
@ -99,8 +121,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
pcb->local_port = _localPort++; pcb->local_port = _localPort++;
} }
ip_addr_t addr;
addr.addr = ip;
tcp_arg(pcb, this); tcp_arg(pcb, this);
tcp_err(pcb, &WiFiClient::_s_err); tcp_err(pcb, &WiFiClient::_s_err);
tcp_connect(pcb, &addr, port, reinterpret_cast<tcp_connected_fn>(&WiFiClient::_s_connected)); 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)
reinterpret_cast<WiFiClient*>(arg)->_err(err); reinterpret_cast<WiFiClient*>(arg)->_err(err);
} }
void WiFiClient::stopAll()
{
for (WiFiClient* it = _s_first; it; it = it->_next) {
ClientContext* c = it->_client;
if (c) {
c->abort();
c->unref();
it->_client = 0;
}
}
}

View File

@ -26,11 +26,12 @@
#include "Client.h" #include "Client.h"
#include "IPAddress.h" #include "IPAddress.h"
#include <memory> #include <memory>
#include "include/slist.h"
class ClientContext; class ClientContext;
class WiFiServer; class WiFiServer;
class WiFiClient : public Client { class WiFiClient : public Client, public SList<WiFiClient> {
protected: protected:
WiFiClient(ClientContext* client); WiFiClient(ClientContext* client);
@ -89,6 +90,8 @@ public:
using Print::write; using Print::write;
static void stopAll();
private: private:
static int8_t _s_connected(void* arg, void* tpcb, int8_t err); static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
@ -99,7 +102,6 @@ private:
ClientContext* _client; ClientContext* _client;
static uint16_t _localPort; static uint16_t _localPort;
}; };

View File

@ -40,14 +40,22 @@ extern "C"
#include "lwip/mem.h" #include "lwip/mem.h"
#include "include/UdpContext.h" #include "include/UdpContext.h"
template<>
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
/* Constructor */ /* Constructor */
WiFiUDP::WiFiUDP() : _ctx(0) {} WiFiUDP::WiFiUDP() : _ctx(0)
{
WiFiUDP::_add(this);
}
WiFiUDP::WiFiUDP(const WiFiUDP& other) WiFiUDP::WiFiUDP(const WiFiUDP& other)
{ {
_ctx = other._ctx; _ctx = other._ctx;
if (_ctx) if (_ctx)
_ctx->ref(); _ctx->ref();
WiFiUDP::_add(this);
} }
WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
@ -60,6 +68,7 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
WiFiUDP::~WiFiUDP() WiFiUDP::~WiFiUDP()
{ {
WiFiUDP::_remove(this);
if (_ctx) if (_ctx)
_ctx->unref(); _ctx->unref();
} }
@ -258,3 +267,11 @@ uint16_t WiFiUDP::localPort()
return _ctx->getLocalPort(); return _ctx->getLocalPort();
} }
void WiFiUDP::stopAll()
{
for (WiFiUDP* it = _s_first; it; it = it->_next) {
it->stop();
}
}

View File

@ -23,12 +23,13 @@
#define WIFIUDP_H #define WIFIUDP_H
#include <Udp.h> #include <Udp.h>
#include <include/slist.h>
#define UDP_TX_PACKET_MAX_SIZE 8192 #define UDP_TX_PACKET_MAX_SIZE 8192
class UdpContext; class UdpContext;
class WiFiUDP : public UDP { class WiFiUDP : public UDP, public SList<WiFiUDP> {
private: private:
UdpContext* _ctx; UdpContext* _ctx;
@ -103,6 +104,8 @@ public:
// Return the local port for outgoing packets // Return the local port for outgoing packets
uint16_t localPort(); uint16_t localPort();
static void stopAll();
}; };
#endif //WIFIUDP_H #endif //WIFIUDP_H

View File

@ -0,0 +1,38 @@
#ifndef SLIST_H
#define SLIST_H
template<typename T>
class SList {
public:
SList() : _next(0) { }
protected:
static void _add(T* self) {
T* tmp = _s_first;
_s_first = self;
self->_next = tmp;
}
static void _remove(T* self) {
if (_s_first == self) {
_s_first = self->_next;
self->_next = 0;
return;
}
for (T* prev = _s_first; prev->_next; _s_first = _s_first->_next) {
if (prev->_next == self) {
prev->_next = self->_next;
self->_next = 0;
return;
}
}
}
static T* _s_first;
T* _next;
};
#endif //SLIST_H