Back to index

lightning-sunbird  0.9+nobinonly
prmapopt.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039  * This file defines _PR_MapOptionName().  The purpose of putting
00040  * _PR_MapOptionName() in a separate file is to work around a Winsock
00041  * header file problem on Windows NT.
00042  *
00043  * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
00044  * to use Service Pack 3 extensions), windows.h includes winsock2.h
00045  * (instead of winsock.h), which doesn't define many socket options
00046  * defined in winsock.h.
00047  *
00048  * We need the socket options defined in winsock.h.  So this file
00049  * includes winsock.h, with _WIN32_WINNT undefined.
00050  */
00051 
00052 #if defined(WINNT) || defined(__MINGW32__)
00053 #include <winsock.h>
00054 #endif
00055 
00056 /* MinGW doesn't define these in its winsock.h. */
00057 #ifdef __MINGW32__
00058 #ifndef IP_TTL
00059 #define IP_TTL 7
00060 #endif
00061 #ifndef IP_TOS
00062 #define IP_TOS 8
00063 #endif
00064 #endif
00065 
00066 #include "primpl.h"
00067 
00068 #if defined(NEXTSTEP)
00069 /* NEXTSTEP is special: this must come before netinet/tcp.h. */
00070 #include <netinet/in_systm.h>  /* n_short, n_long, n_time */
00071 #endif
00072 
00073 #if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
00074 #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
00075 #endif
00076 
00077 #ifndef _PR_PTHREADS
00078 
00079 PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
00080 {
00081     PRStatus rv;
00082     PRInt32 length;
00083     PRInt32 level, name;
00084 
00085     /*
00086      * PR_SockOpt_Nonblocking is a special case that does not
00087      * translate to a getsockopt() call
00088      */
00089     if (PR_SockOpt_Nonblocking == data->option)
00090     {
00091         data->value.non_blocking = fd->secret->nonblocking;
00092         return PR_SUCCESS;
00093     }
00094 
00095     rv = _PR_MapOptionName(data->option, &level, &name);
00096     if (PR_SUCCESS == rv)
00097     {
00098         switch (data->option)
00099         {
00100             case PR_SockOpt_Linger:
00101             {
00102 #if !defined(XP_BEOS) || defined(BONE_VERSION)
00103                 struct linger linger;
00104                 length = sizeof(linger);
00105                 rv = _PR_MD_GETSOCKOPT(
00106                     fd, level, name, (char *) &linger, &length);
00107                 if (PR_SUCCESS == rv)
00108                 {
00109                     PR_ASSERT(sizeof(linger) == length);
00110                     data->value.linger.polarity =
00111                         (linger.l_onoff) ? PR_TRUE : PR_FALSE;
00112                     data->value.linger.linger =
00113                         PR_SecondsToInterval(linger.l_linger);
00114                 }
00115                 break;
00116 #else
00117                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
00118                 return PR_FAILURE;
00119 #endif
00120             }
00121             case PR_SockOpt_Reuseaddr:
00122             case PR_SockOpt_Keepalive:
00123             case PR_SockOpt_NoDelay:
00124             case PR_SockOpt_Broadcast:
00125             {
00126 #ifdef WIN32 /* Winsock */
00127                 BOOL value;
00128 #else
00129                 PRIntn value;
00130 #endif
00131                 length = sizeof(value);
00132                 rv = _PR_MD_GETSOCKOPT(
00133                     fd, level, name, (char*)&value, &length);
00134                 if (PR_SUCCESS == rv)
00135                     data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
00136                 break;
00137             }
00138             case PR_SockOpt_McastLoopback:
00139             {
00140 #ifdef WIN32 /* Winsock */
00141                 BOOL bool;
00142 #else
00143                 PRUint8 bool;
00144 #endif
00145                 length = sizeof(bool);
00146                 rv = _PR_MD_GETSOCKOPT(
00147                     fd, level, name, (char*)&bool, &length);
00148                 if (PR_SUCCESS == rv)
00149                     data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
00150                 break;
00151             }
00152             case PR_SockOpt_RecvBufferSize:
00153             case PR_SockOpt_SendBufferSize:
00154             case PR_SockOpt_MaxSegment:
00155             {
00156                 PRIntn value;
00157                 length = sizeof(value);
00158                 rv = _PR_MD_GETSOCKOPT(
00159                     fd, level, name, (char*)&value, &length);
00160                 if (PR_SUCCESS == rv)
00161                     data->value.recv_buffer_size = value;
00162                 break;
00163             }
00164             case PR_SockOpt_IpTimeToLive:
00165             case PR_SockOpt_IpTypeOfService:
00166             {
00167                 /* These options should really be an int (or PRIntn). */
00168                 length = sizeof(PRUintn);
00169                 rv = _PR_MD_GETSOCKOPT(
00170                     fd, level, name, (char*)&data->value.ip_ttl, &length);
00171                 break;
00172             }
00173             case PR_SockOpt_McastTimeToLive:
00174             {
00175 #ifdef WIN32 /* Winsock */
00176                 int ttl;
00177 #else
00178                 PRUint8 ttl;
00179 #endif
00180                 length = sizeof(ttl);
00181                 rv = _PR_MD_GETSOCKOPT(
00182                     fd, level, name, (char*)&ttl, &length);
00183                 if (PR_SUCCESS == rv)
00184                     data->value.mcast_ttl = ttl;
00185                 break;
00186             }
00187 #ifdef IP_ADD_MEMBERSHIP
00188             case PR_SockOpt_AddMember:
00189             case PR_SockOpt_DropMember:
00190             {
00191                 struct ip_mreq mreq;
00192                 length = sizeof(mreq);
00193                 rv = _PR_MD_GETSOCKOPT(
00194                     fd, level, name, (char*)&mreq, &length);
00195                 if (PR_SUCCESS == rv)
00196                 {
00197                     data->value.add_member.mcaddr.inet.ip =
00198                         mreq.imr_multiaddr.s_addr;
00199                     data->value.add_member.ifaddr.inet.ip =
00200                         mreq.imr_interface.s_addr;
00201                 }
00202                 break;
00203             }
00204 #endif /* IP_ADD_MEMBERSHIP */
00205             case PR_SockOpt_McastInterface:
00206             {
00207                 /* This option is a struct in_addr. */
00208                 length = sizeof(data->value.mcast_if.inet.ip);
00209                 rv = _PR_MD_GETSOCKOPT(
00210                     fd, level, name,
00211                     (char*)&data->value.mcast_if.inet.ip, &length);
00212                 break;
00213             }
00214             default:
00215                 PR_NOT_REACHED("Unknown socket option");
00216                 break;
00217         }  
00218     }
00219     return rv;
00220 }  /* _PR_SocketGetSocketOption */
00221 
00222 PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
00223 {
00224     PRStatus rv;
00225     PRInt32 level, name;
00226 
00227     /*
00228      * PR_SockOpt_Nonblocking is a special case that does not
00229      * translate to a setsockopt call.
00230      */
00231     if (PR_SockOpt_Nonblocking == data->option)
00232     {
00233 #ifdef WINNT
00234         PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
00235             || (fd->secret->nonblocking == data->value.non_blocking));
00236         if (fd->secret->md.io_model_committed
00237             && (fd->secret->nonblocking != data->value.non_blocking))
00238         {
00239             /*
00240              * On NT, once we have associated a socket with the io
00241              * completion port, we can't disassociate it.  So we
00242              * can't change the nonblocking option of the socket
00243              * afterwards.
00244              */
00245             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00246             return PR_FAILURE;
00247         }
00248 #endif
00249         fd->secret->nonblocking = data->value.non_blocking;
00250         return PR_SUCCESS;
00251     }
00252 
00253     rv = _PR_MapOptionName(data->option, &level, &name);
00254     if (PR_SUCCESS == rv)
00255     {
00256         switch (data->option)
00257         {
00258             case PR_SockOpt_Linger:
00259             {
00260 #if !defined(XP_BEOS) || defined(BONE_VERSION)
00261                 struct linger linger;
00262                 linger.l_onoff = data->value.linger.polarity;
00263                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
00264                 rv = _PR_MD_SETSOCKOPT(
00265                     fd, level, name, (char*)&linger, sizeof(linger));
00266                 break;
00267 #else
00268                 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
00269                 return PR_FAILURE;
00270 #endif
00271             }
00272             case PR_SockOpt_Reuseaddr:
00273             case PR_SockOpt_Keepalive:
00274             case PR_SockOpt_NoDelay:
00275             case PR_SockOpt_Broadcast:
00276             {
00277 #ifdef WIN32 /* Winsock */
00278                 BOOL value;
00279 #else
00280                 PRIntn value;
00281 #endif
00282                 value = (data->value.reuse_addr) ? 1 : 0;
00283                 rv = _PR_MD_SETSOCKOPT(
00284                     fd, level, name, (char*)&value, sizeof(value));
00285                 break;
00286             }
00287             case PR_SockOpt_McastLoopback:
00288             {
00289 #ifdef WIN32 /* Winsock */
00290                 BOOL bool;
00291 #else
00292                 PRUint8 bool;
00293 #endif
00294                 bool = data->value.mcast_loopback ? 1 : 0;
00295                 rv = _PR_MD_SETSOCKOPT(
00296                     fd, level, name, (char*)&bool, sizeof(bool));
00297                 break;
00298             }
00299             case PR_SockOpt_RecvBufferSize:
00300             case PR_SockOpt_SendBufferSize:
00301             case PR_SockOpt_MaxSegment:
00302             {
00303                 PRIntn value = data->value.recv_buffer_size;
00304                 rv = _PR_MD_SETSOCKOPT(
00305                     fd, level, name, (char*)&value, sizeof(value));
00306                 break;
00307             }
00308             case PR_SockOpt_IpTimeToLive:
00309             case PR_SockOpt_IpTypeOfService:
00310             {
00311                 /* These options should really be an int (or PRIntn). */
00312                 rv = _PR_MD_SETSOCKOPT(
00313                     fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
00314                 break;
00315             }
00316             case PR_SockOpt_McastTimeToLive:
00317             {
00318 #ifdef WIN32 /* Winsock */
00319                 int ttl;
00320 #else
00321                 PRUint8 ttl;
00322 #endif
00323                 ttl = data->value.mcast_ttl;
00324                 rv = _PR_MD_SETSOCKOPT(
00325                     fd, level, name, (char*)&ttl, sizeof(ttl));
00326                 break;
00327             }
00328 #ifdef IP_ADD_MEMBERSHIP
00329             case PR_SockOpt_AddMember:
00330             case PR_SockOpt_DropMember:
00331             {
00332                 struct ip_mreq mreq;
00333                 mreq.imr_multiaddr.s_addr =
00334                     data->value.add_member.mcaddr.inet.ip;
00335                 mreq.imr_interface.s_addr =
00336                     data->value.add_member.ifaddr.inet.ip;
00337                 rv = _PR_MD_SETSOCKOPT(
00338                     fd, level, name, (char*)&mreq, sizeof(mreq));
00339                 break;
00340             }
00341 #endif /* IP_ADD_MEMBERSHIP */
00342             case PR_SockOpt_McastInterface:
00343             {
00344                 /* This option is a struct in_addr. */
00345                 rv = _PR_MD_SETSOCKOPT(
00346                     fd, level, name, (char*)&data->value.mcast_if.inet.ip,
00347                     sizeof(data->value.mcast_if.inet.ip));
00348                 break;
00349             }
00350             default:
00351                 PR_NOT_REACHED("Unknown socket option");
00352                 break;
00353         }  
00354     }
00355     return rv;
00356 }  /* _PR_SocketSetSocketOption */
00357 
00358 #endif /* ! _PR_PTHREADS */
00359 
00360 /*
00361  *********************************************************************
00362  *********************************************************************
00363  **
00364  ** Make sure that the following is at the end of this file,
00365  ** because we will be playing with macro redefines.
00366  **
00367  *********************************************************************
00368  *********************************************************************
00369  */
00370 
00371 #if defined(VMS)
00372 /*
00373 ** Sad but true. The DEC C header files define the following socket options
00374 ** differently to what UCX is expecting. The values that UCX expects are
00375 ** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values
00376 ** that UCX expects. Note that UCX V4.x will only accept these values while
00377 ** UCX V5.x will accept either. So in theory this hack can be removed once
00378 ** UCX V5 is the minimum.
00379 */
00380 #undef IP_MULTICAST_IF
00381 #undef IP_MULTICAST_TTL
00382 #undef IP_MULTICAST_LOOP
00383 #undef IP_ADD_MEMBERSHIP
00384 #undef IP_DROP_MEMBERSHIP
00385 #include <ucx$inetdef.h>
00386 #define IP_MULTICAST_IF    UCX$C_IP_MULTICAST_IF
00387 #define IP_MULTICAST_TTL   UCX$C_IP_MULTICAST_TTL
00388 #define IP_MULTICAST_LOOP  UCX$C_IP_MULTICAST_LOOP
00389 #define IP_ADD_MEMBERSHIP  UCX$C_IP_ADD_MEMBERSHIP
00390 #define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP
00391 #endif
00392 
00393 /*
00394  * Not every platform has all the socket options we want to
00395  * support.  Some older operating systems such as SunOS 4.1.3
00396  * don't have the IP multicast socket options.  Win32 doesn't
00397  * have TCP_MAXSEG.
00398  *
00399  * To deal with this problem, we define the missing socket
00400  * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
00401  * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
00402  * available on the platform is requested.
00403  */
00404 
00405 /*
00406  * Sanity check.  SO_LINGER and TCP_NODELAY should be available
00407  * on all platforms.  Just to make sure we have included the
00408  * appropriate header files.  Then any undefined socket options
00409  * are really missing.
00410  */
00411 
00412 #if !defined(SO_LINGER)
00413 #error "SO_LINGER is not defined"
00414 #endif
00415 
00416 /*
00417  * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
00418  * in <netinet/tcp.h>
00419  */
00420 #if !defined(NCR)
00421 #if !defined(TCP_NODELAY)
00422 #error "TCP_NODELAY is not defined"
00423 #endif
00424 #endif
00425 
00426 /*
00427  * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
00428  * a valid socket option.
00429  */
00430 #define _PR_NO_SUCH_SOCKOPT -1
00431 
00432 #ifndef SO_KEEPALIVE
00433 #define SO_KEEPALIVE        _PR_NO_SUCH_SOCKOPT
00434 #endif
00435 
00436 #ifndef SO_SNDBUF
00437 #define SO_SNDBUF           _PR_NO_SUCH_SOCKOPT
00438 #endif
00439 
00440 #ifndef SO_RCVBUF
00441 #define SO_RCVBUF           _PR_NO_SUCH_SOCKOPT
00442 #endif
00443 
00444 #ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
00445 #define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
00446 #endif
00447 
00448 #ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
00449 #define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
00450 #endif
00451 
00452 #ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
00453 #define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
00454 #endif
00455 
00456 #ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
00457 #define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
00458 #endif
00459 
00460 #ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
00461 #define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
00462 #endif
00463 
00464 #ifndef IP_TTL                          /* set/get IP Time To Live          */
00465 #define IP_TTL              _PR_NO_SUCH_SOCKOPT
00466 #endif
00467 
00468 #ifndef IP_TOS                          /* set/get IP Type Of Service       */
00469 #define IP_TOS              _PR_NO_SUCH_SOCKOPT
00470 #endif
00471 
00472 #ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
00473 #define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
00474 #endif
00475 
00476 #ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
00477 #define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
00478 #endif
00479 
00480 #ifndef SO_BROADCAST                 /* enable broadcast on udp sockets */
00481 #define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
00482 #endif
00483 
00484 PRStatus _PR_MapOptionName(
00485     PRSockOption optname, PRInt32 *level, PRInt32 *name)
00486 {
00487     static PRInt32 socketOptions[PR_SockOpt_Last] =
00488     {
00489         0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
00490         IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
00491         IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
00492         TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
00493     };
00494     static PRInt32 socketLevels[PR_SockOpt_Last] =
00495     {
00496         0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
00497         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
00498         IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
00499         IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
00500     };
00501 
00502     if ((optname < PR_SockOpt_Linger)
00503     || (optname >= PR_SockOpt_Last))
00504     {
00505         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00506         return PR_FAILURE;
00507     }
00508 
00509     if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
00510     {
00511         PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
00512         return PR_FAILURE;
00513     }
00514     *name = socketOptions[optname];
00515     *level = socketLevels[optname];
00516     return PR_SUCCESS;
00517 }  /* _PR_MapOptionName */