1 #pragma once 2 3 #include "async_resp.hpp" 4 #include "http_request.hpp" 5 #include "http_server.hpp" 6 #include "logging.hpp" 7 #include "privileges.hpp" 8 #include "routing.hpp" 9 #include "utility.hpp" 10 11 #include <systemd/sd-daemon.h> 12 13 #include <boost/asio/io_context.hpp> 14 #include <boost/asio/ip/tcp.hpp> 15 #include <boost/asio/ssl/context.hpp> 16 #include <boost/asio/ssl/stream.hpp> 17 18 #include <chrono> 19 #include <cstdint> 20 #include <functional> 21 #include <future> 22 #include <memory> 23 #include <string> 24 #include <utility> 25 26 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage, clang-diagnostic-unused-macros) 27 #define BMCWEB_ROUTE(app, url) \ 28 app.template route<crow::utility::getParameterTag(url)>(url) 29 30 namespace crow 31 { 32 class App 33 { 34 public: 35 using ssl_socket_t = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>; 36 using raw_socket_t = boost::asio::ip::tcp::socket; 37 38 using socket_type = std::conditional_t<BMCWEB_INSECURE_DISABLE_SSL, 39 raw_socket_t, ssl_socket_t>; 40 using server_type = Server<App, socket_type>; 41 42 explicit App(std::shared_ptr<boost::asio::io_context> ioIn = 43 std::make_shared<boost::asio::io_context>()) : 44 io(std::move(ioIn)) 45 {} 46 47 template <typename Adaptor> 48 void handleUpgrade(const std::shared_ptr<Request>& req, 49 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 50 Adaptor&& adaptor) 51 { 52 router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor)); 53 } 54 55 void handle(const std::shared_ptr<Request>& req, 56 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 57 { 58 router.handle(req, asyncResp); 59 } 60 61 DynamicRule& routeDynamic(const std::string& rule) 62 { 63 return router.newRuleDynamic(rule); 64 } 65 66 template <uint64_t Tag> 67 auto& route(std::string&& rule) 68 { 69 return router.newRuleTagged<Tag>(std::move(rule)); 70 } 71 72 void validate() 73 { 74 router.validate(); 75 } 76 77 void loadCertificate() 78 { 79 BMCWEB_LOG_DEBUG("Loading certificate"); 80 if (!server) 81 { 82 return; 83 } 84 server->loadCertificate(); 85 } 86 87 std::optional<boost::asio::ip::tcp::acceptor> setupSocket() 88 { 89 if (io == nullptr) 90 { 91 BMCWEB_LOG_CRITICAL("IO was nullptr?"); 92 return std::nullopt; 93 } 94 constexpr int defaultPort = 18080; 95 if (sd_listen_fds(0) == 1) 96 { 97 BMCWEB_LOG_INFO("attempting systemd socket activation"); 98 if (sd_is_socket_inet(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 99 1, 0) != 0) 100 { 101 BMCWEB_LOG_INFO("Starting webserver on socket handle {}", 102 SD_LISTEN_FDS_START); 103 return boost::asio::ip::tcp::acceptor( 104 *io, boost::asio::ip::tcp::v6(), SD_LISTEN_FDS_START); 105 } 106 BMCWEB_LOG_ERROR( 107 "bad incoming socket, starting webserver on port {}", 108 defaultPort); 109 } 110 BMCWEB_LOG_INFO("Starting webserver on port {}", defaultPort); 111 return boost::asio::ip::tcp::acceptor( 112 *io, boost::asio::ip::tcp::endpoint( 113 boost::asio::ip::make_address("0.0.0.0"), defaultPort)); 114 } 115 116 void run() 117 { 118 validate(); 119 120 std::optional<boost::asio::ip::tcp::acceptor> acceptor = setupSocket(); 121 if (!acceptor) 122 { 123 BMCWEB_LOG_CRITICAL("Couldn't start server"); 124 return; 125 } 126 server.emplace(this, std::move(*acceptor), sslContext, io); 127 server->run(); 128 } 129 130 void debugPrint() 131 { 132 BMCWEB_LOG_DEBUG("Routing:"); 133 router.debugPrint(); 134 } 135 136 std::vector<const std::string*> getRoutes() 137 { 138 const std::string root; 139 return router.getRoutes(root); 140 } 141 std::vector<const std::string*> getRoutes(const std::string& parent) 142 { 143 return router.getRoutes(parent); 144 } 145 146 App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx) 147 { 148 sslContext = std::move(ctx); 149 BMCWEB_LOG_INFO("app::ssl context use_count={}", 150 sslContext.use_count()); 151 return *this; 152 } 153 154 std::shared_ptr<boost::asio::ssl::context> sslContext = nullptr; 155 156 boost::asio::io_context& ioContext() 157 { 158 return *io; 159 } 160 161 private: 162 std::shared_ptr<boost::asio::io_context> io; 163 164 std::optional<server_type> server; 165 166 Router router; 167 }; 168 } // namespace crow 169 using App = crow::App; 170