mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-03-18 23:56:32 +03:00
use ESP_SSLClient for mqtt, add sendmail command (using readymail)
This commit is contained in:
@@ -49,6 +49,10 @@ the LICENSE file.
|
||||
#define EMC_CLIENTID_LENGTH 23 + 1
|
||||
#endif
|
||||
|
||||
#ifdef EMSESP_MQTT_STACKSIZE
|
||||
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
|
||||
#endif
|
||||
|
||||
#ifndef EMC_TASK_STACK_SIZE
|
||||
#define EMC_TASK_STACK_SIZE 5120
|
||||
#endif
|
||||
|
||||
@@ -62,7 +62,11 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
||||
_xSemaphore = xSemaphoreCreateMutex();
|
||||
EMC_SEMAPHORE_GIVE(); // release before first use
|
||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
||||
if (core > 1) {
|
||||
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
|
||||
} else {
|
||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void) useInternalTask;
|
||||
@@ -70,6 +74,7 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
||||
(void) core;
|
||||
#endif
|
||||
_clientId = _generatedClientId;
|
||||
_core = core;
|
||||
}
|
||||
|
||||
MqttClient::~MqttClient() {
|
||||
|
||||
@@ -69,7 +69,17 @@ class MqttClient {
|
||||
const char* getClientId() const;
|
||||
size_t queueSize(); // No const because of mutex
|
||||
void loop();
|
||||
|
||||
uint32_t stack() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
return uxTaskGetStackHighWaterMark(_taskHandle);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
uint8_t core() {
|
||||
return _core;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
|
||||
espMqttClientTypes::UseInternalTask _useInternalTask;
|
||||
@@ -98,6 +108,7 @@ class MqttClient {
|
||||
uint8_t _willQos;
|
||||
bool _willRetain;
|
||||
uint32_t _timeout;
|
||||
uint8_t _core;
|
||||
|
||||
// state is protected to allow state changes by the transport system, defined in child classes
|
||||
// eg. to allow AsyncTCP
|
||||
|
||||
@@ -9,18 +9,16 @@ the LICENSE file.
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
|
||||
#include "ClientSecureSync.h"
|
||||
#include "mbedtls_ssl.h" // triggers compilation of mbedtls SSL module (stripped from Tasmota libmbedtls.a)
|
||||
|
||||
#include <cstring>
|
||||
#include <lwip/sockets.h>
|
||||
#include <fcntl.h>
|
||||
#include "../Config.h"
|
||||
|
||||
namespace espMqttClientInternals {
|
||||
|
||||
ClientSecureSync::ClientSecureSync()
|
||||
: _tls(nullptr)
|
||||
, _cfg{}
|
||||
, _connected(false) {
|
||||
: client() {
|
||||
client.setClient(&basic_client, true);
|
||||
client.setBufferSizes(EMC_RX_BUFFER_SIZE, EMC_TX_BUFFER_SIZE);
|
||||
client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds)
|
||||
}
|
||||
|
||||
ClientSecureSync::~ClientSecureSync() {
|
||||
@@ -28,133 +26,43 @@ ClientSecureSync::~ClientSecureSync() {
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connect(IPAddress ip, uint16_t port) {
|
||||
char host[16];
|
||||
sprintf(host, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
return connect(host, port);
|
||||
bool ret = client.connect(ip, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connect(const char * host, uint16_t port) {
|
||||
stop(); // clean up any previous connection
|
||||
|
||||
_tls = esp_tls_init();
|
||||
if (!_tls) {
|
||||
return false;
|
||||
bool ret = client.connect(host, port); // implicit conversion of return code int --> bool
|
||||
if (ret) {
|
||||
// Set TCP option directly to bypass lack of working setNoDelay for WiFiClientSecure
|
||||
int val = true;
|
||||
basic_client.setSocketOption(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
|
||||
}
|
||||
|
||||
if (esp_tls_conn_new_sync(host, strlen(host), port, &_cfg, _tls) <= 0) {
|
||||
esp_tls_conn_destroy(_tls);
|
||||
_tls = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
_connected = true;
|
||||
|
||||
// Set TCP_NODELAY and non-blocking mode on the underlying socket
|
||||
int fd = -1;
|
||||
if (esp_tls_get_conn_sockfd(_tls, &fd) == ESP_OK && fd >= 0) {
|
||||
int val = 1;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
// Make socket non-blocking so reads don't stall the MQTT event loop
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags >= 0) {
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t ClientSecureSync::write(const uint8_t * buf, size_t size) {
|
||||
if (!_tls || !_connected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write all data, retrying on WANT_WRITE (non-blocking socket)
|
||||
size_t written = 0;
|
||||
while (written < size) {
|
||||
int ret = esp_tls_conn_write(_tls, buf + written, size - written);
|
||||
if (ret > 0) {
|
||||
written += ret;
|
||||
} else if (ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ) {
|
||||
continue; // retry
|
||||
} else {
|
||||
_connected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
return client.write(buf, size);
|
||||
}
|
||||
|
||||
int ClientSecureSync::read(uint8_t * buf, size_t size) {
|
||||
if (!_tls || !_connected) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = esp_tls_conn_read(_tls, buf, size);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
if (ret == ESP_TLS_ERR_SSL_WANT_READ || ret == ESP_TLS_ERR_SSL_WANT_WRITE) {
|
||||
return -1; // no data available yet, still connected
|
||||
}
|
||||
// Connection closed or error
|
||||
_connected = false;
|
||||
return -1;
|
||||
return client.read(buf, size);
|
||||
}
|
||||
|
||||
void ClientSecureSync::stop() {
|
||||
if (_tls) {
|
||||
esp_tls_conn_destroy(_tls);
|
||||
_tls = nullptr;
|
||||
}
|
||||
_connected = false;
|
||||
client.stop();
|
||||
}
|
||||
|
||||
bool ClientSecureSync::connected() {
|
||||
return _connected && _tls != nullptr;
|
||||
return client.connected();
|
||||
}
|
||||
|
||||
bool ClientSecureSync::disconnected() {
|
||||
return !connected();
|
||||
}
|
||||
|
||||
void ClientSecureSync::setCACert(const char * rootCA) {
|
||||
_cfg.cacert_pem_buf = reinterpret_cast<const unsigned char *>(rootCA);
|
||||
_cfg.cacert_pem_bytes = strlen(rootCA) + 1;
|
||||
}
|
||||
|
||||
void ClientSecureSync::setCertificate(const char * clientCert) {
|
||||
_cfg.clientcert_pem_buf = reinterpret_cast<const unsigned char *>(clientCert);
|
||||
_cfg.clientcert_pem_bytes = strlen(clientCert) + 1;
|
||||
}
|
||||
|
||||
void ClientSecureSync::setPrivateKey(const char * privateKey) {
|
||||
_cfg.clientkey_pem_buf = reinterpret_cast<const unsigned char *>(privateKey);
|
||||
_cfg.clientkey_pem_bytes = strlen(privateKey) + 1;
|
||||
}
|
||||
|
||||
void ClientSecureSync::setPreSharedKey(const char * pskIdent, const char * psKey) {
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
_psk.hint = pskIdent;
|
||||
size_t key_len = strlen(psKey) / 2;
|
||||
if (key_len > sizeof(_psk_key)) {
|
||||
key_len = sizeof(_psk_key);
|
||||
}
|
||||
for (size_t i = 0; i < key_len; i++) {
|
||||
sscanf(psKey + 2 * i, "%2hhx", &_psk_key[i]);
|
||||
}
|
||||
_psk.key = _psk_key;
|
||||
_psk.key_size = key_len;
|
||||
_cfg.psk_hint_key = &_psk;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClientSecureSync::setInsecure() {
|
||||
_cfg.cacert_pem_buf = nullptr;
|
||||
_cfg.cacert_pem_bytes = 0;
|
||||
_cfg.crt_bundle_attach = nullptr;
|
||||
_cfg.use_global_ca_store = false;
|
||||
_cfg.skip_common_name = true;
|
||||
return !client.connected();
|
||||
}
|
||||
|
||||
} // namespace espMqttClientInternals
|
||||
|
||||
@@ -10,7 +10,9 @@ the LICENSE file.
|
||||
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
|
||||
#include "esp_tls.h"
|
||||
// #include "esp_tls.h"
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP_SSLClient.h>
|
||||
#include "Transport.h"
|
||||
|
||||
namespace espMqttClientInternals {
|
||||
@@ -27,21 +29,8 @@ class ClientSecureSync : public Transport {
|
||||
bool connected() override;
|
||||
bool disconnected() override;
|
||||
|
||||
// TLS configuration (call before connect)
|
||||
void setCACert(const char * rootCA);
|
||||
void setCertificate(const char * clientCert);
|
||||
void setPrivateKey(const char * privateKey);
|
||||
void setPreSharedKey(const char * pskIdent, const char * psKey);
|
||||
void setInsecure();
|
||||
|
||||
private:
|
||||
esp_tls_t * _tls;
|
||||
esp_tls_cfg_t _cfg;
|
||||
bool _connected;
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
psk_hint_key_t _psk;
|
||||
unsigned char _psk_key[64];
|
||||
#endif
|
||||
WiFiClient basic_client;
|
||||
ESP_SSLClient client;
|
||||
};
|
||||
|
||||
} // namespace espMqttClientInternals
|
||||
|
||||
@@ -8,50 +8,6 @@ the LICENSE file.
|
||||
|
||||
#include "espMqttClient.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
espMqttClient::espMqttClient()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
|
||||
espMqttClientSecure::espMqttClientSecure()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO)
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
||||
_client.client.setInsecure();
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setFingerprint(const uint8_t fingerprint[20]) {
|
||||
_client.client.setFingerprint(fingerprint);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setTrustAnchors(const X509List * ta) {
|
||||
_client.client.setTrustAnchors(ta);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setClientRSACert(const X509List * cert, const PrivateKey * sk) {
|
||||
_client.client.setClientRSACert(cert, sk);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setClientECCert(const X509List * cert, const PrivateKey * sk, unsigned allowed_usages, unsigned cert_issuer_key_type) {
|
||||
_client.client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCertStore(CertStoreBase * certStore) {
|
||||
_client.client.setCertStore(certStore);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask)
|
||||
: MqttClientSetup(useInternalTask)
|
||||
@@ -79,35 +35,34 @@ espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setInsecure() {
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.setInsecure();
|
||||
_client.client.setInsecure();
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCACert(const char * rootCA) {
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.setCACert(rootCA);
|
||||
_client.client.setCACert(rootCA);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setCertificate(const char * clientCa) {
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.setCertificate(clientCa);
|
||||
_client.client.setCertificate(clientCa);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setPrivateKey(const char * privateKey) {
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.setPrivateKey(privateKey);
|
||||
_client.client.setPrivateKey(privateKey);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
espMqttClientSecure & espMqttClientSecure::setPreSharedKey(const char * pskIdent, const char * psKey) {
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
_client.setPreSharedKey(pskIdent, psKey);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
@@ -120,9 +75,4 @@ espMqttClient::espMqttClient()
|
||||
, _client() {
|
||||
_transport = &_client;
|
||||
}
|
||||
#elif defined(_WIN32) || defined(__APPLE__)
|
||||
// Windows
|
||||
espMqttClient::espMqttClient()
|
||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::NO) {
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,10 +65,16 @@ class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
||||
espMqttClientSecure & setPreSharedKey(const char * pskIdent, const char * psKey);
|
||||
|
||||
protected:
|
||||
#ifndef NO_TLS_SUPPORT
|
||||
espMqttClientInternals::ClientSecureSync _client;
|
||||
#else
|
||||
espMqttClientInternals::ClientSync _client;
|
||||
#endif
|
||||
};
|
||||
|
||||
#elif defined(__linux__)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
public:
|
||||
espMqttClient();
|
||||
@@ -76,10 +82,4 @@ class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
protected:
|
||||
espMqttClientInternals::ClientPosix _client;
|
||||
};
|
||||
#elif defined(_WIN32) || defined(__APPLE__)
|
||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||
public:
|
||||
espMqttClient();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user