blob: 97c57efecabfa456701f46007991883b7b88940d [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 Tanous04e438c2020-10-03 08:06:26 -07005#include "http_connection.hpp"
6#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08007#include "ssl_key_handler.hpp"
Manojkiran Eda44250442020-06-16 12:51:38 +05308
Ed Tanouse278c182019-03-13 16:23:37 -07009#include <boost/asio/ip/address.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -080010#include <boost/asio/ip/tcp.hpp>
11#include <boost/asio/signal_set.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080012#include <boost/asio/ssl/context.hpp>
Ed Tanous003301a2024-04-16 09:59:19 -070013#include <boost/asio/ssl/stream.hpp>
Ed Tanous271584a2019-07-09 16:24:22 -070014#include <boost/asio/steady_timer.hpp>
Ed Tanous3281bcf2024-06-25 16:02:05 -070015#include <boost/beast/core/stream_traits.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050016
Manojkiran Eda44250442020-06-16 12:51:38 +053017#include <atomic>
Ed Tanous3dac7492017-08-02 13:46:20 -070018#include <chrono>
Ed Tanous911ac312017-08-15 09:37:42 -070019#include <cstdint>
Marri Devender Rao5968cae2019-01-21 10:27:12 -060020#include <filesystem>
Ed Tanous911ac312017-08-15 09:37:42 -070021#include <future>
22#include <memory>
Ed Tanous099225c2024-03-27 22:03:05 -070023#include <string>
Ed Tanous911ac312017-08-15 09:37:42 -070024#include <utility>
25#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070026
Ed Tanous1abe55e2018-09-05 08:30:59 -070027namespace crow
28{
Ed Tanous7045c8d2017-04-03 10:04:37 -070029
Ed Tanous52cc1122020-07-18 13:51:21 -070030template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket>
Ed Tanous1abe55e2018-09-05 08:30:59 -070031class Server
32{
Ed Tanous3281bcf2024-06-25 16:02:05 -070033 using self_t = Server<Handler, Adaptor>;
34
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 public:
Ed Tanous8db83742024-04-13 09:11:15 -070036 Server(Handler* handlerIn, boost::asio::ip::tcp::acceptor&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070037 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous8db83742024-04-13 09:11:15 -070038 std::shared_ptr<boost::asio::io_context> io) :
Patrick Williamsbd79bce2024-08-16 15:22:20 -040039 ioService(std::move(io)), acceptor(std::move(acceptorIn)),
Ed Tanous5dfb5b22021-12-03 11:24:53 -080040 signals(*ioService, SIGINT, SIGTERM, SIGHUP), handler(handlerIn),
Ed Tanous8a592812022-06-04 09:06:59 -070041 adaptorCtx(std::move(adaptorCtxIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070043
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 void updateDateStr()
45 {
Ed Tanous99131cd2019-10-24 11:12:47 -070046 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 dateStr.resize(100);
Ed Tanous0f837072023-06-30 09:57:26 -070052 size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1,
Patrick Williams89492a12023-05-10 07:51:34 -050053 "%a, %d %b %Y %H:%M:%S GMT", &myTm);
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000055 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070056
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 void run()
58 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060059 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070061
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 getCachedDateStr = [this]() -> std::string {
63 static std::chrono::time_point<std::chrono::steady_clock>
64 lastDateUpdate = std::chrono::steady_clock::now();
65 if (std::chrono::steady_clock::now() - lastDateUpdate >=
66 std::chrono::seconds(10))
67 {
68 lastDateUpdate = std::chrono::steady_clock::now();
69 updateDateStr();
70 }
Ed Tanous21b4aba2023-06-05 11:42:43 -070071 return dateStr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070073
Ed Tanous62598e32023-07-17 17:06:25 -070074 BMCWEB_LOG_INFO("bmcweb server is running, local endpoint {}",
Ed Tanous8db83742024-04-13 09:11:15 -070075 acceptor.local_endpoint().address().to_string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060076 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070077 doAccept();
78 }
79
Marri Devender Rao5968cae2019-01-21 10:27:12 -060080 void loadCertificate()
81 {
Ed Tanous25b54db2024-04-17 15:40:31 -070082 if constexpr (BMCWEB_INSECURE_DISABLE_SSL)
Ed Tanous8db83742024-04-13 09:11:15 -070083 {
84 return;
85 }
Abhilash Rajud5fb5842024-06-03 11:40:17 -050086
87 auto sslContext = ensuressl::getSslServerContext();
88
Marri Devender Rao5968cae2019-01-21 10:27:12 -060089 adaptorCtx = sslContext;
90 handler->ssl(std::move(sslContext));
Marri Devender Rao5968cae2019-01-21 10:27:12 -060091 }
92
93 void startAsyncWaitForSignal()
94 {
Ed Tanous002d39b2022-05-31 08:59:27 -070095 signals.async_wait(
96 [this](const boost::system::error_code& ec, int signalNo) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040097 if (ec)
Marri Devender Rao5968cae2019-01-21 10:27:12 -060098 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -040099 BMCWEB_LOG_INFO("Error in signal handler{}", ec.message());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600100 }
101 else
102 {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400103 if (signalNo == SIGHUP)
104 {
105 BMCWEB_LOG_INFO("Receivied reload signal");
106 loadCertificate();
107 startAsyncWaitForSignal();
108 }
109 else
110 {
111 stop();
112 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600113 }
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400114 });
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600115 }
116
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 void stop()
118 {
119 ioService->stop();
120 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700121 using Socket = boost::beast::lowest_layer_type<Adaptor>;
122 using SocketPtr = std::unique_ptr<Socket>;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123
Ed Tanous3281bcf2024-06-25 16:02:05 -0700124 void afterAccept(SocketPtr socket, const boost::system::error_code& ec)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700125 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700126 if (ec)
Ed Tanous8db83742024-04-13 09:11:15 -0700127 {
Ed Tanous3281bcf2024-06-25 16:02:05 -0700128 BMCWEB_LOG_ERROR("Failed to accept socket {}", ec);
Ed Tanous8db83742024-04-13 09:11:15 -0700129 return;
130 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700131
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800132 boost::asio::steady_timer timer(*ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800133 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanous3281bcf2024-06-25 16:02:05 -0700134
Ed Tanousceac6f72018-12-02 11:58:47 -0800135 if constexpr (std::is_same<Adaptor,
Ed Tanous003301a2024-04-16 09:59:19 -0700136 boost::asio::ssl::stream<
Ed Tanousceac6f72018-12-02 11:58:47 -0800137 boost::asio::ip::tcp::socket>>::value)
138 {
Ed Tanous8db83742024-04-13 09:11:15 -0700139 if (adaptorCtx == nullptr)
140 {
141 BMCWEB_LOG_CRITICAL(
Abhilash Rajud5fb5842024-06-03 11:40:17 -0500142 "Asked to launch TLS socket but no context available");
Ed Tanous8db83742024-04-13 09:11:15 -0700143 return;
144 }
Ed Tanous88e16122021-12-06 14:14:43 -0800145 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800146 handler, std::move(timer), getCachedDateStr,
Ed Tanous3281bcf2024-06-25 16:02:05 -0700147 Adaptor(std::move(*socket), *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800148 }
149 else
150 {
Ed Tanous88e16122021-12-06 14:14:43 -0800151 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800152 handler, std::move(timer), getCachedDateStr,
Ed Tanous3281bcf2024-06-25 16:02:05 -0700153 Adaptor(std::move(*socket)));
Ed Tanousceac6f72018-12-02 11:58:47 -0800154 }
Ed Tanous3281bcf2024-06-25 16:02:05 -0700155
156 boost::asio::post(*ioService, [connection] { connection->start(); });
157
158 doAccept();
159 }
160
161 void doAccept()
162 {
163 if (ioService == nullptr)
164 {
165 BMCWEB_LOG_CRITICAL("IoService was null");
166 return;
167 }
168
169 SocketPtr socket = std::make_unique<Socket>(*ioService);
170 // Keep a raw pointer so when the socket is moved, the pointer is still
171 // valid
172 Socket* socketPtr = socket.get();
173
Ed Tanous8db83742024-04-13 09:11:15 -0700174 acceptor.async_accept(
Ed Tanous3281bcf2024-06-25 16:02:05 -0700175 *socketPtr,
176 std::bind_front(&self_t::afterAccept, this, std::move(socket)));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700177 }
178
179 private:
Ed Tanous23e64202020-09-15 19:21:30 -0700180 std::shared_ptr<boost::asio::io_context> ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700181 std::function<std::string()> getCachedDateStr;
Ed Tanous8db83742024-04-13 09:11:15 -0700182 boost::asio::ip::tcp::acceptor acceptor;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700183 boost::asio::signal_set signals;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700184
185 std::string dateStr;
186
187 Handler* handler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600189 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800190};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700191} // namespace crow