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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
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.
21 : *
22 : * Contributor(s):
23 : *
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.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
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.
42 : *
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.
47 : *
48 : * We need the socket options defined in winsock.h. So this file
49 : * includes winsock.h, with _WIN32_WINNT undefined.
50 : */
51 :
52 : #if defined(WINNT) || defined(__MINGW32__)
53 : #include <winsock.h>
54 : #endif
55 :
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
65 :
66 : #include "primpl.h"
67 :
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
72 :
73 : #ifdef HAVE_NETINET_TCP_H
74 : #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
75 : #endif
76 :
77 : #ifndef _PR_PTHREADS
78 :
79 : PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
80 : {
81 : PRStatus rv;
82 : PRInt32 length;
83 : PRInt32 level, name;
84 :
85 : /*
86 : * PR_SockOpt_Nonblocking is a special case that does not
87 : * translate to a getsockopt() call
88 : */
89 : if (PR_SockOpt_Nonblocking == data->option)
90 : {
91 : data->value.non_blocking = fd->secret->nonblocking;
92 : return PR_SUCCESS;
93 : }
94 :
95 : rv = _PR_MapOptionName(data->option, &level, &name);
96 : if (PR_SUCCESS == rv)
97 : {
98 : switch (data->option)
99 : {
100 : case PR_SockOpt_Linger:
101 : {
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)
108 : {
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);
114 : }
115 : break;
116 : #else
117 : PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
118 : return PR_FAILURE;
119 : #endif
120 : }
121 : case PR_SockOpt_Reuseaddr:
122 : case PR_SockOpt_Keepalive:
123 : case PR_SockOpt_NoDelay:
124 : case PR_SockOpt_Broadcast:
125 : {
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;
137 : }
138 : case PR_SockOpt_McastLoopback:
139 : {
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;
151 : }
152 : case PR_SockOpt_RecvBufferSize:
153 : case PR_SockOpt_SendBufferSize:
154 : case PR_SockOpt_MaxSegment:
155 : {
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;
163 : }
164 : case PR_SockOpt_IpTimeToLive:
165 : case PR_SockOpt_IpTypeOfService:
166 : {
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;
172 : }
173 : case PR_SockOpt_McastTimeToLive:
174 : {
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;
186 : }
187 : #ifdef IP_ADD_MEMBERSHIP
188 : case PR_SockOpt_AddMember:
189 : case PR_SockOpt_DropMember:
190 : {
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)
196 : {
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;
201 : }
202 : break;
203 : }
204 : #endif /* IP_ADD_MEMBERSHIP */
205 : case PR_SockOpt_McastInterface:
206 : {
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;
213 : }
214 : default:
215 : PR_NOT_REACHED("Unknown socket option");
216 : break;
217 : }
218 : }
219 : return rv;
220 : } /* _PR_SocketGetSocketOption */
221 :
222 : PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
223 : {
224 : PRStatus rv;
225 : PRInt32 level, name;
226 :
227 : /*
228 : * PR_SockOpt_Nonblocking is a special case that does not
229 : * translate to a setsockopt call.
230 : */
231 : if (PR_SockOpt_Nonblocking == data->option)
232 : {
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))
238 : {
239 : /*
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.
244 : */
245 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
246 : return PR_FAILURE;
247 : }
248 : #endif
249 : fd->secret->nonblocking = data->value.non_blocking;
250 : return PR_SUCCESS;
251 : }
252 :
253 : rv = _PR_MapOptionName(data->option, &level, &name);
254 : if (PR_SUCCESS == rv)
255 : {
256 : switch (data->option)
257 : {
258 : case PR_SockOpt_Linger:
259 : {
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
271 : }
272 : case PR_SockOpt_Reuseaddr:
273 : case PR_SockOpt_Keepalive:
274 : case PR_SockOpt_NoDelay:
275 : case PR_SockOpt_Broadcast:
276 : {
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;
286 : }
287 : case PR_SockOpt_McastLoopback:
288 : {
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;
298 : }
299 : case PR_SockOpt_RecvBufferSize:
300 : case PR_SockOpt_SendBufferSize:
301 : case PR_SockOpt_MaxSegment:
302 : {
303 : PRIntn value = data->value.recv_buffer_size;
304 : rv = _PR_MD_SETSOCKOPT(
305 : fd, level, name, (char*)&value, sizeof(value));
306 : break;
307 : }
308 : case PR_SockOpt_IpTimeToLive:
309 : case PR_SockOpt_IpTypeOfService:
310 : {
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;
315 : }
316 : case PR_SockOpt_McastTimeToLive:
317 : {
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;
327 : }
328 : #ifdef IP_ADD_MEMBERSHIP
329 : case PR_SockOpt_AddMember:
330 : case PR_SockOpt_DropMember:
331 : {
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;
340 : }
341 : #endif /* IP_ADD_MEMBERSHIP */
342 : case PR_SockOpt_McastInterface:
343 : {
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;
349 : }
350 : default:
351 : PR_NOT_REACHED("Unknown socket option");
352 : break;
353 : }
354 : }
355 : return rv;
356 : } /* _PR_SocketSetSocketOption */
357 :
358 : #endif /* ! _PR_PTHREADS */
359 :
360 : /*
361 : *********************************************************************
362 : *********************************************************************
363 : **
364 : ** Make sure that the following is at the end of this file,
365 : ** because we will be playing with macro redefines.
366 : **
367 : *********************************************************************
368 : *********************************************************************
369 : */
370 :
371 : /*
372 : * Not every platform has all the socket options we want to
373 : * support. Some older operating systems such as SunOS 4.1.3
374 : * don't have the IP multicast socket options. Win32 doesn't
375 : * have TCP_MAXSEG.
376 : *
377 : * To deal with this problem, we define the missing socket
378 : * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
379 : * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
380 : * available on the platform is requested.
381 : */
382 :
383 : /*
384 : * Sanity check. SO_LINGER and TCP_NODELAY should be available
385 : * on all platforms. Just to make sure we have included the
386 : * appropriate header files. Then any undefined socket options
387 : * are really missing.
388 : */
389 :
390 : #if !defined(SO_LINGER)
391 : #error "SO_LINGER is not defined"
392 : #endif
393 :
394 : /*
395 : * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
396 : * in <netinet/tcp.h>
397 : */
398 : #if !defined(NCR)
399 : #if !defined(TCP_NODELAY)
400 : #error "TCP_NODELAY is not defined"
401 : #endif
402 : #endif
403 :
404 : /*
405 : * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
406 : * a valid socket option.
407 : */
408 : #define _PR_NO_SUCH_SOCKOPT -1
409 :
410 : #ifndef SO_KEEPALIVE
411 : #define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
412 : #endif
413 :
414 : #ifndef SO_SNDBUF
415 : #define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
416 : #endif
417 :
418 : #ifndef SO_RCVBUF
419 : #define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
420 : #endif
421 :
422 : #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
423 : #define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
424 : #endif
425 :
426 : #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
427 : #define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
428 : #endif
429 :
430 : #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
431 : #define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
432 : #endif
433 :
434 : #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
435 : #define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
436 : #endif
437 :
438 : #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
439 : #define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
440 : #endif
441 :
442 : #ifndef IP_TTL /* set/get IP Time To Live */
443 : #define IP_TTL _PR_NO_SUCH_SOCKOPT
444 : #endif
445 :
446 : #ifndef IP_TOS /* set/get IP Type Of Service */
447 : #define IP_TOS _PR_NO_SUCH_SOCKOPT
448 : #endif
449 :
450 : #ifndef TCP_NODELAY /* don't delay to coalesce data */
451 : #define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
452 : #endif
453 :
454 : #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
455 : #define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
456 : #endif
457 :
458 : #ifndef SO_BROADCAST /* enable broadcast on udp sockets */
459 : #define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
460 : #endif
461 :
462 3431 : PRStatus _PR_MapOptionName(
463 : PRSockOption optname, PRInt32 *level, PRInt32 *name)
464 : {
465 : static PRInt32 socketOptions[PR_SockOpt_Last] =
466 : {
467 : 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
468 : IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
469 : IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
470 : TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
471 : };
472 : static PRInt32 socketLevels[PR_SockOpt_Last] =
473 : {
474 : 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
475 : IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
476 : IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
477 : IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
478 : };
479 :
480 3431 : if ((optname < PR_SockOpt_Linger)
481 3431 : || (optname >= PR_SockOpt_Last))
482 : {
483 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
484 0 : return PR_FAILURE;
485 : }
486 :
487 3431 : if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
488 : {
489 0 : PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
490 0 : return PR_FAILURE;
491 : }
492 3431 : *name = socketOptions[optname];
493 3431 : *level = socketLevels[optname];
494 3431 : return PR_SUCCESS;
495 : } /* _PR_MapOptionName */
|