diff options
author | erwin freebsd <erwin.freebsd-bugzilla@bk3.nl> | 2025-05-16 13:18:15 +0200 |
---|---|---|
committer | Xavier Beaudouin <kiwi@FreeBSD.org> | 2025-05-16 16:02:12 +0200 |
commit | 2265bb7f1054b01eafc34b3619be028cd222a402 (patch) | |
tree | 99386fb3668b4176616b731b3272939c16366eea /www/domoticz/files/patch-pr6252 | |
parent | archivers/zstd: Add CPE information (diff) |
www/domoticz*: Fix build for boost >= 1.87
With boost >= 1.87, domoticz cannot be built. This has been
handled by PR 6252 on domoticz github.
I'm adding the patches to files/ because they do not apply
cleanly unfortunately when managed via PATCH_SITES.
The problem is that the upstream patch modifies the
msbuild-related parts of the build system. Those parts are
not relevant on FreeBSD and has been already removed in
previous updates. So adding modified version of the patches
from the GitHub PR to files/ seems to be the right approach.
PR: 286076
Reported by: <erwin.freebsd-bugzilla@bk3.nl>
Approved by: 0mp (mentor)
Differential Revision: https://reviews.freebsd.org/D50373
Diffstat (limited to 'www/domoticz/files/patch-pr6252')
-rw-r--r-- | www/domoticz/files/patch-pr6252 | 2178 |
1 files changed, 2178 insertions, 0 deletions
diff --git a/www/domoticz/files/patch-pr6252 b/www/domoticz/files/patch-pr6252 new file mode 100644 index 000000000000..34c4efd3f4e4 --- /dev/null +++ b/www/domoticz/files/patch-pr6252 @@ -0,0 +1,2178 @@ +Fix for boost 1.87 + +Removed the diff for the msbuild project files, didn't apply cleanly and not relevant anyway. +This will merged in the next stable of domoticz. + +Pullrequest: https://github.com/domoticz/domoticz/pull/6252 +Patch: https://patch-diff.githubusercontent.com/raw/domoticz/domoticz/pull/6252.patch-diff + +diff --git hardware/ASyncSerial.cpp hardware/ASyncSerial.cpp +index 52c950d..6147cdb 100644 +--- hardware/ASyncSerial.cpp ++++ hardware/ASyncSerial.cpp +@@ -54,7 +54,7 @@ public: + { + } + +- boost::asio::io_service io; ///< Io service object ++ boost::asio::io_context io; ///< Io service object + boost::asio::serial_port port; ///< Serial port object + boost::thread backgroundThread; ///< Thread that runs read/write operations + bool open{ false }; ///< True if port open +@@ -117,10 +117,10 @@ void AsyncSerial::open(const std::string& devname, unsigned int baud_rate, + throw; + } + +- pimpl->io.reset(); ++ pimpl->io.restart(); + +- // This gives some work to the io_service before it is started +- pimpl->io.post([this] { return doRead(); }); ++ // This gives some work to the io_context before it is started ++ boost::asio::post(pimpl->io, [this] { return doRead(); }); + + boost::thread t([p = &pimpl->io] { p->run(); }); + pimpl->backgroundThread.swap(t); +@@ -149,10 +149,10 @@ void AsyncSerial::openOnlyBaud(const std::string& devname, unsigned int baud_rat + throw; + } + +- pimpl->io.reset(); ++ pimpl->io.restart(); + +- //This gives some work to the io_service before it is started +- pimpl->io.post([this] { return doRead(); }); ++ //This gives some work to the io_context before it is started ++ boost::asio::post(pimpl->io, [this] { return doRead(); }); + + boost::thread t([p = &pimpl->io] { p->run(); }); + pimpl->backgroundThread.swap(t); +@@ -176,9 +176,9 @@ void AsyncSerial::close() + if(!isOpen()) return; + + pimpl->open = false; +- pimpl->io.post([this] { doClose(); }); ++ boost::asio::post(pimpl->io, [this] { doClose(); }); + pimpl->backgroundThread.join(); +- pimpl->io.reset(); ++ pimpl->io.restart(); + if(errorStatus()) + { + throw(boost::system::system_error(boost::system::error_code(), +@@ -192,7 +192,7 @@ void AsyncSerial::write(const char *data, size_t size) + std::lock_guard<std::mutex> l(pimpl->writeQueueMutex); + pimpl->writeQueue.insert(pimpl->writeQueue.end(),data,data+size); + } +- pimpl->io.post([this] { doWrite(); }); ++ boost::asio::post(pimpl->io, [this] { doWrite(); }); + } + + void AsyncSerial::write(const std::string &data) +@@ -201,7 +201,7 @@ void AsyncSerial::write(const std::string &data) + std::lock_guard<std::mutex> l(pimpl->writeQueueMutex); + pimpl->writeQueue.insert(pimpl->writeQueue.end(), data.c_str(), data.c_str()+data.size()); + } +- pimpl->io.post([this] { doWrite(); }); ++ boost::asio::post(pimpl->io, [this] { doWrite(); }); + } + + void AsyncSerial::write(const std::vector<char>& data) +@@ -211,7 +211,7 @@ void AsyncSerial::write(const std::vector<char>& data) + pimpl->writeQueue.insert(pimpl->writeQueue.end(),data.begin(), + data.end()); + } +- pimpl->io.post([this] { doWrite(); }); ++ boost::asio::post(pimpl->io, [this] { doWrite(); }); + } + + void AsyncSerial::writeString(const std::string& s) +@@ -220,7 +220,7 @@ void AsyncSerial::writeString(const std::string& s) + std::lock_guard<std::mutex> l(pimpl->writeQueueMutex); + pimpl->writeQueue.insert(pimpl->writeQueue.end(),s.begin(),s.end()); + } +- pimpl->io.post([this] { doWrite(); }); ++ boost::asio::post(pimpl->io, [this] { doWrite(); }); + } + + void AsyncSerial::doRead() +diff --git hardware/ASyncSerial.h hardware/ASyncSerial.h +index 0a51ef0..de83f8a 100644 +--- hardware/ASyncSerial.h ++++ hardware/ASyncSerial.h +@@ -123,27 +123,27 @@ class AsyncSerial : private domoticz::noncopyable + + /** + * Callback called to start an asynchronous read operation. +- * This callback is called by the io_service in the spawned thread. ++ * This callback is called by the io_context in the spawned thread. + */ + void doRead(); + + /** + * Callback called at the end of the asynchronous operation. +- * This callback is called by the io_service in the spawned thread. ++ * This callback is called by the io_context in the spawned thread. + */ + void readEnd(const boost::system::error_code &error, size_t bytes_transferred); + + /** + * Callback called to start an asynchronous write operation. + * If it is already in progress, does nothing. +- * This callback is called by the io_service in the spawned thread. ++ * This callback is called by the io_context in the spawned thread. + */ + void doWrite(); + + /** + * Callback called at the end of an asynchronuous write operation, + * if there is more data to write, restarts a new write operation. +- * This callback is called by the io_service in the spawned thread. ++ * This callback is called by the io_context in the spawned thread. + */ + void writeEnd(const boost::system::error_code &error); + +diff --git hardware/ASyncTCP.cpp hardware/ASyncTCP.cpp +index a375561..7c3b536 100644 +--- hardware/ASyncTCP.cpp ++++ hardware/ASyncTCP.cpp +@@ -4,213 +4,241 @@ + #include <boost/system/error_code.hpp> // for error_code + #include "../main/Logger.h" + +-struct hostent; +- + #define MAX_TCP_BUFFER_SIZE 4096 + +-#ifndef WIN32 +- #include <unistd.h> //gethostbyname +-#endif +- + #define STATUS_OK(err) !err +- +-ASyncTCP::ASyncTCP(const bool secure) ++#define STATUS_ERR(err) err ++ ++ASyncTCP::ASyncTCP(const bool secure) : ++ m_Tcpwork(boost::asio::make_work_guard(m_io_context)) ++ , m_Socket(m_io_context) ++ , m_Resolver(m_io_context) ++ , m_ReconnectTimer(m_io_context) ++ , m_TimeoutTimer(m_io_context) ++ , m_SendStrand(m_io_context) + #ifdef WWW_ENABLE_SSL +- : mSecure(secure) ++ , m_bSecure(secure) + #endif + { + m_pRXBuffer = new uint8_t[MAX_TCP_BUFFER_SIZE]; + #ifdef WWW_ENABLE_SSL + mContext.set_verify_mode(boost::asio::ssl::verify_none); +- if (mSecure) ++ if (m_bSecure) + { +- mSslSocket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(mIos, mContext)); ++ m_SslSocket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_context, mContext)); + } + #endif + } + + ASyncTCP::~ASyncTCP() + { +- assert(mTcpthread == nullptr); +- mIsTerminating = true; +- if (mTcpthread) ++ assert(m_Tcpthread == nullptr); ++ m_bIsTerminating = true; ++ if (m_Tcpthread) + { + //This should never happen. terminate() never called!! +- _log.Log(LOG_ERROR, "ASyncTCP: Workerthread not closed. terminate() never called!!!"); +- mIos.stop(); +- if (mTcpthread) ++ _log.Log(LOG_ERROR, "ASyncTCP: Worker thread not closed. terminate() never called!!!"); ++ m_io_context.stop(); ++ if (m_Tcpthread) + { +- mTcpthread->join(); +- mTcpthread.reset(); ++ m_Tcpthread->join(); ++ m_Tcpthread.reset(); + } + } + if (m_pRXBuffer != nullptr) + delete[] m_pRXBuffer; + } + +-void ASyncTCP::SetReconnectDelay(int32_t Delay) ++void ASyncTCP::SetReconnectDelay(const int32_t Delay) + { +- mReconnectDelay = Delay; ++ m_iReconnectDelay = Delay; + } + + void ASyncTCP::connect(const std::string& ip, uint16_t port) + { +- assert(!mSocket.is_open()); +- if (mSocket.is_open()) ++ assert(!m_Socket.is_open()); ++ if (m_Socket.is_open()) + { + _log.Log(LOG_ERROR, "ASyncTCP: connect called while socket is still open. !!!"); + terminate(); + } + +- // RK: We reset mIos here because it might have been stopped in terminate() +- mIos.reset(); +- // RK: After the reset, we need to provide it work anew +- mTcpwork = std::make_shared<boost::asio::io_service::work>(mIos); +- if (!mTcpthread) +- mTcpthread = std::make_shared<std::thread>([p = &mIos] { p->run(); }); +- +- mIp = ip; +- mPort = port; ++ m_IP = ip; ++ m_Port = port; + std::string port_str = std::to_string(port); +- boost::asio::ip::tcp::resolver::query query(ip, port_str); + timeout_start_timer(); +- mResolver.async_resolve(query, [this](auto &&err, auto &&iter) { cb_resolve_done(err, iter); }); ++ ++ m_Resolver.async_resolve( ++ ip, port_str, ++ [this](const boost::system::error_code& error, const boost::asio::ip::tcp::resolver::results_type& endpoints) { ++ handle_resolve(error, endpoints); ++ } ++ ); ++ ++ // RK: We restart m_io_context here because it might have been stopped in terminate() ++ m_io_context.restart(); ++ // RK: After the reset, we need to provide it work anew ++ m_Tcpwork.reset(); ++ m_Tcpwork.emplace(boost::asio::make_work_guard(m_io_context)); ++ if (!m_Tcpthread) ++ m_Tcpthread = std::make_shared<std::thread>([p = &m_io_context] { p->run(); }); + } + +-void ASyncTCP::cb_resolve_done(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) ++void ASyncTCP::handle_resolve(const boost::system::error_code& error, const boost::asio::ip::tcp::resolver::results_type &endpoints) + { +- if (mIsTerminating) return; ++ if (m_bIsTerminating) return; + +- if (STATUS_OK(error)) +- { +- connect_start(endpoint_iterator); +- } +- else ++ if (STATUS_ERR(error)) + { + process_error(error); ++ return; + } +-} +- +-void ASyncTCP::connect_start(boost::asio::ip::tcp::resolver::iterator& endpoint_iterator) +-{ +- if (mIsConnected) return; +- +- mEndPoint = *endpoint_iterator++; ++ if (m_bIsConnected) return; + + timeout_start_timer(); ++ + #ifdef WWW_ENABLE_SSL +- if (mSecure) ++ if (m_bSecure) + { + // we reset the ssl socket, because the ssl context needs to be reinitialized after a reconnect +- mSslSocket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(mIos, mContext)); +- mSslSocket->lowest_layer().async_connect(mEndPoint, [this, endpoint_iterator](auto &&err) mutable { cb_connect_done(err, endpoint_iterator); }); ++ m_SslSocket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_context, mContext)); ++ boost::asio::async_connect(m_SslSocket->lowest_layer(), endpoints, ++ [this](const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint) ++ { ++ handle_connect(error, endpoint); ++ } ++ ); + } + else + #endif + { +- mSocket.async_connect(mEndPoint, [this, endpoint_iterator](auto &&err) mutable { cb_connect_done(err, endpoint_iterator); }); ++ boost::asio::async_connect(m_Socket, endpoints, ++ [this](const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint) ++ { ++ handle_connect(error, endpoint); ++ } ++ ); + } + } + +-void ASyncTCP::cb_connect_done(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator &endpoint_iterator) ++void ASyncTCP::handle_connect(const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& /*endpoint*/) + { +- if (mIsTerminating) return; ++ if (m_bIsTerminating) return; + +- if (STATUS_OK(error)) ++ if (STATUS_ERR(error)) + { ++ process_error(error); ++ return; ++ } + #ifdef WWW_ENABLE_SSL +- if (mSecure) +- { +- timeout_start_timer(); +- mSslSocket->async_handshake(boost::asio::ssl::stream_base::client, [this](auto &&err) { cb_handshake_done(err); }); +- } +- else +-#endif +- { +- process_connection(); +- } ++ if (m_bSecure) ++ { ++ timeout_start_timer(); ++ m_SslSocket->async_handshake(boost::asio::ssl::stream_base::client, ++ [this](const boost::system::error_code& error) { ++ cb_handshake_done(error); ++ } ++ ); + } +- else ++ else ++#endif + { +- if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) +- { +- // The connection failed. Try the next endpoint in the list. +- connect_start(endpoint_iterator); +- return; +- } +- process_error(error); ++ process_connection(); + } + } + + #ifdef WWW_ENABLE_SSL + void ASyncTCP::cb_handshake_done(const boost::system::error_code& error) + { +- if (mIsTerminating) return; ++ if (m_bIsTerminating) return; + +- if (STATUS_OK(error)) +- { +- process_connection(); +- } +- else ++ if (STATUS_ERR(error)) + { + process_error(error); ++ return; + } ++ process_connection(); ++#endif + } ++ ++void ASyncTCP::process_connection() ++{ ++ m_bIsConnected = true; ++#ifdef WWW_ENABLE_SSL ++ ++ if (!m_bSecure) + #endif ++ { ++ // RK: only if non-secure ++ boost::asio::socket_base::keep_alive option(true); ++ m_Socket.set_option(option); ++ } ++ OnConnect(); ++ do_read_start(); ++ do_write_start(); ++} + + void ASyncTCP::reconnect_start_timer() + { +- if (mIsReconnecting) return; ++ if (m_bIsReconnecting) return; + +- if (mReconnectDelay != 0) ++ if (m_iReconnectDelay != 0) + { +- mIsReconnecting = true; +- +- mReconnectTimer.expires_from_now(boost::posix_time::seconds(mReconnectDelay)); +- mReconnectTimer.async_wait([this](auto &&err) { cb_reconnect_start(err); }); ++ m_bIsReconnecting = true; ++ ++ m_ReconnectTimer.expires_from_now(boost::posix_time::seconds(m_iReconnectDelay)); ++ m_ReconnectTimer.async_wait( ++ [this](const boost::system::error_code& error) { ++ cb_reconnect_start(error); ++ } ++ ); + } + } + + void ASyncTCP::cb_reconnect_start(const boost::system::error_code& error) + { +- mIsReconnecting = false; +- mReconnectTimer.cancel(); +- mTimeoutTimer.cancel(); ++ m_bIsReconnecting = false; ++ m_ReconnectTimer.cancel(); ++ m_TimeoutTimer.cancel(); + +- if (mIsConnected) return; ++ if (m_bIsConnected) return; + if (error) return; // timer was cancelled + + do_close(); +- connect(mIp, mPort); ++ connect(m_IP, m_Port); + } + + + void ASyncTCP::terminate(const bool silent) + { +- mIsTerminating = true; ++ m_bIsTerminating = true; + disconnect(silent); +- mTcpwork.reset(); +- mIos.stop(); +- if (mTcpthread) ++ m_Tcpwork.reset(); ++ m_io_context.stop(); ++ if (m_Tcpthread) + { +- mTcpthread->join(); +- mTcpthread.reset(); ++ m_Tcpthread->join(); ++ m_Tcpthread.reset(); + } +- mIsReconnecting = false; +- mIsConnected = false; +- mWriteQ.clear(); +- mIsTerminating = false; ++ m_bIsReconnecting = false; ++ m_bIsConnected = false; ++ m_WriteQ.clear(); ++ m_bIsTerminating = false; + } + + void ASyncTCP::disconnect(const bool silent) + { +- mReconnectTimer.cancel(); +- mTimeoutTimer.cancel(); +- if (!mTcpthread) return; ++ m_ReconnectTimer.cancel(); ++ m_TimeoutTimer.cancel(); ++ if (!m_Tcpthread) return; + + try + { +- mIos.post([this] { do_close(); }); ++ boost::asio::post(m_io_context, ++ [this] { ++ do_close(); ++ } ++ ); + } + catch (...) + { +@@ -223,62 +251,68 @@ void ASyncTCP::disconnect(const bool silent) + + void ASyncTCP::do_close() + { +- if (mIsReconnecting) { ++ if (m_bIsReconnecting) { + return; + } +- mReconnectTimer.cancel(); +- mTimeoutTimer.cancel(); ++ m_ReconnectTimer.cancel(); ++ m_TimeoutTimer.cancel(); + boost::system::error_code ec; + #ifdef WWW_ENABLE_SSL +- if (mSecure) ++ if (m_bSecure) + { +- if (mSslSocket->lowest_layer().is_open()) ++ if (m_SslSocket->lowest_layer().is_open()) + { +- mSslSocket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); +- mSslSocket->lowest_layer().close(ec); ++ m_SslSocket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); ++ m_SslSocket->lowest_layer().close(ec); + } + } + else + #endif + { +- if (mSocket.is_open()) ++ if (m_Socket.is_open()) + { +- mSocket.close(ec); ++ m_Socket.close(ec); + } + } + } + + void ASyncTCP::do_read_start() + { +- if (mIsTerminating) return; +- if (!mIsConnected) return; ++ if (m_bIsTerminating) return; ++ if (!m_bIsConnected) return; + + timeout_start_timer(); + #ifdef WWW_ENABLE_SSL +- if (mSecure) ++ if (m_bSecure) + { +- mSslSocket->async_read_some(boost::asio::buffer(m_pRXBuffer, MAX_TCP_BUFFER_SIZE), [this](auto &&err, auto bytes) { cb_read_done(err, bytes); }); ++ m_SslSocket->async_read_some(boost::asio::buffer(m_pRXBuffer, MAX_TCP_BUFFER_SIZE), ++ [this](const boost::system::error_code& error, size_t bytes_transferred) { ++ cb_read_done(error, bytes_transferred); ++ } ++ ); + } + else + #endif + { +- mSocket.async_read_some(boost::asio::buffer(m_pRXBuffer, MAX_TCP_BUFFER_SIZE), [this](auto &&err, auto bytes) { cb_read_done(err, bytes); }); ++ m_Socket.async_read_some(boost::asio::buffer(m_pRXBuffer, MAX_TCP_BUFFER_SIZE), ++ [this](const boost::system::error_code& error, size_t bytes_transferred) { ++ cb_read_done(error, bytes_transferred); ++ } ++ ); + } + } + + void ASyncTCP::cb_read_done(const boost::system::error_code& error, size_t bytes_transferred) + { +- if (mIsTerminating) return; ++ if (m_bIsTerminating) return; + +- if (STATUS_OK(error)) +- { +- OnData(m_pRXBuffer, bytes_transferred); +- do_read_start(); +- } +- else ++ if (STATUS_ERR(error)) + { + process_error(error); ++ return; + } ++ OnData(m_pRXBuffer, bytes_transferred); ++ do_read_start(); + } + + void ASyncTCP::write(const uint8_t* pData, size_t length) +@@ -288,77 +322,66 @@ void ASyncTCP::write(const uint8_t* pData, size_t length) + + void ASyncTCP::write(const std::string& msg) + { +- if (!mTcpthread) return; ++ if (!m_Tcpthread) return; + +- mSendStrand.post([this, msg]() { cb_write_queue(msg); }); ++ boost::asio::post(m_SendStrand, [this, msg]() { cb_write_queue(msg); }); + } + + void ASyncTCP::cb_write_queue(const std::string& msg) + { +- mWriteQ.push_back(msg); ++ m_WriteQ.push_back(msg); + +- if (mWriteQ.size() == 1) ++ if (m_WriteQ.size() == 1) + do_write_start(); + } + + void ASyncTCP::do_write_start() + { +- if (mIsTerminating) return; +- if (!mIsConnected) return; +- if (mWriteQ.empty()) ++ if (m_bIsTerminating) return; ++ if (!m_bIsConnected) return; ++ if (m_WriteQ.empty()) + return; + + timeout_start_timer(); + #ifdef WWW_ENABLE_SSL +- if (mSecure) ++ if (m_bSecure) + { +- boost::asio::async_write(*mSslSocket, boost::asio::buffer(mWriteQ.front()), [this](auto &&err, auto) { cb_write_done(err); }); ++ boost::asio::async_write(*m_SslSocket, boost::asio::buffer(m_WriteQ.front()), ++ [this](const boost::system::error_code& error, std::size_t length) { ++ cb_write_done(error, length); ++ } ++ ); + } + else + #endif + { +- boost::asio::async_write(mSocket, boost::asio::buffer(mWriteQ.front()), [this](auto &&err, auto) { cb_write_done(err); }); ++ boost::asio::async_write(m_Socket, boost::asio::buffer(m_WriteQ.front()), ++ [this](const boost::system::error_code& error, std::size_t length) { ++ cb_write_done(error, length); ++ } ++ ); + } + } + +-void ASyncTCP::cb_write_done(const boost::system::error_code& error) ++void ASyncTCP::cb_write_done(const boost::system::error_code& error, std::size_t /*length*/) + { +- if (mIsTerminating) return; ++ if (m_bIsTerminating) return; + +- if (STATUS_OK(error)) +- { +- mWriteQ.pop_front(); +- do_write_start(); +- } +- else ++ if (STATUS_ERR(error)) + { + process_error(error); ++ return; + } +-} +- +-void ASyncTCP::process_connection() +-{ +- mIsConnected = true; +-#ifdef WWW_ENABLE_SSL +- +- if (!mSecure) +-#endif +- { +- // RK: only if non-secure +- boost::asio::socket_base::keep_alive option(true); +- mSocket.set_option(option); +- } +- OnConnect(); +- do_read_start(); ++ m_WriteQ.pop_front(); + do_write_start(); + } + + void ASyncTCP::process_error(const boost::system::error_code& error) + { + do_close(); +- if (mIsConnected) ++ if (m_bIsConnected) + { +- mIsConnected = false; ++ m_bIsConnected = false; + OnDisconnect(); + } + +@@ -369,20 +392,23 @@ void ASyncTCP::process_error(const boost::system::error_code& error) + reconnect_start_timer(); + } + +-/* timeout methods */ + void ASyncTCP::timeout_start_timer() + { +- if (0 == mTimeoutDelay) { ++ if (0 == m_iTimeoutDelay) { + return; + } + timeout_cancel_timer(); +- mTimeoutTimer.expires_from_now(boost::posix_time::seconds(mTimeoutDelay)); +- mTimeoutTimer.async_wait([this](auto &&err) { timeout_handler(err); }); ++ m_TimeoutTimer.expires_from_now(boost::posix_time::seconds(m_iTimeoutDelay)); ++ m_TimeoutTimer.async_wait( ++ [this](const boost::system::error_code& error) { ++ timeout_handler(error); ++ } ++ ); + } + + void ASyncTCP::timeout_cancel_timer() + { +- mTimeoutTimer.cancel(); ++ m_TimeoutTimer.cancel(); + } + + void ASyncTCP::timeout_handler(const boost::system::error_code& error) +@@ -397,5 +423,5 @@ void ASyncTCP::timeout_handler(const boost::system::error_code& error) + + void ASyncTCP::SetTimeout(const uint32_t Timeout) + { +- mTimeoutDelay = Timeout; ++ m_iTimeoutDelay = Timeout; + } +diff --git hardware/ASyncTCP.h hardware/ASyncTCP.h +index cf859bb..a8b3ae2 100644 +--- hardware/ASyncTCP.h ++++ hardware/ASyncTCP.h +@@ -3,39 +3,31 @@ + #include <stddef.h> // for size_t + #include <deque> // for write queue + #include <boost/asio/deadline_timer.hpp> // for deadline_timer +-#include <boost/asio/io_service.hpp> // for io_service ++#include <boost/asio/io_context.hpp> // for io_context + #include <boost/asio/strand.hpp> // for strand + #include <boost/asio/ip/tcp.hpp> // for tcp, tcp::endpoint, tcp::s... + #include <boost/asio/ssl.hpp> // for secure sockets + #include <boost/asio/ssl/stream.hpp> // for secure sockets + #include <exception> // for exception ++#include <optional> // for optional + + #define ASYNCTCP_THREAD_NAME "ASyncTCP" + #define DEFAULT_RECONNECT_TIME 30 + #define DEFAULT_TIMEOUT_TIME 60 + +-namespace boost +-{ +- namespace system +- { +- class error_code; +- } // namespace system +-} // namespace boost +- + class ASyncTCP + { +- protected: ++protected: + ASyncTCP(bool secure = false); + virtual ~ASyncTCP(); +- +- void connect(const std::string &hostname, uint16_t port); ++ void connect(const std::string& hostname, uint16_t port); + void disconnect(bool silent = true); +- void write(const std::string &msg); +- void write(const uint8_t *pData, size_t length); +- void SetReconnectDelay(int32_t Delay = DEFAULT_RECONNECT_TIME); ++ void write(const std::string& msg); ++ void write(const uint8_t* pData, size_t length); ++ void SetReconnectDelay(const int32_t Delay = DEFAULT_RECONNECT_TIME); + bool isConnected() + { +- return mIsConnected; ++ return m_bIsConnected; + }; + void terminate(bool silent = true); + void SetTimeout(uint32_t Timeout = DEFAULT_TIMEOUT_TIME); +@@ -43,65 +35,61 @@ class ASyncTCP + // Callback interface to implement in derived classes + virtual void OnConnect() = 0; + virtual void OnDisconnect() = 0; +- virtual void OnData(const uint8_t *pData, size_t length) = 0; +- virtual void OnError(const boost::system::error_code &error) = 0; +- +- boost::asio::io_service mIos; // protected to allow derived classes to attach timers etc. ++ virtual void OnData(const uint8_t* pData, size_t length) = 0; ++ virtual void OnError(const boost::system::error_code& error) = 0; + +- private: +- void cb_resolve_done(const boost::system::error_code &err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); +- void connect_start(boost::asio::ip::tcp::resolver::iterator &endpoint_iterator); +- void cb_connect_done(const boost::system::error_code &error, boost::asio::ip::tcp::resolver::iterator &endpoint_iterator); ++ boost::asio::io_context m_io_context; // protected to allow derived classes to attach timers etc. ++private: ++ void handle_resolve(const boost::system::error_code& ec, const boost::asio::ip::tcp::resolver::results_type &results); ++ void handle_connect(const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint); + #ifdef WWW_ENABLE_SSL +- void cb_handshake_done(const boost::system::error_code &error); ++ void cb_handshake_done(const boost::system::error_code& error); + #endif + +- /* timeout methods */ + void timeout_start_timer(); + void timeout_cancel_timer(); + void reconnect_start_timer(); +- void timeout_handler(const boost::system::error_code &error); ++ void timeout_handler(const boost::system::error_code& error); + +- void cb_reconnect_start(const boost::system::error_code &error); ++ void cb_reconnect_start(const boost::system::error_code& error); + + void do_close(); + + void do_read_start(); +- void cb_read_done(const boost::system::error_code &error, size_t bytes_transferred); ++ void cb_read_done(const boost::system::error_code& error, size_t bytes_transferred); + +- void cb_write_queue(const std::string &msg); ++ void cb_write_queue(const std::string& msg); + void do_write_start(); +- void cb_write_done(const boost::system::error_code &error); ++ void cb_write_done(const boost::system::error_code& error, size_t length); + + void process_connection(); +- void process_error(const boost::system::error_code &error); ++ void process_error(const boost::system::error_code& error); + +- bool mIsConnected = false; +- bool mIsReconnecting = false; +- bool mIsTerminating = false; ++ bool m_bIsConnected = false; ++ bool m_bIsReconnecting = false; ++ bool m_bIsTerminating = false; + +- boost::asio::io_service::strand mSendStrand{ mIos }; +- std::deque<std::string> mWriteQ; // we need a write queue to allow concurrent writes ++ boost::asio::io_context::strand m_SendStrand; ++ std::deque<std::string> m_WriteQ; // we need a write queue to allow concurrent writes + + uint8_t* m_pRXBuffer = nullptr; + +- int mReconnectDelay = DEFAULT_RECONNECT_TIME; +- int mTimeoutDelay = 0; +- boost::asio::deadline_timer mReconnectTimer{ mIos }; +- boost::asio::deadline_timer mTimeoutTimer{ mIos }; ++ int m_iReconnectDelay = DEFAULT_RECONNECT_TIME; ++ int m_iTimeoutDelay = 0; ++ boost::asio::deadline_timer m_ReconnectTimer; ++ boost::asio::deadline_timer m_TimeoutTimer; + +- std::shared_ptr<std::thread> mTcpthread; +- std::shared_ptr<boost::asio::io_service::work> mTcpwork; ++ std::shared_ptr<std::thread> m_Tcpthread; ++ std::optional<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_Tcpwork; + + #ifdef WWW_ENABLE_SSL +- const bool mSecure; ++ const bool m_bSecure; + boost::asio::ssl::context mContext{ boost::asio::ssl::context::sslv23 }; +- std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> mSslSocket; // the ssl socket ++ std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_SslSocket; + #endif +- boost::asio::ip::tcp::socket mSocket{ mIos }; +- boost::asio::ip::tcp::endpoint mEndPoint; +- boost::asio::ip::tcp::resolver mResolver{ mIos }; ++ boost::asio::ip::tcp::socket m_Socket; ++ boost::asio::ip::tcp::resolver m_Resolver; + +- std::string mIp; +- uint16_t mPort; ++ std::string m_IP; ++ uint16_t m_Port; + }; +diff --git hardware/Arilux.cpp hardware/Arilux.cpp +index 400f5a3..20bc373 100644 +--- hardware/Arilux.cpp ++++ hardware/Arilux.cpp +@@ -79,7 +79,7 @@ void Arilux::InsertUpdateSwitch(const std::string &lightName, const int subType, + { + uint32_t sID; + try { +- sID = boost::asio::ip::address_v4::from_string(location).to_ulong(); ++ sID = boost::asio::ip::make_address_v4(location).to_uint(); + } catch (const std::exception &e) { + Log(LOG_ERROR, "Bad IP address: %s (%s)", location.c_str(), e.what()); + return; +@@ -112,8 +112,8 @@ bool Arilux::SendTCPCommand(uint32_t ip,std::vector<unsigned char> &command) + sum = sum & 0xFF; + command.push_back((unsigned char)sum); + +- boost::asio::io_service io_service; +- boost::asio::ip::tcp::socket sendSocket(io_service); ++ boost::asio::io_context io_context; ++ boost::asio::ip::tcp::socket sendSocket(io_context); + boost::asio::ip::address_v4 address(ip); + boost::asio::ip::tcp::endpoint endpoint(address, 5577); + try +diff --git hardware/Kodi.cpp hardware/Kodi.cpp +index b528017..5ababf6 100644 +--- hardware/Kodi.cpp ++++ hardware/Kodi.cpp +@@ -143,14 +143,14 @@ _eNotificationTypes CKodiNode::CKodiStatus::NotificationType() + } + } + +-CKodiNode::CKodiNode(boost::asio::io_service *pIos, const int pHwdID, const int PollIntervalsec, const int pTimeoutMs, ++CKodiNode::CKodiNode(boost::asio::io_context *pIoc, const int pHwdID, const int PollIntervalsec, const int pTimeoutMs, + const std::string& pID, const std::string& pName, const std::string& pIP, const std::string& pPort) + { + m_Busy = false; + m_Stoppable = false; + m_PlaylistPosition = 0; + +- m_Ios = pIos; ++ m_Ioc = pIoc; + m_HwdID = pHwdID; + m_DevID = atoi(pID.c_str()); + sprintf(m_szDevID, "%X%02X%02X%02X", 0, 0, (m_DevID & 0xFF00) >> 8, m_DevID & 0xFF); +@@ -581,11 +581,10 @@ void CKodiNode::handleConnect() + { + m_iMissedPongs = 0; + boost::system::error_code ec; +- boost::asio::ip::tcp::resolver resolver(*m_Ios); +- boost::asio::ip::tcp::resolver::query query(m_IP, (m_Port[0] != '-' ? m_Port : m_Port.substr(1))); +- auto iter = resolver.resolve(query); +- boost::asio::ip::tcp::endpoint endpoint = *iter; +- m_Socket = new boost::asio::ip::tcp::socket(*m_Ios); ++ boost::asio::ip::tcp::resolver resolver(*m_Ioc); ++ auto iter = resolver.resolve(m_IP, (m_Port[0] != '-' ? m_Port : m_Port.substr(1))); ++ boost::asio::ip::tcp::endpoint endpoint = *iter.begin(); ++ m_Socket = new boost::asio::ip::tcp::socket(*m_Ioc); + m_Socket->connect(endpoint, ec); + if (!ec) + { +@@ -975,19 +974,19 @@ void CKodi::Do_Work() + _log.Log(LOG_NORM, "Kodi: (%s) - Restarting thread.", node->m_Name.c_str()); + boost::thread *tAsync = new boost::thread(&CKodiNode::Do_Work, node); + SetThreadName(tAsync->native_handle(), "KodiNode"); +- m_ios.stop(); ++ m_ioc.stop(); + } + if (node->IsOn()) + bWorkToDo = true; + } + +- if (bWorkToDo && m_ios.stopped()) // make sure that there is a boost thread to service i/o operations ++ if (bWorkToDo && m_ioc.stopped()) // make sure that there is a boost thread to service i/o operations + { +- m_ios.reset(); ++ m_ioc.restart(); + // Note that this is the only thread that handles async i/o so we don't + // need to worry about locking or concurrency issues when processing messages + _log.Log(LOG_NORM, "Kodi: Restarting I/O service thread."); +- boost::thread bt([p = &m_ios] { p->run(); }); ++ boost::thread bt([p = &m_ioc] { p->run(); }); + SetThreadName(bt.native_handle(), "KodiIO"); + } + } +@@ -1138,7 +1137,7 @@ void CKodi::ReloadNodes() + { + UnloadNodes(); + +- m_ios.reset(); // in case this is not the first time in ++ m_ioc.restart(); // in case this is not the first time in + + std::vector<std::vector<std::string> > result; + result = m_sql.safe_query("SELECT ID,Name,MacAddress,Timeout FROM WOLNodes WHERE (HardwareID==%d)", m_HwdID); +@@ -1149,7 +1148,7 @@ void CKodi::ReloadNodes() + // create a vector to hold the nodes + for (const auto &sd : result) + { +- auto pNode = std::make_shared<CKodiNode>(&m_ios, m_HwdID, m_iPollInterval, m_iPingTimeoutms, sd[0], sd[1], sd[2], sd[3]); ++ auto pNode = std::make_shared<CKodiNode>(&m_ioc, m_HwdID, m_iPollInterval, m_iPingTimeoutms, sd[0], sd[1], sd[2], sd[3]); + m_pNodes.push_back(pNode); + } + // start the threads to control each kodi +@@ -1161,7 +1160,7 @@ void CKodi::ReloadNodes() + } + sleep_milliseconds(100); + _log.Log(LOG_NORM, "Kodi: Starting I/O service thread."); +- boost::thread bt([p = &m_ios] { p->run(); }); ++ boost::thread bt([p = &m_ioc] { p->run(); }); + SetThreadName(bt.native_handle(), "KodiIO"); + } + } +@@ -1170,10 +1169,10 @@ void CKodi::UnloadNodes() + { + std::lock_guard<std::mutex> l(m_mutex); + +- m_ios.stop(); // stop the service if it is running ++ m_ioc.stop(); // stop the service if it is running + sleep_milliseconds(100); + +- while (((!m_pNodes.empty()) || (!m_ios.stopped()))) ++ while (((!m_pNodes.empty()) || (!m_ioc.stopped()))) + { + for (auto itt = m_pNodes.begin(); itt != m_pNodes.end(); ++itt) + { +diff --git hardware/Kodi.h hardware/Kodi.h +index 14f331c..4435740 100644 +--- hardware/Kodi.h ++++ hardware/Kodi.h +@@ -150,7 +150,7 @@ class CKodiNode : public std::enable_shared_from_this<CKodiNode>, StoppableTask + }; + + public: +- CKodiNode(boost::asio::io_service *, int, int, int, const std::string &, const std::string &, const std::string &, const std::string &); ++ CKodiNode(boost::asio::io_context *, int, int, int, const std::string &, const std::string &, const std::string &, const std::string &); + ~CKodiNode(); + void Do_Work(); + void SendCommand(const std::string &); +@@ -207,7 +207,7 @@ class CKodiNode : public std::enable_shared_from_this<CKodiNode>, StoppableTask + int m_iPollIntSec; + int m_iMissedPongs; + std::string m_sLastMessage; +- boost::asio::io_service *m_Ios; ++ boost::asio::io_context *m_Ioc; + boost::asio::ip::tcp::socket *m_Socket; + std::array<char, 256> m_Buffer; + }; +@@ -243,5 +243,5 @@ class CKodi : public CDomoticzHardwareBase + int m_iPingTimeoutms; + std::shared_ptr<std::thread> m_thread; + std::mutex m_mutex; +- boost::asio::io_service m_ios; ++ boost::asio::io_context m_ioc; + }; +diff --git hardware/MQTTAutoDiscover.h hardware/MQTTAutoDiscover.h +index 0832664..1501d6f 100644 +--- hardware/MQTTAutoDiscover.h ++++ hardware/MQTTAutoDiscover.h +@@ -176,7 +176,7 @@ public: + void on_message(const struct mosquitto_message *message) override; + void on_connect(int rc) override; + void on_disconnect(int rc) override; +- void on_going_down(); ++ void on_going_down() override; + private: + void InsertUpdateSwitch(_tMQTTASensor* pSensor); + +diff --git hardware/PanasonicTV.cpp hardware/PanasonicTV.cpp +index fc57d34..ce20565 100644 +--- hardware/PanasonicTV.cpp ++++ hardware/PanasonicTV.cpp +@@ -356,18 +356,17 @@ std::string CPanasonicNode::handleWriteAndRead(const std::string& pMessageToSend + { + + _log.Debug(DEBUG_HARDWARE, "Panasonic Plugin: (%s) Handling message: '%s'.", m_Name.c_str(), pMessageToSend.c_str()); +- boost::asio::io_service io_service; ++ boost::asio::io_context io_context; + // Get a list of endpoints corresponding to the server name. +- boost::asio::ip::tcp::resolver resolver(io_service); +- boost::asio::ip::tcp::resolver::query query(m_IP, (m_Port[0] != '-' ? m_Port : m_Port.substr(1))); +- auto iter = resolver.resolve(query); ++ boost::asio::ip::tcp::resolver resolver(io_context); ++ auto endpoints = resolver.resolve(m_IP, (m_Port[0] != '-' ? m_Port : m_Port.substr(1))); ++ auto iter = endpoints.begin(); + boost::asio::ip::tcp::endpoint endpoint = *iter; +- boost::asio::ip::tcp::resolver::iterator end; + + // Try each endpoint until we successfully establish a connection. +- boost::asio::ip::tcp::socket socket(io_service); ++ boost::asio::ip::tcp::socket socket(io_context); + boost::system::error_code error = boost::asio::error::host_not_found; +- while (error && iter != end) ++ while (error && iter != endpoints.end()) + { + socket.close(); + if (handleConnect(socket, *iter, error)) +@@ -1060,7 +1059,7 @@ void CPanasonic::ReloadNodes() + { + UnloadNodes(); + +- //m_ios.reset(); // in case this is not the first time in ++ //m_ioc.reset(); // in case this is not the first time in + + std::vector<std::vector<std::string> > result; + result = m_sql.safe_query("SELECT ID,Name,MacAddress,Timeout FROM WOLNodes WHERE (HardwareID==%d)", m_HwdID); +@@ -1088,10 +1087,10 @@ void CPanasonic::UnloadNodes() + { + std::lock_guard<std::mutex> l(m_mutex); + +- m_ios.stop(); // stop the service if it is running ++ m_ioc.stop(); // stop the service if it is running + sleep_milliseconds(100); + +- while (((!m_pNodes.empty()) || (!m_ios.stopped()))) ++ while (((!m_pNodes.empty()) || (!m_ioc.stopped()))) + { + for (auto itt = m_pNodes.begin(); itt != m_pNodes.end(); ++itt) + { +diff --git hardware/PanasonicTV.h hardware/PanasonicTV.h +index b0a94ff..30e1ca1 100644 +--- hardware/PanasonicTV.h ++++ hardware/PanasonicTV.h +@@ -39,7 +39,7 @@ class CPanasonic : public CDomoticzHardwareBase + bool m_bTryIfOff; + std::shared_ptr<std::thread> m_thread; + std::mutex m_mutex; +- boost::asio::io_service m_ios; ++ boost::asio::io_context m_ioc; + + friend class CPanasonicNode; + }; +diff --git hardware/Pinger.cpp hardware/Pinger.cpp +index a66c7a1..e070b29 100644 +--- hardware/Pinger.cpp ++++ hardware/Pinger.cpp +@@ -21,23 +21,23 @@ + #if BOOST_VERSION >= 107000 + #define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context()) + #else +-#define GET_IO_SERVICE(s) ((s).get_io_service()) ++#define GET_IO_SERVICE(s) ((s).get_io_context()) + #endif + + class pinger + : private domoticz::noncopyable + { + public: +- pinger(boost::asio::io_service &io_service, const char *destination, const int iPingTimeoutms) ++ pinger(boost::asio::io_context &io_context, const char *destination, const int iPingTimeoutms) + : num_replies_(0) + , m_PingState(false) +- , resolver_(io_service) +- , socket_(io_service, boost::asio::ip::icmp::v4()) +- , timer_(io_service) ++ , resolver_(io_context) ++ , socket_(io_context, boost::asio::ip::icmp::v4()) ++ , timer_(io_context) + , sequence_number_(0) + { +- boost::asio::ip::icmp::resolver::query query(boost::asio::ip::icmp::v4(), destination, ""); +- destination_ = *resolver_.resolve(query); ++ auto endpoints = resolver_.resolve(boost::asio::ip::icmp::v4(), destination, ""); ++ destination_ = endpoints.begin()->endpoint(); + + num_tries_ = 1; + PingTimeoutms_ = iPingTimeoutms; +@@ -332,11 +332,11 @@ void CPinger::ReloadNodes() + void CPinger::Do_Ping_Worker(const PingNode &Node) + { + bool bPingOK = false; +- boost::asio::io_service io_service; ++ boost::asio::io_context io_context; + try + { +- pinger p(io_service, Node.IP.c_str(), m_iPingTimeoutms); +- io_service.run(); ++ pinger p(io_context, Node.IP.c_str(), m_iPingTimeoutms); ++ io_context.run(); + if (p.m_PingState == true) + { + bPingOK = true; +diff --git hardware/RFLinkMQTT.h hardware/RFLinkMQTT.h +index e938328..72433b8 100644 +--- hardware/RFLinkMQTT.h ++++ hardware/RFLinkMQTT.h +@@ -46,7 +46,7 @@ protected: + boost::signals2::connection m_sDeviceReceivedConnection; + boost::signals2::connection m_sSwitchSceneConnection; + void selectNextIPAdress( void ); +- virtual bool WriteInt(const std::string &sendString); // override; ++ bool WriteInt(const std::string &sendString) override; + void Do_Work(); + virtual void SendHeartbeat(); + void StopMQTT(); +diff --git hardware/TCPProxy/tcpproxy_server.cpp hardware/TCPProxy/tcpproxy_server.cpp +index 8aceb0b..d77d4bf 100644 +--- hardware/TCPProxy/tcpproxy_server.cpp ++++ hardware/TCPProxy/tcpproxy_server.cpp +@@ -18,12 +18,12 @@ + #if BOOST_VERSION >= 107000 + #define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context()) + #else +-#define GET_IO_SERVICE(s) ((s).get_io_service()) ++#define GET_IO_SERVICE(s) ((s).get_io_context()) + #endif + + namespace tcp_proxy + { +- bridge::bridge(boost::asio::io_service& ios) ++ bridge::bridge(boost::asio::io_context& ios) + : downstream_socket_(ios), + upstream_socket_(ios) + { +@@ -44,7 +44,7 @@ namespace tcp_proxy + boost::asio::ip::tcp::endpoint end; + + +- boost::asio::io_service &ios= GET_IO_SERVICE(downstream_socket_); ++ boost::asio::io_context &ios= GET_IO_SERVICE(downstream_socket_); + boost::asio::ip::tcp::resolver resolver(ios); + boost::asio::ip::tcp::resolver::query query(upstream_host, upstream_port, boost::asio::ip::resolver_query_base::numeric_service); + auto i = resolver.resolve(query); +@@ -137,10 +137,10 @@ namespace tcp_proxy + } + //Acceptor Class + acceptor::acceptor(const std::string &local_host, unsigned short local_port, const std::string &upstream_host, const std::string &upstream_port) +- : io_service_() ++ : io_context_() + , m_bDoStop(false) + , localhost_address(boost::asio::ip::address_v4::from_string(local_host)) +- , acceptor_(io_service_, boost::asio::ip::tcp::endpoint(localhost_address, local_port)) ++ , acceptor_(io_context_, boost::asio::ip::tcp::endpoint(localhost_address, local_port)) + , upstream_host_(upstream_host) + , upstream_port_(upstream_port) + { +@@ -151,7 +151,7 @@ namespace tcp_proxy + { + try + { +- session_ = std::make_shared<bridge>(io_service_); ++ session_ = std::make_shared<bridge>(io_context_); + session_->sDownstreamData.connect([this](auto d, auto l) { OnDownstreamData(d, l); }); + session_->sUpstreamData.connect([this](auto d, auto l) { OnUpstreamData(d, l); }); + +@@ -169,11 +169,11 @@ namespace tcp_proxy + m_bDoStop=false; + + accept_connections(); +- // The io_service::run() call will block until all asynchronous operations ++ // The io_context::run() call will block until all asynchronous operations + // have finished. While the server is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. +- io_service_.run(); ++ io_context_.run(); + return true; + } + bool acceptor::stop() +@@ -181,14 +181,14 @@ namespace tcp_proxy + m_bDoStop=true; + // Post a call to the stop function so that server::stop() is safe to call + // from any thread. +- io_service_.post([this] { handle_stop(); }); ++ io_context_.post([this] { handle_stop(); }); + return true; + } + + void acceptor::handle_stop() + { + // The server is stopped by canceling all outstanding asynchronous +- // operations. Once all operations have finished the io_service::run() call ++ // operations. Once all operations have finished the io_context::run() call + // will exit. + acceptor_.close(); + //connection_manager_.stop_all(); +diff --git hardware/TCPProxy/tcpproxy_server.h hardware/TCPProxy/tcpproxy_server.h +index 3d1a150..148e65f 100644 +--- hardware/TCPProxy/tcpproxy_server.h ++++ hardware/TCPProxy/tcpproxy_server.h +@@ -10,7 +10,7 @@ namespace tcp_proxy + class bridge : public std::enable_shared_from_this<bridge> + { + public: +- explicit bridge(boost::asio::io_service& ios); ++ explicit bridge(boost::asio::io_context& ios); + boost::asio::ip::tcp::socket& downstream_socket(); + boost::asio::ip::tcp::socket& upstream_socket(); + +@@ -52,8 +52,8 @@ namespace tcp_proxy + void OnUpstreamData(const unsigned char *pData, size_t Len); + void OnDownstreamData(const unsigned char *pData, size_t Len); + +- /// The io_service used to perform asynchronous operations. +- boost::asio::io_service io_service_; ++ /// The io_context used to perform asynchronous operations. ++ boost::asio::io_context io_context_; + bool m_bDoStop; + boost::asio::ip::address_v4 localhost_address; + boost::asio::ip::tcp::acceptor acceptor_; +diff --git hardware/XiaomiDeviceSupport.h hardware/XiaomiDeviceSupport.h +index fad7884..4a76d96 100644 +--- hardware/XiaomiDeviceSupport.h ++++ hardware/XiaomiDeviceSupport.h +@@ -15,6 +15,7 @@ + class XiaomiDeviceSupport + { + public: ++ virtual ~XiaomiDeviceSupport() = default; + /** + * Method to get 'model' corresponding to the ID of the device in case the Gateway API didn't provide it. + * +diff --git hardware/XiaomiGateway.cpp hardware/XiaomiGateway.cpp +index 66acdc5..fb4387a 100644 +--- hardware/XiaomiGateway.cpp ++++ hardware/XiaomiGateway.cpp +@@ -538,12 +538,12 @@ bool XiaomiGateway::SendMessageToGateway(const std::string &controlmessage) + { + std::string message = controlmessage; + bool result = true; +- boost::asio::io_service io_service; +- boost::asio::ip::udp::socket socket_(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)); ++ boost::asio::io_context io_context; ++ boost::asio::ip::udp::socket socket_(io_context, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)); + stdreplace(message, "@gatewaykey", GetGatewayKey()); + std::shared_ptr<std::string> message1(new std::string(message)); + boost::asio::ip::udp::endpoint remote_endpoint_; +- remote_endpoint_ = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(m_GatewayIp), 9898); ++ remote_endpoint_ = boost::asio::ip::udp::endpoint(boost::asio::ip::make_address_v4(m_GatewayIp), 9898); + socket_.send_to(boost::asio::buffer(*message1), remote_endpoint_); + sleep_milliseconds(150); // TODO: reduce or remove sleep + std::array<char, 512> recv_buffer_; +@@ -1015,15 +1015,14 @@ bool XiaomiGateway::StopHardware() + void XiaomiGateway::Do_Work() + { + Log(LOG_STATUS, "XiaomiGateway (ID=%d): Worker started...", m_HwdID); +- boost::asio::io_service io_service; ++ boost::asio::io_context io_context; + // Find the local ip address that is similar to the xiaomi gateway + try + { +- boost::asio::ip::udp::resolver resolver(io_service); +- boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), m_GatewayIp, ""); +- auto endpoints = resolver.resolve(query); +- boost::asio::ip::udp::endpoint ep = *endpoints; +- boost::asio::ip::udp::socket socket(io_service); ++ boost::asio::ip::udp::resolver resolver(io_context); ++ auto endpoints = resolver.resolve(boost::asio::ip::udp::v4(), m_GatewayIp, ""); ++ boost::asio::ip::udp::endpoint ep = *endpoints.begin(); ++ boost::asio::ip::udp::socket socket(io_context); + socket.connect(ep); + boost::asio::ip::address addr = socket.local_endpoint().address(); + std::string compareIp = m_GatewayIp.substr(0, (m_GatewayIp.length() - 3)); +@@ -1073,11 +1072,11 @@ void XiaomiGateway::Do_Work() + } + } + +- XiaomiGateway::xiaomi_udp_server udp_server(io_service, m_HwdID, m_GatewayIp, m_LocalIp, m_ListenPort9898, m_OutputMessage, m_IncludeVoltage, this); ++ XiaomiGateway::xiaomi_udp_server udp_server(io_context, m_HwdID, m_GatewayIp, m_LocalIp, m_ListenPort9898, m_OutputMessage, m_IncludeVoltage, this); + boost::thread bt; + if (m_ListenPort9898) + { +- bt = boost::thread([p = &io_service] { p->run(); }); ++ bt = boost::thread([p = &io_context] { p->run(); }); + SetThreadName(bt.native_handle(), "XiaomiGatewayIO"); + } + +@@ -1094,7 +1093,7 @@ void XiaomiGateway::Do_Work() + // Log(LOG_STATUS, "sec_counter %d", sec_counter); + } + } +- io_service.stop(); ++ io_context.stop(); + if (bt.joinable()) + { + bt.join(); +@@ -1178,9 +1177,9 @@ unsigned int XiaomiGateway::GetShortID(const std::string &nodeid) + return sID; + } + +-XiaomiGateway::xiaomi_udp_server::xiaomi_udp_server(boost::asio::io_service &io_service, int m_HwdID, const std::string &gatewayIp, const std::string &localIp, const bool listenPort9898, ++XiaomiGateway::xiaomi_udp_server::xiaomi_udp_server(boost::asio::io_context &io_context, int m_HwdID, const std::string &gatewayIp, const std::string &localIp, const bool listenPort9898, + const bool outputMessage, const bool includeVoltage, XiaomiGateway *parent) +- : socket_(io_service, boost::asio::ip::udp::v4()) ++ : socket_(io_context, boost::asio::ip::udp::v4()) + { + m_HardwareID = m_HwdID; + m_XiaomiGateway = parent; +@@ -1196,8 +1195,8 @@ XiaomiGateway::xiaomi_udp_server::xiaomi_udp_server(boost::asio::io_service &io_ + if (!m_localip.empty()) + { + boost::system::error_code ec; +- boost::asio::ip::address listen_addr = boost::asio::ip::address::from_string(m_localip, ec); +- boost::asio::ip::address mcast_addr = boost::asio::ip::address::from_string("224.0.0.50", ec); ++ boost::asio::ip::address listen_addr = boost::asio::ip::make_address_v4(m_localip, ec); ++ boost::asio::ip::address mcast_addr = boost::asio::ip::make_address_v4("224.0.0.50", ec); + boost::asio::ip::udp::endpoint listen_endpoint(mcast_addr, 9898); + + socket_.bind(boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 9898)); +@@ -1213,9 +1212,9 @@ XiaomiGateway::xiaomi_udp_server::xiaomi_udp_server(boost::asio::io_service &io_ + socket_.bind(boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 9898)); + std::shared_ptr<std::string> message(new std::string(R"({"cmd":"whois"})")); + boost::asio::ip::udp::endpoint remote_endpoint; +- remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("224.0.0.50"), 4321); ++ remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::make_address_v4("224.0.0.50"), 4321); + socket_.send_to(boost::asio::buffer(*message), remote_endpoint); +- socket_.set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::address::from_string("224.0.0.50"))); ++ socket_.set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::make_address_v4("224.0.0.50"))); + } + } + catch (const boost::system::system_error &ex) +@@ -1720,7 +1719,7 @@ void XiaomiGateway::xiaomi_udp_server::handle_receive(const boost::system::error + message.append("\"}"); + std::shared_ptr<std::string> message1(new std::string(message)); + boost::asio::ip::udp::endpoint remote_endpoint; +- remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(TrueGateway->GetGatewayIp().c_str()), 9898); ++ remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::make_address_v4(TrueGateway->GetGatewayIp().c_str()), 9898); + socket_.send_to(boost::asio::buffer(*message1), remote_endpoint); + } + } +@@ -1746,7 +1745,7 @@ void XiaomiGateway::xiaomi_udp_server::handle_receive(const boost::system::error + std::string message = R"({"cmd" : "get_id_list"})"; + std::shared_ptr<std::string> message2(new std::string(message)); + boost::asio::ip::udp::endpoint remote_endpoint; +- remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string(TrueGateway->GetGatewayIp().c_str()), 9898); ++ remote_endpoint = boost::asio::ip::udp::endpoint(boost::asio::ip::make_address_v4(TrueGateway->GetGatewayIp().c_str()), 9898); + socket_.send_to(boost::asio::buffer(*message2), remote_endpoint); + } + } +diff --git hardware/XiaomiGateway.h hardware/XiaomiGateway.h +index dce4b34..1f552f3 100644 +--- hardware/XiaomiGateway.h ++++ hardware/XiaomiGateway.h +@@ -100,7 +100,7 @@ class XiaomiGateway : public CDomoticzHardwareBase + class xiaomi_udp_server + { + public: +- xiaomi_udp_server(boost::asio::io_service &io_service, int m_HwdID, const std::string &gatewayIp, const std::string &localIp, bool listenPort9898, bool outputMessage, ++ xiaomi_udp_server(boost::asio::io_context &io_context, int m_HwdID, const std::string &gatewayIp, const std::string &localIp, bool listenPort9898, bool outputMessage, + bool includeVolage, XiaomiGateway *parent); + ~xiaomi_udp_server() = default; + +diff --git hardware/Yeelight.cpp hardware/Yeelight.cpp +index cdb7889..e5fe8fc 100644 +--- hardware/Yeelight.cpp ++++ hardware/Yeelight.cpp +@@ -93,8 +93,8 @@ void Yeelight::Do_Work() + + try + { +- boost::asio::io_service io_service; +- udp_server server(io_service, m_HwdID); ++ boost::asio::io_context io_context; ++ udp_server server(io_context, m_HwdID); + int sec_counter = YEELIGHT_POLL_INTERVAL - 5; + while (!IsStopRequested(1000)) + { +@@ -105,7 +105,7 @@ void Yeelight::Do_Work() + if (sec_counter % 60 == 0) //poll YeeLights every minute + { + server.start_send(); +- io_service.run(); ++ io_context.run(); + } + } + } +@@ -227,12 +227,11 @@ bool Yeelight::WriteToHardware(const char *pdata, const unsigned char length) + + try + { +- boost::asio::io_service io_service; +- boost::asio::ip::tcp::socket sendSocket(io_service); +- boost::asio::ip::tcp::resolver resolver(io_service); +- boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), szTmp, "55443"); +- auto iterator = resolver.resolve(query); +- boost::asio::connect(sendSocket, iterator); ++ boost::asio::io_context io_context; ++ boost::asio::ip::tcp::socket sendSocket(io_context); ++ boost::asio::ip::tcp::resolver resolver(io_context); ++ auto endpoints = resolver.resolve(boost::asio::ip::tcp::v4(), szTmp, "55443"); ++ boost::asio::connect(sendSocket, endpoints); + + std::string message; + std::string message2; +@@ -404,8 +403,8 @@ bool Yeelight::WriteToHardware(const char *pdata, const unsigned char length) + std::array<char, 1024> recv_buffer_; + int hardwareId; + +-Yeelight::udp_server::udp_server(boost::asio::io_service& io_service, int m_HwdID) +- : socket_(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) ++Yeelight::udp_server::udp_server(boost::asio::io_context& io_context, int m_HwdID) ++ : socket_(io_context, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) + { + socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + socket_.set_option(boost::asio::socket_base::broadcast(true)); +@@ -421,7 +420,7 @@ void Yeelight::udp_server::start_send() + //Log(LOG_STATUS, "start_send.................."); + std::shared_ptr<std::string> message( + new std::string(testMessage)); +- remote_endpoint_ = boost::asio::ip::udp::endpoint(boost::asio::ip::address::from_string("239.255.255.250"), 1982); ++ remote_endpoint_ = boost::asio::ip::udp::endpoint(boost::asio::ip::make_address_v4("239.255.255.250"), 1982); + socket_.send_to(boost::asio::buffer(*message), remote_endpoint_); + sleep_milliseconds(150); + start_receive(); +diff --git hardware/Yeelight.h hardware/Yeelight.h +index fb03c28..3b7b4c3 100644 +--- hardware/Yeelight.h ++++ hardware/Yeelight.h +@@ -25,7 +25,7 @@ class Yeelight : public CDomoticzHardwareBase + class udp_server + { + public: +- udp_server(boost::asio::io_service &io_service, int m_HwdID); ++ udp_server(boost::asio::io_context &io_context, int m_HwdID); + boost::asio::ip::udp::socket socket_; + boost::asio::ip::udp::endpoint remote_endpoint_; + void start_send(); +diff --git hardware/plugins/PluginManager.cpp hardware/plugins/PluginManager.cpp +index 2813112..423edbb 100644 +--- hardware/plugins/PluginManager.cpp ++++ hardware/plugins/PluginManager.cpp +@@ -64,7 +64,7 @@ namespace Plugins { + // PyMODINIT_FUNC PyInit_DomoticzEvents(void); + + std::mutex PluginMutex; // controls accessto the message queue and m_pPlugins map +- boost::asio::io_service ios; ++ boost::asio::io_context ios; + + std::map<int, CDomoticzHardwareBase*> CPluginSystem::m_pPlugins; + std::map<std::string, std::string> CPluginSystem::m_PluginXml; +@@ -315,7 +315,7 @@ namespace Plugins { + // Create initial IO Service thread + ios.restart(); + // Create some work to keep IO Service alive +- auto work = boost::asio::io_service::work(ios); ++ auto work = boost::asio::make_work_guard(ios); + boost::thread_group BoostThreads; + for (int i = 0; i < 1; i++) + { +diff --git hardware/plugins/PluginTransports.cpp hardware/plugins/PluginTransports.cpp +index 52d14e7..f7ace0f 100644 +--- hardware/plugins/PluginTransports.cpp ++++ hardware/plugins/PluginTransports.cpp +@@ -116,15 +116,14 @@ namespace Plugins { + m_bConnected = false; + m_Socket = new boost::asio::ip::tcp::socket(ios); + +- boost::system::error_code ec; +- boost::asio::ip::tcp::resolver::query query(m_IP, m_Port); +- auto iter = m_Resolver.resolve(query); +- boost::asio::ip::tcp::endpoint endpoint = *iter; +- + // + // Async resolve/connect based on http://www.boost.org/doc/libs/1_45_0/doc/html/boost_asio/example/http/client/async_client.cpp + // +- m_Resolver.async_resolve(query, [this](auto &&err, auto end) { handleAsyncResolve(err, end); }); ++ m_Resolver.async_resolve(m_IP, m_Port, ++ [this](auto &&err, auto endpoints) { ++ handleAsyncResolve(err, endpoints); ++ } ++ ); + } + } + catch (std::exception& e) +@@ -139,15 +138,14 @@ namespace Plugins { + return true; + } + +- void CPluginTransportTCP::handleAsyncResolve(const boost::system::error_code & err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) ++ void CPluginTransportTCP::handleAsyncResolve(const boost::system::error_code & err, boost::asio::ip::tcp::resolver::results_type endpoints) + { + CPlugin* pPlugin = ((CConnection*)m_pConnection)->pPlugin; + AccessPython Guard(pPlugin, "CPluginTransportTCP::handleAsyncResolve"); + + if (!err) + { +- boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator; +- m_Socket->async_connect(endpoint, [this, endpoint_iterator](auto &&err) mutable { handleAsyncConnect(err, ++endpoint_iterator); }); ++ boost::asio::async_connect(*m_Socket, endpoints, [this](auto &&err, const boost::asio::ip::tcp::endpoint &endpoint) mutable { handleAsyncConnect(err, endpoint); }); + } + else + { +@@ -169,7 +167,7 @@ namespace Plugins { + } + } + +- void CPluginTransportTCP::handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::resolver::iterator &endpoint_iterator) ++ void CPluginTransportTCP::handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::endpoint &endpoint) + { + CPlugin* pPlugin = ((CConnection*)m_pConnection)->pPlugin; + AccessPython Guard(pPlugin, "CPluginTransportTCP::handleAsyncResolve"); +@@ -481,7 +479,7 @@ namespace Plugins { + } + }; + +- void CPluginTransportTCPSecure::handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::resolver::iterator &endpoint_iterator) ++ void CPluginTransportTCPSecure::handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::endpoint &endpoint) + { + CPlugin* pPlugin = ((CConnection*)m_pConnection)->pPlugin; + if (!pPlugin) return; +@@ -498,7 +496,7 @@ namespace Plugins { + SSL_set_tlsext_host_name(m_TLSSock->native_handle(), m_IP.c_str()); // Enable SNI + + m_TLSSock->set_verify_mode(boost::asio::ssl::verify_none); +- m_TLSSock->set_verify_callback(boost::asio::ssl::rfc2818_verification(m_IP)); ++ m_TLSSock->set_verify_callback(boost::asio::ssl::host_name_verification(m_IP)); + // m_TLSSock->set_verify_callback([this](auto v, auto &c){ VerifyCertificate(v, c);}); + try + { +@@ -648,7 +646,7 @@ namespace Plugins { + // Hanlde multicast + if (((m_IP.substr(0, 4) >= "224.") && (m_IP.substr(0, 4) <= "239.")) || (m_IP.substr(0, 4) == "255.")) + { +- m_Socket->set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::address::from_string(m_IP.c_str())), ec); ++ m_Socket->set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::make_address_v4(m_IP.c_str())), ec); + m_Socket->set_option(boost::asio::ip::multicast::hops(2), ec); + } + } +@@ -764,7 +762,7 @@ namespace Plugins { + } + else + { +- boost::asio::ip::udp::endpoint destination(boost::asio::ip::address::from_string(m_IP.c_str()), atoi(m_Port.c_str())); ++ boost::asio::ip::udp::endpoint destination(boost::asio::ip::make_address_v4(m_IP.c_str()), atoi(m_Port.c_str())); + size_t bytes_transferred = m_Socket->send_to(boost::asio::buffer(pMessage, pMessage.size()), destination); + } + } +@@ -825,12 +823,14 @@ namespace Plugins { + } + }; + +- void CPluginTransportICMP::handleAsyncResolve(const boost::system::error_code &ec, const boost::asio::ip::icmp::resolver::iterator &endpoint_iterator) ++ void CPluginTransportICMP::handleAsyncResolve(const boost::system::error_code &ec, boost::asio::ip::icmp::resolver::results_type endpoints) + { + if (!ec) + { ++ m_Endpoint = endpoints.begin()->endpoint(); ++ m_IP = m_Endpoint.address().to_string(); ++ + m_bConnected = true; +- m_IP = endpoint_iterator->endpoint().address().to_string(); + + // Listen will fail (10022 - bad parameter) unless something has been sent(?) + std::string body("ping"); +@@ -857,15 +857,11 @@ namespace Plugins { + m_bConnecting = true; + m_Socket = new boost::asio::ip::icmp::socket(ios, boost::asio::ip::icmp::v4()); + +- boost::system::error_code ec; +- boost::asio::ip::icmp::resolver::query query(boost::asio::ip::icmp::v4(), m_IP, ""); +- auto iter = m_Resolver.resolve(query); +- m_Endpoint = *iter; +- +- // +- // Async resolve/connect based on http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/example/icmp/ping.cpp +- // +- m_Resolver.async_resolve(query, [this](auto &&err, auto i) { handleAsyncResolve(err, i); }); ++ m_Resolver.async_resolve(boost::asio::ip::icmp::v4(), m_IP, "", ++ [this](auto &&err, auto endpoints) { ++ handleAsyncResolve(err, endpoints); ++ } ++ ); + } + else + { +diff --git hardware/plugins/PluginTransports.h hardware/plugins/PluginTransports.h +index c1cc1e3..79d5725 100644 +--- hardware/plugins/PluginTransports.h ++++ hardware/plugins/PluginTransports.h +@@ -6,7 +6,7 @@ + + namespace Plugins { + +- extern boost::asio::io_service ios; ++ extern boost::asio::io_context ios; + + class CPluginTransport + { +@@ -85,8 +85,8 @@ namespace Plugins { + , m_Socket(nullptr){}; + bool handleConnect() override; + bool handleListen() override; +- virtual void handleAsyncResolve(const boost::system::error_code &err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); +- virtual void handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::resolver::iterator &endpoint_iterator); ++ virtual void handleAsyncResolve(const boost::system::error_code &err, boost::asio::ip::tcp::resolver::results_type endpoints); ++ virtual void handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::endpoint &endpoint); + virtual void handleAsyncAccept(boost::asio::ip::tcp::socket *pSocket, const boost::system::error_code &error); + void handleRead(const boost::system::error_code &e, std::size_t bytes_transferred) override; + void handleWrite(const std::vector<byte> &pMessage) override; +@@ -111,7 +111,7 @@ namespace Plugins { + : CPluginTransportTCP(HwdID, pConnection, Address, Port) + , m_Context(nullptr) + , m_TLSSock(nullptr){}; +- void handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::resolver::iterator &endpoint_iterator) override; ++ void handleAsyncConnect(const boost::system::error_code &err, const boost::asio::ip::tcp::endpoint &endpoint) override; + void handleRead(const boost::system::error_code &e, std::size_t bytes_transferred) override; + void handleWrite(const std::vector<byte> &pMessage) override; + ~CPluginTransportTCPSecure() override; +@@ -151,7 +151,7 @@ namespace Plugins { + , m_Socket(nullptr) + , m_Timer(nullptr) + , m_SequenceNo(-1){}; +- void handleAsyncResolve(const boost::system::error_code &err, const boost::asio::ip::icmp::resolver::iterator &endpoint_iterator); ++ void handleAsyncResolve(const boost::system::error_code &err, boost::asio::ip::icmp::resolver::results_type endpoints); + bool handleListen() override; + void handleTimeout(const boost::system::error_code &) override; + void handleRead(const boost::system::error_code &e, std::size_t bytes_transferred) override; +diff --git main/WebServerCmds.cpp main/WebServerCmds.cpp +index 7d4a9f2..3586373 100644 +--- main/WebServerCmds.cpp ++++ main/WebServerCmds.cpp +@@ -1632,7 +1632,7 @@ namespace http + ExtraHeaders.push_back("App_Revision: " + std::to_string(iAppRevision)); + ExtraHeaders.push_back("System_Name: " + systemname); + ExtraHeaders.push_back("Machine: " + machine); +- ExtraHeaders.push_back("Type: " + (!bIsBetaChannel) ? "Stable" : "Beta"); ++ ExtraHeaders.push_back("Type: " + std::string(!bIsBetaChannel ? "Stable" : "Beta")); + + if (!HTTPClient::GET(szHistoryURL, ExtraHeaders, historyfile)) + { +diff --git main/mainworker.cpp main/mainworker.cpp +index b5027eb..b8f8dc7 100644 +--- main/mainworker.cpp ++++ main/mainworker.cpp +@@ -1318,7 +1318,7 @@ bool MainWorker::IsUpdateAvailable(const bool bIsForced) + ExtraHeaders.push_back("App_Revision: " + std::to_string(iAppRevision)); + ExtraHeaders.push_back("System_Name: " + m_szSystemName); + ExtraHeaders.push_back("Machine: " + machine); +- ExtraHeaders.push_back("Type: " + (!bIsBetaChannel) ? "Stable" : "Beta"); ++ ExtraHeaders.push_back("Type: " + std::string(!bIsBetaChannel ? "Stable" : "Beta")); + + if (!HTTPClient::GET(szURL, ExtraHeaders, revfile)) + return false; +diff --git plugins/examples/Pinger.py plugins/examples/Pinger.py +index 6b54559..c7a776d 100644 +--- plugins/examples/Pinger.py ++++ plugins/examples/Pinger.py +@@ -3,7 +3,7 @@ + # Author: Dnpwwo, 2017 - 2018 + # + """ +-<plugin key="ICMP" name="Pinger (ICMP)" author="dnpwwo" version="3.1.4"> ++<plugin key="ICMP" name="Pinger (ICMP)" author="dnpwwo" version="3.1.5"> + <description> + ICMP Pinger Plugin.<br/><br/> + Specify comma delimted addresses (IP or DNS names) of devices that are to be pinged.<br/> +@@ -144,8 +144,9 @@ class BasePlugin: + for Device in Devices: + if (("Name" in Devices[Device].Options) and (Devices[Device].Options["Name"] == Connection.Name)): + UpdateDevice(Device, 0, "Off", TimedOut) +- self.icmpConn.Close() +- self.icmpConn = None ++ if (self.icmpConn != None): ++ self.icmpConn.Close() ++ self.icmpConn = None + + def onHeartbeat(self): + Domoticz.Debug("Heartbeating...") +diff --git push/MQTTPush.h push/MQTTPush.h +index 0773b43..d9f9332 100644 +--- push/MQTTPush.h ++++ push/MQTTPush.h +@@ -14,7 +14,7 @@ public: + void on_message(const struct mosquitto_message* message) override; + void on_connect(int rc) override; + void on_disconnect(int rc) override; +- void on_going_down(); ++ void on_going_down() override; + private: + struct _tPushItem + { +diff --git tcpserver/TCPClient.cpp tcpserver/TCPClient.cpp +index d55da10..3eee093 100644 +--- tcpserver/TCPClient.cpp ++++ tcpserver/TCPClient.cpp +@@ -19,7 +19,7 @@ namespace tcp { + delete socket_; + } + +- CTCPClient::CTCPClient(boost::asio::io_service& ios, CTCPServerIntBase* pManager) ++ CTCPClient::CTCPClient(boost::asio::io_context& ios, CTCPServerIntBase* pManager) + : CTCPClientBase(pManager) + { + socket_ = new boost::asio::ip::tcp::socket(ios); +diff --git tcpserver/TCPClient.h tcpserver/TCPClient.h +index df4350d..e7a882b 100644 +--- tcpserver/TCPClient.h ++++ tcpserver/TCPClient.h +@@ -38,7 +38,7 @@ class CTCPClient : public CTCPClientBase, + public std::enable_shared_from_this<CTCPClient> + { + public: +- CTCPClient(boost::asio::io_service& ios, CTCPServerIntBase *pManager); ++ CTCPClient(boost::asio::io_context& ios, CTCPServerIntBase *pManager); + ~CTCPClient() = default; + void start() override; + void stop() override; +diff --git tcpserver/TCPServer.cpp tcpserver/TCPServer.cpp +index 91fdc7e..57f8709 100644 +--- tcpserver/TCPServer.cpp ++++ tcpserver/TCPServer.cpp +@@ -18,14 +18,14 @@ namespace tcp { + + CTCPServerInt::CTCPServerInt(const std::string& address, const std::string& port, CTCPServer* pRoot) : + CTCPServerIntBase(pRoot), +- io_service_(), +- acceptor_(io_service_) ++ io_context_(), ++ acceptor_(io_context_) + { + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). +- boost::asio::ip::tcp::resolver resolver(io_service_); +- boost::asio::ip::tcp::resolver::query query(address, port); +- boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); +- acceptor_.open(endpoint.protocol()); ++ boost::asio::ip::tcp::resolver resolver(io_context_); ++ boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::results_type endpoints = resolver.resolve(address, port); ++ auto endpoint = *endpoints.begin(); ++ acceptor_.open(endpoint.endpoint().protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + // bind to both ipv6 and ipv4 sockets for the "::" address only + if (address == "::") +@@ -35,7 +35,7 @@ namespace tcp { + acceptor_.bind(endpoint); + acceptor_.listen(); + +- new_connection_ = std::make_shared<CTCPClient>(io_service_, this); ++ new_connection_ = std::make_shared<CTCPClient>(io_context_, this); + if (new_connection_ == nullptr) + { + _log.Log(LOG_ERROR, "Error creating new client!"); +@@ -47,24 +47,24 @@ namespace tcp { + + void CTCPServerInt::start() + { +- // The io_service::run() call will block until all asynchronous operations ++ // The io_context::run() call will block until all asynchronous operations + // have finished. While the server is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. +- io_service_.run(); ++ io_context_.run(); + } + + void CTCPServerInt::stop() + { + // Post a call to the stop function so that server::stop() is safe to call + // from any thread. +- io_service_.post([this] { handle_stop(); }); ++ boost::asio::post([this] { handle_stop(); }); + } + + void CTCPServerInt::handle_stop() + { + // The server is stopped by cancelling all outstanding asynchronous +- // operations. Once all operations have finished the io_service::run() call ++ // operations. Once all operations have finished the io_context::run() call + // will exit. + acceptor_.close(); + stopAllClients(); +@@ -88,7 +88,7 @@ namespace tcp { + connections_.insert(new_connection_); + new_connection_->start(); + +- new_connection_.reset(new CTCPClient(io_service_, this)); ++ new_connection_.reset(new CTCPClient(io_context_, this)); + + acceptor_.async_accept(*(new_connection_->socket()), [this](auto&& err) { handleAccept(err); }); + } +diff --git tcpserver/TCPServer.h tcpserver/TCPServer.h +index ca611b1..17284ca 100644 +--- tcpserver/TCPServer.h ++++ tcpserver/TCPServer.h +@@ -70,8 +70,8 @@ private: + /// Handle a request to stop the server. + void handle_stop(); + +- /// The io_service used to perform asynchronous operations. +- boost::asio::io_service io_service_; ++ /// The io_context used to perform asynchronous operations. ++ boost::asio::io_context io_context_; + + boost::asio::ip::tcp::acceptor acceptor_; + +diff --git webserver/cWebem.cpp webserver/cWebem.cpp +index 57d9683..c0d292d 100644 +--- webserver/cWebem.cpp ++++ webserver/cWebem.cpp +@@ -47,13 +47,13 @@ namespace http { + , myRequestHandler(doc_root, this) + // Rene, make sure we initialize m_sessions first, before starting a server + , myServer(server_factory::create(settings, myRequestHandler)) +- , m_io_service() +- , m_session_clean_timer(m_io_service, boost::posix_time::minutes(1)) ++ , m_io_context() ++ , m_session_clean_timer(m_io_context, boost::posix_time::minutes(1)) + { + // associate handler to timer and schedule the first iteration + m_session_clean_timer.async_wait([this](auto &&) { CleanSessions(); }); +- m_io_service_thread = std::make_shared<std::thread>([p = &m_io_service] { p->run(); }); +- SetThreadName(m_io_service_thread->native_handle(), "Webem_ssncleaner"); ++ m_io_context_thread = std::make_shared<std::thread>([p = &m_io_context] { p->run(); }); ++ SetThreadName(m_io_context_thread->native_handle(), "Webem_ssncleaner"); + } + + cWebem::~cWebem() +@@ -93,14 +93,14 @@ namespace http { + // Stop session cleaner + try + { +- if (!m_io_service.stopped()) ++ if (!m_io_context.stopped()) + { +- m_io_service.stop(); ++ m_io_context.stop(); + } +- if (m_io_service_thread) ++ if (m_io_context_thread) + { +- m_io_service_thread->join(); +- m_io_service_thread.reset(); ++ m_io_context_thread->join(); ++ m_io_context_thread.reset(); + } + } + catch (...) +diff --git webserver/cWebem.h webserver/cWebem.h +index 6e3b899..7905c45 100644 +--- webserver/cWebem.h ++++ webserver/cWebem.h +@@ -259,9 +259,9 @@ namespace http + std::string m_webRoot; + /// sessions management + std::mutex m_sessionsMutex; +- boost::asio::io_service m_io_service; ++ boost::asio::io_context m_io_context; + boost::asio::deadline_timer m_session_clean_timer; +- std::shared_ptr<std::thread> m_io_service_thread; ++ std::shared_ptr<std::thread> m_io_context_thread; + }; + + } // namespace server +diff --git webserver/connection.cpp webserver/connection.cpp +index 40f9788..3a70924 100644 +--- webserver/connection.cpp ++++ webserver/connection.cpp +@@ -22,13 +22,13 @@ namespace http { + extern time_t last_write_time(const std::string& path); + + // this is the constructor for plain connections +- connection::connection(boost::asio::io_service &io_service, connection_manager &manager, request_handler &handler, int read_timeout) ++ connection::connection(boost::asio::io_context &io_context, connection_manager &manager, request_handler &handler, int read_timeout) + : send_buffer_(nullptr) + , read_timeout_(read_timeout) +- , read_timer_(io_service, boost::posix_time::seconds(read_timeout)) ++ , read_timer_(io_context, boost::posix_time::seconds(read_timeout)) + , default_abandoned_timeout_(20 * 60) + // 20mn before stopping abandoned connection +- , abandoned_timer_(io_service, boost::posix_time::seconds(default_abandoned_timeout_)) ++ , abandoned_timer_(io_context, boost::posix_time::seconds(default_abandoned_timeout_)) + , connection_manager_(manager) + , request_handler_(handler) + , status_(INITIALIZING) +@@ -39,18 +39,18 @@ namespace http { + keepalive_ = false; + write_in_progress = false; + connection_type = ConnectionType::connection_http; +- socket_ = std::make_unique<boost::asio::ip::tcp::socket>(io_service); ++ socket_ = std::make_unique<boost::asio::ip::tcp::socket>(io_context); + } + + #ifdef WWW_ENABLE_SSL + // this is the constructor for secure connections +- connection::connection(boost::asio::io_service &io_service, connection_manager &manager, request_handler &handler, int read_timeout, boost::asio::ssl::context &context) ++ connection::connection(boost::asio::io_context &io_context, connection_manager &manager, request_handler &handler, int read_timeout, boost::asio::ssl::context &context) + : send_buffer_(nullptr) + , read_timeout_(read_timeout) +- , read_timer_(io_service, boost::posix_time::seconds(read_timeout)) ++ , read_timer_(io_context, boost::posix_time::seconds(read_timeout)) + , default_abandoned_timeout_(20 * 60) + // 20mn before stopping abandoned connection +- , abandoned_timer_(io_service, boost::posix_time::seconds(default_abandoned_timeout_)) ++ , abandoned_timer_(io_context, boost::posix_time::seconds(default_abandoned_timeout_)) + , connection_manager_(manager) + , request_handler_(handler) + , status_(INITIALIZING) +@@ -62,7 +62,7 @@ namespace http { + write_in_progress = false; + connection_type = ConnectionType::connection_http; + socket_ = nullptr; +- sslsocket_ = std::make_unique<ssl_socket>(io_service, context); ++ sslsocket_ = std::make_unique<ssl_socket>(io_context, context); + } + #endif + +@@ -152,9 +152,9 @@ namespace http { + if (error != boost::asio::error::operation_aborted) { + switch (connection_type) { + case ConnectionType::connection_http: +- // Timers should be cancelled before stopping to remove tasks from the io_service. +- // The io_service will stop naturally when every tasks are removed. +- // If timers are not cancelled, the exception ERROR_ABANDONED_WAIT_0 is thrown up to the io_service::run() caller. ++ // Timers should be cancelled before stopping to remove tasks from the io_context. ++ // The io_context will stop naturally when every tasks are removed. ++ // If timers are not cancelled, the exception ERROR_ABANDONED_WAIT_0 is thrown up to the io_context::run() caller. + cancel_abandoned_timeout(); + cancel_read_timeout(); + +@@ -372,7 +372,7 @@ namespace http { + switch (connection_type) + { + case ConnectionType::connection_http: +- begin = boost::asio::buffer_cast<const char*>(_buf.data()); ++ begin = static_cast<const char*>(_buf.data().data()); + try + { + request_parser_.reset(); +@@ -404,7 +404,7 @@ namespace http { + newt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + } + +- size_t sizeread = begin - boost::asio::buffer_cast<const char*>(_buf.data()); ++ size_t sizeread = begin - static_cast<const char*>(_buf.data().data()); + _buf.consume(sizeread); + reply_.reset(); + const char* pConnection = request_.get_req_header(&request_, "Connection"); +@@ -520,7 +520,7 @@ namespace http { + break; + case ConnectionType::connection_websocket: + case ConnectionType::connection_websocket_closing: +- begin = boost::asio::buffer_cast<const char*>(_buf.data()); ++ begin = static_cast<const char*>(_buf.data().data()); + result = websocket_parser.parse((const unsigned char*)begin, _buf.size(), bytes_consumed, keepalive_); + _buf.consume(bytes_consumed); + if (result) { +diff --git webserver/connection.hpp webserver/connection.hpp +index ce452b5..c1a82c5 100644 +--- webserver/connection.hpp ++++ webserver/connection.hpp +@@ -43,11 +43,11 @@ namespace http { + std::string host_local_endpoint_port_; + std::string host_last_request_uri_; + }; +- /// Construct a connection with the given io_service. +- explicit connection(boost::asio::io_service& io_service, ++ /// Construct a connection with the given io_context. ++ explicit connection(boost::asio::io_context& io_context, + connection_manager& manager, request_handler& handler, int timeout); + #ifdef WWW_ENABLE_SSL +- explicit connection(boost::asio::io_service& io_service, ++ explicit connection(boost::asio::io_context& io_context, + connection_manager& manager, request_handler& handler, int timeout, boost::asio::ssl::context& context); + #endif + ~connection() = default; +diff --git webserver/server.cpp webserver/server.cpp +index da15887..8bdfc13 100644 +--- webserver/server.cpp ++++ webserver/server.cpp +@@ -13,15 +13,15 @@ namespace http { + namespace server { + + server_base::server_base(const server_settings &settings, request_handler &user_request_handler) +- : io_service_() +- , acceptor_(io_service_) ++ : io_context_() ++ , acceptor_(io_context_) + , request_handler_(user_request_handler) + , settings_(settings) + , timeout_(20) + , // default read timeout in seconds + is_running(false) + , is_stop_complete(false) +- , m_heartbeat_timer(io_service_) ++ , m_heartbeat_timer(io_context_) + { + if (!settings.is_enabled()) + { +@@ -39,10 +39,10 @@ namespace server { + } + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). +- boost::asio::ip::tcp::resolver resolver(io_service_); +- boost::asio::ip::tcp::resolver::query query(settings_.listening_address, settings_.listening_port); +- boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); +- acceptor_.open(endpoint.protocol()); ++ boost::asio::ip::tcp::resolver resolver(io_context_); ++ boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::results_type endpoints = resolver.resolve(settings_.listening_address, settings_.listening_port); ++ auto endpoint = *endpoints.begin(); ++ acceptor_.open(endpoint.endpoint().protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + // bind to both ipv6 and ipv4 sockets for the "::" address only + if (settings_.listening_address == "::") +@@ -59,28 +59,28 @@ namespace server { + } + + void server_base::run() { +- // The io_service::run() call will block until all asynchronous operations ++ // The io_context::run() call will block until all asynchronous operations + // have finished. While the server is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. + try { + is_running = true; + heart_beat(boost::system::error_code()); +- io_service_.run(); ++ io_context_.run(); + is_running = false; + } catch (std::exception& e) { + _log.Log(LOG_ERROR, "[web:%s] exception occurred : '%s' (need to run again)", settings_.listening_port.c_str(), e.what()); + is_running = false; + // Note: if acceptor is up everything is OK, we can call run() again + // but if the exception has broken the acceptor we cannot stop/start it and the next run() will exit immediatly. +- io_service_.reset(); // this call is needed before calling run() again ++ io_context_.restart(); // this call is needed before calling run() again + throw; + } catch (...) { + _log.Log(LOG_ERROR, "[web:%s] unknown exception occurred (need to run again)", settings_.listening_port.c_str()); + is_running = false; + // Note: if acceptor is up everything is OK, we can call run() again + // but if the exception has broken the acceptor we cannot stop/start it and the next run() will exit immediatly. +- io_service_.reset(); // this call is needed before calling run() again ++ io_context_.restart(); // this call is needed before calling run() again + throw; + } + } +@@ -89,12 +89,12 @@ void server_base::run() { + void server_base::stop() { + if (is_running) { + // Post a call to the stop function so that server_base::stop() is safe to call from any thread. +- // Rene, set is_running to false, because the following is an io_service call, which makes is_running ++ // Rene, set is_running to false, because the following is an io_context call, which makes is_running + // never set to false whilst in the call itself + is_running = false; +- io_service_.post([this] { handle_stop(); }); ++ boost::asio::post(io_context_, [this] { handle_stop(); }); + } else { +- // if io_service is not running then the post call will not be performed ++ // if io_context is not running then the post call will not be performed + handle_stop(); + } + +@@ -112,7 +112,7 @@ void server_base::stop() { + } + sleep_milliseconds(500); + } +- io_service_.stop(); ++ io_context_.stop(); + + // Deregister heartbeat + m_mainworker.HeartbeatRemove(std::string("WebServer:") + settings_.listening_port); +@@ -136,7 +136,7 @@ void server_base::heart_beat(const boost::system::error_code& error) + m_mainworker.HeartbeatUpdate(std::string("WebServer:") + settings_.listening_port); + + // Schedule next heartbeat +- m_heartbeat_timer.expires_from_now(std::chrono::seconds(4)); ++ m_heartbeat_timer.expires_after(std::chrono::seconds(4)); + m_heartbeat_timer.async_wait([this](auto &&err) { heart_beat(err); }); + } + } +@@ -148,7 +148,7 @@ server::server(const server_settings &settings, request_handler &user_request_ha + } + + void server::init_connection() { +- new_connection_.reset(new connection(io_service_, connection_manager_, request_handler_, timeout_)); ++ new_connection_.reset(new connection(io_context_, connection_manager_, request_handler_, timeout_)); + } + + /** +@@ -157,7 +157,7 @@ void server::init_connection() { + void server::handle_accept(const boost::system::error_code& e) { + if (!e) { + connection_manager_.start(new_connection_); +- new_connection_.reset(new connection(io_service_, ++ new_connection_.reset(new connection(io_context_, + connection_manager_, request_handler_, timeout_)); + // listen for a subsequent request + acceptor_.async_accept(new_connection_->socket(), [this](auto &&err) { handle_accept(err); }); +@@ -267,7 +267,7 @@ void ssl_server::init_connection() { + } else { + _log.Log(LOG_ERROR, "[web:%s] missing SSL DH parameters file %s!", settings_.listening_port.c_str(), settings_.tmp_dh_file_path.c_str()); + } +- new_connection_.reset(new connection(io_service_, connection_manager_, request_handler_, timeout_, context_)); ++ new_connection_.reset(new connection(io_context_, connection_manager_, request_handler_, timeout_, context_)); + } + + void ssl_server::reinit_connection() +@@ -305,7 +305,7 @@ void ssl_server::reinit_connection() + _log.Log(LOG_ERROR, "[web:%s] missing SSL DH parameters from file %s", settings_.listening_port.c_str(), settings_.tmp_dh_file_path.c_str()); + } + } +- new_connection_.reset(new connection(io_service_, connection_manager_, request_handler_, timeout_, context_)); ++ new_connection_.reset(new connection(io_context_, connection_manager_, request_handler_, timeout_, context_)); + } + + /** +diff --git webserver/server.hpp webserver/server.hpp +index f9e71c5..bd7132a 100644 +--- webserver/server.hpp ++++ webserver/server.hpp +@@ -31,7 +31,7 @@ namespace http + explicit server_base(const server_settings &settings, request_handler &user_request_handler); + virtual ~server_base() = default; + +- /// Run the server's io_service loop. ++ /// Run the server's io_context loop. + void run(); + + /// Stop the server. +@@ -46,8 +46,8 @@ namespace http + protected: + void init(const init_connectionhandler_func &init_connection_handler, accept_handler_func accept_handler); + +- /// The io_service used to perform asynchronous operations. +- boost::asio::io_service io_service_; ++ /// The io_context used to perform asynchronous operations. ++ boost::asio::io_context io_context_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; |