changeset 639:d12a87c0e3f6

Irccd: implement transport_util, #771
author David Demelier <markand@malikania.fr>
date Mon, 19 Mar 2018 13:26:53 +0100
parents af963ff03c06
children e2ad41b02ebf
files libirccd/CMakeLists.txt libirccd/irccd/daemon/service/transport_service.cpp libirccd/irccd/daemon/transport_util.cpp libirccd/irccd/daemon/transport_util.hpp
diffstat 4 files changed, 250 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/libirccd/CMakeLists.txt	Sat Mar 17 19:29:42 2018 +0100
+++ b/libirccd/CMakeLists.txt	Mon Mar 19 13:26:53 2018 +0100
@@ -69,6 +69,7 @@
     ${libirccd_SOURCE_DIR}/irccd/daemon/service/transport_service.hpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/transport_client.hpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/transport_server.hpp
+    ${libirccd_SOURCE_DIR}/irccd/daemon/transport_util.hpp
     $<$<BOOL:${HAVE_SSL}>:${libirccd_SOURCE_DIR}/irccd/daemon/tls_transport_server.hpp>
 )
 
@@ -115,6 +116,7 @@
     ${libirccd_SOURCE_DIR}/irccd/daemon/service/transport_service.cpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/transport_client.cpp
     ${libirccd_SOURCE_DIR}/irccd/daemon/transport_server.cpp
+    ${libirccd_SOURCE_DIR}/irccd/daemon/transport_util.cpp
     $<$<BOOL:${HAVE_SSL}>:${libirccd_SOURCE_DIR}/irccd/daemon/tls_transport_server.cpp>
 )
 
--- a/libirccd/irccd/daemon/service/transport_service.cpp	Sat Mar 17 19:29:42 2018 +0100
+++ b/libirccd/irccd/daemon/service/transport_service.cpp	Mon Mar 19 13:26:53 2018 +0100
@@ -20,164 +20,19 @@
 
 #include <cassert>
 
-#include <irccd/string_util.hpp>
-
 #include <irccd/daemon/command.hpp>
 #include <irccd/daemon/ip_transport_server.hpp>
 #include <irccd/daemon/irccd.hpp>
 #include <irccd/daemon/logger.hpp>
+#include <irccd/daemon/transport_util.hpp>
 #include <irccd/daemon/transport_client.hpp>
 
