blob: 9fa927a61de2d4295ed1c45e5beeb827bc355e43 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous04e438c2020-10-03 08:06:26 -07003#include "http_connection.hpp"
4#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08005#include "ssl_key_handler.hpp"
Manojkiran Eda44250442020-06-16 12:51:38 +05306
Ed Tanouse278c182019-03-13 16:23:37 -07007#include <boost/asio/ip/address.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -08008#include <boost/asio/ip/tcp.hpp>
9#include <boost/asio/signal_set.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080010#include <boost/asio/ssl/context.hpp>
Ed Tanous003301a2024-04-16 09:59:19 -070011#include <boost/asio/ssl/stream.hpp>
Ed Tanous271584a2019-07-09 16:24:22 -070012#include <boost/asio/steady_timer.hpp>
Ed Tanous3281bcf2024-06-25 16:02:05 -070013#include <boost/beast/core/stream_traits.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050014
Manojkiran Eda44250442020-06-16 12:51:38 +053015#include <atomic>
Ed Tanous3dac7492017-08-02 13:46:20 -070016#include <chrono>
Ed Tanous911ac312017-08-15 09:37:42 -070017#include <cstdint>
Marri Devender Rao5968cae2019-01-21 10:27:12 -060018#include <filesystem>
Ed Tanous911ac312017-08-15 09:37:42 -070019#include <future>
20#include <memory>
Ed Tanous099225c2024-03-27 22:03:05 -070021#include <string>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <utility>
23#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace crow
26{
Ed Tanous7045c8d2017-04-03 10:04:37 -070027
Ed Tanous52cc1122020-07-18 13:51:21 -070028template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket>
Ed Tanous1abe55e2018-09-05 08:30:59 -070029class Server
30{
Ed Tanous3281bcf2024-06-25 16:02:05 -070031 using self_t = Server<Handler, Adaptor>;
32
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 public:
Ed Tanous8db83742024-04-13 09:11:15 -070034 Server(Handler* handlerIn, boost::asio::ip::tcp::acceptor&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070035 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous8db83742024-04-13 09:11:15 -070036 std::shared_ptr<boost::asio::io_context> io) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -040037 ioService(std::move(io)), acceptor(std::move(acceptorIn)),
Ed Tanous5dfb5b22021-12-03 11:24:53 -080038 signals(*ioService, SIGINT, SIGTERM, SIGHUP), handler(handlerIn),
Ed Tanous8a592812022-06-04 09:06:59 -070039 adaptorCtx(std::move(adaptorCtxIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050040 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070041
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 void updateDateStr()
43 {
Ed Tanous99131cd2019-10-24 11:12:47 -070044 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070045 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 dateStr.resize(100);
Ed Tanous0f837072023-06-30 09:57:26 -070050 size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1,
Patrick Williams89492a12023-05-10 07:51:34 -050051 "%a, %d %b %Y %H:%M:%S GMT", &myTm);
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000053 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 void run()
56 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060057 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070059
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 getCachedDateStr = [this]() -> std::string {
61 static std::chrono::time_point<std::chrono::steady_clock>
62 lastDateUpdate = std::chrono::steady_clock::now();
63 if (std::chrono::steady_clock::now() - lastDateUpdate >=
64 std::chrono::seconds(10))
65 {
66 lastDateUpdate = std::chrono::steady_clock::now();
67 updateDateStr();
68 }
Ed Tanous21b4aba2023-06-05 11:42:43 -070069 return dateStr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070071
Ed Tanous62598e32023-07-17 17:06:25 -070072 BMCWEB_LOG_INFO("bmcweb server is running, local endpoint {}",
Ed Tanous8db83742024-04-13 09:11:15 -070073 acceptor.local_endpoint().address().to_string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060074 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 doAccept();
76 }
77
Marri Devender Rao5968cae2019-01-21 10:27:12 -060078 void loadCertificate()
79 {
Ed Tanous25b54db2024-04-17 15:40:31 -070080 if constexpr (BMCWEB_INSECURE_DISABLE_SSL)
Ed Tanous8db83742024-04-13 09:11:15 -070081 {
82 return;
83 }
Abhilash Rajud5fb5842024-06-03 11:40:17 -050084
85 auto sslContext = ensuressl::getSslServerContext();
86
Marri Devender Rao5968cae2019-01-21 10:27:12 -060087 adaptorCtx = sslContext;
88 handler->ssl(std::move(sslContext));
Marri Devender Rao5968cae2019-01-21 10:27:12 -060089 }
90
91 void startAsyncWaitForSignal()
92 {
Ed Tanous002d39b2022-05-31 08:59:27 -070093 signals.async_wait(
94 [this](const boost::system::error_code& ec, int signalNo) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040095 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -060096 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040097 BMCWEB_LOG_INFO("Error in signal handler{}", ec.message());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060098 }
99 else
100 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400101 if (signalNo == SIGHUP)
102 {
103 BMCWEB_LOG_INFO("Receivied reload signal");
104 loadCertificate();
105 startAsyncWaitForSignal();
106 }
107 else
108 {
109 stop();
110 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600111 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400112 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600113 }
114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 void stop()
116 {
117 ioService->stop();
118 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700119 using Socket = boost::beast::lowest_layer_type<Adaptor>;
120 using SocketPtr = std::unique_ptr<Socket>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700121
Ed Tanous3281bcf2024-06-25 16:02:05 -0700122 void afterAccept(SocketPtr socket, const boost::system::error_code& ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700124 if (ec)
Ed Tanous8db83742024-04-13 09:11:15 -0700125 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700126 BMCWEB_LOG_ERROR("Failed to accept socket {}", ec);
Ed Tanous8db83742024-04-13 09:11:15 -0700127 return;
128 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700129
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800130 boost::asio::steady_timer timer(*ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800131 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanous3281bcf2024-06-25 16:02:05 -0700132
Ed Tanousceac6f72018-12-02 11:58:47 -0800133 if constexpr (std::is_same<Adaptor,
Ed Tanous003301a2024-04-16 09:59:19 -0700134 boost::asio::ssl::stream<
Ed Tanousceac6f72018-12-02 11:58:47 -0800135 boost::asio::ip::tcp::socket>>::value)
136 {
Ed Tanous8db83742024-04-13 09:11:15 -0700137 if (adaptorCtx == nullptr)
138 {
139 BMCWEB_LOG_CRITICAL(
Abhilash Rajud5fb5842024-06-03 11:40:17 -0500140 "Asked to launch TLS socket but no context available");
Ed Tanous8db83742024-04-13 09:11:15 -0700141 return;
142 }
Ed Tanous88e16122021-12-06 14:14:43 -0800143 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800144 handler, std::move(timer), getCachedDateStr,
Ed Tanous3281bcf2024-06-25 16:02:05 -0700145 Adaptor(std::move(*socket), *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800146 }
147 else
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)));
Ed Tanousceac6f72018-12-02 11:58:47 -0800152 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700153
154 boost::asio::post(*ioService, [connection] { connection->start(); });
155
156 doAccept();
157 }
158
159 void doAccept()
160 {
161 if (ioService == nullptr)
162 {
163 BMCWEB_LOG_CRITICAL("IoService was null");
164 return;
165 }
166
167 SocketPtr socket = std::make_unique<Socket>(*ioService);
168 // 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 Tanous23e64202020-09-15 19:21:30 -0700178 std::shared_ptr<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