nspr: import 3.0 RC1 cutoff from CVS
[mozilla-nspr.git] / nsprpub / pr / src / io / prmapopt.c
blobe4811e5725f2b1d3b690684c64942bfc9419a6d3
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
13 * License.
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.
22 * Contributor(s):
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__)
53 #include <winsock.h>
54 #endif
56 /* MinGW doesn't define these in its winsock.h. */
57 #ifdef __MINGW32__
58 #ifndef IP_TTL
59 #define IP_TTL 7
60 #endif
61 #ifndef IP_TOS
62 #define IP_TOS 8
63 #endif
64 #endif
66 #include "primpl.h"
68 #if defined(NEXTSTEP)
69 /* NEXTSTEP is special: this must come before netinet/tcp.h. */
70 #include <netinet/in_systm.h> /* n_short, n_long, n_time */
71 #endif
73 #if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
74 #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
75 #endif
77 #ifndef _PR_PTHREADS
79 PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
81 PRStatus rv;
82 PRInt32 length;
83 PRInt32 level, name;
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;
92 return PR_SUCCESS;
95 rv = _PR_MapOptionName(data->option, &level, &name);
96 if (PR_SUCCESS == rv)
98 switch (data->option)
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);
115 break;
116 #else
117 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
118 return PR_FAILURE;
119 #endif
121 case PR_SockOpt_Reuseaddr:
122 case PR_SockOpt_Keepalive:
123 case PR_SockOpt_NoDelay:
124 case PR_SockOpt_Broadcast:
126 #ifdef WIN32 /* Winsock */
127 BOOL value;
128 #else
129 PRIntn value;
130 #endif
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;
136 break;
138 case PR_SockOpt_McastLoopback:
140 #ifdef WIN32 /* Winsock */
141 BOOL bool;
142 #else
143 PRUint8 bool;
144 #endif
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;
150 break;
152 case PR_SockOpt_RecvBufferSize:
153 case PR_SockOpt_SendBufferSize:
154 case PR_SockOpt_MaxSegment:
156 PRIntn value;
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;
162 break;
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);
171 break;
173 case PR_SockOpt_McastTimeToLive:
175 #ifdef WIN32 /* Winsock */
176 int ttl;
177 #else
178 PRUint8 ttl;
179 #endif
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;
185 break;
187 #ifdef IP_ADD_MEMBERSHIP
188 case PR_SockOpt_AddMember:
189 case PR_SockOpt_DropMember:
191 struct ip_mreq mreq;
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;
202 break;
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(
210 fd, level, name,
211 (char*)&data->value.mcast_if.inet.ip, &length);
212 break;
214 default:
215 PR_NOT_REACHED("Unknown socket option");
216 break;
219 return rv;
220 } /* _PR_SocketGetSocketOption */
222 PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
224 PRStatus rv;
225 PRInt32 level, name;
228 * PR_SockOpt_Nonblocking is a special case that does not
229 * translate to a setsockopt call.
231 if (PR_SockOpt_Nonblocking == data->option)
233 #ifdef WINNT
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
243 * afterwards.
245 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
246 return PR_FAILURE;
248 #endif
249 fd->secret->nonblocking = data->value.non_blocking;
250 return PR_SUCCESS;
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));
266 break;
267 #else
268 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
269 return PR_FAILURE;
270 #endif
272 case PR_SockOpt_Reuseaddr:
273 case PR_SockOpt_Keepalive:
274 case PR_SockOpt_NoDelay:
275 case PR_SockOpt_Broadcast:
277 #ifdef WIN32 /* Winsock */
278 BOOL value;
279 #else
280 PRIntn value;
281 #endif
282 value = (data->value.reuse_addr) ? 1 : 0;
283 rv = _PR_MD_SETSOCKOPT(
284 fd, level, name, (char*)&value, sizeof(value));
285 break;
287 case PR_SockOpt_McastLoopback:
289 #ifdef WIN32 /* Winsock */
290 BOOL bool;
291 #else
292 PRUint8 bool;
293 #endif
294 bool = data->value.mcast_loopback ? 1 : 0;
295 rv = _PR_MD_SETSOCKOPT(
296 fd, level, name, (char*)&bool, sizeof(bool));
297 break;
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));
306 break;
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));
314 break;
316 case PR_SockOpt_McastTimeToLive:
318 #ifdef WIN32 /* Winsock */
319 int ttl;
320 #else
321 PRUint8 ttl;
322 #endif
323 ttl = data->value.mcast_ttl;
324 rv = _PR_MD_SETSOCKOPT(
325 fd, level, name, (char*)&ttl, sizeof(ttl));
326 break;
328 #ifdef IP_ADD_MEMBERSHIP
329 case PR_SockOpt_AddMember:
330 case PR_SockOpt_DropMember:
332 struct ip_mreq mreq;
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));
339 break;
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));
348 break;
350 default:
351 PR_NOT_REACHED("Unknown socket option");
352 break;
355 return rv;
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 *********************************************************************
371 #if defined(VMS)
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
391 #endif
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
397 * have TCP_MAXSEG.
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"
414 #endif
417 * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
418 * in <netinet/tcp.h>
420 #if !defined(NCR)
421 #if !defined(TCP_NODELAY)
422 #error "TCP_NODELAY is not defined"
423 #endif
424 #endif
427 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
428 * a valid socket option.
430 #define _PR_NO_SUCH_SOCKOPT -1
432 #ifndef SO_KEEPALIVE
433 #define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
434 #endif
436 #ifndef SO_SNDBUF
437 #define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
438 #endif
440 #ifndef SO_RCVBUF
441 #define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
442 #endif
444 #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
445 #define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
446 #endif
448 #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
449 #define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
450 #endif
452 #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
453 #define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
454 #endif
456 #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
457 #define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
458 #endif
460 #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
461 #define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
462 #endif
464 #ifndef IP_TTL /* set/get IP Time To Live */
465 #define IP_TTL _PR_NO_SUCH_SOCKOPT
466 #endif
468 #ifndef IP_TOS /* set/get IP Type Of Service */
469 #define IP_TOS _PR_NO_SUCH_SOCKOPT
470 #endif
472 #ifndef TCP_NODELAY /* don't delay to coalesce data */
473 #define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
474 #endif
476 #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
477 #define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
478 #endif
480 #ifndef SO_BROADCAST /* enable broadcast on udp sockets */
481 #define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
482 #endif
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);
506 return PR_FAILURE;
509 if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
511 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
512 return PR_FAILURE;
514 *name = socketOptions[optname];
515 *level = socketLevels[optname];
516 return PR_SUCCESS;
517 } /* _PR_MapOptionName */