+union addr {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+
+/* Check whether an address family is even slightly supported. */
+static int addrfamok(int af)
+{
+ switch (af) {
+ case AF_INET: case AF_INET6: return (1);
+ default: return (0);
+ }
+}
+
+/* Return the size of a socket address. */
+static size_t addrsz(const union addr *a)
+{
+ switch (a->sa.sa_family) {
+ case AF_INET: return (sizeof(a->sin));
+ case AF_INET6: return (sizeof(a->sin6));
+ default: abort();
+ }
+}
+
+/* Compare two addresses. Maybe compare the port numbers too. */
+#define AEF_PORT 1u
+static int addreq(const union addr *a, const union addr *b, unsigned f)
+{
+ switch (a->sa.sa_family) {
+ case AF_INET:
+ return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr &&
+ (!(f&AEF_PORT) || a->sin.sin_port == b->sin.sin_port));
+ case AF_INET6:
+ return (!memcmp(a->sin6.sin6_addr.s6_addr,
+ b->sin6.sin6_addr.s6_addr, 16) &&
+ (!(f&AEF_PORT) || a->sin6.sin6_port == b->sin6.sin6_port));
+ default:
+ abort();
+ }
+}
+