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 "WiFiClient.h"
#include "WiFiUdp.h"
extern "C" void esp_schedule();
extern "C" void esp_yield();
@ -42,6 +44,7 @@ ESP8266WiFiClass::ESP8266WiFiClass()
, _useClientMode(false)
, _useStaticIp(false)
{
wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback);
}
void ESP8266WiFiClass::mode(WiFiMode m)
@ -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)
{
const char* modes[] = {"NULL", "STA", "AP", "STA+AP"};

View File

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

View File

@ -34,26 +34,35 @@ extern "C"
#include "WiFiClient.h"
#include "WiFiServer.h"
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include "cbuf.h"
#include "include/ClientContext.h"
#include "c_types.h"
uint16_t WiFiClient::_localPort = 0;
template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;
WiFiClient::WiFiClient()
: _client(0)
{
WiFiClient::_add(this);
}
WiFiClient::WiFiClient(ClientContext* client) : _client(client)
{
_client->ref();
WiFiClient::_add(this);
}
WiFiClient::~WiFiClient()
{
WiFiClient::_remove(this);
if (_client)
_client->unref();
}
@ -63,6 +72,7 @@ WiFiClient::WiFiClient(const WiFiClient& other)
_client = other._client;
if (_client)
_client->ref();
WiFiClient::_add(this);
}
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)
{
ip_addr_t addr;
addr.addr = ip;
if (_client)
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();
if (!pcb)
return 0;
@ -99,8 +121,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
pcb->local_port = _localPort++;
}
ip_addr_t addr;
addr.addr = ip;
tcp_arg(pcb, this);
tcp_err(pcb, &WiFiClient::_s_err);
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);
}
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 "IPAddress.h"
#include <memory>
#include "include/slist.h"
class ClientContext;
class WiFiServer;
class WiFiClient : public Client {
class WiFiClient : public Client, public SList<WiFiClient> {
protected:
WiFiClient(ClientContext* client);
@ -89,6 +90,8 @@ public:
using Print::write;
static void stopAll();
private:
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
@ -99,7 +102,6 @@ private:
ClientContext* _client;
static uint16_t _localPort;
};

View File

@ -40,14 +40,22 @@ extern "C"
#include "lwip/mem.h"
#include "include/UdpContext.h"
template<>
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
/* Constructor */
WiFiUDP::WiFiUDP() : _ctx(0) {}
WiFiUDP::WiFiUDP() : _ctx(0)
{
WiFiUDP::_add(this);
}
WiFiUDP::WiFiUDP(const WiFiUDP& other)
{
_ctx = other._ctx;
if (_ctx)
_ctx->ref();
WiFiUDP::_add(this);
}
WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
@ -60,6 +68,7 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
WiFiUDP::~WiFiUDP()
{
WiFiUDP::_remove(this);
if (_ctx)
_ctx->unref();
}
@ -258,3 +267,11 @@ uint16_t WiFiUDP::localPort()
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
#include <Udp.h>
#include <include/slist.h>
#define UDP_TX_PACKET_MAX_SIZE 8192
class UdpContext;
class WiFiUDP : public UDP {
class WiFiUDP : public UDP, public SList<WiFiUDP> {
private:
UdpContext* _ctx;
@ -103,6 +104,8 @@ public:
// Return the local port for outgoing packets
uint16_t localPort();
static void stopAll();
};
#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