blob: 050a3f000edc49bb08e786878db78742b9c8751d [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"
Manojkiran Eda44250442020-06-16 12:51:38 +05305
Ed Tanouse278c182019-03-13 16:23:37 -07006#include <boost/asio/ip/address.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -08007#include <boost/asio/ip/tcp.hpp>
8#include <boost/asio/signal_set.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -08009#include <boost/asio/ssl/context.hpp>
Ed Tanous271584a2019-07-09 16:24:22 -070010#include <boost/asio/steady_timer.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -070011#include <boost/beast/ssl/ssl_stream.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070012#include <boost/date_time/posix_time/posix_time.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050013#include <ssl_key_handler.hpp>
14
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>
21#include <utility>
22#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070023
Ed Tanous1abe55e2018-09-05 08:30:59 -070024namespace crow
25{
Ed Tanous7045c8d2017-04-03 10:04:37 -070026
Ed Tanous52cc1122020-07-18 13:51:21 -070027template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket>
Ed Tanous1abe55e2018-09-05 08:30:59 -070028class Server
29{
30 public:
Ed Tanous23e64202020-09-15 19:21:30 -070031 Server(Handler* handlerIn,
32 std::unique_ptr<boost::asio::ip::tcp::acceptor>&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070033 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous8f626352018-12-19 14:51:54 -080034 std::shared_ptr<boost::asio::io_context> io =
35 std::make_shared<boost::asio::io_context>()) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 ioService(std::move(io)),
Ed Tanouscb13a392020-07-25 19:02:03 +000037 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 Tanouscb13a392020-07-25 19:02:03 +000042 Server(Handler* handlerIn, const std::string& bindaddr, uint16_t port,
Ed Tanous8a592812022-06-04 09:06:59 -070043 const std::shared_ptr<boost::asio::ssl::context>& adaptorCtxIn,
Ed Tanousb5a76932020-09-29 16:16:58 -070044 const std::shared_ptr<boost::asio::io_context>& io =
Ed Tanous8f626352018-12-19 14:51:54 -080045 std::make_shared<boost::asio::io_context>()) :
Ed Tanouscb13a392020-07-25 19:02:03 +000046 Server(handlerIn,
Ed Tanous23e64202020-09-15 19:21:30 -070047 std::make_unique<boost::asio::ip::tcp::acceptor>(
48 *io, boost::asio::ip::tcp::endpoint(
49 boost::asio::ip::make_address(bindaddr), port)),
Ed Tanous8a592812022-06-04 09:06:59 -070050 adaptorCtxIn, io)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050051 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070052
Ed Tanous81ce6092020-12-17 16:54:55 +000053 Server(Handler* handlerIn, int existingSocket,
Ed Tanous8a592812022-06-04 09:06:59 -070054 const std::shared_ptr<boost::asio::ssl::context>& adaptorCtxIn,
Ed Tanousb5a76932020-09-29 16:16:58 -070055 const std::shared_ptr<boost::asio::io_context>& io =
Ed Tanous8f626352018-12-19 14:51:54 -080056 std::make_shared<boost::asio::io_context>()) :
Ed Tanouscb13a392020-07-25 19:02:03 +000057 Server(handlerIn,
Ed Tanous23e64202020-09-15 19:21:30 -070058 std::make_unique<boost::asio::ip::tcp::acceptor>(
Ed Tanous81ce6092020-12-17 16:54:55 +000059 *io, boost::asio::ip::tcp::v6(), existingSocket),
Ed Tanous8a592812022-06-04 09:06:59 -070060 adaptorCtxIn, io)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050061 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070062
Ed Tanous1abe55e2018-09-05 08:30:59 -070063 void updateDateStr()
64 {
Ed Tanous99131cd2019-10-24 11:12:47 -070065 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070066 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070067
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070069
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 dateStr.resize(100);
71 size_t dateStrSz =
72 strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm);
73 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000074 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 void run()
77 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060078 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070080
Ed Tanous1abe55e2018-09-05 08:30:59 -070081 getCachedDateStr = [this]() -> std::string {
82 static std::chrono::time_point<std::chrono::steady_clock>
83 lastDateUpdate = std::chrono::steady_clock::now();
84 if (std::chrono::steady_clock::now() - lastDateUpdate >=
85 std::chrono::seconds(10))
86 {
87 lastDateUpdate = std::chrono::steady_clock::now();
88 updateDateStr();
89 }
90 return this->dateStr;
91 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070092
Ed Tanouse7d1a1c2020-09-28 09:36:35 -070093 BMCWEB_LOG_INFO << "bmcweb server is running, local endpoint "
Ed Tanous8cc8ede2022-02-28 10:20:59 -080094 << acceptor->local_endpoint().address().to_string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -060095 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070096 doAccept();
97 }
98
Marri Devender Rao5968cae2019-01-21 10:27:12 -060099 void loadCertificate()
100 {
101#ifdef BMCWEB_ENABLE_SSL
102 namespace fs = std::filesystem;
103 // Cleanup older certificate file existing in the system
104 fs::path oldCert = "/home/root/server.pem";
105 if (fs::exists(oldCert))
106 {
107 fs::remove("/home/root/server.pem");
108 }
109 fs::path certPath = "/etc/ssl/certs/https/";
110 // if path does not exist create the path so that
111 // self signed certificate can be created in the
112 // path
113 if (!fs::exists(certPath))
114 {
115 fs::create_directories(certPath);
116 }
117 fs::path certFile = certPath / "server.pem";
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800118 BMCWEB_LOG_INFO << "Building SSL Context file=" << certFile.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600119 std::string sslPemFile(certFile);
120 ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
121 std::shared_ptr<boost::asio::ssl::context> sslContext =
122 ensuressl::getSslContext(sslPemFile);
123 adaptorCtx = sslContext;
124 handler->ssl(std::move(sslContext));
125#endif
126 }
127
128 void startAsyncWaitForSignal()
129 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700130 signals.async_wait(
131 [this](const boost::system::error_code& ec, int signalNo) {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600132 if (ec)
133 {
134 BMCWEB_LOG_INFO << "Error in signal handler" << ec.message();
135 }
136 else
137 {
138 if (signalNo == SIGHUP)
139 {
140 BMCWEB_LOG_INFO << "Receivied reload signal";
141 loadCertificate();
Ed Tanouscb13a392020-07-25 19:02:03 +0000142 boost::system::error_code ec2;
143 acceptor->cancel(ec2);
144 if (ec2)
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200145 {
146 BMCWEB_LOG_ERROR
147 << "Error while canceling async operations:"
Ed Tanouscb13a392020-07-25 19:02:03 +0000148 << ec2.message();
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200149 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600150 this->startAsyncWaitForSignal();
151 }
152 else
153 {
154 stop();
155 }
156 }
157 });
158 }
159
Ed Tanous1abe55e2018-09-05 08:30:59 -0700160 void stop()
161 {
162 ioService->stop();
163 }
164
165 void doAccept()
166 {
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800167 boost::asio::steady_timer timer(*ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800168 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanousceac6f72018-12-02 11:58:47 -0800169 if constexpr (std::is_same<Adaptor,
170 boost::beast::ssl_stream<
171 boost::asio::ip::tcp::socket>>::value)
172 {
Ed Tanous88e16122021-12-06 14:14:43 -0800173 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800174 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800175 Adaptor(*ioService, *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800176 }
177 else
178 {
Ed Tanous88e16122021-12-06 14:14:43 -0800179 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800180 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800181 Adaptor(*ioService));
Ed Tanousceac6f72018-12-02 11:58:47 -0800182 }
Ed Tanous88e16122021-12-06 14:14:43 -0800183 acceptor->async_accept(
184 boost::beast::get_lowest_layer(connection->socket()),
185 [this, connection](boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700186 if (!ec)
187 {
188 boost::asio::post(*this->ioService,
189 [connection] { connection->start(); });
190 }
191 doAccept();
Ed Tanous88e16122021-12-06 14:14:43 -0800192 });
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 }
194
195 private:
Ed Tanous23e64202020-09-15 19:21:30 -0700196 std::shared_ptr<boost::asio::io_context> ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700197 std::function<std::string()> getCachedDateStr;
Ed Tanous23e64202020-09-15 19:21:30 -0700198 std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199 boost::asio::signal_set signals;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700200
201 std::string dateStr;
202
203 Handler* handler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700204
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600205 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800206};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700207} // namespace crow