-#include <irccd/daemon/service/transport_service.hpp>
-
-#if !defined(IRCCD_SYSTEM_WINDOWS)
-#   include <irccd/daemon/local_transport_server.hpp>
-#endif
-
-#if defined(HAVE_SSL)
-#   include <irccd/daemon/tls_transport_server.hpp>
-#endif
+#include "transport_service.hpp"
 
 namespace irccd {
 
 namespace {
 
-std::unique_ptr<transport_server> load_transport_ip(boost::asio::io_service& service, const ini::section& sc)
-{
-    assert(sc.key() == "transport");
-
-    std::unique_ptr<transport_server> transport;
-    ini::section::const_iterator it;
-
-    // Port.
-    if ((it = sc.find("port")) == sc.cend())
-        throw std::invalid_argument("missing 'port' parameter");
-
-    auto port = string_util::to_uint<std::uint16_t>(it->value());
-
-    // Address.
-    std::string address = "*";
-
-    if ((it = sc.find("address")) != sc.end())
-        address = it->value();
-
-    // 0011
-    //    ^ define IPv4
-    //   ^  define IPv6
-    auto mode = 1U;
-
-    /*
-     * Documentation stated family but code checked for 'domain' option.
-     *
-     * As irccdctl uses domain, accept both and unify the option name to 'family'.
-     *
-     * See #637
-     */
-    if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) {
-        mode = 0U;
-
-        for (const auto& v : *it) {
-            if (v == "ipv4")
-                mode |= (1U << 0);
-            if (v == "ipv6")
-                mode |= (1U << 1);
-        }
-    }
-
-    if (mode == 0U)
-        throw std::invalid_argument("family must at least have ipv4 or ipv6");
-
-    auto protocol = (mode & 0x2U)
-        ? boost::asio::ip::tcp::v4()
-        : boost::asio::ip::tcp::v6();
-
-    // Optional SSL.
-    std::string pkey;
-    std::string cert;
-
-    if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) {
-        if ((it = sc.find("certificate")) == sc.end())
-            throw std::invalid_argument("missing 'certificate' parameter");
-
-        cert = it->value();
-
-        if ((it = sc.find("key")) == sc.end())
-            throw std::invalid_argument("missing 'key' parameter");
-
-        pkey = it->value();
-    }
-
-    auto endpoint = (address == "*")
-        ? boost::asio::ip::tcp::endpoint(protocol, port)
-        : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port);
-
-    boost::asio::ip::tcp::acceptor acceptor(service, endpoint, true);
-
-    if (pkey.empty())
-        return std::make_unique<ip_transport_server>(std::move(acceptor));
-
-#if defined(HAVE_SSL)
-    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
-
-    ctx.use_private_key_file(pkey, 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));
-#else
-    throw std::invalid_argument("SSL disabled");
-#endif
-}
-
-std::unique_ptr<transport_server> load_transport_unix(boost::asio::io_service& service, const ini::section& sc)
-{
-    assert(sc.key() == "transport");
-
-#if !defined(IRCCD_SYSTEM_WINDOWS)
-    using boost::asio::local::stream_protocol;
-
-    ini::section::const_iterator it = sc.find("path");
-
-    if (it == sc.end())
-        throw std::invalid_argument("missing 'path' parameter");
-
-    // Remove the file first.
-    std::remove(it->value().c_str());
-
-    stream_protocol::endpoint endpoint(it->value());
-    stream_protocol::acceptor acceptor(service, std::move(endpoint));
-
-    return std::make_unique<local_transport_server>(std::move(acceptor));
-#else
-    (void)service;
-    (void)sc;
-
-    throw std::invalid_argument("unix transports not supported on on this platform");
-#endif
-}
-
-std::unique_ptr<transport_server> load_transport(boost::asio::io_service& service, const ini::section& sc)
-{
-    assert(sc.key() == "transport");
-
-    std::unique_ptr<transport_server> transport;
-    ini::section::const_iterator it = sc.find("type");
-
-    if (it == sc.end())
-        throw std::invalid_argument("missing 'type' parameter");
-
-    if (it->value() == "ip")
-        transport = load_transport_ip(service, sc);
-    else if (it->value() == "unix")
-        transport = load_transport_unix(service, sc);
-    else
-        throw std::invalid_argument(string_util::sprintf("invalid type given: %s", it->value()));
-
-    if ((it = sc.find("password")) != sc.end())
-        transport->set_password(it->value());
-
-    return transport;
-}
-
 } // !namespace
 
 void transport_service::handle_command(std::shared_ptr<transport_client> tc, const nlohmann::json& object)
