blob: 6e63cbd4187d677fdd98f17ecb05d5c13f90e23c [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous911ac312017-08-15 09:37:42 -07003#include <atomic>
Ed Tanouse278c182019-03-13 16:23:37 -07004#include <boost/asio/ip/address.hpp>
Ed Tanous3112a142018-11-29 15:45:10 -08005#include <boost/asio/ip/tcp.hpp>
6#include <boost/asio/signal_set.hpp>
Ed Tanous2f1ebcd2019-02-13 19:39:07 -08007#include <boost/asio/ssl/context.hpp>
Ed Tanous271584a2019-07-09 16:24:22 -07008#include <boost/asio/steady_timer.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -07009#if BOOST_VERSION >= 107000
10#include <boost/beast/ssl/ssl_stream.hpp>
11#else
Ed Tanous2f1ebcd2019-02-13 19:39:07 -080012#include <boost/beast/experimental/core/ssl_stream.hpp>
Ed Tanouse278c182019-03-13 16:23:37 -070013#endif
14
Ed Tanous1abe55e2018-09-05 08:30:59 -070015#include <boost/date_time/posix_time/posix_time.hpp>
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>
Marri Devender Rao5968cae2019-01-21 10:27:12 -060021#include <ssl_key_handler.hpp>
Ed Tanous911ac312017-08-15 09:37:42 -070022#include <utility>
23#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -070024
Ed Tanousc94ad492019-10-10 15:39:33 -070025#include "http_connection.h"
26#include "logging.h"
27#include "timer_queue.h"
Ed Tanous7045c8d2017-04-03 10:04:37 -070028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029namespace crow
30{
Ed Tanous7045c8d2017-04-03 10:04:37 -070031using namespace boost;
32using tcp = asio::ip::tcp;
33
Ed Tanousceac6f72018-12-02 11:58:47 -080034template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket,
Ed Tanous7045c8d2017-04-03 10:04:37 -070035 typename... Middlewares>
Ed Tanous1abe55e2018-09-05 08:30:59 -070036class Server
37{
38 public:
39 Server(Handler* handler, std::unique_ptr<tcp::acceptor>&& acceptor,
Jason M. Billse3e29612019-09-13 08:05:13 -070040 std::shared_ptr<boost::asio::ssl::context> adaptor_ctx,
Ed Tanous1abe55e2018-09-05 08:30:59 -070041 std::tuple<Middlewares...>* middlewares = nullptr,
Ed Tanous8f626352018-12-19 14:51:54 -080042 std::shared_ptr<boost::asio::io_context> io =
43 std::make_shared<boost::asio::io_context>()) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 ioService(std::move(io)),
Marri Devender Rao5968cae2019-01-21 10:27:12 -060045 acceptor(std::move(acceptor)),
46 signals(*ioService, SIGINT, SIGTERM, SIGHUP), tickTimer(*ioService),
Jan Sowinskiee52ae12020-01-09 16:28:32 +000047 timer(*ioService), handler(handler), middlewares(middlewares),
48 adaptorCtx(adaptor_ctx)
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 {
50 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070051
Ed Tanous1abe55e2018-09-05 08:30:59 -070052 Server(Handler* handler, const std::string& bindaddr, uint16_t port,
Jason M. Billse3e29612019-09-13 08:05:13 -070053 std::shared_ptr<boost::asio::ssl::context> adaptor_ctx,
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 std::tuple<Middlewares...>* middlewares = nullptr,
Ed Tanous8f626352018-12-19 14:51:54 -080055 std::shared_ptr<boost::asio::io_context> io =
56 std::make_shared<boost::asio::io_context>()) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070057 Server(handler,
Ed Tanous9e6e1b22018-03-16 13:08:50 -070058 std::make_unique<tcp::acceptor>(
Ed Tanouse278c182019-03-13 16:23:37 -070059 *io, tcp::endpoint(boost::asio::ip::make_address(bindaddr),
60 port)),
Marri Devender Rao5968cae2019-01-21 10:27:12 -060061 adaptor_ctx, middlewares, io)
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 {
Ed Tanous7045c8d2017-04-03 10:04:37 -070063 }
64
Ed Tanous1abe55e2018-09-05 08:30:59 -070065 Server(Handler* handler, int existing_socket,
Jason M. Billse3e29612019-09-13 08:05:13 -070066 std::shared_ptr<boost::asio::ssl::context> adaptor_ctx,
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 std::tuple<Middlewares...>* middlewares = nullptr,
Ed Tanous8f626352018-12-19 14:51:54 -080068 std::shared_ptr<boost::asio::io_context> io =
69 std::make_shared<boost::asio::io_context>()) :
Ed Tanous1abe55e2018-09-05 08:30:59 -070070 Server(handler,
71 std::make_unique<tcp::acceptor>(*io, boost::asio::ip::tcp::v6(),
72 existing_socket),
Marri Devender Rao5968cae2019-01-21 10:27:12 -060073 adaptor_ctx, middlewares, io)
Ed Tanous1abe55e2018-09-05 08:30:59 -070074 {
75 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070076
Ed Tanous1abe55e2018-09-05 08:30:59 -070077 void setTickFunction(std::chrono::milliseconds d, std::function<void()> f)
78 {
79 tickInterval = d;
80 tickFunction = f;
81 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070082
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 void onTick()
84 {
85 tickFunction();
Ed Tanous271584a2019-07-09 16:24:22 -070086 tickTimer.expires_after(
87 std::chrono::milliseconds(tickInterval.count()));
Ed Tanous1abe55e2018-09-05 08:30:59 -070088 tickTimer.async_wait([this](const boost::system::error_code& ec) {
89 if (ec)
90 {
91 return;
92 }
93 onTick();
94 });
95 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070096
Ed Tanous1abe55e2018-09-05 08:30:59 -070097 void updateDateStr()
98 {
Ed Tanous99131cd2019-10-24 11:12:47 -070099 time_t lastTimeT = time(nullptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700101
Ed Tanous1abe55e2018-09-05 08:30:59 -0700102 gmtime_r(&lastTimeT, &myTm);
Ed Tanous271584a2019-07-09 16:24:22 -0700103
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104 dateStr.resize(100);
105 size_t dateStrSz =
106 strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm);
107 dateStr.resize(dateStrSz);
108 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110 void run()
111 {
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600112 loadCertificate();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 updateDateStr();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 getCachedDateStr = [this]() -> std::string {
116 static std::chrono::time_point<std::chrono::steady_clock>
117 lastDateUpdate = std::chrono::steady_clock::now();
118 if (std::chrono::steady_clock::now() - lastDateUpdate >=
119 std::chrono::seconds(10))
120 {
121 lastDateUpdate = std::chrono::steady_clock::now();
122 updateDateStr();
123 }
124 return this->dateStr;
125 };
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700126
Ed Tanous271584a2019-07-09 16:24:22 -0700127 timer.expires_after(std::chrono::seconds(1));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700128
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000129 timerHandler = [this](const boost::system::error_code& ec) {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 if (ec)
131 {
132 return;
133 }
134 timerQueue.process();
Ed Tanous271584a2019-07-09 16:24:22 -0700135 timer.expires_after(std::chrono::seconds(1));
Marri Devender Rao92e07bf2019-04-04 01:33:34 -0500136 timer.async_wait(timerHandler);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700137 };
Marri Devender Rao92e07bf2019-04-04 01:33:34 -0500138 timer.async_wait(timerHandler);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700139
Ed Tanous1abe55e2018-09-05 08:30:59 -0700140 if (tickFunction && tickInterval.count() > 0)
141 {
Ed Tanous271584a2019-07-09 16:24:22 -0700142 tickTimer.expires_after(
143 std::chrono::milliseconds(tickInterval.count()));
Ed Tanous1abe55e2018-09-05 08:30:59 -0700144 tickTimer.async_wait([this](const boost::system::error_code& ec) {
145 if (ec)
146 {
147 return;
148 }
149 onTick();
150 });
151 }
152
153 BMCWEB_LOG_INFO << serverName << " server is running, local endpoint "
154 << acceptor->local_endpoint();
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600155 startAsyncWaitForSignal();
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 doAccept();
157 }
158
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600159 void loadCertificate()
160 {
161#ifdef BMCWEB_ENABLE_SSL
162 namespace fs = std::filesystem;
163 // Cleanup older certificate file existing in the system
164 fs::path oldCert = "/home/root/server.pem";
165 if (fs::exists(oldCert))
166 {
167 fs::remove("/home/root/server.pem");
168 }
169 fs::path certPath = "/etc/ssl/certs/https/";
170 // if path does not exist create the path so that
171 // self signed certificate can be created in the
172 // path
173 if (!fs::exists(certPath))
174 {
175 fs::create_directories(certPath);
176 }
177 fs::path certFile = certPath / "server.pem";
178 BMCWEB_LOG_INFO << "Building SSL Context file=" << certFile;
179 std::string sslPemFile(certFile);
180 ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
181 std::shared_ptr<boost::asio::ssl::context> sslContext =
182 ensuressl::getSslContext(sslPemFile);
183 adaptorCtx = sslContext;
184 handler->ssl(std::move(sslContext));
185#endif
186 }
187
188 void startAsyncWaitForSignal()
189 {
190 signals.async_wait([this](const boost::system::error_code& ec,
191 int signalNo) {
192 if (ec)
193 {
194 BMCWEB_LOG_INFO << "Error in signal handler" << ec.message();
195 }
196 else
197 {
198 if (signalNo == SIGHUP)
199 {
200 BMCWEB_LOG_INFO << "Receivied reload signal";
201 loadCertificate();
Zbigniew Lukwinski7d0120b2019-10-15 09:12:45 +0200202 boost::system::error_code ec;
203 acceptor->cancel(ec);
204 if (ec)
205 {
206 BMCWEB_LOG_ERROR
207 << "Error while canceling async operations:"
208 << ec.message();
209 }
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600210 this->startAsyncWaitForSignal();
211 }
212 else
213 {
214 stop();
215 }
216 }
217 });
218 }
219
Ed Tanous1abe55e2018-09-05 08:30:59 -0700220 void stop()
221 {
222 ioService->stop();
223 }
224
225 void doAccept()
226 {
Ed Tanousceac6f72018-12-02 11:58:47 -0800227 std::optional<Adaptor> adaptorTemp;
228 if constexpr (std::is_same<Adaptor,
229 boost::beast::ssl_stream<
230 boost::asio::ip::tcp::socket>>::value)
231 {
232 adaptorTemp = Adaptor(*ioService, *adaptorCtx);
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000233 auto p =
234 std::make_shared<Connection<Adaptor, Handler, Middlewares...>>(
Ed Tanouse278c182019-03-13 16:23:37 -0700235 *ioService, handler, serverName, middlewares,
236 getCachedDateStr, timerQueue,
237 std::move(adaptorTemp.value()));
238
239 acceptor->async_accept(p->socket().next_layer(),
240 [this, p](boost::system::error_code ec) {
241 if (!ec)
242 {
243 boost::asio::post(
244 *this->ioService,
245 [p] { p->start(); });
246 }
Ed Tanouse278c182019-03-13 16:23:37 -0700247 doAccept();
248 });
Ed Tanousceac6f72018-12-02 11:58:47 -0800249 }
250 else
251 {
252 adaptorTemp = Adaptor(*ioService);
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000253 auto p =
254 std::make_shared<Connection<Adaptor, Handler, Middlewares...>>(
Ed Tanouse278c182019-03-13 16:23:37 -0700255 *ioService, handler, serverName, middlewares,
256 getCachedDateStr, timerQueue,
257 std::move(adaptorTemp.value()));
258
259 acceptor->async_accept(
260 p->socket(), [this, p](boost::system::error_code ec) {
261 if (!ec)
262 {
263 boost::asio::post(*this->ioService,
264 [p] { p->start(); });
265 }
Ed Tanouse278c182019-03-13 16:23:37 -0700266 doAccept();
267 });
Ed Tanousceac6f72018-12-02 11:58:47 -0800268 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700269 }
270
271 private:
Ed Tanous8f626352018-12-19 14:51:54 -0800272 std::shared_ptr<asio::io_context> ioService;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273 detail::TimerQueue timerQueue;
274 std::function<std::string()> getCachedDateStr;
275 std::unique_ptr<tcp::acceptor> acceptor;
276 boost::asio::signal_set signals;
Ed Tanous271584a2019-07-09 16:24:22 -0700277 boost::asio::steady_timer tickTimer;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000278 boost::asio::steady_timer timer;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700279
280 std::string dateStr;
281
282 Handler* handler;
283 std::string serverName = "iBMC";
284
285 std::chrono::milliseconds tickInterval{};
286 std::function<void()> tickFunction;
Jan Sowinskiee52ae12020-01-09 16:28:32 +0000287 std::function<void(const boost::system::error_code& ec)> timerHandler;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700288
289 std::tuple<Middlewares...>* middlewares;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700290
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700291#ifdef BMCWEB_ENABLE_SSL
Ed Tanous1abe55e2018-09-05 08:30:59 -0700292 bool useSsl{false};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700293#endif
Marri Devender Rao5968cae2019-01-21 10:27:12 -0600294 std::shared_ptr<boost::asio::ssl::context> adaptorCtx;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700295}; // namespace crow
296} // namespace crow