From e114258821760cd1b550fc86bf3657b1f9af62f2 Mon Sep 17 00:00:00 2001 From: Benny Baumann <BenBE@geshi.org> Date: Sun, 3 Jan 2021 16:27:46 +0100 Subject: [PATCH] add: sockaddr handling --- src/net/socketaddress.hpp | 134 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/net/socketaddress.hpp diff --git a/src/net/socketaddress.hpp b/src/net/socketaddress.hpp new file mode 100644 index 0000000..7a32f28 --- /dev/null +++ b/src/net/socketaddress.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> + +#include <functional> + +#include "net/netio_exception.hpp" + +#ifdef __linux__ +#include <linux/netlink.h> +#endif + +namespace rmrf::net { + +template <typename T> +struct family_map {}; + +template <> +struct family_map<sockaddr_in> { + static constexpr int sa_family = AF_INET; + static constexpr auto sa_family_field = &sockaddr_in::sin_family; +}; + +template <> +struct family_map<sockaddr_in6> { + static constexpr int sa_family = AF_INET6; + static constexpr auto sa_family_field = &sockaddr_in6::sin6_family; +}; + +template <> +struct family_map<sockaddr_un> { + static constexpr int sa_family = AF_UNIX; + static constexpr auto sa_family_field = &sockaddr_un::sun_family; +}; + +template <> +struct family_map<sockaddr_nl> { + static constexpr int sa_family = AF_NETLINK; + static constexpr auto sa_family_field = &sockaddr_nl::nl_family; +}; + +template <typename, typename = void> +struct has_field : std::false_type {}; + +template <typename T> +struct has_field<T, std::void_t<decltype(family_map<T>::sa_family)>> : std::is_convertible<decltype(family_map<T>::sa_family), int> {}; + +class socketaddr { +private: + sockaddr_storage addr; + socklen_t len; + +public: + socketaddr(); + + template <typename T, typename std::enable_if<has_field<T>::value, T>::type * = nullptr> + explicit socketaddr(T *other) : addr{}, len{} { + if (other->*(family_map<T>::sa_family_field) != family_map<T>::sa_family) { + throw netio_exception("Address family mismatch in sockaddr structure."); + } + + memcpy(&addr, other, sizeof(T)); + len = sizeof(T); + } + + template <typename T, typename std::enable_if<has_field<T>::value, T>::type * = nullptr> + explicit socketaddr(const T& other) : addr{}, len{} { + if (other.*(family_map<T>::sa_family_field) != family_map<T>::sa_family) { + throw netio_exception("Address family mismatch in sockaddr structure."); + } + + memcpy(&addr, &other, sizeof(T)); + len = sizeof(T); + } + + template <typename T> + socketaddr &operator=(T *rhs) { + if (rhs->*(family_map<T>::sa_family_field) != family_map<T>::sa_family) { + throw netio_exception("Address family mismatch in sockaddr structure."); + } + + memcpy(&addr, rhs, sizeof(T)); + len = sizeof(T); + } + + socketaddr &operator=(sockaddr_storage *rhs) { + return *this = (sockaddr*)rhs; + } + + socketaddr& operator=(sockaddr *rhs) { + switch(rhs->sa_family) { + case AF_INET: + return *this = (sockaddr_in *)rhs; + case AF_INET6: + return *this = (sockaddr_in6 *)rhs; + case AF_UNIX: + return *this = (sockaddr_un *)rhs; + case AF_NETLINK: + return *this = (sockaddr_nl *)rhs; + default: + throw netio_exception("Trying to assign unknown address family"); + } + }; + + int family() const { + return addr.ss_family; + } + + template <typename T> + operator T*() const { + if (addr.ss_family != family_map<T>::sa_family) { + throw netio_exception("Cannot convert address family of stored sockaddr structure."); + } + + return (T*)&addr; + } + + sockaddr* ptr() const { + return (sockaddr*)&addr; + } + + socklen_t size() const { + return len; + } + +}; + +} -- GitLab