changeset 666:c99780476eb7

Misc: rework networking The network_stream and irc classes do not assume that owner is alive anymore by keeping handlers before end of block. Instead, callers postpone deletion of themselves when required to allow handler finishing correctly. Capture all exceptions that can happen in network_stream to make sure handler is called as appropriate in any case. Do the same in irc class. Create a dedicated on_disconnect event in server class which is emitted when the server gets disconnected but is not dead yet.
author David Demelier <markand@malikania.fr>
date Fri, 06 Apr 2018 13:44:20 +0200
parents 7ed23c858694
children 133353284280
files libcommon/irccd/network_stream.hpp libirccd-test/irccd/test/command_test.hpp libirccd/irccd/daemon/basic_transport_client.hpp libirccd/irccd/daemon/basic_transport_server.hpp libirccd/irccd/daemon/irc.cpp libirccd/irccd/daemon/irc.hpp libirccd/irccd/daemon/server.cpp libirccd/irccd/daemon/server.hpp libirccd/irccd/daemon/service/server_service.cpp libirccd/irccd/daemon/service/server_service.hpp libirccd/irccd/daemon/tls_transport_server.cpp libirccd/irccd/daemon/tls_transport_server.hpp libirccd/irccd/daemon/transport_client.cpp libirccd/irccd/daemon/transport_client.hpp libirccd/irccd/daemon/transport_server.cpp libirccd/irccd/daemon/transport_server.hpp libirccd/irccd/daemon/transport_util.cpp
diffstat 17 files changed, 240 insertions(+), 114 deletions(-) [+]
line wrap: on
line diff
--- a/libcommon/irccd/network_stream.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libcommon/irccd/network_stream.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -76,8 +76,15 @@
     rqueue_t rqueue_;
     squeue_t squeue_;
 
+    // Decomposition functions.
+    std::string eat(boost::system::error_code&, std::size_t) noexcept;
+    nlohmann::json parse(boost::system::error_code&, const std::string&) noexcept;
+
+    // I/O flushing.
     void rflush();
     void sflush();
+
+    // Wrap async_read_until/async_write.
     void do_recv(network_recv_handler);
     void do_send(const std::string&, network_send_handler);
 
@@ -146,6 +153,9 @@
     /**
      * Request a receive operation.
      *
+     * The handler must not throw exceptions and `this` must be valid in the
+     * lifetime of the handler.
+     *
      * \pre handler != nullptr
      * \param handler the handler
      */
