# HG changeset patch # User David Demelier # Date 1541944564 -3600 # Node ID 1a6152af08667bd691c2626c93440afaf5876f1d # Parent d42e8415e477ff0a8b78a251ee74161aeb599f62 misc: use ipv4 as option rather than family Now, all sections and JSON options that require a IP family will take ipv4 and ipv6 boolean options for convenience. It reduces parsing complexity and is more convenient for the user. Examples: # IPv6 server only [server] name = example port = 6667 hostname = example.org ipv4 = false ipv6 = true # IPv4 transport only [transport] type = ip ipv4 = true ipv6 = false port = 3320 If both options are defined (default everywhere), both protocols will be tried or bound. diff -r d42e8415e477 -r 1a6152af0866 CHANGES.md --- a/CHANGES.md Sun Nov 11 14:53:14 2018 +0100 +++ b/CHANGES.md Sun Nov 11 14:56:04 2018 +0100 @@ -12,7 +12,13 @@ - Irccd no longer supports uid, gid, pid and daemon features (#846), - Sections `[identity]` and `[server]` have been merged (#905), - Local transports support SSL (#939), -- The origin in rule is now first class value (#947). +- The origin in rule is now first class value (#947), +- New option `ipv4` in `[transport]` (#945), +- New option `ipv4` in `[server]` (#945). + +irccdctl: + +- New option `ipv4` in `[connect]` (#945). irccd-test: diff -r d42e8415e477 -r 1a6152af0866 MIGRATING.md --- a/MIGRATING.md Sun Nov 11 14:53:14 2018 +0100 +++ b/MIGRATING.md Sun Nov 11 14:56:04 2018 +0100 @@ -10,7 +10,6 @@ - The option `reconnect-tries` has been removed from `[server]` section, use `auto-reconnect` boolean option instead, -- The option `ipv6` has been removed, use `family` instead, - The option `reconnect-timeout` has been renamed to `auto-reconnect-delay`. - The section `[identity]` has been removed, instead move those values inside each server in their `[server]` section. @@ -37,8 +36,6 @@ - The request `server-mode` command requires a new argument `channel`. - The property `host` in request `server-connect` has been renamed to `hostname`, -- The property `ipv6` in request `server-connect` has been renamed to - `family`, - The request `server-info` sends `hostname` property instead of `host`, - The event `onWhois` sends `hostname` property instead of `host`, @@ -73,9 +70,7 @@ - The object returned in the method `Server.info` now has a `hostname` property instead of `host`. - The property `host` in constructor `Server` has been renamed to - `hostname`, -- The property `ipv6` in constructor `Server` has been renamed to - `family`, + `hostname`. #### Module ElapsedTimer diff -r d42e8415e477 -r 1a6152af0866 irccdctl/main.cpp --- a/irccdctl/main.cpp Sun Nov 11 14:53:14 2018 +0100 +++ b/irccdctl/main.cpp Sun Nov 11 14:56:04 2018 +0100 @@ -79,7 +79,8 @@ * type = "ip" * hostname = "ip or hostname" * port = "port number or service" - * family = "ipv4, ipv6" (Optional, default: ipv4, ipv6) + * ipv4 = try IPv4 (Optional, default: true) + * ipv6 = try IPv6 (Optional, default: true) * ssl = true | false (Optional, default: false) */ auto read_connect_ip(const ini::section& sc) -> std::unique_ptr @@ -89,16 +90,10 @@ bool ipv4 = true; bool ipv6 = true; - if (auto it = sc.find("family"); it != sc.end()) { - ipv4 = ipv6 = false; - - for (auto v : *it) { - if (v == "ipv4") - ipv4 = true; - else if (v == "ipv6") - ipv6 = true; - } - } + if (const auto it = sc.find("ipv4"); it != sc.end()) + ipv4 = string_util::is_boolean(it->get_value()); + if (const auto it = sc.find("ipv6"); it != sc.end()) + ipv6 = string_util::is_boolean(it->get_value()); if (!ipv4 && !ipv6) throw transport_error(transport_error::invalid_family); diff -r d42e8415e477 -r 1a6152af0866 libirccd/irccd/daemon/command.cpp --- a/libirccd/irccd/daemon/command.cpp Sun Nov 11 14:53:14 2018 +0100 +++ b/libirccd/irccd/daemon/command.cpp Sun Nov 11 14:56:04 2018 +0100 @@ -533,6 +533,8 @@ // Optional stuff. if ((server->get_options() & server::options::ipv6) == server::options::ipv6) response.push_back({"ipv6", true}); + if ((server->get_options() & server::options::ipv6) == server::options::ipv6) + response.push_back({"ipv6", true}); if ((server->get_options() & server::options::ssl) == server::options::ssl) response.push_back({"ssl", true}); if ((server->get_options() & server::options::ssl_verify) == server::options::ssl_verify) diff -r d42e8415e477 -r 1a6152af0866 libirccd/irccd/daemon/server_util.cpp --- a/libirccd/irccd/daemon/server_util.cpp Sun Nov 11 14:53:14 2018 +0100 +++ b/libirccd/irccd/daemon/server_util.cpp Sun Nov 11 14:56:04 2018 +0100 @@ -32,6 +32,14 @@ namespace { +void toggle(server& s, server::options opt, bool value) noexcept +{ + if (value) + s.set_options(s.get_options() | opt); + else + s.set_options(s.get_options() & ~(opt)); +} + void from_config_load_identity(server& sv, const ini::section& sc) { const auto username = ini_util::optional_string(sc, "username", sv.get_username()); @@ -71,38 +79,32 @@ void from_config_load_flags(server& sv, const ini::section& sc) { - const auto ssl = sc.get("ssl"); - const auto ssl_verify = sc.get("ssl-verify"); - const auto auto_rejoin = sc.get("auto-rejoin"); - const auto auto_reconnect = sc.get("auto-reconnect"); - const auto join_invite = sc.get("join-invite"); + const auto ssl = sc.find("ssl"); + const auto ssl_verify = sc.find("ssl-verify"); + const auto auto_rejoin = sc.find("auto-rejoin"); + const auto auto_reconnect = sc.find("auto-reconnect"); + const auto join_invite = sc.find("join-invite"); + const auto ipv4 = sc.find("ipv4"); + const auto ipv6 = sc.find("ipv6"); - if (const auto family = sc.find("family"); family != sc.end()) { - sv.set_options(sv.get_options() & ~(server::options::ipv4)); - sv.set_options(sv.get_options() & ~(server::options::ipv6)); - - for (const auto& v : *family) { - if (v == "ipv4") - sv.set_options(sv.get_options() | server::options::ipv4); - if (v == "ipv6") - sv.set_options(sv.get_options() | server::options::ipv6); - } - } + if (ssl != sc.end()) + toggle(sv, server::options::ssl, string_util::is_boolean(ssl->get_value())); + if (ssl_verify != sc.end()) + toggle(sv, server::options::ssl_verify, string_util::is_boolean(ssl_verify->get_value())); + if (auto_rejoin != sc.end()) + toggle(sv, server::options::auto_rejoin, string_util::is_boolean(auto_rejoin->get_value())); + if (auto_reconnect != sc.end()) + toggle(sv, server::options::auto_reconnect, string_util::is_boolean(auto_reconnect->get_value())); + if (join_invite != sc.end()) + toggle(sv, server::options::join_invite, string_util::is_boolean(join_invite->get_value())); + if (ipv4 != sc.end()) + toggle(sv, server::options::ipv4, string_util::is_boolean(ipv4->get_value())); + if (ipv6 != sc.end()) + toggle(sv, server::options::ipv6, string_util::is_boolean(ipv6->get_value())); if ((sv.get_options() & server::options::ipv4) != server::options::ipv4 && (sv.get_options() & server::options::ipv6) != server::options::ipv6) throw server_error(server_error::invalid_family); - - if (string_util::is_boolean(ssl.get_value())) - sv.set_options(sv.get_options() | server::options::ssl); - if (string_util::is_boolean(ssl_verify.get_value())) - sv.set_options(sv.get_options() | server::options::ssl_verify); - if (string_util::is_boolean(auto_rejoin.get_value())) - sv.set_options(sv.get_options() | server::options::auto_rejoin); - if (string_util::is_boolean(auto_reconnect.get_value())) - sv.set_options(sv.get_options() | server::options::auto_reconnect); - if (string_util::is_boolean(join_invite.get_value())) - sv.set_options(sv.get_options() | server::options::join_invite); } void from_config_load_numeric_parameters(server& sv, const ini::section& sc) @@ -132,7 +134,7 @@ sv.set_command_char(command_char); } -void from_json_load_options(server& sv, const deserializer& parser) +void from_json_load_general(server& sv, const deserializer& parser) { const auto port = parser.optional("port", sv.get_port()); const auto nickname = parser.optional("nickname", sv.get_nickname()); @@ -142,25 +144,6 @@ const auto command = parser.optional("commandChar", sv.get_command_char()); const auto password = parser.optional("password", sv.get_password()); - if (const auto family = parser.find("family"); family != parser.end()) { - if (!family->is_array()) - throw server_error(server_error::invalid_family); - - sv.set_options(sv.get_options() & ~(server::options::ipv4)); - sv.set_options(sv.get_options() & ~(server::options::ipv6)); - - for (const auto& v : *family) { - if (v.is_string() && v.get() == "ipv4") - sv.set_options(sv.get_options() | server::options::ipv4); - if (v.is_string() && v.get() == "ipv6") - sv.set_options(sv.get_options() | server::options::ipv6); - } - } - - if ((sv.get_options() & server::options::ipv4) != server::options::ipv4 && - (sv.get_options() & server::options::ipv6) != server::options::ipv6) - throw server_error(server_error::invalid_family); - if (!port || *port > std::numeric_limits::max()) throw server_error(server_error::invalid_port); if (!nickname) @@ -185,12 +168,20 @@ sv.set_password(*password); } -void from_json_load_flags(server& sv, const deserializer& parser) +void from_json_load_options(server& sv, const deserializer& parser) { const auto auto_rejoin = parser.get("autoRejoin"); const auto join_invite = parser.get("joinInvite"); const auto ssl = parser.get("ssl"); const auto ssl_verify = parser.get("sslVerify"); + const auto ipv4 = parser.optional("ipv4", true); + const auto ipv6 = parser.optional("ipv6", true); + + if (!ipv4 || !ipv6) + throw server_error(server_error::invalid_family); + + toggle(sv, server::options::ipv4, *ipv4); + toggle(sv, server::options::ipv6, *ipv6); if (auto_rejoin.value_or(false)) sv.set_options(sv.get_options() | server::options::auto_rejoin); @@ -205,6 +196,11 @@ #endif if (ssl_verify.value_or(false)) sv.set_options(sv.get_options() | server::options::ssl_verify); + + // Verify that at least IPv4 or IPv6 is set. + if ((sv.get_options() & server::options::ipv4) != server::options::ipv4 && + (sv.get_options() & server::options::ipv6) != server::options::ipv6) + throw server_error(server_error::invalid_family); } } // !namespace @@ -263,8 +259,8 @@ const auto sv = std::make_shared(service, *id, *hostname); + from_json_load_general(*sv, parser); from_json_load_options(*sv, parser); - from_json_load_flags(*sv, parser); return sv; } diff -r d42e8415e477 -r 1a6152af0866 libirccd/irccd/daemon/transport_util.cpp --- a/libirccd/irccd/daemon/transport_util.cpp Sun Nov 11 14:53:14 2018 +0100 +++ b/libirccd/irccd/daemon/transport_util.cpp Sun Nov 11 14:56:04 2018 +0100 @@ -35,27 +35,12 @@ auto from_config_load_ip_protocols(const ini::section& sc) -> std::pair { - bool ipv4 = true, ipv6 = false; - - /* - * Documentation stated family but code checked for 'domain' option. - * - * As irccdctl uses domain, accept both and unify the option name to 'family'. - * - * See #637 - */ - ini::section::const_iterator it; + bool ipv4 = true, ipv6 = true; - if ((it = sc.find("domain")) != sc.end() || (it = sc.find("family")) != sc.end()) { - ipv4 = ipv6 = false; - - for (const auto& v : *it) { - if (v == "ipv4") - ipv4 = true; - if (v == "ipv6") - ipv6 = true; - } - } + if (const auto it = sc.find("ipv4"); it != sc.end()) + ipv4 = string_util::is_boolean(it->get_value()); + if (const auto it = sc.find("ipv6"); it != sc.end()) + ipv6 = string_util::is_boolean(it->get_value()); if (!ipv4 && !ipv6) throw transport_error(transport_error::invalid_family); diff -r d42e8415e477 -r 1a6152af0866 tests/src/libirccd/command-server-connect/main.cpp --- a/tests/src/libirccd/command-server-connect/main.cpp Sun Nov 11 14:53:14 2018 +0100 +++ b/tests/src/libirccd/command-server-connect/main.cpp Sun Nov 11 14:56:04 2018 +0100 @@ -51,21 +51,22 @@ BOOST_AUTO_TEST_CASE(full) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "local2" }, - { "hostname", "irc.example2.org" }, - { "password", "nonono" }, - { "nickname", "francis" }, - { "realname", "the_francis" }, - { "username", "frc" }, - { "family", { "ipv6" } }, - { "ctcpVersion", "ultra bot" }, - { "commandChar", "::" }, - { "port", 18000 }, - { "ssl", true }, - { "sslVerify", true }, - { "autoRejoin", true }, - { "joinInvite", true } + { "command", "server-connect" }, + { "name", "local2" }, + { "hostname", "irc.example2.org" }, + { "password", "nonono" }, + { "nickname", "francis" }, + { "realname", "the_francis" }, + { "username", "frc" }, + { "ipv4", false }, + { "ipv6", true }, + { "ctcpVersion", "ultra bot" }, + { "commandChar", "::" }, + { "port", 18000 }, + { "ssl", true }, + { "sslVerify", true }, + { "autoRejoin", true }, + { "joinInvite", true } }); const auto s = irccd_.servers().get("local2"); @@ -98,9 +99,9 @@ irccd_.servers().add(std::make_unique(ctx_, "local")); const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "local" }, - { "hostname", "127.0.0.1" } + { "command", "server-connect" }, + { "name", "local" }, + { "hostname", "127.0.0.1" } }); BOOST_TEST(code == server_error::already_exists); @@ -111,8 +112,8 @@ BOOST_AUTO_TEST_CASE(invalid_hostname_1) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, + { "command", "server-connect" }, + { "name", "new" }, }); BOOST_TEST(code == server_error::invalid_hostname); @@ -123,9 +124,9 @@ BOOST_AUTO_TEST_CASE(invalid_hostname_2) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", 123456 } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", 123456 } }); BOOST_TEST(code == server_error::invalid_hostname); @@ -136,9 +137,9 @@ BOOST_AUTO_TEST_CASE(invalid_identifier_1) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "" }, - { "hostname", "127.0.0.1" } + { "command", "server-connect" }, + { "name", "" }, + { "hostname", "127.0.0.1" } }); BOOST_TEST(code == server_error::invalid_identifier); @@ -149,9 +150,9 @@ BOOST_AUTO_TEST_CASE(invalid_identifier_2) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", 123456 }, - { "hostname", "127.0.0.1" } + { "command", "server-connect" }, + { "name", 123456 }, + { "hostname", "127.0.0.1" } }); BOOST_TEST(code == server_error::invalid_identifier); @@ -162,10 +163,10 @@ BOOST_AUTO_TEST_CASE(invalid_port_1) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "port", "notaint" } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "port", "notaint" } }); BOOST_TEST(code == server_error::invalid_port); @@ -176,10 +177,10 @@ BOOST_AUTO_TEST_CASE(invalid_port_2) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "port", -123 } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "port", -123 } }); BOOST_TEST(code == server_error::invalid_port); @@ -190,10 +191,10 @@ BOOST_AUTO_TEST_CASE(invalid_port_3) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "port", 1000000 } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "port", 1000000 } }); BOOST_TEST(code == server_error::invalid_port); @@ -206,10 +207,10 @@ BOOST_AUTO_TEST_CASE(ssl_disabled) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "ssl", true } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "ssl", true } }); BOOST_TEST(code == server_error::ssl_disabled); @@ -222,11 +223,11 @@ BOOST_AUTO_TEST_CASE(invalid_family_1) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "port", 1000000 }, - { "family", "invalid" } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "port", 6667 }, + { "ipv4", "invalid" } }); BOOST_TEST(code == server_error::invalid_family); @@ -237,11 +238,11 @@ BOOST_AUTO_TEST_CASE(invalid_family_2) { const auto [json, code] = request({ - { "command", "server-connect" }, - { "name", "new" }, - { "hostname", "127.0.0.1" }, - { "port", 1000000 }, - { "family", { 123, 456 } } + { "command", "server-connect" }, + { "name", "new" }, + { "hostname", "127.0.0.1" }, + { "port", 6667 }, + { "ipv6", 1234 } }); BOOST_TEST(code == server_error::invalid_family);