Mercurial > irccd
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