blob: afa4514c1fa3180c0d5de50b24edefbf66d48d8a [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 Tanous271584a2019-07-09 16:24:22 -070011#include <boost/asio/steady_timer.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -070012#include <boost/beast/ssl/ssl_stream.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 Tanous23e64202020-09-15 19:21:30 -070030 Server(Handler* handlerIn,
31 std::unique_ptr<boost::asio::ip::tcp::acceptor>&& acceptorIn,
Ed Tanous8a592812022-06-04 09:06:59 -070032 std::shared_ptr<boost::asio::ssl::context> adaptorCtxIn,
Ed Tanous8f626352018-12-19 14:51:54 -080033 std::shared_ptr<boost::asio::io_context> io =
34 std::make_shared<boost::asio::io_context>()) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 ioService(std::move(io)),
Ed Tanouscb13a392020-07-25 19:02:03 +000036 acceptor(std::move(acceptorIn)),
Ed Tanous5dfb5b22021-12-03 11:24:53 -080037 signals(*ioService, SIGINT, SIGTERM, SIGHUP), handler(handlerIn),
Ed Tanous8a592812022-06-04 09:06:59 -070038 adaptorCtx(std::move(adaptorCtxIn))
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070040
Ed Tanouscb13a392020-07-25 19:02:03 +000041 Server(Handler* handlerIn, const std::string& bindaddr, uint16_t port,
Ed Tanous8a592812022-06-04 09:06:59 -070042 const std::shared_ptr<boost::asio::ssl::context>& adaptorCtxIn,
Ed Tanousb5a76932020-09-29 16:16:58 -070043 const std::shared_ptr<boost::asio::io_context>& io =
Ed Tanous8f626352018-12-19 14:51:54 -080044 std::make_shared<boost::asio::io_context>()) :
Ed Tanouscb13a392020-07-25 19:02:03 +000045 Server(handlerIn,
Ed Tanous23e64202020-09-15 19:21:30 -070046 std::make_unique<boost::asio::ip::tcp::acceptor>(
47 *io, boost::asio::ip::tcp::endpoint(
48 boost::asio::ip::make_address(bindaddr), port)),
Ed Tanous8a592812022-06-04 09:06:59 -070049 adaptorCtxIn, io)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050050 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070051
Ed Tanous81ce6092020-12-17 16:54:55 +000052 Server(Handler* handlerIn, int existingSocket,
Ed Tanous8a592812022-06-04 09:06:59 -070053 const std::shared_ptr<boost::asio::ssl::context>& adaptorCtxIn,
Ed Tanousb5a76932020-09-29 16:16:58 -070054 const std::shared_ptr<boost::asio::io_context>& io =
Ed Tanous8f626352018-12-19 14:51:54 -080055 std::make_shared<boost::asio::io_context>()) :
Ed Tanouscb13a392020-07-25 19:02:03 +000056 Server(handlerIn,
Ed Tanous23e64202020-09-15 19:21:30 -070057 std::make_unique<boost::asio::ip::tcp::acceptor>(
Ed Tanous81ce6092020-12-17 16:54:55 +000058 *io, boost::asio::ip::tcp::v6(), existingSocket),
Ed Tanous8a592812022-06-04 09:06:59 -070059 adaptorCtxIn, io)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050060 {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070061
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 void updateDateStr()
63 {
Ed Tanous99131cd2019-10-24 11:12:47 -070064 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070066
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -070068
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 dateStr.resize(100);
Patrick Williams89492a12023-05-10 07:51:34 -050070 size_t dateStrSz = strftime(&dateStr[0], 99,
71 "%a, %d %b %Y %H:%M:%S GMT", &myTm);
Ed Tanous1abe55e2018-09-05 08:30:59 -070072 dateStr.resize(dateStrSz);
Ed Tanous23a21a12020-07-25 04:45:05 +000073 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 void run()
76 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -060077 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -070078 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -070079
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 getCachedDateStr = [this]() -> std::string {
81 static std::chrono::time_point<std::chrono::steady_clock>
82 lastDateUpdate = std::chrono::steady_clock::now();
83 if (std::chrono::steady_clock::now() - lastDateUpdate >=
84 std::chrono::seconds(10))
85 {
86 lastDateUpdate = std::chrono::steady_clock::now();
87 updateDateStr();
88 }
89 return this->dateStr;
90 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -070091
Ed Tanouse7d1a1c2020-09-28 09:36:35 -070092 BMCWEB_LOG_INFO << "bmcweb server is running, local endpoint "
Ed Tanous8cc8ede2022-02-28 10:20:59 -080093 << acceptor->local_endpoint().address().to_string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -060094 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -070095 doAccept();
96 }
97
Marri Devender Rao5968cae2019-01-21 10:27:12 -060098 void loadCertificate()
99 {
100#ifdef BMCWEB_ENABLE_SSL
101 namespace fs = std::filesystem;
102 // Cleanup older certificate file existing in the system
103 fs::path oldCert = "/home/root/server.pem";
104 if (fs::exists(oldCert))
105 {
106 fs::remove("/home/root/server.pem");
107 }
108 fs::path certPath = "/etc/ssl/certs/https/";
109 // if path does not exist create the path so that
110 // self signed certificate can be created in the
111 // path
112 if (!fs::exists(certPath))
113 {
114 fs::create_directories(certPath);
115 }
116 fs::path certFile = certPath / "server.pem";
Ed Tanous8cc8ede2022-02-28 10:20:59 -0800117 BMCWEB_LOG_INFO << "Building SSL Context file=" << certFile.string();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600118 std::string sslPemFile(certFile);
119 ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
120 std::shared_ptr<boost::asio::ssl::context> sslContext =
121 ensuressl::getSslContext(sslPemFile);
122 adaptorCtx = sslContext;
123 handler->ssl(std::move(sslContext));
124#endif
125 }
126
127 void startAsyncWaitForSignal()
128 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700129 signals.async_wait(
130 [this](const boost::system::error_code& ec, int signalNo) {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600131 if (ec)
132 {
133 BMCWEB_LOG_INFO << "Error in signal handler" << ec.message();
134 }
135 else
136 {
137 if (signalNo == SIGHUP)
138 {
139 BMCWEB_LOG_INFO << "Receivied reload signal";
140 loadCertificate();
Ed Tanouscb13a392020-07-25 19:02:03 +0000141 boost::system::error_code ec2;
142 acceptor->cancel(ec2);
143 if (ec2)
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200144 {
145 BMCWEB_LOG_ERROR
146 << "Error while canceling async operations:"
Ed Tanouscb13a392020-07-25 19:02:03 +0000147 << ec2.message();
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200148 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600149 this->startAsyncWaitForSignal();
150 }
151 else
152 {
153 stop();
154 }
155 }
156 });
157 }
158
Ed Tanous1abe55e2018-09-05 08:30:59 -0700159 void stop()
160 {
161 ioService->stop();
162 }
163
164 void doAccept()
165 {
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800166 boost::asio::steady_timer timer(*ioService);
Ed Tanous88e16122021-12-06 14:14:43 -0800167 std::shared_ptr<Connection<Adaptor, Handler>> connection;
Ed Tanousceac6f72018-12-02 11:58:47 -0800168 if constexpr (std::is_same<Adaptor,
169 boost::beast::ssl_stream<
170 boost::asio::ip::tcp::socket>>::value)
171 {
Ed Tanous88e16122021-12-06 14:14:43 -0800172 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800173 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800174 Adaptor(*ioService, *adaptorCtx));
Ed Tanousceac6f72018-12-02 11:58:47 -0800175 }
176 else
177 {
Ed Tanous88e16122021-12-06 14:14:43 -0800178 connection = std::make_shared<Connection<Adaptor, Handler>>(
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800179 handler, std::move(timer), getCachedDateStr,
Ed Tanous88e16122021-12-06 14:14:43 -0800180 Adaptor(*ioService));
Ed Tanousceac6f72018-12-02 11:58:47 -0800181 }
Ed Tanous88e16122021-12-06 14:14:43 -0800182 acceptor->async_accept(
183 boost::beast::get_lowest_layer(connection->socket()),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800184 [this, connection](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700185 if (!ec)
186 {
187 boost::asio::post(*this->ioService,
188 [connection] { connection->start(); });
189 }
190 doAccept();
Ed Tanous88e16122021-12-06 14:14:43 -0800191 });
Ed Tanous1abe55e2018-09-05 08:30:59 -0700192 }
193
194 private:
Ed Tanous23e64202020-09-15 19:21:30 -0700195 std::shared_ptr<boost::asio::io_context> ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196 std::function<std::string()> getCachedDateStr;
Ed Tanous23e64202020-09-15 19:21:30 -0700197 std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700198 boost::asio::signal_set signals;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700199
200 std::string dateStr;
201
202 Handler* handler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700203
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600204 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous5dfb5b22021-12-03 11:24:53 -0800205};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700206} // namespace crow