140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 304e438cbSEd Tanous #pragma once 404e438cbSEd Tanous 5d7857201SEd Tanous #include "bmcweb_config.h" 6d7857201SEd Tanous 7*796ba93bSEd Tanous #include "http_connect_types.hpp" 804e438cbSEd Tanous #include "http_connection.hpp" 9*796ba93bSEd Tanous #include "io_context_singleton.hpp" 1004e438cbSEd Tanous #include "logging.hpp" 113ccb3adbSEd Tanous #include "ssl_key_handler.hpp" 1204e438cbSEd Tanous 1304e438cbSEd Tanous #include <boost/asio/ip/address.hpp> 1404e438cbSEd Tanous #include <boost/asio/ip/tcp.hpp> 1504e438cbSEd Tanous #include <boost/asio/signal_set.hpp> 1604e438cbSEd Tanous #include <boost/asio/ssl/context.hpp> 17003301a2SEd Tanous #include <boost/asio/ssl/stream.hpp> 1804e438cbSEd Tanous #include <boost/asio/steady_timer.hpp> 1904e438cbSEd Tanous 2004e438cbSEd Tanous #include <chrono> 21d7857201SEd Tanous #include <csignal> 22d7857201SEd Tanous #include <cstddef> 23d7857201SEd Tanous #include <ctime> 24d7857201SEd Tanous #include <functional> 2504e438cbSEd Tanous #include <memory> 26099225ccSEd Tanous #include <string> 2704e438cbSEd Tanous #include <utility> 28*796ba93bSEd Tanous #include <vector> 2904e438cbSEd Tanous 3004e438cbSEd Tanous namespace crow 3104e438cbSEd Tanous { 3204e438cbSEd Tanous 33*796ba93bSEd Tanous struct Acceptor 34*796ba93bSEd Tanous { 35*796ba93bSEd Tanous boost::asio::ip::tcp::acceptor acceptor; 36*796ba93bSEd Tanous HttpType httpType; 37*796ba93bSEd Tanous }; 38*796ba93bSEd Tanous 3904e438cbSEd Tanous template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket> 4004e438cbSEd Tanous class Server 4104e438cbSEd Tanous { 423281bcf1SEd Tanous using self_t = Server<Handler, Adaptor>; 433281bcf1SEd Tanous 4404e438cbSEd Tanous public: Server(Handler * handlerIn,std::vector<Acceptor> && acceptorsIn)45*796ba93bSEd Tanous Server(Handler* handlerIn, std::vector<Acceptor>&& acceptorsIn) : 46*796ba93bSEd Tanous acceptors(std::move(acceptorsIn)), 47*796ba93bSEd Tanous 48d7857201SEd Tanous // NOLINTNEXTLINE(misc-include-cleaner) 49*796ba93bSEd Tanous signals(getIoContext(), SIGINT, SIGTERM, SIGHUP), handler(handlerIn) 5004e438cbSEd Tanous {} 5104e438cbSEd Tanous updateDateStr()5204e438cbSEd Tanous void updateDateStr() 5304e438cbSEd Tanous { 5404e438cbSEd Tanous time_t lastTimeT = time(nullptr); 5504e438cbSEd Tanous tm myTm{}; 5604e438cbSEd Tanous 5704e438cbSEd Tanous gmtime_r(&lastTimeT, &myTm); 5804e438cbSEd Tanous 5904e438cbSEd Tanous dateStr.resize(100); 600f83707dSEd Tanous size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1, 6189492a15SPatrick Williams "%a, %d %b %Y %H:%M:%S GMT", &myTm); 6204e438cbSEd Tanous dateStr.resize(dateStrSz); 6304e438cbSEd Tanous } 6404e438cbSEd Tanous run()6504e438cbSEd Tanous void run() 6604e438cbSEd Tanous { 6704e438cbSEd Tanous loadCertificate(); 6804e438cbSEd Tanous updateDateStr(); 6904e438cbSEd Tanous 7004e438cbSEd Tanous getCachedDateStr = [this]() -> std::string { 7104e438cbSEd Tanous static std::chrono::time_point<std::chrono::steady_clock> 7204e438cbSEd Tanous lastDateUpdate = std::chrono::steady_clock::now(); 7304e438cbSEd Tanous if (std::chrono::steady_clock::now() - lastDateUpdate >= 7404e438cbSEd Tanous std::chrono::seconds(10)) 7504e438cbSEd Tanous { 7604e438cbSEd Tanous lastDateUpdate = std::chrono::steady_clock::now(); 7704e438cbSEd Tanous updateDateStr(); 7804e438cbSEd Tanous } 7921b4aba4SEd Tanous return dateStr; 8004e438cbSEd Tanous }; 8104e438cbSEd Tanous 82*796ba93bSEd Tanous for (const Acceptor& accept : acceptors) 83*796ba93bSEd Tanous { 84*796ba93bSEd Tanous BMCWEB_LOG_INFO( 85*796ba93bSEd Tanous "bmcweb server is running, local endpoint {}", 86*796ba93bSEd Tanous accept.acceptor.local_endpoint().address().to_string()); 87*796ba93bSEd Tanous } 8804e438cbSEd Tanous startAsyncWaitForSignal(); 8904e438cbSEd Tanous doAccept(); 9004e438cbSEd Tanous } 9104e438cbSEd Tanous loadCertificate()9204e438cbSEd Tanous void loadCertificate() 9304e438cbSEd Tanous { 9425b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_SSL) 958db83747SEd Tanous { 968db83747SEd Tanous return; 978db83747SEd Tanous } 98d5fb584aSAbhilash Raju 99*796ba93bSEd Tanous adaptorCtx = ensuressl::getSslServerContext(); 10004e438cbSEd Tanous } 10104e438cbSEd Tanous startAsyncWaitForSignal()10204e438cbSEd Tanous void startAsyncWaitForSignal() 10304e438cbSEd Tanous { 104002d39b4SEd Tanous signals.async_wait( 105002d39b4SEd Tanous [this](const boost::system::error_code& ec, int signalNo) { 10604e438cbSEd Tanous if (ec) 10704e438cbSEd Tanous { 10862598e31SEd Tanous BMCWEB_LOG_INFO("Error in signal handler{}", ec.message()); 10904e438cbSEd Tanous } 11004e438cbSEd Tanous else 11104e438cbSEd Tanous { 11204e438cbSEd Tanous if (signalNo == SIGHUP) 11304e438cbSEd Tanous { 11462598e31SEd Tanous BMCWEB_LOG_INFO("Receivied reload signal"); 11504e438cbSEd Tanous loadCertificate(); 11621b4aba4SEd Tanous startAsyncWaitForSignal(); 11704e438cbSEd Tanous } 11804e438cbSEd Tanous else 11904e438cbSEd Tanous { 120*796ba93bSEd Tanous getIoContext().stop(); 12104e438cbSEd Tanous } 12204e438cbSEd Tanous } 12304e438cbSEd Tanous }); 12404e438cbSEd Tanous } 12504e438cbSEd Tanous 126*796ba93bSEd Tanous using SocketPtr = std::unique_ptr<Adaptor>; 12704e438cbSEd Tanous afterAccept(SocketPtr socket,HttpType httpType,const boost::system::error_code & ec)128*796ba93bSEd Tanous void afterAccept(SocketPtr socket, HttpType httpType, 129*796ba93bSEd Tanous const boost::system::error_code& ec) 13004e438cbSEd Tanous { 1313281bcf1SEd Tanous if (ec) 1328db83747SEd Tanous { 1333281bcf1SEd Tanous BMCWEB_LOG_ERROR("Failed to accept socket {}", ec); 1348db83747SEd Tanous return; 1358db83747SEd Tanous } 1363281bcf1SEd Tanous 137*796ba93bSEd Tanous boost::asio::steady_timer timer(getIoContext()); 1388db83747SEd Tanous if (adaptorCtx == nullptr) 1398db83747SEd Tanous { 140*796ba93bSEd Tanous adaptorCtx = std::make_shared<boost::asio::ssl::context>( 141*796ba93bSEd Tanous boost::asio::ssl::context::tls_server); 14288e1612bSEd Tanous } 1433281bcf1SEd Tanous 144*796ba93bSEd Tanous boost::asio::ssl::stream<Adaptor> stream(std::move(*socket), 145*796ba93bSEd Tanous *adaptorCtx); 146*796ba93bSEd Tanous using ConnectionType = Connection<Adaptor, Handler>; 147*796ba93bSEd Tanous auto connection = std::make_shared<ConnectionType>( 148*796ba93bSEd Tanous handler, httpType, std::move(timer), getCachedDateStr, 149*796ba93bSEd Tanous std::move(stream)); 150*796ba93bSEd Tanous 151*796ba93bSEd Tanous boost::asio::post(getIoContext(), 152*796ba93bSEd Tanous [connection] { connection->start(); }); 1533281bcf1SEd Tanous 15404e438cbSEd Tanous doAccept(); 1553281bcf1SEd Tanous } 1563281bcf1SEd Tanous doAccept()1573281bcf1SEd Tanous void doAccept() 1583281bcf1SEd Tanous { 159*796ba93bSEd Tanous SocketPtr socket = std::make_unique<Adaptor>(getIoContext()); 1603281bcf1SEd Tanous // Keep a raw pointer so when the socket is moved, the pointer is still 1613281bcf1SEd Tanous // valid 162*796ba93bSEd Tanous Adaptor* socketPtr = socket.get(); 163*796ba93bSEd Tanous for (Acceptor& accept : acceptors) 164*796ba93bSEd Tanous { 165*796ba93bSEd Tanous accept.acceptor.async_accept( 1663281bcf1SEd Tanous *socketPtr, 167*796ba93bSEd Tanous std::bind_front(&self_t::afterAccept, this, std::move(socket), 168*796ba93bSEd Tanous accept.httpType)); 169*796ba93bSEd Tanous } 17004e438cbSEd Tanous } 17104e438cbSEd Tanous 17204e438cbSEd Tanous private: 17304e438cbSEd Tanous std::function<std::string()> getCachedDateStr; 174*796ba93bSEd Tanous std::vector<Acceptor> acceptors; 17504e438cbSEd Tanous boost::asio::signal_set signals; 17604e438cbSEd Tanous 17704e438cbSEd Tanous std::string dateStr; 17804e438cbSEd Tanous 17904e438cbSEd Tanous Handler* handler; 18004e438cbSEd Tanous 18104e438cbSEd Tanous std::shared_ptr<boost::asio::ssl::context> adaptorCtx; 1825dfb5b2dSEd Tanous }; 18304e438cbSEd Tanous } // namespace crow 184