nsprpub/pr/src/io/prmapopt.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  * This file defines _PR_MapOptionName().  The purpose of putting
     8  * _PR_MapOptionName() in a separate file is to work around a Winsock
     9  * header file problem on Windows NT.
    10  *
    11  * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
    12  * to use Service Pack 3 extensions), windows.h includes winsock2.h
    13  * (instead of winsock.h), which doesn't define many socket options
    14  * defined in winsock.h.
    15  *
    16  * We need the socket options defined in winsock.h.  So this file
    17  * includes winsock.h, with _WIN32_WINNT undefined.
    18  */
    20 #if defined(WINNT) || defined(__MINGW32__)
    21 #include <winsock.h>
    22 #endif
    24 /* MinGW doesn't define these in its winsock.h. */
    25 #ifdef __MINGW32__
    26 #ifndef IP_TTL
    27 #define IP_TTL 7
    28 #endif
    29 #ifndef IP_TOS
    30 #define IP_TOS 8
    31 #endif
    32 #endif
    34 #include "primpl.h"
    36 #ifdef HAVE_NETINET_TCP_H
    37 #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
    38 #endif
    40 #ifndef _PR_PTHREADS
    42 PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
    43 {
    44     PRStatus rv;
    45     PRInt32 length;
    46     PRInt32 level, name;
    48     /*
    49      * PR_SockOpt_Nonblocking is a special case that does not
    50      * translate to a getsockopt() call
    51      */
    52     if (PR_SockOpt_Nonblocking == data->option)
    53     {
    54         data->value.non_blocking = fd->secret->nonblocking;
    55         return PR_SUCCESS;
    56     }
    58     rv = _PR_MapOptionName(data->option, &level, &name);
    59     if (PR_SUCCESS == rv)
    60     {
    61         switch (data->option)
    62         {
    63             case PR_SockOpt_Linger:
    64             {
    65 #if !defined(XP_BEOS) || defined(BONE_VERSION)
    66                 struct linger linger;
    67                 length = sizeof(linger);
    68                 rv = _PR_MD_GETSOCKOPT(
    69                     fd, level, name, (char *) &linger, &length);
    70                 if (PR_SUCCESS == rv)
    71                 {
    72                     PR_ASSERT(sizeof(linger) == length);
    73                     data->value.linger.polarity =
    74                         (linger.l_onoff) ? PR_TRUE : PR_FALSE;
    75                     data->value.linger.linger =
    76                         PR_SecondsToInterval(linger.l_linger);
    77                 }
    78                 break;
    79 #else
    80                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
    81                 return PR_FAILURE;
    82 #endif
    83             }
    84             case PR_SockOpt_Reuseaddr:
    85             case PR_SockOpt_Keepalive:
    86             case PR_SockOpt_NoDelay:
    87             case PR_SockOpt_Broadcast:
    88             case PR_SockOpt_Reuseport:
    89             {
    90 #ifdef WIN32 /* Winsock */
    91                 BOOL value;
    92 #else
    93                 PRIntn value;
    94 #endif
    95                 length = sizeof(value);
    96                 rv = _PR_MD_GETSOCKOPT(
    97                     fd, level, name, (char*)&value, &length);
    98                 if (PR_SUCCESS == rv)
    99                     data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
   100                 break;
   101             }
   102             case PR_SockOpt_McastLoopback:
   103             {
   104 #ifdef WIN32 /* Winsock */
   105                 BOOL bool;
   106 #else
   107                 PRUint8 bool;
   108 #endif
   109                 length = sizeof(bool);
   110                 rv = _PR_MD_GETSOCKOPT(
   111                     fd, level, name, (char*)&bool, &length);
   112                 if (PR_SUCCESS == rv)
   113                     data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
   114                 break;
   115             }
   116             case PR_SockOpt_RecvBufferSize:
   117             case PR_SockOpt_SendBufferSize:
   118             case PR_SockOpt_MaxSegment:
   119             {
   120                 PRIntn value;
   121                 length = sizeof(value);
   122                 rv = _PR_MD_GETSOCKOPT(
   123                     fd, level, name, (char*)&value, &length);
   124                 if (PR_SUCCESS == rv)
   125                     data->value.recv_buffer_size = value;
   126                 break;
   127             }
   128             case PR_SockOpt_IpTimeToLive:
   129             case PR_SockOpt_IpTypeOfService:
   130             {
   131                 /* These options should really be an int (or PRIntn). */
   132                 length = sizeof(PRUintn);
   133                 rv = _PR_MD_GETSOCKOPT(
   134                     fd, level, name, (char*)&data->value.ip_ttl, &length);
   135                 break;
   136             }
   137             case PR_SockOpt_McastTimeToLive:
   138             {
   139 #ifdef WIN32 /* Winsock */
   140                 int ttl;
   141 #else
   142                 PRUint8 ttl;
   143 #endif
   144                 length = sizeof(ttl);
   145                 rv = _PR_MD_GETSOCKOPT(
   146                     fd, level, name, (char*)&ttl, &length);
   147                 if (PR_SUCCESS == rv)
   148                     data->value.mcast_ttl = ttl;
   149                 break;
   150             }
   151 #ifdef IP_ADD_MEMBERSHIP
   152             case PR_SockOpt_AddMember:
   153             case PR_SockOpt_DropMember:
   154             {
   155                 struct ip_mreq mreq;
   156                 length = sizeof(mreq);
   157                 rv = _PR_MD_GETSOCKOPT(
   158                     fd, level, name, (char*)&mreq, &length);
   159                 if (PR_SUCCESS == rv)
   160                 {
   161                     data->value.add_member.mcaddr.inet.ip =
   162                         mreq.imr_multiaddr.s_addr;
   163                     data->value.add_member.ifaddr.inet.ip =
   164                         mreq.imr_interface.s_addr;
   165                 }
   166                 break;
   167             }
   168 #endif /* IP_ADD_MEMBERSHIP */
   169             case PR_SockOpt_McastInterface:
   170             {
   171                 /* This option is a struct in_addr. */
   172                 length = sizeof(data->value.mcast_if.inet.ip);
   173                 rv = _PR_MD_GETSOCKOPT(
   174                     fd, level, name,
   175                     (char*)&data->value.mcast_if.inet.ip, &length);
   176                 break;
   177             }
   178             default:
   179                 PR_NOT_REACHED("Unknown socket option");
   180                 break;
   181         }  
   182     }
   183     return rv;
   184 }  /* _PR_SocketGetSocketOption */
   186 PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
   187 {
   188     PRStatus rv;
   189     PRInt32 level, name;
   191     /*
   192      * PR_SockOpt_Nonblocking is a special case that does not
   193      * translate to a setsockopt call.
   194      */
   195     if (PR_SockOpt_Nonblocking == data->option)
   196     {
   197 #ifdef WINNT
   198         PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
   199             || (fd->secret->nonblocking == data->value.non_blocking));
   200         if (fd->secret->md.io_model_committed
   201             && (fd->secret->nonblocking != data->value.non_blocking))
   202         {
   203             /*
   204              * On NT, once we have associated a socket with the io
   205              * completion port, we can't disassociate it.  So we
   206              * can't change the nonblocking option of the socket
   207              * afterwards.
   208              */
   209             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   210             return PR_FAILURE;
   211         }
   212 #endif
   213         fd->secret->nonblocking = data->value.non_blocking;
   214         return PR_SUCCESS;
   215     }
   217     rv = _PR_MapOptionName(data->option, &level, &name);
   218     if (PR_SUCCESS == rv)
   219     {
   220         switch (data->option)
   221         {
   222             case PR_SockOpt_Linger:
   223             {
   224 #if !defined(XP_BEOS) || defined(BONE_VERSION)
   225                 struct linger linger;
   226                 linger.l_onoff = data->value.linger.polarity;
   227                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
   228                 rv = _PR_MD_SETSOCKOPT(
   229                     fd, level, name, (char*)&linger, sizeof(linger));
   230                 break;
   231 #else
   232                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
   233                 return PR_FAILURE;
   234 #endif
   235             }
   236             case PR_SockOpt_Reuseaddr:
   237             case PR_SockOpt_Keepalive:
   238             case PR_SockOpt_NoDelay:
   239             case PR_SockOpt_Broadcast:
   240             case PR_SockOpt_Reuseport:
   241             {
   242 #ifdef WIN32 /* Winsock */
   243                 BOOL value;
   244 #else
   245                 PRIntn value;
   246 #endif
   247                 value = (data->value.reuse_addr) ? 1 : 0;
   248                 rv = _PR_MD_SETSOCKOPT(
   249                     fd, level, name, (char*)&value, sizeof(value));
   250                 break;
   251             }
   252             case PR_SockOpt_McastLoopback:
   253             {
   254 #ifdef WIN32 /* Winsock */
   255                 BOOL bool;
   256 #else
   257                 PRUint8 bool;
   258 #endif
   259                 bool = data->value.mcast_loopback ? 1 : 0;
   260                 rv = _PR_MD_SETSOCKOPT(
   261                     fd, level, name, (char*)&bool, sizeof(bool));
   262                 break;
   263             }
   264             case PR_SockOpt_RecvBufferSize:
   265             case PR_SockOpt_SendBufferSize:
   266             case PR_SockOpt_MaxSegment:
   267             {
   268                 PRIntn value = data->value.recv_buffer_size;
   269                 rv = _PR_MD_SETSOCKOPT(
   270                     fd, level, name, (char*)&value, sizeof(value));
   271                 break;
   272             }
   273             case PR_SockOpt_IpTimeToLive:
   274             case PR_SockOpt_IpTypeOfService:
   275             {
   276                 /* These options should really be an int (or PRIntn). */
   277                 rv = _PR_MD_SETSOCKOPT(
   278                     fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
   279                 break;
   280             }
   281             case PR_SockOpt_McastTimeToLive:
   282             {
   283 #ifdef WIN32 /* Winsock */
   284                 int ttl;
   285 #else
   286                 PRUint8 ttl;
   287 #endif
   288                 ttl = data->value.mcast_ttl;
   289                 rv = _PR_MD_SETSOCKOPT(
   290                     fd, level, name, (char*)&ttl, sizeof(ttl));
   291                 break;
   292             }
   293 #ifdef IP_ADD_MEMBERSHIP
   294             case PR_SockOpt_AddMember:
   295             case PR_SockOpt_DropMember:
   296             {
   297                 struct ip_mreq mreq;
   298                 mreq.imr_multiaddr.s_addr =
   299                     data->value.add_member.mcaddr.inet.ip;
   300                 mreq.imr_interface.s_addr =
   301                     data->value.add_member.ifaddr.inet.ip;
   302                 rv = _PR_MD_SETSOCKOPT(
   303                     fd, level, name, (char*)&mreq, sizeof(mreq));
   304                 break;
   305             }
   306 #endif /* IP_ADD_MEMBERSHIP */
   307             case PR_SockOpt_McastInterface:
   308             {
   309                 /* This option is a struct in_addr. */
   310                 rv = _PR_MD_SETSOCKOPT(
   311                     fd, level, name, (char*)&data->value.mcast_if.inet.ip,
   312                     sizeof(data->value.mcast_if.inet.ip));
   313                 break;
   314             }
   315             default:
   316                 PR_NOT_REACHED("Unknown socket option");
   317                 break;
   318         }  
   319     }
   320     return rv;
   321 }  /* _PR_SocketSetSocketOption */
   323 #endif /* ! _PR_PTHREADS */
   325 /*
   326  *********************************************************************
   327  *********************************************************************
   328  **
   329  ** Make sure that the following is at the end of this file,
   330  ** because we will be playing with macro redefines.
   331  **
   332  *********************************************************************
   333  *********************************************************************
   334  */
   336 /*
   337  * Not every platform has all the socket options we want to
   338  * support.  Some older operating systems such as SunOS 4.1.3
   339  * don't have the IP multicast socket options.  Win32 doesn't
   340  * have TCP_MAXSEG.
   341  *
   342  * To deal with this problem, we define the missing socket
   343  * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
   344  * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
   345  * available on the platform is requested.
   346  */
   348 /*
   349  * Sanity check.  SO_LINGER and TCP_NODELAY should be available
   350  * on all platforms.  Just to make sure we have included the
   351  * appropriate header files.  Then any undefined socket options
   352  * are really missing.
   353  */
   355 #if !defined(SO_LINGER)
   356 #error "SO_LINGER is not defined"
   357 #endif
   359 #if !defined(TCP_NODELAY)
   360 #error "TCP_NODELAY is not defined"
   361 #endif
   363 /*
   364  * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
   365  * a valid socket option.
   366  */
   367 #define _PR_NO_SUCH_SOCKOPT -1
   369 #ifndef SO_KEEPALIVE
   370 #define SO_KEEPALIVE        _PR_NO_SUCH_SOCKOPT
   371 #endif
   373 #ifndef SO_SNDBUF
   374 #define SO_SNDBUF           _PR_NO_SUCH_SOCKOPT
   375 #endif
   377 #ifndef SO_RCVBUF
   378 #define SO_RCVBUF           _PR_NO_SUCH_SOCKOPT
   379 #endif
   381 #ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
   382 #define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
   383 #endif
   385 #ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
   386 #define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
   387 #endif
   389 #ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
   390 #define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
   391 #endif
   393 #ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
   394 #define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
   395 #endif
   397 #ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
   398 #define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
   399 #endif
   401 #ifndef IP_TTL                          /* set/get IP Time To Live          */
   402 #define IP_TTL              _PR_NO_SUCH_SOCKOPT
   403 #endif
   405 #ifndef IP_TOS                          /* set/get IP Type Of Service       */
   406 #define IP_TOS              _PR_NO_SUCH_SOCKOPT
   407 #endif
   409 #ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
   410 #define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
   411 #endif
   413 #ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
   414 #define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
   415 #endif
   417 #ifndef SO_BROADCAST                    /* enable broadcast on UDP sockets  */
   418 #define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
   419 #endif
   421 #ifndef SO_REUSEPORT                    /* allow local address & port reuse */
   422 #define SO_REUSEPORT        _PR_NO_SUCH_SOCKOPT
   423 #endif
   425 PRStatus _PR_MapOptionName(
   426     PRSockOption optname, PRInt32 *level, PRInt32 *name)
   427 {
   428     static PRInt32 socketOptions[PR_SockOpt_Last] =
   429     {
   430         0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
   431         IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
   432         IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
   433         TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT
   434     };
   435     static PRInt32 socketLevels[PR_SockOpt_Last] =
   436     {
   437         0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
   438         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
   439         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
   440         IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET
   441     };
   443     if ((optname < PR_SockOpt_Linger)
   444     || (optname >= PR_SockOpt_Last))
   445     {
   446         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   447         return PR_FAILURE;
   448     }
   450     if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
   451     {
   452         PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
   453         return PR_FAILURE;
   454     }
   455     *name = socketOptions[optname];
   456     *level = socketLevels[optname];
   457     return PR_SUCCESS;
   458 }  /* _PR_MapOptionName */

mercurial