@@ -275,7 +130,7 @@
             continue;
 
         try {
-            add(load_transport(irccd_.service(), section));
+            add(transport_util::from_config(irccd_.service(), section));
         } catch (const std::exception& ex) {
             irccd_.log().warning() << "transport: " << ex.what() << std::endl;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd/irccd/daemon/transport_util.cpp	Mon Mar 19 13:26:53 2018 +0100
@@ -0,0 +1,185 @@
+/*
+ * transport_util.cpp -- transport utilities
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <irccd/sysconfig.hpp>
+
+#include <cassert>
+
+#include <irccd/ini.hpp>
+#include <irccd/string_util.hpp>
+
+#if !defined(IRCCD_SYSTEM_WINDOWS)
+#   include <irccd/daemon/local_transport_server.hpp>
+#endif
+
+#if defined(HAVE_SSL)
+#   include <irccd/daemon/tls_transport_server.hpp>
+#endif
+
+#include "transport_util.hpp"
+
+namespace irccd {
+
+namespace transport_util {
+
+namespace {
+
+std::unique_ptr<transport_server> load_transport_ip(boost::asio::io_service& service,
+                                                    const ini::section& sc)
+{
+    assert(sc.key() == "transport");
+
+    std::unique_ptr<transport_server> transport;
+    ini::section::const_iterator it;
+
+    // Port.
+    if ((it = sc.find("port")) == sc.cend())
+        throw std::invalid_argument("missing 'port' parameter");
+
+    auto port = string_util::to_uint<std::uint16_t>(it->value());
+
+    // Address.
+    std::string address = "*";
+
+    if ((it = sc.find("address")) != sc.end())
+        address = it->value();
+
+    // 0011
+    //    ^ define IPv4
+    //   ^  define IPv6
+    auto mode = 1U;
+
+    /*
+     * Documentation stated family but code checked for 'domain' option.
+     *
+     * As irccdctl uses domain, accept both and unify the option name to 'family'.
+     *
+     * See #637
+     */
+    if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) {
+        mode = 0U;
+
+        for (const auto& v : *it) {
+            if (v == "ipv4")
+                mode |= (1U << 0);
+            if (v == "ipv6")
+                mode |= (1U << 1);
+        }
+    }
+
+    if (mode == 0U)
+        throw std::invalid_argument("family must at least have ipv4 or ipv6");
+
+    auto protocol = (mode & 0x2U)
+        ? boost::asio::ip::tcp::v4()
+        : boost::asio::ip::tcp::v6();
+
+    // Optional SSL.
+    std::string pkey;
+    std::string cert;
+
+    if ((it = sc.find("ssl")) != sc.end() && string_util::is_boolean(it->value())) {
+        if ((it = sc.find("certificate")) == sc.end())
+            throw std::invalid_argument("missing 'certificate' parameter");
+
+        cert = it->value();
+
+        if ((it = sc.find("key")) == sc.end())
+            throw std::invalid_argument("missing 'key' parameter");
+
+        pkey = it->value();
+    }
+
+    auto endpoint = (address == "*")
+        ? boost::asio::ip::tcp::endpoint(protocol, port)
+        : boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port);
+
+    boost::asio::ip::tcp::acceptor acceptor(service, endpoint, true);
+
+    if (pkey.empty())
+        return std::make_unique<ip_transport_server>(std::move(acceptor));
+
+#if defined(HAVE_SSL)
+    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
+
+    ctx.use_private_key_file(pkey, 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));
+#else
+    throw std::invalid_argument("SSL disabled");
+#endif
+}
+
+std::unique_ptr<transport_server> load_transport_unix(boost::asio::io_service& service,
+                                                      const ini::section& sc)
+{
+    assert(sc.key() == "transport");
+
+#if !defined(IRCCD_SYSTEM_WINDOWS)
+    using boost::asio::local::stream_protocol;
+
+    ini::section::const_iterator it = sc.find("path");
+
+    if (it == sc.end())
+        throw std::invalid_argument("missing 'path' parameter");
+
+    // Remove the file first.
+    std::remove(it->value().c_str());
+
+    stream_protocol::endpoint endpoint(it->value());
+    stream_protocol::acceptor acceptor(service, std::move(endpoint));
+
+    return std::make_unique<local_transport_server>(std::move(acceptor));
+#else
+    (void)service;
+    (void)sc;
+
+    throw std::invalid_argument("unix transports not supported on on this platform");
+#endif
+}
+
+} // !namespace
+
+std::unique_ptr<transport_server> from_config(boost::asio::io_service& service, const ini::section& sc)
+{
+    assert(sc.key() == "transport");
+
+    std::unique_ptr<transport_server> transport;
+    ini::section::const_iterator it = sc.find("type");
+
+    if (it == sc.end())
+        throw std::invalid_argument("missing 'type' parameter");
+
+    if (it->value() == "ip")
+        transport = load_transport_ip(service, sc);
+    else if (it->value() == "unix")
+        transport = load_transport_unix(service, sc);
+    else
+        throw std::invalid_argument(string_util::sprintf("invalid type given: %s", it->value()));
+
+
+    if ((it = sc.find("password")) != sc.end())
+        transport->set_password(it->value());
+
+    return transport;
+}
+
+} // !transport_util
+
+} // !irccd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libirccd/irccd/daemon/transport_util.hpp	Mon Mar 19 13:26:53 2018 +0100
@@ -0,0 +1,60 @@
+/*
+ * transport_util.hpp -- transport utilities
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IRCCD_DAEMON_TRANSPORT_UTIL_HPP
+#define IRCCD_DAEMON_TRANSPORT_UTIL_HPP
+
+/*
+ * \file transport_util.hpp
+ * \brief Transport utilities.
+ */
+
+#include <memory>
+
+#include <boost/asio/io_service.hpp>
+
+namespace irccd {
+
+class transport_server;
+
+namespace ini {
+
+class section;
+
+} // !ini
+
+/*
+ * \brief Transport utilities.
+ */
+namespace transport_util {
+
+/**
+ * Load a transport from a [transport] configuration section.
+ *
+ * \param service the IO service
+ * \param sc the configuration
+ * \return the transport
+ */
+std::unique_ptr<transport_server> from_config(boost::asio::io_service& service,
+                                              const ini::section& sc);
+
+} // !transport_util
+
+} // !irccd
+
+#endif // !IRCCD_DAEMON_TRANSPORT_UTIL_HPP