1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * This file defines _PR_MapOptionName(). The purpose of putting
8 * _PR_MapOptionName() in a separate file is to work around a Winsock
9 * header file problem on Windows NT.
11 * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
12 * to use Service Pack 3 extensions), windows.h includes winsock2.h
13 * (instead of winsock.h), which doesn't define many socket options
14 * defined in winsock.h.
16 * We need the socket options defined in winsock.h. So this file
17 * includes winsock.h, with _WIN32_WINNT undefined.
20 #if defined(WINNT) || defined(__MINGW32__)
24 /* MinGW doesn't define these in its winsock.h. */
36 #if defined(LINUX) || defined(ANDROID)
37 # include <netinet/in.h>
41 # include <netinet/in.h>
42 # include <netinet/ip.h>
45 #ifdef HAVE_NETINET_TCP_H
46 # include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
51 PRStatus PR_CALLBACK
_PR_SocketGetSocketOption(PRFileDesc
* fd
,
52 PRSocketOptionData
* data
) {
58 * PR_SockOpt_Nonblocking is a special case that does not
59 * translate to a getsockopt() call
61 if (PR_SockOpt_Nonblocking
== data
->option
) {
62 data
->value
.non_blocking
= fd
->secret
->nonblocking
;
66 rv
= _PR_MapOptionName(data
->option
, &level
, &name
);
67 if (PR_SUCCESS
== rv
) {
68 switch (data
->option
) {
69 case PR_SockOpt_Linger
: {
71 length
= sizeof(linger
);
72 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&linger
, &length
);
73 if (PR_SUCCESS
== rv
) {
74 PR_ASSERT(sizeof(linger
) == length
);
75 data
->value
.linger
.polarity
= (linger
.l_onoff
) ? PR_TRUE
: PR_FALSE
;
76 data
->value
.linger
.linger
= PR_SecondsToInterval(linger
.l_linger
);
80 case PR_SockOpt_Reuseaddr
:
81 case PR_SockOpt_Keepalive
:
82 case PR_SockOpt_NoDelay
:
83 case PR_SockOpt_Broadcast
:
84 case PR_SockOpt_Reuseport
: {
85 # ifdef WIN32 /* Winsock */
90 length
= sizeof(value
);
91 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&value
, &length
);
92 if (PR_SUCCESS
== rv
) {
93 data
->value
.reuse_addr
= (0 == value
) ? PR_FALSE
: PR_TRUE
;
97 case PR_SockOpt_McastLoopback
: {
98 # ifdef WIN32 /* Winsock */
103 length
= sizeof(bool);
104 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&bool, &length
);
105 if (PR_SUCCESS
== rv
) {
106 data
->value
.mcast_loopback
= (0 == bool) ? PR_FALSE
: PR_TRUE
;
110 case PR_SockOpt_RecvBufferSize
:
111 case PR_SockOpt_SendBufferSize
:
112 case PR_SockOpt_MaxSegment
: {
114 length
= sizeof(value
);
115 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&value
, &length
);
116 if (PR_SUCCESS
== rv
) {
117 data
->value
.recv_buffer_size
= value
;
121 case PR_SockOpt_IpTimeToLive
:
122 case PR_SockOpt_IpTypeOfService
: {
123 /* These options should really be an int (or PRIntn). */
124 length
= sizeof(PRUintn
);
125 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&data
->value
.ip_ttl
,
129 case PR_SockOpt_McastTimeToLive
: {
130 # ifdef WIN32 /* Winsock */
135 length
= sizeof(ttl
);
136 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&ttl
, &length
);
137 if (PR_SUCCESS
== rv
) {
138 data
->value
.mcast_ttl
= ttl
;
142 # ifdef IP_ADD_MEMBERSHIP
143 case PR_SockOpt_AddMember
:
144 case PR_SockOpt_DropMember
: {
146 length
= sizeof(mreq
);
147 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&mreq
, &length
);
148 if (PR_SUCCESS
== rv
) {
149 data
->value
.add_member
.mcaddr
.inet
.ip
= mreq
.imr_multiaddr
.s_addr
;
150 data
->value
.add_member
.ifaddr
.inet
.ip
= mreq
.imr_interface
.s_addr
;
154 # endif /* IP_ADD_MEMBERSHIP */
155 case PR_SockOpt_McastInterface
: {
156 /* This option is a struct in_addr. */
157 length
= sizeof(data
->value
.mcast_if
.inet
.ip
);
158 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
,
159 (char*)&data
->value
.mcast_if
.inet
.ip
, &length
);
162 case PR_SockOpt_DontFrag
: {
163 # if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
165 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR
, 0);
168 # ifdef WIN32 /* Winsock */
173 length
= sizeof(value
);
174 rv
= _PR_MD_GETSOCKOPT(fd
, level
, name
, (char*)&value
, &length
);
175 # if defined(WIN32) || defined(DARWIN)
176 data
->value
.dont_fragment
= value
;
178 data
->value
.dont_fragment
= (value
== IP_PMTUDISC_DO
) ? 1 : 0;
180 # endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
181 !defined(ANDROID)) */
185 PR_NOT_REACHED("Unknown socket option");
190 } /* _PR_SocketGetSocketOption */
192 PRStatus PR_CALLBACK
_PR_SocketSetSocketOption(PRFileDesc
* fd
,
193 const PRSocketOptionData
* data
) {
198 * PR_SockOpt_Nonblocking is a special case that does not
199 * translate to a setsockopt call.
201 if (PR_SockOpt_Nonblocking
== data
->option
) {
203 PR_ASSERT((fd
->secret
->md
.io_model_committed
== PR_FALSE
) ||
204 (fd
->secret
->nonblocking
== data
->value
.non_blocking
));
205 if (fd
->secret
->md
.io_model_committed
&&
206 (fd
->secret
->nonblocking
!= data
->value
.non_blocking
)) {
208 * On NT, once we have associated a socket with the io
209 * completion port, we can't disassociate it. So we
210 * can't change the nonblocking option of the socket
213 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
217 fd
->secret
->nonblocking
= data
->value
.non_blocking
;
221 rv
= _PR_MapOptionName(data
->option
, &level
, &name
);
222 if (PR_SUCCESS
== rv
) {
223 switch (data
->option
) {
224 case PR_SockOpt_Linger
: {
225 struct linger linger
;
226 linger
.l_onoff
= data
->value
.linger
.polarity
;
227 linger
.l_linger
= PR_IntervalToSeconds(data
->value
.linger
.linger
);
228 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&linger
, sizeof(linger
));
231 case PR_SockOpt_Reuseaddr
:
232 case PR_SockOpt_Keepalive
:
233 case PR_SockOpt_NoDelay
:
234 case PR_SockOpt_Broadcast
:
235 case PR_SockOpt_Reuseport
: {
236 # ifdef WIN32 /* Winsock */
241 value
= (data
->value
.reuse_addr
) ? 1 : 0;
242 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&value
, sizeof(value
));
245 case PR_SockOpt_McastLoopback
: {
246 # ifdef WIN32 /* Winsock */
251 bool = data
->value
.mcast_loopback
? 1 : 0;
252 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&bool, sizeof(bool));
255 case PR_SockOpt_RecvBufferSize
:
256 case PR_SockOpt_SendBufferSize
:
257 case PR_SockOpt_MaxSegment
: {
258 PRIntn value
= data
->value
.recv_buffer_size
;
259 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&value
, sizeof(value
));
262 case PR_SockOpt_IpTimeToLive
:
263 case PR_SockOpt_IpTypeOfService
: {
264 /* These options should really be an int (or PRIntn). */
265 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&data
->value
.ip_ttl
,
269 case PR_SockOpt_McastTimeToLive
: {
270 # ifdef WIN32 /* Winsock */
275 ttl
= data
->value
.mcast_ttl
;
276 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&ttl
, sizeof(ttl
));
279 # ifdef IP_ADD_MEMBERSHIP
280 case PR_SockOpt_AddMember
:
281 case PR_SockOpt_DropMember
: {
283 mreq
.imr_multiaddr
.s_addr
= data
->value
.add_member
.mcaddr
.inet
.ip
;
284 mreq
.imr_interface
.s_addr
= data
->value
.add_member
.ifaddr
.inet
.ip
;
285 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&mreq
, sizeof(mreq
));
288 # endif /* IP_ADD_MEMBERSHIP */
289 case PR_SockOpt_McastInterface
: {
290 /* This option is a struct in_addr. */
291 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
,
292 (char*)&data
->value
.mcast_if
.inet
.ip
,
293 sizeof(data
->value
.mcast_if
.inet
.ip
));
296 case PR_SockOpt_DontFrag
: {
297 # if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
299 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR
, 0);
302 # if defined(WIN32) /* Winsock */
304 value
= (data
->value
.dont_fragment
) ? 1 : 0;
305 # elif defined(LINUX) || defined(ANDROID)
307 value
= (data
->value
.dont_fragment
) ? IP_PMTUDISC_DO
: IP_PMTUDISC_DONT
;
308 # elif defined(DARWIN)
310 value
= data
->value
.dont_fragment
;
312 rv
= _PR_MD_SETSOCKOPT(fd
, level
, name
, (char*)&value
, sizeof(value
));
313 # endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
314 !defined(ANDROID)) */
318 PR_NOT_REACHED("Unknown socket option");
323 } /* _PR_SocketSetSocketOption */
325 #endif /* ! _PR_PTHREADS */
328 *********************************************************************
329 *********************************************************************
331 ** Make sure that the following is at the end of this file,
332 ** because we will be playing with macro redefines.
334 *********************************************************************
335 *********************************************************************
339 * Not every platform has all the socket options we want to
340 * support. Some older operating systems such as SunOS 4.1.3
341 * don't have the IP multicast socket options. Win32 doesn't
344 * To deal with this problem, we define the missing socket
345 * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
346 * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
347 * available on the platform is requested.
351 * Sanity check. SO_LINGER and TCP_NODELAY should be available
352 * on all platforms. Just to make sure we have included the
353 * appropriate header files. Then any undefined socket options
354 * are really missing.
357 #if !defined(SO_LINGER)
358 # error "SO_LINGER is not defined"
361 #if !defined(TCP_NODELAY)
362 # error "TCP_NODELAY is not defined"
366 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
367 * a valid socket option.
369 #define _PR_NO_SUCH_SOCKOPT -1
372 # define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
376 # define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
380 # define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
383 #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
384 # define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
387 #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
388 # define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
391 #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
392 # define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
395 #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
396 # define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
399 #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
400 # define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
403 #ifndef IP_TTL /* set/get IP Time To Live */
404 # define IP_TTL _PR_NO_SUCH_SOCKOPT
407 #ifndef IP_TOS /* set/get IP Type Of Service */
408 # define IP_TOS _PR_NO_SUCH_SOCKOPT
411 /* set/get IP do not fragment */
413 # ifndef IP_DONTFRAGMENT
414 # define IP_DONTFRAGMENT _PR_NO_SUCH_SOCKOPT
417 #elif defined(LINUX) || defined(ANDROID)
418 # ifndef IP_MTU_DISCOVER
419 # define IP_MTU_DISCOVER _PR_NO_SUCH_SOCKOPT
422 #elif defined(DARWIN)
424 # define IP_DONTFRAG _PR_NO_SUCH_SOCKOPT
428 #ifndef TCP_NODELAY /* don't delay to coalesce data */
429 # define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
432 #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
433 # define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
436 #ifndef SO_BROADCAST /* enable broadcast on UDP sockets */
437 # define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
440 #ifndef SO_REUSEPORT /* allow local address & port reuse */
441 # define SO_REUSEPORT _PR_NO_SUCH_SOCKOPT
444 PRStatus
_PR_MapOptionName(PRSockOption optname
, PRInt32
* level
,
446 static PRInt32 socketOptions
[PR_SockOpt_Last
] = {
466 #elif defined(LINUX) || defined(ANDROID)
468 #elif defined(DARWIN)
474 static PRInt32 socketLevels
[PR_SockOpt_Last
] = {
475 0, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
, SOL_SOCKET
,
476 IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
, IPPROTO_IP
,
477 IPPROTO_IP
, IPPROTO_TCP
, IPPROTO_TCP
, SOL_SOCKET
, SOL_SOCKET
, IPPROTO_IP
};
479 if ((optname
< PR_SockOpt_Linger
) || (optname
>= PR_SockOpt_Last
)) {
480 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
484 if (socketOptions
[optname
] == _PR_NO_SUCH_SOCKOPT
) {
485 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR
, 0);
488 *name
= socketOptions
[optname
];
489 *level
= socketLevels
[optname
];
491 } /* _PR_MapOptionName */