Compare commits
@@ -57,7 +57,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3]
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
BUILD_PARITY: custom
|
||||
mod: 4
|
||||
mod: 6
|
||||
rem: ${{ matrix.chunk }}
|
||||
run: |
|
||||
cd pico-sdk
|
||||
|
||||
+3
-1
@@ -50,7 +50,9 @@ enum SeekMode {
|
||||
|
||||
class File : public Stream {
|
||||
public:
|
||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }
|
||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
|
||||
_startMillis = millis(); /* workaround -O3 spurious warning #768 */
|
||||
}
|
||||
|
||||
// Print methods:
|
||||
size_t write(uint8_t) override;
|
||||
|
||||
@@ -314,7 +314,10 @@ public:
|
||||
}
|
||||
|
||||
void reboot() {
|
||||
watchdog_reboot(0, 0, 100);
|
||||
watchdog_reboot(0, 0, 10);
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
inline void restart() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 2
|
||||
#define ARDUINO_PICO_MINOR 4
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "2.4.0"
|
||||
#define ARDUINO_PICO_REVISION 1
|
||||
#define ARDUINO_PICO_VERSION_STR "2.4.1"
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#define CYW43_WL_GPIO_LED_PIN 0
|
||||
#endif
|
||||
|
||||
|
||||
volatile bool __inLWIP = false;
|
||||
|
||||
// note same code
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'2.4.0'
|
||||
version = u'2.4.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'2.4.0'
|
||||
release = u'2.4.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+11
-1
@@ -98,9 +98,19 @@ The included ``SD`` library is the Arduino standard one. Please refer to
|
||||
the [Arduino SD reference](https://www.arduino.cc/en/reference/SD) for
|
||||
more information.
|
||||
|
||||
Using Second SPI port for SD
|
||||
----------------------------
|
||||
The ``SD`` library ``begin()`` has been modified to allow you to use the
|
||||
second SPI port, ``SPI1``. Just use the following call in place of
|
||||
``SD.begin(cspin)``
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
SD.begin(cspin, SPI1);
|
||||
|
||||
|
||||
File system object (LittleFS/SD/SDFS)
|
||||
--------------------------------------------
|
||||
-------------------------------------
|
||||
|
||||
setConfig
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
HTTPClient Library
|
||||
==================
|
||||
|
||||
A simple HTTP requestor that can handle both HTTP and HTTP requests is
|
||||
included as the ``HTTPClient`` library.
|
||||
|
||||
Check the examples for use under HTTP and HTTPS configurations. In general,
|
||||
for HTTP connections (unsecured and very uncommon on the internet today) simply
|
||||
passing in a URL and performiung a GET is sufficient to transfer data.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// Error checking is left as an exercise for the reader...
|
||||
HTTPClient http;
|
||||
if (http.begin("http://my.server/url")) {
|
||||
if (http.GET() > 0) {
|
||||
String data = http.getString();
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
|
||||
For HTTPS connections, simply add the appropriate WiFiClientSecure calls
|
||||
as needed (i.e. ``setInsecure()``, ``setTrustAnchor``, etc.). See the
|
||||
WiFiClientSecure documentation for more details.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// Error checking is left as an exercise for the reader...
|
||||
HTTPClient https;
|
||||
https.setInsecure(); // Use certs, but do not check their authenticity
|
||||
if (https.begin("https://my.secure.server/url")) {
|
||||
if (http.GET() > 0) {
|
||||
String data = http.getString();
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
|
||||
Unlike the ESP8266 and ESP32 ``HTTPClient`` implementations it is not necessary
|
||||
to create a ``WiFiClient`` or ``WiFiClientSecure`` to pass in to the ``HTTPClient``
|
||||
object.
|
||||
+1
-1
@@ -38,7 +38,7 @@ for normal operations.
|
||||
Generic RP2040 Support
|
||||
----------------------
|
||||
If your RP2040 board isn't in the menus you can still use it with the
|
||||
IDE bu using the `Board->Generic RP2040` menu option. You will need to
|
||||
IDE by using the `Board->Generic RP2040` menu option. You will need to
|
||||
then set the flash size (see above) and tell the IDE how to communicate
|
||||
with the flash chip using the `Tools->Boot Stage 2` menu.
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
WiFiClientSecure (TLS/SSL/HTTPS) <bearssl-client-secure-class>
|
||||
WiFiServerSecure (TLS/SSL/HTTPS) <bearssl-server-secure-class>
|
||||
|
||||
HTTP/HTTPS Client <httpclient>
|
||||
|
||||
Over-the-Air (OTA) Updates <ota>
|
||||
|
||||
Ported/Optimized Libraries <libraries>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ The Arduino-Pico core can be installed using the Arduino IDE Boards Manager
|
||||
or using `git`. If you want to simply write programs for your RP2040 board,
|
||||
the Boards Manager installation will suffice, but if you want to try the
|
||||
latest pre-release versions and submit improvements, you will need the `git`
|
||||
instllation.
|
||||
installation.
|
||||
|
||||
Installing via Arduino Boards Manager
|
||||
-------------------------------------
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ A firmware file is uploaded via any method (Ethernet, WiFi, serial ZModem, etc.)
|
||||
|
||||
The ROM layout consists of:
|
||||
|
||||
... code:
|
||||
.. code:: cpp
|
||||
|
||||
[boot2.S] [OTA Bootloader] [0-pad] [OTA partition table] [Main sketch] [LittleFS filesystem] [EEPROM]
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
WiFi (Raspberry Pi Pico W) Support
|
||||
==================================
|
||||
|
||||
WiFi is supported on the Raspberry Pi Pico W by selecting the "Raspbery Pi Pico W" board in the Boards Manager. It is generally compatible with the `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ and the `ESP8266 Arduino WiFi library <https://github.com/esp8266/Arduino>`__.
|
||||
WiFi is supported on the Raspberry Pi Pico W by selecting the "Raspberry Pi Pico W" board in the Boards Manager. It is generally compatible with the `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ and the `ESP8266 Arduino WiFi library <https://github.com/esp8266/Arduino>`__.
|
||||
|
||||
Enable WiFi support by selecting the `Raspberry Pi Pico W` board in the IDE and adding ``#include <WiFi.h>`` in your sketch.
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
Arduino KEYWORD3 RESERVED_WORD
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
@@ -243,6 +243,19 @@ void ArduinoOTAClass::_onRx() {
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
IPAddress ota_ip = _ota_ip;
|
||||
|
||||
if (!LittleFS.begin()) {
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.println("LittleFS Begin Error");
|
||||
#endif
|
||||
_udp_ota->append("ERR: ", 5);
|
||||
_udp_ota->append("No Filesystem", 13);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
delay(100);
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.println("Update Begin Error");
|
||||
@@ -261,15 +274,6 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
if (!LittleFS.begin()) {
|
||||
_udp_ota->append("ERR: ", 5);
|
||||
_udp_ota->append("nofilesystem", 6);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
delay(100);
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
_udp_ota->append("OK", 2);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For DNSServer
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
DNSServer KEYWORD3 RESERVED_WORD
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
DNSReplyCode KEYWORD1 DATA_TYPE
|
||||
DNSHeader KEYWORD1 DATA_TYPE
|
||||
DNSServer KEYWORD1 DATA_TYPE
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
processNextRequest KEYWORD2
|
||||
setErrorReplyCode KEYWORD2
|
||||
setTTL KEYWORD2
|
||||
start KEYWORD2
|
||||
stop KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
DNS_QR_QUERY LITERAL1 RESERVED_WORD_2
|
||||
DNS_QR_RESPONSE LITERAL1 RESERVED_WORD_2
|
||||
DNS_OPCODE_QUERY LITERAL1 RESERVED_WORD_2
|
||||
MAX_DNSNAME_LENGTH LITERAL1 RESERVED_WORD_2
|
||||
NoError LITERAL1 RESERVED_WORD_2
|
||||
FormError LITERAL1 RESERVED_WORD_2
|
||||
ServerFailure LITERAL1 RESERVED_WORD_2
|
||||
NonExistentDomain LITERAL1 RESERVED_WORD_2
|
||||
NotImplemented LITERAL1 RESERVED_WORD_2
|
||||
Refused LITERAL1 RESERVED_WORD_2
|
||||
YXDomain LITERAL1 RESERVED_WORD_2
|
||||
YXRRSet LITERAL1 RESERVED_WORD_2
|
||||
NXRRSet LITERAL1 RESERVED_WORD_2
|
||||
@@ -0,0 +1,10 @@
|
||||
name=DNSServer
|
||||
version=1.1.1
|
||||
author=Kristijan Novoselić
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=A simple DNS server for ESP8266, ported to the Pico
|
||||
paragraph=This library implements a simple DNS server.
|
||||
category=Communication
|
||||
url=
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
@@ -0,0 +1,447 @@
|
||||
#include "WiFi.h"
|
||||
#include "DNSServer.h"
|
||||
#include <lwip/def.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
extern struct rst_info resetInfo;
|
||||
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define CONSOLE DEBUG_ESP_PORT
|
||||
#else
|
||||
#define CONSOLE Serial
|
||||
#endif
|
||||
|
||||
#define _PRINTF(a, ...) printf(PSTR(a), ##__VA_ARGS__)
|
||||
#define _PRINT(a) print(String(F(a)))
|
||||
#define _PRINTLN(a) println(String(F(a)))
|
||||
#define _PRINTLN2(a, b) println(String(F(a)) + b )
|
||||
|
||||
#define CONSOLE_PRINTF CONSOLE._PRINTF
|
||||
#define CONSOLE_PRINT CONSOLE._PRINT
|
||||
#define CONSOLE_PRINTLN CONSOLE._PRINTLN
|
||||
#define CONSOLE_PRINTLN2 CONSOLE._PRINTLN2
|
||||
|
||||
|
||||
#ifdef DEBUG_DNSSERVER
|
||||
#define DEBUG_PRINTF CONSOLE_PRINTF
|
||||
#define DEBUG_PRINT CONSOLE_PRINT
|
||||
#define DEBUG_PRINTLN CONSOLE_PRINTLN
|
||||
#define DEBUG_PRINTLN2 CONSOLE_PRINTLN2
|
||||
#define DBGLOG_FAIL LOG_FAIL
|
||||
|
||||
#define DEBUG_(...) do { (__VA_ARGS__); } while(false)
|
||||
#define DEBUG__(...) __VA_ARGS__
|
||||
#define LOG_FAIL(a, fmt, ...) do { if (!(a)) { CONSOLE.printf( PSTR(fmt " line: %d, function: %s\r\n"), ##__VA_ARGS__, __LINE__, __FUNCTION__ ); } } while(false);
|
||||
|
||||
#else
|
||||
#define DEBUG_PRINTF(...) do { } while(false)
|
||||
#define DEBUG_PRINT(...) do { } while(false)
|
||||
#define DEBUG_PRINTLN(...) do { } while(false)
|
||||
#define DEBUG_PRINTLN2(...) do { } while(false)
|
||||
#define DEBUG_(...) do { } while(false)
|
||||
#define DEBUG__(...) do { } while(false)
|
||||
#define LOG_FAIL(a, ...) do { a; } while(false)
|
||||
#define DBGLOG_FAIL(...) do { } while(false)
|
||||
#endif
|
||||
|
||||
#define DNS_HEADER_SIZE sizeof(DNSHeader)
|
||||
|
||||
// Want to keep IDs unique across restarts and continquious
|
||||
static uint32_t _ids __attribute__((section(".noinit")));
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
// I have observed that using 0 for captive and non-zero (600) when
|
||||
// forwarding, will help Android devices recognize the change in connectivity.
|
||||
// They will then report connected.
|
||||
_ttl = lwip_htonl(60);
|
||||
|
||||
srand(rp2040.getCycleCount());
|
||||
_ids = random(0, (1UL << 16) - 1);
|
||||
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
}
|
||||
|
||||
void DNSServer::disableForwarder(const String &domainName, bool freeResources)
|
||||
{
|
||||
_forwarder = false;
|
||||
if (domainName != "") {
|
||||
_domainName = domainName;
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
}
|
||||
if (freeResources) {
|
||||
_dns = (uint32_t)0;
|
||||
if (_que) {
|
||||
_que = nullptr;
|
||||
DEBUG_PRINTF("from stop, deleted _que\r\n");
|
||||
DEBUG_(({
|
||||
if (_que_ov) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que overflow or no reply to request: ", (_que_ov));
|
||||
}
|
||||
if (_que_drop) {
|
||||
DEBUG_PRINTLN2("DNS forwarder que wrapped, reply dropped: ", (_que_drop));
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DNSServer::enableForwarder(const String &domainName, const IPAddress &dns)
|
||||
{
|
||||
disableForwarder(domainName, false); // Just happens to have the same logic needed here.
|
||||
|
||||
if (dns.isSet()) {
|
||||
_dns = dns;
|
||||
}
|
||||
|
||||
if (_dns.isSet()) {
|
||||
if (!_que) {
|
||||
_que = std::unique_ptr<DNSS_REQUESTER[]> (new (std::nothrow) DNSS_REQUESTER[kDNSSQueSize]);
|
||||
DEBUG_PRINTF("Created new _que\r\n");
|
||||
if (_que) {
|
||||
for (size_t i = 0; i < kDNSSQueSize; i++) {
|
||||
_que[i].ip = 0;
|
||||
}
|
||||
DEBUG_((_que_ov = 0));
|
||||
DEBUG_((_que_drop = 0));
|
||||
}
|
||||
}
|
||||
if (_que) {
|
||||
_forwarder = true;
|
||||
}
|
||||
}
|
||||
return _forwarder;
|
||||
}
|
||||
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName,
|
||||
const IPAddress &resolvedIP, const IPAddress &dns)
|
||||
{
|
||||
_port = (port) ? port : IANA_DNS_PORT;
|
||||
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
|
||||
if (!enableForwarder(domainName, dns) && (dns.isSet() || _dns.isSet())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _udp.begin(_port) == 1;
|
||||
}
|
||||
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
|
||||
{
|
||||
_errorReplyCode = replyCode;
|
||||
}
|
||||
|
||||
void DNSServer::setTTL(const uint32_t &ttl)
|
||||
{
|
||||
_ttl = lwip_htonl(ttl);
|
||||
}
|
||||
|
||||
uint32_t DNSServer::getTTL()
|
||||
{
|
||||
return lwip_ntohl(_ttl);
|
||||
}
|
||||
|
||||
void DNSServer::stop()
|
||||
{
|
||||
_udp.stop();
|
||||
disableForwarder("", true);
|
||||
}
|
||||
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||
{
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www."))
|
||||
domainName.remove(0, 4);
|
||||
}
|
||||
|
||||
void DNSServer::forwardReply(uint8_t *buffer, size_t length)
|
||||
{
|
||||
if (!_forwarder || !_que) {
|
||||
return;
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
uint16_t id = dnsHeader->ID;
|
||||
// if (kDNSSQueSize <= (uint16_t)((uint16_t)_ids - id)) {
|
||||
if ((uint16_t)kDNSSQueSize <= (uint16_t)_ids - id) {
|
||||
DEBUG_((++_que_drop));
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" dropped!")));
|
||||
return;
|
||||
}
|
||||
size_t i = id & (kDNSSQueSize - 1);
|
||||
|
||||
// Drop duplicate packets
|
||||
if (0 == _que[i].ip) {
|
||||
DEBUG_PRINTLN2("Duplicate reply dropped ID: 0x", String(id, HEX));
|
||||
return;
|
||||
}
|
||||
dnsHeader->ID = _que[i].id;
|
||||
_udp.beginPacket(_que[i].ip, _que[i].port);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward reply ID: 0x", (String(id, HEX) + F(" to ") + IPAddress(_que[i].ip).toString()));
|
||||
_que[i].ip = 0; // This gets used to detect duplicate packets and overflow
|
||||
}
|
||||
|
||||
void DNSServer::forwardRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
if (!_forwarder || !_dns.isSet() || !_que) {
|
||||
return;
|
||||
}
|
||||
DNSHeader *dnsHeader = (DNSHeader *)buffer;
|
||||
++_ids;
|
||||
size_t i = _ids & (kDNSSQueSize - 1);
|
||||
DEBUG_(({
|
||||
if (0 != _que[i].ip) {
|
||||
++_que_ov;
|
||||
}
|
||||
}));
|
||||
_que[i].ip = _udp.remoteIP();
|
||||
_que[i].port = _udp.remotePort();
|
||||
_que[i].id = dnsHeader->ID;
|
||||
dnsHeader->ID = (uint16_t)_ids;
|
||||
_udp.beginPacket(_dns, IANA_DNS_PORT);
|
||||
_udp.write(buffer, length);
|
||||
_udp.endPacket();
|
||||
DEBUG_PRINTLN2("Forward request ID: 0x", (String(dnsHeader->ID, HEX) + F(" to ") + _dns.toString()));
|
||||
}
|
||||
|
||||
bool DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
DNSHeader *dnsHeader;
|
||||
uint8_t *query, *start;
|
||||
const char *matchString;
|
||||
size_t remaining, labelLength, queryLength;
|
||||
uint16_t qtype, qclass;
|
||||
|
||||
dnsHeader = (DNSHeader *)buffer;
|
||||
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0) {
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
return false;
|
||||
}
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
memcpy(&qtype, start, sizeof(qtype));
|
||||
start += 2;
|
||||
memcpy(&qclass, start, sizeof(qclass));
|
||||
start += 2;
|
||||
|
||||
queryLength = start - query;
|
||||
|
||||
if (qclass != lwip_htons(DNS_QCLASS_ANY)
|
||||
&& qclass != lwip_htons(DNS_QCLASS_IN)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qtype != lwip_htons(DNS_QTYPE_A)
|
||||
&& qtype != lwip_htons(DNS_QTYPE_ANY)) {
|
||||
replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have no domain name configured, just return an error
|
||||
if (_domainName == "") {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*") {
|
||||
DEBUG_PRINTF("dnsServer - replyWithIP\r\n");
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
start = query;
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
|
||||
start += 4;
|
||||
|
||||
while (*start != 0) {
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0) {
|
||||
if (tolower(*start) != *matchString) {
|
||||
if (_forwarder) {
|
||||
return true;
|
||||
} else {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++start;
|
||||
++matchString;
|
||||
--labelLength;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0') {
|
||||
replyWithIP(dnsHeader, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*matchString != '.') {
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
++matchString;
|
||||
}
|
||||
|
||||
replyWithError(dnsHeader, _errorReplyCode, query, queryLength);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DNSServer::processNextRequest()
|
||||
{
|
||||
size_t currentPacketSize;
|
||||
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0)
|
||||
return;
|
||||
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE)
|
||||
return;
|
||||
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE)
|
||||
return;
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
if (buffer == nullptr)
|
||||
return;
|
||||
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
if (_dns.isSet() && _udp.remoteIP() == _dns) {
|
||||
// _forwarder may have been set to false; however, for now allow in-flight
|
||||
// replies to finish. //??
|
||||
forwardReply(buffer.get(), currentPacketSize);
|
||||
} else
|
||||
if (respondToRequest(buffer.get(), currentPacketSize)) {
|
||||
forwardRequest(buffer.get(), currentPacketSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DNSServer::writeNBOShort(uint16_t value)
|
||||
{
|
||||
_udp.write((unsigned char *)&value, 2);
|
||||
}
|
||||
|
||||
void DNSServer::replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
dnsHeader->ANCount = lwip_htons(1);
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
|
||||
_udp.write(query, queryLength);
|
||||
|
||||
// Rather than restate the name here, we use a pointer to the name contained
|
||||
// in the query section. Pointers have the top two bits set.
|
||||
value = 0xC000 | DNS_HEADER_SIZE;
|
||||
writeNBOShort(lwip_htons(value));
|
||||
|
||||
// Answer is type A (an IPv4 address)
|
||||
writeNBOShort(lwip_htons(DNS_QTYPE_A));
|
||||
|
||||
// Answer is in the Internet Class
|
||||
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
|
||||
|
||||
// Output TTL (already NBO)
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength)
|
||||
{
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query)
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
else
|
||||
dnsHeader->QDCount = 0;
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != NULL)
|
||||
_udp.write(query, queryLength);
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode)
|
||||
{
|
||||
replyWithError(dnsHeader, rcode, NULL, 0);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
#ifndef DNSServer_h
|
||||
#define DNSServer_h
|
||||
|
||||
#include <memory>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
// #define DEBUG_DNSSERVER
|
||||
|
||||
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
|
||||
#ifndef IANA_DNS_PORT
|
||||
#define IANA_DNS_PORT 53 // AKA domain
|
||||
constexpr inline uint16_t kIanaDnsPort = IANA_DNS_PORT;
|
||||
#endif
|
||||
|
||||
#define DNS_QR_QUERY 0
|
||||
#define DNS_QR_RESPONSE 1
|
||||
#define DNS_OPCODE_QUERY 0
|
||||
|
||||
#define DNS_QCLASS_IN 1
|
||||
#define DNS_QCLASS_ANY 255
|
||||
|
||||
#define DNS_QTYPE_A 1
|
||||
#define DNS_QTYPE_ANY 255
|
||||
|
||||
#define MAX_DNSNAME_LENGTH 253
|
||||
#define MAX_DNS_PACKETSIZE 512
|
||||
|
||||
enum class DNSReplyCode
|
||||
{
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
};
|
||||
|
||||
struct DNSHeader
|
||||
{
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritative answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
};
|
||||
|
||||
constexpr inline size_t kDNSSQueSizeAddrBits = 3; // The number of bits used to address que entries
|
||||
constexpr inline size_t kDNSSQueSize = (1UL << (kDNSSQueSizeAddrBits));
|
||||
|
||||
struct DNSS_REQUESTER {
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
uint16_t id;
|
||||
};
|
||||
|
||||
class DNSServer
|
||||
{
|
||||
public:
|
||||
DNSServer();
|
||||
~DNSServer() {
|
||||
stop();
|
||||
};
|
||||
/*
|
||||
If specified, `enableForwarder` will update the `domainName` that is used
|
||||
to match DNS request to this AP's IP Address. A non-matching request will
|
||||
be forwarded to the DNS server specified by `dns`.
|
||||
|
||||
Returns `true` on success.
|
||||
|
||||
Returns `false`,
|
||||
* when forwarding `dns` is not set, or
|
||||
* unable to allocate resources for managing the DNS forward function.
|
||||
*/
|
||||
bool enableForwarder(const String &domainName = String(""), const IPAddress &dns = (uint32_t)0);
|
||||
/*
|
||||
`disableForwarder` will stop forwarding DNS requests. If specified,
|
||||
updates the `domainName` that is matched for returning this AP's IP Address.
|
||||
Optionally, resources used for the DNS forward function can be freed.
|
||||
*/
|
||||
void disableForwarder(const String &domainName = String(""), bool freeResources = false);
|
||||
bool isForwarding() { return _forwarder && _dns.isSet(); }
|
||||
void setDNS(const IPAddress& dns) { _dns = dns; }
|
||||
IPAddress getDNS() { return _dns; }
|
||||
bool isDNSSet() { return _dns.isSet(); }
|
||||
|
||||
void processNextRequest();
|
||||
void setErrorReplyCode(const DNSReplyCode &replyCode);
|
||||
void setTTL(const uint32_t &ttl);
|
||||
uint32_t getTTL();
|
||||
String getDomainName() { return _domainName; }
|
||||
|
||||
// Returns true if successful, false if there are no sockets available
|
||||
bool start(const uint16_t &port,
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP,
|
||||
const IPAddress &dns = (uint32_t)0);
|
||||
// stops the DNS server
|
||||
void stop();
|
||||
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
String _domainName;
|
||||
IPAddress _dns;
|
||||
std::unique_ptr<DNSS_REQUESTER[]> _que;
|
||||
uint32_t _ttl;
|
||||
#ifdef DEBUG_DNSSERVER
|
||||
// There are 2 possibilities for overflow:
|
||||
// 1) we have more than kDNSSQueSize request already outstanding.
|
||||
// 2) we have request that never received a reply.
|
||||
uint32_t _que_ov;
|
||||
uint32_t _que_drop;
|
||||
#endif
|
||||
DNSReplyCode _errorReplyCode;
|
||||
bool _forwarder;
|
||||
unsigned char _resolvedIP[4];
|
||||
uint16_t _port;
|
||||
|
||||
void downcaseAndRemoveWwwPrefix(String &domainName);
|
||||
void replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode);
|
||||
bool respondToRequest(uint8_t *buffer, size_t length);
|
||||
void forwardRequest(uint8_t *buffer, size_t length);
|
||||
void forwardReply(uint8_t *buffer, size_t length);
|
||||
void writeNBOShort(uint16_t value);
|
||||
};
|
||||
#endif
|
||||
@@ -62,6 +62,10 @@ public:
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T &update(int const address, const T &t) {
|
||||
return put(address, t);
|
||||
}
|
||||
size_t length() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
Authorization.ino
|
||||
|
||||
Created on: 09.12.2015
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
HTTPClient http;
|
||||
http.setInsecure();
|
||||
|
||||
Serial.print("[HTTP] begin...\n");
|
||||
// configure traged server and url
|
||||
|
||||
|
||||
http.begin("https://guest:guest@jigsaw.w3.org/HTTP/Basic/");
|
||||
|
||||
/*
|
||||
// or
|
||||
http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
|
||||
http.setAuthorization("guest", "guest");
|
||||
|
||||
// or
|
||||
http.begin(client, "http://jigsaw.w3.org/HTTP/Basic/");
|
||||
http.setAuthorization("Z3Vlc3Q6Z3Vlc3Q=");
|
||||
*/
|
||||
|
||||
|
||||
Serial.print("[HTTP] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = http.GET();
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
String payload = http.getString();
|
||||
Serial.println(payload);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
}
|
||||
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
BasicHTTPClient.ino
|
||||
|
||||
Created on: 24.05.2015
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
Serial.print("[HTTP] begin...\n");
|
||||
if (http.begin("http://httpbin.org")) { // HTTP
|
||||
|
||||
|
||||
Serial.print("[HTTP] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = http.GET();
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||
String payload = http.getString();
|
||||
Serial.println(payload);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
} else {
|
||||
Serial.printf("[HTTP} Unable to connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
BasicHTTPSClient-Hard.ino
|
||||
|
||||
Demonstrates the manual way of making a WiFiClient and passing it in to the HTTPClient
|
||||
|
||||
Created on: 20.08.2018
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure(); // Not safe against MITM attacks
|
||||
|
||||
HTTPClient https;
|
||||
|
||||
Serial.print("[HTTPS] begin...\n");
|
||||
if (https.begin(client, "https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS
|
||||
|
||||
Serial.print("[HTTPS] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = https.GET();
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||
String payload = https.getString();
|
||||
Serial.println(payload);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
https.end();
|
||||
} else {
|
||||
Serial.printf("[HTTPS] Unable to connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Wait 10s before next round...");
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
BasicHTTPSClient.ino
|
||||
|
||||
Created on: 20.08.2018
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
const char *jigsaw_cert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFKTCCBM+gAwIBAgIQAbTKhAICxb7iDJbE6qU/NzAKBggqhkjOPQQDAjBKMQsw
|
||||
CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
|
||||
Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjIwMzE3MDAwMDAwWhcNMjMwMzE2
|
||||
MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
|
||||
A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe
|
||||
MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI
|
||||
zj0DAQcDQgAEYnkGDyrIltjRnxoVdy/xgndo+WGMOASzs2hHeCjbJ1KplKJc/ciK
|
||||
XCWq/4+pTzSiVgTFhRmCdLcU1Fa05YFNQaOCA2owggNmMB8GA1UdIwQYMBaAFKXO
|
||||
N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBRIzOWGCDBB/PMrMucSrjIKqlgE
|
||||
uDAvBgNVHREEKDAmghVzbmkuY2xvdWRmbGFyZXNzbC5jb22CDWppZ3Nhdy53My5v
|
||||
cmcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||
AjB7BgNVHR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vQ2xv
|
||||
dWRmbGFyZUluY0VDQ0NBLTMuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2Vy
|
||||
dC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3JsMD4GA1UdIAQ3MDUwMwYGZ4EM
|
||||
AQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzB2
|
||||
BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0
|
||||
LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Ns
|
||||
b3VkZmxhcmVJbmNFQ0NDQS0zLmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHW
|
||||
eQIEAgSCAW8EggFrAWkAdQDoPtDaPvUGNTLnVyi8iWvJA9PL0RFr7Otp4Xd9bQa9
|
||||
bgAAAX+aFPh6AAAEAwBGMEQCICivjuh2ywUYvVpTKHo65JEheR8dFq8QvBgEiXfw
|
||||
m6q6AiAkxAgz77oboGQGetNmab45+peY+nAGOfyW9vi9S1gMaAB3ADXPGRu/sWxX
|
||||
vw+tTG1Cy7u2JyAmUeo/4SrvqAPDO9ZMAAABf5oU+GEAAAQDAEgwRgIhANKeTNMy
|
||||
GqUsCo7ph7YMWzrhMuDeyP8xPSiCtFzKcn/eAiEAyv5lgCUQ6K14V13zYfL99wZD
|
||||
LFcIP/KZ1y7nuPAksTAAdwCzc3cH4YRQ+GOG1gWp3BEJSnktsWcMC4fc8AMOeTal
|
||||
mgAAAX+aFPiWAAAEAwBIMEYCIQD6535jWw776D4vjyupP2fBw26CBMpVT5++k4rR
|
||||
xqeOXwIhAIbEaEKkEq6JtpWWfVpTyDkMpMfTuiqYVe6REy2XsmEhMAoGCCqGSM49
|
||||
BAMCA0gAMEUCIH3r/puXZcX1bfUoBq2njuHe0bxWtvzDaz5k6WLYrazTAiEA+ePL
|
||||
N6K5xrmaof185pVCxACPLc/BoKyUwMeC8iXCm00=
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
static int cnt = 0;
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
HTTPClient https;
|
||||
switch (cnt) {
|
||||
case 0:
|
||||
Serial.println("[HTTPS] using insecure SSL, not validating certificate");
|
||||
https.setInsecure(); // Note this is unsafe against MITM attacks
|
||||
cnt++;
|
||||
break;
|
||||
case 1:
|
||||
Serial.println("[HTTPS] using secure SSL, validating certificate");
|
||||
https.setCACert(jigsaw_cert);
|
||||
cnt++;
|
||||
break;
|
||||
default:
|
||||
Serial.println("[HTTPS] not setting any SSL verification settings, will fail");
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
Serial.print("[HTTPS] begin...\n");
|
||||
if (https.begin("https://jigsaw.w3.org/HTTP/connection.html")) { // HTTPS
|
||||
|
||||
Serial.print("[HTTPS] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = https.GET();
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||
String payload = https.getString();
|
||||
Serial.println(payload);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
https.end();
|
||||
} else {
|
||||
Serial.printf("[HTTPS] Unable to connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Wait 10s before next round...");
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
ChunkedClient.ino
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
HTTPClient http;
|
||||
|
||||
Serial.print("[HTTP] begin...\n");
|
||||
if (http.begin("http://anglesharp.azurewebsites.net/Chunked")) {
|
||||
|
||||
Serial.print("[HTTP] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = http.GET();
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
|
||||
String payload = http.getString();
|
||||
Serial.println(payload);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
} else {
|
||||
Serial.printf("[HTTP] Unable to connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Wait forever...");
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
This sketch shows how to handle HTTP Digest Authorization.
|
||||
|
||||
Written by Parham Alvani and Sajjad Rahnama, 2018-01-07.
|
||||
|
||||
This example is released into public domain,
|
||||
or, at your option, CC0 licensed.
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "NOBABIES"
|
||||
#define STAPSK "ElephantsAreGreat"
|
||||
#endif
|
||||
|
||||
const char* ssid = STASSID;
|
||||
const char* ssidPassword = STAPSK;
|
||||
|
||||
const char* username = "admin";
|
||||
const char* password = "admin";
|
||||
|
||||
const char* server = "http://httpbin.org";
|
||||
const char* uri = "/digest-auth/auth/admin/admin/MD5";
|
||||
|
||||
String exractParam(String& authReq, const String& param, const char delimit) {
|
||||
int _begin = authReq.indexOf(param);
|
||||
if (_begin == -1) {
|
||||
return "";
|
||||
}
|
||||
return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
|
||||
}
|
||||
|
||||
String getCNonce(const int len) {
|
||||
static const char alphanum[] = "0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
String s = "";
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
s += alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter) {
|
||||
// extracting required parameters for RFC 2069 simpler Digest
|
||||
String realm = exractParam(authReq, "realm=\"", '"');
|
||||
String nonce = exractParam(authReq, "nonce=\"", '"');
|
||||
String cNonce = getCNonce(8);
|
||||
|
||||
char nc[9];
|
||||
snprintf(nc, sizeof(nc), "%08x", counter);
|
||||
|
||||
// parameters for the RFC 2617 newer Digest
|
||||
MD5Builder md5;
|
||||
md5.begin();
|
||||
md5.add(username + ":" + realm + ":" + password); // md5 of the user:realm:user
|
||||
md5.calculate();
|
||||
String h1 = md5.toString();
|
||||
|
||||
md5.begin();
|
||||
md5.add(method + ":" + uri);
|
||||
md5.calculate();
|
||||
String h2 = md5.toString();
|
||||
|
||||
md5.begin();
|
||||
md5.add(h1 + ":" + nonce + ":" + String(nc) + ":" + cNonce + ":" + "auth" + ":" + h2);
|
||||
md5.calculate();
|
||||
String response = md5.toString();
|
||||
|
||||
String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";
|
||||
Serial.println(authorization);
|
||||
|
||||
return authorization;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, ssidPassword);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
srand(rp2040.getCycleCount());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
HTTPClient http;
|
||||
|
||||
Serial.print("[HTTP] begin...\n");
|
||||
|
||||
// configure target server and url
|
||||
http.begin(String(server) + String(uri));
|
||||
|
||||
|
||||
const char* keys[] = { "WWW-Authenticate" };
|
||||
http.collectHeaders(keys, 1);
|
||||
|
||||
Serial.print("[HTTP] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode > 0) {
|
||||
String authReq = http.header("WWW-Authenticate");
|
||||
Serial.println(authReq);
|
||||
|
||||
String authorization = getDigestAuth(authReq, String(username), String(password), "GET", String(uri), 1);
|
||||
|
||||
http.end();
|
||||
http.begin(String(server) + String(uri));
|
||||
|
||||
http.addHeader("Authorization", authorization);
|
||||
|
||||
int httpCode = http.GET();
|
||||
if (httpCode > 0) {
|
||||
String payload = http.getString();
|
||||
Serial.println(payload);
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
PostHTTPClient.ino
|
||||
|
||||
Created on: 21.11.2016
|
||||
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
WiFi.begin(STASSID, STAPSK);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("");
|
||||
Serial.print("Connected! IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFi.status() == WL_CONNECTED)) {
|
||||
|
||||
HTTPClient http;
|
||||
http.setInsecure();
|
||||
|
||||
Serial.print("[HTTP] begin...\n");
|
||||
// configure target server and url
|
||||
http.begin("https://httpbin.org/post");
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
Serial.print("[HTTP] POST...\n");
|
||||
// start connection and send HTTP header and body
|
||||
int httpCode = http.POST("{\"hello\":\"world\"}");
|
||||
|
||||
// httpCode will be negative on error
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
const String& payload = http.getString();
|
||||
Serial.println("received payload:\n<<");
|
||||
Serial.println(payload);
|
||||
Serial.println(">>");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
http.end();
|
||||
}
|
||||
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
reuseConnectionV2.ino
|
||||
|
||||
Created on: 22.11.2015
|
||||
|
||||
This example reuses the http connection and also restores the connection if the connection is lost
|
||||
*/
|
||||
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
HTTPClient http;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println("Connecting to WiFi...");
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(STASSID, STAPSK);
|
||||
|
||||
// wait for WiFi connection
|
||||
while ((WiFiMulti.run() != WL_CONNECTED)) {
|
||||
Serial.write('.');
|
||||
delay(500);
|
||||
}
|
||||
Serial.println(" connected to WiFi");
|
||||
|
||||
// allow reuse (if server supports it)
|
||||
http.setReuse(true);
|
||||
http.setInsecure();
|
||||
|
||||
http.begin("https://jigsaw.w3.org/HTTP/connection.html");
|
||||
// http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
|
||||
}
|
||||
|
||||
int pass = 0;
|
||||
|
||||
void loop() {
|
||||
// First 10 loop()s, retrieve the URL
|
||||
if (pass < 10) {
|
||||
pass++;
|
||||
Serial.printf("Reuse connection example, GET url for the %d time\n", pass);
|
||||
int httpCode = http.GET();
|
||||
if (httpCode > 0) {
|
||||
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
http.writeToStream(&Serial);
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
|
||||
// Something went wrong with the connection, try to reconnect
|
||||
http.end();
|
||||
http.begin("https://jigsaw.w3.org/HTTP/connection.html");
|
||||
// http.begin(client, "jigsaw.w3.org", 80, "/HTTP/connection.html");
|
||||
}
|
||||
|
||||
if (pass == 10) {
|
||||
http.end();
|
||||
Serial.println("Done testing");
|
||||
} else {
|
||||
Serial.println("\n\n\nWait 5 second...\n");
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
StreamHTTPClient.ino
|
||||
|
||||
Created on: 24.05.2015
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
// Serial.setDebugOutput(true);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
Serial.print("[HTTPS] begin...\n");
|
||||
|
||||
// configure server and url
|
||||
const char *fp = "41:FA:FD:B6:96:5F:33:09:F4:ED:09:28:BF:66:4D:5B:A2:88:03:65";
|
||||
|
||||
HTTPClient https;
|
||||
https.setFingerprint(fp);
|
||||
|
||||
if (https.begin("https://www.trustedfirmware.org/projects/mbed-tls")) {
|
||||
|
||||
Serial.print("[HTTPS] GET...\n");
|
||||
// start connection and send HTTP header
|
||||
int httpCode = https.GET();
|
||||
if (httpCode > 0) {
|
||||
// HTTP header has been send and Server response header has been handled
|
||||
Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
|
||||
|
||||
// file found at server
|
||||
if (httpCode == HTTP_CODE_OK) {
|
||||
|
||||
// get length of document (is -1 when Server sends no Content-Length header)
|
||||
int len = https.getSize();
|
||||
|
||||
// create buffer for read
|
||||
static uint8_t buff[128] = { 0 };
|
||||
|
||||
// read all data from server
|
||||
while (https.connected() && (len > 0 || len == -1)) {
|
||||
// get available data size
|
||||
size_t size = https.getStreamPtr()->available();
|
||||
|
||||
if (size) {
|
||||
// read up to 128 byte
|
||||
int c = https.getStreamPtr()->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
|
||||
|
||||
// write it to Serial
|
||||
Serial.write(buff, c);
|
||||
|
||||
if (len > 0) {
|
||||
len -= c;
|
||||
}
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
Serial.println();
|
||||
Serial.print("[HTTPS] connection closed or file end.\n");
|
||||
}
|
||||
} else {
|
||||
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
|
||||
}
|
||||
|
||||
https.end();
|
||||
} else {
|
||||
Serial.printf("Unable to connect\n");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.println("Wait 10s before the next round...");
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For HTTPClient
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
HTTPClient KEYWORD3 RESERVED_WORD
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
t_http_codes KEYWORD1 DATA_TYPE
|
||||
transferEncoding_t KEYWORD1 DATA_TYPE
|
||||
TransportTraits KEYWORD1 DATA_TYPE
|
||||
TransportTraitsPtr KEYWORD1 DATA_TYPE
|
||||
StreamString KEYWORD1 DATA_TYPE
|
||||
HTTPClient KEYWORD1 DATA_TYPE
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
end KEYWORD2
|
||||
connected KEYWORD2
|
||||
setReuse KEYWORD2
|
||||
setUserAgent KEYWORD2
|
||||
setAuthorization KEYWORD2
|
||||
setTimeout KEYWORD2
|
||||
useHTTP10 KEYWORD2
|
||||
GET KEYWORD2
|
||||
POST KEYWORD2
|
||||
PUT KEYWORD2
|
||||
PATCH KEYWORD2
|
||||
sendRequest KEYWORD2
|
||||
addHeader KEYWORD2
|
||||
collectHeaders KEYWORD2
|
||||
header KEYWORD2
|
||||
headerName KEYWORD2
|
||||
headers KEYWORD2
|
||||
hasHeader KEYWORD2
|
||||
getSize KEYWORD2
|
||||
getStream KEYWORD2
|
||||
getStreamPtr KEYWORD2
|
||||
writeToStream KEYWORD2
|
||||
getString KEYWORD2
|
||||
errorToString KEYWORD2
|
||||
|
||||
setSession KEYWORD2
|
||||
setInsecure KEYWORD2
|
||||
setKnownKey KEYWORD2
|
||||
setFingerprint KEYWORD2
|
||||
allowSelfSignedCerts KEYWORD2
|
||||
setTrustAnchors KEYWORD2
|
||||
setX509Time KEYWORD2
|
||||
setClientRSACert KEYWORD2
|
||||
setClientECCert KEYWORD2
|
||||
setBufferSizes KEYWORD2
|
||||
setCertStore KEYWORD2
|
||||
setCiphers KEYWORD2
|
||||
setCiphersLessSecure KEYWORD2
|
||||
setSSLVersion KEYWORD2
|
||||
setCACert KEYWORD2
|
||||
setCertificate KEYWORD2
|
||||
setPrivateKey KEYWORD2
|
||||
loadCACert KEYWORD2
|
||||
loadCertificate KEYWORD2
|
||||
loadPrivateKey KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
HTTPCLIENT_DEFAULT_TCP_TIMEOUT LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_CONNECTION_REFUSED LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_SEND_HEADER_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_SEND_PAYLOAD_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_NOT_CONNECTED LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_CONNECTION_LOST LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_NO_STREAM LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_NO_HTTP_SERVER LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_TOO_LESS_RAM LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_ENCODING LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_STREAM_WRITE LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_ERROR_READ_TIMEOUT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_TCP_BUFFER_SIZE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_CONTINUE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_SWITCHING_PROTOCOLS LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PROCESSING LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_OK LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_CREATED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_ACCEPTED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NON_AUTHORITATIVE_INFORMATION LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NO_CONTENT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_RESET_CONTENT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PARTIAL_CONTENT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_MULTI_STATUS LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_ALREADY_REPORTED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_IM_USED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_MULTIPLE_CHOICES LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_MOVED_PERMANENTLY LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_FOUND LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_SEE_OTHER LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NOT_MODIFIED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_USE_PROXY LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_TEMPORARY_REDIRECT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PERMANENT_REDIRECT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_BAD_REQUEST LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_UNAUTHORIZED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PAYMENT_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_FORBIDDEN LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NOT_FOUND LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_METHOD_NOT_ALLOWED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NOT_ACCEPTABLE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_REQUEST_TIMEOUT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_CONFLICT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_GONE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_LENGTH_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PRECONDITION_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PAYLOAD_TOO_LARGE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_URI_TOO_LONG LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_RANGE_NOT_SATISFIABLE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_EXPECTATION_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_MISDIRECTED_REQUEST LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_UNPROCESSABLE_ENTITY LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_LOCKED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_FAILED_DEPENDENCY LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_UPGRADE_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_PRECONDITION_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_TOO_MANY_REQUESTS LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_INTERNAL_SERVER_ERROR LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NOT_IMPLEMENTED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_BAD_GATEWAY LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_SERVICE_UNAVAILABLE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_GATEWAY_TIMEOUT LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_VARIANT_ALSO_NEGOTIATES LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_INSUFFICIENT_STORAGE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_LOOP_DETECTED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NOT_EXTENDED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_TE_IDENTITY LITERAL1 RESERVED_WORD_2
|
||||
HTTPC_TE_CHUNKED LITERAL1 RESERVED_WORD_2
|
||||
@@ -0,0 +1,10 @@
|
||||
name=HTTPClient
|
||||
version=1.2
|
||||
author=Markus Sattler
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=http Client for ESP8266, portes to the Pico
|
||||
paragraph=
|
||||
category=Communication
|
||||
url=https://github.com/earlephilhower/arduino-pico/blob/master/libraries/HTTPClient
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,373 @@
|
||||
/**
|
||||
HTTPClient.h
|
||||
|
||||
Modified 2022 by Earle F. Philhower, III
|
||||
|
||||
Created on: 02.11.2015
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266HTTPClient for 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
|
||||
|
||||
Modified by Jeroen Döll, June 2018
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <StreamString.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_CLIENT
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_HTTPCLIENT(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//#define DEBUG_HTTPCLIENT(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__ )
|
||||
#ifndef DEBUG_HTTPCLIENT
|
||||
#define DEBUG_HTTPCLIENT(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#define HTTPCLIENT_DEFAULT_TCP_TIMEOUT (5000)
|
||||
|
||||
/// HTTP client errors
|
||||
#define HTTPC_ERROR_CONNECTION_FAILED (-1)
|
||||
#define HTTPC_ERROR_SEND_HEADER_FAILED (-2)
|
||||
#define HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3)
|
||||
#define HTTPC_ERROR_NOT_CONNECTED (-4)
|
||||
#define HTTPC_ERROR_CONNECTION_LOST (-5)
|
||||
#define HTTPC_ERROR_NO_STREAM (-6)
|
||||
#define HTTPC_ERROR_NO_HTTP_SERVER (-7)
|
||||
#define HTTPC_ERROR_TOO_LESS_RAM (-8)
|
||||
#define HTTPC_ERROR_ENCODING (-9)
|
||||
#define HTTPC_ERROR_STREAM_WRITE (-10)
|
||||
#define HTTPC_ERROR_READ_TIMEOUT (-11)
|
||||
|
||||
constexpr int HTTPC_ERROR_CONNECTION_REFUSED __attribute__((deprecated)) = HTTPC_ERROR_CONNECTION_FAILED;
|
||||
|
||||
/// size for the stream handling
|
||||
#define HTTP_TCP_BUFFER_SIZE (1460)
|
||||
|
||||
/// HTTP codes see RFC7231
|
||||
typedef enum {
|
||||
HTTP_CODE_CONTINUE = 100,
|
||||
HTTP_CODE_SWITCHING_PROTOCOLS = 101,
|
||||
HTTP_CODE_PROCESSING = 102,
|
||||
HTTP_CODE_OK = 200,
|
||||
HTTP_CODE_CREATED = 201,
|
||||
HTTP_CODE_ACCEPTED = 202,
|
||||
HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
HTTP_CODE_NO_CONTENT = 204,
|
||||
HTTP_CODE_RESET_CONTENT = 205,
|
||||
HTTP_CODE_PARTIAL_CONTENT = 206,
|
||||
HTTP_CODE_MULTI_STATUS = 207,
|
||||
HTTP_CODE_ALREADY_REPORTED = 208,
|
||||
HTTP_CODE_IM_USED = 226,
|
||||
HTTP_CODE_MULTIPLE_CHOICES = 300,
|
||||
HTTP_CODE_MOVED_PERMANENTLY = 301,
|
||||
HTTP_CODE_FOUND = 302,
|
||||
HTTP_CODE_SEE_OTHER = 303,
|
||||
HTTP_CODE_NOT_MODIFIED = 304,
|
||||
HTTP_CODE_USE_PROXY = 305,
|
||||
HTTP_CODE_TEMPORARY_REDIRECT = 307,
|
||||
HTTP_CODE_PERMANENT_REDIRECT = 308,
|
||||
HTTP_CODE_BAD_REQUEST = 400,
|
||||
HTTP_CODE_UNAUTHORIZED = 401,
|
||||
HTTP_CODE_PAYMENT_REQUIRED = 402,
|
||||
HTTP_CODE_FORBIDDEN = 403,
|
||||
HTTP_CODE_NOT_FOUND = 404,
|
||||
HTTP_CODE_METHOD_NOT_ALLOWED = 405,
|
||||
HTTP_CODE_NOT_ACCEPTABLE = 406,
|
||||
HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
HTTP_CODE_REQUEST_TIMEOUT = 408,
|
||||
HTTP_CODE_CONFLICT = 409,
|
||||
HTTP_CODE_GONE = 410,
|
||||
HTTP_CODE_LENGTH_REQUIRED = 411,
|
||||
HTTP_CODE_PRECONDITION_FAILED = 412,
|
||||
HTTP_CODE_PAYLOAD_TOO_LARGE = 413,
|
||||
HTTP_CODE_URI_TOO_LONG = 414,
|
||||
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
HTTP_CODE_RANGE_NOT_SATISFIABLE = 416,
|
||||
HTTP_CODE_EXPECTATION_FAILED = 417,
|
||||
HTTP_CODE_MISDIRECTED_REQUEST = 421,
|
||||
HTTP_CODE_UNPROCESSABLE_ENTITY = 422,
|
||||
HTTP_CODE_LOCKED = 423,
|
||||
HTTP_CODE_FAILED_DEPENDENCY = 424,
|
||||
HTTP_CODE_UPGRADE_REQUIRED = 426,
|
||||
HTTP_CODE_PRECONDITION_REQUIRED = 428,
|
||||
HTTP_CODE_TOO_MANY_REQUESTS = 429,
|
||||
HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
HTTP_CODE_INTERNAL_SERVER_ERROR = 500,
|
||||
HTTP_CODE_NOT_IMPLEMENTED = 501,
|
||||
HTTP_CODE_BAD_GATEWAY = 502,
|
||||
HTTP_CODE_SERVICE_UNAVAILABLE = 503,
|
||||
HTTP_CODE_GATEWAY_TIMEOUT = 504,
|
||||
HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506,
|
||||
HTTP_CODE_INSUFFICIENT_STORAGE = 507,
|
||||
HTTP_CODE_LOOP_DETECTED = 508,
|
||||
HTTP_CODE_NOT_EXTENDED = 510,
|
||||
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
} t_http_codes;
|
||||
|
||||
typedef enum {
|
||||
HTTPC_TE_IDENTITY,
|
||||
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;
|
||||
|
||||
class TransportTraits;
|
||||
typedef std::unique_ptr<TransportTraits> TransportTraitsPtr;
|
||||
|
||||
class HTTPClient {
|
||||
public:
|
||||
HTTPClient() = default;
|
||||
~HTTPClient() = default;
|
||||
HTTPClient(HTTPClient&&) = default;
|
||||
HTTPClient& operator=(HTTPClient&&) = default;
|
||||
|
||||
// The easier way
|
||||
bool begin(String url);
|
||||
bool begin(String host, uint16_t port, String uri = "/", bool https = false);
|
||||
bool begin(String url, const uint8_t httpsFingerprint[20]) {
|
||||
setFingerprint(httpsFingerprint);
|
||||
return begin(url);
|
||||
}
|
||||
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) {
|
||||
setFingerprint(httpsFingerprint);
|
||||
return begin(host, port, uri);
|
||||
}
|
||||
|
||||
// Let's do it the hard way, too
|
||||
bool begin(WiFiClient &client, const String& url);
|
||||
bool begin(WiFiClient &client, const String& host, uint16_t port, const String& uri = "/", bool https = false);
|
||||
|
||||
|
||||
void end(void);
|
||||
|
||||
bool connected(void);
|
||||
|
||||
void setReuse(bool reuse); /// keep-alive
|
||||
void setUserAgent(const String& userAgent);
|
||||
void setAuthorization(const char * user, const char * password);
|
||||
void setAuthorization(const char * auth);
|
||||
void setAuthorization(String auth);
|
||||
void setTimeout(uint16_t timeout);
|
||||
|
||||
// Redirections
|
||||
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);
|
||||
|
||||
/// request handling
|
||||
int GET();
|
||||
int DELETE();
|
||||
int POST(const uint8_t* payload, size_t size);
|
||||
int POST(const String& payload);
|
||||
int PUT(const uint8_t* payload, size_t size);
|
||||
int PUT(const String& payload);
|
||||
int PATCH(const uint8_t* payload, size_t size);
|
||||
int PATCH(const String& payload);
|
||||
int sendRequest(const char* type, const String& payload);
|
||||
int sendRequest(const char* type, const uint8_t* payload = NULL, size_t size = 0);
|
||||
int sendRequest(const char* type, Stream * stream, size_t size = 0);
|
||||
|
||||
void addHeader(const String& name, const String& value, bool first = false, bool replace = true);
|
||||
|
||||
/// Response handling
|
||||
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount);
|
||||
String header(const char* name); // get request header value by name
|
||||
String header(size_t i); // get request header value by number
|
||||
String headerName(size_t i); // get request header name by number
|
||||
int headers(); // get header count
|
||||
bool hasHeader(const char* name); // check if header exists
|
||||
|
||||
|
||||
int getSize(void);
|
||||
const String& getLocation(void); // Location header from redirect if 3XX
|
||||
|
||||
WiFiClient& getStream(void);
|
||||
WiFiClient* getStreamPtr(void);
|
||||
int writeToPrint(Print* print);
|
||||
int writeToStream(Stream* stream);
|
||||
const String& getString(void);
|
||||
static String errorToString(int error);
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// HTTPS support, mirrors the WiFiClientSecure interface
|
||||
// Could possibly use a virtual interface class between the two, but for now it is more
|
||||
// straightforward to simply feed calls through manually here.
|
||||
void setSession(Session *session) {
|
||||
_tls()->setSession(session);
|
||||
}
|
||||
void setInsecure() {
|
||||
_tls()->setInsecure();
|
||||
}
|
||||
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
|
||||
_tls()->setKnownKey(pk, usages);
|
||||
}
|
||||
bool setFingerprint(const uint8_t fingerprint[20]) {
|
||||
return _tls()->setFingerprint(fingerprint);
|
||||
}
|
||||
bool setFingerprint(const char *fpStr) {
|
||||
return _tls()->setFingerprint(fpStr);
|
||||
}
|
||||
void allowSelfSignedCerts() {
|
||||
_tls()->allowSelfSignedCerts();
|
||||
}
|
||||
void setTrustAnchors(const X509List *ta) {
|
||||
_tls()->setTrustAnchors(ta);
|
||||
}
|
||||
void setX509Time(time_t now) {
|
||||
_tls()->setX509Time(now);
|
||||
}
|
||||
void setClientRSACert(const X509List *cert, const PrivateKey *sk) {
|
||||
_tls()->setClientRSACert(cert, sk);
|
||||
}
|
||||
void setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||
_tls()->setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
|
||||
}
|
||||
void setBufferSizes(int recv, int xmit) {
|
||||
_tls()->setBufferSizes(recv, xmit);
|
||||
}
|
||||
void setCertStore(CertStoreBase *certStore) {
|
||||
_tls()->setCertStore(certStore);
|
||||
}
|
||||
bool setCiphers(const uint16_t *cipherAry, int cipherCount) {
|
||||
return _tls()->setCiphers(cipherAry, cipherCount);
|
||||
}
|
||||
bool setCiphers(const std::vector<uint16_t>& list) {
|
||||
return _tls()->setCiphers(list);
|
||||
}
|
||||
bool setCiphersLessSecure() {
|
||||
return _tls()->setCiphersLessSecure();
|
||||
}
|
||||
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12) {
|
||||
return _tls()->setSSLVersion(min, max);
|
||||
}
|
||||
void setCACert(const char *rootCA) {
|
||||
_tls()->setCACert(rootCA);
|
||||
}
|
||||
void setCertificate(const char *client_ca) {
|
||||
_tls()->setCertificate(client_ca);
|
||||
}
|
||||
void setPrivateKey(const char *private_key) {
|
||||
_tls()->setPrivateKey(private_key);
|
||||
}
|
||||
bool loadCACert(Stream& stream, size_t size) {
|
||||
return _tls()->loadCACert(stream, size);
|
||||
}
|
||||
bool loadCertificate(Stream& stream, size_t size) {
|
||||
return _tls()->loadCertificate(stream, size);
|
||||
}
|
||||
bool loadPrivateKey(Stream& stream, size_t size) {
|
||||
return _tls()->loadPrivateKey(stream, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
// HTTPS helpers
|
||||
WiFiClientSecure *_tls() {
|
||||
if (!_clientMade) {
|
||||
_clientMade = new WiFiClientSecure();
|
||||
_clientGiven = false;
|
||||
}
|
||||
_clientTLS = true;
|
||||
return (WiFiClientSecure*)_clientMade;
|
||||
}
|
||||
|
||||
struct RequestArgument {
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
|
||||
bool beginInternal(const String& url, const char* expectedProtocol);
|
||||
void disconnect(bool preserveClient = false);
|
||||
void clear();
|
||||
int returnError(int error);
|
||||
bool connect(void);
|
||||
bool sendHeader(const char * type);
|
||||
int handleHeaderResponse();
|
||||
int writeToStreamDataBlock(Stream * stream, int len);
|
||||
|
||||
WiFiClient *_clientMade = nullptr;
|
||||
bool _clientTLS = false;
|
||||
|
||||
std::unique_ptr<WiFiClient> _clientIn;
|
||||
bool _clientGiven = false;
|
||||
|
||||
WiFiClient *_client() {
|
||||
if (_clientGiven) {
|
||||
return _clientIn.get();
|
||||
} else {
|
||||
return _clientMade;
|
||||
}
|
||||
}
|
||||
|
||||
/// request handling
|
||||
String _host;
|
||||
uint16_t _port = 0;
|
||||
bool _reuse = true;
|
||||
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
bool _useHTTP10 = false;
|
||||
|
||||
String _uri;
|
||||
String _protocol;
|
||||
String _headers;
|
||||
String _base64Authorization;
|
||||
|
||||
static const String defaultUserAgent;
|
||||
String _userAgent = defaultUserAgent;
|
||||
|
||||
/// Response handling
|
||||
std::unique_ptr<RequestArgument[]> _currentHeaders;
|
||||
size_t _headerKeysCount = 0;
|
||||
|
||||
int _returnCode = 0;
|
||||
int _size = -1;
|
||||
bool _canReuse = false;
|
||||
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
|
||||
uint16_t _redirectLimit = 10;
|
||||
String _location;
|
||||
transferEncoding_t _transferEncoding = HTTPC_TE_IDENTITY;
|
||||
std::unique_ptr<StreamString> _payload;
|
||||
|
||||
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
base64.cpp
|
||||
|
||||
Created on: 09.12.2015
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266 core for 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
|
||||
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
extern "C" {
|
||||
#include "libb64/cencode.h"
|
||||
}
|
||||
#include "base64.h"
|
||||
|
||||
/**
|
||||
convert input data to base64
|
||||
@param data const uint8_t
|
||||
@param length size_t
|
||||
@return String
|
||||
*/
|
||||
String base64::encode(const uint8_t * data, size_t length, bool doNewLines) {
|
||||
String base64;
|
||||
|
||||
// base64 needs more size then the source data, use cencode.h macros
|
||||
size_t size = ((doNewLines ? base64_encode_expected_len(length)
|
||||
: base64_encode_expected_len_nonewlines(length)) + 1);
|
||||
|
||||
if (base64.reserve(size)) {
|
||||
|
||||
base64_encodestate _state;
|
||||
if (doNewLines) {
|
||||
base64_init_encodestate(&_state);
|
||||
} else {
|
||||
base64_init_encodestate_nonewlines(&_state);
|
||||
}
|
||||
|
||||
constexpr size_t BUFSIZE = 48;
|
||||
char buf[BUFSIZE + 1 /* newline */ + 1 /* NUL */];
|
||||
for (size_t len = 0; len < length; len += BUFSIZE * 3 / 4) {
|
||||
size_t blocklen = base64_encode_block((const char*) data + len,
|
||||
std::min(BUFSIZE * 3 / 4, length - len), buf, &_state);
|
||||
buf[blocklen] = '\0';
|
||||
base64 += buf;
|
||||
}
|
||||
if (base64_encode_blockend(buf, &_state)) {
|
||||
base64 += buf;
|
||||
}
|
||||
} else {
|
||||
base64 = F("-FAIL-");
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
base64.h
|
||||
|
||||
Created on: 09.12.2015
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266 core for 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
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/String.h>
|
||||
|
||||
class base64 {
|
||||
public:
|
||||
// NOTE: The default behaviour of backend (lib64)
|
||||
// is to add a newline every 72 (encoded) characters output.
|
||||
// This may 'break' longer uris and json variables
|
||||
static String encode(const uint8_t * data, size_t length, bool doNewLines);
|
||||
static inline String encode(const String& text, bool doNewLines) {
|
||||
return encode((const uint8_t *) text.c_str(), text.length(), doNewLines);
|
||||
}
|
||||
|
||||
// esp32 compat:
|
||||
|
||||
static inline String encode(const uint8_t * data, size_t length) {
|
||||
return encode(data, length, false);
|
||||
}
|
||||
|
||||
static inline String encode(const String& text) {
|
||||
return encode(text, false);
|
||||
}
|
||||
};
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
libb64: Base64 Encoding/Decoding Routines
|
||||
======================================
|
||||
|
||||
Authors:
|
||||
-------
|
||||
|
||||
Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
Copyright-Only Dedication (based on United States law)
|
||||
or Public Domain Certification
|
||||
|
||||
The person or persons who have associated work with this document (the
|
||||
"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
|
||||
his knowledge, the work of authorship identified is in the public domain of the
|
||||
country from which the work is published, or (b) hereby dedicates whatever
|
||||
copyright the dedicators holds in the work of authorship identified below (the
|
||||
"Work") to the public domain. A certifier, moreover, dedicates any copyright
|
||||
interest he may have in the associated work, and for these purposes, is
|
||||
described as a "dedicator" below.
|
||||
|
||||
A certifier has taken reasonable steps to verify the copyright status of this
|
||||
work. Certifier recognizes that his good faith efforts may not shield him from
|
||||
liability if in fact the work certified is not in the public domain.
|
||||
|
||||
Dedicator makes this dedication for the benefit of the public at large and to
|
||||
the detriment of the Dedicator's heirs and successors. Dedicator intends this
|
||||
dedication to be an overt act of relinquishment in perpetuity of all present
|
||||
and future rights under copyright law, whether vested or contingent, in the
|
||||
Work. Dedicator understands that such relinquishment of all rights includes
|
||||
the relinquishment of all rights to enforce (by lawsuit or otherwise) those
|
||||
copyrights in the Work.
|
||||
|
||||
Dedicator recognizes that, once placed in the public domain, the Work may be
|
||||
freely reproduced, distributed, transmitted, used, modified, built upon, or
|
||||
otherwise exploited by anyone for any purpose, commercial or non-commercial,
|
||||
and in any way, including by methods that have not yet been invented or
|
||||
conceived.
|
||||
Executable
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
cdecoder.c - c source to a base64 decoding algorithm implementation
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#include <pgmspace.h>
|
||||
#include <stdint.h>
|
||||
#include "cdecode.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
static int base64_decode_value_signed(int8_t value_in) {
|
||||
static const int8_t decoding[] PROGMEM = {62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||
static const int8_t decoding_size = sizeof(decoding);
|
||||
value_in -= 43;
|
||||
if (value_in < 0 || value_in > decoding_size) {
|
||||
return -1;
|
||||
}
|
||||
return pgm_read_byte(&decoding[(int)value_in]);
|
||||
}
|
||||
|
||||
void base64_init_decodestate(base64_decodestate* state_in) {
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = 0;
|
||||
}
|
||||
|
||||
static int base64_decode_block_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out, base64_decodestate* state_in) {
|
||||
const int8_t* codechar = code_in;
|
||||
int8_t* plainchar = plaintext_out;
|
||||
int8_t fragment;
|
||||
|
||||
*plainchar = state_in->plainchar;
|
||||
|
||||
switch (state_in->step) {
|
||||
while (1) {
|
||||
case step_a:
|
||||
do {
|
||||
if (codechar == code_in + length_in) {
|
||||
state_in->step = step_a;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar = (fragment & 0x03f) << 2;
|
||||
// falls through
|
||||
case step_b:
|
||||
do {
|
||||
if (codechar == code_in + length_in) {
|
||||
state_in->step = step_b;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||
*plainchar = (fragment & 0x00f) << 4;
|
||||
// falls through
|
||||
case step_c:
|
||||
do {
|
||||
if (codechar == code_in + length_in) {
|
||||
state_in->step = step_c;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||
*plainchar = (fragment & 0x003) << 6;
|
||||
// falls through
|
||||
case step_d:
|
||||
do {
|
||||
if (codechar == code_in + length_in) {
|
||||
state_in->step = step_d;
|
||||
state_in->plainchar = *plainchar;
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x03f);
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return plainchar - plaintext_out;
|
||||
}
|
||||
|
||||
static int base64_decode_chars_signed(const int8_t* code_in, const int length_in, int8_t* plaintext_out) {
|
||||
base64_decodestate _state;
|
||||
base64_init_decodestate(&_state);
|
||||
int len = base64_decode_block_signed(code_in, length_in, plaintext_out, &_state);
|
||||
if (len > 0) {
|
||||
plaintext_out[len] = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int base64_decode_value(char value_in) {
|
||||
return base64_decode_value_signed(*((int8_t *) &value_in));
|
||||
}
|
||||
|
||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) {
|
||||
return base64_decode_block_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out, state_in);
|
||||
}
|
||||
|
||||
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out) {
|
||||
return base64_decode_chars_signed((int8_t *) code_in, length_in, (int8_t *) plaintext_out);
|
||||
}
|
||||
|
||||
};
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
cdecode.h - c header for a base64 decoding algorithm
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CDECODE_H
|
||||
#define BASE64_CDECODE_H
|
||||
|
||||
#define base64_decode_expected_len(n) ((n * 3) / 4)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
step_a, step_b, step_c, step_d
|
||||
} base64_decodestep;
|
||||
|
||||
typedef struct {
|
||||
base64_decodestep step;
|
||||
char plainchar;
|
||||
} base64_decodestate;
|
||||
|
||||
void base64_init_decodestate(base64_decodestate* state_in);
|
||||
|
||||
int base64_decode_value(char value_in);
|
||||
|
||||
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
|
||||
|
||||
int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* BASE64_CDECODE_H */
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
cencoder.c - c source to a base64 encoding algorithm implementation
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#include "cencode.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in) {
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
state_in->stepsnewline = BASE64_CHARS_PER_LINE;
|
||||
}
|
||||
|
||||
|
||||
void base64_init_encodestate_nonewlines(base64_encodestate* state_in) {
|
||||
base64_init_encodestate(state_in);
|
||||
state_in->stepsnewline = -1;
|
||||
}
|
||||
|
||||
char base64_encode_value(const char n) {
|
||||
char r;
|
||||
|
||||
if (n < 26) {
|
||||
r = n + 'A';
|
||||
} else if (n < 26 + 26) {
|
||||
r = n - 26 + 'a';
|
||||
} else if (n < 26 + 26 + 10) {
|
||||
r = n - 26 - 26 + '0';
|
||||
} else if (n == 62) {
|
||||
r = '+';
|
||||
} else {
|
||||
r = '/';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) {
|
||||
const char* plainchar = plaintext_in;
|
||||
const char* const plaintextend = plaintext_in + length_in;
|
||||
char* codechar = code_out;
|
||||
char result;
|
||||
char fragment;
|
||||
|
||||
result = state_in->result;
|
||||
|
||||
switch (state_in->step) {
|
||||
while (1) {
|
||||
case step_A:
|
||||
if (plainchar == plaintextend) {
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
// falls through
|
||||
case step_B:
|
||||
if (plainchar == plaintextend) {
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
// falls through
|
||||
case step_C:
|
||||
if (plainchar == plaintextend) {
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return codechar - code_out;
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0c0) >> 6;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x03f) >> 0;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
if ((state_in->stepcount == BASE64_CHARS_PER_LINE / 4) && (state_in->stepsnewline > 0)) {
|
||||
*codechar++ = '\n';
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in) {
|
||||
char* codechar = code_out;
|
||||
|
||||
switch (state_in->step) {
|
||||
case step_B:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_C:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_A:
|
||||
break;
|
||||
}
|
||||
*codechar = 0x00;
|
||||
|
||||
return codechar - code_out;
|
||||
}
|
||||
|
||||
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out) {
|
||||
base64_encodestate _state;
|
||||
base64_init_encodestate(&_state);
|
||||
int len = base64_encode_block(plaintext_in, length_in, code_out, &_state);
|
||||
return len + base64_encode_blockend((code_out + len), &_state);
|
||||
}
|
||||
|
||||
};
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
cencode.h - c header for a base64 encoding algorithm
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CENCODE_H
|
||||
#define BASE64_CENCODE_H
|
||||
|
||||
#define BASE64_CHARS_PER_LINE 72
|
||||
|
||||
#define base64_encode_expected_len_nonewlines(n) ((((4 * (n)) / 3) + 3) & ~3)
|
||||
#define base64_encode_expected_len(n) \
|
||||
(base64_encode_expected_len_nonewlines(n) + ((n / ((BASE64_CHARS_PER_LINE * 3) / 4)) + 1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
step_A, step_B, step_C
|
||||
} base64_encodestep;
|
||||
|
||||
typedef struct {
|
||||
base64_encodestep step;
|
||||
char result;
|
||||
int stepcount;
|
||||
int stepsnewline;
|
||||
} base64_encodestate;
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in);
|
||||
void base64_init_encodestate_nonewlines(base64_encodestate* state_in);
|
||||
|
||||
char base64_encode_value(char value_in);
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
|
||||
|
||||
int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* BASE64_CENCODE_H */
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
httpUpdate.ino
|
||||
|
||||
Created on: 27.11.2015
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <HTTPUpdate.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
#define UPDATE_URL "http://192.168.1.8/xfer/file.bin"
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void update_started() {
|
||||
Serial.println("CALLBACK: HTTP update process started");
|
||||
}
|
||||
|
||||
void update_finished() {
|
||||
Serial.println("CALLBACK: HTTP update process finished");
|
||||
}
|
||||
|
||||
void update_progress(int cur, int total) {
|
||||
Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total);
|
||||
}
|
||||
|
||||
void update_error(int err) {
|
||||
Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
// Add optional callback notifiers
|
||||
httpUpdate.onStart(update_started);
|
||||
httpUpdate.onEnd(update_finished);
|
||||
httpUpdate.onProgress(update_progress);
|
||||
httpUpdate.onError(update_error);
|
||||
|
||||
t_httpUpdate_return ret = httpUpdate.update(UPDATE_URL);
|
||||
// Or:
|
||||
// t_httpUpdate_return ret = httpUpdate.update("server", 80, "file.bin");
|
||||
|
||||
switch (ret) {
|
||||
case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break;
|
||||
|
||||
case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
|
||||
|
||||
case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
httpUpdateSecure.ino
|
||||
|
||||
Created on: 27.11.2015
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <HTTPUpdate.h>
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char *ssid = STASSID;
|
||||
const char *pass = STAPSK;
|
||||
|
||||
#define UPDATE_URL "https://www.ziplabel.com/file.bin"
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
for (uint8_t t = 4; t > 0; t--) {
|
||||
Serial.printf("[SETUP] WAIT %d...\n", t);
|
||||
Serial.flush();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiMulti.addAP(ssid, pass);
|
||||
}
|
||||
|
||||
void update_started() {
|
||||
Serial.println("CALLBACK: HTTP update process started");
|
||||
}
|
||||
|
||||
void update_finished() {
|
||||
Serial.println("CALLBACK: HTTP update process finished");
|
||||
}
|
||||
|
||||
void update_progress(int cur, int total) {
|
||||
Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total);
|
||||
}
|
||||
|
||||
void update_error(int err) {
|
||||
Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
// wait for WiFi connection
|
||||
if ((WiFiMulti.run() == WL_CONNECTED)) {
|
||||
|
||||
// Add optional callback notifiers
|
||||
httpUpdate.onStart(update_started);
|
||||
httpUpdate.onEnd(update_finished);
|
||||
httpUpdate.onProgress(update_progress);
|
||||
httpUpdate.onError(update_error);
|
||||
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure();
|
||||
t_httpUpdate_return ret = httpUpdate.update(client, UPDATE_URL);
|
||||
// Or:
|
||||
// t_httpUpdate_return ret = httpUpdate.update("server", 80, "file.bin");
|
||||
|
||||
switch (ret) {
|
||||
case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); break;
|
||||
|
||||
case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break;
|
||||
|
||||
case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For ESP8266httpUpdate
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Library (KEYWORD3)
|
||||
#######################################
|
||||
|
||||
HTTPUpdate KEYWORD3 RESERVED_WORD
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
HTTPUpdateResult KEYWORD1 DATA_TYPE
|
||||
ESPhttpUpdate KEYWORD1 DATA_TYPE
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
rebootOnUpdate KEYWORD2
|
||||
update KEYWORD2
|
||||
updateSpiffs KEYWORD2
|
||||
getLastError KEYWORD2
|
||||
getLastErrorString KEYWORD2
|
||||
setAuthorization KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
HTTP_UE_TOO_LESS_SPACE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_NOT_REPORT_SIZE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_FILE_NOT_FOUND LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_FORBIDDEN LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_WRONG_HTTP_CODE LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_FAULTY_MD5 LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_BIN_VERIFY_HEADER_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_BIN_FOR_WRONG_FLASH LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UE_SERVER_UNAUTHORIZED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UPDATE_FAILED LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UPDATE_NO_UPDATES LITERAL1 RESERVED_WORD_2
|
||||
HTTP_UPDATE_OK LITERAL1 RESERVED_WORD_2
|
||||
@@ -0,0 +1,10 @@
|
||||
name=HTTPUpdate
|
||||
version=1.3
|
||||
author=Markus Sattler
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Http Update for ESP8266, ported to Pico
|
||||
paragraph=
|
||||
category=Data Processing
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
Executable
+392
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
|
||||
@file HTTPUpdate.cpp
|
||||
@date 21.06.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the Http Updater.
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include "HTTPUpdate.h"
|
||||
#include <StreamString.h>
|
||||
|
||||
extern uint8_t _FS_start;
|
||||
extern uint8_t _FS_end;
|
||||
|
||||
HTTPUpdate::HTTPUpdate(void)
|
||||
: _httpClientTimeout(8000) {
|
||||
}
|
||||
|
||||
HTTPUpdate::HTTPUpdate(int httpClientTimeout)
|
||||
: _httpClientTimeout(httpClientTimeout) {
|
||||
}
|
||||
|
||||
HTTPUpdate::~HTTPUpdate(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
set the Authorization for the http request
|
||||
@param user const String&
|
||||
@param password const String&
|
||||
*/
|
||||
void HTTPUpdate::setAuthorization(const String &user, const String &password) {
|
||||
_user = user;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
set the Authorization for the http request
|
||||
@param auth const String& base64
|
||||
*/
|
||||
void HTTPUpdate::setAuthorization(const String &auth) {
|
||||
_auth = auth;
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& url, const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(client, url);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::updateFS(WiFiClient& client, const String& url, const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(client, url);
|
||||
return handleUpdate(http, currentVersion, true);
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& host, uint16_t port, const String& uri,
|
||||
const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(client, host, port, uri);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::update(const String& url, const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::update(const String& host, uint16_t port, const String& uri, const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(host, port, uri);
|
||||
return handleUpdate(http, currentVersion, false);
|
||||
}
|
||||
|
||||
HTTPUpdateResult HTTPUpdate::updateFS(const String& url, const String& currentVersion) {
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
return handleUpdate(http, currentVersion, true);
|
||||
}
|
||||
|
||||
/**
|
||||
return error code as int
|
||||
@return int error code
|
||||
*/
|
||||
int HTTPUpdate::getLastError(void) {
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
return error code as String
|
||||
@return String error
|
||||
*/
|
||||
String HTTPUpdate::getLastErrorString(void) {
|
||||
|
||||
if (_lastError == 0) {
|
||||
return String(); // no error
|
||||
}
|
||||
|
||||
// error from Update class
|
||||
if (_lastError > 0) {
|
||||
StreamString error;
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
return String(F("Update error: ")) + error;
|
||||
}
|
||||
|
||||
// error from http client
|
||||
if (_lastError > -100) {
|
||||
return String(F("HTTP error: ")) + HTTPClient::errorToString(_lastError);
|
||||
}
|
||||
|
||||
switch (_lastError) {
|
||||
case HTTP_UE_TOO_LESS_SPACE:
|
||||
return F("Not Enough space");
|
||||
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
|
||||
return F("Server Did Not Report Size");
|
||||
case HTTP_UE_SERVER_FILE_NOT_FOUND:
|
||||
return F("File Not Found (404)");
|
||||
case HTTP_UE_SERVER_FORBIDDEN:
|
||||
return F("Forbidden (403)");
|
||||
case HTTP_UE_SERVER_WRONG_HTTP_CODE:
|
||||
return F("Wrong HTTP Code");
|
||||
case HTTP_UE_SERVER_FAULTY_MD5:
|
||||
return F("Wrong MD5");
|
||||
case HTTP_UE_BIN_VERIFY_HEADER_FAILED:
|
||||
return F("Verify Bin Header Failed");
|
||||
case HTTP_UE_BIN_FOR_WRONG_FLASH:
|
||||
return F("New Binary Does Not Fit Flash Size");
|
||||
case HTTP_UE_SERVER_UNAUTHORIZED:
|
||||
return F("Unauthorized (401)");
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@param http HTTPClient
|
||||
@param currentVersion const char
|
||||
@return HTTPUpdateResult
|
||||
*/
|
||||
HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs) {
|
||||
|
||||
HTTPUpdateResult ret = HTTP_UPDATE_FAILED;
|
||||
|
||||
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
|
||||
http.useHTTP10(true);
|
||||
http.setTimeout(_httpClientTimeout);
|
||||
http.setFollowRedirects(_followRedirects);
|
||||
http.setUserAgent(F("-http-Update"));
|
||||
http.addHeader(F("x--Chip-ID"), String(rp2040.getChipID()));
|
||||
http.addHeader(F("x--STA-MAC"), WiFi.macAddress());
|
||||
http.addHeader(F("x--AP-MAC"), WiFi.softAPmacAddress());
|
||||
|
||||
if (spiffs) {
|
||||
http.addHeader(F("x--mode"), F("spiffs"));
|
||||
} else {
|
||||
http.addHeader(F("x--mode"), F("sketch"));
|
||||
}
|
||||
|
||||
if (currentVersion && currentVersion[0] != 0x00) {
|
||||
http.addHeader(F("x--version"), currentVersion);
|
||||
}
|
||||
|
||||
if (_user != "" && _password != "") {
|
||||
http.setAuthorization(_user.c_str(), _password.c_str());
|
||||
}
|
||||
|
||||
if (_auth != "") {
|
||||
http.setAuthorization(_auth.c_str());
|
||||
}
|
||||
|
||||
const char * headerkeys[] = { "x-MD5" };
|
||||
size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*);
|
||||
|
||||
// track these headers
|
||||
http.collectHeaders(headerkeys, headerkeyssize);
|
||||
|
||||
|
||||
int code = http.GET();
|
||||
int len = http.getSize();
|
||||
|
||||
if (code <= 0) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str());
|
||||
_setLastError(code);
|
||||
http.end();
|
||||
return HTTP_UPDATE_FAILED;
|
||||
}
|
||||
|
||||
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Header read fin.\n");
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Server header:\n");
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - len: %d\n", len);
|
||||
|
||||
String md5;
|
||||
if (_md5Sum.length()) {
|
||||
md5 = _md5Sum;
|
||||
} else if (http.hasHeader("x-MD5")) {
|
||||
md5 = http.header("x-MD5");
|
||||
}
|
||||
if (md5.length()) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - MD5: %s\n", md5.c_str());
|
||||
}
|
||||
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] info:\n");
|
||||
|
||||
if (currentVersion && currentVersion[0] != 0x00) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str());
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case HTTP_CODE_OK: ///< OK (Start Update)
|
||||
if (len > 0) {
|
||||
bool startUpdate = true;
|
||||
if (spiffs) {
|
||||
size_t spiffsSize = ((size_t)&_FS_end - (size_t)&_FS_start);
|
||||
if (len > (int) spiffsSize) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] spiffsSize to low (%d) needed: %d\n", spiffsSize, len);
|
||||
startUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!startUpdate) {
|
||||
_setLastError(HTTP_UE_TOO_LESS_SPACE);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
} else {
|
||||
// Warn main app we're starting up...
|
||||
if (_cbStart) {
|
||||
_cbStart();
|
||||
}
|
||||
|
||||
WiFiClient * tcp = http.getStreamPtr();
|
||||
if (!tcp) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] WiFiClient connection unexpectedly absent\n");
|
||||
_setLastError(HTTPC_ERROR_CONNECTION_LOST);
|
||||
http.end();
|
||||
return HTTP_UPDATE_FAILED;
|
||||
}
|
||||
|
||||
if (_closeConnectionsOnUpdate) {
|
||||
WiFiUDP::stopAll();
|
||||
WiFiClient::stopAllExcept(tcp);
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
int command;
|
||||
|
||||
if (spiffs) {
|
||||
command = U_FS;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate filesystem...\n");
|
||||
} else {
|
||||
command = U_FLASH;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
|
||||
}
|
||||
|
||||
if (runUpdate(*tcp, len, md5, command)) {
|
||||
ret = HTTP_UPDATE_OK;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
|
||||
http.end();
|
||||
// Warn main app we're all done
|
||||
if (_cbEnd) {
|
||||
_cbEnd();
|
||||
}
|
||||
|
||||
#ifdef ATOMIC_FS_UPDATE
|
||||
if (_rebootOnUpdate) {
|
||||
#else
|
||||
if (_rebootOnUpdate && !spiffs) {
|
||||
#endif
|
||||
rp2040.restart();
|
||||
}
|
||||
|
||||
} else {
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update failed\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_setLastError(HTTP_UE_SERVER_NOT_REPORT_SIZE);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length was 0 or wasn't set by Server?!\n");
|
||||
}
|
||||
break;
|
||||
case HTTP_CODE_NOT_MODIFIED:
|
||||
///< Not Modified (No updates)
|
||||
ret = HTTP_UPDATE_NO_UPDATES;
|
||||
break;
|
||||
case HTTP_CODE_NOT_FOUND:
|
||||
_setLastError(HTTP_UE_SERVER_FILE_NOT_FOUND);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
break;
|
||||
case HTTP_CODE_FORBIDDEN:
|
||||
_setLastError(HTTP_UE_SERVER_FORBIDDEN);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
break;
|
||||
case HTTP_CODE_UNAUTHORIZED:
|
||||
_setLastError(HTTP_UE_SERVER_UNAUTHORIZED);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
break;
|
||||
default:
|
||||
_setLastError(HTTP_UE_SERVER_WRONG_HTTP_CODE);
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code);
|
||||
//http.writeToStream(&Serial1);
|
||||
break;
|
||||
}
|
||||
|
||||
http.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
write Update to flash
|
||||
@param in Stream&
|
||||
@param size uint32_t
|
||||
@param md5 String
|
||||
@return true if Update ok
|
||||
*/
|
||||
bool HTTPUpdate::runUpdate(Stream& in, uint32_t size, const String& md5, int command) {
|
||||
|
||||
StreamString error;
|
||||
|
||||
if (_cbProgress) {
|
||||
Update.onProgress(_cbProgress);
|
||||
}
|
||||
|
||||
if (!Update.begin(size, command)) {
|
||||
_setLastError(Update.getError());
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_cbProgress) {
|
||||
_cbProgress(0, size);
|
||||
}
|
||||
|
||||
if (md5.length()) {
|
||||
if (!Update.setMD5(md5.c_str())) {
|
||||
_setLastError(HTTP_UE_SERVER_FAULTY_MD5);
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.writeStream(in) != size) {
|
||||
_setLastError(Update.getError());
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_cbProgress) {
|
||||
_cbProgress(size, size);
|
||||
}
|
||||
|
||||
if (!Update.end()) {
|
||||
_setLastError(Update.getError());
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
|
||||
HTTPUpdate httpUpdate;
|
||||
#endif
|
||||
Executable
+163
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
|
||||
@file ESP8266HTTPUpdate.h
|
||||
@date 21.06.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266 Http Updater.
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_UPDATE
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_HTTP_UPDATE(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ## __VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_HTTP_UPDATE
|
||||
#define DEBUG_HTTP_UPDATE(...) do { (void)0; } while(0)
|
||||
#endif
|
||||
|
||||
/// note we use HTTP client errors too so we start at 100
|
||||
//TODO - in v3.0.0 make this an enum
|
||||
constexpr int HTTP_UE_TOO_LESS_SPACE = (-100);
|
||||
constexpr int HTTP_UE_SERVER_NOT_REPORT_SIZE = (-101);
|
||||
constexpr int HTTP_UE_SERVER_FILE_NOT_FOUND = (-102);
|
||||
constexpr int HTTP_UE_SERVER_FORBIDDEN = (-103);
|
||||
constexpr int HTTP_UE_SERVER_WRONG_HTTP_CODE = (-104);
|
||||
constexpr int HTTP_UE_SERVER_FAULTY_MD5 = (-105);
|
||||
constexpr int HTTP_UE_BIN_VERIFY_HEADER_FAILED = (-106);
|
||||
constexpr int HTTP_UE_BIN_FOR_WRONG_FLASH = (-107);
|
||||
constexpr int HTTP_UE_SERVER_UNAUTHORIZED = (-108);
|
||||
|
||||
enum HTTPUpdateResult {
|
||||
HTTP_UPDATE_FAILED,
|
||||
HTTP_UPDATE_NO_UPDATES,
|
||||
HTTP_UPDATE_OK
|
||||
};
|
||||
|
||||
typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility
|
||||
|
||||
using HTTPUpdateStartCB = std::function<void()>;
|
||||
using HTTPUpdateEndCB = std::function<void()>;
|
||||
using HTTPUpdateErrorCB = std::function<void(int)>;
|
||||
using HTTPUpdateProgressCB = std::function<void(int, int)>;
|
||||
|
||||
class HTTPUpdate {
|
||||
public:
|
||||
HTTPUpdate(void);
|
||||
HTTPUpdate(int httpClientTimeout);
|
||||
~HTTPUpdate(void);
|
||||
|
||||
void rebootOnUpdate(bool reboot) {
|
||||
_rebootOnUpdate = reboot;
|
||||
}
|
||||
|
||||
/**
|
||||
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 available modes.
|
||||
@param follow
|
||||
*/
|
||||
void setFollowRedirects(followRedirects_t follow) {
|
||||
_followRedirects = follow;
|
||||
}
|
||||
|
||||
void closeConnectionsOnUpdate(bool sever) {
|
||||
_closeConnectionsOnUpdate = sever;
|
||||
}
|
||||
|
||||
void setMD5sum(const String &md5Sum) {
|
||||
_md5Sum = md5Sum;
|
||||
}
|
||||
|
||||
void setAuthorization(const String& user, const String& password);
|
||||
void setAuthorization(const String& auth);
|
||||
|
||||
t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = "");
|
||||
t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/",
|
||||
const String& currentVersion = "");
|
||||
t_httpUpdate_return updateFS(WiFiClient& client, const String& url, const String& currentVersion = "");
|
||||
|
||||
t_httpUpdate_return update(const String& url, const String& currentVersion = "");
|
||||
t_httpUpdate_return update(const String& host, uint16_t port, const String& uri = "/", const String& currentVersion = "");
|
||||
t_httpUpdate_return updateFS(const String& url, const String& currentVersion = "");
|
||||
|
||||
// Notification callbacks
|
||||
void onStart(HTTPUpdateStartCB cbOnStart) {
|
||||
_cbStart = cbOnStart;
|
||||
}
|
||||
void onEnd(HTTPUpdateEndCB cbOnEnd) {
|
||||
_cbEnd = cbOnEnd;
|
||||
}
|
||||
void onError(HTTPUpdateErrorCB cbOnError) {
|
||||
_cbError = cbOnError;
|
||||
}
|
||||
void onProgress(HTTPUpdateProgressCB cbOnProgress) {
|
||||
_cbProgress = cbOnProgress;
|
||||
}
|
||||
|
||||
int getLastError(void);
|
||||
String getLastErrorString(void);
|
||||
|
||||
protected:
|
||||
t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false);
|
||||
bool runUpdate(Stream& in, uint32_t size, const String& md5, int command = U_FLASH);
|
||||
|
||||
// Set the error and potentially use a CB to notify the application
|
||||
void _setLastError(int err) {
|
||||
_lastError = err;
|
||||
if (_cbError) {
|
||||
_cbError(err);
|
||||
}
|
||||
}
|
||||
int _lastError;
|
||||
bool _rebootOnUpdate = true;
|
||||
bool _closeConnectionsOnUpdate = true;
|
||||
String _user;
|
||||
String _password;
|
||||
String _auth;
|
||||
String _md5Sum;
|
||||
private:
|
||||
int _httpClientTimeout;
|
||||
followRedirects_t _followRedirects = HTTPC_DISABLE_FOLLOW_REDIRECTS;
|
||||
|
||||
// Callbacks
|
||||
HTTPUpdateStartCB _cbStart;
|
||||
HTTPUpdateEndCB _cbEnd;
|
||||
HTTPUpdateErrorCB _cbError;
|
||||
HTTPUpdateProgressCB _cbProgress;
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE)
|
||||
extern HTTPUpdate httpUpdate;
|
||||
#endif
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
return write((uint32_t)s);
|
||||
}
|
||||
|
||||
// Write 32 bit value to port, user responsbile for packing/alignment, etc.
|
||||
// Write 32 bit value to port, user responsible for packing/alignment, etc.
|
||||
size_t write(int32_t val, bool sync);
|
||||
|
||||
// Write sample to I2S port, will block until completed
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
size_t write24(int32_t l, int32_t r); // Note that 24b must have values left-aligned (i.e. 0xABCDEF00)
|
||||
size_t write32(int32_t l, int32_t r);
|
||||
|
||||
// Read 32 bit value to port, user responsbile for packing/alignment, etc.
|
||||
// Read 32 bit value to port, user responsible for packing/alignment, etc.
|
||||
size_t read(int32_t *val, bool sync);
|
||||
|
||||
// Read samples from I2S port, will block until data available
|
||||
|
||||
@@ -1100,7 +1100,7 @@ protected:
|
||||
};
|
||||
|
||||
public:
|
||||
uint16_t m_u16ID; // Query ID (used only in lagacy queries)
|
||||
uint16_t m_u16ID; // Query ID (used only in legacy queries)
|
||||
stcMDNS_RRQuestion* m_pQuestions; // A list of queries
|
||||
uint8_t m_u8HostReplyMask; // Flags for reply components/answers
|
||||
bool m_bLegacyQuery; // Flag: Legacy query
|
||||
|
||||
@@ -1980,7 +1980,7 @@ uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader&
|
||||
#ifdef MDNS_IP6_SUPPORT
|
||||
// TODO
|
||||
#endif
|
||||
} // Address qeuest
|
||||
} // Address quest
|
||||
|
||||
stcMDNS_RRDomain hostDomain;
|
||||
if ((_buildDomainForHost(m_pcHostname, hostDomain))
|
||||
|
||||
@@ -32,8 +32,12 @@
|
||||
|
||||
class SDClass {
|
||||
public:
|
||||
boolean begin(uint8_t csPin, uint32_t cfg = SPI_HALF_SPEED) {
|
||||
SDFS.setConfig(SDFSConfig(csPin, cfg));
|
||||
boolean begin(uint8_t csPin, HardwareSPI &spi) {
|
||||
SDFS.setConfig(SDFSConfig(csPin, SPI_HALF_SPEED, spi));
|
||||
return (boolean)SDFS.begin();
|
||||
}
|
||||
boolean begin(uint8_t csPin, uint32_t cfg = SPI_HALF_SPEED, HardwareSPI &spi = SPI) {
|
||||
SDFS.setConfig(SDFSConfig(csPin, cfg, spi));
|
||||
return (boolean)SDFS.begin();
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class SDFSConfig : public FSConfig {
|
||||
public:
|
||||
static constexpr uint32_t FSId = 0x53444653;
|
||||
|
||||
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { }
|
||||
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10), HardwareSPI &port = SPI) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi), _spi(&port) { }
|
||||
|
||||
SDFSConfig setAutoFormat(bool val = true) {
|
||||
_autoFormat = val;
|
||||
@@ -55,10 +55,14 @@ public:
|
||||
_csPin = pin;
|
||||
return *this;
|
||||
}
|
||||
SDFSConfig setSPI(uint32_t spi) {
|
||||
SDFSConfig setSPISpeed(uint32_t spi) {
|
||||
_spiSettings = spi;
|
||||
return *this;
|
||||
}
|
||||
SDFSConfig setSPI(HardwareSPI &spi) {
|
||||
_spi = &spi;
|
||||
return true;
|
||||
}
|
||||
SDFSConfig setPart(uint8_t part) {
|
||||
_part = part;
|
||||
return *this;
|
||||
@@ -68,6 +72,7 @@ public:
|
||||
uint8_t _csPin;
|
||||
uint8_t _part;
|
||||
uint32_t _spiSettings;
|
||||
HardwareSPI *_spi;
|
||||
};
|
||||
|
||||
class SDFSImpl : public FSImpl {
|
||||
@@ -146,10 +151,11 @@ public:
|
||||
if (_mounted) {
|
||||
return true;
|
||||
}
|
||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||
SdSpiConfig ssc(_cfg._csPin, SHARED_SPI, _cfg._spiSettings, _cfg._spi);
|
||||
_mounted = _fs.begin(ssc);
|
||||
if (!_mounted && _cfg._autoFormat) {
|
||||
format();
|
||||
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
|
||||
_mounted = _fs.begin(ssc);
|
||||
}
|
||||
FsDateTime::setCallback(dateTimeCB);
|
||||
return _mounted;
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <hardware/flash.h>
|
||||
#include <PicoOTA.h>
|
||||
|
||||
#define DEBUG_UPDATER Serial
|
||||
|
||||
#include <Updater_Signing.h>
|
||||
#ifndef ARDUINO_SIGNING
|
||||
#define ARDUINO_SIGNING 0
|
||||
@@ -200,7 +198,7 @@ bool UpdaterClass::end(bool evenIfRemaining) {
|
||||
|
||||
int binSize = _size;
|
||||
if (expectedSigLen > 0) {
|
||||
_size -= (sigLen + sizeof(uint32_t) /* The siglen word */);
|
||||
binSize -= (sigLen + sizeof(uint32_t) /* The siglen word */);
|
||||
}
|
||||
_hash->begin();
|
||||
#ifdef DEBUG_UPDATER
|
||||
@@ -414,30 +412,37 @@ void UpdaterClass::_setError(int error) {
|
||||
}
|
||||
|
||||
void UpdaterClass::printError(Print &out) {
|
||||
out.printf_P(PSTR("ERROR[%u]: "), _error);
|
||||
String err;
|
||||
err = "ERROR[";
|
||||
err += _error;
|
||||
err += "]: ";
|
||||
if (_error == UPDATE_ERROR_OK) {
|
||||
out.println(F("No Error"));
|
||||
err += "No Error";
|
||||
} else if (_error == UPDATE_ERROR_WRITE) {
|
||||
out.println(F("Flash Write Failed"));
|
||||
err += "Flash Write Failed";
|
||||
} else if (_error == UPDATE_ERROR_ERASE) {
|
||||
out.println(F("Flash Erase Failed"));
|
||||
err += "Flash Erase Failed";
|
||||
} else if (_error == UPDATE_ERROR_READ) {
|
||||
out.println(F("Flash Read Failed"));
|
||||
err += "Flash Read Failed";
|
||||
} else if (_error == UPDATE_ERROR_SPACE) {
|
||||
out.println(F("Not Enough Space"));
|
||||
err += "Not Enough Space";
|
||||
} else if (_error == UPDATE_ERROR_SIZE) {
|
||||
out.println(F("Bad Size Given"));
|
||||
err += "Bad Size Given";
|
||||
} else if (_error == UPDATE_ERROR_STREAM) {
|
||||
out.println(F("Stream Read Timeout"));
|
||||
err += "Stream Read Timeout";
|
||||
} else if (_error == UPDATE_ERROR_NO_DATA) {
|
||||
out.println(F("No data supplied"));
|
||||
err += "No data supplied";
|
||||
} else if (_error == UPDATE_ERROR_MD5) {
|
||||
out.printf_P(PSTR("MD5 Failed: expected:%s, calculated:%s\n"), _target_md5.c_str(), _md5.toString().c_str());
|
||||
err += "MD5 Failed: expected:";
|
||||
err += _target_md5.c_str();
|
||||
err += " calculated:";
|
||||
err += _md5.toString();
|
||||
} else if (_error == UPDATE_ERROR_SIGN) {
|
||||
out.println(F("Signature verification failed"));
|
||||
err += "Signature verification failed";
|
||||
} else {
|
||||
out.println(F("UNKNOWN"));
|
||||
err += "UNKNOWN";
|
||||
}
|
||||
out.println(err.c_str());
|
||||
}
|
||||
|
||||
UpdaterClass Update;
|
||||
|
||||
@@ -16,6 +16,8 @@ const char* password = STAPSK;
|
||||
const char* host = "djxmmx.net";
|
||||
const uint16_t port = 17;
|
||||
|
||||
WiFiMulti multi;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
@@ -26,11 +28,12 @@ void setup() {
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
multi.addAP(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
if (multi.run() != WL_CONNECTED) {
|
||||
Serial.println("Unable to connect to network, rebooting in 10 seconds...");
|
||||
delay(10000);
|
||||
rp2040.reboot();
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
|
||||
@@ -13,6 +13,7 @@ WiFiClient KEYWORD1
|
||||
WiFiSSLClient KEYWORD1
|
||||
WiFiServer KEYWORD1
|
||||
WiFiUDP KEYWORD1
|
||||
WiFiMulti KEYWORD1
|
||||
NTP KEYWORD1
|
||||
|
||||
|
||||
@@ -48,6 +49,7 @@ parsePacket KEYWORD2
|
||||
remoteIP KEYWORD2
|
||||
remotePort KEYWORD2
|
||||
mode KEYWORD2
|
||||
addAP KEYWORD2
|
||||
|
||||
beginAP KEYWORD2
|
||||
beginEnterprise KEYWORD2
|
||||
@@ -61,6 +63,26 @@ beginMulticast KEYWORD2
|
||||
setTimeout KEYWORD2
|
||||
waitSet KEYWORD2
|
||||
|
||||
setSession KEYWORD2
|
||||
setInsecure KEYWORD2
|
||||
setKnownKey KEYWORD2
|
||||
setFingerprint KEYWORD2
|
||||
allowSelfSignedCerts KEYWORD2
|
||||
setTrustAnchors KEYWORD2
|
||||
setX509Time KEYWORD2
|
||||
setClientRSACert KEYWORD2
|
||||
setClientECCert KEYWORD2
|
||||
setBufferSizes KEYWORD2
|
||||
setCertStore KEYWORD2
|
||||
setCiphers KEYWORD2
|
||||
setCiphersLessSecure KEYWORD2
|
||||
setSSLVersion KEYWORD2
|
||||
setCACert KEYWORD2
|
||||
setCertificate KEYWORD2
|
||||
setPrivateKey KEYWORD2
|
||||
loadCACert KEYWORD2
|
||||
loadCertificate KEYWORD2
|
||||
loadPrivateKey KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
#include <string.h>
|
||||
#include <Arduino.h>
|
||||
#include "StackThunk.h"
|
||||
//#include <Updater_Signing.h>
|
||||
|
||||
#include <Updater_Signing.h>
|
||||
#ifndef ARDUINO_SIGNING
|
||||
#define ARDUINO_SIGNING 0
|
||||
#endif
|
||||
|
||||
@@ -12,4 +12,6 @@
|
||||
#include "WiFiServerSecure.h"
|
||||
#include "WiFiUdp.h"
|
||||
|
||||
#include "WiFiMulti.h"
|
||||
|
||||
#include "WiFiNTP.h"
|
||||
|
||||
@@ -96,6 +96,8 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
// Enable CYW43 event debugging (make sure Debug Port is set)
|
||||
//cyw43_state.trace_flags = 0xffff;
|
||||
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
|
||||
delay(10);
|
||||
}
|
||||
@@ -152,7 +154,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
|
||||
#endif
|
||||
|
||||
bool WiFiClass::connected() {
|
||||
return (_apMode && _wifiHWInitted) || (_wifi.connected() && localIP().isSet());
|
||||
return (_apMode && _wifiHWInitted) || (_wifi.connected() && localIP().isSet() && (cyw43_wifi_link_status(&cyw43_state, _apMode ? 1 : 0) == CYW43_LINK_JOIN));
|
||||
}
|
||||
|
||||
/* Change Ip configuration settings disabling the dhcp client
|
||||
@@ -223,6 +225,9 @@ void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) {
|
||||
void WiFiClass::setHostname(const char* name) {
|
||||
_wifi.setHostname(name);
|
||||
}
|
||||
const char *WiFiClass::getHostname() {
|
||||
return _wifi.getHostname();
|
||||
}
|
||||
|
||||
/*
|
||||
Disconnect from the network
|
||||
|
||||
@@ -91,6 +91,57 @@ public:
|
||||
uint8_t beginAP(const char *ssid, const char* passphrase);
|
||||
uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel);
|
||||
|
||||
// ESP8266 compatible calls
|
||||
bool softAP(const char* ssid, const char* psk = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4) {
|
||||
(void) ssid_hidden;
|
||||
(void) max_connection;
|
||||
return beginAP(ssid, psk, channel) == WL_CONNECTED;
|
||||
}
|
||||
|
||||
bool softAP(const String& ssid, const String& psk = "", int channel = 1, int ssid_hidden = 0, int max_connection = 4) {
|
||||
(void) ssid_hidden;
|
||||
(void) max_connection;
|
||||
if (psk != "") {
|
||||
return beginAP(ssid.c_str(), psk.c_str(), channel) == WL_CONNECTED;
|
||||
} else {
|
||||
return beginAP(ssid.c_str(), channel) == WL_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) {
|
||||
config(local_ip, local_ip, gateway, subnet);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool softAPdisconnect(bool wifioff = false) {
|
||||
(void) wifioff;
|
||||
end();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t softAPgetStationNum();
|
||||
|
||||
IPAddress softAPIP() {
|
||||
return localIP();
|
||||
}
|
||||
|
||||
uint8_t* softAPmacAddress(uint8_t* mac) {
|
||||
return macAddress(mac);
|
||||
}
|
||||
|
||||
String softAPmacAddress(void) {
|
||||
uint8_t mac[8];
|
||||
macAddress(mac);
|
||||
char buff[32];
|
||||
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
|
||||
return String(buff);
|
||||
}
|
||||
|
||||
String softAPSSID() {
|
||||
return String(SSID());
|
||||
}
|
||||
|
||||
|
||||
// TODO - EAP is not supported by the driver. Maybe some way of user-level wap-supplicant in the future?
|
||||
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password);
|
||||
//uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity);
|
||||
@@ -147,6 +198,7 @@ public:
|
||||
|
||||
*/
|
||||
void setHostname(const char* name);
|
||||
const char *getHostname();
|
||||
|
||||
/*
|
||||
Disconnect from the network
|
||||
@@ -163,6 +215,13 @@ public:
|
||||
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* macAddress(uint8_t* mac);
|
||||
String macAddress(void) {
|
||||
uint8_t mac[8];
|
||||
macAddress(mac);
|
||||
char buff[32];
|
||||
sprintf(buff, "%02x:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
|
||||
return String(buff);
|
||||
}
|
||||
|
||||
/*
|
||||
Get the interface IP address.
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "WiFi.h"
|
||||
#include "Print.h"
|
||||
#include "Client.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
@@ -1224,7 +1224,7 @@ bool WiFiClientSecureCtx::_connectSSL(const char* hostName) {
|
||||
_x509_insecure = nullptr;
|
||||
_x509_knownkey = nullptr;
|
||||
|
||||
// reduce timeout after successful handshake to fail fast if server stop accepting our data for whathever reason
|
||||
// reduce timeout after successful handshake to fail fast if server stop accepting our data for whatever reason
|
||||
if (ret) {
|
||||
_timeout = 5000;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
WiFiMulti.cpp - Choose best RSSI and connect
|
||||
Copyright (c) 2022 Earle F. Philhower, III
|
||||
|
||||
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
|
||||
|
||||
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
|
||||
*/
|
||||
|
||||
#include "WiFi.h"
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
WiFiMulti::WiFiMulti() {
|
||||
}
|
||||
|
||||
WiFiMulti::~WiFiMulti() {
|
||||
while (!_list.empty()) {
|
||||
struct _AP ap = _list.front();
|
||||
_list.pop_front();
|
||||
free(ap.ssid);
|
||||
free(ap.pass);
|
||||
}
|
||||
}
|
||||
|
||||
bool WiFiMulti::addAP(const char *ssid, const char *pass) {
|
||||
struct _AP ap;
|
||||
if (!ssid) {
|
||||
return false;
|
||||
}
|
||||
ap.ssid = strdup(ssid);
|
||||
if (!ap.ssid) {
|
||||
return false;
|
||||
}
|
||||
if (pass) {
|
||||
ap.pass = strdup(pass);
|
||||
if (!ap.pass) {
|
||||
free(ap.ssid);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ap.pass = nullptr;
|
||||
}
|
||||
DEBUGV("[WIFIMULTI] Adding: '%s' %s' to list\n", ap.ssid, ap.pass);
|
||||
_list.push_front(ap);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t WiFiMulti::run(uint32_t to) {
|
||||
|
||||
// If we're already connected, don't re-scan/etc.
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
return WL_CONNECTED;
|
||||
}
|
||||
|
||||
int cnt = WiFi.scanNetworks();
|
||||
if (!cnt) {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
|
||||
// Find the highest RSSI network in our list. Probably more efficient searches, but the list
|
||||
// of APs will have < 5 in > 99% of the cases so it's a don't care.
|
||||
int maxRSSID = -999;
|
||||
std::list<struct _AP>::iterator hit;
|
||||
bool found = false;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (WiFi.RSSI(i) > maxRSSID) {
|
||||
for (auto j = _list.begin(); j != _list.end(); j++) {
|
||||
DEBUGV("[WIFIMULTI] Checking for '%s' at %d\n", WiFi.SSID(i), WiFi.RSSI(i));
|
||||
if (!strcmp(j->ssid, WiFi.SSID(i))) {
|
||||
hit = j;
|
||||
maxRSSID = WiFi.RSSI(i);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
|
||||
// Connect!
|
||||
DEBUGV("[WIFIMULTI] Connecting to '%s' and '%s'\n", hit->ssid, hit->pass);
|
||||
uint32_t start = millis();
|
||||
if (hit->pass) {
|
||||
WiFi.begin(hit->ssid, hit->pass);
|
||||
} else {
|
||||
WiFi.begin(hit->ssid);
|
||||
}
|
||||
while (!WiFi.connected() && (millis() - start < to)) {
|
||||
delay(5);
|
||||
}
|
||||
return WiFi.status();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
WiFiMulti.h - Choose best RSSI and connect
|
||||
Copyright (c) 2022 Earle F. Philhower, III
|
||||
|
||||
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
|
||||
|
||||
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <stdint.h>
|
||||
#include "wl_definitions.h"
|
||||
|
||||
class WiFiMulti {
|
||||
public:
|
||||
WiFiMulti();
|
||||
~WiFiMulti();
|
||||
|
||||
bool addAP(const char *ssid, const char *pass = NULL);
|
||||
|
||||
uint8_t run(uint32_t to = 10000);
|
||||
|
||||
private:
|
||||
struct _AP {
|
||||
char *ssid;
|
||||
char *pass;
|
||||
};
|
||||
std::list<struct _AP> _list;
|
||||
};
|
||||
@@ -63,7 +63,7 @@
|
||||
#define PORT_DHCP_SERVER (67)
|
||||
#define PORT_DHCP_CLIENT (68)
|
||||
|
||||
#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
|
||||
//#define DEFAULT_DNS MAKE_IP4(8, 8, 8, 8)
|
||||
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds
|
||||
|
||||
#define MAC_LEN (6)
|
||||
@@ -276,9 +276,10 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
||||
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, ip_2_ip4(&d->ip));
|
||||
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, ip_2_ip4(&d->nm));
|
||||
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, ip_2_ip4(&d->ip)); // aka gateway; can have multiple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses
|
||||
opt_write_n(&opt, DHCP_OPT_DNS, 4, ip_2_ip4(&d->ip)); // can have multiple addresses
|
||||
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
|
||||
*opt++ = DHCP_OPT_END;
|
||||
|
||||
dhcp_socket_sendto(&d->udp, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
|
||||
|
||||
ignore_request:
|
||||
|
||||
@@ -43,7 +43,7 @@ extern "C" {
|
||||
#define WL_IPV4_LENGTH 4
|
||||
// Maximum size of a SSID list
|
||||
#define WL_NETWORKS_LIST_MAXNUM 10
|
||||
// Maxmium number of socket
|
||||
// Maximum number of socket
|
||||
#define WIFI_MAX_SOCK_NUM 10
|
||||
// Socket not available constant
|
||||
#define SOCK_NOT_AVAIL 255
|
||||
|
||||
@@ -26,6 +26,18 @@ extern "C" {
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// From cyw43_ctrl.c
|
||||
#define WIFI_JOIN_STATE_KIND_MASK (0x000f)
|
||||
#define WIFI_JOIN_STATE_ACTIVE (0x0001)
|
||||
#define WIFI_JOIN_STATE_FAIL (0x0002)
|
||||
#define WIFI_JOIN_STATE_NONET (0x0003)
|
||||
#define WIFI_JOIN_STATE_BADAUTH (0x0004)
|
||||
#define WIFI_JOIN_STATE_AUTH (0x0200)
|
||||
#define WIFI_JOIN_STATE_LINK (0x0400)
|
||||
#define WIFI_JOIN_STATE_KEYED (0x0800)
|
||||
#define WIFI_JOIN_STATE_ALL (0x0e01)
|
||||
|
||||
|
||||
netif *CYW43::_netif = nullptr;
|
||||
|
||||
CYW43::CYW43(int8_t cs, arduino::SPIClass& spi, int8_t intrpin) {
|
||||
@@ -124,6 +136,7 @@ extern "C" void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
|
||||
if (CYW43::_netif) {
|
||||
netif_set_link_down(CYW43::_netif);
|
||||
}
|
||||
self->wifi_join_state &= ~WIFI_JOIN_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
extern "C" int cyw43_tcpip_link_status(cyw43_t *self, int itf) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Simple sketch to do something on a BOOTSEL press */
|
||||
/* Releaed into the public domain */
|
||||
/* Released into the public domain */
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.20400.0",
|
||||
"version": "1.20401.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@
|
||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||
|
||||
name=Raspberry Pi RP2040 Boards
|
||||
version=2.4.0
|
||||
version=2.4.1
|
||||
|
||||
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
|
||||
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
|
||||
@@ -110,7 +110,7 @@ recipe.hooks.sketch.prebuild.pattern="{runtime.tools.pqt-python3.path}/python3"
|
||||
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
|
||||
|
||||
## Compile c++ files
|
||||
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
|
||||
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" -I "{build.path}/core" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
|
||||
|
||||
## Compile S files
|
||||
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {includes} "{source_file}" -o "{object_file}"
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
|
||||
./libraries/WiFi ./libraries/lwIP_Ethernet ./libraries/lwIP_CYW43 \
|
||||
./libraries/FreeRTOS/src ./libraries/LEAmDNS ./libraries/MD5Builder \
|
||||
./libraries/PicoOTA ./libraries/SDFS ./libraries/ArduinoOTA \
|
||||
./libraries/Updater; do
|
||||
./libraries/Updater ./libraries/HTTPClient ./libraries/HTTPUpdate; do
|
||||
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;
|
||||
find $dir -type f -name "*.ino" -exec astyle --suffix=none --options=./tests/astyle_examples.conf \{\} \;
|
||||
done
|
||||
|
||||
+1
-3
@@ -65,9 +65,7 @@ def compile(tmp_dir, sketch, cache, tools_dir, hardware_dir, ide_path, f, args):
|
||||
'dbgport={dbgport},' \
|
||||
'dbglvl={dbglvl},' \
|
||||
'usbstack={usbstack}'.format(**vars(args))
|
||||
if "/WiFi" in sketch:
|
||||
fqbn = fqbn.replace("rpipico", "rpipicow")
|
||||
if "/ArduinoOTA" in sketch:
|
||||
if ("/WiFi" in sketch) or ("/ArduinoOTA" in sketch) or ("/HTTPClient" in sketch) or ('/HTTPUpdate' in sketch):
|
||||
fqbn = fqbn.replace("rpipico", "rpipicow")
|
||||
cmd += [fqbn]
|
||||
cmd += ['-built-in-libraries', ide_path + '/libraries']
|
||||
|
||||
Reference in New Issue
Block a user