Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / nsprpub / pr / src / io / prmapopt.c
blobc887c6446056b35df5756237cec485dc8721f04b
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/. */
6 /*
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__)
21 # include <winsock.h>
22 #endif
24 /* MinGW doesn't define these in its winsock.h. */
25 #ifdef __MINGW32__
26 # ifndef IP_TTL
27 # define IP_TTL 7
28 # endif
29 # ifndef IP_TOS
30 # define IP_TOS 8
31 # endif
32 #endif
34 #include "primpl.h"
36 #if defined(LINUX) || defined(ANDROID)
37 # include <netinet/in.h>
38 #endif
40 #ifdef DARWIN
41 # include <netinet/in.h>
42 # include <netinet/ip.h>
43 #endif
45 #ifdef HAVE_NETINET_TCP_H
46 # include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
47 #endif
49 #ifndef _PR_PTHREADS
51 PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc* fd,
52 PRSocketOptionData* data) {
53 PRStatus rv;
54 PRInt32 length;
55 PRInt32 level, name;
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;
63 return PR_SUCCESS;
66 rv = _PR_MapOptionName(data->option, &level, &name);
67 if (PR_SUCCESS == rv) {
68 switch (data->option) {
69 case PR_SockOpt_Linger: {
70 struct linger 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);
78 break;
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 */
86 BOOL value;
87 # else
88 PRIntn value;
89 # endif
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;
95 break;
97 case PR_SockOpt_McastLoopback: {
98 # ifdef WIN32 /* Winsock */
99 BOOL bool;
100 # else
101 PRUint8 bool;
102 # endif
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;
108 break;
110 case PR_SockOpt_RecvBufferSize:
111 case PR_SockOpt_SendBufferSize:
112 case PR_SockOpt_MaxSegment: {
113 PRIntn value;
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;
119 break;
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,
126 &length);
127 break;
129 case PR_SockOpt_McastTimeToLive: {
130 # ifdef WIN32 /* Winsock */
131 int ttl;
132 # else
133 PRUint8 ttl;
134 # endif
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;
140 break;
142 # ifdef IP_ADD_MEMBERSHIP
143 case PR_SockOpt_AddMember:
144 case PR_SockOpt_DropMember: {
145 struct ip_mreq mreq;
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;
152 break;
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);
160 break;
162 case PR_SockOpt_DontFrag: {
163 # if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
164 !defined(ANDROID)
165 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
166 rv = PR_FAILURE;
167 # else
168 # ifdef WIN32 /* Winsock */
169 DWORD value;
170 # else
171 PRIntn value;
172 # endif
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;
177 # else
178 data->value.dont_fragment = (value == IP_PMTUDISC_DO) ? 1 : 0;
179 # endif
180 # endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
181 !defined(ANDROID)) */
182 break;
184 default:
185 PR_NOT_REACHED("Unknown socket option");
186 break;
189 return rv;
190 } /* _PR_SocketGetSocketOption */
192 PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc* fd,
193 const PRSocketOptionData* data) {
194 PRStatus rv;
195 PRInt32 level, name;
198 * PR_SockOpt_Nonblocking is a special case that does not
199 * translate to a setsockopt call.
201 if (PR_SockOpt_Nonblocking == data->option) {
202 # ifdef WINNT
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
211 * afterwards.
213 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
214 return PR_FAILURE;
216 # endif
217 fd->secret->nonblocking = data->value.non_blocking;
218 return PR_SUCCESS;
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));
229 break;
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 */
237 BOOL value;
238 # else
239 PRIntn value;
240 # endif
241 value = (data->value.reuse_addr) ? 1 : 0;
242 rv = _PR_MD_SETSOCKOPT(fd, level, name, (char*)&value, sizeof(value));
243 break;
245 case PR_SockOpt_McastLoopback: {
246 # ifdef WIN32 /* Winsock */
247 BOOL bool;
248 # else
249 PRUint8 bool;
250 # endif
251 bool = data->value.mcast_loopback ? 1 : 0;
252 rv = _PR_MD_SETSOCKOPT(fd, level, name, (char*)&bool, sizeof(bool));
253 break;
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));
260 break;
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,
266 sizeof(PRUintn));
267 break;
269 case PR_SockOpt_McastTimeToLive: {
270 # ifdef WIN32 /* Winsock */
271 int ttl;
272 # else
273 PRUint8 ttl;
274 # endif
275 ttl = data->value.mcast_ttl;
276 rv = _PR_MD_SETSOCKOPT(fd, level, name, (char*)&ttl, sizeof(ttl));
277 break;
279 # ifdef IP_ADD_MEMBERSHIP
280 case PR_SockOpt_AddMember:
281 case PR_SockOpt_DropMember: {
282 struct ip_mreq mreq;
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));
286 break;
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));
294 break;
296 case PR_SockOpt_DontFrag: {
297 # if !defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
298 !defined(ANDROID)
299 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
300 rv = PR_FAILURE;
301 # else
302 # if defined(WIN32) /* Winsock */
303 DWORD value;
304 value = (data->value.dont_fragment) ? 1 : 0;
305 # elif defined(LINUX) || defined(ANDROID)
306 PRIntn value;
307 value = (data->value.dont_fragment) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
308 # elif defined(DARWIN)
309 PRIntn value;
310 value = data->value.dont_fragment;
311 # endif
312 rv = _PR_MD_SETSOCKOPT(fd, level, name, (char*)&value, sizeof(value));
313 # endif /* !(!defined(WIN32) && !defined(DARWIN) && !defined(LINUX) && \
314 !defined(ANDROID)) */
315 break;
317 default:
318 PR_NOT_REACHED("Unknown socket option");
319 break;
322 return rv;
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
342 * have TCP_MAXSEG.
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"
359 #endif
361 #if !defined(TCP_NODELAY)
362 # error "TCP_NODELAY is not defined"
363 #endif
366 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
367 * a valid socket option.
369 #define _PR_NO_SUCH_SOCKOPT -1
371 #ifndef SO_KEEPALIVE
372 # define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
373 #endif
375 #ifndef SO_SNDBUF
376 # define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
377 #endif
379 #ifndef SO_RCVBUF
380 # define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
381 #endif
383 #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
384 # define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
385 #endif
387 #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
388 # define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
389 #endif
391 #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
392 # define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
393 #endif
395 #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
396 # define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
397 #endif
399 #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
400 # define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
401 #endif
403 #ifndef IP_TTL /* set/get IP Time To Live */
404 # define IP_TTL _PR_NO_SUCH_SOCKOPT
405 #endif
407 #ifndef IP_TOS /* set/get IP Type Of Service */
408 # define IP_TOS _PR_NO_SUCH_SOCKOPT
409 #endif
411 /* set/get IP do not fragment */
412 #if defined(WIN32)
413 # ifndef IP_DONTFRAGMENT
414 # define IP_DONTFRAGMENT _PR_NO_SUCH_SOCKOPT
415 # endif
417 #elif defined(LINUX) || defined(ANDROID)
418 # ifndef IP_MTU_DISCOVER
419 # define IP_MTU_DISCOVER _PR_NO_SUCH_SOCKOPT
420 # endif
422 #elif defined(DARWIN)
423 # ifndef IP_DONTFRAG
424 # define IP_DONTFRAG _PR_NO_SUCH_SOCKOPT
425 # endif
426 #endif
428 #ifndef TCP_NODELAY /* don't delay to coalesce data */
429 # define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
430 #endif
432 #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
433 # define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
434 #endif
436 #ifndef SO_BROADCAST /* enable broadcast on UDP sockets */
437 # define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
438 #endif
440 #ifndef SO_REUSEPORT /* allow local address & port reuse */
441 # define SO_REUSEPORT _PR_NO_SUCH_SOCKOPT
442 #endif
444 PRStatus _PR_MapOptionName(PRSockOption optname, PRInt32* level,
445 PRInt32* name) {
446 static PRInt32 socketOptions[PR_SockOpt_Last] = {
448 SO_LINGER,
449 SO_REUSEADDR,
450 SO_KEEPALIVE,
451 SO_RCVBUF,
452 SO_SNDBUF,
453 IP_TTL,
454 IP_TOS,
455 IP_ADD_MEMBERSHIP,
456 IP_DROP_MEMBERSHIP,
457 IP_MULTICAST_IF,
458 IP_MULTICAST_TTL,
459 IP_MULTICAST_LOOP,
460 TCP_NODELAY,
461 TCP_MAXSEG,
462 SO_BROADCAST,
463 SO_REUSEPORT,
464 #if defined(WIN32)
465 IP_DONTFRAGMENT,
466 #elif defined(LINUX) || defined(ANDROID)
467 IP_MTU_DISCOVER,
468 #elif defined(DARWIN)
469 IP_DONTFRAG,
470 #else
471 _PR_NO_SUCH_SOCKOPT,
472 #endif
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);
481 return PR_FAILURE;
484 if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT) {
485 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
486 return PR_FAILURE;
488 *name = socketOptions[optname];
489 *level = socketLevels[optname];
490 return PR_SUCCESS;
491 } /* _PR_MapOptionName */