~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/io/prmapopt.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* 
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is the Netscape Portable Runtime (NSPR).
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Netscape
 
16
 * Communications Corporation.  Portions created by Netscape are 
 
17
 * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
 
18
 * Rights Reserved.
 
19
 * 
 
20
 * Contributor(s):
 
21
 * 
 
22
 * Alternatively, the contents of this file may be used under the
 
23
 * terms of the GNU General Public License Version 2 or later (the
 
24
 * "GPL"), in which case the provisions of the GPL are applicable 
 
25
 * instead of those above.  If you wish to allow use of your 
 
26
 * version of this file only under the terms of the GPL and not to
 
27
 * allow others to use your version of this file under the MPL,
 
28
 * indicate your decision by deleting the provisions above and
 
29
 * replace them with the notice and other provisions required by
 
30
 * the GPL.  If you do not delete the provisions above, a recipient
 
31
 * may use your version of this file under either the MPL or the
 
32
 * GPL.
 
33
 */
 
34
 
 
35
/*
 
36
 * This file defines _PR_MapOptionName().  The purpose of putting
 
37
 * _PR_MapOptionName() in a separate file is to work around a Winsock
 
38
 * header file problem on Windows NT.
 
39
 *
 
40
 * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
 
41
 * to use Service Pack 3 extensions), windows.h includes winsock2.h
 
42
 * (instead of winsock.h), which doesn't define many socket options
 
43
 * defined in winsock.h.
 
44
 *
 
45
 * We need the socket options defined in winsock.h.  So this file
 
46
 * includes winsock.h, with _WIN32_WINNT undefined.
 
47
 */
 
48
 
 
49
#if defined(WINNT) || defined(__MINGW32__)
 
50
#include <winsock.h>
 
51
#endif
 
52
 
 
53
/* MinGW doesn't define these in its winsock.h. */
 
54
#ifdef __MINGW32__
 
55
#ifndef IP_TTL
 
56
#define IP_TTL 7
 
57
#endif
 
58
#ifndef IP_TOS
 
59
#define IP_TOS 8
 
60
#endif
 
61
#endif
 
62
 
 
63
#include "primpl.h"
 
64
 
 
65
#if defined(NEXTSTEP)
 
66
/* NEXTSTEP is special: this must come before netinet/tcp.h. */
 
67
#include <netinet/in_systm.h>  /* n_short, n_long, n_time */
 
68
#endif
 
69
 
 
70
#if defined(XP_UNIX) || defined(OS2) || (defined(XP_BEOS) && defined(BONE_VERSION))
 
71
#include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
 
72
#endif
 
73
 
 
74
#ifndef _PR_PTHREADS
 
75
 
 
76
PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
 
77
{
 
78
    PRStatus rv;
 
79
    PRInt32 length;
 
80
    PRInt32 level, name;
 
81
 
 
82
    /*
 
83
     * PR_SockOpt_Nonblocking is a special case that does not
 
84
     * translate to a getsockopt() call
 
85
     */
 
86
    if (PR_SockOpt_Nonblocking == data->option)
 
87
    {
 
88
        data->value.non_blocking = fd->secret->nonblocking;
 
89
        return PR_SUCCESS;
 
90
    }
 
91
 
 
92
    rv = _PR_MapOptionName(data->option, &level, &name);
 
93
    if (PR_SUCCESS == rv)
 
94
    {
 
95
        switch (data->option)
 
96
        {
 
97
            case PR_SockOpt_Linger:
 
98
            {
 
99
#if !defined(XP_BEOS) || defined(BONE_VERSION)
 
100
                struct linger linger;
 
101
                length = sizeof(linger);
 
102
                rv = _PR_MD_GETSOCKOPT(
 
103
                    fd, level, name, (char *) &linger, &length);
 
104
                if (PR_SUCCESS == rv)
 
105
                {
 
106
                    PR_ASSERT(sizeof(linger) == length);
 
107
                    data->value.linger.polarity =
 
108
                        (linger.l_onoff) ? PR_TRUE : PR_FALSE;
 
109
                    data->value.linger.linger =
 
110
                        PR_SecondsToInterval(linger.l_linger);
 
111
                }
 
112
                break;
 
113
#else
 
114
                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
 
115
                return PR_FAILURE;
 
116
#endif
 
117
            }
 
118
            case PR_SockOpt_Reuseaddr:
 
119
            case PR_SockOpt_Keepalive:
 
120
            case PR_SockOpt_NoDelay:
 
121
            case PR_SockOpt_Broadcast:
 
122
            {
 
123
#ifdef WIN32 /* Winsock */
 
124
                BOOL value;
 
125
#else
 
126
                PRIntn value;
 
127
#endif
 
128
                length = sizeof(value);
 
129
                rv = _PR_MD_GETSOCKOPT(
 
130
                    fd, level, name, (char*)&value, &length);
 
131
                if (PR_SUCCESS == rv)
 
132
                    data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
 
133
                break;
 
134
            }
 
135
            case PR_SockOpt_McastLoopback:
 
136
            {
 
137
#ifdef WIN32 /* Winsock */
 
138
                BOOL bool;
 
139
#else
 
140
                PRUint8 bool;
 
141
#endif
 
142
                length = sizeof(bool);
 
143
                rv = _PR_MD_GETSOCKOPT(
 
144
                    fd, level, name, (char*)&bool, &length);
 
145
                if (PR_SUCCESS == rv)
 
146
                    data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
 
147
                break;
 
148
            }
 
149
            case PR_SockOpt_RecvBufferSize:
 
150
            case PR_SockOpt_SendBufferSize:
 
151
            case PR_SockOpt_MaxSegment:
 
152
            {
 
153
                PRIntn value;
 
154
                length = sizeof(value);
 
155
                rv = _PR_MD_GETSOCKOPT(
 
156
                    fd, level, name, (char*)&value, &length);
 
157
                if (PR_SUCCESS == rv)
 
158
                    data->value.recv_buffer_size = value;
 
159
                break;
 
160
            }
 
161
            case PR_SockOpt_IpTimeToLive:
 
162
            case PR_SockOpt_IpTypeOfService:
 
163
            {
 
164
                /* These options should really be an int (or PRIntn). */
 
165
                length = sizeof(PRUintn);
 
166
                rv = _PR_MD_GETSOCKOPT(
 
167
                    fd, level, name, (char*)&data->value.ip_ttl, &length);
 
168
                break;
 
169
            }
 
170
            case PR_SockOpt_McastTimeToLive:
 
171
            {
 
172
#ifdef WIN32 /* Winsock */
 
173
                int ttl;
 
174
#else
 
175
                PRUint8 ttl;
 
176
#endif
 
177
                length = sizeof(ttl);
 
178
                rv = _PR_MD_GETSOCKOPT(
 
179
                    fd, level, name, (char*)&ttl, &length);
 
180
                if (PR_SUCCESS == rv)
 
181
                    data->value.mcast_ttl = ttl;
 
182
                break;
 
183
            }
 
184
#ifdef IP_ADD_MEMBERSHIP
 
185
            case PR_SockOpt_AddMember:
 
186
            case PR_SockOpt_DropMember:
 
187
            {
 
188
                struct ip_mreq mreq;
 
189
                length = sizeof(mreq);
 
190
                rv = _PR_MD_GETSOCKOPT(
 
191
                    fd, level, name, (char*)&mreq, &length);
 
192
                if (PR_SUCCESS == rv)
 
193
                {
 
194
                    data->value.add_member.mcaddr.inet.ip =
 
195
                        mreq.imr_multiaddr.s_addr;
 
196
                    data->value.add_member.ifaddr.inet.ip =
 
197
                        mreq.imr_interface.s_addr;
 
198
                }
 
199
                break;
 
200
            }
 
201
#endif /* IP_ADD_MEMBERSHIP */
 
202
            case PR_SockOpt_McastInterface:
 
203
            {
 
204
                /* This option is a struct in_addr. */
 
205
                length = sizeof(data->value.mcast_if.inet.ip);
 
206
                rv = _PR_MD_GETSOCKOPT(
 
207
                    fd, level, name,
 
208
                    (char*)&data->value.mcast_if.inet.ip, &length);
 
209
                break;
 
210
            }
 
211
            default:
 
212
                PR_NOT_REACHED("Unknown socket option");
 
213
                break;
 
214
        }  
 
215
    }
 
216
    return rv;
 
217
}  /* _PR_SocketGetSocketOption */
 
218
 
 
219
PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
 
220
{
 
221
    PRStatus rv;
 
222
    PRInt32 level, name;
 
223
 
 
224
    /*
 
225
     * PR_SockOpt_Nonblocking is a special case that does not
 
226
     * translate to a setsockopt call.
 
227
     */
 
228
    if (PR_SockOpt_Nonblocking == data->option)
 
229
    {
 
230
#ifdef WINNT
 
231
        PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
 
232
            || (fd->secret->nonblocking == data->value.non_blocking));
 
233
        if (fd->secret->md.io_model_committed
 
234
            && (fd->secret->nonblocking != data->value.non_blocking))
 
235
        {
 
236
            /*
 
237
             * On NT, once we have associated a socket with the io
 
238
             * completion port, we can't disassociate it.  So we
 
239
             * can't change the nonblocking option of the socket
 
240
             * afterwards.
 
241
             */
 
242
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
243
            return PR_FAILURE;
 
244
        }
 
245
#endif
 
246
        fd->secret->nonblocking = data->value.non_blocking;
 
247
        return PR_SUCCESS;
 
248
    }
 
249
 
 
250
    rv = _PR_MapOptionName(data->option, &level, &name);
 
251
    if (PR_SUCCESS == rv)
 
252
    {
 
253
        switch (data->option)
 
254
        {
 
255
            case PR_SockOpt_Linger:
 
256
            {
 
257
#if !defined(XP_BEOS) || defined(BONE_VERSION)
 
258
                struct linger linger;
 
259
                linger.l_onoff = data->value.linger.polarity;
 
260
                linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
 
261
                rv = _PR_MD_SETSOCKOPT(
 
262
                    fd, level, name, (char*)&linger, sizeof(linger));
 
263
                break;
 
264
#else
 
265
                PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
 
266
                return PR_FAILURE;
 
267
#endif
 
268
            }
 
269
            case PR_SockOpt_Reuseaddr:
 
270
            case PR_SockOpt_Keepalive:
 
271
            case PR_SockOpt_NoDelay:
 
272
            case PR_SockOpt_Broadcast:
 
273
            {
 
274
#ifdef WIN32 /* Winsock */
 
275
                BOOL value;
 
276
#else
 
277
                PRIntn value;
 
278
#endif
 
279
                value = (data->value.reuse_addr) ? 1 : 0;
 
280
                rv = _PR_MD_SETSOCKOPT(
 
281
                    fd, level, name, (char*)&value, sizeof(value));
 
282
                break;
 
283
            }
 
284
            case PR_SockOpt_McastLoopback:
 
285
            {
 
286
#ifdef WIN32 /* Winsock */
 
287
                BOOL bool;
 
288
#else
 
289
                PRUint8 bool;
 
290
#endif
 
291
                bool = data->value.mcast_loopback ? 1 : 0;
 
292
                rv = _PR_MD_SETSOCKOPT(
 
293
                    fd, level, name, (char*)&bool, sizeof(bool));
 
294
                break;
 
295
            }
 
296
            case PR_SockOpt_RecvBufferSize:
 
297
            case PR_SockOpt_SendBufferSize:
 
298
            case PR_SockOpt_MaxSegment:
 
299
            {
 
300
                PRIntn value = data->value.recv_buffer_size;
 
301
                rv = _PR_MD_SETSOCKOPT(
 
302
                    fd, level, name, (char*)&value, sizeof(value));
 
303
                break;
 
304
            }
 
305
            case PR_SockOpt_IpTimeToLive:
 
306
            case PR_SockOpt_IpTypeOfService:
 
307
            {
 
308
                /* These options should really be an int (or PRIntn). */
 
309
                rv = _PR_MD_SETSOCKOPT(
 
310
                    fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
 
311
                break;
 
312
            }
 
313
            case PR_SockOpt_McastTimeToLive:
 
314
            {
 
315
#ifdef WIN32 /* Winsock */
 
316
                int ttl;
 
317
#else
 
318
                PRUint8 ttl;
 
319
#endif
 
320
                ttl = data->value.mcast_ttl;
 
321
                rv = _PR_MD_SETSOCKOPT(
 
322
                    fd, level, name, (char*)&ttl, sizeof(ttl));
 
323
                break;
 
324
            }
 
325
#ifdef IP_ADD_MEMBERSHIP
 
326
            case PR_SockOpt_AddMember:
 
327
            case PR_SockOpt_DropMember:
 
328
            {
 
329
                struct ip_mreq mreq;
 
330
                mreq.imr_multiaddr.s_addr =
 
331
                    data->value.add_member.mcaddr.inet.ip;
 
332
                mreq.imr_interface.s_addr =
 
333
                    data->value.add_member.ifaddr.inet.ip;
 
334
                rv = _PR_MD_SETSOCKOPT(
 
335
                    fd, level, name, (char*)&mreq, sizeof(mreq));
 
336
                break;
 
337
            }
 
338
#endif /* IP_ADD_MEMBERSHIP */
 
339
            case PR_SockOpt_McastInterface:
 
340
            {
 
341
                /* This option is a struct in_addr. */
 
342
                rv = _PR_MD_SETSOCKOPT(
 
343
                    fd, level, name, (char*)&data->value.mcast_if.inet.ip,
 
344
                    sizeof(data->value.mcast_if.inet.ip));
 
345
                break;
 
346
            }
 
347
            default:
 
348
                PR_NOT_REACHED("Unknown socket option");
 
349
                break;
 
350
        }  
 
351
    }
 
352
    return rv;
 
353
}  /* _PR_SocketSetSocketOption */
 
354
 
 
355
#endif /* ! _PR_PTHREADS */
 
356
 
 
357
/*
 
358
 *********************************************************************
 
359
 *********************************************************************
 
360
 **
 
361
 ** Make sure that the following is at the end of this file,
 
362
 ** because we will be playing with macro redefines.
 
363
 **
 
364
 *********************************************************************
 
365
 *********************************************************************
 
366
 */
 
367
 
 
368
#if defined(VMS)
 
369
/*
 
370
** Sad but true. The DEC C header files define the following socket options
 
371
** differently to what UCX is expecting. The values that UCX expects are
 
372
** defined in SYS$LIBRARY:UCX$INETDEF.H. We redefine them here to the values
 
373
** that UCX expects. Note that UCX V4.x will only accept these values while
 
374
** UCX V5.x will accept either. So in theory this hack can be removed once
 
375
** UCX V5 is the minimum.
 
376
*/
 
377
#undef IP_MULTICAST_IF
 
378
#undef IP_MULTICAST_TTL
 
379
#undef IP_MULTICAST_LOOP
 
380
#undef IP_ADD_MEMBERSHIP
 
381
#undef IP_DROP_MEMBERSHIP
 
382
#include <ucx$inetdef.h>
 
383
#define IP_MULTICAST_IF    UCX$C_IP_MULTICAST_IF
 
384
#define IP_MULTICAST_TTL   UCX$C_IP_MULTICAST_TTL
 
385
#define IP_MULTICAST_LOOP  UCX$C_IP_MULTICAST_LOOP
 
386
#define IP_ADD_MEMBERSHIP  UCX$C_IP_ADD_MEMBERSHIP
 
387
#define IP_DROP_MEMBERSHIP UCX$C_IP_DROP_MEMBERSHIP
 
388
#endif
 
389
 
 
390
/*
 
391
 * Not every platform has all the socket options we want to
 
392
 * support.  Some older operating systems such as SunOS 4.1.3
 
393
 * don't have the IP multicast socket options.  Win32 doesn't
 
394
 * have TCP_MAXSEG.
 
395
 *
 
396
 * To deal with this problem, we define the missing socket
 
397
 * options as _PR_NO_SUCH_SOCKOPT.  _PR_MapOptionName() fails with
 
398
 * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
 
399
 * available on the platform is requested.
 
400
 */
 
401
 
 
402
/*
 
403
 * Sanity check.  SO_LINGER and TCP_NODELAY should be available
 
404
 * on all platforms.  Just to make sure we have included the
 
405
 * appropriate header files.  Then any undefined socket options
 
406
 * are really missing.
 
407
 */
 
408
 
 
409
#if !defined(SO_LINGER)
 
410
#error "SO_LINGER is not defined"
 
411
#endif
 
412
 
 
413
/*
 
414
 * Some platforms, such as NCR 2.03, don't have TCP_NODELAY defined
 
415
 * in <netinet/tcp.h>
 
416
 */
 
417
#if !defined(NCR)
 
418
#if !defined(TCP_NODELAY)
 
419
#error "TCP_NODELAY is not defined"
 
420
#endif
 
421
#endif
 
422
 
 
423
/*
 
424
 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
 
425
 * a valid socket option.
 
426
 */
 
427
#define _PR_NO_SUCH_SOCKOPT -1
 
428
 
 
429
#ifndef SO_KEEPALIVE
 
430
#define SO_KEEPALIVE        _PR_NO_SUCH_SOCKOPT
 
431
#endif
 
432
 
 
433
#ifndef SO_SNDBUF
 
434
#define SO_SNDBUF           _PR_NO_SUCH_SOCKOPT
 
435
#endif
 
436
 
 
437
#ifndef SO_RCVBUF
 
438
#define SO_RCVBUF           _PR_NO_SUCH_SOCKOPT
 
439
#endif
 
440
 
 
441
#ifndef IP_MULTICAST_IF                 /* set/get IP multicast interface   */
 
442
#define IP_MULTICAST_IF     _PR_NO_SUCH_SOCKOPT
 
443
#endif
 
444
 
 
445
#ifndef IP_MULTICAST_TTL                /* set/get IP multicast timetolive  */
 
446
#define IP_MULTICAST_TTL    _PR_NO_SUCH_SOCKOPT
 
447
#endif
 
448
 
 
449
#ifndef IP_MULTICAST_LOOP               /* set/get IP multicast loopback    */
 
450
#define IP_MULTICAST_LOOP   _PR_NO_SUCH_SOCKOPT
 
451
#endif
 
452
 
 
453
#ifndef IP_ADD_MEMBERSHIP               /* add  an IP group membership      */
 
454
#define IP_ADD_MEMBERSHIP   _PR_NO_SUCH_SOCKOPT
 
455
#endif
 
456
 
 
457
#ifndef IP_DROP_MEMBERSHIP              /* drop an IP group membership      */
 
458
#define IP_DROP_MEMBERSHIP  _PR_NO_SUCH_SOCKOPT
 
459
#endif
 
460
 
 
461
#ifndef IP_TTL                          /* set/get IP Time To Live          */
 
462
#define IP_TTL              _PR_NO_SUCH_SOCKOPT
 
463
#endif
 
464
 
 
465
#ifndef IP_TOS                          /* set/get IP Type Of Service       */
 
466
#define IP_TOS              _PR_NO_SUCH_SOCKOPT
 
467
#endif
 
468
 
 
469
#ifndef TCP_NODELAY                     /* don't delay to coalesce data     */
 
470
#define TCP_NODELAY         _PR_NO_SUCH_SOCKOPT
 
471
#endif
 
472
 
 
473
#ifndef TCP_MAXSEG                      /* maxumum segment size for tcp     */
 
474
#define TCP_MAXSEG          _PR_NO_SUCH_SOCKOPT
 
475
#endif
 
476
 
 
477
#ifndef SO_BROADCAST                 /* enable broadcast on udp sockets */
 
478
#define SO_BROADCAST        _PR_NO_SUCH_SOCKOPT
 
479
#endif
 
480
 
 
481
PRStatus _PR_MapOptionName(
 
482
    PRSockOption optname, PRInt32 *level, PRInt32 *name)
 
483
{
 
484
    static PRInt32 socketOptions[PR_SockOpt_Last] =
 
485
    {
 
486
        0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
 
487
        IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
 
488
        IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
 
489
        TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST
 
490
    };
 
491
    static PRInt32 socketLevels[PR_SockOpt_Last] =
 
492
    {
 
493
        0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
 
494
        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
 
495
        IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
 
496
        IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET
 
497
    };
 
498
 
 
499
    if ((optname < PR_SockOpt_Linger)
 
500
    || (optname >= PR_SockOpt_Last))
 
501
    {
 
502
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
503
        return PR_FAILURE;
 
504
    }
 
505
 
 
506
    if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
 
507
    {
 
508
        PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
 
509
        return PR_FAILURE;
 
510
    }
 
511
    *name = socketOptions[optname];
 
512
    *level = socketLevels[optname];
 
513
    return PR_SUCCESS;
 
514
}  /* _PR_MapOptionName */