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).
- The `mcast` and `ucast` operators now stop calling `on_next` immediately when
disposed.
- Actors no longer terminate despite having open streams (#1377).
<<<<<<< HEAD
- 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
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).
- 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
`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
......
......@@ -80,6 +80,13 @@ public:
const array_type& data() const noexcept {
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 -------------------------------------------------------------
......
......@@ -99,6 +99,14 @@ public:
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 -------------------------------------------------------------
template <class Inspector>
......
......@@ -63,6 +63,16 @@ bool ipv4_address::is_multicast() const noexcept {
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 ---------------------------------------------------
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 {
: 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 ---------------------------------------------------
namespace {
......
......@@ -187,8 +187,8 @@ std::vector<ip_address> local_addresses(std::string_view host) {
for_each_adapter(
[&](std::string_view, ip_address ip) { results.push_back(ip); });
} else if (host == localhost) {
auto v6_local = ip_address{{0}, {0x1}};
auto v4_local = ip_address{make_ipv4_address(127, 0, 0, 1)};
auto v6_local = ip_address::loopback();
auto v4_local = ip_address{ipv4_address::loopback()};
for_each_adapter([&](std::string_view, ip_address ip) {
if (ip == v4_local || ip == v6_local)
results.push_back(ip);
......@@ -205,10 +205,8 @@ std::vector<ip_address> local_addresses(std::string_view host) {
}
std::vector<ip_address> local_addresses(ip_address host) {
static auto v6_any = ip_address{{0}, {0}};
static auto v4_any = ip_address{make_ipv4_address(0, 0, 0, 0)};
if (host == v4_any || host == v6_any)
return resolve("");
if (host == ipv6_address::any() || host == ipv4_address::any())
return {host};
auto link_local = ip_address({0xfe, 0x8, 0x0, 0x0}, {0x0, 0x0, 0x0, 0x0});
auto ll_prefix = ip_subnet(link_local, 10);
// 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,
expected<tcp_accept_socket> make_tcp_accept_socket(ip_endpoint node,
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());
bool is_v4 = node.address().embeds_v4();
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,
expected<tcp_accept_socket>
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))
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);
if (addrs.empty())
return make_error(sec::cannot_open_port, "no local interface available",
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) {
if (auto sock = make_tcp_accept_socket(ip_endpoint{addr, node.port},
reuse_addr))
......@@ -124,6 +141,7 @@ make_tcp_accept_socket(const uri::authority_type& node, bool reuse_addr) {
expected<tcp_accept_socket>
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;
auth.port = port;
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