LCOV - code coverage report
Current view: top level - asio - listener.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 1 1
Test Date: 2026-11-10 10:38:07 Functions: - 0 0

            Line data    Source code
       1              : #ifndef THINGER_ASIO_LISTENER_HPP
       2              : #define THINGER_ASIO_LISTENER_HPP
       3              : 
       4              : #include <chrono>
       5              : #include <cstddef>
       6              : #include <cstdint>
       7              : #include <functional>
       8              : #include <memory>
       9              : #include <string>
      10              : #include <variant>
      11              : #include <vector>
      12              : #include <boost/asio/any_io_executor.hpp>
      13              : #include <boost/system/error_code.hpp>
      14              : #include "ssl/tls_session.hpp"
      15              : #include "../util/types.hpp"
      16              : 
      17              : namespace thinger::asio {
      18              : 
      19              : class socket;
      20              : class certificate_manager;
      21              : 
      22              : namespace detail {
      23              : // The internal switches of a listener (see detail/listener_access.hpp)
      24              : struct listener_access;
      25              : }
      26              : 
      27              : // A TCP endpoint to listen on: a host name or address (resolved synchronously by open()) and a
      28              : // port, 0 for one chosen by the system (see listener::local_port())
      29              : struct tcp_endpoint {
      30              :     std::string host = "0.0.0.0";
      31              :     uint16_t port = 0;
      32              : };
      33              : 
      34              : // A Unix domain socket to listen on: a file there before is replaced, and the file is removed
      35              : // when the listener stops
      36              : struct unix_endpoint {
      37              :     std::string path;
      38              : };
      39              : 
      40              : // How a listener listens. Plain data: the listener copies it
      41              : struct listener_options {
      42              :     std::variant<tcp_endpoint, unix_endpoint> endpoint;
      43              :     // The certificates of TLS: null for plain connections; one manager per listener, or shared
      44              :     // by several. The listener holds it until stop(), whatever open() returns: its connections
      45              :     // start with the default certificate open() found, and take the certificate and the client
      46              :     // certificate mode of their host name (SNI) from the manager. The application need not keep
      47              :     // a reference to it
      48              :     std::shared_ptr<certificate_manager> tls;
      49              :     // The client certificates asked for. A handshake that names a host (SNI) with a mode of its
      50              :     // own (see certificate_manager::set_client_verify()) gets that mode; every other handshake
      51              :     // gets this one. Ignored (logged) without tls
      52              :     client_verify_options client_verify;
      53              :     // How long a TLS client has to complete its handshake, from the connection accepted
      54              :     // (waiting for a slot included, see below): closed otherwise, without reaching the
      55              :     // handler. 0: no limit
      56           15 :     std::chrono::milliseconds handshake_timeout{60000};
      57              :     // TLS handshakes in progress at once per IO thread (per serve executor); a connection whose
      58              :     // thread is at the bound waits for a slot before its handshake starts, while accepting goes
      59              :     // on. 0: unbounded. With no handshake_timeout, connections waiting behind stalled
      60              :     // handshakes wait for as long as those do
      61              :     size_t max_pending_handshakes = 0;
      62              :     // Applied to the contexts of `tls`: listeners sharing a manager must agree (see open())
      63              :     session_cache_options session_cache;
      64              :     bool tcp_no_delay = true;
      65              :     // Attempts to bind before open() fails, every 5 s; -1: until it binds
      66              :     int max_listening_attempts = -1;
      67              :     // Remote addresses of TCP connections closed as they are accepted: a forbidden address is
      68              :     // always closed, and a non-empty allowed list closes every address not in it
      69              :     std::vector<std::string> allowed_remotes;
      70              :     std::vector<std::string> forbidden_remotes;
      71              : };
      72              : 
      73              : // The executor to accept on, or the next one to serve a connection on. In this release it must
      74              : // run on an io_context (an io_context executor, or a strand of one)
      75              : using executor_provider = std::function<boost::asio::any_io_executor()>;
      76              : 
      77              : // Accepts connections on a TCP endpoint, with or without TLS, or on a Unix domain socket, and
      78              : // hands each one to a handler: TLS connections once their handshake succeeded.
      79              : //
      80              : // open() binds and listens, start() accepts, stop() ends it: a listener is used once. It
      81              : // accepts on the executor of `accept_on` and serves each connection on the next executor of
      82              : // `serve_on`, where its handshake runs and its handler is called (a plain connection is handed
      83              : // over on the executor it was accepted on).
      84              : //
      85              : // stop() may be called from any thread, the handler included, and more than once. Once it
      86              : // returns, no handler starts anymore and none runs on another thread: called outside the
      87              : // handler, it waits for the handlers running on other threads to return, so a handler must
      88              : // never wait for a thread calling stop(). The destructor stops the listener.
      89              : class listener {
      90              : public:
      91              :     listener(listener_options options, executor_provider accept_on, executor_provider serve_on);
      92              :     ~listener();
      93              : 
      94              :     listener(const listener&) = delete;
      95              :     listener& operator=(const listener&) = delete;
      96              :     listener(listener&&) = delete;
      97              :     listener& operator=(listener&&) = delete;
      98              : 
      99              :     // Bind and listen. An error if it cannot: `invalid_argument` for options that cannot be
     100              :     // used (an executor not on an io_context, unreadable trusted CAs, a manager without a
     101              :     // context, a session cache that differs from the one of another listener of the same
     102              :     // manager), `already_open` if it was opened (or stopped) before, or the error resolving
     103              :     // the host or binding (after max_listening_attempts). Resolving is synchronous
     104              :     boost::system::error_code open();
     105              :     // Accept connections, handing each one to `on_connection` (see above). Nothing (logged) if
     106              :     // the listener is not open, or started already
     107              :     void start(sync_callback<void(std::shared_ptr<socket>)> on_connection);
     108              :     // Stop accepting: closes the listening socket and the connections whose handshake is
     109              :     // pending (see above)
     110              :     void stop();
     111              : 
     112              :     // The port listened on: 0 before open(), after stop(), and for Unix domain sockets
     113              :     uint16_t local_port() const;
     114              :     // Where it listens, once open: "http://0.0.0.0:8080", "https://[::1]:443", "unix:/run/x.sock"
     115              :     std::string url() const;
     116              : 
     117              : private:
     118              :     friend struct detail::listener_access;
     119              :     struct state;
     120              :     std::shared_ptr<state> state_;
     121              : };
     122              : 
     123              : } // namespace thinger::asio
     124              : 
     125              : #endif // THINGER_ASIO_LISTENER_HPP
        

Generated by: LCOV version 2.0-1