@@ -154,6 +164,9 @@
     /**
      * Request a send operation.
      *
+     * The handler must not throw exceptions and `this` must be valid in the
+     * lifetime of the handler.
+     *
      * \pre json.is_object()
      * \param json the json message
      * \param handler the optional handler
@@ -162,44 +175,43 @@
 };
 
 template <typename Socket>
-void network_stream<Socket>::do_recv(network_recv_handler handler)
+std::string network_stream<Socket>::eat(boost::system::error_code& code, std::size_t xfer) noexcept
 {
-    boost::asio::async_read_until(socket_, rbuffer_, "\r\n\r\n", [this, handler] (auto code, auto xfer) {
-        if (code || xfer == 0U)
-            handler(make_error_code(boost::system::errc::network_down), nullptr);
-        else {
-            std::string str(
-                boost::asio::buffers_begin(rbuffer_.data()),
-                boost::asio::buffers_begin(rbuffer_.data()) + xfer - 4
-            );
-
-            // Remove early in case of errors.
-            rbuffer_.consume(xfer);
+    try {
+        std::string str(
+            boost::asio::buffers_begin(rbuffer_.data()),
+            boost::asio::buffers_begin(rbuffer_.data()) + xfer - 4
+        );
 
-            // TODO: catch nlohmann::json::parse_error when 3.0.0 is released.
-            nlohmann::json message;
-
-            try {
-                message = nlohmann::json::parse(str);
-            } catch (...) {}
+        // Only clean buffer here, so user can still try again later.
+        rbuffer_.consume(xfer);
+        code = make_error_code(boost::system::errc::success);
 
-            if (!message.is_object())
-                handler(make_error_code(boost::system::errc::invalid_argument), nullptr);
-            else
-                handler(code, std::move(message));
-        }
-    });
+        return str;
+    } catch (...) {
+        code = make_error_code(boost::system::errc::not_enough_memory);
+        return "";
+    }
 }
 
 template <typename Socket>
-void network_stream<Socket>::do_send(const std::string& str, network_send_handler handler)
+nlohmann::json network_stream<Socket>::parse(boost::system::error_code& code, const std::string& data) noexcept
 {
-    boost::asio::async_write(socket_, boost::asio::buffer(str), [handler] (auto code, auto xfer) {
-        if (code || xfer == 0U)
-            handler(make_error_code(boost::system::errc::network_down));
-        else
-            handler(code);
-    });
+    try {
+        const auto json = nlohmann::json::parse(data);
+
+        if (!json.is_object()) {
+            code = make_error_code(boost::system::errc::invalid_argument);
+            return nullptr;
+        }
+
+        code = make_error_code(boost::system::errc::success);
+
+        return json;
+    } catch (...) {
+        code = make_error_code(boost::system::errc::invalid_argument);
+        return nullptr;
+    }
 }
 
 template <typename Socket>
@@ -208,11 +220,9 @@
     if (rqueue_.empty())
         return;
 
-    do_recv([this] (auto code, auto json) {
-        auto h = rqueue_.front();
-
-        if (h)
-            h(code, std::move(json));
+    do_recv([this] (auto code, auto json) noexcept {
+        if (rqueue_.front())
+            rqueue_.front()(code, std::move(json));
 
         rqueue_.pop_front();
 
@@ -227,11 +237,9 @@
     if (squeue_.empty())
         return;
 
-    do_send(squeue_.front().first, [this] (auto code) {
-        auto h = squeue_.front().second;
-
-        if (h)
-            h(code);
+    do_send(squeue_.front().first, [this] (auto code) noexcept {
+        if (squeue_.front().second)
+            squeue_.front().second(code);
 
         squeue_.pop_front();
 
@@ -241,6 +249,37 @@
 }
 
 template <typename Socket>
+void network_stream<Socket>::do_recv(network_recv_handler handler)
+{
+    boost::asio::async_read_until(socket_, rbuffer_, "\r\n\r\n", [this, handler] (auto code, auto xfer) noexcept {
+        if (code || xfer == 0U) {
+            handler(make_error_code(boost::system::errc::network_down), nullptr);
+            return;
+        }
+
+        auto str = eat(code, xfer);
+
+        if (code)
+            handler(std::move(code), nullptr);
+
+        auto message = parse(code, str);
+
+        handler(std::move(code), std::move(message));
+    });
+}
+
+template <typename Socket>
+void network_stream<Socket>::do_send(const std::string& str, network_send_handler handler)
+{
+    boost::asio::async_write(socket_, boost::asio::buffer(str), [handler] (auto code, auto xfer) noexcept {
+        if (code || xfer == 0U)
+            handler(make_error_code(boost::system::errc::network_down));
+        else
+            handler(code);
+    });
+}
+
+template <typename Socket>
 void network_stream<Socket>::recv(network_recv_handler handler)
 {
     auto in_progress = !rqueue_.empty();
--- a/libirccd-test/irccd/test/command_test.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd-test/irccd/test/command_test.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -109,7 +109,7 @@
     // Add the server and the command.
     add<Commands...>();
     daemon_->set_log(std::make_unique<silent_logger>());
-    daemon_->transports().add(std::make_unique<ip_transport_server>(std::move(acc)));
+    daemon_->transports().add(std::make_unique<ip_transport_server>(service_, std::move(acc)));
 
     timer_.expires_from_now(boost::posix_time::seconds(10));
     timer_.async_wait([] (auto code) {
--- a/libirccd/irccd/daemon/basic_transport_client.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/basic_transport_client.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -35,6 +35,32 @@
 private:
     network_stream<Socket> stream_;
 
+protected:
+    /**
+     * \copydoc transport_client::do_recv
+     */
+    void do_recv(network_recv_handler handler) override
+    {
+        const auto self = shared_from_this();
+
+        stream_.recv([this, self, handler] (auto msg, auto code) noexcept {
+            handler(std::move(msg), std::move(code));
+        });
+    }
+
+    /**
+     * \copydoc transport_client::do_send
+     */
+    void do_send(nlohmann::json json, network_send_handler handler) override
+    {
+        const auto self = shared_from_this();
+
+        stream_.send(std::move(json), [this, self, handler] (auto code) noexcept {
+            if (handler)
+                handler(std::move(code));
+        });
+    }
+
 public:
     /**
      * Construct the client.
@@ -68,33 +94,6 @@
     {
         return stream_;
     }
-
-    /**
-     * \copydoc transport_client::do_recv
-     */
-    void do_recv(network_recv_handler handler) override
-    {
-        assert(handler);
-
-        auto self = shared_from_this();
-
-        stream_.recv([this, self, handler] (auto msg, auto code) {
-            handler(std::move(msg), std::move(code));
-        });
-    }
-
-    /**
-     * \copydoc transport_client::do_send
-     */
-    void do_send(nlohmann::json json, network_send_handler handler) override
-    {
-        auto self = shared_from_this();
-
-        stream_.send(std::move(json), [this, self, handler] (auto code) {
-            if (handler)
-                handler(std::move(code));
-        });
-    }
 };
 
 } // !irccd
