net/addr/sock: SockAddrBuf -> SockAddr conversion
This makes it trivial to convert buffers from the kernel into sockaddrs
that can be manipulated and printed.
Change-Id: I13f4998e5f33bae4a8af03ea3c2243254010a0b4
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/stdplus/net/addr/sock.hpp b/include/stdplus/net/addr/sock.hpp
index 970fbd2..73b4edf 100644
--- a/include/stdplus/net/addr/sock.hpp
+++ b/include/stdplus/net/addr/sock.hpp
@@ -16,6 +16,11 @@
namespace stdplus
{
+namespace detail
+{
+struct SockAddrUnsafe
+{};
+} // namespace detail
struct SockAddrBuf
{
@@ -60,6 +65,26 @@
In4Addr addr;
std::uint16_t port;
+ static constexpr Sock4Addr fromBuf(const SockAddrBuf& buf)
+ {
+ if (buf.fam != AF_INET)
+ {
+ throw std::invalid_argument("Sock4Addr fromBuf");
+ }
+ return fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ static constexpr Sock4Addr fromBuf(detail::SockAddrUnsafe,
+ const SockAddrBuf& buf)
+ {
+ if (buf.len != sizeof(sockaddr_in))
+ {
+ throw std::invalid_argument("Sock4Addr fromBuf");
+ }
+ const auto& sin = reinterpret_cast<const sockaddr_in&>(buf);
+ return Sock4Addr{.addr = sin.sin_addr,
+ .port = stdplus::ntoh(sin.sin_port)};
+ }
+
constexpr bool operator==(Sock4Addr rhs) const noexcept
{
return addr == rhs.addr && port == rhs.port;
@@ -105,6 +130,27 @@
std::uint16_t port;
std::uint32_t scope;
+ static constexpr Sock6Addr fromBuf(const SockAddrBuf& buf)
+ {
+ if (buf.fam != AF_INET6)
+ {
+ throw std::invalid_argument("Sock6Addr fromBuf");
+ }
+ return fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ static constexpr Sock6Addr fromBuf(detail::SockAddrUnsafe,
+ const SockAddrBuf& buf)
+ {
+ if (buf.len != sizeof(sockaddr_in6))
+ {
+ throw std::invalid_argument("Sock6Addr fromBuf");
+ }
+ const auto& sin6 = reinterpret_cast<const sockaddr_in6&>(buf);
+ return Sock6Addr{.addr = sin6.sin6_addr,
+ .port = stdplus::ntoh(sin6.sin6_port),
+ .scope = sin6.sin6_scope_id};
+ }
+
constexpr bool operator==(Sock6Addr rhs) const noexcept
{
return addr == rhs.addr && port == rhs.port && scope == rhs.scope;
@@ -170,6 +216,41 @@
std::copy(path.begin() + 1, path.end(), buf_.begin() + 1);
}
+ constexpr SockUAddr(detail::SockAddrUnsafe, std::string_view path) noexcept
+ {
+ if (path.empty())
+ {
+ len_ = 0;
+ return;
+ }
+ bool abstract = path[0] == '\0';
+ // Abstract sockets are not null terminated but path sockets are
+ len_ = path.size() - (abstract ? 0 : 1);
+ buf_[0] = abstract ? '@' : path[0];
+ std::copy_n(path.begin() + 1, len_ - 1, buf_.begin() + 1);
+ }
+
+ static constexpr SockUAddr fromBuf(const SockAddrBuf& buf)
+ {
+ if (buf.fam != AF_UNIX)
+ {
+ throw std::invalid_argument("SockUAddr fromBuf");
+ }
+ return fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ static constexpr SockUAddr fromBuf(detail::SockAddrUnsafe,
+ const SockAddrBuf& buf)
+ {
+ if (buf.len < sizeof(sockaddr_un{}.sun_family))
+ {
+ throw std::invalid_argument("SockUAddr fromBuf");
+ }
+ const auto& sun = reinterpret_cast<const sockaddr_un&>(buf);
+ return SockUAddr{
+ detail::SockAddrUnsafe(),
+ {sun.sun_path, buf.len - offsetof(sockaddr_un, sun_path)}};
+ }
+
constexpr bool operator==(const SockUAddr& rhs) const noexcept
{
return path() == rhs.path();
@@ -288,6 +369,19 @@
constexpr SockInAddr(Sock6Addr a) noexcept :
detail::SockAnyAddr<detail::SockInAddrV>(a)
{}
+
+ static constexpr SockInAddr fromBuf(const SockAddrBuf& buf)
+ {
+ if (buf.fam == AF_INET)
+ {
+ return Sock4Addr::fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ else if (buf.fam == AF_INET6)
+ {
+ return Sock6Addr::fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ throw std::invalid_argument("Unknown SockInAddr");
+ }
};
template <>
@@ -321,6 +415,23 @@
detail::SockAnyAddr<detail::SockAnyAddrV>(
std::visit([](auto v) { return detail::SockAnyAddrV(v); }, a))
{}
+
+ static constexpr SockAnyAddr fromBuf(const SockAddrBuf& buf)
+ {
+ if (buf.fam == AF_INET)
+ {
+ return Sock4Addr::fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ else if (buf.fam == AF_INET6)
+ {
+ return Sock6Addr::fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ else if (buf.fam == AF_UNIX)
+ {
+ return SockUAddr::fromBuf(detail::SockAddrUnsafe(), buf);
+ }
+ throw std::invalid_argument("Unknown SockInAddr");
+ }
};
template <>
diff --git a/test/net/addr/sock.cpp b/test/net/addr/sock.cpp
index e5ed833..2a7487b 100644
--- a/test/net/addr/sock.cpp
+++ b/test/net/addr/sock.cpp
@@ -28,6 +28,22 @@
EXPECT_EQ(sizeof(sockaddr_in), addr1.sockaddrLen());
}
+TEST(Sock4Addr, FromBuf)
+{
+ SockAddrBuf buf = {};
+ auto& sin = reinterpret_cast<sockaddr_in&>(buf);
+ sin.sin_addr.s_addr = stdplus::hton(std::uint32_t{0xff000000});
+ sin.sin_port = stdplus::hton(std::uint16_t{33});
+ EXPECT_THROW(Sock4Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET;
+ EXPECT_THROW(Sock4Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET6;
+ buf.len = sizeof(sockaddr_in);
+ EXPECT_THROW(Sock4Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET;
+ EXPECT_EQ(Sock4Addr::fromBuf(buf), Sock4Addr(In4Addr{255, 0, 0, 0}, 33));
+}
+
TEST(Sock4Addr, FromStr)
{
constexpr FromStr<Sock4Addr> fs;
@@ -68,6 +84,22 @@
EXPECT_EQ(sizeof(sockaddr_in6), addr1.sockaddrLen());
}
+TEST(Sock6Addr, FromBuf)
+{
+ SockAddrBuf buf = {};
+ auto& sin6 = reinterpret_cast<sockaddr_in6&>(buf);
+ sin6.sin6_addr.s6_addr[0] = 0xff;
+ sin6.sin6_port = stdplus::hton(std::uint16_t{33});
+ EXPECT_THROW(Sock6Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET6;
+ EXPECT_THROW(Sock6Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET;
+ buf.len = sizeof(sockaddr_in6);
+ EXPECT_THROW(Sock6Addr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET6;
+ EXPECT_EQ(Sock6Addr::fromBuf(buf), Sock6Addr(In6Addr{0xff}, 33, 0));
+}
+
TEST(Sock6Addr, FromStr)
{
constexpr FromStr<Sock6Addr> fs;
@@ -134,6 +166,30 @@
EXPECT_EQ(addr4.sockaddrLen(), sizeof(addr.sun_family));
}
+TEST(SockUAddr, FromBuf)
+{
+ SockAddrBuf buf = {};
+ auto& sun = reinterpret_cast<sockaddr_un&>(buf);
+ auto path = "/my-path"sv;
+ std::copy(path.begin(), path.end(), sun.sun_path);
+ EXPECT_THROW(SockUAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_UNIX;
+ EXPECT_THROW(SockUAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET6;
+ buf.len = sizeof(buf.fam) + path.size() + 1;
+ EXPECT_THROW(SockUAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_UNIX;
+ EXPECT_EQ(SockUAddr::fromBuf(buf), SockUAddr(path));
+
+ path = "\0abs-path"sv;
+ std::copy(path.begin(), path.end(), sun.sun_path);
+ buf.len = sizeof(buf.fam) + path.size();
+ EXPECT_EQ(SockUAddr::fromBuf(buf), SockUAddr(path));
+
+ buf.len = sizeof(buf.fam);
+ EXPECT_EQ(SockUAddr::fromBuf(buf), SockUAddr(""));
+}
+
TEST(SockUAddr, FromStr)
{
constexpr FromStr<SockUAddr> fs;
@@ -164,6 +220,23 @@
EXPECT_EQ(addr2.sockaddrLen(), sizeof(sockaddr_in6));
}
+TEST(SockInAddr, FromBuf)
+{
+ SockAddrBuf buf = {};
+ EXPECT_THROW(SockInAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_UNIX;
+ buf.len = sizeof(sockaddr_un);
+ EXPECT_THROW(SockInAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET6;
+ buf.len = sizeof(sockaddr_in);
+ EXPECT_THROW(SockInAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET;
+ EXPECT_EQ(SockInAddr::fromBuf(buf), SockInAddr(In4Addr{}, 0));
+ buf.fam = AF_INET6;
+ buf.len = sizeof(sockaddr_in6);
+ EXPECT_EQ(SockInAddr::fromBuf(buf), SockInAddr(In6Addr{}, 0));
+}
+
TEST(SockInAddr, FromStr)
{
constexpr FromStr<SockInAddr> fs;
@@ -194,6 +267,24 @@
EXPECT_EQ(addr2.sockaddrLen(), sizeof(sa_family_t) + 4);
}
+TEST(SockAnyAddr, FromBuf)
+{
+ SockAddrBuf buf = {};
+ EXPECT_THROW(SockAnyAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_UNIX;
+ EXPECT_THROW(SockInAddr::fromBuf(buf), std::invalid_argument);
+ buf.len = sizeof(sockaddr_un{}.sun_family);
+ EXPECT_EQ(SockAnyAddr::fromBuf(buf), SockAnyAddr(""));
+ buf.fam = AF_INET6;
+ buf.len = sizeof(sockaddr_in);
+ EXPECT_THROW(SockAnyAddr::fromBuf(buf), std::invalid_argument);
+ buf.fam = AF_INET;
+ EXPECT_EQ(SockAnyAddr::fromBuf(buf), SockAnyAddr(In4Addr{}, 0));
+ buf.fam = AF_INET6;
+ buf.len = sizeof(sockaddr_in6);
+ EXPECT_EQ(SockAnyAddr::fromBuf(buf), SockAnyAddr(In6Addr{}, 0));
+}
+
TEST(SockAnyAddr, FromStr)
{
constexpr FromStr<SockAnyAddr> fs;