From 153d0040044277c1a725fb92e046c3d705a76143 Mon Sep 17 00:00:00 2001 From: badaix Date: Fri, 10 May 2024 09:57:27 +0200 Subject: [PATCH] Reenable plain HTTP, change HTTPS port to 1788 --- server/control_server.cpp | 117 +++++++++++++------------ server/control_server.hpp | 7 +- server/control_session_http.cpp | 147 ++++++++++++++++++++++---------- server/control_session_http.hpp | 13 ++- server/control_session_ws.cpp | 36 ++++++-- server/control_session_ws.hpp | 10 ++- server/etc/snapserver.conf | 6 ++ server/server_settings.hpp | 2 + server/snapserver.cpp | 9 ++ server/stream_session_ws.cpp | 50 ++++++++--- server/stream_session_ws.hpp | 9 +- 11 files changed, 264 insertions(+), 142 deletions(-) diff --git a/server/control_server.cpp b/server/control_server.cpp index 48a08ee4..208efccc 100644 --- a/server/control_server.cpp +++ b/server/control_server.cpp @@ -44,7 +44,12 @@ ControlServer::ControlServer(boost::asio::io_context& io_context, const ServerSe { const ServerSettings::Ssl& ssl = settings.ssl; ssl_context_.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); - ssl_context_.set_password_callback(std::bind(&ControlServer::getPassword, this)); + ssl_context_.set_password_callback( + [](size_t max_length, boost::asio::ssl::context_base::password_purpose purpose) -> string + { + LOG(DEBUG, LOG_TAG) << "getPassword, purpose: " << purpose << ", max length: " << max_length << "\n"; + return "test"; + }); ssl_context_.use_certificate_chain_file(ssl.certificate); ssl_context_.use_private_key_file(ssl.private_key, boost::asio::ssl::context::pem); // ssl_context_.use_tmp_dh_file("dh4096.pem"); @@ -57,13 +62,6 @@ ControlServer::~ControlServer() } -std::string ControlServer::getPassword() const -{ - LOG(DEBUG, LOG_TAG) << "getPassword\n"; - return "test"; -} - - void ControlServer::cleanup() { auto new_end = std::remove_if(sessions_.begin(), sessions_.end(), [](const std::weak_ptr& session) { return session.expired(); }); @@ -117,59 +115,50 @@ void ControlServer::onNewSession(std::shared_ptr session) void ControlServer::startAccept() { - auto accept_handler_tcp = [this](error_code ec, tcp::socket socket) - { - if (!ec) - handleAccept(std::move(socket)); - else - LOG(ERROR, LOG_TAG) << "Error while accepting socket connection: " << ec.message() << "\n"; - }; - - auto accept_handler_http = [this](error_code ec, tcp::socket socket) + auto accept_handler = [this](error_code ec, tcp::socket socket) { if (!ec) { - // handleAccept(std::move(socket), http_settings_); - auto session = make_shared(this, std::move(socket), ssl_context_, http_settings_); - onNewSession(std::move(session)); + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + // socket->set_option(boost::asio::ip::tcp::no_delay(false)); + auto port = socket.local_endpoint().port(); + LOG(NOTICE, LOG_TAG) << "New connection from: " << socket.remote_endpoint().address().to_string() << ", port: " << port << endl; + + if (port == http_settings_.ssl_port) + { + auto session = make_shared(this, ssl_socket(std::move(socket), ssl_context_), http_settings_); + onNewSession(std::move(session)); + } + else if (port == http_settings_.port) + { + auto session = make_shared(this, std::move(socket), http_settings_); + onNewSession(std::move(session)); + } + else if (port == tcp_settings_.port) + { + auto session = make_shared(this, std::move(socket)); + onNewSession(std::move(session)); + } + else + { + LOG(ERROR, LOG_TAG) << "Port unknown, should not listen on this port?!?\n"; + } + startAccept(); } else LOG(ERROR, LOG_TAG) << "Error while accepting socket connection: " << ec.message() << "\n"; }; - for (auto& acceptor : acceptor_tcp_) - acceptor->async_accept(accept_handler_tcp); - - for (auto& acceptor : acceptor_http_) - acceptor->async_accept(accept_handler_http); + for (auto& acceptor : acceptor_) + acceptor->async_accept(accept_handler); } -template -void ControlServer::handleAccept(tcp::socket socket, Args&&... args) -{ - try - { - struct timeval tv; - tv.tv_sec = 5; - tv.tv_usec = 0; - setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - // socket->set_option(boost::asio::ip::tcp::no_delay(false)); - LOG(NOTICE, LOG_TAG) << "ControlServer::NewConnection: " << socket.remote_endpoint().address().to_string() << endl; - shared_ptr session = make_shared(this, std::move(socket), std::forward(args)...); - onNewSession(std::move(session)); - } - catch (const std::exception& e) - { - LOG(ERROR, LOG_TAG) << "Exception in ControlServer::handleAccept: " << e.what() << endl; - } - startAccept(); -} - - - void ControlServer::start() { if (tcp_settings_.enabled) @@ -179,8 +168,8 @@ void ControlServer::start() try { LOG(INFO, LOG_TAG) << "Creating TCP acceptor for address: " << address << ", port: " << tcp_settings_.port << "\n"; - acceptor_tcp_.emplace_back(make_unique(boost::asio::make_strand(io_context_.get_executor()), - tcp::endpoint(boost::asio::ip::make_address(address), tcp_settings_.port))); + acceptor_.emplace_back(make_unique(boost::asio::make_strand(io_context_.get_executor()), + tcp::endpoint(boost::asio::ip::address::from_string(address), tcp_settings_.port))); } catch (const boost::system::system_error& e) { @@ -195,8 +184,22 @@ void ControlServer::start() try { LOG(INFO, LOG_TAG) << "Creating HTTP acceptor for address: " << address << ", port: " << http_settings_.port << "\n"; - acceptor_http_.emplace_back(make_unique(boost::asio::make_strand(io_context_.get_executor()), - tcp::endpoint(boost::asio::ip::make_address(address), http_settings_.port))); + acceptor_.emplace_back(make_unique(boost::asio::make_strand(io_context_.get_executor()), + tcp::endpoint(boost::asio::ip::address::from_string(address), http_settings_.port))); + } + catch (const boost::system::system_error& e) + { + LOG(ERROR, LOG_TAG) << "error creating HTTP acceptor: " << e.what() << ", code: " << e.code() << "\n"; + } + } + + for (const auto& address : http_settings_.ssl_bind_to_address) + { + try + { + LOG(INFO, LOG_TAG) << "Creating HTTPS acceptor for address: " << address << ", port: " << http_settings_.ssl_port << "\n"; + acceptor_.emplace_back(make_unique(boost::asio::make_strand(io_context_.get_executor()), + tcp::endpoint(boost::asio::ip::address::from_string(address), http_settings_.ssl_port))); } catch (const boost::system::system_error& e) { @@ -211,14 +214,10 @@ void ControlServer::start() void ControlServer::stop() { - for (auto& acceptor : acceptor_tcp_) + for (auto& acceptor : acceptor_) acceptor->cancel(); - for (auto& acceptor : acceptor_http_) - acceptor->cancel(); - - acceptor_tcp_.clear(); - acceptor_http_.clear(); + acceptor_.clear(); std::lock_guard mlock(session_mutex_); cleanup(); diff --git a/server/control_server.hpp b/server/control_server.hpp index 8f5d3f92..7e770f39 100644 --- a/server/control_server.hpp +++ b/server/control_server.hpp @@ -55,8 +55,6 @@ public: private: void startAccept(); - template - void handleAccept(tcp::socket socket, Args&&... args); void cleanup(); /// Implementation of ControlMessageReceiver @@ -64,13 +62,10 @@ private: void onNewSession(std::shared_ptr session) override; void onNewSession(std::shared_ptr session) override; - std::string getPassword() const; - mutable std::recursive_mutex session_mutex_; std::vector> sessions_; - std::vector acceptor_tcp_; - std::vector acceptor_http_; + std::vector acceptor_; boost::asio::io_context& io_context_; boost::asio::ssl::context ssl_context_; diff --git a/server/control_session_http.cpp b/server/control_session_http.cpp index 828382b2..5e2e944b 100644 --- a/server/control_session_http.cpp +++ b/server/control_session_http.cpp @@ -147,11 +147,16 @@ std::string path_cat(boost::beast::string_view base, boost::beast::string_view p } } // namespace -ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, tcp_socket&& socket, boost::asio::ssl::context& ssl_context, - const ServerSettings::Http& settings) - : ControlSession(receiver), ssl_socket_(ssl_socket(std::move(socket), ssl_context)), ssl_context_(ssl_context), settings_(settings) +ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, ssl_socket&& socket, const ServerSettings::Http& settings) + : ControlSession(receiver), ssl_socket_(std::move(socket)), settings_(settings), is_ssl_(true) { - LOG(DEBUG, LOG_TAG) << "ControlSessionHttp, mode: ssl, Local IP: " << ssl_socket_.next_layer().local_endpoint().address().to_string() << "\n"; + LOG(DEBUG, LOG_TAG) << "ControlSessionHttp, mode: ssl, Local IP: " << ssl_socket_->next_layer().local_endpoint().address().to_string() << "\n"; +} + +ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, tcp_socket&& socket, const ServerSettings::Http& settings) + : ControlSession(receiver), tcp_socket_(std::move(socket)), settings_(settings), is_ssl_(false) +{ + LOG(DEBUG, LOG_TAG) << "ControlSessionHttp, mode: tcp, Local IP: " << tcp_socket_->local_endpoint().address().to_string() << "\n"; } @@ -165,21 +170,28 @@ ControlSessionHttp::~ControlSessionHttp() void ControlSessionHttp::start() { LOG(DEBUG, LOG_TAG) << "start\n"; - ssl_socket_.async_handshake(boost::asio::ssl::stream_base::server, - [this, self = shared_from_this()](const boost::system::error_code& error) - { - LOG(DEBUG, LOG_TAG) << "async_handshake\n"; - if (error) - { - LOG(ERROR, LOG_TAG) << "async_handshake error: " << error.message() << "\n"; - } - else - { - http::async_read(ssl_socket_, buffer_, req_, - [this, self = shared_from_this()](boost::system::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); - } - }); - // http::async_read(tcp_socket_, buffer_, req_, [this, self = shared_from_this()](boost::system::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); + if (is_ssl_) + { + ssl_socket_->async_handshake(boost::asio::ssl::stream_base::server, + [this, self = shared_from_this()](const boost::system::error_code& error) + { + LOG(DEBUG, LOG_TAG) << "async_handshake\n"; + if (error) + { + LOG(ERROR, LOG_TAG) << "async_handshake error: " << error.message() << "\n"; + } + else + { + http::async_read(*ssl_socket_, buffer_, req_, + [this, self = shared_from_this()](boost::system::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); + } + }); + } + else + { + http::async_read(*tcp_socket_, buffer_, req_, + [this, self = shared_from_this()](boost::system::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); + } } @@ -349,8 +361,10 @@ void ControlSessionHttp::on_read(beast::error_code ec, std::size_t bytes_transfe if (ec == http::error::end_of_stream) { boost::system::error_code res; - res = ssl_socket_.shutdown(res); - // auto res = ssl_socket_.lowest_layer().shutdown(tcp_socket::shutdown_send, ec); + if (is_ssl_) + res = ssl_socket_->shutdown(res); + else + res = tcp_socket_->shutdown(tcp_socket::shutdown_send, ec); if (res.failed()) LOG(ERROR, LOG_TAG) << "Failed to shudown socket: " << res << "\n"; return; @@ -372,30 +386,60 @@ void ControlSessionHttp::on_read(beast::error_code ec, std::size_t bytes_transfe LOG(DEBUG, LOG_TAG) << "websocket upgrade, target: " << req_.target() << "\n"; if ((req_.target() == "/jsonrpc") || (req_.target() == "/stream")) { - // Create a WebSocket session by transferring the socket - auto ws = std::make_shared>(std::move(ssl_socket_)); - // Accept the websocket handshake - ws->async_accept(req_, - [this, ws, self = shared_from_this()](beast::error_code ec) mutable - { - if (ec) - { - LOG(ERROR, LOG_TAG) << "Error during WebSocket accept (control): " << ec.message() << "\n"; - } - else - { - if (req_.target() == "/jsonrpc") + if (is_ssl_) + { + // Create a WebSocket session by transferring the socket + auto ws = std::make_shared>(std::move(*ssl_socket_)); + // Accept the websocket handshake + ws->async_accept(req_, + [this, ws, self = shared_from_this()](beast::error_code ec) mutable + { + if (ec) { - auto ws_session = make_shared(message_receiver_, std::move(*ws)); - message_receiver_->onNewSession(std::move(ws_session)); + LOG(ERROR, LOG_TAG) << "Error during WebSocket accept (control): " << ec.message() << "\n"; } - else // if (req_.target() == "/stream") + else { - auto ws_session = make_shared(nullptr, std::move(*ws)); - message_receiver_->onNewSession(std::move(ws_session)); + if (req_.target() == "/jsonrpc") + { + auto ws_session = make_shared(message_receiver_, std::move(*ws)); + message_receiver_->onNewSession(std::move(ws_session)); + } + else // if (req_.target() == "/stream") + { + auto ws_session = make_shared(nullptr, std::move(*ws)); + message_receiver_->onNewSession(std::move(ws_session)); + } } - } - }); + }); + } + else + { + // Create a WebSocket session by transferring the socket + auto ws = std::make_shared>(std::move(*tcp_socket_)); + // Accept the websocket handshake + ws->async_accept(req_, + [this, ws, self = shared_from_this()](beast::error_code ec) mutable + { + if (ec) + { + LOG(ERROR, LOG_TAG) << "Error during WebSocket accept (control): " << ec.message() << "\n"; + } + else + { + if (req_.target() == "/jsonrpc") + { + auto ws_session = make_shared(message_receiver_, std::move(*ws)); + message_receiver_->onNewSession(std::move(ws_session)); + } + else // if (req_.target() == "/stream") + { + auto ws_session = make_shared(nullptr, std::move(*ws)); + message_receiver_->onNewSession(std::move(ws_session)); + } + } + }); + } } return; } @@ -411,8 +455,14 @@ void ControlSessionHttp::on_read(beast::error_code ec, std::size_t bytes_transfe auto sp = std::make_shared(std::forward(response)); // Write the response - http::async_write(this->ssl_socket_, *sp, - [this, self = this->shared_from_this(), sp](beast::error_code ec, std::size_t bytes) { this->on_write(ec, bytes, sp->need_eof()); }); + if (is_ssl_) + http::async_write(this->ssl_socket_.value(), *sp, + [this, self = this->shared_from_this(), sp](beast::error_code ec, std::size_t bytes) + { this->on_write(ec, bytes, sp->need_eof()); }); + else + http::async_write(this->tcp_socket_.value(), *sp, + [this, self = this->shared_from_this(), sp](beast::error_code ec, std::size_t bytes) + { this->on_write(ec, bytes, sp->need_eof()); }); }); } @@ -433,8 +483,10 @@ void ControlSessionHttp::on_write(beast::error_code ec, std::size_t bytes, bool // This means we should close the connection, usually because // the response indicated the "Connection: close" semantic. boost::system::error_code res; - res = ssl_socket_.shutdown(res); - // auto res = ssl_socket_.lowest_layer().shutdown(tcp::socket::shutdown_send, ec); + if (is_ssl_) + res = ssl_socket_->shutdown(res); + else + res = tcp_socket_->shutdown(tcp_socket::shutdown_send, ec); if (res.failed()) LOG(ERROR, LOG_TAG) << "Failed to shudown socket: " << res << "\n"; return; @@ -445,7 +497,10 @@ void ControlSessionHttp::on_write(beast::error_code ec, std::size_t bytes, bool req_ = {}; // Read another request - http::async_read(ssl_socket_, buffer_, req_, [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); + if (is_ssl_) + http::async_read(*ssl_socket_, buffer_, req_, [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); + else + http::async_read(*tcp_socket_, buffer_, req_, [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes) { on_read(ec, bytes); }); } diff --git a/server/control_session_http.hpp b/server/control_session_http.hpp index ec81fbfe..811d0e0c 100644 --- a/server/control_session_http.hpp +++ b/server/control_session_http.hpp @@ -38,7 +38,7 @@ // standard headers #include -// #include +#include namespace beast = boost::beast; // from namespace http = beast::http; // from @@ -56,8 +56,8 @@ class ControlSessionHttp : public ControlSession { public: /// ctor. Received message from the client are passed to ControlMessageReceiver - ControlSessionHttp(ControlMessageReceiver* receiver, tcp_socket&& socket, boost::asio::ssl::context& ssl_context, const ServerSettings::Http& settings); - // ControlSessionHttp(ControlMessageReceiver* receiver, tcp_socket&& socket, const ServerSettings::Http& settings); + ControlSessionHttp(ControlMessageReceiver* receiver, ssl_socket&& socket, const ServerSettings::Http& settings); + ControlSessionHttp(ControlMessageReceiver* receiver, tcp_socket&& socket, const ServerSettings::Http& settings); ~ControlSessionHttp() override; void start() override; void stop() override; @@ -76,11 +76,10 @@ protected: http::request req_; protected: - // tcp_socket socket_; - ssl_socket ssl_socket_; - // std::variant socket_; - boost::asio::ssl::context& ssl_context_; + std::optional tcp_socket_; + std::optional ssl_socket_; beast::flat_buffer buffer_; ServerSettings::Http settings_; std::deque messages_; + bool is_ssl_; }; diff --git a/server/control_session_ws.cpp b/server/control_session_ws.cpp index 227b3b1d..cded57e6 100644 --- a/server/control_session_ws.cpp +++ b/server/control_session_ws.cpp @@ -32,10 +32,16 @@ using namespace std; static constexpr auto LOG_TAG = "ControlSessionWS"; -ControlSessionWebsocket::ControlSessionWebsocket(ControlMessageReceiver* receiver, websocket::stream&& wss) - : ControlSession(receiver), wss_(std::move(wss)), strand_(boost::asio::make_strand(wss_.get_executor())) +ControlSessionWebsocket::ControlSessionWebsocket(ControlMessageReceiver* receiver, ssl_websocket&& ssl_ws) + : ControlSession(receiver), ssl_ws_(std::move(ssl_ws)), strand_(boost::asio::make_strand(ssl_ws_->get_executor())), is_ssl_(true) { - LOG(DEBUG, LOG_TAG) << "ControlSessionWebsocket\n"; + LOG(DEBUG, LOG_TAG) << "ControlSessionWebsocket, mode: ssl\n"; +} + +ControlSessionWebsocket::ControlSessionWebsocket(ControlMessageReceiver* receiver, tcp_websocket&& tcp_ws) + : ControlSession(receiver), tcp_ws_(std::move(tcp_ws)), strand_(boost::asio::make_strand(tcp_ws_->get_executor())), is_ssl_(false) +{ + LOG(DEBUG, LOG_TAG) << "ControlSessionWebsocket, mode: tcp\n"; } @@ -84,9 +90,9 @@ void ControlSessionWebsocket::sendAsync(const std::string& message) void ControlSessionWebsocket::send_next() { const std::string& message = messages_.front(); - wss_.async_write(boost::asio::buffer(message), - [this, self = shared_from_this()](std::error_code ec, std::size_t length) - { + + auto write_handler = [this, self = shared_from_this()](std::error_code ec, std::size_t length) + { messages_.pop_front(); if (ec) { @@ -98,14 +104,28 @@ void ControlSessionWebsocket::send_next() } if (!messages_.empty()) send_next(); - }); + }; + + if (is_ssl_) + { + ssl_ws_->async_write(boost::asio::buffer(message), [write_handler](std::error_code ec, std::size_t length) { write_handler(ec, length); }); + } + else + { + tcp_ws_->async_write(boost::asio::buffer(message), [write_handler](std::error_code ec, std::size_t length) { write_handler(ec, length); }); + } } void ControlSessionWebsocket::do_read_ws() { // Read a message into our buffer - wss_.async_read(buffer_, [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); + if (is_ssl_) + ssl_ws_->async_read(buffer_, + [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); + else + tcp_ws_->async_read(buffer_, + [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); } diff --git a/server/control_session_ws.hpp b/server/control_session_ws.hpp index 209cbb9d..e3e78075 100644 --- a/server/control_session_ws.hpp +++ b/server/control_session_ws.hpp @@ -45,12 +45,15 @@ // standard headers #include +#include namespace beast = boost::beast; // from namespace websocket = beast::websocket; // from using tcp_socket = boost::asio::ip::tcp::socket; using ssl_socket = boost::asio::ssl::stream; +using tcp_websocket = websocket::stream; +using ssl_websocket = websocket::stream; /// Endpoint for a connected control client. @@ -63,7 +66,8 @@ class ControlSessionWebsocket : public ControlSession { public: /// ctor. Received message from the client are passed to ControlMessageReceiver - ControlSessionWebsocket(ControlMessageReceiver* receiver, websocket::stream&& wss); + ControlSessionWebsocket(ControlMessageReceiver* receiver, ssl_websocket&& ssl_ws); + ControlSessionWebsocket(ControlMessageReceiver* receiver, tcp_websocket&& tcp_ws); ~ControlSessionWebsocket() override; void start() override; void stop() override; @@ -77,10 +81,12 @@ protected: void do_read_ws(); void send_next(); - websocket::stream wss_; + std::optional ssl_ws_; + std::optional tcp_ws_; protected: beast::flat_buffer buffer_; boost::asio::strand strand_; std::deque messages_; + bool is_ssl_; }; diff --git a/server/etc/snapserver.conf b/server/etc/snapserver.conf index 91070906..e6a7b218 100644 --- a/server/etc/snapserver.conf +++ b/server/etc/snapserver.conf @@ -75,6 +75,12 @@ private_key = certs/snapserver.key # which port the server should listen to #port = 1780 +#ssl address for the server to listen on +# ssl_bind_to_address = 0.0.0.0 + +# which ssl port the server should listen to +# ssl_port = 1788 + # serve a website from the doc_root location # disabled if commented or empty doc_root = /usr/share/snapserver/snapweb diff --git a/server/server_settings.hpp b/server/server_settings.hpp index ac427628..747dd076 100644 --- a/server/server_settings.hpp +++ b/server/server_settings.hpp @@ -48,7 +48,9 @@ struct ServerSettings { bool enabled{true}; size_t port{1780}; + size_t ssl_port{1788}; std::vector bind_to_address{{"0.0.0.0"}}; + std::vector ssl_bind_to_address{{"0.0.0.0"}}; std::string doc_root{""}; std::string host{""}; inline static ImageCache image_cache; diff --git a/server/snapserver.cpp b/server/snapserver.cpp index dadf1a87..1ba90fc0 100644 --- a/server/snapserver.cpp +++ b/server/snapserver.cpp @@ -89,6 +89,9 @@ int main(int argc, char* argv[]) conf.add>("", "http.port", "which port the server should listen on", settings.http.port, &settings.http.port); auto http_bind_to_address = conf.add>("", "http.bind_to_address", "address for the server to listen on", settings.http.bind_to_address.front(), &settings.http.bind_to_address[0]); + conf.add>("", "http.ssl_port", "which ssl port the server should listen on", settings.http.ssl_port, &settings.http.ssl_port); + auto http_ssl_bind_to_address = conf.add>("", "http.ssl_bind_to_address", "ssl address for the server to listen on", + settings.http.ssl_bind_to_address.front(), &settings.http.ssl_bind_to_address[0]); conf.add>("", "http.doc_root", "serve a website from the doc_root location", settings.http.doc_root, &settings.http.doc_root); conf.add>("", "http.host", "Hostname or IP under which clients can reach this host", settings.http.host, &settings.http.host); @@ -147,6 +150,12 @@ int main(int argc, char* argv[]) for (size_t n = 0; n < http_bind_to_address->count(); ++n) settings.http.bind_to_address.push_back(http_bind_to_address->value(n)); } + if (http_ssl_bind_to_address->is_set()) + { + settings.http.ssl_bind_to_address.clear(); + for (size_t n = 0; n < http_ssl_bind_to_address->count(); ++n) + settings.http.ssl_bind_to_address.push_back(http_ssl_bind_to_address->value(n)); + } if (stream_bind_to_address->is_set()) { settings.stream.bind_to_address.clear(); diff --git a/server/stream_session_ws.cpp b/server/stream_session_ws.cpp index bb9bee28..dc234432 100644 --- a/server/stream_session_ws.cpp +++ b/server/stream_session_ws.cpp @@ -32,10 +32,16 @@ using namespace std; static constexpr auto LOG_TAG = "StreamSessionWS"; -StreamSessionWebsocket::StreamSessionWebsocket(StreamMessageReceiver* receiver, websocket::stream&& wss) - : StreamSession(wss.get_executor(), receiver), wss_(std::move(wss)) +StreamSessionWebsocket::StreamSessionWebsocket(StreamMessageReceiver* receiver, ssl_websocket&& ssl_ws) + : StreamSession(ssl_ws.get_executor(), receiver), ssl_ws_(std::move(ssl_ws)), is_ssl_(true) { - LOG(DEBUG, LOG_TAG) << "StreamSessionWS\n"; + LOG(DEBUG, LOG_TAG) << "StreamSessionWS, mode: ssl\n"; +} + +StreamSessionWebsocket::StreamSessionWebsocket(StreamMessageReceiver* receiver, tcp_websocket&& tcp_ws) + : StreamSession(tcp_ws.get_executor(), receiver), tcp_ws_(std::move(tcp_ws)), is_ssl_(false) +{ + LOG(DEBUG, LOG_TAG) << "StreamSessionWS, mode: tcp\n"; } @@ -50,20 +56,29 @@ void StreamSessionWebsocket::start() { // Read a message LOG(DEBUG, LOG_TAG) << "start\n"; - wss_.binary(true); + if (is_ssl_) + ssl_ws_->binary(true); + else + tcp_ws_->binary(true); do_read_ws(); } void StreamSessionWebsocket::stop() { - if (wss_.is_open()) + boost::beast::error_code ec; + if (is_ssl_) { - boost::beast::error_code ec; - wss_.close(beast::websocket::close_code::normal, ec); - if (ec) - LOG(ERROR, LOG_TAG) << "Error in socket close: " << ec.message() << "\n"; + if (ssl_ws_->is_open()) + ssl_ws_->close(beast::websocket::close_code::normal, ec); } + else + { + if (tcp_ws_->is_open()) + tcp_ws_->close(beast::websocket::close_code::normal, ec); + } + if (ec) + LOG(ERROR, LOG_TAG) << "Error in socket close: " << ec.message() << "\n"; } @@ -71,7 +86,10 @@ std::string StreamSessionWebsocket::getIP() { try { - return wss_.next_layer().lowest_layer().remote_endpoint().address().to_string(); + if (is_ssl_) + return ssl_ws_->next_layer().lowest_layer().remote_endpoint().address().to_string(); + else + return tcp_ws_->next_layer().lowest_layer().remote_endpoint().address().to_string(); } catch (...) { @@ -83,14 +101,22 @@ std::string StreamSessionWebsocket::getIP() void StreamSessionWebsocket::sendAsync(const shared_const_buffer& buffer, const WriteHandler& handler) { LOG(TRACE, LOG_TAG) << "sendAsync: " << buffer.message().type << "\n"; - wss_.async_write(buffer, [self = shared_from_this(), buffer, handler](boost::system::error_code ec, std::size_t length) { handler(ec, length); }); + if (is_ssl_) + ssl_ws_->async_write(buffer, [self = shared_from_this(), buffer, handler](boost::system::error_code ec, std::size_t length) { handler(ec, length); }); + else + tcp_ws_->async_write(buffer, [self = shared_from_this(), buffer, handler](boost::system::error_code ec, std::size_t length) { handler(ec, length); }); } void StreamSessionWebsocket::do_read_ws() { // Read a message into our buffer - wss_.async_read(buffer_, [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); + if (is_ssl_) + ssl_ws_->async_read(buffer_, + [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); + else + tcp_ws_->async_read(buffer_, + [this, self = shared_from_this()](beast::error_code ec, std::size_t bytes_transferred) { on_read_ws(ec, bytes_transferred); }); } diff --git a/server/stream_session_ws.hpp b/server/stream_session_ws.hpp index dc4a0ec4..032fbb3d 100644 --- a/server/stream_session_ws.hpp +++ b/server/stream_session_ws.hpp @@ -42,6 +42,8 @@ namespace beast = boost::beast; // from namespace websocket = beast::websocket; // from using tcp_socket = boost::asio::ip::tcp::socket; using ssl_socket = boost::asio::ssl::stream; +using tcp_websocket = websocket::stream; +using ssl_websocket = websocket::stream; /// Endpoint for a connected control client. @@ -54,7 +56,8 @@ class StreamSessionWebsocket : public StreamSession { public: /// ctor. Received message from the client are passed to StreamMessageReceiver - StreamSessionWebsocket(StreamMessageReceiver* receiver, websocket::stream&& wss); + StreamSessionWebsocket(StreamMessageReceiver* receiver, ssl_websocket&& ssl_ws); + StreamSessionWebsocket(StreamMessageReceiver* receiver, tcp_websocket&& tcp_ws); ~StreamSessionWebsocket() override; void start() override; void stop() override; @@ -66,8 +69,10 @@ protected: void on_read_ws(beast::error_code ec, std::size_t bytes_transferred); void do_read_ws(); - websocket::stream wss_; + std::optional ssl_ws_; + std::optional tcp_ws_; protected: beast::flat_buffer buffer_; + bool is_ssl_; };