From b1532eaae3b8c30b398a67654bac635dddbcffd6 Mon Sep 17 00:00:00 2001 From: loonycyborg Date: Mon, 15 Feb 2021 16:22:48 +0300 Subject: [PATCH] Add TLS support to campaignd --- src/server/campaignd/server.cpp | 106 +++++++++++++++++++----------- src/server/campaignd/server.hpp | 17 +++-- src/server/common/server_base.cpp | 2 + 3 files changed, 81 insertions(+), 44 deletions(-) diff --git a/src/server/campaignd/server.cpp b/src/server/campaignd/server.cpp index f9204d7eed48..a372c41bc341 100644 --- a/src/server/campaignd/server.cpp +++ b/src/server/campaignd/server.cpp @@ -467,37 +467,50 @@ std::ostream& operator<<(std::ostream& o, const server::request& r) return o; } +void server::handle_new_client(tls_socket_ptr socket) +{ + boost::asio::spawn(io_service_, [this, socket](boost::asio::yield_context yield) { + serve_requests(socket, yield); + }); +} + void server::handle_new_client(socket_ptr socket) { boost::asio::spawn(io_service_, [this, socket](boost::asio::yield_context yield) { - while(true) { - boost::system::error_code ec; - auto doc { coro_receive_doc(socket, yield[ec]) }; - if(check_error(ec, socket) || !doc) return; + serve_requests(socket, yield); + }); +} - config data; - read(data, doc->output()); +template +void server::serve_requests(Socket socket, boost::asio::yield_context yield) +{ + while(true) { + boost::system::error_code ec; + auto doc { coro_receive_doc(socket, yield[ec]) }; + if(check_error(ec, socket) || !doc) return; - config::all_children_iterator i = data.ordered_begin(); + config data; + read(data, doc->output()); - if(i != data.ordered_end()) { - // We only handle the first child. - const config::any_child& c = *i; + config::all_children_iterator i = data.ordered_begin(); - request_handlers_table::const_iterator j - = handlers_.find(c.key); + if(i != data.ordered_end()) { + // We only handle the first child. + const config::any_child& c = *i; - if(j != handlers_.end()) { - // Call the handler. - request req{c.key, c.cfg, socket, yield}; - auto st = service_timer(req); - j->second(this, req); - } else { - send_error("Unrecognized [" + c.key + "] request.",socket); - } + request_handlers_table::const_iterator j + = handlers_.find(c.key); + + if(j != handlers_.end()) { + // Call the handler. + request req{c.key, c.cfg, socket, yield}; + auto st = service_timer(req); + j->second(this, req); + } else { + send_error("Unrecognized [" + c.key + "] request.",socket); } } - }); + } } #ifndef _WIN32 @@ -751,24 +764,28 @@ bool server::ignore_address_stats(const std::string& addr) const return false; } -void server::send_message(const std::string& msg, socket_ptr sock) +void server::send_message(const std::string& msg, const any_socket_ptr& sock) { const auto& escaped_msg = simple_wml_escape(msg); simple_wml::document doc; doc.root().add_child("message").set_attr_dup("message", escaped_msg.c_str()); - async_send_doc_queued(sock, doc); + utils::visit([this, &doc](auto&& sock) { async_send_doc_queued(sock, doc); }, sock); } -void server::send_error(const std::string& msg, socket_ptr sock) +inline std::string client_address(const any_socket_ptr& sock) { + return utils::visit([](auto&& sock) { return client_address(sock); }, sock); +} + +void server::send_error(const std::string& msg, const any_socket_ptr& sock) { ERR_CS << "[" << client_address(sock) << "] " << msg << '\n'; const auto& escaped_msg = simple_wml_escape(msg); simple_wml::document doc; doc.root().add_child("error").set_attr_dup("message", escaped_msg.c_str()); - async_send_doc_queued(sock, doc); + utils::visit([this, &doc](auto&& sock) { async_send_doc_queued(sock, doc); }, sock); } -void server::send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, socket_ptr sock) +void server::send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, const any_socket_ptr& sock) { const std::string& status_hex = formatter() << "0x" << std::setfill('0') << std::setw(2*sizeof(unsigned int)) << std::hex @@ -786,7 +803,7 @@ void server::send_error(const std::string& msg, const std::string& extra_data, u err_cfg.set_attr_dup("extra_data", escaped_extra_data.c_str()); err_cfg.set_attr_dup("status_code", escaped_status_str.c_str()); - async_send_doc_queued(sock, doc); + utils::visit([this, &doc](auto&& sock) { async_send_doc_queued(sock, doc); }, sock); } config& server::get_addon(const std::string& id) @@ -859,7 +876,7 @@ void server::handle_server_id(const server::request& req) simple_wml::document doc(wml.c_str(), simple_wml::INIT_STATIC); doc.compress(); - async_send_doc_queued(req.sock, doc); + utils::visit([this, &doc](auto&& sock) { async_send_doc_queued(sock, doc); }, req.sock); } void server::handle_request_campaign_list(const server::request& req) @@ -960,7 +977,7 @@ void server::handle_request_campaign_list(const server::request& req) simple_wml::document doc(wml.c_str(), simple_wml::INIT_STATIC); doc.compress(); - async_send_doc_queued(req.sock, doc); + utils::visit([this, &doc](auto&& sock) { async_send_doc_queued(sock, doc); }, req.sock); } void server::handle_request_campaign(const server::request& req) @@ -1063,9 +1080,11 @@ void server::handle_request_campaign(const server::request& req) LOG_CS << req << "Sending add-on '" << name << "' version: " << from << " -> " << to << " (delta))\n"; - boost::system::error_code ec; - coro_send_doc(req.sock, doc, req.yield[ec]); - if(check_error(ec, req.sock)) return; + utils::visit([this, &req, &doc](auto && sock) { + boost::system::error_code ec; + coro_send_doc(sock, doc, req.yield[ec]); + if(check_error(ec, sock)) return; + }, req.sock); full_pack_path.clear(); } @@ -1081,9 +1100,16 @@ void server::handle_request_campaign(const server::request& req) } LOG_CS << req << "Sending add-on '" << name << "' version: " << to << " size: " << full_pack_size / 1024 << " KiB\n"; - boost::system::error_code ec; - coro_send_file(req.sock, full_pack_path, req.yield[ec]); - if(check_error(ec, req.sock)) return; + if(auto sock = utils::get_if(&req.sock)) { + boost::system::error_code ec; + coro_send_file(*sock, full_pack_path, req.yield[ec]); + if(check_error(ec, *sock)) return; + } else { + // FIXME: need to decide what to do about sending addons over TLS. + // sendfile is low level api so either drop TLS for this part + // or don't use sendfile at all. + ERR_CS << "Not sending addon over TLS yet\n"; + } } // Clients doing upgrades or some other specific thing shouldn't bump @@ -1135,9 +1161,13 @@ void server::handle_request_campaign_hash(const server::request& req) } LOG_CS << req << "Sending add-on hash index for '" << req.cfg["name"] << "' size: " << file_size / 1024 << " KiB\n"; - boost::system::error_code ec; - coro_send_file(req.sock, path, req.yield[ec]); - if(check_error(ec, req.sock)) return; + if(auto sock = utils::get_if(&req.sock)) { + boost::system::error_code ec; + coro_send_file(*sock, path, req.yield[ec]); + if(check_error(ec, *sock)) return; + } else { + ERR_CS << "No sendfile over TLS\n"; + } } } diff --git a/src/server/campaignd/server.hpp b/src/server/campaignd/server.hpp index dfb9b2567054..a30776d8958b 100644 --- a/src/server/campaignd/server.hpp +++ b/src/server/campaignd/server.hpp @@ -56,7 +56,7 @@ class server : public server_base const std::string& cmd; const config& cfg; - const socket_ptr sock; + const any_socket_ptr sock; const std::string addr; /** @@ -79,14 +79,15 @@ class server : public server_base * TO A CONST OBJECT, since some code may modify it directly for * performance reasons. */ + template request(const std::string& reqcmd, config& reqcfg, - socket_ptr reqsock, + Socket reqsock, boost::asio::yield_context yield) : cmd(reqcmd) , cfg(reqcfg) , sock(reqsock) - , addr(client_address(sock)) + , addr(client_address(reqsock)) , yield(yield) {} }; @@ -134,6 +135,10 @@ class server : public server_base boost::asio::basic_waitable_timer flush_timer_; void handle_new_client(socket_ptr socket); + void handle_new_client(tls_socket_ptr socket); + + template + void serve_requests(Socket socket, boost::asio::yield_context yield); #ifndef _WIN32 void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred); @@ -236,7 +241,7 @@ class server : public server_base * The WML sent consists of a document containing a single @p [message] * child with a @a message attribute holding the value of @a msg. */ - void send_message(const std::string& msg, socket_ptr sock); + void send_message(const std::string& msg, const any_socket_ptr& sock); /** * Send a client an error message. @@ -246,7 +251,7 @@ class server : public server_base * sending the error to the client, a line with the client IP and message * is recorded to the server log. */ - void send_error(const std::string& msg, socket_ptr sock); + void send_error(const std::string& msg, const any_socket_ptr& sock); /** * Send a client an error message. @@ -258,7 +263,7 @@ class server : public server_base * addition to sending the error to the client, a line with the client IP * and message is recorded to the server log. */ - void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, socket_ptr sock); + void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, const any_socket_ptr& sock); }; } // end namespace campaignd diff --git a/src/server/common/server_base.cpp b/src/server/common/server_base.cpp index 380ea05919ce..98e14c203719 100644 --- a/src/server/common/server_base.cpp +++ b/src/server/common/server_base.cpp @@ -437,6 +437,8 @@ template void server_base::coro_send_file(SocketPtr socket, con #endif +template void server_base::coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield); + template std::unique_ptr server_base::coro_receive_doc(SocketPtr socket, boost::asio::yield_context yield) { union DataSize