* Migrate esp32 families to pioarduino platform * ESP32c6 align text.handler_execute same as C3 * Use pioarduino `develop` The latest fixes and the latest bugs! * preliminary esp32p4.ini * pioarduino: Update LovyanGFX Includes Manuel's recent commit * pioarduino 3.3.6 * pioarduino 3.3.6 *release* chasing the release * pioarduino: Fix OG ESP32 duplicate libs * pioarduino: T-Beam 1W CDC mode * pioarduino: disable network provisioning (wifiprov) * pioarduino: use legacy esptoolpy naming (forward-compatible) * Update lovyangfx from `develop` commit to 1.2.19 * fix esp32p4.ini * check for esp32 w/ wifi * esp32-p4 specific adaptations * Switch to meshtastic/esp32_https_server fork (idf5 branch) * don't ignore esp_lcd * config for MUI * fix/workaround SDMMC * revert a6f6175, update to 3.3.8 * enable esp_hosted for esp32-p4 (experimental) * Pioarduino 55.03.38-1 * NimBLE-Arduino -> Arduino "BLE" (3.3.x) migration (#10164) * NimBLE-Arduino -> Arduino "BLE" (3.3.x) migration * More NimBLE * Fix Device Name in ATT Read Request (0x2A00). Device Name is exposed in two places: - Advertisement data: this is set properly in startAdvertising. - GATT attribute Device Name (0x2A00). This one is handled internally in NimBLE and comes from ble_svc_gap_device_name_set. This is set initially, but then BLEDevice::createServer calls ble_svc_gap_init which resets the device name. This causes the device to apparently "change name after pairing": < ACL Data TX:... flags 0x00 dlen 7 #113 [hci0] 14.241149 ATT: Read Request (0x0a) len 2 Handle: 0x0003 Type: Device Name (0x2a00) > ACL Data RX: Handle 2048 flags 0x02 dlen 11 #115 [hci0] 14.269050 ATT: Read Response (0x0b) len 6 Value[6]: 6e696d626c65 # "nimble" Workaround this by setting the device name once again after BLEDevice::createServer. * Temporarily lower CORE_DEBUG_LEVEL to INFO to avoid triggering an apparent ESP-IDF Bluetooth bug when re-connecting to Pixel 8 Android devices. Initial pairing works, but after ESP32 is rebooted, phone fails to reconnect. Meshtastic app shows it as disconnecting immediately. LightBlue shows a more detailed error "Peripheral Connection - Warning: onConnectionStatusChange: status 61" (0x3D - MIC Failure). Bug report to Espresssif: https://github.com/espressif/esp-idf/issues/18126#issuecomment-4286197744 * Temporarily disable ble_gap_set_data_len, causes crash with Pixel 8 Android reconnect. Crash looks like this: [ 11966][E][BLEAdvertising.cpp:341] setScanResponseData(): ble_gap_adv_rsp_set_data: 22 [ 11975][E][BLEAdvertising.cpp:1554] start(): Host reset, wait for sync. ERROR | ??:??:?? 11 BLE failed to start advertising Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled. Core 0 register dump: PC : 0x420e6190 PS : 0x00060730 A0 : 0x820e158b A1 : 0x3fce50c0 A2 : 0x00000000 A3 : 0x3fcb8600 A4 : 0x3fcb85cc A5 : 0x00000000 A6 : 0x00000000 A7 : 0x00000c03 A8 : 0x00000000 A9 : 0x3fce50b0 A10 : 0x0000000e A11 : 0x00000000 A12 : 0x00000010 A13 : 0x3fce50e0 A14 : 0x00000c03 A15 : 0x00000001 SAR : 0x0000001e EXCCAUSE: 0x0000001c EXCVADDR: 0x00000000 LBEG : 0x400570e8 LEND : 0x400570f3 LCOUNT : 0x00000000 Backtrace: 0x420e618d:0x3fce50c0 0x420e1588:0x3fce5110 0x420dfe87:0x3fce5200 0x420dfefb:0x3fce5220 0x420dff3f:0x3fce5240 0x4219602b:0x3fce5260 0x4037b0e5:0x3fce5280 0x4201edf3:0x3fce52a0 Connection seems fast enough even without this. We'll investigate the reason for the crash and re-enable once it's safe. --------- Co-authored-by: Catalin Patulea <cronos586@gmail.com> * Add extension from pioarduino nag "Jason2866.esp-decoder" * Cleanup after merge * ESP32: Disable classic bluetooth * Cleanup: Fix ADC channels on new variants * InkHUD: Fix type casting for message size in saveToFlash method inkhud compiles again! * update p4 esp_hosted for BT * I thought I fixed this * fix linker error using response file (p4 only) * fix infinite loop * Fix Power.cpp check warning Local variable 'config' shadows outer variable [shadowVariable] * Build ESP32 original with NimBLE ('custom_sdkconfig' approach). (#10235) * Re-enable littlefs json manifest This works locally again :) Not sure what changed * Re-add tool-mklittlefs * sensecap indicator fixes after upgrade arduino-esp & lovyanGFX libs * hackaday fix * robot tbeam cache error fix Co-authored-by: Copilot <copilot@github.com> * trunk fmt * ignore trunk * BLEDevice::deinit() added Co-authored-by: Copilot <copilot@github.com> * platformio-custom: Modify mtjson target dependency to prevent fake-success. (#10291) Co-authored-by: Copilot <copilot@github.com> * Fix ESP32-C6 linker errors. Align .text.handler_execute section to 4 bytes and update watchdog timer core mask configuration Co-authored-by: Copilot <copilot@github.com> * tlora-c6: Disable Screen MESHTASTIC_EXCLUDE_SCREEN=1 on tlora-c6. It doesn't have a screen, and this gets it compiling again (saving flash). * Use mverch's iram_memset hack for all OG-ESP32 * Refactor watchdog timer initialization and handling * use adc_channel_t in variant.h * Fix variant headers * More idiomatic default ethernet that doesn't break the build * Elecrows: Delete problematic variant.cpp Not needed after USE_ETHERNET_DEFAULT --------- Co-authored-by: mverch67 <manuel.verch@gmx.de> Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> Co-authored-by: Catalin Patulea <cronos586@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com> Co-authored-by: Copilot <copilot@github.com> Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
269 lines
7.9 KiB
C++
269 lines
7.9 KiB
C++
#include "configuration.h"
|
|
#if !MESHTASTIC_EXCLUDE_WEBSERVER
|
|
#include "NodeDB.h"
|
|
#include "graphics/Screen.h"
|
|
#include "main.h"
|
|
#include "mesh/http/WebServer.h"
|
|
#include "mesh/wifi/WiFiAPClient.h"
|
|
#include "sleep.h"
|
|
#include <HTTPBodyParser.hpp>
|
|
#include <HTTPMultipartBodyParser.hpp>
|
|
#include <HTTPURLEncodedBodyParser.hpp>
|
|
#include <Throttle.h>
|
|
#include <WebServer.h>
|
|
#include <WiFi.h>
|
|
|
|
#if HAS_ETHERNET && defined(ARCH_ESP32)
|
|
#include <ETH.h>
|
|
#endif // HAS_ETHERNET
|
|
|
|
#ifdef ARCH_ESP32
|
|
#include "esp_task_wdt.h"
|
|
#endif
|
|
|
|
// Persistent Data Storage
|
|
#include <Preferences.h>
|
|
Preferences prefs;
|
|
|
|
/*
|
|
Including the esp32_https_server library will trigger a compile time error. I've
|
|
tracked it down to a reoccurrance of this bug:
|
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824
|
|
The work around is described here:
|
|
https://forums.xilinx.com/t5/Embedded-Development-Tools/Error-with-Standard-Libaries-in-Zynq/td-p/450032
|
|
|
|
Long story short is we need "#undef str" before including the esp32_https_server.
|
|
- Jm Casler (jm@casler.org) Oct 2020
|
|
*/
|
|
#undef str
|
|
|
|
// Includes for the https server
|
|
// https://github.com/fhessel/esp32_https_server
|
|
#include <HTTPRequest.hpp>
|
|
#include <HTTPResponse.hpp>
|
|
#include <HTTPSServer.hpp>
|
|
#include <HTTPServer.hpp>
|
|
#include <SSLCert.hpp>
|
|
|
|
// The HTTPS Server comes in a separate namespace. For easier use, include it here.
|
|
using namespace httpsserver;
|
|
#include "mesh/http/ContentHandler.h"
|
|
|
|
static const uint32_t ACTIVE_THRESHOLD_MS = 5000;
|
|
static const uint32_t MEDIUM_THRESHOLD_MS = 30000;
|
|
static const int32_t ACTIVE_INTERVAL_MS = 50;
|
|
static const int32_t MEDIUM_INTERVAL_MS = 200;
|
|
static const int32_t IDLE_INTERVAL_MS = 1000;
|
|
|
|
// Maximum concurrent HTTPS connections (reduced from default 4 to save memory)
|
|
static const uint8_t MAX_HTTPS_CONNECTIONS = 2;
|
|
|
|
// Minimum free heap required for SSL handshake (~40KB for mbedTLS contexts)
|
|
static const uint32_t MIN_HEAP_FOR_SSL = 40000;
|
|
|
|
static SSLCert *cert;
|
|
static HTTPSServer *secureServer;
|
|
static HTTPServer *insecureServer;
|
|
|
|
volatile bool isWebServerReady;
|
|
volatile bool isCertReady;
|
|
|
|
static void handleWebResponse()
|
|
{
|
|
if (isWifiAvailable()) {
|
|
|
|
if (isWebServerReady) {
|
|
// Check heap before HTTPS processing - SSL requires significant memory
|
|
if (secureServer) {
|
|
uint32_t freeHeap = ESP.getFreeHeap();
|
|
if (freeHeap >= MIN_HEAP_FOR_SSL) {
|
|
secureServer->loop();
|
|
} else {
|
|
// Skip HTTPS when memory is low to prevent SSL setup failures
|
|
static uint32_t lastHeapWarning = 0;
|
|
if (lastHeapWarning == 0 || !Throttle::isWithinTimespanMs(lastHeapWarning, 30000)) {
|
|
LOG_WARN("Low heap (%u bytes), skipping HTTPS processing", freeHeap);
|
|
lastHeapWarning = millis();
|
|
}
|
|
}
|
|
}
|
|
insecureServer->loop();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void taskCreateCert(void *parameter)
|
|
{
|
|
prefs.begin("MeshtasticHTTPS", false);
|
|
|
|
#if 0
|
|
// Delete the saved certs (used in debugging)
|
|
LOG_DEBUG("Delete any saved SSL keys");
|
|
// prefs.clear();
|
|
prefs.remove("PK");
|
|
prefs.remove("cert");
|
|
#endif
|
|
|
|
LOG_INFO("Checking if we have a saved SSL Certificate");
|
|
|
|
size_t pkLen = prefs.getBytesLength("PK");
|
|
size_t certLen = prefs.getBytesLength("cert");
|
|
|
|
if (pkLen && certLen) {
|
|
LOG_INFO("Existing SSL Certificate found!");
|
|
|
|
uint8_t *pkBuffer = new uint8_t[pkLen];
|
|
prefs.getBytes("PK", pkBuffer, pkLen);
|
|
|
|
uint8_t *certBuffer = new uint8_t[certLen];
|
|
prefs.getBytes("cert", certBuffer, certLen);
|
|
|
|
cert = new SSLCert(certBuffer, certLen, pkBuffer, pkLen);
|
|
|
|
LOG_DEBUG("Retrieved Private Key: %d Bytes", cert->getPKLength());
|
|
LOG_DEBUG("Retrieved Certificate: %d Bytes", cert->getCertLength());
|
|
} else {
|
|
|
|
LOG_INFO("Creating the certificate. This may take a while. Please wait");
|
|
yield();
|
|
cert = new SSLCert();
|
|
yield();
|
|
int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=meshtastic.local,O=Meshtastic,C=US",
|
|
"20190101000000", "20300101000000");
|
|
yield();
|
|
|
|
if (createCertResult != 0) {
|
|
LOG_ERROR("Creating the certificate failed");
|
|
} else {
|
|
LOG_INFO("Creating the certificate was successful");
|
|
|
|
LOG_DEBUG("Created Private Key: %d Bytes", cert->getPKLength());
|
|
|
|
LOG_DEBUG("Created Certificate: %d Bytes", cert->getCertLength());
|
|
|
|
prefs.putBytes("PK", (uint8_t *)cert->getPKData(), cert->getPKLength());
|
|
prefs.putBytes("cert", (uint8_t *)cert->getCertData(), cert->getCertLength());
|
|
}
|
|
}
|
|
|
|
isCertReady = true;
|
|
|
|
// Must delete self, can't just fall out
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
void createSSLCert()
|
|
{
|
|
if (isWifiAvailable() && !isCertReady) {
|
|
bool runLoop = false;
|
|
|
|
// Create a new process just to handle creating the cert.
|
|
// This is a workaround for Bug: https://github.com/fhessel/esp32_https_server/issues/48
|
|
// jm@casler.org (Oct 2020)
|
|
xTaskCreate(taskCreateCert, /* Task function. */
|
|
"createCert", /* String with name of task. */
|
|
// 16384, /* Stack size in bytes. */
|
|
8192, /* Stack size in bytes. */
|
|
NULL, /* Parameter passed as input of the task */
|
|
16, /* Priority of the task. */
|
|
NULL); /* Task handle. */
|
|
|
|
LOG_DEBUG("Waiting for SSL Cert to be generated");
|
|
while (!isCertReady) {
|
|
if ((millis() / 500) % 2) {
|
|
if (runLoop) {
|
|
LOG_DEBUG(".");
|
|
|
|
yield();
|
|
esp_task_wdt_reset();
|
|
#if HAS_SCREEN
|
|
if (millis() / 1000 >= 3) {
|
|
if (screen)
|
|
screen->setSSLFrames();
|
|
}
|
|
#endif
|
|
}
|
|
runLoop = false;
|
|
} else {
|
|
runLoop = true;
|
|
}
|
|
}
|
|
LOG_INFO("SSL Cert Ready!");
|
|
}
|
|
}
|
|
|
|
WebServerThread *webServerThread;
|
|
|
|
WebServerThread::WebServerThread() : concurrency::OSThread("WebServer")
|
|
{
|
|
if (!config.network.wifi_enabled && !config.network.eth_enabled) {
|
|
disable();
|
|
}
|
|
lastActivityTime = millis();
|
|
}
|
|
|
|
void WebServerThread::markActivity()
|
|
{
|
|
lastActivityTime = millis();
|
|
}
|
|
|
|
int32_t WebServerThread::getAdaptiveInterval()
|
|
{
|
|
uint32_t currentTime = millis();
|
|
uint32_t timeSinceActivity;
|
|
|
|
if (currentTime >= lastActivityTime) {
|
|
timeSinceActivity = currentTime - lastActivityTime;
|
|
} else {
|
|
timeSinceActivity = (UINT32_MAX - lastActivityTime) + currentTime + 1;
|
|
}
|
|
|
|
if (timeSinceActivity < ACTIVE_THRESHOLD_MS) {
|
|
return ACTIVE_INTERVAL_MS;
|
|
} else if (timeSinceActivity < MEDIUM_THRESHOLD_MS) {
|
|
return MEDIUM_INTERVAL_MS;
|
|
} else {
|
|
return IDLE_INTERVAL_MS;
|
|
}
|
|
}
|
|
|
|
int32_t WebServerThread::runOnce()
|
|
{
|
|
if (!config.network.wifi_enabled && !config.network.eth_enabled) {
|
|
disable();
|
|
}
|
|
|
|
handleWebResponse();
|
|
|
|
if (requestRestart && (millis() / 1000) > requestRestart) {
|
|
ESP.restart();
|
|
}
|
|
|
|
return getAdaptiveInterval();
|
|
}
|
|
|
|
void initWebServer()
|
|
{
|
|
LOG_DEBUG("Init Web Server");
|
|
|
|
// We can now use the new certificate to setup our server as usual.
|
|
secureServer = new HTTPSServer(cert, 443, MAX_HTTPS_CONNECTIONS);
|
|
insecureServer = new HTTPServer();
|
|
|
|
registerHandlers(insecureServer, secureServer);
|
|
|
|
if (secureServer) {
|
|
LOG_INFO("Start Secure Web Server");
|
|
secureServer->start();
|
|
}
|
|
LOG_INFO("Start Insecure Web Server");
|
|
insecureServer->start();
|
|
if (insecureServer->isRunning()) {
|
|
LOG_INFO("Web Servers Ready! :-) ");
|
|
isWebServerReady = true;
|
|
} else {
|
|
LOG_ERROR("Web Servers Failed! ;-( ");
|
|
}
|
|
}
|
|
#endif
|