blob: a7c245989c35a6d349c087cb3d36ef0589a45340 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanous7045c8d2017-04-03 10:04:37 -07003#pragma once
4
Ed Tanousd7857202025-01-28 15:32:26 -08005#include "bmcweb_config.h"
6
Ed Tanous04e438c2020-10-03 08:06:26 -07007#include "http_connection.hpp"
8#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08009#include "ssl_key_handler.hpp"
Manojkiran Eda44250442020-06-16 12:51:38 +053010
Ed Tanousd7857202025-01-28 15:32:26 -080011#include <boost/asio/io_context.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -070012#include <boost/asio/ip/address.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -080013#include <boost/asio/ip/tcp.hpp>
14#include <boost/asio/signal_set.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080015#include <boost/asio/ssl/context.hpp>
Ed Tanous003301a2024-04-16 09:59:19 -070016#include <boost/asio/ssl/stream.hpp>
Ed Tanous271584a2019-07-09 16:24:22 -070017#include <boost/asio/steady_timer.hpp>
Ed Tanous3281bcf2024-06-25 16:02:05 -070018#include <boost/beast/core/stream_traits.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050019
Ed Tanous3dac7492017-08-02 13:46:20 -070020#include <chrono>
Ed Tanousd7857202025-01-28 15:32:26 -080021#include <csignal>
22#include <cstddef>
23#include <ctime>
24#include <functional>
Ed Tanous911ac312017-08-15 09:37:42 -070025#include <memory>
Ed Tanous099225c2024-03-27 22:03:05 -070026#include <string>
Ed Tanousd7857202025-01-28 15:32:26 -080027#include <type_traits>
Ed Tanous911ac312017-08-15 09:37:42 -070028#include <utility>
Ed Tanous1abe55e2018-09-05 08:30:59 -070029
Ed Tanous1abe55e2018-09-05 08:30:59 -070030namespace crow
31{
Ed Tanous7045c8d2017-04-03 10:04:37 -070032
Ed Tanous52cc1122020-07-18 13:51:21 -070033template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket>
Ed Tanous1abe55e2018-09-05 08:30:59 -070034class Server
35{
Ed Tanous3281bcf2024-06-25 16:02:05 -070036 using self_t = Server<Handler, Adaptor>;
37
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 public:
Ed Tanous8db83742024-04-13 09:11:15 -070039 Server(Handler* handlerIn, boost::asio::ip::tcp::acceptor&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070040 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous9838eb22025-01-29 16:24:42 -080041 boost::asio::io_context& io) :
42 ioService(io), acceptor(std::move(acceptorIn)),
Ed Tanousd7857202025-01-28 15:32:26 -080043 // NOLINTNEXTLINE(misc-include-cleaner)
Ed Tanous9838eb22025-01-29 16:24:42 -080044 signals(ioService, SIGINT, SIGTERM, SIGHUP), handler(handlerIn),
Ed Tanous8a592812022-06-04 09:06:59 -070045 adaptorCtx(std::move(adaptorCtxIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050046 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 void updateDateStr()
49 {
Ed Tanous99131cd2019-10-24 11:12:47 -070050 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070052
Ed Tanous1abe55e2018-09-05 08:30:59 -070053 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 dateStr.resize(100);
Ed Tanous0f837072023-06-30 09:57:26 -070056 size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1,
Patrick Williams89492a12023-05-10 07:51:34 -050057 "%a, %d %b %Y %H:%M:%S GMT", &myTm);
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000059 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070060
Ed Tanous1abe55e2018-09-05 08:30:59 -070061 void run()
62 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060063 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070064 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070065
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 getCachedDateStr = [this]() -> std::string {
67 static std::chrono::time_point<std::chrono::steady_clock>
68 lastDateUpdate = std::chrono::steady_clock::now();
69 if (std::chrono::steady_clock::now() - lastDateUpdate >=
70 std::chrono::seconds(10))
71 {
72 lastDateUpdate = std::chrono::steady_clock::now();
73 updateDateStr();
74 }
Ed Tanous21b4aba2023-06-05 11:42:43 -070075 return dateStr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070077
Ed Tanous62598e32023-07-17 17:06:25 -070078 BMCWEB_LOG_INFO("bmcweb server is running, local endpoint {}",
Ed Tanous8db83742024-04-13 09:11:15 -070079 acceptor.local_endpoint().address().to_string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060080 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070081 doAccept();
82 }
83
Marri Devender Rao5968cae2019-01-21 10:27:12 -060084 void loadCertificate()
85 {
Ed Tanous25b54db2024-04-17 15:40:31 -070086 if constexpr (BMCWEB_INSECURE_DISABLE_SSL)
Ed Tanous8db83742024-04-13 09:11:15 -070087 {
88 return;
89 }
Abhilash Rajud5fb5842024-06-03 11:40:17 -050090
91 auto sslContext = ensuressl::getSslServerContext();
92
Marri Devender Rao5968cae2019-01-21 10:27:12 -060093 adaptorCtx = sslContext;
94 handler->ssl(std::move(sslContext));
Marri Devender Rao5968cae2019-01-21 10:27:12 -060095 }
96
97 void startAsyncWaitForSignal()
98 {
Ed Tanous002d39b2022-05-31 08:59:27 -070099 signals.async_wait(
100 [this](const boost::system::error_code& ec, int signalNo) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400101 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600102 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400103 BMCWEB_LOG_INFO("Error in signal handler{}", ec.message());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600104 }
105 else
106 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400107 if (signalNo == SIGHUP)
108 {
109 BMCWEB_LOG_INFO("Receivied reload signal");
110 loadCertificate();
111 startAsyncWaitForSignal();
112 }
113 else
114 {
115 stop();
116 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600117 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400118 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600119 }
120
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121 void stop()
122 {
Ed Tanous9838eb22025-01-29 16:24:42 -0800123 ioService.stop();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700124 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700125 using Socket = boost::beast::lowest_layer_type<Adaptor>;
126 using SocketPtr = std::unique_ptr<Socket>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127
Ed Tanous3281bcf2024-06-25 16:02:05 -0700128 void afterAccept(SocketPtr socket, const boost::system::error_code& ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700129 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700130 if (ec)
Ed Tanous8db83742024-04-13 09:11:15 -0700131 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700132 BMCWEB_LOG_ERROR("Failed to accept socket {}", ec);
Ed Tanous8db83742024-04-13 09:11:15 -0700133 return;
134 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700135
Ed Tanous9838eb22025-01-29 16:24:42 -0800136 boost::asio::steady_timer timer(ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800137 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanous3281bcf2024-06-25 16:02:05 -0700138
Ed Tanousceac6f72018-12-02 11:58:47 -0800139 if constexpr (std::is_same<Adaptor,
Ed Tanous003301a2024-04-16 09:59:19 -0700140 boost::asio::ssl::stream<
Ed Tanousceac6f72018-12-02 11:58:47 -0800141 boost::asio::ip::tcp::socket>>::value)
142 {
Ed Tanous8db83742024-04-13 09:11:15 -0700143 if (adaptorCtx == nullptr)
144 {
145 BMCWEB_LOG_CRITICAL(
Abhilash Rajud5fb5842024-06-03 11:40:17 -0500146 "Asked to launch TLS socket but no context available");
Ed Tanous8db83742024-04-13 09:11:15 -0700147 return;
148 }
Ed Tanous88e16122021-12-06 14:14:43 -0800149 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800150 handler, std::move(timer), getCachedDateStr,
Ed Tanous3281bcf2024-06-25 16:02:05 -0700151 Adaptor(std::move(*socket), *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800152 }
153 else
154 {
Ed Tanous88e16122021-12-06 14:14:43 -0800155 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800156 handler, std::move(timer), getCachedDateStr,
Ed Tanous3281bcf2024-06-25 16:02:05 -0700157 Adaptor(std::move(*socket)));
Ed Tanousceac6f72018-12-02 11:58:47 -0800158 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700159
Ed Tanous9838eb22025-01-29 16:24:42 -0800160 boost::asio::post(ioService, [connection] { connection->start(); });
Ed Tanous3281bcf2024-06-25 16:02:05 -0700161
162 doAccept();
163 }
164
165 void doAccept()
166 {
Ed Tanous9838eb22025-01-29 16:24:42 -0800167 SocketPtr socket = std::make_unique<Socket>(ioService);
Ed Tanous3281bcf2024-06-25 16:02:05 -0700168 // Keep a raw pointer so when the socket is moved, the pointer is still
169 // valid
170 Socket* socketPtr = socket.get();
171
Ed Tanous8db83742024-04-13 09:11:15 -0700172 acceptor.async_accept(
Ed Tanous3281bcf2024-06-25 16:02:05 -0700173 *socketPtr,
174 std::bind_front(&self_t::afterAccept, this, std::move(socket)));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700175 }
176
177 private:
Ed Tanous9838eb22025-01-29 16:24:42 -0800178 boost::asio::io_context& ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700179 std::function<std::string()> getCachedDateStr;
Ed Tanous8db83742024-04-13 09:11:15 -0700180 boost::asio::ip::tcp::acceptor acceptor;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 boost::asio::signal_set signals;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700182
183 std::string dateStr;
184
185 Handler* handler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600187 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800188};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189} // namespace crow