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