1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * This file defines _PR_MapOptionName(). The purpose of putting
40 * _PR_MapOptionName() in a separate file is to work around a Winsock
41 * header file problem on Windows NT.
43 * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
44 * to use Service Pack 3 extensions), windows.h includes winsock2.h
45 * (instead of winsock.h), which doesn't define many socket options
46 * defined in winsock.h.
48 * We need the socket options defined in winsock.h. So this file
49 * includes winsock.h, with _WIN32_WINNT undefined.
52 #if defined(WINNT) || defined(__MINGW32__)
56 /* MinGW doesn't define these in its winsock.h. */
69 /* NEXTSTEP is special: this must come before netinet/tcp.h. */
70 #include <netinet/in_systm.h> /* n_short, n_long, n_time */
73 #if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
74 #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
79 PRStatus PR_CALLBACK
_PR_SocketGetSocketOption(PRFileDesc
*fd
, PRSocketOptionData
*data
)
86 * PR_SockOpt_Nonblocking is a special case that does not
87 * translate to a getsockopt() call
89 if (PR_SockOpt_Nonblocking
== data
->option
)
91 data
->value
.non_blocking
= fd
->secret
->nonblocking
;
95 rv
= _PR_MapOptionName(data
->option
, &level
, &name
);
100 case PR_SockOpt_Linger
:
102 #if !defined(XP_BEOS) || defined(BONE_VERSION)
103 struct linger linger
;
104 length
= sizeof(linger
);
105 rv
= _PR_MD_GETSOCKOPT(
106 fd
, level
, name
, (char *) &linger
, &length
);
107 if (PR_SUCCESS
== rv
)
109 PR_ASSERT(sizeof(linger
) == length
);
110 data
->value
.linger
.polarity
=
111 (linger
.l_onoff
) ? PR_TRUE
: PR_FALSE
;
112 data
->value
.linger
.linger
=
113 PR_SecondsToInterval(linger
.l_linger
);
117 PR_SetError( PR_NOT_IMPLEMENTED_ERROR
, 0 );
121 case PR_SockOpt_Reuseaddr
:
122 case PR_SockOpt_Keepalive
:
123 case PR_SockOpt_NoDelay
:
124 case PR_SockOpt_Broadcast
:
126 #ifdef WIN32 /* Winsock */
131 length
= sizeof(value
);
132 rv
= _PR_MD_GETSOCKOPT(
133 fd
, level
, name
, (char*)&value
, &length
);
134 if (PR_SUCCESS
== rv
)
135 data
->value
.reuse_addr
= (0 == value
) ? PR_FALSE
: PR_TRUE
;
138 case PR_SockOpt_McastLoopback
:
140 #ifdef WIN32 /* Winsock */
145 length
= sizeof(bool);
146 rv
= _PR_MD_GETSOCKOPT(
147 fd
, level
, name
, (char*)&bool, &length
);
148 if (PR_SUCCESS
== rv
)
149 data
->value
.mcast_loopback
= (0 == bool) ? PR_FALSE
: PR_TRUE
;
152 case PR_SockOpt_RecvBufferSize
:
153 case PR_SockOpt_SendBufferSize
:
154 case PR_SockOpt_MaxSegment
:
157 length
= sizeof(value
);
158 rv
= _PR_MD_GETSOCKOPT(
159 fd
, level
, name
, (char*)&value
, &length
);
160 if (PR_SUCCESS
== rv
)
161 data
->value
.recv_buffer_size
= value
;
164 case PR_SockOpt_IpTimeToLive
:
165 case PR_SockOpt_IpTypeOfService
:
167 /* These options should really be an int (or PRIntn). */
168 length
= sizeof(PRUintn
);
169 rv
= _PR_MD_GETSOCKOPT(
170 fd
, level
, name
, (char*)&data
->value
.ip_ttl
, &length
);
173 case PR_SockOpt_McastTimeToLive
:
175 #ifdef WIN32 /* Winsock */
180 length
= sizeof(ttl
);
181 rv
= _PR_MD_GETSOCKOPT(
182 fd
, level
, name
, (char*)&ttl
, &length
);
183 if (PR_SUCCESS
== rv
)
184 data
->value
.mcast_ttl
= ttl
;
187 #ifdef IP_ADD_MEMBERSHIP
188 case PR_SockOpt_AddMember
:
189 case PR_SockOpt_DropMember
:
192 length
= sizeof(mreq
);
193 rv
= _PR_MD_GETSOCKOPT(
194 fd
, level
, name
, (char*)&mreq
, &length
);
195 if (PR_SUCCESS
== rv
)
197 data
->value
.add_member
.mcaddr
.inet
.ip
=
198 mreq
.imr_multiaddr
.s_addr
;
199 data
->value
.add_member
.ifaddr
.inet
.ip
=
200 mreq
.imr_interface
.s_addr
;
204 #endif /* IP_ADD_MEMBERSHIP */
205 case PR_SockOpt_McastInterface
:
207 /* This option is a struct in_addr. */
208 length
= sizeof(data
->value
.mcast_if
.inet
.ip
);
209 rv
= _PR_MD_GETSOCKOPT(
211 (char*)&data
->value
.mcast_if
.inet
.ip
, &length
);
215 PR_NOT_REACHED("Unknown socket option");
220 } /* _PR_SocketGetSocketOption */
222 PRStatus PR_CALLBACK
_PR_SocketSetSocketOption(PRFileDesc
*fd
, const PRSocketOptionData
*data
)
228 * PR_SockOpt_Nonblocking is a special case that does not
229 * translate to a setsockopt call.
231 if (PR_SockOpt_Nonblocking
== data
->option
)
234 PR_ASSERT((fd
->secret
->md
.io_model_committed
== PR_FALSE
)
235 || (fd
->secret
->nonblocking
== data
->value
.non_blocking
));
236 if (fd
->secret
->md
.io_model_committed
237 && (fd
->secret
->nonblocking
!= data
->value
.non_blocking
))
240 * On NT, once we have associated a socket with the io
241 * completion port, we can't disassociate it. So we
242 * can't change the nonblocking option of the socket
245 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
249 fd
->secret
->nonblocking
= data
->value
.non_blocking
;
253 rv
= _PR_MapOptionName(data
->option
, &level
, &name
);
254 if (PR_SUCCESS
== rv
)
256 switch (data
->option
)
258 case PR_SockOpt_Linger
:
260 #if !defined(XP_BEOS) || defined(BONE_VERSION)
261 struct linger linger
;
262 linger
.l_onoff
= data
->value
.linger
.polarity
;
263 linger
.l_linger
= PR_IntervalToSeconds(data
->value
.linger
.linger
);
264 rv
= _PR_MD_SETSOCKOPT(
265 fd
, level
, name
, (char*)&linger
, sizeof(linger
));
268 PR_SetError( PR_NOT_IMPLEMENTED_ERROR
, 0 );
272 case PR_SockOpt_Reuseaddr
:
273 case PR_SockOpt_Keepalive
:
274 case PR_SockOpt_NoDelay
:
275 case PR_SockOpt_Broadcast
:
277 #ifdef WIN32 /* Winsock */
282 value
= (data
->value
.reuse_addr
) ? 1 : 0;
283 rv
= _PR_MD_SETSOCKOPT(
284 fd
, level
, name
, (char*)&value
, sizeof(value
));
287 case PR_SockOpt_McastLoopback
:
289 #ifdef WIN32 /* Winsock */
294 bool = data
->value
.mcast_loopback
? 1 : 0;
295 rv
= _PR_MD_SETSOCKOPT(
296 fd
, level
, name
, (char*)&bool, sizeof(bool));
299 case PR_SockOpt_RecvBufferSize
:
300 case PR_SockOpt_SendBufferSize
:
301 case PR_SockOpt_MaxSegment
:
303 PRIntn value
= data
->value
.recv_buffer_size
;
304 rv
= _PR_MD_SETSOCKOPT(
305 fd
, level
, name
, (char*)&value
, sizeof(value
));
308 case PR_SockOpt_IpTimeToLive
:
309 case PR_SockOpt_IpTypeOfService
:
311 /* These options should really be an int (or PRIntn). */
312 rv
= _PR_MD_SETSOCKOPT(
313 fd
, level
, name
, (char*)&data
->value
.ip_ttl
, sizeof(PRUintn
));
316 case PR_SockOpt_McastTimeToLive
:
318 #ifdef WIN32 /* Winsock */
323 ttl
= data
->value
.mcast_ttl
;
324 rv
= _PR_MD_SETSOCKOPT(
325 fd
, level
, name
, (char*)&ttl
, sizeof(ttl
));
328 #ifdef IP_ADD_MEMBERSHIP
329 case PR_SockOpt_AddMember
:
330 case PR_SockOpt_DropMember
:
333 mreq
.imr_multiaddr
.s_addr
=
334 data
->value
.add_member
.mcaddr
.inet
.ip
;
335 mreq
.imr_interface
.s_addr
=
336 data
->value
.add_member
.ifaddr
.inet
.ip
;
337 rv
= _PR_MD_SETSOCKOPT(
338 fd
, level
, name
, (char*)&mreq
, sizeof(mreq
));
341 #endif /* IP_ADD_MEMBERSHIP */
342 case PR_SockOpt_McastInterface
:
344 /* This option is a struct in_addr. */
345 rv
= _PR_MD_SETSOCKOPT(
346 fd
, level
, name
, (char*)&data
->value
.mcast_if
.inet
.ip
,
347 sizeof(data
->value
.mcast_if
.inet
.ip
));
351 PR_NOT_REACHED("Unknown socket option");
356 } /* _PR_SocketSetSocketOption */
358 #endif /* ! _PR_PTHREADS */
361 *********************************************************************
362 *********************************************************************
364 ** Make sure that the following is at the end of this file,
365 ** because we will be playing with macro redefines.
367 *********************************************************************
368 *********************************************************************
373 ** Sad but true. The DEC C header files define the following socket options
374 ** differently to what UCX is expecting. The values that UCX expects are
375 ** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values
376 ** that UCX expects. Note that UCX V4.x will only accept these values while
377 ** UCX V5.x will accept either. So in theory this hack can be removed once
378 ** UCX V5 is the minimum.
380 #undef IP_MULTICAST_IF
381 #undef IP_MULTICAST_TTL
382 #undef IP_MULTICAST_LOOP
383 #undef IP_ADD_MEMBERSHIP
384 #undef IP_DROP_MEMBERSHIP
385 #include <ucx$inetdef.h>
386 #define IP_MULTICAST_IF UCX$C_IP_MULTICAST_IF
387 #define IP_MULTICAST_TTL UCX$C_IP_MULTICAST_TTL
388 #define IP_MULTICAST_LOOP UCX$C_IP_MULTICAST_LOOP
389 #define IP_ADD_MEMBERSHIP UCX$C_IP_ADD_MEMBERSHIP
390 #define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP
394 * Not every platform has all the socket options we want to
395 * support. Some older operating systems such as SunOS 4.1.3
396 * don't have the IP multicast socket options. Win32 doesn't
399 * To deal with this problem, we define the missing socket
400 * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
401 * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
402 * available on the platform is requested.
406 * Sanity check. SO_LINGER and TCP_NODELAY should be available
407 * on all platforms. Just to make sure we have included the
408 * appropriate header files. Then any undefined socket options
409 * are really missing.
412 #if !defined(SO_LINGER)
413 #error "SO_LINGER is not defined"
417 * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
421 #if !defined(TCP_NODELAY)
422 #error "TCP_NODELAY is not defined"
427 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
428 * a valid socket option.
430 #define _PR_NO_SUCH_SOCKOPT -1
433 #define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
437 #define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
441 #define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
444 #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
445 #define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
448 #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
449 #define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
452 #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
453 #define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
456 #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
457 #define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
460 #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
461 #define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
464 #ifndef IP_TTL /* set/get IP Time To Live */
465 #define IP_TTL _PR_NO_SUCH_SOCKOPT
468 #ifndef IP_TOS /* set/get IP Type Of Service */
469 #define IP_TOS _PR_NO_SUCH_SOCKOPT
472 #ifndef TCP_NODELAY /* don't delay to coalesce data */
473 #define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
476 #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
477 #define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
480 #ifndef SO_BROADCAST /* enable broadcast on udp sockets */
481 #define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
484 PRStatus
_PR_MapOptionName(
485 PRSockOption optname
, PRInt32
*level
, PRInt32
*name
)
487 static PRInt32 socketOptions
[PR_SockOpt_Last
] =
489 0, SO_LINGER
, SO_REUSEADDR
, SO_KEEPALIVE
, SO_RCVBUF
, SO_SNDBUF
,
490 IP_TTL
, IP_TOS
, IP_ADD_MEMBERSHIP
, IP_DROP_MEMBERSHIP
,
491 IP_MULTICAST_IF
, IP_MULTICAST_TTL
, IP_MULTICAST_LOOP
,
492 TCP_NODELAY
, TCP_MAXSEG
, SO_BROADCAST
494 static PRInt32 socketLevels
[PR_SockOpt_Last
] =
496 0, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
,
497 IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
,
498 IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
,
499 IPPROTO_TCP
, IPPROTO_TCP
, SOL_SOCKET
502 if ((optname
< PR_SockOpt_Linger
)
503 || (optname
>= PR_SockOpt_Last
))
505 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
509 if (socketOptions
[optname
] == _PR_NO_SUCH_SOCKOPT
)
511 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR
, 0);
514 *name
= socketOptions
[optname
];
515 *level
= socketLevels
[optname
];
517 } /* _PR_MapOptionName */