Bug 1807268 - Fix verifyOpenAllInNewTabsOptionTest UI test r=ohorvath
[gecko.git] / nsprpub / pr / src / io / pripv6.c
blob1c299652e6cf5ac62c943bdbac76ffd497afc3e0
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)
28 const PRUint8 *srcp;
30 PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
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);
40 dst_v4addr->inet.family = PR_AF_INET;
41 dst_v4addr->inet.port = src_v6addr->ipv6.port;
45 * convert an IPv4 addr to an IPv4-mapped IPv6 addr
47 static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
48 PRNetAddr *dst_v6addr)
50 PRUint8 *dstp;
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;
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);
66 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
67 const PRNetAddr *addr)
69 PRNetAddr tmp_ipv4addr;
70 const PRNetAddr *tmp_addrp;
71 PRFileDesc *lo = fd->lower;
73 if (PR_AF_INET6 != addr->raw.family) {
74 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
75 return PR_FAILURE;
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;
85 return((lo->methods->bind)(lo,tmp_addrp));
88 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
89 PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
91 PRNetAddr tmp_ipv4addr;
92 const PRNetAddr *tmp_addrp;
94 if (PR_AF_INET6 != addr->raw.family) {
95 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
96 return PR_FAILURE;
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;
106 return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
109 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
110 PRFileDesc *fd, const void *buf, PRInt32 amount,
111 PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
113 PRNetAddr tmp_ipv4addr;
114 const PRNetAddr *tmp_addrp;
116 if (PR_AF_INET6 != addr->raw.family) {
117 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
118 return PR_FAILURE;
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;
128 return (fd->lower->methods->sendto)(
129 fd->lower, buf, amount, flags, tmp_addrp, timeout);
132 static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
133 PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
135 PRStatus rv;
136 PRFileDesc *newfd;
137 PRFileDesc *newstack;
138 PRNetAddr tmp_ipv4addr;
139 PRNetAddr *addrlower = NULL;
141 PR_ASSERT(fd != NULL);
142 PR_ASSERT(fd->lower != NULL);
144 newstack = PR_NEW(PRFileDesc);
145 if (NULL == newstack)
147 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
148 return NULL;
150 *newstack = *fd; /* make a copy of the accepting layer */
152 if (addr) {
153 addrlower = &tmp_ipv4addr;
155 newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
156 if (NULL == newfd)
158 PR_DELETE(newstack);
159 return NULL;
161 if (addr) {
162 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
165 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
166 PR_ASSERT(PR_SUCCESS == rv);
167 return newfd; /* that's it */
170 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
171 PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
172 PRIntervalTime timeout)
174 PRInt32 nbytes;
175 PRStatus rv;
176 PRNetAddr tmp_ipv4addr;
177 PRFileDesc *newstack;
179 PR_ASSERT(sd != NULL);
180 PR_ASSERT(sd->lower != NULL);
182 newstack = PR_NEW(PRFileDesc);
183 if (NULL == newstack)
185 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
186 return -1;
188 *newstack = *sd; /* make a copy of the accepting layer */
190 nbytes = sd->lower->methods->acceptread(
191 sd->lower, nd, ipv6_raddr, buf, amount, timeout);
192 if (-1 == nbytes)
194 PR_DELETE(newstack);
195 return nbytes;
197 tmp_ipv4addr = **ipv6_raddr; /* copy */
198 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
200 /* this PR_PushIOLayer call cannot fail */
201 rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
202 PR_ASSERT(PR_SUCCESS == rv);
203 return nbytes;
206 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
207 PRNetAddr *ipv6addr)
209 PRStatus result;
210 PRNetAddr tmp_ipv4addr;
212 result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
213 if (PR_SUCCESS == result) {
214 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
215 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
217 return result;
220 static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
221 PRNetAddr *ipv6addr)
223 PRStatus result;
224 PRNetAddr tmp_ipv4addr;
226 result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
227 if (PR_SUCCESS == result) {
228 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
229 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
231 return result;
234 static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
235 PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
236 PRIntervalTime timeout)
238 PRNetAddr tmp_ipv4addr;
239 PRInt32 result;
241 result = (fd->lower->methods->recvfrom)(
242 fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
243 if (-1 != result) {
244 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
245 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
247 return result;
250 #if defined(_PR_INET6_PROBE)
251 static PRBool ipv6_is_present;
252 PR_EXTERN(PRBool) _pr_test_ipv6_socket(void);
254 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
255 extern PRStatus _pr_find_getipnodebyname(void);
256 #endif
258 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
259 extern PRStatus _pr_find_getaddrinfo(void);
260 #endif
262 static PRBool
263 _pr_probe_ipv6_presence(void)
265 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
266 if (_pr_find_getipnodebyname() != PR_SUCCESS) {
267 return PR_FALSE;
269 #endif
271 #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
272 if (_pr_find_getaddrinfo() != PR_SUCCESS) {
273 return PR_FALSE;
275 #endif
277 return _pr_test_ipv6_socket();
279 #endif /* _PR_INET6_PROBE */
281 static PRCallOnceType _pr_init_ipv6_once;
283 static PRStatus PR_CALLBACK _pr_init_ipv6(void)
285 const PRIOMethods *stubMethods;
287 #if defined(_PR_INET6_PROBE)
288 ipv6_is_present = _pr_probe_ipv6_presence();
289 if (ipv6_is_present) {
290 return PR_SUCCESS;
292 #endif
294 _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
295 PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
297 stubMethods = PR_GetDefaultIOMethods();
299 ipv6_to_v4_tcpMethods = *stubMethods; /* first get the entire batch */
300 /* then override the ones we care about */
301 ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
302 ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
303 ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
304 ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
305 ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
306 ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
308 ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
309 ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
311 ipv6_to_v4_udpMethods = *stubMethods; /* first get the entire batch */
312 /* then override the ones we care about */
313 ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
314 ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
315 ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
316 ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
317 ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
318 ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
320 ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
321 ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
323 return PR_SUCCESS;
326 #if defined(_PR_INET6_PROBE)
327 PRBool _pr_ipv6_is_present(void)
329 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) {
330 return PR_FALSE;
332 return ipv6_is_present;
334 #endif
336 PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
338 PRFileDesc *ipv6_fd = NULL;
340 if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS) {
341 return PR_FAILURE;
345 * For platforms with no support for IPv6
346 * create layered socket for IPv4-mapped IPv6 addresses
348 if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
349 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
350 &ipv6_to_v4_tcpMethods);
351 else
352 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
353 &ipv6_to_v4_udpMethods);
354 if (NULL == ipv6_fd) {
355 goto errorExit;
357 ipv6_fd->secret = NULL;
359 if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
360 goto errorExit;
363 return PR_SUCCESS;
364 errorExit:
366 if (ipv6_fd) {
367 ipv6_fd->dtor(ipv6_fd);
369 return PR_FAILURE;
372 #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */