home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / io / prmapopt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.5 KB  |  409 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * This file defines _PR_MapOptionName().  The purpose of putting
  21.  * _PR_MapOptionName() in a separate file is to work around a Winsock
  22.  * header file problem on Windows NT.
  23.  *
  24.  * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
  25.  * to use Service Pack 3 extensions), windows.h includes winsock2.h
  26.  * (instead of winsock.h), which doesn't define many socket options
  27.  * defined in winsock.h.
  28.  *
  29.  * We need the socket options defined in winsock.h.  So this file
  30.  * includes winsock.h, with _WIN32_WINNT undefined.
  31.  */
  32.  
  33. #ifdef WINNT
  34. #include <winsock.h>
  35. #endif
  36.  
  37. #include "primpl.h"
  38.  
  39. #if defined(XP_UNIX) || defined(OS2)
  40. #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
  41. #endif
  42.  
  43. /*
  44.  * Not every platform has all the socket options we want to
  45.  * support.  Some older operating systems such as SunOS 4.1.3
  46.  * don't have the IP multicast socket options.  Win32 doesn't
  47.  * have TCP_MAXSEG.
  48.  *
  49.  * To deal with this problem, we define the missing socket
  50.  * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
  51.  * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
  52.  * available on the platform is requested.
  53.  */
  54.  
  55. /*
  56.  * Sanity check.  SO_LINGER and TCP_NODELAY should be available
  57.  * on all platforms.  Just to make sure we have included the
  58.  * appropriate header files.  Then any undefined socket options
  59.  * are really missing.
  60.  */
  61.  
  62. #if !defined(SO_LINGER)
  63. #error "SO_LINGER is not defined"
  64. #endif
  65.  
  66. #if !defined(TCP_NODELAY)
  67. #error "TCP_NODELAY is not defined"
  68. #endif
  69.  
  70. /*
  71.  * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
  72.  * a valid socket option.
  73.  */
  74. #define _PR_NO_SUCH_SOCKOPT -1
  75.  
  76. #ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
  77. #define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
  78. #endif
  79.  
  80. #ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
  81. #define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
  82. #endif
  83.  
  84. #ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
  85. #define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
  86. #endif
  87.  
  88. #ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
  89. #define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
  90. #endif
  91.  
  92. #ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
  93. #define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
  94. #endif
  95.  
  96. #ifndef IP_TTL                          /* set/get IP Time To Live          */
  97. #define IP_TTL              _PR_NO_SUCH_SOCKOPT
  98. #endif
  99.  
  100. #ifndef IP_TOS                          /* set/get IP Type Of Service       */
  101. #define IP_TOS              _PR_NO_SUCH_SOCKOPT
  102. #endif
  103.  
  104. #ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
  105. #define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
  106. #endif
  107.  
  108. PRStatus _PR_MapOptionName(
  109.     PRSockOption optname, PRInt32 *level, PRInt32 *name)
  110. {
  111.     static PRInt32 socketOptions[PR_SockOpt_Last] =
  112.     {
  113.         0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
  114.         IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
  115.         IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
  116.         TCP_NODELAY, TCP_MAXSEG
  117.     };
  118.     static PRInt32 socketLevels[PR_SockOpt_Last] =
  119.     {
  120.         0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
  121.         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
  122.         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
  123.         IPPROTO_TCP, IPPROTO_TCP
  124.     };
  125.  
  126.     if ((optname < PR_SockOpt_Linger)
  127.     && (optname > PR_SockOpt_MaxSegment))
  128.     {
  129.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  130.         return PR_FAILURE;
  131.     }
  132.  
  133.     if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
  134.     {
  135.         PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
  136.         return PR_FAILURE;
  137.     }
  138.     *name = socketOptions[optname];
  139.     *level = socketLevels[optname];
  140.     return PR_SUCCESS;
  141. }  /* _PR_MapOptionName */
  142.  
  143. #ifndef _PR_PTHREADS
  144.  
  145. PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
  146. {
  147.     PRStatus rv;
  148.     PRInt32 length;
  149.     PRInt32 level, name;
  150.  
  151.     /*
  152.      * PR_SockOpt_Nonblocking is a special case that does not
  153.      * translate to a getsockopt() call
  154.      */
  155.     if (PR_SockOpt_Nonblocking == data->option)
  156.     {
  157.         data->value.non_blocking = fd->secret->nonblocking;
  158.         return PR_SUCCESS;
  159.     }
  160.  
  161.     rv = _PR_MapOptionName(data->option, &level, &name);
  162.     if (PR_SUCCESS == rv)
  163.     {
  164.         switch (data->option)
  165.         {
  166.             case PR_SockOpt_Linger:
  167.             {
  168.                 struct linger linger;
  169.                 length = sizeof(linger);
  170.                 rv = _PR_MD_GETSOCKOPT(
  171.                     fd, level, name, (char *) &linger, &length);
  172.                 if (PR_SUCCESS == rv)
  173.                 {
  174.                     PR_ASSERT(sizeof(linger) == length);
  175.                     data->value.linger.polarity =
  176.                         (linger.l_onoff) ? PR_TRUE : PR_FALSE;
  177.                     data->value.linger.linger =
  178.                         PR_SecondsToInterval(linger.l_linger);
  179.                 }
  180.                 break;
  181.             }
  182.             case PR_SockOpt_Reuseaddr:
  183.             case PR_SockOpt_Keepalive:
  184.             case PR_SockOpt_NoDelay:
  185.             {
  186. #ifdef WIN32 /* Winsock */
  187.                 BOOL value;
  188. #else
  189.                 PRIntn value;
  190. #endif
  191.                 length = sizeof(value);
  192.                 rv = _PR_MD_GETSOCKOPT(
  193.                     fd, level, name, (char*)&value, &length);
  194.                 if (PR_SUCCESS == rv)
  195.                     data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
  196.                 break;
  197.             }
  198.             case PR_SockOpt_McastLoopback:
  199.             {
  200. #ifdef WIN32 /* Winsock */
  201.                 BOOL bool;
  202. #else
  203.                 PRUint8 bool;
  204. #endif
  205.                 length = sizeof(bool);
  206.                 rv = _PR_MD_GETSOCKOPT(
  207.                     fd, level, name, (char*)&bool, &length);
  208.                 if (PR_SUCCESS == rv)
  209.                     data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
  210.                 break;
  211.             }
  212.             case PR_SockOpt_RecvBufferSize:
  213.             case PR_SockOpt_SendBufferSize:
  214.             case PR_SockOpt_MaxSegment:
  215.             {
  216.                 PRIntn value;
  217.                 length = sizeof(value);
  218.                 rv = _PR_MD_GETSOCKOPT(
  219.                     fd, level, name, (char*)&value, &length);
  220.                 if (PR_SUCCESS == rv)
  221.                     data->value.recv_buffer_size = value;
  222.                 break;
  223.             }
  224.             case PR_SockOpt_IpTimeToLive:
  225.             case PR_SockOpt_IpTypeOfService:
  226.             {
  227.                 /* These options should really be an int (or PRIntn). */
  228.                 length = sizeof(PRUintn);
  229.                 rv = _PR_MD_GETSOCKOPT(
  230.                     fd, level, name, (char*)&data->value.ip_ttl, &length);
  231.                 break;
  232.             }
  233.             case PR_SockOpt_McastTimeToLive:
  234.             {
  235. #ifdef WIN32 /* Winsock */
  236.                 int ttl;
  237. #else
  238.                 PRUint8 ttl;
  239. #endif
  240.                 length = sizeof(ttl);
  241.                 rv = _PR_MD_GETSOCKOPT(
  242.                     fd, level, name, (char*)&ttl, &length);
  243.                 if (PR_SUCCESS == rv)
  244.                     data->value.mcast_ttl = ttl;
  245.                 break;
  246.             }
  247.             case PR_SockOpt_AddMember:
  248.             case PR_SockOpt_DropMember:
  249.             {
  250.                 struct ip_mreq mreq;
  251.                 length = sizeof(mreq);
  252.                 rv = _PR_MD_GETSOCKOPT(
  253.                     fd, level, name, (char*)&mreq, &length);
  254.                 if (PR_SUCCESS == rv)
  255.                 {
  256.                     data->value.add_member.mcaddr.inet.ip =
  257.                         mreq.imr_multiaddr.s_addr;
  258.                     data->value.add_member.ifaddr.inet.ip =
  259.                         mreq.imr_interface.s_addr;
  260.                 }
  261.                 break;
  262.             }
  263.             case PR_SockOpt_McastInterface:
  264.             {
  265.                 /* This option is a struct in_addr. */
  266.                 length = sizeof(data->value.mcast_if.inet.ip);
  267.                 rv = _PR_MD_GETSOCKOPT(
  268.                     fd, level, name,
  269.                     (char*)&data->value.mcast_if.inet.ip, &length);
  270.                 break;
  271.             }
  272.             default:
  273.                 PR_NOT_REACHED("Unknown socket option");
  274.                 break;
  275.         }  
  276.     }
  277.     return rv;
  278. }  /* _PR_SocketGetSocketOption */
  279.  
  280. PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
  281. {
  282.     PRStatus rv;
  283.     PRInt32 level, name;
  284.  
  285.     /*
  286.      * PR_SockOpt_Nonblocking is a special case that does not
  287.      * translate to a setsockopt call.
  288.      */
  289.     if (PR_SockOpt_Nonblocking == data->option)
  290.     {
  291. #ifdef WINNT
  292.         PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
  293.             || (fd->secret->nonblocking == data->value.non_blocking));
  294.         if (fd->secret->md.io_model_committed
  295.             && (fd->secret->nonblocking != data->value.non_blocking))
  296.         {
  297.             /*
  298.              * On NT, once we have associated a socket with the io
  299.              * completion port, we can't disassociate it.  So we
  300.              * can't change the nonblocking option of the socket
  301.              * afterwards.
  302.              */
  303.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  304.             return PR_FAILURE;
  305.         }
  306. #endif
  307.         fd->secret->nonblocking = data->value.non_blocking;
  308.         return PR_SUCCESS;
  309.     }
  310.  
  311.     rv = _PR_MapOptionName(data->option, &level, &name);
  312.     if (PR_SUCCESS == rv)
  313.     {
  314.         switch (data->option)
  315.         {
  316.             case PR_SockOpt_Linger:
  317.             {
  318.                 struct linger linger;
  319.                 linger.l_onoff = data->value.linger.polarity;
  320.                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
  321.                 rv = _PR_MD_SETSOCKOPT(
  322.                     fd, level, name, (char*)&linger, sizeof(linger));
  323.                 break;
  324.             }
  325.             case PR_SockOpt_Reuseaddr:
  326.             case PR_SockOpt_Keepalive:
  327.             case PR_SockOpt_NoDelay:
  328.             {
  329. #ifdef WIN32 /* Winsock */
  330.                 BOOL value;
  331. #else
  332.                 PRIntn value;
  333. #endif
  334.                 value = (data->value.reuse_addr) ? 1 : 0;
  335.                 rv = _PR_MD_SETSOCKOPT(
  336.                     fd, level, name, (char*)&value, sizeof(value));
  337.                 break;
  338.             }
  339.             case PR_SockOpt_McastLoopback:
  340.             {
  341. #ifdef WIN32 /* Winsock */
  342.                 BOOL bool;
  343. #else
  344.                 PRUint8 bool;
  345. #endif
  346.                 bool = data->value.mcast_loopback ? 1 : 0;
  347.                 rv = _PR_MD_SETSOCKOPT(
  348.                     fd, level, name, (char*)&bool, sizeof(bool));
  349.                 break;
  350.             }
  351.             case PR_SockOpt_RecvBufferSize:
  352.             case PR_SockOpt_SendBufferSize:
  353.             case PR_SockOpt_MaxSegment:
  354.             {
  355.                 PRIntn value = data->value.recv_buffer_size;
  356.                 rv = _PR_MD_SETSOCKOPT(
  357.                     fd, level, name, (char*)&value, sizeof(value));
  358.                 break;
  359.             }
  360.             case PR_SockOpt_IpTimeToLive:
  361.             case PR_SockOpt_IpTypeOfService:
  362.             {
  363.                 /* These options should really be an int (or PRIntn). */
  364.                 rv = _PR_MD_SETSOCKOPT(
  365.                     fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
  366.                 break;
  367.             }
  368.             case PR_SockOpt_McastTimeToLive:
  369.             {
  370. #ifdef WIN32 /* Winsock */
  371.                 int ttl;
  372. #else
  373.                 PRUint8 ttl;
  374. #endif
  375.                 ttl = data->value.mcast_ttl;
  376.                 rv = _PR_MD_SETSOCKOPT(
  377.                     fd, level, name, (char*)&ttl, sizeof(ttl));
  378.                 break;
  379.             }
  380.             case PR_SockOpt_AddMember:
  381.             case PR_SockOpt_DropMember:
  382.             {
  383.                 struct ip_mreq mreq;
  384.                 mreq.imr_multiaddr.s_addr =
  385.                     data->value.add_member.mcaddr.inet.ip;
  386.                 mreq.imr_interface.s_addr =
  387.                     data->value.add_member.ifaddr.inet.ip;
  388.                 rv = _PR_MD_SETSOCKOPT(
  389.                     fd, level, name, (char*)&mreq, sizeof(mreq));
  390.                 break;
  391.             }
  392.             case PR_SockOpt_McastInterface:
  393.             {
  394.                 /* This option is a struct in_addr. */
  395.                 rv = _PR_MD_SETSOCKOPT(
  396.                     fd, level, name, (char*)&data->value.mcast_if.inet.ip,
  397.                     sizeof(data->value.mcast_if.inet.ip));
  398.                 break;
  399.             }
  400.             default:
  401.                 PR_NOT_REACHED("Unknown socket option");
  402.                 break;
  403.         }  
  404.     }
  405.     return rv;
  406. }  /* _PR_SocketSetSocketOption */
  407.  
  408. #endif /* ! _PR_PTHREADS */
  409.