--- a/libirccd/irccd/daemon/basic_transport_server.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/basic_transport_server.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -67,14 +67,16 @@
      * Constructor with an acceptor in parameter.
      *
      * \pre acceptor.is_open()
+     * \param service the io service
      * \param acceptor the already bound acceptor
      */
-    basic_transport_server(acceptor_t acceptor);
+    basic_transport_server(boost::asio::io_service& service, acceptor_t acceptor);
 };
 
 template <typename Protocol>
-basic_transport_server<Protocol>::basic_transport_server(acceptor_t acceptor)
-    : acceptor_(std::move(acceptor))
+basic_transport_server<Protocol>::basic_transport_server(boost::asio::io_service& service, acceptor_t acceptor)
+    : transport_server(service)
+    , acceptor_(std::move(acceptor))
 {
     assert(acceptor_.is_open());
 }
--- a/libirccd/irccd/daemon/irc.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/irc.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -68,18 +68,26 @@
 {
     assert(handler);
 
-    boost::asio::async_read_until(socket, buffer, "\r\n", [&socket, &buffer, handler] (auto code, auto xfer) {
-        if (code || xfer == 0U)
+    boost::asio::async_read_until(socket, buffer, "\r\n", [&socket, &buffer, handler] (auto code, auto xfer) noexcept {
+        if (code || xfer == 0U) {
             handler(std::move(code), message());
-        else {
-            std::string str(
+            return;
+        }
+
+        std::string data;
+
+        try {
+            data = std::string(
                 boost::asio::buffers_begin(buffer.data()),
                 boost::asio::buffers_begin(buffer.data()) + xfer - 2
             );
 
             buffer.consume(xfer);
-            handler(std::move(code), message::parse(str));
+        } catch (...) {
+            code = make_error_code(boost::system::errc::not_enough_memory);
         }
+
+        handler(code, code ? message() : message::parse(data));
     });
 }
 
@@ -88,8 +96,7 @@
 {
     assert(handler);
 
-    boost::asio::async_write(socket, boost::asio::buffer(message), [handler, message] (auto code, auto) {
-        // TODO: xfer
+    boost::asio::async_write(socket, boost::asio::buffer(message), [handler, message] (auto code, auto) noexcept {
         handler(code);
     });
 }
@@ -102,7 +109,9 @@
         return;
 
     do_recv(buffer_, [this] (auto code, auto message) {
-        input_.front()(code, std::move(message));
+        if (input_.front())
+            input_.front()(code, std::move(message));
+
         input_.pop_front();
 
         if (!code)
--- a/libirccd/irccd/daemon/irc.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/irc.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -435,6 +435,9 @@
     /**
      * Start receiving data.
      *
+     * The handler must not throw exceptions and `this` must be valid in the
+     * lifetime of the handler.
+     *
      * \param handler the handler to call
      */
     void recv(recv_t handler);
@@ -442,6 +445,9 @@
     /**
      * Start sending data.
      *
+     * The handler must not throw exceptions and `this` must be valid in the
+     * lifetime of the handler.
+     *
      * \param message the raw message
      * \param handler the handler to call
      */
--- a/libirccd/irccd/daemon/server.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/server.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -398,8 +398,13 @@
 void server::handle_recv(boost::system::error_code code, irc::message message)
 {
     if (code) {
-        state_ = state_t::disconnected;
-        conn_ = nullptr;
+        const auto self = shared_from_this();
+
+        service_.post([this, self] () {
+            state_ = state_t::disconnected;
+            conn_ = nullptr;
+            reconnect();
+        });
     } else {
         dispatch(message);
         recv();
@@ -515,7 +520,7 @@
 {
     conn_ = nullptr;
     state_ = state_t::disconnected;
-    on_die({shared_from_this()});
+    on_disconnect({shared_from_this()});
 }
 
 void server::reconnect() noexcept
@@ -638,8 +643,13 @@
 
     conn_->send(std::move(raw), [this] (auto code) {
         if (code) {
-            state_ = state_t::disconnected;
-            conn_ = nullptr;
+            const auto self = shared_from_this();
+
+            service_.post([this, self] () {
+                state_ = state_t::disconnected;
+                conn_ = nullptr;
+                reconnect();
+            });
         }
     });
 }
--- a/libirccd/irccd/daemon/server.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/server.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -281,6 +281,14 @@
     boost::signals2::signal<void (connect_event)> on_connect;
 
     /**
+     * Signal: on_disconnect
+     * ----------------------------------------------------------
+     *
+     * The server was disconnected but is reconnecting.
+     */
+    boost::signals2::signal<void (disconnect_event)> on_disconnect;
+
+    /**
      * Signal: on_die
      * ----------------------------------------------------------
      *
--- a/libirccd/irccd/daemon/service/server_service.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/service/server_service.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -41,8 +41,8 @@
               ExecFunc exec_func)
 {
     for (auto& plugin : daemon.plugins().list()) {
-        auto eventname = name_func(*plugin);
-        auto allowed = daemon.rules().solve(server, target, origin, plugin->get_name(), eventname);
+        const auto eventname = name_func(*plugin);
+        const auto allowed = daemon.rules().solve(server, target, origin, plugin->get_name(), eventname);
 
         if (!allowed) {
             daemon.get_log().debug("rule: event skipped on match");
@@ -80,11 +80,8 @@
     );
 }
 
-void server_service::handle_die(const disconnect_event& ev)
+void server_service::handle_disconnect(const disconnect_event& ev)
 {
-    // First, remove the server in case of exceptions.
-    servers_.erase(std::find(servers_.begin(), servers_.end(), ev.server));
-
     irccd_.get_log().debug() << "server " << ev.server->get_name() << ": event onDisconnect" << std::endl;
     irccd_.transports().broadcast(nlohmann::json::object({
         { "event",      "onDisconnect"          },
@@ -101,6 +98,11 @@
     );
 }
 
+void server_service::handle_die(const disconnect_event& ev)
+{
+    servers_.erase(std::find(servers_.begin(), servers_.end(), ev.server));
+}
+
 void server_service::handle_invite(const invite_event& ev)
 {
     irccd_.get_log().debug() << "server " << ev.server->get_name() << ": event onInvite:\n";
@@ -443,6 +445,7 @@
     assert(!has(server->get_name()));
 
     server->on_connect.connect(boost::bind(&server_service::handle_connect, this, _1));
+    server->on_disconnect.connect(boost::bind(&server_service::handle_disconnect, this, _1));
     server->on_die.connect(boost::bind(&server_service::handle_die, this, _1));
     server->on_invite.connect(boost::bind(&server_service::handle_invite, this, _1));
     server->on_join.connect(boost::bind(&server_service::handle_join, this, _1));
@@ -462,7 +465,7 @@
 
 std::shared_ptr<server> server_service::get(const std::string& name) const noexcept
 {
-    auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
+    const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
         return server->get_name() == name;
     });
 
@@ -487,7 +490,7 @@
 
 void server_service::remove(const std::string& name)
 {
-    auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
+    const auto it = std::find_if(servers_.begin(), servers_.end(), [&] (const auto& server) {
         return server->get_name() == name;
     });
 
--- a/libirccd/irccd/daemon/service/server_service.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/service/server_service.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -44,6 +44,7 @@
     std::vector<std::shared_ptr<server>> servers_;
 
     void handle_connect(const connect_event&);
+    void handle_disconnect(const disconnect_event&);
     void handle_die(const disconnect_event&);
     void handle_invite(const invite_event&);
     void handle_join(const join_event&);
--- a/libirccd/irccd/daemon/tls_transport_server.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/tls_transport_server.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -31,8 +31,8 @@
     });
 }
 
-tls_transport_server::tls_transport_server(acceptor_t acceptor, context_t context)
-    : ip_transport_server(std::move(acceptor))
+tls_transport_server::tls_transport_server(boost::asio::io_service& service, acceptor_t acceptor, context_t context)
+    : ip_transport_server(service, std::move(acceptor))
     , context_(std::move(context))
 {
 }
--- a/libirccd/irccd/daemon/tls_transport_server.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/tls_transport_server.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -59,10 +59,11 @@
     /**
      * Construct a secure layer transport server.
      *
+     * \param service the io service
      * \param acceptor the acceptor
      * \param context the SSL context
      */
-    tls_transport_server(acceptor_t acceptor, context_t context);
+    tls_transport_server(boost::asio::io_service& service, acceptor_t acceptor, context_t context);
 };
 
 } // !irccd
--- a/libirccd/irccd/daemon/transport_client.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/transport_client.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -23,16 +23,44 @@
 
 namespace irccd {
 
+void transport_client::erase()
+{
+    const auto self = shared_from_this();
+
+    state_ = state_t::closing;
+    parent_.get_service().post([this, self] () {
+        parent_.get_clients().erase(self);
+    });
+}
+
 void transport_client::recv(network_recv_handler handler)
 {
-    if (state_ != state_t::closing)
-        do_recv(std::move(handler));
+    assert(handler);
+
+    const auto self = shared_from_this();
+
+    if (state_ != state_t::closing) {
+        do_recv([this, self, handler] (auto code, auto msg) {
+            handler(code, msg);
+
+            if (code)
+                erase();
+        });
+    }
 }
 
 void transport_client::send(nlohmann::json json, network_send_handler handler)
 {
-    if (state_ != state_t::closing)
-        do_send(std::move(json), std::move(handler));
+    const auto self = shared_from_this();
+
+    if (state_ != state_t::closing) {
+        do_send(json, [this, self, handler] (auto code) {
+            if (handler)
+                handler(std::move(code));
+            if (code)
+                erase();
+        });
+    }
 }
 
 void transport_client::success(const std::string& cname, network_send_handler handler)
@@ -66,7 +94,7 @@
         if (handler)
             handler(code);
 
-        parent_.get_clients().erase(shared_from_this());
+        erase();
     });
 
     state_ = state_t::closing;
--- a/libirccd/irccd/daemon/transport_client.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/transport_client.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -45,6 +45,8 @@
     state_t state_{state_t::authenticating};
     transport_server& parent_;
 
+    void erase();
+
 protected:
     /**
      * Request a receive operation.
--- a/libirccd/irccd/daemon/transport_server.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/transport_server.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -64,7 +64,7 @@
     assert(client);
     assert(handler);
 
-    auto greetings = nlohmann::json({
+    const auto greetings = nlohmann::json({
         { "program",    "irccd"             },
         { "major",      IRCCD_VERSION_MAJOR },
         { "minor",      IRCCD_VERSION_MINOR },
@@ -108,9 +108,9 @@
 {
 }
 
-const std::error_category& transport_category() noexcept
+const boost::system::error_category& transport_category() noexcept
 {
-    static const class category : public std::error_category {
+    static const class category : public boost::system::error_category {
     public:
         const char* name() const noexcept override
         {
@@ -151,7 +151,7 @@
     return category;
 };
 
-std::error_code make_error_code(transport_error::error e) noexcept
+boost::system::error_code make_error_code(transport_error::error e) noexcept
 {
     return {static_cast<int>(e), transport_category()};
 }
--- a/libirccd/irccd/daemon/transport_server.hpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/transport_server.hpp	Fri Apr 06 13:44:20 2018 +0200
@@ -51,6 +51,7 @@
     using accept_t = std::function<void (boost::system::error_code, std::shared_ptr<transport_client>)>;
 
 private:
+    boost::asio::io_service& service_;
     client_set_t clients_;
     std::string password_;
 
@@ -71,7 +72,10 @@
     /**
      * Default constructor.
      */
-    transport_server() noexcept = default;
+    inline transport_server(boost::asio::io_service& service) noexcept
+        : service_(service)
+    {
+    }
 
     /**
      * Virtual destructor defaulted.
@@ -88,6 +92,16 @@
      */
     void accept(accept_t handler);
 
+    inline const boost::asio::io_service& get_service() const noexcept
+    {
+        return service_;
+    }
+
+    inline boost::asio::io_service& get_service() noexcept
+    {
+        return service_;
+    }
+
     /**
      * Get the clients.
      *
@@ -129,7 +143,7 @@
     }
 };
 
-class transport_error : public std::system_error {
+class transport_error : public boost::system::system_error {
 public:
     enum error {
         //!< Authentication is required.
@@ -174,23 +188,27 @@
  *
  * \return the singleton
  */
-const std::error_category& transport_category() noexcept;
+const boost::system::error_category& transport_category() noexcept;
 
 /**
  * Create a boost::system::error_code from server_error::error enum.
  *
  * \param e the error code
  */
-std::error_code make_error_code(transport_error::error e) noexcept;
+boost::system::error_code make_error_code(transport_error::error e) noexcept;
 
 } // !irccd
 
-namespace std {
+namespace boost {
+
+namespace system {
 
 template <>
 struct is_error_code_enum<irccd::transport_error::error> : public std::true_type {
 };
 
-} // !std
+} // !system
+
+} // !boost
 
 #endif // !IRCCD_DAEMON_TRANSPORT_SERVER_HPP
--- a/libirccd/irccd/daemon/transport_util.cpp	Thu Mar 29 20:01:02 2018 +0200
+++ b/libirccd/irccd/daemon/transport_util.cpp	Fri Apr 06 13:44:20 2018 +0200
@@ -119,11 +119,11 @@
         ctx.use_private_key_file(key, boost::asio::ssl::context::pem);
         ctx.use_certificate_file(cert, boost::asio::ssl::context::pem);
 
-        return std::make_unique<tls_transport_server>(std::move(acceptor), std::move(ctx));
+        return std::make_unique<tls_transport_server>(service, std::move(acceptor), std::move(ctx));
 #endif
     }
 
-    return std::make_unique<ip_transport_server>(std::move(acceptor));
+    return std::make_unique<ip_transport_server>(service, std::move(acceptor));
 }
 
 std::unique_ptr<transport_server> from_config_load_unix(io_service& service, const ini::section& sc)
@@ -144,7 +144,7 @@
     stream_protocol::endpoint endpoint(path);
     stream_protocol::acceptor acceptor(service, std::move(endpoint));
 
-    return std::make_unique<local_transport_server>(std::move(acceptor));
+    return std::make_unique<local_transport_server>(service, std::move(acceptor));
 #else
     (void)service;
     (void)sc;