When systemd starts the service, I should be provided with a fd as argument. How can I assign that fd to the boost socket? I read sd_listen_fds() returns how many file descriptors are passed. Should I use socket.assign() to assign that fd to the boost socket?
example-server.socket
[Unit]
Description= Example Server
[Socket]
ListenStream=127.0.0.1:8080
ReusePort=yes
[Install]
WantedBy=sockets.target
example=server.service
[Unit]
Description=Example Server
Requires=example-server.socket
[Service]
Type=simple
StandardInput=socket
StandardError=journal
ExecStartPre=+/bin/mount --bind /usr/share/fonts/maps /data/maps/fonts
ExecStart=/usr/bin/example-tile-server
ExecStopPost=+/bin/umount /data/maps/fonts
[Install]
WantedBy=multi-user.target
Modified server_http.hpp (https://gitlab.com/eidheim/Simple-Web-Server)
#include <arpa/inet.h>
#include <systemd/sd-daemon.h>
/// Start the server.
/// If io_service is not set, an internal io_service is created instead.
/// The callback argument is called after the server is accepting connections,
/// where its parameter contains the assigned port.
void start(const std::function<void(unsigned short /*port*/)> &callback = nullptr) {
std::unique_lock<std::mutex> lock(start_stop_mutex);
asio::ip::tcp::endpoint endpoint;
if(!config.address.empty())
endpoint = asio::ip::tcp::endpoint(make_address(config.address), config.port);
else
endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v6(), config.port);
if(!io_service) {
io_service = std::make_shared<io_context>();
internal_io_service = true;
}
if(!acceptor)
acceptor = std::unique_ptr<asio::ip::tcp::acceptor>(new asio::ip::tcp::acceptor(*io_service));
try {
acceptor->open(endpoint.protocol());
}
catch(const system_error &error) {
if(error.code() == asio::error::address_family_not_supported && config.address.empty()) {
endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config.port);
acceptor->open(endpoint.protocol());
}
else
throw;
}
acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address));
int opt = 1;
// Forcefully attaching the socket to the port
setsockopt(acceptor->native_handle(), SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(acceptor->native_handle(), SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
if(config.fast_open) {
#if defined(__linux__) && defined(TCP_FASTOPEN)
const int qlen = 5; // This seems to be the value that is used in other examples.
error_code ec;
acceptor->set_option(asio::detail::socket_option::integer<IPPROTO_TCP, TCP_FASTOPEN>(qlen), ec);
#endif // End Linux
}
acceptor->bind(endpoint);
after_bind();
auto port = acceptor->local_endpoint().port();
acceptor->listen();
accept();
if(internal_io_service && io_service->stopped())
restart(*io_service);
if(callback)
post(*io_service, [callback, port] {
callback(port);
});
if(internal_io_service) {
// If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
threads.clear();
for(std::size_t c = 1; c < config.thread_pool_size; c++) {
threads.emplace_back([this]() {
this->io_service->run();
});
}
lock.unlock();
// Main thread
if(config.thread_pool_size > 0)
io_service->run();
lock.lock();
// Wait for the rest of the threads, if any, to finish as well
for(auto &t : threads)
t.join();
}