blob: 96b85dc264c103b6fa657c88a70a6c0d2f24ca20 [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 Tanous3dac7492017-08-02 13:46:20 -07004#include <chrono>
Ed Tanous911ac312017-08-15 09:37:42 -07005#include <cstdint>
6#include <future>
7#include <memory>
8#include <utility>
9#include <vector>
Ed Tanous911ac312017-08-15 09:37:42 -070010#include "crow/http_connection.h"
11#include "crow/logging.h"
Ed Tanous55c7b7a2018-05-22 15:27:24 -070012#include "crow/timer_queue.h"
Ed Tanous7045c8d2017-04-03 10:04:37 -070013#include <boost/asio.hpp>
14#include <boost/date_time/posix_time/posix_time.hpp>
Ed Tanous55c7b7a2018-05-22 15:27:24 -070015#ifdef BMCWEB_ENABLE_SSL
Ed Tanous7045c8d2017-04-03 10:04:37 -070016#include <boost/asio/ssl.hpp>
17#endif
Ed Tanous7045c8d2017-04-03 10:04:37 -070018
19namespace crow {
20using namespace boost;
21using tcp = asio::ip::tcp;
22
23template <typename Handler, typename Adaptor = SocketAdaptor,
24 typename... Middlewares>
25class Server {
26 public:
Vernon Mauery168792a2018-01-26 13:42:54 -080027 Server(Handler* handler, std::unique_ptr<tcp::acceptor>&& acceptor,
Ed Tanous7045c8d2017-04-03 10:04:37 -070028 std::tuple<Middlewares...>* middlewares = nullptr,
Ed Tanous3dac7492017-08-02 13:46:20 -070029 typename Adaptor::context* adaptor_ctx = nullptr,
30 std::shared_ptr<boost::asio::io_service> io =
31 std::make_shared<boost::asio::io_service>())
Ed Tanous55c7b7a2018-05-22 15:27:24 -070032 : ioService(std::move(io)),
33 acceptor(std::move(acceptor)),
34 signals(*ioService, SIGINT, SIGTERM),
35 tickTimer(*ioService),
36 handler(handler),
37 middlewares(middlewares),
38 adaptorCtx(adaptor_ctx) {}
Ed Tanous7045c8d2017-04-03 10:04:37 -070039
Vernon Mauery168792a2018-01-26 13:42:54 -080040 Server(Handler* handler, const std::string& bindaddr, uint16_t port,
41 std::tuple<Middlewares...>* middlewares = nullptr,
Vernon Mauery168792a2018-01-26 13:42:54 -080042 typename Adaptor::context* adaptor_ctx = nullptr,
43 std::shared_ptr<boost::asio::io_service> io =
44 std::make_shared<boost::asio::io_service>())
45 : Server(handler,
Ed Tanous9e6e1b22018-03-16 13:08:50 -070046 std::make_unique<tcp::acceptor>(
47 *io,
48 tcp::endpoint(
49 boost::asio::ip::address::from_string(bindaddr), port)),
50 middlewares, adaptor_ctx, io) {}
Vernon Mauery168792a2018-01-26 13:42:54 -080051
52 Server(Handler* handler, int existing_socket,
53 std::tuple<Middlewares...>* middlewares = nullptr,
Vernon Mauery168792a2018-01-26 13:42:54 -080054 typename Adaptor::context* adaptor_ctx = nullptr,
55 std::shared_ptr<boost::asio::io_service> io =
56 std::make_shared<boost::asio::io_service>())
57 : Server(handler,
Ed Tanous9e6e1b22018-03-16 13:08:50 -070058 std::make_unique<tcp::acceptor>(*io, boost::asio::ip::tcp::v6(),
59 existing_socket),
60 middlewares, adaptor_ctx, io) {}
Vernon Mauery168792a2018-01-26 13:42:54 -080061
Ed Tanous55c7b7a2018-05-22 15:27:24 -070062 void setTickFunction(std::chrono::milliseconds d, std::function<void()> f) {
63 tickInterval = d;
64 tickFunction = f;
Ed Tanous7045c8d2017-04-03 10:04:37 -070065 }
66
Ed Tanous55c7b7a2018-05-22 15:27:24 -070067 void onTick() {
68 tickFunction();
69 tickTimer.expires_from_now(
70 boost::posix_time::milliseconds(tickInterval.count()));
71 tickTimer.async_wait([this](const boost::system::error_code& ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -070072 if (ec) {
Ed Tanous911ac312017-08-15 09:37:42 -070073 return;
74 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -070075 onTick();
Ed Tanous7045c8d2017-04-03 10:04:37 -070076 });
77 }
78
Ed Tanous55c7b7a2018-05-22 15:27:24 -070079 void updateDateStr() {
80 auto lastTimeT = time(0);
81 tm myTm{};
Ed Tanous7045c8d2017-04-03 10:04:37 -070082
83#ifdef _MSC_VER
Ed Tanous9e6e1b22018-03-16 13:08:50 -070084 gmtime_s(&my_tm, &last_time_t);
Ed Tanous7045c8d2017-04-03 10:04:37 -070085#else
Ed Tanous55c7b7a2018-05-22 15:27:24 -070086 gmtime_r(&lastTimeT, &myTm);
Ed Tanous7045c8d2017-04-03 10:04:37 -070087#endif
Ed Tanous55c7b7a2018-05-22 15:27:24 -070088 dateStr.resize(100);
89 size_t dateStrSz =
90 strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm);
91 dateStr.resize(dateStrSz);
Ed Tanous9e6e1b22018-03-16 13:08:50 -070092 };
93
94 void run() {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070095 updateDateStr();
Ed Tanous9e6e1b22018-03-16 13:08:50 -070096
Ed Tanous55c7b7a2018-05-22 15:27:24 -070097 getCachedDateStr = [this]() -> std::string {
98 static std::chrono::time_point<std::chrono::steady_clock> lastDateUpdate =
99 std::chrono::steady_clock::now();
100 if (std::chrono::steady_clock::now() - lastDateUpdate >=
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700101 std::chrono::seconds(10)) {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700102 lastDateUpdate = std::chrono::steady_clock::now();
103 updateDateStr();
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700104 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700105 return this->dateStr;
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700106 };
Ed Tanous7045c8d2017-04-03 10:04:37 -0700107
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700108 boost::asio::deadline_timer timer(*ioService);
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700109 timer.expires_from_now(boost::posix_time::seconds(1));
Ed Tanous7045c8d2017-04-03 10:04:37 -0700110
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700111 std::function<void(const boost::system::error_code& ec)> handler;
112 handler = [&](const boost::system::error_code& ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700113 if (ec) {
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700114 return;
115 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700116 timerQueue.process();
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700117 timer.expires_from_now(boost::posix_time::seconds(1));
118 timer.async_wait(handler);
119 };
120 timer.async_wait(handler);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700121
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700122 if (tickFunction && tickInterval.count() > 0) {
123 tickTimer.expires_from_now(
124 boost::posix_time::milliseconds(tickInterval.count()));
125 tickTimer.async_wait([this](const boost::system::error_code& ec) {
Ed Tanouse0d918b2018-03-27 17:41:04 -0700126 if (ec) {
Ed Tanous911ac312017-08-15 09:37:42 -0700127 return;
128 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700129 onTick();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700130 });
131 }
132
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700133 BMCWEB_LOG_INFO << serverName << " server is running, local endpoint "
134 << acceptor->local_endpoint();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700135
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700136 signals.async_wait([&](const boost::system::error_code& /*error*/,
137 int /*signal_number*/) { stop(); });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700138
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700139 doAccept();
Ed Tanous7045c8d2017-04-03 10:04:37 -0700140 }
141
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700142 void stop() { ioService->stop(); }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700143
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700144 void doAccept() {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700145 auto p = new Connection<Adaptor, Handler, Middlewares...>(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700146 *ioService, handler, serverName, middlewares, getCachedDateStr,
147 timerQueue, adaptorCtx);
148 acceptor->async_accept(p->socket(),
149 [this, p](boost::system::error_code ec) {
150 if (!ec) {
151 this->ioService->post([p] { p->start(); });
152 } else {
153 delete p;
154 }
155 doAccept();
156 });
Ed Tanous7045c8d2017-04-03 10:04:37 -0700157 }
158
159 private:
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700160 std::shared_ptr<asio::io_service> ioService;
161 detail::TimerQueue timerQueue;
162 std::function<std::string()> getCachedDateStr;
163 std::unique_ptr<tcp::acceptor> acceptor;
164 boost::asio::signal_set signals;
165 boost::asio::deadline_timer tickTimer;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700166
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700167 std::string dateStr;
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700168
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700169 Handler* handler;
170 std::string serverName = "iBMC";
Ed Tanous7045c8d2017-04-03 10:04:37 -0700171
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700172 std::chrono::milliseconds tickInterval{};
173 std::function<void()> tickFunction;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700174
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700175 std::tuple<Middlewares...>* middlewares;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700176
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700177#ifdef BMCWEB_ENABLE_SSL
178 bool useSsl{false};
179 boost::asio::ssl::context sslContext{boost::asio::ssl::context::sslv23};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700180#endif
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700181 typename Adaptor::context* adaptorCtx;
Ed Tanous9e6e1b22018-03-16 13:08:50 -0700182}; // namespace crow
Ed Tanous911ac312017-08-15 09:37:42 -0700183} // namespace crow