nsprpub/pr/src/io/prmapopt.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/io/prmapopt.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,458 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * This file defines _PR_MapOptionName().  The purpose of putting
    1.11 + * _PR_MapOptionName() in a separate file is to work around a Winsock
    1.12 + * header file problem on Windows NT.
    1.13 + *
    1.14 + * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
    1.15 + * to use Service Pack 3 extensions), windows.h includes winsock2.h
    1.16 + * (instead of winsock.h), which doesn't define many socket options
    1.17 + * defined in winsock.h.
    1.18 + *
    1.19 + * We need the socket options defined in winsock.h.  So this file
    1.20 + * includes winsock.h, with _WIN32_WINNT undefined.
    1.21 + */
    1.22 +
    1.23 +#if defined(WINNT) || defined(__MINGW32__)
    1.24 +#include <winsock.h>
    1.25 +#endif
    1.26 +
    1.27 +/* MinGW doesn't define these in its winsock.h. */
    1.28 +#ifdef __MINGW32__
    1.29 +#ifndef IP_TTL
    1.30 +#define IP_TTL 7
    1.31 +#endif
    1.32 +#ifndef IP_TOS
    1.33 +#define IP_TOS 8
    1.34 +#endif
    1.35 +#endif
    1.36 +
    1.37 +#include "primpl.h"
    1.38 +
    1.39 +#ifdef HAVE_NETINET_TCP_H
    1.40 +#include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
    1.41 +#endif
    1.42 +
    1.43 +#ifndef _PR_PTHREADS
    1.44 +
    1.45 +PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
    1.46 +{
    1.47 +    PRStatus rv;
    1.48 +    PRInt32 length;
    1.49 +    PRInt32 level, name;
    1.50 +
    1.51 +    /*
    1.52 +     * PR_SockOpt_Nonblocking is a special case that does not
    1.53 +     * translate to a getsockopt() call
    1.54 +     */
    1.55 +    if (PR_SockOpt_Nonblocking == data->option)
    1.56 +    {
    1.57 +        data->value.non_blocking = fd->secret->nonblocking;
    1.58 +        return PR_SUCCESS;
    1.59 +    }
    1.60 +
    1.61 +    rv = _PR_MapOptionName(data->option, &level, &name);
    1.62 +    if (PR_SUCCESS == rv)
    1.63 +    {
    1.64 +        switch (data->option)
    1.65 +        {
    1.66 +            case PR_SockOpt_Linger:
    1.67 +            {
    1.68 +#if !defined(XP_BEOS) || defined(BONE_VERSION)
    1.69 +                struct linger linger;
    1.70 +                length = sizeof(linger);
    1.71 +                rv = _PR_MD_GETSOCKOPT(
    1.72 +                    fd, level, name, (char *) &linger, &length);
    1.73 +                if (PR_SUCCESS == rv)
    1.74 +                {
    1.75 +                    PR_ASSERT(sizeof(linger) == length);
    1.76 +                    data->value.linger.polarity =
    1.77 +                        (linger.l_onoff) ? PR_TRUE : PR_FALSE;
    1.78 +                    data->value.linger.linger =
    1.79 +                        PR_SecondsToInterval(linger.l_linger);
    1.80 +                }
    1.81 +                break;
    1.82 +#else
    1.83 +                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
    1.84 +                return PR_FAILURE;
    1.85 +#endif
    1.86 +            }
    1.87 +            case PR_SockOpt_Reuseaddr:
    1.88 +            case PR_SockOpt_Keepalive:
    1.89 +            case PR_SockOpt_NoDelay:
    1.90 +            case PR_SockOpt_Broadcast:
    1.91 +            case PR_SockOpt_Reuseport:
    1.92 +            {
    1.93 +#ifdef WIN32 /* Winsock */
    1.94 +                BOOL value;
    1.95 +#else
    1.96 +                PRIntn value;
    1.97 +#endif
    1.98 +                length = sizeof(value);
    1.99 +                rv = _PR_MD_GETSOCKOPT(
   1.100 +                    fd, level, name, (char*)&value, &length);
   1.101 +                if (PR_SUCCESS == rv)
   1.102 +                    data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
   1.103 +                break;
   1.104 +            }
   1.105 +            case PR_SockOpt_McastLoopback:
   1.106 +            {
   1.107 +#ifdef WIN32 /* Winsock */
   1.108 +                BOOL bool;
   1.109 +#else
   1.110 +                PRUint8 bool;
   1.111 +#endif
   1.112 +                length = sizeof(bool);
   1.113 +                rv = _PR_MD_GETSOCKOPT(
   1.114 +                    fd, level, name, (char*)&bool, &length);
   1.115 +                if (PR_SUCCESS == rv)
   1.116 +                    data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
   1.117 +                break;
   1.118 +            }
   1.119 +            case PR_SockOpt_RecvBufferSize:
   1.120 +            case PR_SockOpt_SendBufferSize:
   1.121 +            case PR_SockOpt_MaxSegment:
   1.122 +            {
   1.123 +                PRIntn value;
   1.124 +                length = sizeof(value);
   1.125 +                rv = _PR_MD_GETSOCKOPT(
   1.126 +                    fd, level, name, (char*)&value, &length);
   1.127 +                if (PR_SUCCESS == rv)
   1.128 +                    data->value.recv_buffer_size = value;
   1.129 +                break;
   1.130 +            }
   1.131 +            case PR_SockOpt_IpTimeToLive:
   1.132 +            case PR_SockOpt_IpTypeOfService:
   1.133 +            {
   1.134 +                /* These options should really be an int (or PRIntn). */
   1.135 +                length = sizeof(PRUintn);
   1.136 +                rv = _PR_MD_GETSOCKOPT(
   1.137 +                    fd, level, name, (char*)&data->value.ip_ttl, &length);
   1.138 +                break;
   1.139 +            }
   1.140 +            case PR_SockOpt_McastTimeToLive:
   1.141 +            {
   1.142 +#ifdef WIN32 /* Winsock */
   1.143 +                int ttl;
   1.144 +#else
   1.145 +                PRUint8 ttl;
   1.146 +#endif
   1.147 +                length = sizeof(ttl);
   1.148 +                rv = _PR_MD_GETSOCKOPT(
   1.149 +                    fd, level, name, (char*)&ttl, &length);
   1.150 +                if (PR_SUCCESS == rv)
   1.151 +                    data->value.mcast_ttl = ttl;
   1.152 +                break;
   1.153 +            }
   1.154 +#ifdef IP_ADD_MEMBERSHIP
   1.155 +            case PR_SockOpt_AddMember:
   1.156 +            case PR_SockOpt_DropMember:
   1.157 +            {
   1.158 +                struct ip_mreq mreq;
   1.159 +                length = sizeof(mreq);
   1.160 +                rv = _PR_MD_GETSOCKOPT(
   1.161 +                    fd, level, name, (char*)&mreq, &length);
   1.162 +                if (PR_SUCCESS == rv)
   1.163 +                {
   1.164 +                    data->value.add_member.mcaddr.inet.ip =
   1.165 +                        mreq.imr_multiaddr.s_addr;
   1.166 +                    data->value.add_member.ifaddr.inet.ip =
   1.167 +                        mreq.imr_interface.s_addr;
   1.168 +                }
   1.169 +                break;
   1.170 +            }
   1.171 +#endif /* IP_ADD_MEMBERSHIP */
   1.172 +            case PR_SockOpt_McastInterface:
   1.173 +            {
   1.174 +                /* This option is a struct in_addr. */
   1.175 +                length = sizeof(data->value.mcast_if.inet.ip);
   1.176 +                rv = _PR_MD_GETSOCKOPT(
   1.177 +                    fd, level, name,
   1.178 +                    (char*)&data->value.mcast_if.inet.ip, &length);
   1.179 +                break;
   1.180 +            }
   1.181 +            default:
   1.182 +                PR_NOT_REACHED("Unknown socket option");
   1.183 +                break;
   1.184 +        }  
   1.185 +    }
   1.186 +    return rv;
   1.187 +}  /* _PR_SocketGetSocketOption */
   1.188 +
   1.189 +PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
   1.190 +{
   1.191 +    PRStatus rv;
   1.192 +    PRInt32 level, name;
   1.193 +
   1.194 +    /*
   1.195 +     * PR_SockOpt_Nonblocking is a special case that does not
   1.196 +     * translate to a setsockopt call.
   1.197 +     */
   1.198 +    if (PR_SockOpt_Nonblocking == data->option)
   1.199 +    {
   1.200 +#ifdef WINNT
   1.201 +        PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
   1.202 +            || (fd->secret->nonblocking == data->value.non_blocking));
   1.203 +        if (fd->secret->md.io_model_committed
   1.204 +            && (fd->secret->nonblocking != data->value.non_blocking))
   1.205 +        {
   1.206 +            /*
   1.207 +             * On NT, once we have associated a socket with the io
   1.208 +             * completion port, we can't disassociate it.  So we
   1.209 +             * can't change the nonblocking option of the socket
   1.210 +             * afterwards.
   1.211 +             */
   1.212 +            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.213 +            return PR_FAILURE;
   1.214 +        }
   1.215 +#endif
   1.216 +        fd->secret->nonblocking = data->value.non_blocking;
   1.217 +        return PR_SUCCESS;
   1.218 +    }
   1.219 +
   1.220 +    rv = _PR_MapOptionName(data->option, &level, &name);
   1.221 +    if (PR_SUCCESS == rv)
   1.222 +    {
   1.223 +        switch (data->option)
   1.224 +        {
   1.225 +            case PR_SockOpt_Linger:
   1.226 +            {
   1.227 +#if !defined(XP_BEOS) || defined(BONE_VERSION)
   1.228 +                struct linger linger;
   1.229 +                linger.l_onoff = data->value.linger.polarity;
   1.230 +                linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
   1.231 +                rv = _PR_MD_SETSOCKOPT(
   1.232 +                    fd, level, name, (char*)&linger, sizeof(linger));
   1.233 +                break;
   1.234 +#else
   1.235 +                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
   1.236 +                return PR_FAILURE;
   1.237 +#endif
   1.238 +            }
   1.239 +            case PR_SockOpt_Reuseaddr:
   1.240 +            case PR_SockOpt_Keepalive:
   1.241 +            case PR_SockOpt_NoDelay:
   1.242 +            case PR_SockOpt_Broadcast:
   1.243 +            case PR_SockOpt_Reuseport:
   1.244 +            {
   1.245 +#ifdef WIN32 /* Winsock */
   1.246 +                BOOL value;
   1.247 +#else
   1.248 +                PRIntn value;
   1.249 +#endif
   1.250 +                value = (data->value.reuse_addr) ? 1 : 0;
   1.251 +                rv = _PR_MD_SETSOCKOPT(
   1.252 +                    fd, level, name, (char*)&value, sizeof(value));
   1.253 +                break;
   1.254 +            }
   1.255 +            case PR_SockOpt_McastLoopback:
   1.256 +            {
   1.257 +#ifdef WIN32 /* Winsock */
   1.258 +                BOOL bool;
   1.259 +#else
   1.260 +                PRUint8 bool;
   1.261 +#endif
   1.262 +                bool = data->value.mcast_loopback ? 1 : 0;
   1.263 +                rv = _PR_MD_SETSOCKOPT(
   1.264 +                    fd, level, name, (char*)&bool, sizeof(bool));
   1.265 +                break;
   1.266 +            }
   1.267 +            case PR_SockOpt_RecvBufferSize:
   1.268 +            case PR_SockOpt_SendBufferSize:
   1.269 +            case PR_SockOpt_MaxSegment:
   1.270 +            {
   1.271 +                PRIntn value = data->value.recv_buffer_size;
   1.272 +                rv = _PR_MD_SETSOCKOPT(
   1.273 +                    fd, level, name, (char*)&value, sizeof(value));
   1.274 +                break;
   1.275 +            }
   1.276 +            case PR_SockOpt_IpTimeToLive:
   1.277 +            case PR_SockOpt_IpTypeOfService:
   1.278 +            {
   1.279 +                /* These options should really be an int (or PRIntn). */
   1.280 +                rv = _PR_MD_SETSOCKOPT(
   1.281 +                    fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
   1.282 +                break;
   1.283 +            }
   1.284 +            case PR_SockOpt_McastTimeToLive:
   1.285 +            {
   1.286 +#ifdef WIN32 /* Winsock */
   1.287 +                int ttl;
   1.288 +#else
   1.289 +                PRUint8 ttl;
   1.290 +#endif
   1.291 +                ttl = data->value.mcast_ttl;
   1.292 +                rv = _PR_MD_SETSOCKOPT(
   1.293 +                    fd, level, name, (char*)&ttl, sizeof(ttl));
   1.294 +                break;
   1.295 +            }
   1.296 +#ifdef IP_ADD_MEMBERSHIP
   1.297 +            case PR_SockOpt_AddMember:
   1.298 +            case PR_SockOpt_DropMember:
   1.299 +            {
   1.300 +                struct ip_mreq mreq;
   1.301 +                mreq.imr_multiaddr.s_addr =
   1.302 +                    data->value.add_member.mcaddr.inet.ip;
   1.303 +                mreq.imr_interface.s_addr =
   1.304 +                    data->value.add_member.ifaddr.inet.ip;
   1.305 +                rv = _PR_MD_SETSOCKOPT(
   1.306 +                    fd, level, name, (char*)&mreq, sizeof(mreq));
   1.307 +                break;
   1.308 +            }
   1.309 +#endif /* IP_ADD_MEMBERSHIP */
   1.310 +            case PR_SockOpt_McastInterface:
   1.311 +            {
   1.312 +                /* This option is a struct in_addr. */
   1.313 +                rv = _PR_MD_SETSOCKOPT(
   1.314 +                    fd, level, name, (char*)&data->value.mcast_if.inet.ip,
   1.315 +                    sizeof(data->value.mcast_if.inet.ip));
   1.316 +                break;
   1.317 +            }
   1.318 +            default:
   1.319 +                PR_NOT_REACHED("Unknown socket option");
   1.320 +                break;
   1.321 +        }  
   1.322 +    }
   1.323 +    return rv;
   1.324 +}  /* _PR_SocketSetSocketOption */
   1.325 +
   1.326 +#endif /* ! _PR_PTHREADS */
   1.327 +
   1.328 +/*
   1.329 + *********************************************************************
   1.330 + *********************************************************************
   1.331 + **
   1.332 + ** Make sure that the following is at the end of this file,
   1.333 + ** because we will be playing with macro redefines.
   1.334 + **
   1.335 + *********************************************************************
   1.336 + *********************************************************************
   1.337 + */
   1.338 +
   1.339 +/*
   1.340 + * Not every platform has all the socket options we want to
   1.341 + * support.  Some older operating systems such as SunOS 4.1.3
   1.342 + * don't have the IP multicast socket options.  Win32 doesn't
   1.343 + * have TCP_MAXSEG.
   1.344 + *
   1.345 + * To deal with this problem, we define the missing socket
   1.346 + * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
   1.347 + * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
   1.348 + * available on the platform is requested.
   1.349 + */
   1.350 +
   1.351 +/*
   1.352 + * Sanity check.  SO_LINGER and TCP_NODELAY should be available
   1.353 + * on all platforms.  Just to make sure we have included the
   1.354 + * appropriate header files.  Then any undefined socket options
   1.355 + * are really missing.
   1.356 + */
   1.357 +
   1.358 +#if !defined(SO_LINGER)
   1.359 +#error "SO_LINGER is not defined"
   1.360 +#endif
   1.361 +
   1.362 +#if !defined(TCP_NODELAY)
   1.363 +#error "TCP_NODELAY is not defined"
   1.364 +#endif
   1.365 +
   1.366 +/*
   1.367 + * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
   1.368 + * a valid socket option.
   1.369 + */
   1.370 +#define _PR_NO_SUCH_SOCKOPT -1
   1.371 +
   1.372 +#ifndef SO_KEEPALIVE
   1.373 +#define SO_KEEPALIVE        _PR_NO_SUCH_SOCKOPT
   1.374 +#endif
   1.375 +
   1.376 +#ifndef SO_SNDBUF
   1.377 +#define SO_SNDBUF           _PR_NO_SUCH_SOCKOPT
   1.378 +#endif
   1.379 +
   1.380 +#ifndef SO_RCVBUF
   1.381 +#define SO_RCVBUF           _PR_NO_SUCH_SOCKOPT
   1.382 +#endif
   1.383 +
   1.384 +#ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
   1.385 +#define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
   1.386 +#endif
   1.387 +
   1.388 +#ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
   1.389 +#define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
   1.390 +#endif
   1.391 +
   1.392 +#ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
   1.393 +#define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
   1.394 +#endif
   1.395 +
   1.396 +#ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
   1.397 +#define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
   1.398 +#endif
   1.399 +
   1.400 +#ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
   1.401 +#define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
   1.402 +#endif
   1.403 +
   1.404 +#ifndef IP_TTL                          /* set/get IP Time To Live          */
   1.405 +#define IP_TTL              _PR_NO_SUCH_SOCKOPT
   1.406 +#endif
   1.407 +
   1.408 +#ifndef IP_TOS                          /* set/get IP Type Of Service       */
   1.409 +#define IP_TOS              _PR_NO_SUCH_SOCKOPT
   1.410 +#endif
   1.411 +
   1.412 +#ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
   1.413 +#define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
   1.414 +#endif
   1.415 +
   1.416 +#ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
   1.417 +#define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
   1.418 +#endif
   1.419 +
   1.420 +#ifndef SO_BROADCAST                    /* enable broadcast on UDP sockets  */
   1.421 +#define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
   1.422 +#endif
   1.423 +
   1.424 +#ifndef SO_REUSEPORT                    /* allow local address & port reuse */
   1.425 +#define SO_REUSEPORT        _PR_NO_SUCH_SOCKOPT
   1.426 +#endif
   1.427 +
   1.428 +PRStatus _PR_MapOptionName(
   1.429 +    PRSockOption optname, PRInt32 *level, PRInt32 *name)
   1.430 +{
   1.431 +    static PRInt32 socketOptions[PR_SockOpt_Last] =
   1.432 +    {
   1.433 +        0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
   1.434 +        IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
   1.435 +        IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
   1.436 +        TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT
   1.437 +    };
   1.438 +    static PRInt32 socketLevels[PR_SockOpt_Last] =
   1.439 +    {
   1.440 +        0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
   1.441 +        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
   1.442 +        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
   1.443 +        IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET
   1.444 +    };
   1.445 +
   1.446 +    if ((optname < PR_SockOpt_Linger)
   1.447 +    || (optname >= PR_SockOpt_Last))
   1.448 +    {
   1.449 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.450 +        return PR_FAILURE;
   1.451 +    }
   1.452 +
   1.453 +    if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
   1.454 +    {
   1.455 +        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
   1.456 +        return PR_FAILURE;
   1.457 +    }
   1.458 +    *name = socketOptions[optname];
   1.459 +    *level = socketLevels[optname];
   1.460 +    return PR_SUCCESS;
   1.461 +}  /* _PR_MapOptionName */

mercurial