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/beast/ssl/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::beast::ssl_stream<boost::asio::ip::tcp::socket>; 36 using raw_socket_t = boost::asio::ip::tcp::socket; 37 38 using socket_type = 39 std::conditional_t<bmcwebEnableTLS, ssl_socket_t, raw_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 ~App() 47 { 48 stop(); 49 } 50 51 App(const App&) = delete; 52 App(App&&) = delete; 53 App& operator=(const App&) = delete; 54 App& operator=(const App&&) = delete; 55 56 template <typename Adaptor> 57 void handleUpgrade(Request& req, 58 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 59 Adaptor&& adaptor) 60 { 61 router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor)); 62 } 63 64 void handle(Request& req, 65 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 66 { 67 router.handle(req, asyncResp); 68 } 69 70 DynamicRule& routeDynamic(const std::string& rule) 71 { 72 return router.newRuleDynamic(rule); 73 } 74 75 template <uint64_t Tag> 76 auto& route(std::string&& rule) 77 { 78 return router.newRuleTagged<Tag>(std::move(rule)); 79 } 80 81 void validate() 82 { 83 router.validate(); 84 } 85 86 std::optional<boost::asio::ip::tcp::acceptor> setupSocket() 87 { 88 if (io == nullptr) 89 { 90 BMCWEB_LOG_CRITICAL("IO was nullptr?"); 91 return std::nullopt; 92 } 93 constexpr int defaultPort = 18080; 94 int listenFd = sd_listen_fds(0); 95 if (listenFd == 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 stop() 131 { 132 io->stop(); 133 } 134 135 void debugPrint() 136 { 137 BMCWEB_LOG_DEBUG("Routing:"); 138 router.debugPrint(); 139 } 140 141 std::vector<const std::string*> getRoutes() 142 { 143 const std::string root; 144 return router.getRoutes(root); 145 } 146 std::vector<const std::string*> getRoutes(const std::string& parent) 147 { 148 return router.getRoutes(parent); 149 } 150 151 App& ssl(std::shared_ptr<boost::asio::ssl::context>&& ctx) 152 { 153 sslContext = std::move(ctx); 154 BMCWEB_LOG_INFO("app::ssl context use_count={}", 155 sslContext.use_count()); 156 return *this; 157 } 158 159 std::shared_ptr<boost::asio::ssl::context> sslContext = nullptr; 160 161 boost::asio::io_context& ioContext() 162 { 163 return *io; 164 } 165 166 private: 167 std::shared_ptr<boost::asio::io_context> io; 168 169 std::optional<server_type> server; 170 171 Router router; 172 }; 173 } // namespace crow 174 using App = crow::App; 175