From 060b6bf67ef5a6cf06079fccfa89333abfcbbe42 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Jun 2024 11:37:13 +0700 Subject: [PATCH] Add support session timeout setting which requires when ESP32 WiFiClient was used --- README.md | 27 ++++++- .../Custom_Secure_Port/Custom_Secure_Port.ino | 6 ++ examples/HTTP_Upgrade/HTTP_Upgrade.ino | 6 ++ examples/HTTPs/https.ino | 6 ++ examples/MQTT/MQTT.ino | 6 ++ examples/Session/Session.ino | 6 ++ keywords.txt | 2 +- library.json | 2 +- library.properties | 2 +- src/ESP_SSLClient.h | 4 +- src/client/BSSL_SSL_Client.cpp | 70 ++++++++++++++++++- src/client/BSSL_SSL_Client.h | 13 +++- src/client/BSSL_TCP_Client.cpp | 14 +++- src/client/BSSL_TCP_Client.h | 24 +++++-- 14 files changed, 170 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f312110..ab448ce 100644 --- a/README.md +++ b/README.md @@ -253,9 +253,17 @@ return **`operating result`**. bool connectSSL(); ``` -### Get the TCP timeout in seconds. +### Set the TCP connection timeout in seconds. -return **`The TCP timeout`** in seconds. +param **`seconds`** The TCP connection timeout in seconds. + +```cpp +int setTimeout(uint32_t seconds); +``` + +### Get the TCP connection timeout in seconds. + +return **`The TCP connection timeout`** in seconds. ```cpp int getTimeout(); @@ -269,6 +277,21 @@ param **`handshake_timeout`** The SSL handshake timeout in seconds. void setHandshakeTimeout(unsigned long handshake_timeout); ``` +### Set the TCP session timeout in seconds. + +param **`seconds`** The TCP session timeout in seconds. + +The minimum session timeout value is 60 seconds. + +Set 0 to disable session timed out. + +If There is no data to send (write) within this period, the current connection will be closed and reconnect. + +This requires when ESP32 WiFiClient was used. + +```cpp +int setSessionTimeout(uint32_t seconds); +``` ## MIT License diff --git a/examples/Custom_Secure_Port/Custom_Secure_Port.ino b/examples/Custom_Secure_Port/Custom_Secure_Port.ino index b66c6db..a2574b7 100644 --- a/examples/Custom_Secure_Port/Custom_Secure_Port.ino +++ b/examples/Custom_Secure_Port/Custom_Secure_Port.ino @@ -86,6 +86,12 @@ void setup() */ ssl_client.setDebugLevel(1); + // In case ESP32 WiFiClient, the session timeout should be set, + // if the TCP session was kept alive because it was unable to detect the server disconnection. +#if defined(ESP32) + ssl_client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) +#endif + // Assign the basic client to use in non-secure mode. ssl_client.setClient(&basic_client, false /* set enable SSL option to false */); } diff --git a/examples/HTTP_Upgrade/HTTP_Upgrade.ino b/examples/HTTP_Upgrade/HTTP_Upgrade.ino index 9610f80..8d3da8e 100644 --- a/examples/HTTP_Upgrade/HTTP_Upgrade.ino +++ b/examples/HTTP_Upgrade/HTTP_Upgrade.ino @@ -82,6 +82,12 @@ void setup() */ ssl_client.setDebugLevel(1); + // In case ESP32 WiFiClient, the session timeout should be set, + // if the TCP session was kept alive because it was unable to detect the server disconnection. +#if defined(ESP32) + ssl_client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) +#endif + // Assign the basic client // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existed // as long as it was used by ssl_client for transportation. diff --git a/examples/HTTPs/https.ino b/examples/HTTPs/https.ino index 1ff0a40..afc3eae 100644 --- a/examples/HTTPs/https.ino +++ b/examples/HTTPs/https.ino @@ -83,6 +83,12 @@ void setup() */ ssl_client.setDebugLevel(1); + // In case ESP32 WiFiClient, the session timeout should be set, + // if the TCP session was kept alive because it was unable to detect the server disconnection. +#if defined(ESP32) + ssl_client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) +#endif + // Assign the basic client // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existed // as long as it was used by ssl_client for transportation. diff --git a/examples/MQTT/MQTT.ino b/examples/MQTT/MQTT.ino index 8fa949e..13f88ff 100644 --- a/examples/MQTT/MQTT.ino +++ b/examples/MQTT/MQTT.ino @@ -100,6 +100,12 @@ void setup() */ ssl_client.setDebugLevel(1); + // In case ESP32 WiFiClient, the session timeout should be set, + // if the TCP session was kept alive because it was unable to detect the server disconnection. +#if defined(ESP32) + ssl_client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) +#endif + // Assign the basic client // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existed // as long as it was used by ssl_client for transportation. diff --git a/examples/Session/Session.ino b/examples/Session/Session.ino index 139276e..d7922bc 100644 --- a/examples/Session/Session.ino +++ b/examples/Session/Session.ino @@ -203,6 +203,12 @@ void setup() */ ssl_client.setDebugLevel(1); + // In case ESP32 WiFiClient, the session timeout should be set, + // if the TCP session was kept alive because it was unable to detect the server disconnection. +#if defined(ESP32) + ssl_client.setSessionTimeout(120); // Set the timeout in seconds (>=120 seconds) +#endif + // Assign the basic client // Due to the basic_client pointer is assigned, to avoid dangling pointer, basic_client should be existed // as long as it was used by ssl_client for transportation. diff --git a/keywords.txt b/keywords.txt index 4104bfe..6d53bdc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -23,7 +23,6 @@ peek KEYWORD2 setInsecure KEYWORD2 enableSSL KEYWORD2 connectSSL KEYWORD2 -setTimeout KEYWORD2 flush KEYWORD2 setBufferSizes KEYWORD2 setPreSharedKey KEYWORD2 @@ -36,6 +35,7 @@ loadPrivateKey KEYWORD2 verify KEYWORD2 setHandshakeTimeout KEYWORD2 setTimeout KEYWORD2 +setSessionTimeout KEYWORD2 stop KEYWORD2 availableForWrite KEYWORD2 setSession KEYWORD2 diff --git a/library.json b/library.json index 9e79102..e1cdb77 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP_SSLClient", - "version": "2.1.8", + "version": "2.1.9", "keywords": "communication, REST, esp32, esp8266, arduino", "description": "This library provided the Secure Layer Networking (SSL/TLS) TCP Client for ESP8266, ESP32 and Raspberry Pi RP2040, Teensy, SAMD, AVR and other Arduino devices (except for avr) that support external networking interfaces e.g., WiFiClient, EthernetClient and GSMClient.", "repository": { diff --git a/library.properties b/library.properties index da57b9a..1ae1bfc 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=ESP_SSLClient -version=2.1.8 +version=2.1.9 author=Mobizt diff --git a/src/ESP_SSLClient.h b/src/ESP_SSLClient.h index d5b6b2a..a97a6b3 100644 --- a/src/ESP_SSLClient.h +++ b/src/ESP_SSLClient.h @@ -1,8 +1,8 @@ /** * - * The ESP SSL Client Class, ESP_SSLClient.h v2.1.8 + * The ESP SSL Client Class, ESP_SSLClient.h v2.1.9 * - * Created June 12, 2024 + * Created June 27, 2024 * * The MIT License (MIT) * Copyright (c) 2023 K. Suwatchai (Mobizt) diff --git a/src/client/BSSL_SSL_Client.cpp b/src/client/BSSL_SSL_Client.cpp index 6c015de..355afcd 100644 --- a/src/client/BSSL_SSL_Client.cpp +++ b/src/client/BSSL_SSL_Client.cpp @@ -1,7 +1,7 @@ /** - * BSSL_SSL_Client library v1.0.13 for Arduino devices. + * BSSL_SSL_Client library v1.0.14 for Arduino devices. * - * Created June 12, 2024 + * Created June 27, 2024 * * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. * @@ -132,6 +132,9 @@ int BSSL_SSL_Client::connect(IPAddress ip, uint16_t port) if (!mConnectBasicClient(nullptr, ip, port)) return 0; + _connect_with_ip = true; + _session_ts = millis(); + return 1; } @@ -143,6 +146,9 @@ int BSSL_SSL_Client::connect(const char *host, uint16_t port) if (!mConnectBasicClient(host, IPAddress(), port)) return 0; + _connect_with_ip = false; + _session_ts = millis(); + return 1; } @@ -276,15 +282,21 @@ size_t BSSL_SSL_Client::write(const uint8_t *buf, size_t size) if (!mIsClientInitialized(false)) return 0; + if (!mCheckSessionTimeout()) + return 0; + + _session_ts = millis(); + if (!_secure) return _basic_client->write(buf, size); - const char *func_name = __func__; #if defined(ESP_SSLCLIENT_ENABLE_DEBUG) // super debug if (_debug_level >= esp_ssl_debug_dump) ESP_SSLCLIENT_DEBUG_PORT.write(buf, size); #endif + + const char *func_name = __func__; // check if the socket is still open and such if (!mSoftConnected(func_name) || !buf || !size) return 0; @@ -440,6 +452,7 @@ int BSSL_SSL_Client::connectSSL(IPAddress ip, uint16_t port) _ip = ip; _port = port; + _connect_with_ip = true; return mConnectSSL(nullptr); } @@ -455,6 +468,7 @@ int BSSL_SSL_Client::connectSSL(const char *host, uint16_t port) _host = host; _port = port; + _connect_with_ip = false; return mConnectSSL(host); } @@ -497,6 +511,8 @@ void BSSL_SSL_Client::setTimeout(unsigned int timeoutMs) { _timeout_ms = timeout void BSSL_SSL_Client::setHandshakeTimeout(unsigned int timeoutMs) { _handshake_timeout = timeoutMs; } +void BSSL_SSL_Client::setSessionTimeout(uint32_t seconds) { _tcp_session_timeout = seconds; } + void BSSL_SSL_Client::flush() { if (!_secure && _basic_client) @@ -1091,6 +1107,7 @@ BSSL_SSL_Client &BSSL_SSL_Client::operator=(const BSSL_SSL_Client &other) _use_insecure = other._use_insecure; _timeout_ms = other._timeout_ms; _handshake_timeout = other._handshake_timeout; + _tcp_session_timeout = other._tcp_session_timeout; return *this; } @@ -1574,6 +1591,7 @@ int BSSL_SSL_Client::mConnectSSL(const char *host) _handshake_done = true; _is_connected = true; _secure = true; + _session_ts = millis(); // Save session if (_session) @@ -1600,6 +1618,52 @@ bool BSSL_SSL_Client::mConnectionValidate(const char *host, IPAddress ip, uint16 _basic_client->stop(); } + mCheckSessionTimeout(); + + return true; +} + +bool BSSL_SSL_Client::mCheckSessionTimeout() +{ + const char *func_name = __func__; + + if (_tcp_session_timeout >= BSSL_SSL_CLIENT_MIN_SESSION_TIMEOUT_SEC && _session_ts > 0 && millis() - _session_ts > _tcp_session_timeout * 1000) + { + if (_basic_client && _basic_client->connected()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("The session was timed out. Starting new server connection."), _debug_level, esp_ssl_debug_info, func_name); +#endif + int ret = 0; + if (!_secure) + { + _basic_client->flush(); + _basic_client->stop(); + + if (_connect_with_ip) + ret = connect(_ip, _port); + else + ret = connect(_host.c_str(), _port); + } + else + { + stop(); + if (_connect_with_ip) + ret = connectSSL(_ip, _port); + else + ret = connectSSL(_host.c_str(), _port); + } + + if (!ret) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Failed while starting new server connection."), _debug_level, esp_ssl_debug_error, func_name); +#endif + return false; + } + } + } + return true; } diff --git a/src/client/BSSL_SSL_Client.h b/src/client/BSSL_SSL_Client.h index 44a75ba..302646c 100644 --- a/src/client/BSSL_SSL_Client.h +++ b/src/client/BSSL_SSL_Client.h @@ -1,7 +1,7 @@ /** - * BSSL_SSL_Client library v1.0.13 for Arduino devices. + * BSSL_SSL_Client library v1.0.14 for Arduino devices. * - * Created June 12, 2024 + * Created June 27, 2024 * * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. * @@ -46,6 +46,8 @@ #define EMBED_SSL_ENGINE_BASE_OVERRIDE #endif +#define BSSL_SSL_CLIENT_MIN_SESSION_TIMEOUT_SEC 60 + #if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) #include @@ -141,6 +143,8 @@ class BSSL_SSL_Client : public Client void setHandshakeTimeout(unsigned int timeoutMs); + void setSessionTimeout(uint32_t seconds); + void flush() override; void setBufferSizes(int recv, int xmit); @@ -247,6 +251,8 @@ class BSSL_SSL_Client : public Client bool mConnectionValidate(const char *host, IPAddress ip, uint16_t port); + bool mCheckSessionTimeout(); + int mRunUntil(const unsigned target, unsigned long timeout = 0); unsigned mUpdateEngine(); @@ -346,10 +352,13 @@ class BSSL_SSL_Client : public Client // Renameing from _timeout which also defined in parent's Stream class. unsigned long _timeout_ms = 15000; unsigned long _handshake_timeout = 60000; + unsigned long _tcp_session_timeout = 0; + unsigned long _session_ts = 0; bool _isSSLEnabled = false; String _host; uint16_t _port = 0; IPAddress _ip; + bool _connect_with_ip = false; }; #endif diff --git a/src/client/BSSL_TCP_Client.cpp b/src/client/BSSL_TCP_Client.cpp index 9e5159e..a0b141d 100644 --- a/src/client/BSSL_TCP_Client.cpp +++ b/src/client/BSSL_TCP_Client.cpp @@ -1,7 +1,7 @@ /** - * BSSL_TCP_Client v2.0.13 for Arduino devices. + * BSSL_TCP_Client v2.0.14 for Arduino devices. * - * Created June 12, 2024 + * Created June 27, 2024 * * The MIT License (MIT) * Copyright (c) 2023 K. Suwatchai (Mobizt) @@ -279,6 +279,14 @@ void BSSL_TCP_Client::setHandshakeTimeout(unsigned long handshake_timeout) _ssl_client.setHandshakeTimeout(_handshake_timeout); } +void BSSL_TCP_Client::setSessionTimeout(uint32_t seconds) +{ + if (seconds > 0 && seconds < BSSL_SSL_CLIENT_MIN_SESSION_TIMEOUT_SEC) + seconds = BSSL_SSL_CLIENT_MIN_SESSION_TIMEOUT_SEC; + _tcp_session_timeout = seconds; + _ssl_client.setSessionTimeout(seconds); +} + void BSSL_TCP_Client::flush() { if (!_basic_client) @@ -426,8 +434,10 @@ BSSL_TCP_Client &BSSL_TCP_Client::operator=(const BSSL_TCP_Client &other) _use_insecure = other._use_insecure; _timeout_ms = other._timeout_ms; _handshake_timeout = other._handshake_timeout; + _tcp_session_timeout = other._tcp_session_timeout; _ssl_client.setTimeout(_timeout_ms); _ssl_client.setHandshakeTimeout(_handshake_timeout); + _ssl_client.setSessionTimeout(_tcp_session_timeout); if (_use_insecure) _ssl_client.setInsecure(); return *this; diff --git a/src/client/BSSL_TCP_Client.h b/src/client/BSSL_TCP_Client.h index 8e80257..c88ea94 100644 --- a/src/client/BSSL_TCP_Client.h +++ b/src/client/BSSL_TCP_Client.h @@ -1,7 +1,7 @@ /** - * BSSL_TCP_Client v2.0.13 for Arduino devices. + * BSSL_TCP_Client v2.0.14 for Arduino devices. * - * Created June 12, 2024 + * Created June 27, 2024 * * The MIT License (MIT) * Copyright (c) 2023 K. Suwatchai (Mobizt) @@ -298,13 +298,13 @@ class BSSL_TCP_Client : public Client void stop() override; /** - * Set the TCP timeout in seconds. + * Set the TCP connection timeout in seconds. * @param seconds The TCP timeout in seconds. */ int setTimeout(uint32_t seconds); /** - * Get the TCP timeout in seconds. + * Get the TCP connection timeout in seconds. * @return The TCP timeout in seconds. */ int getTimeout(); @@ -315,6 +315,21 @@ class BSSL_TCP_Client : public Client */ void setHandshakeTimeout(unsigned long handshake_timeout); + /** + * Set the TCP session timeout in seconds. + * + * @param seconds The TCP session timeout in seconds. + * + * The minimum session timeout value is 60 seconds. + * Set 0 to disable session timed out. + * + * If There is no data to send (write) within this period, + * the current connection will be closed and reconnect. + * + * This requires when ESP32 WiFiClient was used. + */ + void setSessionTimeout(uint32_t seconds); + /** * Wait for all receive buffer data read. */ @@ -427,6 +442,7 @@ class BSSL_TCP_Client : public Client // Renameing from _timeout which also defined in parent's Stream class. unsigned long _timeout_ms = 15000; unsigned long _handshake_timeout = 60000; + unsigned long _tcp_session_timeout = 0; char *mStreamLoad(Stream &stream, size_t size); };