blob: 206a0d175e64ef93bdc1ec3d9030acabab733053 [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>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050013
Manojkiran Eda44250442020-06-16 12:51:38 +053014#include <atomic>
Ed Tanous3dac7492017-08-02 13:46:20 -070015#include <chrono>
Ed Tanous911ac312017-08-15 09:37:42 -070016#include <cstdint>
Marri Devender Rao5968cae2019-01-21 10:27:12 -060017#include <filesystem>
Ed Tanous911ac312017-08-15 09:37:42 -070018#include <future>
19#include <memory>
20#include <utility>
21#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023namespace crow
24{
Ed Tanous7045c8d2017-04-03 10:04:37 -070025
Ed Tanous52cc1122020-07-18 13:51:21 -070026template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket>
Ed Tanous1abe55e2018-09-05 08:30:59 -070027class Server
28{
29 public:
Ed Tanous8db83742024-04-13 09:11:15 -070030 Server(Handler* handlerIn, boost::asio::ip::tcp::acceptor&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070031 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous8db83742024-04-13 09:11:15 -070032 std::shared_ptr<boost::asio::io_context> io) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 ioService(std::move(io)),
Ed Tanouscb13a392020-07-25 19:02:03 +000034 acceptor(std::move(acceptorIn)),
Ed Tanous5dfb5b22021-12-03 11:24:53 -080035 signals(*ioService, SIGINT, SIGTERM, SIGHUP), handler(handlerIn),
Ed Tanous8a592812022-06-04 09:06:59 -070036 adaptorCtx(std::move(adaptorCtxIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070038
Ed Tanous1abe55e2018-09-05 08:30:59 -070039 void updateDateStr()
40 {
Ed Tanous99131cd2019-10-24 11:12:47 -070041 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070042 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070043
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070045
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 dateStr.resize(100);
Ed Tanous0f837072023-06-30 09:57:26 -070047 size_t dateStrSz = strftime(dateStr.data(), dateStr.size() - 1,
Patrick Williams89492a12023-05-10 07:51:34 -050048 "%a, %d %b %Y %H:%M:%S GMT", &myTm);
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000050 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070051
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 void run()
53 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060054 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070056
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 getCachedDateStr = [this]() -> std::string {
58 static std::chrono::time_point<std::chrono::steady_clock>
59 lastDateUpdate = std::chrono::steady_clock::now();
60 if (std::chrono::steady_clock::now() - lastDateUpdate >=
61 std::chrono::seconds(10))
62 {
63 lastDateUpdate = std::chrono::steady_clock::now();
64 updateDateStr();
65 }
Ed Tanous21b4aba2023-06-05 11:42:43 -070066 return dateStr;
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070068
Ed Tanous62598e32023-07-17 17:06:25 -070069 BMCWEB_LOG_INFO("bmcweb server is running, local endpoint {}",
Ed Tanous8db83742024-04-13 09:11:15 -070070 acceptor.local_endpoint().address().to_string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060071 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 doAccept();
73 }
74
Marri Devender Rao5968cae2019-01-21 10:27:12 -060075 void loadCertificate()
76 {
Ed Tanous25b54db2024-04-17 15:40:31 -070077 if constexpr (BMCWEB_INSECURE_DISABLE_SSL)
Ed Tanous8db83742024-04-13 09:11:15 -070078 {
79 return;
80 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -060081 namespace fs = std::filesystem;
82 // Cleanup older certificate file existing in the system
83 fs::path oldCert = "/home/root/server.pem";
84 if (fs::exists(oldCert))
85 {
86 fs::remove("/home/root/server.pem");
87 }
88 fs::path certPath = "/etc/ssl/certs/https/";
89 // if path does not exist create the path so that
90 // self signed certificate can be created in the
91 // path
92 if (!fs::exists(certPath))
93 {
94 fs::create_directories(certPath);
95 }
96 fs::path certFile = certPath / "server.pem";
Ed Tanous62598e32023-07-17 17:06:25 -070097 BMCWEB_LOG_INFO("Building SSL Context file={}", certFile.string());
Marri Devender Rao5968cae2019-01-21 10:27:12 -060098 std::string sslPemFile(certFile);
99 ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
100 std::shared_ptr<boost::asio::ssl::context> sslContext =
101 ensuressl::getSslContext(sslPemFile);
102 adaptorCtx = sslContext;
103 handler->ssl(std::move(sslContext));
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600104 }
105
106 void startAsyncWaitForSignal()
107 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700108 signals.async_wait(
109 [this](const boost::system::error_code& ec, int signalNo) {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600110 if (ec)
111 {
Ed Tanous62598e32023-07-17 17:06:25 -0700112 BMCWEB_LOG_INFO("Error in signal handler{}", ec.message());
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600113 }
114 else
115 {
116 if (signalNo == SIGHUP)
117 {
Ed Tanous62598e32023-07-17 17:06:25 -0700118 BMCWEB_LOG_INFO("Receivied reload signal");
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600119 loadCertificate();
Ed Tanouscb13a392020-07-25 19:02:03 +0000120 boost::system::error_code ec2;
Ed Tanous8db83742024-04-13 09:11:15 -0700121 acceptor.cancel(ec2);
Ed Tanouscb13a392020-07-25 19:02:03 +0000122 if (ec2)
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200123 {
Ed Tanous62598e32023-07-17 17:06:25 -0700124 BMCWEB_LOG_ERROR(
125 "Error while canceling async operations:{}",
126 ec2.message());
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200127 }
Ed Tanous21b4aba2023-06-05 11:42:43 -0700128 startAsyncWaitForSignal();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600129 }
130 else
131 {
132 stop();
133 }
134 }
135 });
136 }
137
Ed Tanous1abe55e2018-09-05 08:30:59 -0700138 void stop()
139 {
140 ioService->stop();
141 }
142
143 void doAccept()
144 {
Ed Tanous8db83742024-04-13 09:11:15 -0700145 if (ioService == nullptr)
146 {
147 BMCWEB_LOG_CRITICAL("IoService was null");
148 return;
149 }
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800150 boost::asio::steady_timer timer(*ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800151 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanousceac6f72018-12-02 11:58:47 -0800152 if constexpr (std::is_same<Adaptor,
Ed Tanous003301a2024-04-16 09:59:19 -0700153 boost::asio::ssl::stream<
Ed Tanousceac6f72018-12-02 11:58:47 -0800154 boost::asio::ip::tcp::socket>>::value)
155 {
Ed Tanous8db83742024-04-13 09:11:15 -0700156 if (adaptorCtx == nullptr)
157 {
158 BMCWEB_LOG_CRITICAL(
159 "Asked to lauch TLS socket but no context available");
160 return;
161 }
Ed Tanous88e16122021-12-06 14:14:43 -0800162 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800163 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800164 Adaptor(*ioService, *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800165 }
166 else
167 {
Ed Tanous88e16122021-12-06 14:14:43 -0800168 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800169 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800170 Adaptor(*ioService));
Ed Tanousceac6f72018-12-02 11:58:47 -0800171 }
Ed Tanous8db83742024-04-13 09:11:15 -0700172 acceptor.async_accept(
Ed Tanous88e16122021-12-06 14:14:43 -0800173 boost::beast::get_lowest_layer(connection->socket()),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800174 [this, connection](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700175 if (!ec)
176 {
Ed Tanous21b4aba2023-06-05 11:42:43 -0700177 boost::asio::post(*ioService,
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 [connection] { connection->start(); });
179 }
180 doAccept();
Patrick Williams5a39f772023-10-20 11:20:21 -0500181 });
Ed Tanous1abe55e2018-09-05 08:30:59 -0700182 }
183
184 private:
Ed Tanous23e64202020-09-15 19:21:30 -0700185 std::shared_ptr<boost::asio::io_context> ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186 std::function<std::string()> getCachedDateStr;
Ed Tanous8db83742024-04-13 09:11:15 -0700187 boost::asio::ip::tcp::acceptor acceptor;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700188 boost::asio::signal_set signals;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189
190 std::string dateStr;
191
192 Handler* handler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600194 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800195};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196} // namespace crow