Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/seastar/net/api.hh
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ class network_stack {
public:
virtual ~network_stack() {}
virtual server_socket listen(socket_address sa, listen_options opts) = 0;
// FIXME: local parameter assumes ipv4 for now, fix when adding other AF
// `local` may be of either family; unspecified means the wildcard address
// of the destination's family, with a port the system picks.
future<connected_socket> connect(socket_address sa, socket_address = {}, transport proto = transport::TCP);
virtual ::seastar::socket socket() = 0;

Expand Down
11 changes: 10 additions & 1 deletion include/seastar/net/socket_defs.hh
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ struct ipv4_addr {
ipv4_addr(const std::string &addr, uint16_t port);
// throws if not an ipv4 addr
ipv4_addr(const net::inet_address&, uint16_t);
ipv4_addr(const socket_address &) noexcept;
// throws if the address is IPv6 and not IPv4-mapped
ipv4_addr(const socket_address &);
ipv4_addr(const ::in_addr&, uint16_t = 0) noexcept;

bool is_ip_unspecified() const noexcept {
Expand Down Expand Up @@ -160,6 +161,10 @@ std::ostream& operator<<(std::ostream&, const ipv6_addr&);
inline bool operator==(const ipv4_addr &lhs, const ipv4_addr& rhs) noexcept {
return lhs.ip == rhs.ip && lhs.port == rhs.port;
}

inline bool operator==(const ipv6_addr &lhs, const ipv6_addr& rhs) noexcept {
return lhs.ip == rhs.ip && lhs.port == rhs.port;
}
}

namespace std {
Expand All @@ -172,6 +177,10 @@ struct hash<seastar::ipv4_addr> {
size_t operator()(const seastar::ipv4_addr&) const;
};
template<>
struct hash<seastar::ipv6_addr> {
size_t operator()(const seastar::ipv6_addr&) const;
};
template<>
struct hash<seastar::unix_domain_addr> {
size_t operator()(const seastar::unix_domain_addr&) const;
};
Expand Down
7 changes: 7 additions & 0 deletions src/net/inet_address.cc
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ ::in_port_t seastar::socket_address::port() const noexcept {
bool seastar::socket_address::is_wildcard() const noexcept {
switch (family()) {
case AF_INET: {
// cannot throw: the address is AF_INET here
ipv4_addr addr(*this);
return addr.is_ip_unspecified() && addr.is_port_unspecified();
}
Expand Down Expand Up @@ -432,3 +433,9 @@ size_t std::hash<seastar::ipv4_addr>::operator()(const seastar::ipv4_addr& x) co
boost::hash_combine(h, x.port);
return h;
}

size_t std::hash<seastar::ipv6_addr>::operator()(const seastar::ipv6_addr& x) const {
size_t h = boost::hash_range(x.ip.begin(), x.ip.end());
boost::hash_combine(h, x.port);
return h;
}
3 changes: 3 additions & 0 deletions src/net/native-stack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ net::datagram_channel native_network_stack::make_unbound_datagram_channel(sa_fam
}

net::datagram_channel native_network_stack::make_bound_datagram_channel(const socket_address& local) {
if (local.family() != AF_INET && !local.is_unspecified()) {
throw std::runtime_error("Unsupported address family");
}
return _inet.get_udp().make_channel(local);
}

Expand Down
2 changes: 1 addition & 1 deletion src/net/net.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ ipv4_addr::ipv4_addr(const net::inet_address& a, uint16_t port)
: ipv4_addr(::in_addr(a), port)
{}

ipv4_addr::ipv4_addr(const socket_address &sa) noexcept
ipv4_addr::ipv4_addr(const socket_address &sa)
: ipv4_addr(sa.addr(), sa.port())
{}

Expand Down
15 changes: 15 additions & 0 deletions tests/unit/ipv6_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,21 @@ SEASTAR_TEST_CASE(dual_stack_listen_test) {
}
}

// ipv6_addr compares and hashes like ipv4_addr.
SEASTAR_TEST_CASE(ipv6_addr_value_type_test) {
const ipv6_addr a("2001:db8::1", 9092);
const ipv6_addr same("2001:db8::1", 9092);
const ipv6_addr other_port("2001:db8::1", 9093);
const ipv6_addr other_addr("2001:db8::2", 9092);

BOOST_REQUIRE(a == same);
BOOST_REQUIRE(!(a == other_port));
BOOST_REQUIRE(!(a == other_addr));
BOOST_REQUIRE_EQUAL(std::hash<ipv6_addr>()(a), std::hash<ipv6_addr>()(same));
BOOST_REQUIRE_NE(std::hash<ipv6_addr>()(a), std::hash<ipv6_addr>()(other_port));
return make_ready_future();
}

SEASTAR_TEST_CASE(ipv6_equal_test) {
const uint16_t port{8080};
const uint16_t port2{8088};
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/network_interface_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,19 @@ SEASTAR_TEST_CASE(test_ipv6_addr_string_forms) {
return make_ready_future();
}

// The socket_address -> ipv4_addr conversion is reachable with an address of
// either family (it is implicit), so a non-mapped IPv6 one has to report an
// error rather than terminate the process from a noexcept function.
SEASTAR_TEST_CASE(test_ipv4_addr_from_socket_address) {
BOOST_REQUIRE_EQUAL(ipv4_addr(socket_address(ipv4_addr("10.0.0.1", 9092))).port, 9092);
// IPv4-mapped is an IPv4 address in an IPv6 shape, so it converts
BOOST_REQUIRE_EQUAL(ipv4_addr(socket_address(ipv6_addr("::ffff:10.0.0.1", 9092))),
ipv4_addr("10.0.0.1", 9092));
BOOST_CHECK_THROW(ipv4_addr(socket_address(ipv6_addr("2001:db8::1", 9092))), std::invalid_argument);
BOOST_CHECK_THROW(ipv4_addr(socket_address(ipv6_addr("::1", 0))), std::invalid_argument);
return make_ready_future();
}

SEASTAR_TEST_CASE(test_inet_address_format) {
const std::string tests[] = {
// IPv4 addresses
Expand Down
Loading