diff options
author | Ed Tanous <ed@tanous.net> | 2020-10-03 18:06:26 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2020-10-23 18:03:17 +0300 |
commit | 04e438cbad66838724d78ce12f28aff1fb892a63 (patch) | |
tree | 8d8c42a8b3d3e9f8e10c108dd6273e8185d04530 /http/http_server.hpp | |
parent | dc511aa73001a593a16dbcdaa5d53f320e4c7818 (diff) | |
download | bmcweb-04e438cbad66838724d78ce12f28aff1fb892a63.tar.xz |
fix include names
cppcheck isn't smart enough to recognize these are c++ headers, not c
headers. Considering we're already inconsistent about our naming, it's
easier to just be consistent, and move the last few files to use .hpp
instead of .h.
Tested:
Code builds, no changes.
Signed-off-by: Ed Tanous <ed@tanous.net>
Change-Id: Ic348d695f8527fa4a0ded53f433e1558c319db40
Diffstat (limited to 'http/http_server.hpp')
-rw-r--r-- | http/http_server.hpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/http/http_server.hpp b/http/http_server.hpp new file mode 100644 index 0000000000..0be487f036 --- /dev/null +++ b/http/http_server.hpp @@ -0,0 +1,240 @@ +#pragma once + +#include "http_connection.hpp" +#include "logging.hpp" +#include "timer_queue.hpp" + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/ssl/context.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/beast/ssl/ssl_stream.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <ssl_key_handler.hpp> + +#include <atomic> +#include <chrono> +#include <cstdint> +#include <filesystem> +#include <future> +#include <memory> +#include <utility> +#include <vector> + +namespace crow +{ + +template <typename Handler, typename Adaptor = boost::asio::ip::tcp::socket> +class Server +{ + public: + Server(Handler* handlerIn, + std::unique_ptr<boost::asio::ip::tcp::acceptor>&& acceptorIn, + std::shared_ptr<boost::asio::ssl::context> adaptor_ctx, + std::shared_ptr<boost::asio::io_context> io = + std::make_shared<boost::asio::io_context>()) : + ioService(std::move(io)), + acceptor(std::move(acceptorIn)), + signals(*ioService, SIGINT, SIGTERM, SIGHUP), timer(*ioService), + handler(handlerIn), adaptorCtx(std::move(adaptor_ctx)) + {} + + Server(Handler* handlerIn, const std::string& bindaddr, uint16_t port, + const std::shared_ptr<boost::asio::ssl::context>& adaptor_ctx, + const std::shared_ptr<boost::asio::io_context>& io = + std::make_shared<boost::asio::io_context>()) : + Server(handlerIn, + std::make_unique<boost::asio::ip::tcp::acceptor>( + *io, boost::asio::ip::tcp::endpoint( + boost::asio::ip::make_address(bindaddr), port)), + adaptor_ctx, io) + {} + + Server(Handler* handlerIn, int existing_socket, + const std::shared_ptr<boost::asio::ssl::context>& adaptor_ctx, + const std::shared_ptr<boost::asio::io_context>& io = + std::make_shared<boost::asio::io_context>()) : + Server(handlerIn, + std::make_unique<boost::asio::ip::tcp::acceptor>( + *io, boost::asio::ip::tcp::v6(), existing_socket), + adaptor_ctx, io) + {} + + void updateDateStr() + { + time_t lastTimeT = time(nullptr); + tm myTm{}; + + gmtime_r(&lastTimeT, &myTm); + + dateStr.resize(100); + size_t dateStrSz = + strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm); + dateStr.resize(dateStrSz); + } + + void run() + { + loadCertificate(); + updateDateStr(); + + getCachedDateStr = [this]() -> std::string { + static std::chrono::time_point<std::chrono::steady_clock> + lastDateUpdate = std::chrono::steady_clock::now(); + if (std::chrono::steady_clock::now() - lastDateUpdate >= + std::chrono::seconds(10)) + { + lastDateUpdate = std::chrono::steady_clock::now(); + updateDateStr(); + } + return this->dateStr; + }; + + timer.expires_after(std::chrono::seconds(1)); + + timerHandler = [this](const boost::system::error_code& ec) { + if (ec) + { + return; + } + timerQueue.process(); + timer.expires_after(std::chrono::seconds(1)); + timer.async_wait(timerHandler); + }; + timer.async_wait(timerHandler); + + BMCWEB_LOG_INFO << "bmcweb server is running, local endpoint " + << acceptor->local_endpoint(); + startAsyncWaitForSignal(); + doAccept(); + } + + void loadCertificate() + { +#ifdef BMCWEB_ENABLE_SSL + namespace fs = std::filesystem; + // Cleanup older certificate file existing in the system + fs::path oldCert = "/home/root/server.pem"; + if (fs::exists(oldCert)) + { + fs::remove("/home/root/server.pem"); + } + fs::path certPath = "/etc/ssl/certs/https/"; + // if path does not exist create the path so that + // self signed certificate can be created in the + // path + if (!fs::exists(certPath)) + { + fs::create_directories(certPath); + } + fs::path certFile = certPath / "server.pem"; + BMCWEB_LOG_INFO << "Building SSL Context file=" << certFile; + std::string sslPemFile(certFile); + ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile); + std::shared_ptr<boost::asio::ssl::context> sslContext = + ensuressl::getSslContext(sslPemFile); + adaptorCtx = sslContext; + handler->ssl(std::move(sslContext)); +#endif + } + + void startAsyncWaitForSignal() + { + signals.async_wait([this](const boost::system::error_code& ec, + int signalNo) { + if (ec) + { + BMCWEB_LOG_INFO << "Error in signal handler" << ec.message(); + } + else + { + if (signalNo == SIGHUP) + { + BMCWEB_LOG_INFO << "Receivied reload signal"; + loadCertificate(); + boost::system::error_code ec2; + acceptor->cancel(ec2); + if (ec2) + { + BMCWEB_LOG_ERROR + << "Error while canceling async operations:" + << ec2.message(); + } + this->startAsyncWaitForSignal(); + } + else + { + stop(); + } + } + }); + } + + void stop() + { + ioService->stop(); + } + + void doAccept() + { + std::optional<Adaptor> adaptorTemp; + if constexpr (std::is_same<Adaptor, + boost::beast::ssl_stream< + boost::asio::ip::tcp::socket>>::value) + { + adaptorTemp = Adaptor(*ioService, *adaptorCtx); + auto p = std::make_shared<Connection<Adaptor, Handler>>( + handler, getCachedDateStr, timerQueue, + std::move(adaptorTemp.value())); + + acceptor->async_accept(p->socket().next_layer(), + [this, p](boost::system::error_code ec) { + if (!ec) + { + boost::asio::post( + *this->ioService, + [p] { p->start(); }); + } + doAccept(); + }); + } + else + { + adaptorTemp = Adaptor(*ioService); + auto p = std::make_shared<Connection<Adaptor, Handler>>( + handler, getCachedDateStr, timerQueue, + std::move(adaptorTemp.value())); + + acceptor->async_accept( + p->socket(), [this, p](boost::system::error_code ec) { + if (!ec) + { + boost::asio::post(*this->ioService, + [p] { p->start(); }); + } + doAccept(); + }); + } + } + + private: + std::shared_ptr<boost::asio::io_context> ioService; + detail::TimerQueue timerQueue; + std::function<std::string()> getCachedDateStr; + std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor; + boost::asio::signal_set signals; + boost::asio::steady_timer timer; + + std::string dateStr; + + Handler* handler; + + std::function<void(const boost::system::error_code& ec)> timerHandler; + +#ifdef BMCWEB_ENABLE_SSL + bool useSsl{false}; +#endif + std::shared_ptr<boost::asio::ssl::context> adaptorCtx; +}; // namespace crow +} // namespace crow |