1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
36
* This file defines _PR_MapOptionName(). The purpose of putting
37
* _PR_MapOptionName() in a separate file is to work around a Winsock
38
* header file problem on Windows NT.
40
* On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
41
* to use Service Pack 3 extensions), windows.h includes winsock2.h
42
* (instead of winsock.h), which doesn't define many socket options
43
* defined in winsock.h.
45
* We need the socket options defined in winsock.h. So this file
46
* includes winsock.h, with _WIN32_WINNT undefined.
49
#if defined(WINNT) || defined(__MINGW32__)
53
/* MinGW doesn't define these in its winsock.h. */
66
/* NEXTSTEP is special: this must come before netinet/tcp.h. */
67
#include <netinet/in_systm.h> /* n_short, n_long, n_time */
70
#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
71
#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
76
PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
83
* PR_SockOpt_Nonblocking is a special case that does not
84
* translate to a getsockopt() call
86
if (PR_SockOpt_Nonblocking == data->option)
88
data->value.non_blocking = fd->secret->nonblocking;
92
rv = _PR_MapOptionName(data->option, &level, &name);
97
case PR_SockOpt_Linger:
99
#if !defined(XP_BEOS) || defined(BONE_VERSION)
100
struct linger linger;
101
length = sizeof(linger);
102
rv = _PR_MD_GETSOCKOPT(
103
fd, level, name, (char *) &linger, &length);
104
if (PR_SUCCESS == rv)
106
PR_ASSERT(sizeof(linger) == length);
107
data->value.linger.polarity =
108
(linger.l_onoff) ? PR_TRUE : PR_FALSE;
109
data->value.linger.linger =
110
PR_SecondsToInterval(linger.l_linger);
114
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
118
case PR_SockOpt_Reuseaddr:
119
case PR_SockOpt_Keepalive:
120
case PR_SockOpt_NoDelay:
121
case PR_SockOpt_Broadcast:
123
#ifdef WIN32 /* Winsock */
128
length = sizeof(value);
129
rv = _PR_MD_GETSOCKOPT(
130
fd, level, name, (char*)&value, &length);
131
if (PR_SUCCESS == rv)
132
data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
135
case PR_SockOpt_McastLoopback:
137
#ifdef WIN32 /* Winsock */
142
length = sizeof(bool);
143
rv = _PR_MD_GETSOCKOPT(
144
fd, level, name, (char*)&bool, &length);
145
if (PR_SUCCESS == rv)
146
data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
149
case PR_SockOpt_RecvBufferSize:
150
case PR_SockOpt_SendBufferSize:
151
case PR_SockOpt_MaxSegment:
154
length = sizeof(value);
155
rv = _PR_MD_GETSOCKOPT(
156
fd, level, name, (char*)&value, &length);
157
if (PR_SUCCESS == rv)
158
data->value.recv_buffer_size = value;
161
case PR_SockOpt_IpTimeToLive:
162
case PR_SockOpt_IpTypeOfService:
164
/* These options should really be an int (or PRIntn). */
165
length = sizeof(PRUintn);
166
rv = _PR_MD_GETSOCKOPT(
167
fd, level, name, (char*)&data->value.ip_ttl, &length);
170
case PR_SockOpt_McastTimeToLive:
172
#ifdef WIN32 /* Winsock */
177
length = sizeof(ttl);
178
rv = _PR_MD_GETSOCKOPT(
179
fd, level, name, (char*)&ttl, &length);
180
if (PR_SUCCESS == rv)
181
data->value.mcast_ttl = ttl;
184
#ifdef IP_ADD_MEMBERSHIP
185
case PR_SockOpt_AddMember:
186
case PR_SockOpt_DropMember:
189
length = sizeof(mreq);
190
rv = _PR_MD_GETSOCKOPT(
191
fd, level, name, (char*)&mreq, &length);
192
if (PR_SUCCESS == rv)
194
data->value.add_member.mcaddr.inet.ip =
195
mreq.imr_multiaddr.s_addr;
196
data->value.add_member.ifaddr.inet.ip =
197
mreq.imr_interface.s_addr;
201
#endif /* IP_ADD_MEMBERSHIP */
202
case PR_SockOpt_McastInterface:
204
/* This option is a struct in_addr. */
205
length = sizeof(data->value.mcast_if.inet.ip);
206
rv = _PR_MD_GETSOCKOPT(
208
(char*)&data->value.mcast_if.inet.ip, &length);
212
PR_NOT_REACHED("Unknown socket option");
217
} /* _PR_SocketGetSocketOption */
219
PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
225
* PR_SockOpt_Nonblocking is a special case that does not
226
* translate to a setsockopt call.
228
if (PR_SockOpt_Nonblocking == data->option)
231
PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
232
|| (fd->secret->nonblocking == data->value.non_blocking));
233
if (fd->secret->md.io_model_committed
234
&& (fd->secret->nonblocking != data->value.non_blocking))
237
* On NT, once we have associated a socket with the io
238
* completion port, we can't disassociate it. So we
239
* can't change the nonblocking option of the socket
242
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
246
fd->secret->nonblocking = data->value.non_blocking;
250
rv = _PR_MapOptionName(data->option, &level, &name);
251
if (PR_SUCCESS == rv)
253
switch (data->option)
255
case PR_SockOpt_Linger:
257
#if !defined(XP_BEOS) || defined(BONE_VERSION)
258
struct linger linger;
259
linger.l_onoff = data->value.linger.polarity;
260
linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
261
rv = _PR_MD_SETSOCKOPT(
262
fd, level, name, (char*)&linger, sizeof(linger));
265
PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
269
case PR_SockOpt_Reuseaddr:
270
case PR_SockOpt_Keepalive:
271
case PR_SockOpt_NoDelay:
272
case PR_SockOpt_Broadcast:
274
#ifdef WIN32 /* Winsock */
279
value = (data->value.reuse_addr) ? 1 : 0;
280
rv = _PR_MD_SETSOCKOPT(
281
fd, level, name, (char*)&value, sizeof(value));
284
case PR_SockOpt_McastLoopback:
286
#ifdef WIN32 /* Winsock */
291
bool = data->value.mcast_loopback ? 1 : 0;
292
rv = _PR_MD_SETSOCKOPT(
293
fd, level, name, (char*)&bool, sizeof(bool));
296
case PR_SockOpt_RecvBufferSize:
297
case PR_SockOpt_SendBufferSize:
298
case PR_SockOpt_MaxSegment:
300
PRIntn value = data->value.recv_buffer_size;
301
rv = _PR_MD_SETSOCKOPT(
302
fd, level, name, (char*)&value, sizeof(value));
305
case PR_SockOpt_IpTimeToLive:
306
case PR_SockOpt_IpTypeOfService:
308
/* These options should really be an int (or PRIntn). */
309
rv = _PR_MD_SETSOCKOPT(
310
fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
313
case PR_SockOpt_McastTimeToLive:
315
#ifdef WIN32 /* Winsock */
320
ttl = data->value.mcast_ttl;
321
rv = _PR_MD_SETSOCKOPT(
322
fd, level, name, (char*)&ttl, sizeof(ttl));
325
#ifdef IP_ADD_MEMBERSHIP
326
case PR_SockOpt_AddMember:
327
case PR_SockOpt_DropMember:
330
mreq.imr_multiaddr.s_addr =
331
data->value.add_member.mcaddr.inet.ip;
332
mreq.imr_interface.s_addr =
333
data->value.add_member.ifaddr.inet.ip;
334
rv = _PR_MD_SETSOCKOPT(
335
fd, level, name, (char*)&mreq, sizeof(mreq));
338
#endif /* IP_ADD_MEMBERSHIP */
339
case PR_SockOpt_McastInterface:
341
/* This option is a struct in_addr. */
342
rv = _PR_MD_SETSOCKOPT(
343
fd, level, name, (char*)&data->value.mcast_if.inet.ip,
344
sizeof(data->value.mcast_if.inet.ip));
348
PR_NOT_REACHED("Unknown socket option");
353
} /* _PR_SocketSetSocketOption */
355
#endif /* ! _PR_PTHREADS */
358
*********************************************************************
359
*********************************************************************
361
** Make sure that the following is at the end of this file,
362
** because we will be playing with macro redefines.
364
*********************************************************************
365
*********************************************************************
370
** Sad but true. The DEC C header files define the following socket options
371
** differently to what UCX is expecting. The values that UCX expects are
372
** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values
373
** that UCX expects. Note that UCX V4.x will only accept these values while
374
** UCX V5.x will accept either. So in theory this hack can be removed once
375
** UCX V5 is the minimum.
377
#undef IP_MULTICAST_IF
378
#undef IP_MULTICAST_TTL
379
#undef IP_MULTICAST_LOOP
380
#undef IP_ADD_MEMBERSHIP
381
#undef IP_DROP_MEMBERSHIP
382
#include <ucx$inetdef.h>
383
#define IP_MULTICAST_IF UCX$C_IP_MULTICAST_IF
384
#define IP_MULTICAST_TTL UCX$C_IP_MULTICAST_TTL
385
#define IP_MULTICAST_LOOP UCX$C_IP_MULTICAST_LOOP
386
#define IP_ADD_MEMBERSHIP UCX$C_IP_ADD_MEMBERSHIP
387
#define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP
391
* Not every platform has all the socket options we want to
392
* support. Some older operating systems such as SunOS 4.1.3
393
* don't have the IP multicast socket options. Win32 doesn't
396
* To deal with this problem, we define the missing socket
397
* options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
398
* PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
399
* available on the platform is requested.
403
* Sanity check. SO_LINGER and TCP_NODELAY should be available
404
* on all platforms. Just to make sure we have included the
405
* appropriate header files. Then any undefined socket options
406
* are really missing.
409
#if !defined(SO_LINGER)
410
#error "SO_LINGER is not defined"
414
* Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
418
#if !defined(TCP_NODELAY)
419
#error "TCP_NODELAY is not defined"
424
* Make sure the value of _PR_NO_SUCH_SOCKOPT is not
425
* a valid socket option.
427
#define _PR_NO_SUCH_SOCKOPT -1
430
#define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
434
#define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
438
#define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
441
#ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
442
#define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
445
#ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
446
#define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
449
#ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
450
#define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
453
#ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
454
#define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
457
#ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
458
#define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
461
#ifndef IP_TTL /* set/get IP Time To Live */
462
#define IP_TTL _PR_NO_SUCH_SOCKOPT
465
#ifndef IP_TOS /* set/get IP Type Of Service */
466
#define IP_TOS _PR_NO_SUCH_SOCKOPT
469
#ifndef TCP_NODELAY /* don't delay to coalesce data */
470
#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
473
#ifndef TCP_MAXSEG /* maxumum segment size for tcp */
474
#define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
477
#ifndef SO_BROADCAST /* enable broadcast on udp sockets */
478
#define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
481
PRStatus _PR_MapOptionName(
482
PRSockOption optname, PRInt32 *level, PRInt32 *name)
484
static PRInt32 socketOptions[PR_SockOpt_Last] =
486
0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
487
IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
488
IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
489
TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
491
static PRInt32 socketLevels[PR_SockOpt_Last] =
493
0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
494
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
495
IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
496
IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
499
if ((optname < PR_SockOpt_Linger)
500
|| (optname >= PR_SockOpt_Last))
502
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
506
if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
508
PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
511
*name = socketOptions[optname];
512
*level = socketLevels[optname];
514
} /* _PR_MapOptionName */