Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / nsprpub / pr / src / io / pripv6.c
blob284b01a2f3f2c2fcc0d99d3684be6c729a0efe2c
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/. */
6 /*
7 ** File: pripv6.c
8 ** Description: Support for various functions unique to IPv6
9 */
10 #include "primpl.h"
11 #include <string.h>
13 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
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 const PRIPv6Addr _pr_in6addr_any;
20 extern const PRIPv6Addr _pr_in6addr_loopback;
23 * convert an IPv4-mapped IPv6 addr to an IPv4 addr
25 static void _PR_ConvertToIpv4NetAddr(const PRNetAddr* src_v6addr,
26 PRNetAddr* dst_v4addr) {
27 const PRUint8* srcp;
29 PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
31 if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
32 srcp = src_v6addr->ipv6.ip.pr_s6_addr;
33 memcpy((char*)&dst_v4addr->inet.ip, srcp + 12, 4);
34 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
35 dst_v4addr->inet.ip = htonl(INADDR_ANY);
36 } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
37 dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
39 dst_v4addr->inet.family = PR_AF_INET;
40 dst_v4addr->inet.port = src_v6addr->ipv6.port;
44 * convert an IPv4 addr to an IPv4-mapped IPv6 addr
46 static void _PR_ConvertToIpv6NetAddr(const PRNetAddr* src_v4addr,
47 PRNetAddr* dst_v6addr) {
48 PRUint8* dstp;
50 PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
51 dst_v6addr->ipv6.family = PR_AF_INET6;
52 dst_v6addr->ipv6.port = src_v4addr->inet.port;
54 if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
55 dst_v6addr->ipv6.ip = _pr_in6addr_any;
56 } else {
57 dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
58 memset(dstp, 0, 10);
59 memset(dstp + 10, 0xff, 2);
60 memcpy(dstp + 12, (char*)&src_v4addr->inet.ip, 4);
64 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc* fd,
65 const PRNetAddr* addr) {
66 PRNetAddr tmp_ipv4addr;
67 const PRNetAddr* tmp_addrp;
68 PRFileDesc* lo = fd->lower;
70 if (PR_AF_INET6 != addr->raw.family) {
71 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
72 return PR_FAILURE;
74 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
75 PR_IsNetAddrType(addr, PR_IpAddrAny)) {
76 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
77 tmp_addrp = &tmp_ipv4addr;
78 } else {
79 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
80 return PR_FAILURE;
82 return ((lo->methods->bind)(lo, tmp_addrp));
85 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(PRFileDesc* fd,
86 const PRNetAddr* addr,
87 PRIntervalTime timeout) {
88 PRNetAddr tmp_ipv4addr;
89 const PRNetAddr* tmp_addrp;
91 if (PR_AF_INET6 != addr->raw.family) {
92 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
93 return PR_FAILURE;
95 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
96 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
97 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
98 tmp_addrp = &tmp_ipv4addr;
99 } else {
100 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
101 return PR_FAILURE;
103 return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
106 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(PRFileDesc* fd,
107 const void* buf,
108 PRInt32 amount, PRIntn flags,
109 const PRNetAddr* addr,
110 PRIntervalTime timeout) {
111 PRNetAddr tmp_ipv4addr;
112 const PRNetAddr* tmp_addrp;
114 if (PR_AF_INET6 != addr->raw.family) {
115 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
116 return PR_FAILURE;
118 if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
119 PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
120 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
121 tmp_addrp = &tmp_ipv4addr;
122 } else {
123 PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
124 return PR_FAILURE;
126 return (fd->lower->methods->sendto)(fd->lower, buf, amount, flags, tmp_addrp,
127 timeout);
130 static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept(PRFileDesc* fd,
131 PRNetAddr* addr,
132 PRIntervalTime timeout) {
133 PRStatus rv;
134 PRFileDesc* newfd;
135 PRFileDesc* newstack;
136 PRNetAddr tmp_ipv4addr;
137 PRNetAddr* addrlower = NULL;
139 PR_ASSERT(fd != NULL);
140 PR_ASSERT(fd->lower != NULL);
142 newstack = PR_NEW(PRFileDesc);
143 if (NULL == newstack) {
144 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
145 return NULL;
147 *newstack = *fd; /* make a copy of the accepting layer */
149 if (addr) {
150 addrlower = &tmp_ipv4addr;
152 newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
153 if (NULL == newfd) {
154 PR_DELETE(newstack);
155 return NULL;
157 if (addr) {
158 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
161 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
162 PR_ASSERT(PR_SUCCESS == rv);
163 return newfd; /* that's it */
166 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc* sd,
167 PRFileDesc** nd,
168 PRNetAddr** ipv6_raddr,
169 void* buf, PRInt32 amount,
170 PRIntervalTime timeout) {
171 PRInt32 nbytes;
172 PRStatus rv;
173 PRNetAddr tmp_ipv4addr;
174 PRFileDesc* newstack;
176 PR_ASSERT(sd != NULL);
177 PR_ASSERT(sd->lower != NULL);
179 newstack = PR_NEW(PRFileDesc);
180 if (NULL == newstack) {
181 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
182 return -1;
184 *newstack = *sd; /* make a copy of the accepting layer */
186 nbytes = sd->lower->methods->acceptread(sd->lower, nd, ipv6_raddr, buf,
187 amount, timeout);
188 if (-1 == nbytes) {
189 PR_DELETE(newstack);
190 return nbytes;
192 tmp_ipv4addr = **ipv6_raddr; /* copy */
193 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
195 /* this PR_PushIOLayer call cannot fail */
196 rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
197 PR_ASSERT(PR_SUCCESS == rv);
198 return nbytes;
201 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc* fd,
202 PRNetAddr* ipv6addr) {
203 PRStatus result;
204 PRNetAddr tmp_ipv4addr;
206 result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
207 if (PR_SUCCESS == result) {
208 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
209 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
211 return result;
214 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc* fd,
215 PRNetAddr* ipv6addr) {
216 PRStatus result;
217 PRNetAddr tmp_ipv4addr;
219 result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
220 if (PR_SUCCESS == result) {
221 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
222 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
224 return result;
227 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc* fd, void* buf,
228 PRInt32 amount,
229 PRIntn flags,
230 PRNetAddr* ipv6addr,
231 PRIntervalTime timeout) {
232 PRNetAddr tmp_ipv4addr;
233 PRInt32 result;
235 result = (fd->lower->methods->recvfrom)(fd->lower, buf, amount, flags,
236 &tmp_ipv4addr, timeout);
237 if (-1 != result) {
238 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
239 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
241 return result;
244 # if defined(_PR_INET6_PROBE)
245 static PRBool ipv6_is_present;
246 PR_EXTERN(PRBool) _pr_test_ipv6_socket(void);
248 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
249 extern PRStatus _pr_find_getipnodebyname(void);
250 # endif
252 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
253 extern PRStatus _pr_find_getaddrinfo(void);
254 # endif
256 static PRBool _pr_probe_ipv6_presence(void) {
257 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
258 if (_pr_find_getipnodebyname() != PR_SUCCESS) {
259 return PR_FALSE;
261 # endif
263 # if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
264 if (_pr_find_getaddrinfo() != PR_SUCCESS) {
265 return PR_FALSE;
267 # endif
269 return _pr_test_ipv6_socket();
271 # endif /* _PR_INET6_PROBE */
273 static PRCallOnceType _pr_init_ipv6_once;
275 static PRStatus PR_CALLBACK _pr_init_ipv6(void) {
276 const PRIOMethods* stubMethods;
278 # if defined(_PR_INET6_PROBE)
279 ipv6_is_present = _pr_probe_ipv6_presence();
280 if (ipv6_is_present) {
281 return PR_SUCCESS;
283 # endif
285 _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
286 PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
288 stubMethods = PR_GetDefaultIOMethods();
290 ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */
291 /* then override the ones we care about */
292 ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
293 ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
294 ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
295 ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
296 ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
297 ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
299 ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
300 ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
302 ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */
303 /* then override the ones we care about */
304 ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
305 ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
306 ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
307 ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
308 ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
309 ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
311 ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
312 ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
314 return PR_SUCCESS;
317 # if defined(_PR_INET6_PROBE)
318 PRBool _pr_ipv6_is_present(void) {
319 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) {
320 return PR_FALSE;
322 return ipv6_is_present;
324 # endif
326 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc* fd) {
327 PRFileDesc* ipv6_fd = NULL;
329 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) {
330 return PR_FAILURE;
334 * For platforms with no support for IPv6
335 * create layered socket for IPv4-mapped IPv6 addresses
337 if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
338 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, &ipv6_to_v4_tcpMethods);
339 else
340 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id, &ipv6_to_v4_udpMethods);
341 if (NULL == ipv6_fd) {
342 goto errorExit;
344 ipv6_fd->secret = NULL;
346 if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
347 goto errorExit;
350 return PR_SUCCESS;
351 errorExit:
353 if (ipv6_fd) {
354 ipv6_fd->dtor(ipv6_fd);
356 return PR_FAILURE;
359 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */