changeset 871:de55ae9a8839

sock: add sockaddr_{ntop,cmp,copy} helpers and a sockaddr_union For now, it only supports AF_INET and AF_INET6. That should be enough for most things, but it is likely only a matter of time before AF_UNIX crops up. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Wed, 14 Feb 2024 09:54:10 -0500
parents 7ecf3aed80fc
children a3965185623f
files include/jeffpc/sock.h mapfile-vers sock.c
diffstat 3 files changed, 92 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/include/jeffpc/sock.h	Wed Jan 31 23:41:07 2024 -0500
+++ b/include/jeffpc/sock.h	Wed Feb 14 09:54:10 2024 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * Copyright (c) 2016-2019,2024 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -25,13 +25,33 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
 
 #include <jeffpc/error.h>
 
+/* a union of all the different socket address structs */
+union xsockaddr {
+	struct sockaddr sa;
+	struct sockaddr_in inet;
+	struct sockaddr_in6 inet6;
+};
+
+/* max length (with trailing nul) generated by xsockaddr_ntop */
+#define XSOCKADDR_STRLEN	(MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1)
+
 enum ip_type {
 	IP_TCP,
 };
 
+/*
+ * socket address helpers
+ */
+extern const char *xsockaddr_ntop(const struct sockaddr *sa, char *str,
+				  size_t strlen);
+extern bool xsockaddr_cmp(struct sockaddr *sa1, struct sockaddr *sa2);
+extern void xsockaddr_copy(union xsockaddr *u, struct sockaddr *sa);
+
 extern int connect_ip(const char *host, uint16_t port, bool v4, bool v6,
 		      enum ip_type type);
 
--- a/mapfile-vers	Wed Jan 31 23:41:07 2024 -0500
+++ b/mapfile-vers	Wed Feb 14 09:54:10 2024 -0500
@@ -255,6 +255,9 @@
 		# sock
 		connect_ip;
 		xgethostname;
+		xsockaddr_cmp;
+		xsockaddr_copy;
+		xsockaddr_ntop;
 
 		# socksvc
 		socksvc;
--- a/sock.c	Wed Jan 31 23:41:07 2024 -0500
+++ b/sock.c	Wed Feb 14 09:54:10 2024 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+ * Copyright (c) 2016-2020,2024 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -23,6 +23,7 @@
 #include <sys/socket.h>
 #include <netdb.h>
 #include <unistd.h>
+#include <arpa/inet.h>
 
 #include <jeffpc/sock.h>
 #include <jeffpc/atomic.h>
@@ -152,3 +153,69 @@
 
 	return sock;
 }
+
+const char *xsockaddr_ntop(const struct sockaddr *sa, char *str, size_t strlen)
+{
+	const union xsockaddr *u = (const union xsockaddr *) sa;
+
+	switch (u->sa.sa_family) {
+		case AF_INET:
+			return inet_ntop(AF_INET, &u->inet.sin_addr, str,
+					 strlen);
+		case AF_INET6:
+			return inet_ntop(AF_INET6, &u->inet6.sin6_addr, str,
+					 strlen);
+	}
+
+	panic("Unknown address family %d", u->sa.sa_family);
+}
+
+bool xsockaddr_cmp(struct sockaddr *sa1, struct sockaddr *sa2)
+{
+	if (sa1->sa_family != sa2->sa_family)
+		return false;
+
+	/*
+	 * NOTE: Some systems (e.g., FreeBSD) have sa_len which we could
+	 * sanity check, but other systems (e.g., Linux) do not have it.  We
+	 * could work around this with conditional compilation, but that's
+	 * too much effort with no obvious benefit.  So, just imagine that
+	 * we assert here that sa1->sa_len == sa2->sa_len.
+	 */
+
+	switch (sa1->sa_family) {
+		case AF_INET: {
+			struct sockaddr_in *in1 = (struct sockaddr_in *) sa1;
+			struct sockaddr_in *in2 = (struct sockaddr_in *) sa2;
+
+			return in1->sin_addr.s_addr == in2->sin_addr.s_addr;
+		}
+		case AF_INET6: {
+			struct sockaddr_in6 *in1 = (struct sockaddr_in6 *) sa1;
+			struct sockaddr_in6 *in2 = (struct sockaddr_in6 *) sa2;
+
+			return IN6_ARE_ADDR_EQUAL(&in1->sin6_addr,
+						  &in2->sin6_addr);
+		}
+	}
+
+	panic("Unknown address family %d", sa1->sa_family);
+}
+
+void xsockaddr_copy(union xsockaddr *u, struct sockaddr *sa)
+{
+	size_t len;
+
+	switch (sa->sa_family) {
+		case AF_INET:
+			len = sizeof(u->inet);
+			break;
+		case AF_INET6:
+			len = sizeof(u->inet6);
+			break;
+		default:
+			panic("Unknown address family %d", sa->sa_family);
+	}
+
+	memcpy(u, sa, len);
+}