Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/io/pripv6.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
5 | |
6 /* | |
7 ** File: pripv6.c | |
8 ** Description: Support for various functions unique to IPv6 | |
9 */ | |
10 #include "primpl.h" | |
11 #include <string.h> | |
12 | |
13 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) | |
14 | |
15 static PRIOMethods ipv6_to_v4_tcpMethods; | |
16 static PRIOMethods ipv6_to_v4_udpMethods; | |
17 static PRDescIdentity _pr_ipv6_to_ipv4_id; | |
18 extern PRBool IsValidNetAddr(const PRNetAddr *addr); | |
19 extern PRIPv6Addr _pr_in6addr_any; | |
20 extern PRIPv6Addr _pr_in6addr_loopback; | |
21 | |
22 /* | |
23 * convert an IPv4-mapped IPv6 addr to an IPv4 addr | |
24 */ | |
25 static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr, | |
26 PRNetAddr *dst_v4addr) | |
27 { | |
28 const PRUint8 *srcp; | |
29 | |
30 PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family); | |
31 | |
32 if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) { | |
33 srcp = src_v6addr->ipv6.ip.pr_s6_addr; | |
34 memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4); | |
35 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) { | |
36 dst_v4addr->inet.ip = htonl(INADDR_ANY); | |
37 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) { | |
38 dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK); | |
39 } | |
40 dst_v4addr->inet.family = PR_AF_INET; | |
41 dst_v4addr->inet.port = src_v6addr->ipv6.port; | |
42 } | |
43 | |
44 /* | |
45 * convert an IPv4 addr to an IPv4-mapped IPv6 addr | |
46 */ | |
47 static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr, | |
48 PRNetAddr *dst_v6addr) | |
49 { | |
50 PRUint8 *dstp; | |
51 | |
52 PR_ASSERT(PR_AF_INET == src_v4addr->inet.family); | |
53 dst_v6addr->ipv6.family = PR_AF_INET6; | |
54 dst_v6addr->ipv6.port = src_v4addr->inet.port; | |
55 | |
56 if (htonl(INADDR_ANY) == src_v4addr->inet.ip) { | |
57 dst_v6addr->ipv6.ip = _pr_in6addr_any; | |
58 } else { | |
59 dstp = dst_v6addr->ipv6.ip.pr_s6_addr; | |
60 memset(dstp, 0, 10); | |
61 memset(dstp + 10, 0xff, 2); | |
62 memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4); | |
63 } | |
64 } | |
65 | |
66 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd, | |
67 const PRNetAddr *addr) | |
68 { | |
69 PRNetAddr tmp_ipv4addr; | |
70 const PRNetAddr *tmp_addrp; | |
71 PRFileDesc *lo = fd->lower; | |
72 | |
73 if (PR_AF_INET6 != addr->raw.family) { | |
74 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); | |
75 return PR_FAILURE; | |
76 } | |
77 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || | |
78 PR_IsNetAddrType(addr, PR_IpAddrAny)) { | |
79 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); | |
80 tmp_addrp = &tmp_ipv4addr; | |
81 } else { | |
82 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); | |
83 return PR_FAILURE; | |
84 } | |
85 return((lo->methods->bind)(lo,tmp_addrp)); | |
86 } | |
87 | |
88 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect( | |
89 PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) | |
90 { | |
91 PRNetAddr tmp_ipv4addr; | |
92 const PRNetAddr *tmp_addrp; | |
93 | |
94 if (PR_AF_INET6 != addr->raw.family) { | |
95 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); | |
96 return PR_FAILURE; | |
97 } | |
98 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || | |
99 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { | |
100 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); | |
101 tmp_addrp = &tmp_ipv4addr; | |
102 } else { | |
103 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); | |
104 return PR_FAILURE; | |
105 } | |
106 return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout); | |
107 } | |
108 | |
109 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo( | |
110 PRFileDesc *fd, const void *buf, PRInt32 amount, | |
111 PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) | |
112 { | |
113 PRNetAddr tmp_ipv4addr; | |
114 const PRNetAddr *tmp_addrp; | |
115 | |
116 if (PR_AF_INET6 != addr->raw.family) { | |
117 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); | |
118 return PR_FAILURE; | |
119 } | |
120 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) || | |
121 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) { | |
122 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr); | |
123 tmp_addrp = &tmp_ipv4addr; | |
124 } else { | |
125 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0); | |
126 return PR_FAILURE; | |
127 } | |
128 return (fd->lower->methods->sendto)( | |
129 fd->lower, buf, amount, flags, tmp_addrp, timeout); | |
130 } | |
131 | |
132 static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept ( | |
133 PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) | |
134 { | |
135 PRStatus rv; | |
136 PRFileDesc *newfd; | |
137 PRFileDesc *newstack; | |
138 PRNetAddr tmp_ipv4addr; | |
139 PRNetAddr *addrlower = NULL; | |
140 | |
141 PR_ASSERT(fd != NULL); | |
142 PR_ASSERT(fd->lower != NULL); | |
143 | |
144 newstack = PR_NEW(PRFileDesc); | |
145 if (NULL == newstack) | |
146 { | |
147 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
148 return NULL; | |
149 } | |
150 *newstack = *fd; /* make a copy of the accepting layer */ | |
151 | |
152 if (addr) | |
153 addrlower = &tmp_ipv4addr; | |
154 newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout); | |
155 if (NULL == newfd) | |
156 { | |
157 PR_DELETE(newstack); | |
158 return NULL; | |
159 } | |
160 if (addr) | |
161 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr); | |
162 | |
163 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); | |
164 PR_ASSERT(PR_SUCCESS == rv); | |
165 return newfd; /* that's it */ | |
166 } | |
167 | |
168 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd, | |
169 PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount, | |
170 PRIntervalTime timeout) | |
171 { | |
172 PRInt32 nbytes; | |
173 PRStatus rv; | |
174 PRNetAddr tmp_ipv4addr; | |
175 PRFileDesc *newstack; | |
176 | |
177 PR_ASSERT(sd != NULL); | |
178 PR_ASSERT(sd->lower != NULL); | |
179 | |
180 newstack = PR_NEW(PRFileDesc); | |
181 if (NULL == newstack) | |
182 { | |
183 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
184 return -1; | |
185 } | |
186 *newstack = *sd; /* make a copy of the accepting layer */ | |
187 | |
188 nbytes = sd->lower->methods->acceptread( | |
189 sd->lower, nd, ipv6_raddr, buf, amount, timeout); | |
190 if (-1 == nbytes) | |
191 { | |
192 PR_DELETE(newstack); | |
193 return nbytes; | |
194 } | |
195 tmp_ipv4addr = **ipv6_raddr; /* copy */ | |
196 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr); | |
197 | |
198 /* this PR_PushIOLayer call cannot fail */ | |
199 rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack); | |
200 PR_ASSERT(PR_SUCCESS == rv); | |
201 return nbytes; | |
202 } | |
203 | |
204 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd, | |
205 PRNetAddr *ipv6addr) | |
206 { | |
207 PRStatus result; | |
208 PRNetAddr tmp_ipv4addr; | |
209 | |
210 result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr); | |
211 if (PR_SUCCESS == result) { | |
212 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); | |
213 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); | |
214 } | |
215 return result; | |
216 } | |
217 | |
218 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd, | |
219 PRNetAddr *ipv6addr) | |
220 { | |
221 PRStatus result; | |
222 PRNetAddr tmp_ipv4addr; | |
223 | |
224 result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr); | |
225 if (PR_SUCCESS == result) { | |
226 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); | |
227 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); | |
228 } | |
229 return result; | |
230 } | |
231 | |
232 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf, | |
233 PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr, | |
234 PRIntervalTime timeout) | |
235 { | |
236 PRNetAddr tmp_ipv4addr; | |
237 PRInt32 result; | |
238 | |
239 result = (fd->lower->methods->recvfrom)( | |
240 fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout); | |
241 if (-1 != result) { | |
242 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr); | |
243 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE); | |
244 } | |
245 return result; | |
246 } | |
247 | |
248 #if defined(_PR_INET6_PROBE) | |
249 static PRBool ipv6_is_present; | |
250 extern PRBool _pr_test_ipv6_socket(void); | |
251 | |
252 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) | |
253 extern PRStatus _pr_find_getipnodebyname(void); | |
254 #endif | |
255 | |
256 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) | |
257 extern PRStatus _pr_find_getaddrinfo(void); | |
258 #endif | |
259 | |
260 static PRBool | |
261 _pr_probe_ipv6_presence(void) | |
262 { | |
263 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME) | |
264 if (_pr_find_getipnodebyname() != PR_SUCCESS) | |
265 return PR_FALSE; | |
266 #endif | |
267 | |
268 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO) | |
269 if (_pr_find_getaddrinfo() != PR_SUCCESS) | |
270 return PR_FALSE; | |
271 #endif | |
272 | |
273 return _pr_test_ipv6_socket(); | |
274 } | |
275 #endif /* _PR_INET6_PROBE */ | |
276 | |
277 static PRCallOnceType _pr_init_ipv6_once; | |
278 | |
279 static PRStatus PR_CALLBACK _pr_init_ipv6(void) | |
280 { | |
281 const PRIOMethods *stubMethods; | |
282 | |
283 #if defined(_PR_INET6_PROBE) | |
284 ipv6_is_present = _pr_probe_ipv6_presence(); | |
285 if (ipv6_is_present) | |
286 return PR_SUCCESS; | |
287 #endif | |
288 | |
289 _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer"); | |
290 PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id); | |
291 | |
292 stubMethods = PR_GetDefaultIOMethods(); | |
293 | |
294 ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */ | |
295 /* then override the ones we care about */ | |
296 ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect; | |
297 ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind; | |
298 ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept; | |
299 ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead; | |
300 ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName; | |
301 ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; | |
302 /* | |
303 ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; | |
304 ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; | |
305 */ | |
306 ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */ | |
307 /* then override the ones we care about */ | |
308 ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect; | |
309 ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind; | |
310 ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo; | |
311 ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom; | |
312 ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName; | |
313 ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName; | |
314 /* | |
315 ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption; | |
316 ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption; | |
317 */ | |
318 return PR_SUCCESS; | |
319 } | |
320 | |
321 #if defined(_PR_INET6_PROBE) | |
322 PRBool _pr_ipv6_is_present(void) | |
323 { | |
324 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) | |
325 return PR_FALSE; | |
326 return ipv6_is_present; | |
327 } | |
328 #endif | |
329 | |
330 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd) | |
331 { | |
332 PRFileDesc *ipv6_fd = NULL; | |
333 | |
334 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) | |
335 return PR_FAILURE; | |
336 | |
337 /* | |
338 * For platforms with no support for IPv6 | |
339 * create layered socket for IPv4-mapped IPv6 addresses | |
340 */ | |
341 if (fd->methods->file_type == PR_DESC_SOCKET_TCP) | |
342 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, | |
343 &ipv6_to_v4_tcpMethods); | |
344 else | |
345 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, | |
346 &ipv6_to_v4_udpMethods); | |
347 if (NULL == ipv6_fd) { | |
348 goto errorExit; | |
349 } | |
350 ipv6_fd->secret = NULL; | |
351 | |
352 if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) { | |
353 goto errorExit; | |
354 } | |
355 | |
356 return PR_SUCCESS; | |
357 errorExit: | |
358 | |
359 if (ipv6_fd) | |
360 ipv6_fd->dtor(ipv6_fd); | |
361 return PR_FAILURE; | |
362 } | |
363 | |
364 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */ |