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:
parent
567d401ed3
commit
e6e57a8b81
@ -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"};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
38
libraries/ESP8266WiFi/src/include/slist.h
Normal file
38
libraries/ESP8266WiFi/src/include/slist.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user