mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-30 16:24:09 +03:00
Merge branch 'master' into wifi_mesh_update_2.2
This commit is contained in:
@ -328,9 +328,13 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
}
|
||||
|
||||
if (Update.end()) {
|
||||
client.print("OK");
|
||||
client.stop();
|
||||
// Ensure last count packet has been sent out and not combined with the final OK
|
||||
client.flush();
|
||||
delay(1000);
|
||||
client.print("OK");
|
||||
client.flush();
|
||||
delay(1000);
|
||||
client.stop();
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Update Success\n");
|
||||
#endif
|
||||
|
@ -423,7 +423,6 @@ void HTTPClient::end(void)
|
||||
{
|
||||
disconnect(false);
|
||||
clear();
|
||||
_redirectCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -558,8 +557,17 @@ bool HTTPClient::setURL(const String& url)
|
||||
/**
|
||||
* set true to follow redirects.
|
||||
* @param follow
|
||||
* @deprecated
|
||||
*/
|
||||
void HTTPClient::setFollowRedirects(bool follow)
|
||||
{
|
||||
_followRedirects = follow ? HTTPC_STRICT_FOLLOW_REDIRECTS : HTTPC_DISABLE_FOLLOW_REDIRECTS;
|
||||
}
|
||||
/**
|
||||
* set redirect follow mode. See `followRedirects_t` enum for avaliable modes.
|
||||
* @param follow
|
||||
*/
|
||||
void HTTPClient::setFollowRedirects(followRedirects_t follow)
|
||||
{
|
||||
_followRedirects = follow;
|
||||
}
|
||||
@ -652,8 +660,9 @@ int HTTPClient::sendRequest(const char * type, const String& payload)
|
||||
*/
|
||||
int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t size)
|
||||
{
|
||||
int code;
|
||||
bool redirect = false;
|
||||
int code = 0;
|
||||
uint16_t redirectCount = 0;
|
||||
do {
|
||||
// wipe out any existing headers from previous request
|
||||
for(size_t i = 0; i < _headerKeysCount; i++) {
|
||||
@ -662,8 +671,7 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
|
||||
}
|
||||
}
|
||||
|
||||
redirect = false;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, _redirectCount);
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] type: '%s' redirCount: %d\n", type, redirectCount);
|
||||
|
||||
// connect to server
|
||||
if(!connect()) {
|
||||
@ -687,9 +695,9 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
|
||||
int towrite = std::min((int)size, (int)HTTP_TCP_BUFFER_SIZE);
|
||||
written = _client->write(p + bytesWritten, towrite);
|
||||
if (written < 0) {
|
||||
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||
return returnError(HTTPC_ERROR_SEND_PAYLOAD_FAILED);
|
||||
} else if (written == 0) {
|
||||
return returnError(HTTPC_ERROR_CONNECTION_LOST);
|
||||
return returnError(HTTPC_ERROR_CONNECTION_LOST);
|
||||
}
|
||||
bytesWritten += written;
|
||||
size -= written;
|
||||
@ -700,42 +708,67 @@ int HTTPClient::sendRequest(const char * type, const uint8_t * payload, size_t s
|
||||
code = handleHeaderResponse();
|
||||
|
||||
//
|
||||
// We can follow redirects for 301/302/307 for GET and HEAD requests and
|
||||
// and we have not exceeded the redirect limit preventing an infinite
|
||||
// redirect loop.
|
||||
//
|
||||
// Handle redirections as stated in RFC document:
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
//
|
||||
if (_followRedirects &&
|
||||
(_redirectCount < _redirectLimit) &&
|
||||
(_location.length() > 0) &&
|
||||
(code == 301 || code == 302 || code == 307) &&
|
||||
(!strcmp(type, "GET") || !strcmp(type, "HEAD"))
|
||||
) {
|
||||
_redirectCount += 1; // increment the count for redirect.
|
||||
redirect = true;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect:: '%s' redirCount: %d\n", _location.c_str(), _redirectCount);
|
||||
if (!setURL(_location)) {
|
||||
// return the redirect instead of handling on failure of setURL()
|
||||
redirect = false;
|
||||
// Implementing HTTP_CODE_FOUND as redirection with GET method,
|
||||
// to follow most of existing user agent implementations.
|
||||
//
|
||||
redirect = false;
|
||||
if (
|
||||
_followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
|
||||
redirectCount < _redirectLimit &&
|
||||
_location.length() > 0
|
||||
) {
|
||||
switch (code) {
|
||||
// redirecting using the same method
|
||||
case HTTP_CODE_MOVED_PERMANENTLY:
|
||||
case HTTP_CODE_TEMPORARY_REDIRECT: {
|
||||
if (
|
||||
// allow to force redirections on other methods
|
||||
// (the RFC require user to accept the redirection)
|
||||
_followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS ||
|
||||
// allow GET and HEAD methods without force
|
||||
!strcmp(type, "GET") ||
|
||||
!strcmp(type, "HEAD")
|
||||
) {
|
||||
redirectCount += 1;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
|
||||
if (!setURL(_location)) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] failed setting URL for redirection\n");
|
||||
// no redirection
|
||||
break;
|
||||
}
|
||||
// redirect using the same request method and payload, diffrent URL
|
||||
redirect = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// redirecting with method dropped to GET or HEAD
|
||||
// note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method
|
||||
case HTTP_CODE_FOUND:
|
||||
case HTTP_CODE_SEE_OTHER: {
|
||||
redirectCount += 1;
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
|
||||
if (!setURL(_location)) {
|
||||
DEBUG_HTTPCLIENT("[HTTP-Client][sendRequest] failed setting URL for redirection\n");
|
||||
// no redirection
|
||||
break;
|
||||
}
|
||||
// redirect after changing method to GET/HEAD and dropping payload
|
||||
type = "GET";
|
||||
payload = nullptr;
|
||||
size = 0;
|
||||
redirect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (redirect);
|
||||
|
||||
// handle 303 redirect for non GET/HEAD by changing to GET and requesting new url
|
||||
if (_followRedirects &&
|
||||
(_redirectCount < _redirectLimit) &&
|
||||
(_location.length() > 0) &&
|
||||
(code == 303) &&
|
||||
strcmp(type, "GET") && strcmp(type, "HEAD")
|
||||
) {
|
||||
_redirectCount += 1;
|
||||
if (setURL(_location)) {
|
||||
code = sendRequest("GET");
|
||||
}
|
||||
}
|
||||
|
||||
// handle Server Response (Header)
|
||||
return returnError(code);
|
||||
}
|
||||
|
@ -130,6 +130,23 @@ typedef enum {
|
||||
HTTPC_TE_CHUNKED
|
||||
} transferEncoding_t;
|
||||
|
||||
/**
|
||||
* redirection follow mode.
|
||||
* + `HTTPC_DISABLE_FOLLOW_REDIRECTS` - no redirection will be followed.
|
||||
* + `HTTPC_STRICT_FOLLOW_REDIRECTS` - strict RFC2616, only requests using
|
||||
* GET or HEAD methods will be redirected (using the same method),
|
||||
* since the RFC requires end-user confirmation in other cases.
|
||||
* + `HTTPC_FORCE_FOLLOW_REDIRECTS` - all redirections will be followed,
|
||||
* regardless of a used method. New request will use the same method,
|
||||
* and they will include the same body data and the same headers.
|
||||
* In the sense of the RFC, it's just like every redirection is confirmed.
|
||||
*/
|
||||
typedef enum {
|
||||
HTTPC_DISABLE_FOLLOW_REDIRECTS,
|
||||
HTTPC_STRICT_FOLLOW_REDIRECTS,
|
||||
HTTPC_FORCE_FOLLOW_REDIRECTS
|
||||
} followRedirects_t;
|
||||
|
||||
#if HTTPCLIENT_1_1_COMPATIBLE
|
||||
class TransportTraits;
|
||||
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
||||
@ -173,8 +190,12 @@ public:
|
||||
void setAuthorization(const char * user, const char * password);
|
||||
void setAuthorization(const char * auth);
|
||||
void setTimeout(uint16_t timeout);
|
||||
void setFollowRedirects(bool follow);
|
||||
|
||||
// Redirections
|
||||
void setFollowRedirects(bool follow) __attribute__ ((deprecated));
|
||||
void setFollowRedirects(followRedirects_t follow);
|
||||
void setRedirectLimit(uint16_t limit); // max redirects to follow for a single request
|
||||
|
||||
bool setURL(const String& url); // handy for handling redirects
|
||||
void useHTTP10(bool usehttp10 = true);
|
||||
|
||||
@ -252,8 +273,7 @@ protected:
|
||||
int _returnCode = 0;
|
||||
int _size = -1;
|
||||
bool _canReuse = false;
|
||||
bool _followRedirects = false;
|
||||
uint16_t _redirectCount = 0;
|
||||
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
|
||||
uint16_t _redirectLimit = 10;
|
||||
String _location;
|
||||
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
|
||||
|
@ -186,12 +186,27 @@ void handleFileList() {
|
||||
Dir dir = filesystem->openDir(path);
|
||||
path.clear();
|
||||
|
||||
String output = "[";
|
||||
// use HTTP/1.1 Chunked response to avoid building a huge temporary string
|
||||
if (!server.chunkedResponseModeStart(200, "text/json")) {
|
||||
server.send(505, FPSTR("text/html"), FPSTR("HTTP1.1 required"));
|
||||
return;
|
||||
}
|
||||
|
||||
// use the same string for every line
|
||||
String output;
|
||||
output.reserve(64);
|
||||
while (dir.next()) {
|
||||
File entry = dir.openFile("r");
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
|
||||
if (output.length()) {
|
||||
// send string from previous iteration
|
||||
// as an HTTP chunk
|
||||
server.sendContent(output);
|
||||
output = ',';
|
||||
} else {
|
||||
output = '[';
|
||||
}
|
||||
|
||||
File entry = dir.openFile("r");
|
||||
bool isDir = false;
|
||||
output += "{\"type\":\"";
|
||||
output += (isDir) ? "dir" : "file";
|
||||
@ -205,8 +220,10 @@ void handleFileList() {
|
||||
entry.close();
|
||||
}
|
||||
|
||||
// send last string
|
||||
output += "]";
|
||||
server.send(200, "text/json", output);
|
||||
server.sendContent(output);
|
||||
server.chunkedResponseFinalize();
|
||||
}
|
||||
|
||||
void setup(void) {
|
||||
|
@ -149,18 +149,36 @@ public:
|
||||
void sendContent(const char *content) { sendContent_P(content); }
|
||||
void sendContent(const char *content, size_t size) { sendContent_P(content, size); }
|
||||
|
||||
bool chunkedResponseModeStart_P (int code, PGM_P content_type) {
|
||||
if (_currentVersion == 0)
|
||||
// no chunk mode in HTTP/1.0
|
||||
return false;
|
||||
setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
send_P(code, content_type, "");
|
||||
return true;
|
||||
}
|
||||
bool chunkedResponseModeStart (int code, const char* content_type) {
|
||||
return chunkedResponseModeStart_P(code, content_type);
|
||||
}
|
||||
bool chunkedResponseModeStart (int code, const String& content_type) {
|
||||
return chunkedResponseModeStart_P(code, content_type.c_str());
|
||||
}
|
||||
void chunkedResponseFinalize () {
|
||||
sendContent(emptyString);
|
||||
}
|
||||
|
||||
static String credentialHash(const String& username, const String& realm, const String& password);
|
||||
|
||||
static String urlDecode(const String& text);
|
||||
|
||||
// Handle a GET request by sending a response header and stream file content to response body
|
||||
// Handle a GET request by sending a response header and stream file content to response body
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType) {
|
||||
return streamFile(file, contentType, HTTP_GET);
|
||||
}
|
||||
|
||||
// Implement GET and HEAD requests for files.
|
||||
// Stream body on HTTP_GET but not on HTTP_HEAD requests.
|
||||
// Stream body on HTTP_GET but not on HTTP_HEAD requests.
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) {
|
||||
size_t contentLength = 0;
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
arduino IPv6 example
|
||||
released to public domain
|
||||
@ -27,7 +26,8 @@
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
#define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses
|
||||
#define FQDN F("www.google.com") // with both IPv4 & IPv6 addresses
|
||||
#define FQDN2 F("www.yahoo.com") // with both IPv4 & IPv6 addresses
|
||||
#define FQDN6 F("ipv6.google.com") // does not resolve in IPv4
|
||||
#define STATUSDELAY_MS 10000
|
||||
#define TCP_PORT 23
|
||||
@ -50,6 +50,21 @@ void fqdn(Print& out, const String& fqdn) {
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
void fqdn_rt(Print& out, const String& fqdn, DNSResolveType resolveType) {
|
||||
out.print(F("resolving "));
|
||||
out.print(fqdn);
|
||||
out.print(F(": "));
|
||||
IPAddress result;
|
||||
if (WiFi.hostByName(fqdn.c_str(), result, 10000, resolveType)) {
|
||||
result.printTo(out);
|
||||
out.println();
|
||||
} else {
|
||||
out.println(F("timeout or not found"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void status(Print& out) {
|
||||
out.println(F("------------------------------"));
|
||||
out.println(ESP.getFullVersion());
|
||||
@ -85,7 +100,10 @@ void status(Print& out) {
|
||||
// an example is provided with a fqdn which does not resolve with IPv4
|
||||
fqdn(out, FQDN);
|
||||
fqdn(out, FQDN6);
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
fqdn_rt(out, FQDN, DNSResolveType::DNS_AddrType_IPv4_IPv6); // IPv4 before IPv6
|
||||
fqdn_rt(out, FQDN2, DNSResolveType::DNS_AddrType_IPv6_IPv4); // IPv6 before IPv4
|
||||
#endif
|
||||
out.println(F("------------------------------"));
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ PublicKey KEYWORD1
|
||||
CertStoreSPIFFSBearSSL KEYWORD1
|
||||
CertStoreSDBearSSL KEYWORD1
|
||||
Session KEYWORD1
|
||||
ESP8266WiFiGratuitous KEYWORD1
|
||||
|
||||
|
||||
#######################################
|
||||
@ -108,6 +109,9 @@ psk KEYWORD2
|
||||
BSSID KEYWORD2
|
||||
BSSIDstr KEYWORD2
|
||||
RSSI KEYWORD2
|
||||
stationKeepAliveSetIntervalMs KEYWORD2
|
||||
stationKeepAliveStop KEYWORD2
|
||||
stationKeepAliveNow KEYWORD2
|
||||
enableInsecureWEP KEYWORD2
|
||||
getListenInterval KEYWORD2
|
||||
isSleepLevelMax KEYWORD2
|
||||
|
@ -870,9 +870,9 @@ uint32_t SigningVerifier::length()
|
||||
}
|
||||
}
|
||||
|
||||
bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) {
|
||||
if (!_pubKey || !hash || !signature || signatureLen != length()) return false;
|
||||
|
||||
// We need to use the 2nd stack to do a verification, so do the thunk
|
||||
// directly inside the class function for ease of use.
|
||||
extern "C" bool SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) {
|
||||
if (_pubKey->isRSA()) {
|
||||
bool ret;
|
||||
unsigned char vrf[hash->len()];
|
||||
@ -890,6 +890,20 @@ bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint
|
||||
}
|
||||
};
|
||||
|
||||
#if !CORE_MOCK
|
||||
make_stack_thunk(SigningVerifier_verify);
|
||||
extern "C" bool thunk_SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen);
|
||||
#endif
|
||||
|
||||
bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) {
|
||||
if (!_pubKey || !hash || !signature || signatureLen != length()) return false;
|
||||
#if !CORE_MOCK
|
||||
return thunk_SigningVerifier_verify(_pubKey, hash, signature, signatureLen);
|
||||
#else
|
||||
return SigningVerifier_verify(_pubKey, hash, signature, signatureLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !CORE_MOCK
|
||||
|
||||
// Second stack thunked helpers
|
||||
|
@ -608,7 +608,7 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
|
||||
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms)
|
||||
{
|
||||
ip_addr_t addr;
|
||||
aResult = static_cast<uint32_t>(0);
|
||||
aResult = static_cast<uint32_t>(INADDR_NONE);
|
||||
|
||||
if(aResult.fromString(aHostname)) {
|
||||
// Host name is a IP address use it!
|
||||
@ -617,7 +617,11 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
|
||||
}
|
||||
|
||||
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult,LWIP_DNS_ADDRTYPE_DEFAULT);
|
||||
#else
|
||||
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
|
||||
#endif
|
||||
if(err == ERR_OK) {
|
||||
aResult = IPAddress(&addr);
|
||||
} else if(err == ERR_INPROGRESS) {
|
||||
@ -640,6 +644,57 @@ int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResul
|
||||
return (err == ERR_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType)
|
||||
{
|
||||
ip_addr_t addr;
|
||||
err_t err;
|
||||
aResult = static_cast<uint32_t>(INADDR_NONE);
|
||||
|
||||
if(aResult.fromString(aHostname)) {
|
||||
// Host name is a IP address use it!
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname);
|
||||
switch(resolveType)
|
||||
{
|
||||
// Use selected addrtype
|
||||
case DNSResolveType::DNS_AddrType_IPv4:
|
||||
case DNSResolveType::DNS_AddrType_IPv6:
|
||||
case DNSResolveType::DNS_AddrType_IPv4_IPv6:
|
||||
case DNSResolveType::DNS_AddrType_IPv6_IPv4:
|
||||
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, (uint8_t) resolveType);
|
||||
break;
|
||||
default:
|
||||
err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, LWIP_DNS_ADDRTYPE_DEFAULT); // If illegal type, use default.
|
||||
break;
|
||||
}
|
||||
|
||||
if(err == ERR_OK) {
|
||||
aResult = IPAddress(&addr);
|
||||
} else if(err == ERR_INPROGRESS) {
|
||||
_dns_lookup_pending = true;
|
||||
delay(timeout_ms);
|
||||
// will resume on timeout or when wifi_dns_found_callback fires
|
||||
_dns_lookup_pending = false;
|
||||
// will return here when dns_found_callback fires
|
||||
if(aResult.isSet()) {
|
||||
err = ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if(err != 0) {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, (int)err);
|
||||
} else {
|
||||
DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str());
|
||||
}
|
||||
|
||||
return (err == ERR_OK) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DNS callback
|
||||
* @param name
|
||||
|
@ -42,6 +42,14 @@ typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
|
||||
|
||||
typedef void (*WiFiEventCb)(WiFiEvent_t);
|
||||
|
||||
enum class DNSResolveType: uint8_t
|
||||
{
|
||||
DNS_AddrType_IPv4 = 0, // LWIP_DNS_ADDRTYPE_IPV4 = 0
|
||||
DNS_AddrType_IPv6, // LWIP_DNS_ADDRTYPE_IPV6 = 1
|
||||
DNS_AddrType_IPv4_IPv6, // LWIP_DNS_ADDRTYPE_IPV4_IPV6 = 2
|
||||
DNS_AddrType_IPv6_IPv4 // LWIP_DNS_ADDRTYPE_IPV6_IPV4 = 3
|
||||
};
|
||||
|
||||
struct WiFiState;
|
||||
|
||||
class ESP8266WiFiGenericClass {
|
||||
@ -113,6 +121,9 @@ class ESP8266WiFiGenericClass {
|
||||
public:
|
||||
int hostByName(const char* aHostname, IPAddress& aResult);
|
||||
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms, DNSResolveType resolveType);
|
||||
#endif
|
||||
bool getPersistent();
|
||||
|
||||
protected:
|
||||
|
95
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp
Normal file
95
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
ESP8266WiFiGratuitous.cpp - esp8266 Wifi support
|
||||
copyright esp8266/arduino
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lwip/init.h" // LWIP_VERSION_*
|
||||
#if LWIP_VERSION_MAJOR == 1
|
||||
#include "netif/wlan_lwip_if.h" // eagle_lwip_getif()
|
||||
#include "netif/etharp.h" // gratuitous arp
|
||||
#include "user_interface.h"
|
||||
#else
|
||||
#include "lwip/etharp.h" // gratuitous arp
|
||||
#endif
|
||||
} // extern "C"
|
||||
|
||||
#include <Schedule.h>
|
||||
|
||||
#include "ESP8266WiFiGratuitous.h"
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
ETSTimer* ESP8266WiFiGratuitous::_timer = nullptr;
|
||||
|
||||
void ESP8266WiFiGratuitous::stationKeepAliveNow ()
|
||||
{
|
||||
for (netif* interface = netif_list; interface != nullptr; interface = interface->next)
|
||||
if (
|
||||
(interface->flags & NETIF_FLAG_LINK_UP)
|
||||
&& (interface->flags & NETIF_FLAG_UP)
|
||||
#if LWIP_VERSION_MAJOR == 1
|
||||
&& interface == eagle_lwip_getif(STATION_IF) /* lwip1 does not set if->num properly */
|
||||
&& (!ip_addr_isany(&interface->ip_addr))
|
||||
#else
|
||||
&& interface->num == STATION_IF
|
||||
&& (!ip4_addr_isany_val(*netif_ip4_addr(interface)))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
etharp_gratuitous(interface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WiFiGratuitous::scheduleItForNextYieldOnce (void*)
|
||||
{
|
||||
schedule_recurrent_function_us([]()
|
||||
{
|
||||
ESP8266WiFiGratuitous::stationKeepAliveNow();
|
||||
return false;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
bool ESP8266WiFiGratuitous::stationKeepAliveSetIntervalMs (uint32_t ms)
|
||||
{
|
||||
if (_timer)
|
||||
{
|
||||
os_timer_disarm(_timer);
|
||||
free(_timer);
|
||||
_timer = nullptr;
|
||||
}
|
||||
|
||||
if (ms)
|
||||
{
|
||||
// send one now
|
||||
stationKeepAliveNow();
|
||||
|
||||
_timer = (ETSTimer*)malloc(sizeof(ETSTimer));
|
||||
if (_timer == nullptr)
|
||||
return false;
|
||||
|
||||
os_timer_setfn(_timer, ESP8266WiFiGratuitous::scheduleItForNextYieldOnce, nullptr);
|
||||
os_timer_arm(_timer, ms, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // experimental::
|
54
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h
Normal file
54
libraries/ESP8266WiFi/src/ESP8266WiFiGratuitous.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
ESP8266WiFiGratuitous.h - esp8266 Wifi support
|
||||
copyright esp8266/arduino
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ESP8266WIFIGRATUITOUS_H_
|
||||
#define ESP8266WIFIGRATUITOUS_H_
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <ets_sys.h> // ETSTimer
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
class ESP8266WiFiGratuitous
|
||||
{
|
||||
public:
|
||||
|
||||
// disable(0) or enable/update automatic sending of Gratuitous ARP packets.
|
||||
// A gratuitous ARP packet is immediately sent when calling this function, then
|
||||
// based on a time interval in milliseconds, default = 1s
|
||||
// return value: true when started, false otherwise
|
||||
static bool stationKeepAliveSetIntervalMs (uint32_t ms = 1000);
|
||||
|
||||
// request for stopping arp gratuitous packets
|
||||
static void stationKeepAliveStop () { (void)stationKeepAliveSetIntervalMs(0); }
|
||||
|
||||
// immediately send one gratuitous ARP from STA
|
||||
static void stationKeepAliveNow ();
|
||||
|
||||
protected:
|
||||
|
||||
static void scheduleItForNextYieldOnce (void*);
|
||||
|
||||
static ETSTimer* _timer;
|
||||
};
|
||||
|
||||
}; // experimental::
|
||||
|
||||
#endif // ESP8266WIFIGRATUITOUS_H_
|
@ -89,7 +89,7 @@ static bool sta_config_equal(const station_config& lhs, const station_config& rh
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(lhs.threshold.rssi != rhs.threshold.rssi) {
|
||||
return false;
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ class ESP8266WiFiSTAClass {
|
||||
wl_status_t begin(const String& ssid, const String& passphrase = emptyString, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin();
|
||||
|
||||
//The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood
|
||||
//to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't
|
||||
//The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood
|
||||
//to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't
|
||||
//work here (see Arduino docs for gway/subnet defaults). In other words: at least 3 args must always be given.
|
||||
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
|
||||
|
||||
|
@ -127,8 +127,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int connect(CONST ip_addr_t* addr, uint16_t port)
|
||||
int connect(ip_addr_t* addr, uint16_t port)
|
||||
{
|
||||
#if LWIP_IPV6
|
||||
// Set zone so that link local addresses use the default interface
|
||||
if (IP_IS_V6(addr) && ip6_addr_lacks_zone(ip_2_ip6(addr), IP6_UNKNOWN)) {
|
||||
ip6_addr_assign_zone(ip_2_ip6(addr), IP6_UNKNOWN, netif_default);
|
||||
}
|
||||
#endif
|
||||
err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected);
|
||||
if (err != ERR_OK) {
|
||||
return 0;
|
||||
|
@ -114,6 +114,12 @@ public:
|
||||
{
|
||||
_pcb->remote_ip = addr;
|
||||
_pcb->remote_port = port;
|
||||
#if LWIP_IPV6
|
||||
// Set zone so that link local addresses use the default interface
|
||||
if (IP_IS_V6(&_pcb->remote_ip) && ip6_addr_lacks_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN)) {
|
||||
ip6_addr_assign_zone(ip_2_ip6(&_pcb->remote_ip), IP6_UNKNOWN, netif_default);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,12 @@ extern "C" uint32_t _FS_start;
|
||||
extern "C" uint32_t _FS_end;
|
||||
|
||||
ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
|
||||
: _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1)
|
||||
: _httpClientTimeout(8000), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout)
|
||||
: _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1)
|
||||
: _httpClientTimeout(httpClientTimeout), _followRedirects(HTTPC_DISABLE_FOLLOW_REDIRECTS), _ledPin(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,20 @@ public:
|
||||
_rebootOnUpdate = reboot;
|
||||
}
|
||||
|
||||
void followRedirects(bool follow)
|
||||
/**
|
||||
* set true to follow redirects.
|
||||
* @param follow
|
||||
* @deprecated Please use `setFollowRedirects(followRedirects_t follow)`
|
||||
*/
|
||||
void followRedirects(bool follow) __attribute__ ((deprecated))
|
||||
{
|
||||
_followRedirects = follow ? HTTPC_STRICT_FOLLOW_REDIRECTS : HTTPC_DISABLE_FOLLOW_REDIRECTS;
|
||||
}
|
||||
/**
|
||||
* set redirect follow mode. See `followRedirects_t` enum for avaliable modes.
|
||||
* @param follow
|
||||
*/
|
||||
void setFollowRedirects(followRedirects_t follow)
|
||||
{
|
||||
_followRedirects = follow;
|
||||
}
|
||||
@ -160,7 +173,7 @@ protected:
|
||||
bool _closeConnectionsOnUpdate = true;
|
||||
private:
|
||||
int _httpClientTimeout;
|
||||
bool _followRedirects;
|
||||
followRedirects_t _followRedirects;
|
||||
|
||||
// Callbacks
|
||||
HTTPUpdateStartCB _cbStart;
|
||||
|
@ -767,6 +767,12 @@ uint32_t MDNSResponder::queryService(const char* p_pcService,
|
||||
const char* p_pcProtocol,
|
||||
const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/)
|
||||
{
|
||||
if (0 == m_pUDPContext)
|
||||
{
|
||||
// safeguard against misuse
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol););
|
||||
|
||||
uint32_t u32Result = 0;
|
||||
|
Submodule libraries/SoftwareSerial updated: 94b2388a47...91ea6b1b1c
@ -35,30 +35,42 @@ public:
|
||||
typedef void (*callback_with_arg_t)(void*);
|
||||
typedef std::function<void(void)> callback_function_t;
|
||||
|
||||
// callback will be called at following loop() after ticker fires
|
||||
void attach_scheduled(float seconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = [callback]() { schedule_function(callback); };
|
||||
_attach_ms(1000UL * seconds, true);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
void attach(float seconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = std::move(callback);
|
||||
_attach_ms(1000UL * seconds, true);
|
||||
}
|
||||
|
||||
// callback will be called at following loop() after ticker fires
|
||||
void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = [callback]() { schedule_function(callback); };
|
||||
_attach_ms(milliseconds, true);
|
||||
}
|
||||
|
||||
// callback will be called at following yield() after ticker fires
|
||||
void attach_ms_scheduled_accurate(uint32_t milliseconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = [callback]() { schedule_recurrent_function_us([callback]() { callback(); return false; }, 0); };
|
||||
_attach_ms(milliseconds, true);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
void attach_ms(uint32_t milliseconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = std::move(callback);
|
||||
_attach_ms(milliseconds, true);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
template<typename TArg>
|
||||
void attach(float seconds, void (*callback)(TArg), TArg arg)
|
||||
{
|
||||
@ -66,6 +78,7 @@ public:
|
||||
_attach_ms(1000UL * seconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
template<typename TArg>
|
||||
void attach_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
|
||||
{
|
||||
@ -73,30 +86,35 @@ public:
|
||||
_attach_ms(milliseconds, true, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
|
||||
}
|
||||
|
||||
// callback will be called at following loop() after ticker fires
|
||||
void once_scheduled(float seconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = [callback]() { schedule_function(callback); };
|
||||
_attach_ms(1000UL * seconds, false);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
void once(float seconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = std::move(callback);
|
||||
_attach_ms(1000UL * seconds, false);
|
||||
}
|
||||
|
||||
// callback will be called at following loop() after ticker fires
|
||||
void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = [callback]() { schedule_function(callback); };
|
||||
_attach_ms(milliseconds, false);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
void once_ms(uint32_t milliseconds, callback_function_t callback)
|
||||
{
|
||||
_callback_function = std::move(callback);
|
||||
_attach_ms(milliseconds, false);
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
template<typename TArg>
|
||||
void once(float seconds, void (*callback)(TArg), TArg arg)
|
||||
{
|
||||
@ -104,6 +122,7 @@ public:
|
||||
_attach_ms(1000UL * seconds, false, reinterpret_cast<callback_with_arg_t>(callback), reinterpret_cast<void*>(arg));
|
||||
}
|
||||
|
||||
// callback will be called in SYS ctx when ticker fires
|
||||
template<typename TArg>
|
||||
void once_ms(uint32_t milliseconds, void (*callback)(TArg), TArg arg)
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ void showTime() {
|
||||
Serial.println((uint32_t)now);
|
||||
|
||||
// timezone and demo in the future
|
||||
Serial.printf("timezone: %s\n", getenv("TZ"));
|
||||
Serial.printf("timezone: %s\n", getenv("TZ") ? : "(none)");
|
||||
|
||||
// human readable
|
||||
Serial.print("ctime: ");
|
||||
|
Reference in New Issue
Block a user