Assign fd to your boost socket for socket activation

Viewed 27

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();
      }
0 Answers
Related