aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2025-05-11 21:11:09 -0700
committerGarrett D'Amore <garrett@damore.org>2025-05-26 19:08:14 -0700
commit08400bd437149c4fb31af9b2abece2ae44041283 (patch)
tree92e70ad8ffc0e074ea56fe0d062acedbd4245de6
parent5d1254fc3d52d8b7421ca152eed1a79a1a50d37c (diff)
downloadnng-08400bd437149c4fb31af9b2abece2ae44041283.tar.gz
nng-08400bd437149c4fb31af9b2abece2ae44041283.tar.bz2
nng-08400bd437149c4fb31af9b2abece2ae44041283.zip
Add new nng_sockaddr_equal and nng_sockaddr_hash functions.
These are intended for new transports. Right now they are not documented, but that will be addressed soon.
-rw-r--r--include/nng/nng.h15
-rw-r--r--src/core/sockaddr.c79
2 files changed, 93 insertions, 1 deletions
diff --git a/include/nng/nng.h b/include/nng/nng.h
index 89fae345..32605e3c 100644
--- a/include/nng/nng.h
+++ b/include/nng/nng.h
@@ -317,7 +317,20 @@ NNG_DECL const char *nng_str_sockaddr(
// Obtain a port number (for NNG_AF_INET and NNG_AF_INET6this will be 16 bits
// maximum, but other address familiies may have larger port numbers.) For
// address that don't have the concept of port numbers, zero will be returned.
-uint32_t nng_sockaddr_port(const nng_sockaddr *sa);
+NNG_DECL uint32_t nng_sockaddr_port(const nng_sockaddr *sa);
+
+// Compare two socket addresses. Returns true if they are equal, false
+// otherwise.
+NNG_DECL bool nng_sockaddr_equal(
+ const nng_sockaddr *sa1, const nng_sockaddr *sa2);
+
+// Generate a quick non-zero 64-bit value for the sockaddr.
+// This should usually be unique, but collisions are possible.
+// The resulting hash is not portable between systems, and may not
+// be portable from one version of NNG to the next.
+//
+// The intended use is to allow creation of an index for use with id maps.
+NNG_DECL uint64_t nng_sockaddr_hash(const nng_sockaddr *sa);
// Arguably the pipe callback functions could be handled as an option,
// but with the need to specify an argument, we find it best to unify
diff --git a/src/core/sockaddr.c b/src/core/sockaddr.c
index c7295083..15842b82 100644
--- a/src/core/sockaddr.c
+++ b/src/core/sockaddr.c
@@ -168,3 +168,82 @@ nng_sockaddr_port(const nng_sockaddr *sa)
return (0);
}
}
+
+bool
+nng_sockaddr_equal(const nng_sockaddr *sa1, const nng_sockaddr *sa2)
+{
+ if (sa1->s_family != sa2->s_family) {
+ return false;
+ }
+ switch (sa1->s_family) {
+ case NNG_AF_INET:
+ return ((sa1->s_in.sa_addr == sa2->s_in.sa_addr) &&
+ (sa1->s_in.sa_port == sa2->s_in.sa_port));
+ case NNG_AF_INET6:
+ return (
+ memcmp(&sa1->s_in6, &sa2->s_in6, sizeof(sa1->s_in6)) == 0);
+ case NNG_AF_INPROC:
+ return (
+ strcmp(sa1->s_inproc.sa_name, sa2->s_inproc.sa_name) == 0);
+ case NNG_AF_IPC:
+ return (strcmp(sa1->s_ipc.sa_path, sa2->s_ipc.sa_path) == 0);
+ case NNG_AF_ABSTRACT:
+ return (strcmp((char *) sa1->s_abstract.sa_name,
+ (char *) sa2->s_abstract.sa_name) == 0);
+ default:
+ return (false);
+ }
+}
+
+// generate a quick non-zero 64-bit value for the sockaddr.
+// This should usually be unique, but collisions are possible.
+// The resulting hash is not portable and should not be used for
+// anything except ephemeral uses (e.g. as an index into a id map.)
+uint64_t
+nng_sockaddr_hash(const nng_sockaddr *sa)
+{
+ uint64_t val1, val2;
+ size_t len;
+ const uint8_t *ptr;
+
+ switch (sa->s_family) {
+ case NNG_AF_INET:
+ return (
+ ((uint64_t) (sa->s_in.sa_addr) << 16) + sa->s_in.sa_port);
+ case NNG_AF_INET6:
+ memcpy(&val1, sa->s_in6.sa_addr, sizeof(val1));
+ memcpy(&val2, sa->s_in6.sa_addr + sizeof(val1), sizeof(val2));
+ // the high order bit is set to ensure it cannot be zero
+ return ((1ULL << 63) | (val1 ^ val2 ^ sa->s_in6.sa_port));
+ case NNG_AF_IPC:
+ len = strlen(sa->s_ipc.sa_path);
+ ptr = (const uint8_t *) sa->s_ipc.sa_path;
+ break;
+ case NNG_AF_INPROC:
+ len = strlen(sa->s_inproc.sa_name);
+ ptr = (const uint8_t *) sa->s_inproc.sa_name;
+ break;
+ case NNG_AF_ABSTRACT:
+ len = strlen((const char *) sa->s_abstract.sa_name);
+ ptr = (const uint8_t *) sa->s_abstract.sa_name;
+ break;
+ default:
+ // should never happen!
+ return (sa->s_family);
+ }
+
+ // sort of a string based hash done 64-bits at time.
+ val1 = 0;
+ while (len >= sizeof(val2)) {
+ memcpy(&val2, ptr, sizeof(val2));
+ val1 ^= val2;
+ len -= sizeof(val2);
+ ptr += sizeof(val2);
+ }
+ if (len > 0) {
+ val2 = 0;
+ memcpy(&val2, ptr, len);
+ val1 ^= val2;
+ }
+ return ((1ULL << 63) | val1);
+}