Allow for systemd socket activation
If spawned via systemd's socket activation mechanism, use that socket
instead of opening a new one to listen on.
Change-Id: Ia35110902b30b08355edf2fe4041e8377582e72c
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ca29d9..591734b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -154,6 +154,7 @@
target_link_libraries(bmcweb ${OPENSSL_LIBRARIES})
target_link_libraries(bmcweb ${ZLIB_LIBRARIES})
target_link_libraries(bmcweb pam)
+target_link_libraries(bmcweb -lsystemd)
target_link_libraries(bmcweb -lstdc++fs)
add_dependencies(bmcweb tinyxml2_static)
target_link_libraries(bmcweb tinyxml2_static)
diff --git a/crow/include/crow/app.h b/crow/include/crow/app.h
index e00cf9d..c43faf3 100644
--- a/crow/include/crow/app.h
+++ b/crow/include/crow/app.h
@@ -54,6 +54,11 @@
return router_.new_rule_tagged<Tag>(std::move(rule));
}
+ self_t& socket(int existing_socket) {
+ socket_ = existing_socket;
+ return *this;
+ }
+
self_t& port(std::uint16_t port) {
port_ = port;
return *this;
@@ -82,16 +87,27 @@
validate();
#ifdef CROW_ENABLE_SSL
if (use_ssl_) {
- ssl_server_ = std::move(
+ if (-1 == socket_) {
+ ssl_server_ = std::move(
std::make_unique<ssl_server_t>(this, bindaddr_, port_, &middlewares_,
concurrency_, &ssl_context_, io_));
+ } else {
+ ssl_server_ = std::move(
+ std::make_unique<ssl_server_t>(this, socket_, &middlewares_,
+ concurrency_, &ssl_context_, io_));
+ }
ssl_server_->set_tick_function(tick_interval_, tick_function_);
ssl_server_->run();
} else
#endif
{
- server_ = std::move(std::make_unique<server_t>(
- this, bindaddr_, port_, &middlewares_, concurrency_, nullptr, io_));
+ if (-1 == socket_) {
+ server_ = std::move(std::make_unique<server_t>(
+ this, bindaddr_, port_, &middlewares_, concurrency_, nullptr, io_));
+ } else {
+ server_ = std::move(std::make_unique<server_t>(
+ this, socket_, &middlewares_, concurrency_, nullptr, io_));
+ }
server_->set_tick_function(tick_interval_, tick_function_);
server_->run();
}
@@ -206,7 +222,8 @@
std::shared_ptr<asio::io_service> io_;
uint16_t port_ = 80;
uint16_t concurrency_ = 1;
- std::string bindaddr_ = "0.0.0.0";
+ std::string bindaddr_ = "::";
+ int socket_ = -1;
Router router_;
std::chrono::milliseconds tick_interval_{};
diff --git a/crow/include/crow/http_server.h b/crow/include/crow/http_server.h
index 7811743..54dd8a8 100644
--- a/crow/include/crow/http_server.h
+++ b/crow/include/crow/http_server.h
@@ -24,25 +24,45 @@
typename... Middlewares>
class Server {
public:
- Server(Handler* handler, const std::string& bindaddr, uint16_t port,
+ Server(Handler* handler, std::unique_ptr<tcp::acceptor>&& acceptor,
std::tuple<Middlewares...>* middlewares = nullptr,
uint16_t concurrency = 1,
typename Adaptor::context* adaptor_ctx = nullptr,
std::shared_ptr<boost::asio::io_service> io =
std::make_shared<boost::asio::io_service>())
: io_service_(std::move(io)),
- acceptor_(*io_service_,
- tcp::endpoint(boost::asio::ip::address::from_string(bindaddr),
- port)),
+ acceptor_(std::move(acceptor)),
signals_(*io_service_, SIGINT, SIGTERM),
tick_timer_(*io_service_),
handler_(handler),
concurrency_(concurrency),
- port_(port),
- bindaddr_(bindaddr),
middlewares_(middlewares),
adaptor_ctx_(adaptor_ctx) {}
+ Server(Handler* handler, const std::string& bindaddr, uint16_t port,
+ std::tuple<Middlewares...>* middlewares = nullptr,
+ uint16_t concurrency = 1,
+ typename Adaptor::context* adaptor_ctx = nullptr,
+ std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>())
+ : Server(handler,
+ std::make_unique<tcp::acceptor>(
+ *io, tcp::endpoint(
+ boost::asio::ip::address::from_string(bindaddr), port)),
+ middlewares, concurrency, adaptor_ctx, io) {}
+
+
+ Server(Handler* handler, int existing_socket,
+ std::tuple<Middlewares...>* middlewares = nullptr,
+ uint16_t concurrency = 1,
+ typename Adaptor::context* adaptor_ctx = nullptr,
+ std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>())
+ : Server(handler,
+ std::make_unique<tcp::acceptor>(
+ *io, boost::asio::ip::tcp::v6(), existing_socket),
+ middlewares, concurrency, adaptor_ctx, io) {}
+
void set_tick_function(std::chrono::milliseconds d, std::function<void()> f) {
tick_interval_ = d;
tick_function_ = f;
@@ -147,7 +167,8 @@
});
}
- CROW_LOG_INFO << server_name_ << " server is running, local port " << port_;
+ CROW_LOG_INFO << server_name_ << " server is running, local endpoint "
+ << acceptor_->local_endpoint();
signals_.async_wait([&](const boost::system::error_code& /*error*/,
int /*signal_number*/) { stop(); });
@@ -185,7 +206,7 @@
is, handler_, server_name_, middlewares_,
get_cached_date_str_pool_[roundrobin_index_],
*timer_queue_pool_[roundrobin_index_], adaptor_ctx_);
- acceptor_.async_accept(p->socket(),
+ acceptor_->async_accept(p->socket(),
[this, p, &is](boost::system::error_code ec) {
if (!ec) {
is.post([p] { p->start(); });
@@ -199,15 +220,13 @@
std::vector<std::unique_ptr<asio::io_service>> io_service_pool_;
std::vector<detail::dumb_timer_queue*> timer_queue_pool_;
std::vector<std::function<std::string()>> get_cached_date_str_pool_;
- tcp::acceptor acceptor_;
+ std::unique_ptr<tcp::acceptor> acceptor_;
boost::asio::signal_set signals_;
boost::asio::deadline_timer tick_timer_;
Handler* handler_;
uint16_t concurrency_{1};
std::string server_name_ = "iBMC";
- uint16_t port_;
- std::string bindaddr_;
unsigned int roundrobin_index_{};
std::chrono::milliseconds tick_interval_{};
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index 8060f88..834a5df 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -14,8 +14,31 @@
#include <string>
#include <crow/app.h>
#include <boost/asio.hpp>
+#include <systemd/sd-daemon.h>
#include "redfish.hpp"
+constexpr int defaultPort = 18080;
+
+template <typename... Middlewares>
+void setup_socket(crow::Crow<Middlewares...>& app) {
+ int listen_fd = sd_listen_fds(0);
+ if (1 == listen_fd) {
+ CROW_LOG_INFO << "attempting systemd socket activation";
+ if (sd_is_socket_inet(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1, 0)) {
+ CROW_LOG_INFO << "Starting webserver on socket handle "
+ << SD_LISTEN_FDS_START;
+ app.socket(SD_LISTEN_FDS_START);
+ } else {
+ CROW_LOG_INFO << "bad incoming socket, starting webserver on port "
+ << defaultPort;
+ app.port(defaultPort);
+ }
+ } else {
+ CROW_LOG_INFO << "Starting webserver on port " << defaultPort;
+ app.port(defaultPort);
+ }
+}
+
int main(int argc, char** argv) {
auto io = std::make_shared<boost::asio::io_service>();
crow::App<crow::PersistentData::Middleware,
@@ -44,9 +67,9 @@
crow::openbmc_mapper::request_routes(app);
crow::logger::setLogLevel(crow::LogLevel::INFO);
- int port = 18080;
- std::cout << "Starting webserver on port " << port << "\n";
- app.port(port);
+
+ CROW_LOG_INFO << "bmcweb (" << __DATE__ << ": " << __TIME__ << ')';
+ setup_socket(app);
// Start dbus connection
crow::connections::system_bus =