summaryrefslogtreecommitdiffstats
path: root/support/include/sockaddr.h
diff options
context:
space:
mode:
Diffstat (limited to 'support/include/sockaddr.h')
-rw-r--r--support/include/sockaddr.h244
1 files changed, 244 insertions, 0 deletions
diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h
new file mode 100644
index 0000000..eeebcdf
--- /dev/null
+++ b/support/include/sockaddr.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2009 Oracle. All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFS_UTILS_SOCKADDR_H
+#define NFS_UTILS_SOCKADDR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*
+ * This type is for defining buffers that contain network socket
+ * addresses.
+ *
+ * Casting a "struct sockaddr *" to the address of a "struct
+ * sockaddr_storage" breaks C aliasing rules. The "union
+ * nfs_sockaddr" type follows C aliasing rules yet specifically
+ * allows converting pointers to it between "struct sockaddr *"
+ * and a few other network sockaddr-related pointer types.
+ *
+ * Note that this union is much smaller than a sockaddr_storage.
+ * It should be used only for AF_INET or AF_INET6 socket addresses.
+ * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
+ * a buffer of this type.
+ */
+union nfs_sockaddr {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+};
+
+#if SIZEOF_SOCKLEN_T - 0 == 0
+#define socklen_t unsigned int
+#endif
+
+#define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0
+#define SIZEOF_SOCKADDR_IN (socklen_t)sizeof(struct sockaddr_in)
+
+#ifdef IPV6_SUPPORTED
+#define SIZEOF_SOCKADDR_IN6 (socklen_t)sizeof(struct sockaddr_in6)
+#else /* !IPV6_SUPPORTED */
+#define SIZEOF_SOCKADDR_IN6 SIZEOF_SOCKADDR_UNKNOWN
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_sockaddr_length - return the size in bytes of a socket address
+ * @sap: pointer to socket address
+ *
+ * Returns the size in bytes of @sap, or zero if the family is
+ * not recognized.
+ */
+static inline socklen_t
+nfs_sockaddr_length(const struct sockaddr *sap)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ return SIZEOF_SOCKADDR_IN;
+ case AF_INET6:
+ return SIZEOF_SOCKADDR_IN6;
+ }
+ return SIZEOF_SOCKADDR_UNKNOWN;
+}
+
+static inline uint16_t
+get_port4(const struct sockaddr *sap)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+ return ntohs(sin->sin_port);
+}
+
+#ifdef IPV6_SUPPORTED
+static inline uint16_t
+get_port6(const struct sockaddr *sap)
+{
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
+ return ntohs(sin6->sin6_port);
+}
+#else /* !IPV6_SUPPORTED */
+static inline uint16_t
+get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
+{
+ return 0;
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_get_port - extract port value from a socket address
+ * @sap: pointer to socket address
+ *
+ * Returns port value in host byte order, or zero if the
+ * socket address contains an unrecognized family.
+ */
+static inline uint16_t
+nfs_get_port(const struct sockaddr *sap)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ return get_port4(sap);
+ case AF_INET6:
+ return get_port6(sap);
+ }
+ return 0;
+}
+
+static inline void
+set_port4(struct sockaddr *sap, const uint16_t port)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ sin->sin_port = htons(port);
+}
+
+#ifdef IPV6_SUPPORTED
+static inline void
+set_port6(struct sockaddr *sap, const uint16_t port)
+{
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+ sin6->sin6_port = htons(port);
+}
+#else /* !IPV6_SUPPORTED */
+static inline void
+set_port6(__attribute__ ((unused)) struct sockaddr *sap,
+ __attribute__ ((unused)) const uint16_t port)
+{
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_set_port - set port value in a socket address
+ * @sap: pointer to socket address
+ * @port: port value to set
+ *
+ */
+static inline void
+nfs_set_port(struct sockaddr *sap, const uint16_t port)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ set_port4(sap, port);
+ break;
+ case AF_INET6:
+ set_port6(sap, port);
+ break;
+ }
+}
+
+/**
+ * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
+ * @sap: pointer to socket address
+ *
+ * Returns true if the socket address is the standard IPv4 loopback
+ * address; otherwise false is returned.
+ */
+static inline _Bool
+nfs_is_v4_loopback(const struct sockaddr *sap)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+
+ if (sin->sin_family != AF_INET)
+ return false;
+ if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+ return false;
+ return true;
+}
+
+static inline _Bool
+compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+ return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
+}
+
+#ifdef IPV6_SUPPORTED
+static inline _Bool
+compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
+ const struct in6_addr *saddr1 = &sin1->sin6_addr;
+ const struct in6_addr *saddr2 = &sin2->sin6_addr;
+
+ if (IN6_IS_ADDR_LINKLOCAL(saddr1) && IN6_IS_ADDR_LINKLOCAL(saddr2))
+ if (sin1->sin6_scope_id != sin2->sin6_scope_id)
+ return false;
+
+ return IN6_ARE_ADDR_EQUAL(saddr1, saddr2);
+}
+#else /* !IPV6_SUPPORTED */
+static inline _Bool
+compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
+ __attribute__ ((unused)) const struct sockaddr *sa2)
+{
+ return false;
+}
+#endif /* !IPV6_SUPPORTED */
+
+/**
+ * nfs_compare_sockaddr - compare two socket addresses for equality
+ * @sa1: pointer to a socket address
+ * @sa2: pointer to a socket address
+ *
+ * Returns true if the two socket addresses contain equivalent
+ * network addresses; otherwise false is returned.
+ */
+static inline _Bool
+nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+ if (sa1 == NULL || sa2 == NULL)
+ return false;
+
+ if (sa1->sa_family == sa2->sa_family)
+ switch (sa1->sa_family) {
+ case AF_INET:
+ return compare_sockaddr4(sa1, sa2);
+ case AF_INET6:
+ return compare_sockaddr6(sa1, sa2);
+ }
+
+ return false;
+}
+
+#endif /* !NFS_UTILS_SOCKADDR_H */