LCOV - app.info - nsprpub/pr/src/io/pripv6.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/io - pripv6.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 156 | 0 | 0.0 %
| Date: | 2012-04-07 | Functions: | 14 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is the Netscape Portable Runtime (NSPR).
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2000
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *
          24                 :  * Alternatively, the contents of this file may be used under the terms of
          25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          28                 :  * of those above. If you wish to allow use of your version of this file only
          29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          30                 :  * use your version of this file under the terms of the MPL, indicate your
          31                 :  * decision by deleting the provisions above and replace them with the notice
          32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          33                 :  * the provisions above, a recipient may use your version of this file under
          34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          35                 :  *
          36                 :  * ***** END LICENSE BLOCK ***** */
          37                 :
          38                 : /*
          39                 : ** File:        pripv6.c
          40                 : ** Description: Support for various functions unique to IPv6
          41                 : */
          42                 : #include "primpl.h"
          43                 : #include <string.h>
          44                 :
          45                 : #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
          46                 :
          47                 : static PRIOMethods ipv6_to_v4_tcpMethods;
          48                 : static PRIOMethods ipv6_to_v4_udpMethods;
          49                 : static PRDescIdentity _pr_ipv6_to_ipv4_id;
          50                 : extern PRBool IsValidNetAddr(const PRNetAddr *addr);
          51                 : extern PRIPv6Addr _pr_in6addr_any;
          52                 : extern PRIPv6Addr _pr_in6addr_loopback;
          53                 :
          54                 : /*
          55                 :  * convert an IPv4-mapped IPv6 addr to an IPv4 addr
          56                 :  */
          57               0 : static void _PR_ConvertToIpv4NetAddr(const PRNetAddr *src_v6addr,
          58                 :                                                                                         PRNetAddr *dst_v4addr)
          59                 : {
          60                 : const PRUint8 *srcp;
          61                 :
          62               0 :         PR_ASSERT(PR_AF_INET6 == src_v6addr->ipv6.family);
          63                 :
          64               0 :         if (PR_IsNetAddrType(src_v6addr, PR_IpAddrV4Mapped)) {
          65               0 :                 srcp = src_v6addr->ipv6.ip.pr_s6_addr;
          66               0 :                 memcpy((char *) &dst_v4addr->inet.ip, srcp + 12, 4);
          67               0 :     } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrAny)) {
          68               0 :         dst_v4addr->inet.ip = htonl(INADDR_ANY);
          69               0 :     } else if (PR_IsNetAddrType(src_v6addr, PR_IpAddrLoopback)) {
          70               0 :         dst_v4addr->inet.ip = htonl(INADDR_LOOPBACK);
          71                 :     }
          72               0 :         dst_v4addr->inet.family = PR_AF_INET;
          73               0 :         dst_v4addr->inet.port = src_v6addr->ipv6.port;
          74               0 : }
          75                 :
          76                 : /*
          77                 :  * convert an IPv4 addr to an IPv4-mapped IPv6 addr
          78                 :  */
          79               0 : static void _PR_ConvertToIpv6NetAddr(const PRNetAddr *src_v4addr,
          80                 :                                             PRNetAddr *dst_v6addr)
          81                 : {
          82                 : PRUint8 *dstp;
          83                 :
          84               0 :         PR_ASSERT(PR_AF_INET == src_v4addr->inet.family);
          85               0 :         dst_v6addr->ipv6.family = PR_AF_INET6;
          86               0 :         dst_v6addr->ipv6.port = src_v4addr->inet.port;
          87                 :
          88               0 :         if (htonl(INADDR_ANY) == src_v4addr->inet.ip) {
          89               0 :                 dst_v6addr->ipv6.ip = _pr_in6addr_any;
          90                 :         } else {
          91               0 :                 dstp = dst_v6addr->ipv6.ip.pr_s6_addr;
          92               0 :                 memset(dstp, 0, 10);
          93               0 :                 memset(dstp + 10, 0xff, 2);
          94               0 :                 memcpy(dstp + 12,(char *) &src_v4addr->inet.ip, 4);
          95                 :         }
          96               0 : }
          97                 :
          98               0 : static PRStatus PR_CALLBACK Ipv6ToIpv4SocketBind(PRFileDesc *fd,
          99                 :                                                                 const PRNetAddr *addr)
         100                 : {
         101                 :         PRNetAddr tmp_ipv4addr;
         102                 :         const PRNetAddr *tmp_addrp;
         103               0 :         PRFileDesc *lo = fd->lower;
         104                 :
         105               0 :         if (PR_AF_INET6 != addr->raw.family) {
         106               0 :         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
         107               0 :                 return PR_FAILURE;
         108                 :         }
         109               0 :         if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
         110               0 :                         PR_IsNetAddrType(addr, PR_IpAddrAny)) {
         111               0 :                 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
         112               0 :                 tmp_addrp = &tmp_ipv4addr;
         113                 :         } else {
         114               0 :         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
         115               0 :                 return PR_FAILURE;
         116                 :         }
         117               0 :         return((lo->methods->bind)(lo,tmp_addrp));
         118                 : }
         119                 :
         120               0 : static PRStatus PR_CALLBACK Ipv6ToIpv4SocketConnect(
         121                 :     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
         122                 : {
         123                 :         PRNetAddr tmp_ipv4addr;
         124                 :         const PRNetAddr *tmp_addrp;
         125                 :
         126               0 :         if (PR_AF_INET6 != addr->raw.family) {
         127               0 :         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
         128               0 :                 return PR_FAILURE;
         129                 :         }
         130               0 :         if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
         131               0 :                         PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
         132               0 :                 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
         133               0 :                 tmp_addrp = &tmp_ipv4addr;
         134                 :         } else {
         135               0 :         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
         136               0 :                 return PR_FAILURE;
         137                 :         }
         138               0 :         return (fd->lower->methods->connect)(fd->lower, tmp_addrp, timeout);
         139                 : }
         140                 :
         141               0 : static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketSendTo(
         142                 :     PRFileDesc *fd, const void *buf, PRInt32 amount,
         143                 :     PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
         144                 : {
         145                 :         PRNetAddr tmp_ipv4addr;
         146                 :         const PRNetAddr *tmp_addrp;
         147                 :
         148               0 :         if (PR_AF_INET6 != addr->raw.family) {
         149               0 :         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
         150               0 :                 return PR_FAILURE;
         151                 :         }
         152               0 :         if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped) ||
         153               0 :                         PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
         154               0 :                 _PR_ConvertToIpv4NetAddr(addr, &tmp_ipv4addr);
         155               0 :                 tmp_addrp = &tmp_ipv4addr;
         156                 :         } else {
         157               0 :         PR_SetError(PR_NETWORK_UNREACHABLE_ERROR, 0);
         158               0 :                 return PR_FAILURE;
         159                 :         }
         160               0 :     return (fd->lower->methods->sendto)(
         161                 :         fd->lower, buf, amount, flags, tmp_addrp, timeout);
         162                 : }
         163                 :
         164               0 : static PRFileDesc* PR_CALLBACK Ipv6ToIpv4SocketAccept (
         165                 :     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
         166                 : {
         167                 :     PRStatus rv;
         168                 :     PRFileDesc *newfd;
         169                 :     PRFileDesc *newstack;
         170                 :         PRNetAddr tmp_ipv4addr;
         171               0 :     PRNetAddr *addrlower = NULL;
         172                 :
         173               0 :     PR_ASSERT(fd != NULL);
         174               0 :     PR_ASSERT(fd->lower != NULL);
         175                 :
         176               0 :     newstack = PR_NEW(PRFileDesc);
         177               0 :     if (NULL == newstack)
         178                 :     {
         179               0 :         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
         180               0 :         return NULL;
         181                 :     }
         182               0 :     *newstack = *fd;  /* make a copy of the accepting layer */
         183                 :
         184               0 :     if (addr)
         185               0 :         addrlower = &tmp_ipv4addr;
         186               0 :     newfd = (fd->lower->methods->accept)(fd->lower, addrlower, timeout);
         187               0 :     if (NULL == newfd)
         188                 :     {
         189               0 :         PR_DELETE(newstack);
         190               0 :         return NULL;
         191                 :     }
         192               0 :     if (addr)
         193               0 :         _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, addr);
         194                 :
         195               0 :     rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack);
         196               0 :     PR_ASSERT(PR_SUCCESS == rv);
         197               0 :     return newfd;  /* that's it */
         198                 : }
         199                 :
         200               0 : static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketAcceptRead(PRFileDesc *sd,
         201                 :                         PRFileDesc **nd, PRNetAddr **ipv6_raddr, void *buf, PRInt32 amount,
         202                 :                                                         PRIntervalTime timeout)
         203                 : {
         204                 :     PRInt32 nbytes;
         205                 :     PRStatus rv;
         206                 :         PRNetAddr tmp_ipv4addr;
         207                 :     PRFileDesc *newstack;
         208                 :
         209               0 :     PR_ASSERT(sd != NULL);
         210               0 :     PR_ASSERT(sd->lower != NULL);
         211                 :
         212               0 :     newstack = PR_NEW(PRFileDesc);
         213               0 :     if (NULL == newstack)
         214                 :     {
         215               0 :         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
         216               0 :         return -1;
         217                 :     }
         218               0 :     *newstack = *sd;  /* make a copy of the accepting layer */
         219                 :
         220               0 :     nbytes = sd->lower->methods->acceptread(
         221                 :         sd->lower, nd, ipv6_raddr, buf, amount, timeout);
         222               0 :     if (-1 == nbytes)
         223                 :     {
         224               0 :         PR_DELETE(newstack);
         225               0 :         return nbytes;
         226                 :     }
         227               0 :         tmp_ipv4addr = **ipv6_raddr;    /* copy */
         228               0 :         _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, *ipv6_raddr);
         229                 :
         230                 :     /* this PR_PushIOLayer call cannot fail */
         231               0 :     rv = PR_PushIOLayer(*nd, PR_TOP_IO_LAYER, newstack);
         232               0 :     PR_ASSERT(PR_SUCCESS == rv);
         233               0 :     return nbytes;
         234                 : }
         235                 :
         236               0 : static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetName(PRFileDesc *fd,
         237                 :                                                                                 PRNetAddr *ipv6addr)
         238                 : {
         239                 :         PRStatus result;
         240                 :         PRNetAddr tmp_ipv4addr;
         241                 :
         242               0 :         result = (fd->lower->methods->getsockname)(fd->lower, &tmp_ipv4addr);
         243               0 :         if (PR_SUCCESS == result) {
         244               0 :                 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
         245               0 :                 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
         246                 :         }
         247               0 :         return result;
         248                 : }
         249                 :
         250               0 : static PRStatus PR_CALLBACK Ipv6ToIpv4SocketGetPeerName(PRFileDesc *fd,
         251                 :                                                                                 PRNetAddr *ipv6addr)
         252                 : {
         253                 :         PRStatus result;
         254                 :         PRNetAddr tmp_ipv4addr;
         255                 :
         256               0 :         result = (fd->lower->methods->getpeername)(fd->lower, &tmp_ipv4addr);
         257               0 :         if (PR_SUCCESS == result) {
         258               0 :                 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
         259               0 :                 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
         260                 :         }
         261               0 :         return result;
         262                 : }
         263                 :
         264               0 : static PRInt32 PR_CALLBACK Ipv6ToIpv4SocketRecvFrom(PRFileDesc *fd, void *buf,
         265                 :                         PRInt32 amount, PRIntn flags, PRNetAddr *ipv6addr,
         266                 :                                 PRIntervalTime timeout)
         267                 : {
         268                 :         PRNetAddr tmp_ipv4addr;
         269                 :         PRInt32 result;
         270                 :
         271               0 :     result = (fd->lower->methods->recvfrom)(
         272                 :         fd->lower, buf, amount, flags, &tmp_ipv4addr, timeout);
         273               0 :         if (-1 != result) {
         274               0 :                 _PR_ConvertToIpv6NetAddr(&tmp_ipv4addr, ipv6addr);
         275               0 :                 PR_ASSERT(IsValidNetAddr(ipv6addr) == PR_TRUE);
         276                 :         }
         277               0 :         return result;
         278                 : }
         279                 :
         280                 : #if defined(_PR_INET6_PROBE)
         281                 : static PRBool ipv6_is_present;
         282                 : extern PRBool _pr_test_ipv6_socket(void);
         283                 :
         284                 : #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
         285                 : extern PRStatus _pr_find_getipnodebyname(void);
         286                 : #endif
         287                 :
         288                 : #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
         289                 : extern PRStatus _pr_find_getaddrinfo(void);
         290                 : #endif
         291                 :
         292                 : static PRBool
         293               0 : _pr_probe_ipv6_presence(void)
         294                 : {
         295                 : #if !defined(_PR_INET6) && defined(_PR_HAVE_GETIPNODEBYNAME)
         296                 :     if (_pr_find_getipnodebyname() != PR_SUCCESS)
         297                 :         return PR_FALSE;
         298                 : #endif
         299                 :
         300                 : #if !defined(_PR_INET6) && defined(_PR_HAVE_GETADDRINFO)
         301                 :     if (_pr_find_getaddrinfo() != PR_SUCCESS)
         302                 :         return PR_FALSE;
         303                 : #endif
         304                 :
         305               0 :     return _pr_test_ipv6_socket();
         306                 : }
         307                 : #endif  /* _PR_INET6_PROBE */
         308                 :
         309                 : static PRCallOnceType _pr_init_ipv6_once;
         310                 :
         311               0 : static PRStatus PR_CALLBACK _pr_init_ipv6(void)
         312                 : {
         313                 :     const PRIOMethods *stubMethods;
         314                 :
         315                 : #if defined(_PR_INET6_PROBE)
         316               0 :     ipv6_is_present = _pr_probe_ipv6_presence();
         317               0 :     if (ipv6_is_present)
         318               0 :         return PR_SUCCESS;
         319                 : #endif
         320                 :
         321               0 :     _pr_ipv6_to_ipv4_id = PR_GetUniqueIdentity("Ipv6_to_Ipv4 layer");
         322               0 :     PR_ASSERT(PR_INVALID_IO_LAYER != _pr_ipv6_to_ipv4_id);
         323                 :
         324               0 :         stubMethods = PR_GetDefaultIOMethods();
         325                 :
         326               0 :         ipv6_to_v4_tcpMethods = *stubMethods;  /* first get the entire batch */
         327                 :         /* then override the ones we care about */
         328               0 :         ipv6_to_v4_tcpMethods.connect = Ipv6ToIpv4SocketConnect;
         329               0 :         ipv6_to_v4_tcpMethods.bind = Ipv6ToIpv4SocketBind;
         330               0 :         ipv6_to_v4_tcpMethods.accept = Ipv6ToIpv4SocketAccept;
         331               0 :         ipv6_to_v4_tcpMethods.acceptread = Ipv6ToIpv4SocketAcceptRead;
         332               0 :         ipv6_to_v4_tcpMethods.getsockname = Ipv6ToIpv4SocketGetName;
         333               0 :         ipv6_to_v4_tcpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
         334                 : /*
         335                 :         ipv6_to_v4_tcpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
         336                 :         ipv6_to_v4_tcpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
         337                 : */
         338               0 :         ipv6_to_v4_udpMethods = *stubMethods;  /* first get the entire batch */
         339                 :         /* then override the ones we care about */
         340               0 :         ipv6_to_v4_udpMethods.connect = Ipv6ToIpv4SocketConnect;
         341               0 :         ipv6_to_v4_udpMethods.bind = Ipv6ToIpv4SocketBind;
         342               0 :         ipv6_to_v4_udpMethods.sendto = Ipv6ToIpv4SocketSendTo;
         343               0 :         ipv6_to_v4_udpMethods.recvfrom = Ipv6ToIpv4SocketRecvFrom;
         344               0 :         ipv6_to_v4_udpMethods.getsockname = Ipv6ToIpv4SocketGetName;
         345               0 :         ipv6_to_v4_udpMethods.getpeername = Ipv6ToIpv4SocketGetPeerName;
         346                 : /*
         347                 :         ipv6_to_v4_udpMethods.getsocketoption = Ipv6ToIpv4GetSocketOption;
         348                 :         ipv6_to_v4_udpMethods.setsocketoption = Ipv6ToIpv4SetSocketOption;
         349                 : */
         350               0 :         return PR_SUCCESS;
         351                 : }
         352                 :
         353                 : #if defined(_PR_INET6_PROBE)
         354               0 : PRBool _pr_ipv6_is_present(void)
         355                 : {
         356               0 :     if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
         357               0 :         return PR_FALSE;
         358               0 :     return ipv6_is_present;
         359                 : }
         360                 : #endif
         361                 :
         362               0 : PR_IMPLEMENT(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd)
         363                 : {
         364               0 :         PRFileDesc *ipv6_fd = NULL;
         365                 :
         366               0 :         if (PR_CallOnce(&_pr_init_ipv6_once, _pr_init_ipv6) != PR_SUCCESS)
         367               0 :                 return PR_FAILURE;
         368                 :
         369                 :         /*
         370                 :          * For platforms with no support for IPv6
         371                 :          * create layered socket for IPv4-mapped IPv6 addresses
         372                 :          */
         373               0 :         if (fd->methods->file_type == PR_DESC_SOCKET_TCP)
         374               0 :                 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
         375                 :                                                                         &ipv6_to_v4_tcpMethods);
         376                 :         else
         377               0 :                 ipv6_fd = PR_CreateIOLayerStub(_pr_ipv6_to_ipv4_id,
         378                 :                                                                         &ipv6_to_v4_udpMethods);
         379               0 :         if (NULL == ipv6_fd) {
         380               0 :                 goto errorExit;
         381                 :         }
         382               0 :         ipv6_fd->secret = NULL;
         383                 :
         384               0 :         if (PR_PushIOLayer(fd, PR_TOP_IO_LAYER, ipv6_fd) == PR_FAILURE) {
         385               0 :                 goto errorExit;
         386                 :         }
         387                 :
         388               0 :         return PR_SUCCESS;
         389                 : errorExit:
         390                 :
         391               0 :         if (ipv6_fd)
         392               0 :                 ipv6_fd->dtor(ipv6_fd);
         393               0 :         return PR_FAILURE;
         394                 : }
         395                 :
         396                 : #endif /* !defined(_PR_INET6) || defined(_PR_INET6_PROBE) */

Generated by: LCOV version 1.7