// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright OpenBMC Authors #pragma once #include "bmcweb_config.h" #include "http_connect_types.hpp" #include "http_connection.hpp" #include "io_context_singleton.hpp" #include "logging.hpp" #include "ssl_key_handler.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace crow { struct Acceptor { boost::asio::ip::tcp::acceptor acceptor; HttpType httpType; }; template class Server { using self_t = Server; public: Server(Handler* handlerIn, std::vector&& acceptorsIn) : acceptors(std::move(acceptorsIn)), // NOLINTNEXTLINE(misc-include-cleaner) signals(getIoContext(), SIGINT, SIGTERM, SIGHUP), handler(handlerIn) {} void updateDateStr() { time_t lastTimeT = time(nullptr); tm myTm{}; gmtime_r(&lastTimeT, &myTm); dateStr.resize(100); size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1, "%a, %d %b %Y %H:%M:%S GMT", &myTm); dateStr.resize(dateStrSz); } void run() { loadCertificate(); updateDateStr(); getCachedDateStr = [this]() -> std::string { static std::chrono::time_point lastDateUpdate = std::chrono::steady_clock::now(); if (std::chrono::steady_clock::now() - lastDateUpdate >= std::chrono::seconds(10)) { lastDateUpdate = std::chrono::steady_clock::now(); updateDateStr(); } return dateStr; }; for (const Acceptor& accept : acceptors) { BMCWEB_LOG_INFO( "bmcweb server is running, local endpoint {}", accept.acceptor.local_endpoint().address().to_string()); } startAsyncWaitForSignal(); doAccept(); } void loadCertificate() { if constexpr (BMCWEB_INSECURE_DISABLE_SSL) { return; } adaptorCtx = ensuressl::getSslServerContext(); } void startAsyncWaitForSignal() { signals.async_wait( [this](const boost::system::error_code& ec, int signalNo) { if (ec) { BMCWEB_LOG_INFO("Error in signal handler{}", ec.message()); } else { if (signalNo == SIGHUP) { BMCWEB_LOG_INFO("Receivied reload signal"); loadCertificate(); startAsyncWaitForSignal(); } else { getIoContext().stop(); } } }); } using SocketPtr = std::unique_ptr; void afterAccept(SocketPtr socket, HttpType httpType, const boost::system::error_code& ec) { if (ec) { BMCWEB_LOG_ERROR("Failed to accept socket {}", ec); return; } boost::asio::steady_timer timer(getIoContext()); if (adaptorCtx == nullptr) { adaptorCtx = std::make_shared( boost::asio::ssl::context::tls_server); } boost::asio::ssl::stream stream(std::move(*socket), *adaptorCtx); using ConnectionType = Connection; auto connection = std::make_shared( handler, httpType, std::move(timer), getCachedDateStr, std::move(stream)); boost::asio::post(getIoContext(), [connection] { connection->start(); }); doAccept(); } void doAccept() { SocketPtr socket = std::make_unique(getIoContext()); // Keep a raw pointer so when the socket is moved, the pointer is still // valid Adaptor* socketPtr = socket.get(); for (Acceptor& accept : acceptors) { accept.acceptor.async_accept( *socketPtr, std::bind_front(&self_t::afterAccept, this, std::move(socket), accept.httpType)); } } private: std::function getCachedDateStr; std::vector acceptors; boost::asio::signal_set signals; std::string dateStr; Handler* handler; std::shared_ptr adaptorCtx; }; } // namespace crow