Commit ed3ec1b9 authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/neverlord/inaddr-any'

parents 5d4349fa 58262f50
...@@ -45,6 +45,7 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -45,6 +45,7 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- The `mcast` and `ucast` operators now stop calling `on_next` immediately when - The `mcast` and `ucast` operators now stop calling `on_next` immediately when
disposed. disposed.
- Actors no longer terminate despite having open streams (#1377). - Actors no longer terminate despite having open streams (#1377).
<<<<<<< HEAD
- Actors reading from external sources such as SPSC buffers via a local flow - Actors reading from external sources such as SPSC buffers via a local flow
could end up in a long-running read loop. To avoid potentially starving other could end up in a long-running read loop. To avoid potentially starving other
actors or activities, scheduled actors now limit the amount of actions that actors or activities, scheduled actors now limit the amount of actions that
...@@ -52,6 +53,10 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -52,6 +53,10 @@ is based on [Keep a Changelog](https://keepachangelog.com).
- Destroying a consumer or producer resource before opening it lead to a stall - Destroying a consumer or producer resource before opening it lead to a stall
of the consumer / producer. The buffer now keeps track of whether `close` or of the consumer / producer. The buffer now keeps track of whether `close` or
`abort` were called prior to consumers or producers attaching. `abort` were called prior to consumers or producers attaching.
- The function `caf::net::make_tcp_accept_socket` now handles passing `0.0.0.0`
correctly by opening the socket in IPv4 mode. Passing an empty bind address
now defaults to `INADDR6_ANY` (but allowing IPv4 clients) with `INADDR_ANY` as
fallback in case opening the socket in IPv6 mode failed.
### Deprecated ### Deprecated
......
...@@ -80,6 +80,13 @@ public: ...@@ -80,6 +80,13 @@ public:
const array_type& data() const noexcept { const array_type& data() const noexcept {
return bytes_; return bytes_;
} }
// -- factories --------------------------------------------------------------
/// Returns `INADDR_ANY`, i.e., `0.0.0.0`.
static ipv4_address any() noexcept;
/// Returns `INADDR_LOOPBACK`, i.e., `127.0.0.1`.
static ipv4_address loopback() noexcept;
// -- comparison ------------------------------------------------------------- // -- comparison -------------------------------------------------------------
......
...@@ -99,6 +99,14 @@ public: ...@@ -99,6 +99,14 @@ public:
return half_segments_[0] == 0 && half_segments_[1] == 0; return half_segments_[0] == 0 && half_segments_[1] == 0;
} }
// -- factories --------------------------------------------------------------
/// Returns `INADDR6_ANY`, i.e., `::`.
static ipv6_address any() noexcept;
/// Returns `INADDR6_LOOPBACK`, i.e., `::1`.
static ipv6_address loopback() noexcept;
// -- inspection ------------------------------------------------------------- // -- inspection -------------------------------------------------------------
template <class Inspector> template <class Inspector>
......
...@@ -63,6 +63,16 @@ bool ipv4_address::is_multicast() const noexcept { ...@@ -63,6 +63,16 @@ bool ipv4_address::is_multicast() const noexcept {
return (bits_ & net_order(0xF0000000)) == net_order(0xE0000000); return (bits_ & net_order(0xF0000000)) == net_order(0xE0000000);
} }
// -- factories ----------------------------------------------------------------
ipv4_address ipv4_address::any() noexcept {
return make_ipv4_address(0, 0, 0, 0);
}
ipv4_address ipv4_address::loopback() noexcept {
return make_ipv4_address(127, 0, 0, 1);
}
// -- related free functions --------------------------------------------------- // -- related free functions ---------------------------------------------------
ipv4_address make_ipv4_address(uint8_t oct1, uint8_t oct2, uint8_t oct3, ipv4_address make_ipv4_address(uint8_t oct1, uint8_t oct2, uint8_t oct3,
......
...@@ -135,6 +135,16 @@ bool ipv6_address::is_loopback() const noexcept { ...@@ -135,6 +135,16 @@ bool ipv6_address::is_loopback() const noexcept {
: half_segments_[0] == 0 && half_segments_[1] == net_order_64(1u); : half_segments_[0] == 0 && half_segments_[1] == net_order_64(1u);
} }
// -- factories ----------------------------------------------------------------
ipv6_address ipv6_address::any() noexcept {
return ip_address{{0}, {0}};
}
ipv6_address ipv6_address::loopback() noexcept {
return ip_address{{0}, {0x1}};
}
// -- related free functions --------------------------------------------------- // -- related free functions ---------------------------------------------------
namespace { namespace {
......
...@@ -187,8 +187,8 @@ std::vector<ip_address> local_addresses(std::string_view host) { ...@@ -187,8 +187,8 @@ std::vector<ip_address> local_addresses(std::string_view host) {
for_each_adapter( for_each_adapter(
[&](std::string_view, ip_address ip) { results.push_back(ip); }); [&](std::string_view, ip_address ip) { results.push_back(ip); });
} else if (host == localhost) { } else if (host == localhost) {
auto v6_local = ip_address{{0}, {0x1}}; auto v6_local = ip_address::loopback();
auto v4_local = ip_address{make_ipv4_address(127, 0, 0, 1)}; auto v4_local = ip_address{ipv4_address::loopback()};
for_each_adapter([&](std::string_view, ip_address ip) { for_each_adapter([&](std::string_view, ip_address ip) {
if (ip == v4_local || ip == v6_local) if (ip == v4_local || ip == v6_local)
results.push_back(ip); results.push_back(ip);
...@@ -205,10 +205,8 @@ std::vector<ip_address> local_addresses(std::string_view host) { ...@@ -205,10 +205,8 @@ std::vector<ip_address> local_addresses(std::string_view host) {
} }
std::vector<ip_address> local_addresses(ip_address host) { std::vector<ip_address> local_addresses(ip_address host) {
static auto v6_any = ip_address{{0}, {0}}; if (host == ipv6_address::any() || host == ipv4_address::any())
static auto v4_any = ip_address{make_ipv4_address(0, 0, 0, 0)}; return {host};
if (host == v4_any || host == v6_any)
return resolve("");
auto link_local = ip_address({0xfe, 0x8, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0}); auto link_local = ip_address({0xfe, 0x8, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0});
auto ll_prefix = ip_subnet(link_local, 10); auto ll_prefix = ip_subnet(link_local, 10);
// Unless explicitly specified we are going to skip link-local addresses. // Unless explicitly specified we are going to skip link-local addresses.
......
...@@ -83,7 +83,7 @@ expected<tcp_accept_socket> new_tcp_acceptor_impl(uint16_t port, ...@@ -83,7 +83,7 @@ expected<tcp_accept_socket> new_tcp_acceptor_impl(uint16_t port,
expected<tcp_accept_socket> make_tcp_accept_socket(ip_endpoint node, expected<tcp_accept_socket> make_tcp_accept_socket(ip_endpoint node,
bool reuse_addr) { bool reuse_addr) {
CAF_LOG_TRACE(CAF_ARG(node)); CAF_LOG_TRACE(CAF_ARG(node) << CAF_ARG(reuse_addr));
auto addr = to_string(node.address()); auto addr = to_string(node.address());
bool is_v4 = node.address().embeds_v4(); bool is_v4 = node.address().embeds_v4();
bool is_zero = is_v4 ? node.address().embedded_v4().bits() == 0 bool is_zero = is_v4 ? node.address().embedded_v4().bits() == 0
...@@ -106,13 +106,30 @@ expected<tcp_accept_socket> make_tcp_accept_socket(ip_endpoint node, ...@@ -106,13 +106,30 @@ expected<tcp_accept_socket> make_tcp_accept_socket(ip_endpoint node,
expected<tcp_accept_socket> expected<tcp_accept_socket>
make_tcp_accept_socket(const uri::authority_type& node, bool reuse_addr) { make_tcp_accept_socket(const uri::authority_type& node, bool reuse_addr) {
CAF_LOG_TRACE(CAF_ARG(node) << CAF_ARG(reuse_addr));
if (auto ip = std::get_if<ip_address>(&node.host)) if (auto ip = std::get_if<ip_address>(&node.host))
return make_tcp_accept_socket(ip_endpoint{*ip, node.port}, reuse_addr); return make_tcp_accept_socket(ip_endpoint{*ip, node.port}, reuse_addr);
auto host = std::get<std::string>(node.host); const auto& host = std::get<std::string>(node.host);
if (host.empty()) {
// For empty strings, try IPv6::any and use IPv4::any as fallback.
auto v6_any = ip_address{{0}, {0}};
auto v4_any = ip_address{make_ipv4_address(0, 0, 0, 0)};
if (auto sock = make_tcp_accept_socket(ip_endpoint{v6_any, node.port},
reuse_addr))
return *sock;
return make_tcp_accept_socket(ip_endpoint{v4_any, node.port}, reuse_addr);
}
auto addrs = ip::local_addresses(host); auto addrs = ip::local_addresses(host);
if (addrs.empty()) if (addrs.empty())
return make_error(sec::cannot_open_port, "no local interface available", return make_error(sec::cannot_open_port, "no local interface available",
to_string(node)); to_string(node));
// Prefer ipv6 addresses.
std::stable_sort(std::begin(addrs), std::end(addrs),
[](const ip_address& lhs, const ip_address& rhs) {
if (lhs.embeds_v4())
return rhs.embeds_v4() ? lhs < rhs : false;
return rhs.embeds_v4() ? true : lhs < rhs;
});
for (auto& addr : addrs) { for (auto& addr : addrs) {
if (auto sock = make_tcp_accept_socket(ip_endpoint{addr, node.port}, if (auto sock = make_tcp_accept_socket(ip_endpoint{addr, node.port},
reuse_addr)) reuse_addr))
...@@ -124,6 +141,7 @@ make_tcp_accept_socket(const uri::authority_type& node, bool reuse_addr) { ...@@ -124,6 +141,7 @@ make_tcp_accept_socket(const uri::authority_type& node, bool reuse_addr) {
expected<tcp_accept_socket> expected<tcp_accept_socket>
make_tcp_accept_socket(uint16_t port, std::string addr, bool reuse_addr) { make_tcp_accept_socket(uint16_t port, std::string addr, bool reuse_addr) {
CAF_LOG_TRACE(CAF_ARG(port) << CAF_ARG(addr) << CAF_ARG(reuse_addr));
uri::authority_type auth; uri::authority_type auth;
auth.port = port; auth.port = port;
auth.host = std::move(addr); auth.host = std::move(addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment