home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- /*
- * This file defines _PR_MapOptionName(). The purpose of putting
- * _PR_MapOptionName() in a separate file is to work around a Winsock
- * header file problem on Windows NT.
- *
- * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
- * to use Service Pack 3 extensions), windows.h includes winsock2.h
- * (instead of winsock.h), which doesn't define many socket options
- * defined in winsock.h.
- *
- * We need the socket options defined in winsock.h. So this file
- * includes winsock.h, with _WIN32_WINNT undefined.
- */
-
- #ifdef WINNT
- #include <winsock.h>
- #endif
-
- #include "primpl.h"
-
- #if defined(XP_UNIX) || defined(OS2)
- #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
- #endif
-
- /*
- * Not every platform has all the socket options we want to
- * support. Some older operating systems such as SunOS 4.1.3
- * don't have the IP multicast socket options. Win32 doesn't
- * have TCP_MAXSEG.
- *
- * To deal with this problem, we define the missing socket
- * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
- * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
- * available on the platform is requested.
- */
-
- /*
- * Sanity check. SO_LINGER and TCP_NODELAY should be available
- * on all platforms. Just to make sure we have included the
- * appropriate header files. Then any undefined socket options
- * are really missing.
- */
-
- #if !defined(SO_LINGER)
- #error "SO_LINGER is not defined"
- #endif
-
- #if !defined(TCP_NODELAY)
- #error "TCP_NODELAY is not defined"
- #endif
-
- /*
- * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
- * a valid socket option.
- */
- #define _PR_NO_SUCH_SOCKOPT -1
-
- #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
- #define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
- #define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
- #define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
- #define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
- #define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_TTL /* set/get IP Time To Live */
- #define IP_TTL _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef IP_TOS /* set/get IP Type Of Service */
- #define IP_TOS _PR_NO_SUCH_SOCKOPT
- #endif
-
- #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
- #define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
- #endif
-
- PRStatus _PR_MapOptionName(
- PRSockOption optname, PRInt32 *level, PRInt32 *name)
- {
- static PRInt32 socketOptions[PR_SockOpt_Last] =
- {
- 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
- IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
- IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
- TCP_NODELAY, TCP_MAXSEG
- };
- static PRInt32 socketLevels[PR_SockOpt_Last] =
- {
- 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
- IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
- IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
- IPPROTO_TCP, IPPROTO_TCP
- };
-
- if ((optname < PR_SockOpt_Linger)
- && (optname > PR_SockOpt_MaxSegment))
- {
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return PR_FAILURE;
- }
-
- if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
- {
- PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
- return PR_FAILURE;
- }
- *name = socketOptions[optname];
- *level = socketLevels[optname];
- return PR_SUCCESS;
- } /* _PR_MapOptionName */
-
- #ifndef _PR_PTHREADS
-
- PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
- {
- PRStatus rv;
- PRInt32 length;
- PRInt32 level, name;
-
- /*
- * PR_SockOpt_Nonblocking is a special case that does not
- * translate to a getsockopt() call
- */
- if (PR_SockOpt_Nonblocking == data->option)
- {
- data->value.non_blocking = fd->secret->nonblocking;
- return PR_SUCCESS;
- }
-
- rv = _PR_MapOptionName(data->option, &level, &name);
- if (PR_SUCCESS == rv)
- {
- switch (data->option)
- {
- case PR_SockOpt_Linger:
- {
- struct linger linger;
- length = sizeof(linger);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char *) &linger, &length);
- if (PR_SUCCESS == rv)
- {
- PR_ASSERT(sizeof(linger) == length);
- data->value.linger.polarity =
- (linger.l_onoff) ? PR_TRUE : PR_FALSE;
- data->value.linger.linger =
- PR_SecondsToInterval(linger.l_linger);
- }
- break;
- }
- case PR_SockOpt_Reuseaddr:
- case PR_SockOpt_Keepalive:
- case PR_SockOpt_NoDelay:
- {
- #ifdef WIN32 /* Winsock */
- BOOL value;
- #else
- PRIntn value;
- #endif
- length = sizeof(value);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&value, &length);
- if (PR_SUCCESS == rv)
- data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
- break;
- }
- case PR_SockOpt_McastLoopback:
- {
- #ifdef WIN32 /* Winsock */
- BOOL bool;
- #else
- PRUint8 bool;
- #endif
- length = sizeof(bool);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&bool, &length);
- if (PR_SUCCESS == rv)
- data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
- break;
- }
- case PR_SockOpt_RecvBufferSize:
- case PR_SockOpt_SendBufferSize:
- case PR_SockOpt_MaxSegment:
- {
- PRIntn value;
- length = sizeof(value);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&value, &length);
- if (PR_SUCCESS == rv)
- data->value.recv_buffer_size = value;
- break;
- }
- case PR_SockOpt_IpTimeToLive:
- case PR_SockOpt_IpTypeOfService:
- {
- /* These options should really be an int (or PRIntn). */
- length = sizeof(PRUintn);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&data->value.ip_ttl, &length);
- break;
- }
- case PR_SockOpt_McastTimeToLive:
- {
- #ifdef WIN32 /* Winsock */
- int ttl;
- #else
- PRUint8 ttl;
- #endif
- length = sizeof(ttl);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&ttl, &length);
- if (PR_SUCCESS == rv)
- data->value.mcast_ttl = ttl;
- break;
- }
- case PR_SockOpt_AddMember:
- case PR_SockOpt_DropMember:
- {
- struct ip_mreq mreq;
- length = sizeof(mreq);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name, (char*)&mreq, &length);
- if (PR_SUCCESS == rv)
- {
- data->value.add_member.mcaddr.inet.ip =
- mreq.imr_multiaddr.s_addr;
- data->value.add_member.ifaddr.inet.ip =
- mreq.imr_interface.s_addr;
- }
- break;
- }
- case PR_SockOpt_McastInterface:
- {
- /* This option is a struct in_addr. */
- length = sizeof(data->value.mcast_if.inet.ip);
- rv = _PR_MD_GETSOCKOPT(
- fd, level, name,
- (char*)&data->value.mcast_if.inet.ip, &length);
- break;
- }
- default:
- PR_NOT_REACHED("Unknown socket option");
- break;
- }
- }
- return rv;
- } /* _PR_SocketGetSocketOption */
-
- PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
- {
- PRStatus rv;
- PRInt32 level, name;
-
- /*
- * PR_SockOpt_Nonblocking is a special case that does not
- * translate to a setsockopt call.
- */
- if (PR_SockOpt_Nonblocking == data->option)
- {
- #ifdef WINNT
- PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
- || (fd->secret->nonblocking == data->value.non_blocking));
- if (fd->secret->md.io_model_committed
- && (fd->secret->nonblocking != data->value.non_blocking))
- {
- /*
- * On NT, once we have associated a socket with the io
- * completion port, we can't disassociate it. So we
- * can't change the nonblocking option of the socket
- * afterwards.
- */
- PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
- return PR_FAILURE;
- }
- #endif
- fd->secret->nonblocking = data->value.non_blocking;
- return PR_SUCCESS;
- }
-
- rv = _PR_MapOptionName(data->option, &level, &name);
- if (PR_SUCCESS == rv)
- {
- switch (data->option)
- {
- case PR_SockOpt_Linger:
- {
- struct linger linger;
- linger.l_onoff = data->value.linger.polarity;
- linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&linger, sizeof(linger));
- break;
- }
- case PR_SockOpt_Reuseaddr:
- case PR_SockOpt_Keepalive:
- case PR_SockOpt_NoDelay:
- {
- #ifdef WIN32 /* Winsock */
- BOOL value;
- #else
- PRIntn value;
- #endif
- value = (data->value.reuse_addr) ? 1 : 0;
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&value, sizeof(value));
- break;
- }
- case PR_SockOpt_McastLoopback:
- {
- #ifdef WIN32 /* Winsock */
- BOOL bool;
- #else
- PRUint8 bool;
- #endif
- bool = data->value.mcast_loopback ? 1 : 0;
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&bool, sizeof(bool));
- break;
- }
- case PR_SockOpt_RecvBufferSize:
- case PR_SockOpt_SendBufferSize:
- case PR_SockOpt_MaxSegment:
- {
- PRIntn value = data->value.recv_buffer_size;
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&value, sizeof(value));
- break;
- }
- case PR_SockOpt_IpTimeToLive:
- case PR_SockOpt_IpTypeOfService:
- {
- /* These options should really be an int (or PRIntn). */
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
- break;
- }
- case PR_SockOpt_McastTimeToLive:
- {
- #ifdef WIN32 /* Winsock */
- int ttl;
- #else
- PRUint8 ttl;
- #endif
- ttl = data->value.mcast_ttl;
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&ttl, sizeof(ttl));
- break;
- }
- case PR_SockOpt_AddMember:
- case PR_SockOpt_DropMember:
- {
- struct ip_mreq mreq;
- mreq.imr_multiaddr.s_addr =
- data->value.add_member.mcaddr.inet.ip;
- mreq.imr_interface.s_addr =
- data->value.add_member.ifaddr.inet.ip;
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&mreq, sizeof(mreq));
- break;
- }
- case PR_SockOpt_McastInterface:
- {
- /* This option is a struct in_addr. */
- rv = _PR_MD_SETSOCKOPT(
- fd, level, name, (char*)&data->value.mcast_if.inet.ip,
- sizeof(data->value.mcast_if.inet.ip));
- break;
- }
- default:
- PR_NOT_REACHED("Unknown socket option");
- break;
- }
- }
- return rv;
- } /* _PR_SocketSetSocketOption */
-
- #endif /* ! _PR_PTHREADS */
-