]> git.decadent.org.uk Git - nfs-utils.git/blob - support/include/sockaddr.h
732514be6c747a2ce981a89b77ffeee372c63ce6
[nfs-utils.git] / support / include / sockaddr.h
1 /*
2  * Copyright 2009 Oracle.  All rights reserved.
3  *
4  * This file is part of nfs-utils.
5  *
6  * nfs-utils is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * nfs-utils is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifndef NFS_UTILS_SOCKADDR_H
21 #define NFS_UTILS_SOCKADDR_H
22
23 #include <stdbool.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26
27 /*
28  * This type is for defining buffers that contain network socket
29  * addresses.
30  *
31  * Casting a "struct sockaddr *" to the address of a "struct
32  * sockaddr_storage" breaks C aliasing rules.  The "union
33  * nfs_sockaddr" type follows C aliasing rules yet specifically
34  * allows converting pointers to it between "struct sockaddr *"
35  * and a few other network sockaddr-related pointer types.
36  *
37  * Note that this union is much smaller than a sockaddr_storage.
38  * It should be used only for AF_INET or AF_INET6 socket addresses.
39  * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
40  * a buffer of this type.
41  */
42 union nfs_sockaddr {
43         struct sockaddr         sa;
44         struct sockaddr_in      s4;
45         struct sockaddr_in6     s6;
46 };
47
48 #if SIZEOF_SOCKLEN_T - 0 == 0
49 #define socklen_t unsigned int
50 #endif
51
52 #define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0
53 #define SIZEOF_SOCKADDR_IN      (socklen_t)sizeof(struct sockaddr_in)
54
55 #ifdef IPV6_SUPPORTED
56 #define SIZEOF_SOCKADDR_IN6     (socklen_t)sizeof(struct sockaddr_in6)
57 #else   /* !IPV6_SUPPORTED */
58 #define SIZEOF_SOCKADDR_IN6     SIZEOF_SOCKADDR_UNKNOWN
59 #endif  /* !IPV6_SUPPORTED */
60
61 /**
62  * nfs_sockaddr_length - return the size in bytes of a socket address
63  * @sap: pointer to socket address
64  *
65  * Returns the size in bytes of @sap, or zero if the family is
66  * not recognized.
67  */
68 static inline socklen_t
69 nfs_sockaddr_length(const struct sockaddr *sap)
70 {
71         switch (sap->sa_family) {
72         case AF_INET:
73                 return SIZEOF_SOCKADDR_IN;
74         case AF_INET6:
75                 return SIZEOF_SOCKADDR_IN6;
76         }
77         return SIZEOF_SOCKADDR_UNKNOWN;
78 }
79
80 static inline uint16_t
81 get_port4(const struct sockaddr *sap)
82 {
83         const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
84         return ntohs(sin->sin_port);
85 }
86
87 #ifdef IPV6_SUPPORTED
88 static inline uint16_t
89 get_port6(const struct sockaddr *sap)
90 {
91         const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
92         return ntohs(sin6->sin6_port);
93 }
94 #else   /* !IPV6_SUPPORTED */
95 static inline uint16_t
96 get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
97 {
98         return 0;
99 }
100 #endif  /* !IPV6_SUPPORTED */
101
102 /**
103  * nfs_get_port - extract port value from a socket address
104  * @sap: pointer to socket address
105  *
106  * Returns port value in host byte order, or zero if the
107  * socket address contains an unrecognized family.
108  */
109 static inline uint16_t
110 nfs_get_port(const struct sockaddr *sap)
111 {
112         switch (sap->sa_family) {
113         case AF_INET:
114                 return get_port4(sap);
115         case AF_INET6:
116                 return get_port6(sap);
117         }
118         return 0;
119 }
120
121 static inline void
122 set_port4(struct sockaddr *sap, const uint16_t port)
123 {
124         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
125         sin->sin_port = htons(port);
126 }
127
128 #ifdef IPV6_SUPPORTED
129 static inline void
130 set_port6(struct sockaddr *sap, const uint16_t port)
131 {
132         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
133         sin6->sin6_port = htons(port);
134 }
135 #else   /* !IPV6_SUPPORTED */
136 static inline void
137 set_port6(__attribute__ ((unused)) struct sockaddr *sap,
138                 __attribute__ ((unused)) const uint16_t port)
139 {
140 }
141 #endif  /* !IPV6_SUPPORTED */
142
143 /**
144  * nfs_set_port - set port value in a socket address
145  * @sap: pointer to socket address
146  * @port: port value to set
147  *
148  */
149 static inline void
150 nfs_set_port(struct sockaddr *sap, const uint16_t port)
151 {
152         switch (sap->sa_family) {
153         case AF_INET:
154                 set_port4(sap, port);
155                 break;
156         case AF_INET6:
157                 set_port6(sap, port);
158                 break;
159         }
160 }
161
162 /**
163  * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
164  * @sap: pointer to socket address
165  *
166  * Returns true if the socket address is the standard IPv4 loopback
167  * address; otherwise false is returned.
168  */
169 static inline _Bool
170 nfs_is_v4_loopback(const struct sockaddr *sap)
171 {
172         const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
173
174         if (sin->sin_family != AF_INET)
175                 return false;
176         if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
177                 return false;
178         return true;
179 }
180
181 static inline _Bool
182 compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
183 {
184         const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
185         const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
186         return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
187 }
188
189 #ifdef IPV6_SUPPORTED
190 static inline _Bool
191 compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
192 {
193         const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
194         const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
195
196         if ((IN6_IS_ADDR_LINKLOCAL((char *)&sin1->sin6_addr) &&
197              IN6_IS_ADDR_LINKLOCAL((char *)&sin2->sin6_addr)) ||
198             (IN6_IS_ADDR_SITELOCAL((char *)&sin1->sin6_addr) &&
199              IN6_IS_ADDR_SITELOCAL((char *)&sin2->sin6_addr)))
200                 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
201                         return false;
202
203         return IN6_ARE_ADDR_EQUAL((char *)&sin1->sin6_addr,
204                                         (char *)&sin2->sin6_addr);
205 }
206 #else   /* !IPV6_SUPPORTED */
207 static inline _Bool
208 compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
209                 __attribute__ ((unused)) const struct sockaddr *sa2)
210 {
211         return false;
212 }
213 #endif  /* !IPV6_SUPPORTED */
214
215 /**
216  * nfs_compare_sockaddr - compare two socket addresses for equality
217  * @sa1: pointer to a socket address
218  * @sa2: pointer to a socket address
219  *
220  * Returns true if the two socket addresses contain equivalent
221  * network addresses; otherwise false is returned.
222  */
223 static inline _Bool
224 nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
225 {
226         if (sa1->sa_family == sa2->sa_family)
227                 switch (sa1->sa_family) {
228                 case AF_INET:
229                         return compare_sockaddr4(sa1, sa2);
230                 case AF_INET6:
231                         return compare_sockaddr6(sa1, sa2);
232                 }
233
234         return false;
235 }
236
237 #endif  /* !NFS_UTILS_SOCKADDR_H */