Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / libisc / net.c
blob131bb30e3db3ac7f6e99113ef76aeb24efb27cf7
1 /* $NetBSD: net.c,v 1.4 2006/06/13 22:36:36 christos Exp $ */
3 /*
4 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: net.c,v 1.22.2.2.10.7 2004/04/29 01:31:22 marka Exp */
22 #include <config.h>
24 #include <errno.h>
25 #include <unistd.h>
27 #include <isc/net.h>
28 #include <isc/once.h>
29 #include <isc/strerror.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
33 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRANY)
34 const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
35 #endif
37 #if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK)
38 const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
39 #endif
41 static isc_boolean_t once = ISC_FALSE;
42 #ifdef WANT_IPV6
43 static isc_once_t once_ipv6only = ISC_ONCE_INIT;
44 static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT;
45 #endif
46 static isc_result_t ipv4_result = ISC_R_NOTFOUND;
47 static isc_result_t ipv6_result = ISC_R_NOTFOUND;
48 static isc_result_t ipv6only_result = ISC_R_NOTFOUND;
49 static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND;
51 static isc_result_t
52 try_proto(int domain) {
53 int s;
54 isc_result_t result = ISC_R_SUCCESS;
55 char strbuf[ISC_STRERRORSIZE];
57 s = socket(domain, SOCK_STREAM, 0);
58 if (s == -1) {
59 switch (errno) {
60 #ifdef EAFNOSUPPORT
61 case EAFNOSUPPORT:
62 #endif
63 #ifdef EPROTONOSUPPORT
64 case EPROTONOSUPPORT:
65 #endif
66 #ifdef EINVAL
67 case EINVAL:
68 #endif
69 return (ISC_R_NOTFOUND);
70 default:
71 isc__strerror(errno, strbuf, sizeof(strbuf));
72 UNEXPECTED_ERROR(__FILE__, __LINE__,
73 "socket() failed: %s",
74 strbuf);
75 return (ISC_R_UNEXPECTED);
79 #ifdef ISC_PLATFORM_HAVEIPV6
80 #ifdef WANT_IPV6
81 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
82 if (domain == PF_INET6) {
83 struct sockaddr_in6 sin6;
84 GETSOCKNAME_SOCKLEN_TYPE len;
87 * Check to see if IPv6 is broken, as is common on Linux.
89 len = sizeof(sin6);
90 if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0)
92 result = ISC_R_NOTFOUND;
93 } else {
94 if (len == sizeof(struct sockaddr_in6))
95 result = ISC_R_SUCCESS;
96 else {
97 result = ISC_R_NOTFOUND;
101 #endif
102 #endif
103 #endif
105 (void)close(s);
107 return (result);
110 static void
111 initialize_action(void) {
112 ipv4_result = try_proto(PF_INET);
113 #ifdef ISC_PLATFORM_HAVEIPV6
114 #ifdef WANT_IPV6
115 #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
116 ipv6_result = try_proto(PF_INET6);
117 #endif
118 #endif
119 #endif
122 static void
123 initialize(void) {
124 if(once == ISC_FALSE) {
125 initialize_action();
126 once = ISC_TRUE;
130 isc_result_t
131 isc_net_probeipv4(void) {
132 initialize();
133 return (ipv4_result);
136 isc_result_t
137 isc_net_probeipv6(void) {
138 initialize();
139 return (ipv6_result);
142 #ifdef ISC_PLATFORM_HAVEIPV6
143 #ifdef WANT_IPV6
144 static void
145 try_ipv6only(void) {
146 #ifdef IPV6_V6ONLY
147 int s, on;
148 char strbuf[ISC_STRERRORSIZE];
149 #endif
150 isc_result_t result;
152 result = isc_net_probeipv6();
153 if (result != ISC_R_SUCCESS) {
154 ipv6only_result = result;
155 return;
158 #ifndef IPV6_V6ONLY
159 ipv6only_result = ISC_R_NOTFOUND;
160 return;
161 #else
162 /* check for TCP sockets */
163 s = socket(PF_INET6, SOCK_STREAM, 0);
164 if (s == -1) {
165 isc__strerror(errno, strbuf, sizeof(strbuf));
166 UNEXPECTED_ERROR(__FILE__, __LINE__,
167 "socket() failed: %s",
168 strbuf);
169 ipv6only_result = ISC_R_UNEXPECTED;
170 return;
173 on = 1;
174 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
175 ipv6only_result = ISC_R_NOTFOUND;
176 goto close;
179 close(s);
181 /* check for UDP sockets */
182 s = socket(PF_INET6, SOCK_DGRAM, 0);
183 if (s == -1) {
184 isc__strerror(errno, strbuf, sizeof(strbuf));
185 UNEXPECTED_ERROR(__FILE__, __LINE__,
186 "socket() failed: %s",
187 strbuf);
188 ipv6only_result = ISC_R_UNEXPECTED;
189 return;
192 on = 1;
193 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
194 ipv6only_result = ISC_R_NOTFOUND;
195 goto close;
198 close(s);
200 ipv6only_result = ISC_R_SUCCESS;
202 close:
203 close(s);
204 return;
205 #endif /* IPV6_V6ONLY */
208 static void
209 initialize_ipv6only(void) {
210 RUNTIME_CHECK(isc_once_do(&once_ipv6only,
211 try_ipv6only) == ISC_R_SUCCESS);
214 static void
215 try_ipv6pktinfo(void) {
216 int s, on;
217 char strbuf[ISC_STRERRORSIZE];
218 isc_result_t result;
219 int optname;
221 result = isc_net_probeipv6();
222 if (result != ISC_R_SUCCESS) {
223 ipv6pktinfo_result = result;
224 return;
227 /* we only use this for UDP sockets */
228 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
229 if (s == -1) {
230 isc__strerror(errno, strbuf, sizeof(strbuf));
231 UNEXPECTED_ERROR(__FILE__, __LINE__,
232 "socket() failed: %s",
233 strbuf);
234 ipv6pktinfo_result = ISC_R_UNEXPECTED;
235 return;
238 #ifdef IPV6_RECVPKTINFO
239 optname = IPV6_RECVPKTINFO;
240 #else
241 optname = IPV6_PKTINFO;
242 #endif
243 on = 1;
244 if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) {
245 ipv6pktinfo_result = ISC_R_NOTFOUND;
246 goto close;
249 close(s);
250 ipv6pktinfo_result = ISC_R_SUCCESS;
252 close:
253 close(s);
254 return;
257 static void
258 initialize_ipv6pktinfo(void) {
259 RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo,
260 try_ipv6pktinfo) == ISC_R_SUCCESS);
262 #endif /* WANT_IPV6 */
263 #endif /* ISC_PLATFORM_HAVEIPV6 */
265 isc_result_t
266 isc_net_probe_ipv6only(void) {
267 #ifdef ISC_PLATFORM_HAVEIPV6
268 #ifdef WANT_IPV6
269 initialize_ipv6only();
270 #else
271 ipv6only_result = ISC_R_NOTFOUND;
272 #endif
273 #endif
274 return (ipv6only_result);
277 isc_result_t
278 isc_net_probe_ipv6pktinfo(void) {
279 #ifdef ISC_PLATFORM_HAVEIPV6
280 #ifdef WANT_IPV6
281 initialize_ipv6pktinfo();
282 #else
283 ipv6pktinfo_result = ISC_R_NOTFOUND;
284 #endif
285 #endif
286 return (ipv6pktinfo_result);
289 void
290 isc_net_disableipv4(void) {
291 initialize();
292 if (ipv4_result == ISC_R_SUCCESS)
293 ipv4_result = ISC_R_DISABLED;
296 void
297 isc_net_disableipv6(void) {
298 initialize();
299 if (ipv6_result == ISC_R_SUCCESS)
300 ipv6_result = ISC_R_DISABLED;
303 void
304 isc_net_enableipv4(void) {
305 initialize();
306 if (ipv4_result == ISC_R_DISABLED)
307 ipv4_result = ISC_R_SUCCESS;
310 void
311 isc_net_enableipv6(void) {
312 initialize();
313 if (ipv6_result == ISC_R_DISABLED)
314 ipv6_result = ISC_R_SUCCESS;