configure: check for libio.h availability
[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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #ifdef HAVE_LIBIO_H
28 #include <libio.h>
29 #endif
30 #include <stdbool.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33
34 /*
35  * This type is for defining buffers that contain network socket
36  * addresses.
37  *
38  * Casting a "struct sockaddr *" to the address of a "struct
39  * sockaddr_storage" breaks C aliasing rules.  The "union
40  * nfs_sockaddr" type follows C aliasing rules yet specifically
41  * allows converting pointers to it between "struct sockaddr *"
42  * and a few other network sockaddr-related pointer types.
43  *
44  * Note that this union is much smaller than a sockaddr_storage.
45  * It should be used only for AF_INET or AF_INET6 socket addresses.
46  * An AF_LOCAL sockaddr_un, for example, will clearly not fit into
47  * a buffer of this type.
48  */
49 union nfs_sockaddr {
50         struct sockaddr         sa;
51         struct sockaddr_in      s4;
52         struct sockaddr_in6     s6;
53 };
54
55 #if SIZEOF_SOCKLEN_T - 0 == 0
56 #define socklen_t unsigned int
57 #endif
58
59 #define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0
60 #define SIZEOF_SOCKADDR_IN      (socklen_t)sizeof(struct sockaddr_in)
61
62 #ifdef IPV6_SUPPORTED
63 #define SIZEOF_SOCKADDR_IN6     (socklen_t)sizeof(struct sockaddr_in6)
64 #else   /* !IPV6_SUPPORTED */
65 #define SIZEOF_SOCKADDR_IN6     SIZEOF_SOCKADDR_UNKNOWN
66 #endif  /* !IPV6_SUPPORTED */
67
68 /**
69  * nfs_sockaddr_length - return the size in bytes of a socket address
70  * @sap: pointer to socket address
71  *
72  * Returns the size in bytes of @sap, or zero if the family is
73  * not recognized.
74  */
75 static inline socklen_t
76 nfs_sockaddr_length(const struct sockaddr *sap)
77 {
78         switch (sap->sa_family) {
79         case AF_INET:
80                 return SIZEOF_SOCKADDR_IN;
81         case AF_INET6:
82                 return SIZEOF_SOCKADDR_IN6;
83         }
84         return SIZEOF_SOCKADDR_UNKNOWN;
85 }
86
87 static inline uint16_t
88 get_port4(const struct sockaddr *sap)
89 {
90         const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
91         return ntohs(sin->sin_port);
92 }
93
94 #ifdef IPV6_SUPPORTED
95 static inline uint16_t
96 get_port6(const struct sockaddr *sap)
97 {
98         const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
99         return ntohs(sin6->sin6_port);
100 }
101 #else   /* !IPV6_SUPPORTED */
102 static inline uint16_t
103 get_port6(__attribute__ ((unused)) const struct sockaddr *sap)
104 {
105         return 0;
106 }
107 #endif  /* !IPV6_SUPPORTED */
108
109 /**
110  * nfs_get_port - extract port value from a socket address
111  * @sap: pointer to socket address
112  *
113  * Returns port value in host byte order, or zero if the
114  * socket address contains an unrecognized family.
115  */
116 static inline uint16_t
117 nfs_get_port(const struct sockaddr *sap)
118 {
119         switch (sap->sa_family) {
120         case AF_INET:
121                 return get_port4(sap);
122         case AF_INET6:
123                 return get_port6(sap);
124         }
125         return 0;
126 }
127
128 static inline void
129 set_port4(struct sockaddr *sap, const uint16_t port)
130 {
131         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
132         sin->sin_port = htons(port);
133 }
134
135 #ifdef IPV6_SUPPORTED
136 static inline void
137 set_port6(struct sockaddr *sap, const uint16_t port)
138 {
139         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
140         sin6->sin6_port = htons(port);
141 }
142 #else   /* !IPV6_SUPPORTED */
143 static inline void
144 set_port6(__attribute__ ((unused)) struct sockaddr *sap,
145                 __attribute__ ((unused)) const uint16_t port)
146 {
147 }
148 #endif  /* !IPV6_SUPPORTED */
149
150 /**
151  * nfs_set_port - set port value in a socket address
152  * @sap: pointer to socket address
153  * @port: port value to set
154  *
155  */
156 static inline void
157 nfs_set_port(struct sockaddr *sap, const uint16_t port)
158 {
159         switch (sap->sa_family) {
160         case AF_INET:
161                 set_port4(sap, port);
162                 break;
163         case AF_INET6:
164                 set_port6(sap, port);
165                 break;
166         }
167 }
168
169 /**
170  * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback
171  * @sap: pointer to socket address
172  *
173  * Returns true if the socket address is the standard IPv4 loopback
174  * address; otherwise false is returned.
175  */
176 static inline _Bool
177 nfs_is_v4_loopback(const struct sockaddr *sap)
178 {
179         const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
180
181         if (sin->sin_family != AF_INET)
182                 return false;
183         if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
184                 return false;
185         return true;
186 }
187
188 static inline _Bool
189 compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
190 {
191         const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
192         const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
193         return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
194 }
195
196 #ifdef IPV6_SUPPORTED
197 static inline _Bool
198 compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
199 {
200         const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
201         const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
202         const struct in6_addr *saddr1 = &sin1->sin6_addr;
203         const struct in6_addr *saddr2 = &sin2->sin6_addr;
204
205         if (IN6_IS_ADDR_LINKLOCAL(saddr1) && IN6_IS_ADDR_LINKLOCAL(saddr2))
206                 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
207                         return false;
208
209         return IN6_ARE_ADDR_EQUAL(saddr1, saddr2);
210 }
211 #else   /* !IPV6_SUPPORTED */
212 static inline _Bool
213 compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1,
214                 __attribute__ ((unused)) const struct sockaddr *sa2)
215 {
216         return false;
217 }
218 #endif  /* !IPV6_SUPPORTED */
219
220 /**
221  * nfs_compare_sockaddr - compare two socket addresses for equality
222  * @sa1: pointer to a socket address
223  * @sa2: pointer to a socket address
224  *
225  * Returns true if the two socket addresses contain equivalent
226  * network addresses; otherwise false is returned.
227  */
228 static inline _Bool
229 nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2)
230 {
231         if (sa1 == NULL || sa2 == NULL)
232                 return false;
233
234         if (sa1->sa_family == sa2->sa_family)
235                 switch (sa1->sa_family) {
236                 case AF_INET:
237                         return compare_sockaddr4(sa1, sa2);
238                 case AF_INET6:
239                         return compare_sockaddr6(sa1, sa2);
240                 }
241
242         return false;
243 }
244
245 #endif  /* !NFS_UTILS_SOCKADDR_H */