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

« back to all changes in this revision

Viewing changes to mozilla/nsprpub/pr/src/io/prsocket.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
#include "primpl.h"
 
36
 
 
37
#include <string.h>
 
38
 
 
39
/************************************************************************/
 
40
 
 
41
/* These two functions are only used in assertions. */
 
42
#if defined(DEBUG)
 
43
 
 
44
PRBool IsValidNetAddr(const PRNetAddr *addr)
 
45
{
 
46
    if ((addr != NULL)
 
47
#if defined(XP_UNIX) || defined(XP_OS2)
 
48
            && (addr->raw.family != PR_AF_LOCAL)
 
49
#endif
 
50
            && (addr->raw.family != PR_AF_INET6)
 
51
            && (addr->raw.family != PR_AF_INET)) {
 
52
        return PR_FALSE;
 
53
    }
 
54
    return PR_TRUE;
 
55
}
 
56
 
 
57
static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
 
58
{
 
59
    /*
 
60
     * The definition of the length of a Unix domain socket address
 
61
     * is not uniform, so we don't check it.
 
62
     */
 
63
    if ((addr != NULL)
 
64
#if defined(XP_UNIX) || defined(XP_OS2)
 
65
            && (addr->raw.family != AF_UNIX)
 
66
#endif
 
67
            && (PR_NETADDR_SIZE(addr) != addr_len)) {
 
68
#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
 
69
        /*
 
70
         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
 
71
         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
 
72
         * field and is 28 bytes.  It is possible for socket functions
 
73
         * to return an addr_len greater than sizeof(struct sockaddr_in6).
 
74
         * We need to allow that.  (Bugzilla bug #77264)
 
75
         */
 
76
        if ((PR_AF_INET6 == addr->raw.family)
 
77
                && (sizeof(addr->ipv6) == addr_len)) {
 
78
            return PR_TRUE;
 
79
        }
 
80
#endif
 
81
        /*
 
82
         * The accept(), getsockname(), etc. calls on some platforms
 
83
         * do not set the actual socket address length on return.
 
84
         * In this case, we verifiy addr_len is still the value we
 
85
         * passed in (i.e., sizeof(PRNetAddr)).
 
86
         */
 
87
#if defined(QNX)
 
88
        if (sizeof(PRNetAddr) == addr_len) {
 
89
            return PR_TRUE;
 
90
        }
 
91
#endif
 
92
        return PR_FALSE;
 
93
    }
 
94
    return PR_TRUE;
 
95
}
 
96
 
 
97
#endif /* DEBUG */
 
98
 
 
99
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
 
100
PRInt32 iov_size, PRIntervalTime timeout)
 
101
{
 
102
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
103
        int w = 0;
 
104
        const PRIOVec *tmp_iov;
 
105
#define LOCAL_MAXIOV    8
 
106
        PRIOVec local_iov[LOCAL_MAXIOV];
 
107
        PRIOVec *iov_copy = NULL;
 
108
        int tmp_out;
 
109
        int index, iov_cnt;
 
110
        int count=0, sz = 0;    /* 'count' is the return value. */
 
111
 
 
112
        if (_PR_PENDING_INTERRUPT(me)) {
 
113
                me->flags &= ~_PR_INTERRUPT;
 
114
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
115
                return -1;
 
116
        }
 
117
        if (_PR_IO_PENDING(me)) {
 
118
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
119
                return -1;
 
120
        }
 
121
 
 
122
    /*
 
123
     * Assume the first writev will succeed.  Copy iov's only on
 
124
     * failure.
 
125
     */
 
126
    tmp_iov = iov;
 
127
    for (index = 0; index < iov_size; index++)
 
128
        sz += iov[index].iov_len;
 
129
 
 
130
        iov_cnt = iov_size;
 
131
 
 
132
        while (sz > 0) {
 
133
 
 
134
                w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
 
135
                if (w < 0) {
 
136
                        count = -1;
 
137
                        break;
 
138
                }
 
139
                count += w;
 
140
                if (fd->secret->nonblocking) {
 
141
                        break;
 
142
                }
 
143
                sz -= w;
 
144
 
 
145
                if (sz > 0) {
 
146
                        /* find the next unwritten vector */
 
147
                        for ( index = 0, tmp_out = count;
 
148
                                tmp_out >= iov[index].iov_len;
 
149
                                tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
 
150
 
 
151
                        if (tmp_iov == iov) {
 
152
                                /*
 
153
                                 * The first writev failed so we
 
154
                                 * must copy iov's around.
 
155
                                 * Avoid calloc/free if there
 
156
                                 * are few enough iov's.
 
157
                                 */
 
158
                                if (iov_size - index <= LOCAL_MAXIOV)
 
159
                                        iov_copy = local_iov;
 
160
                                else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
 
161
                                        sizeof *iov_copy)) == NULL) {
 
162
                                        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
163
                                        return -1;
 
164
                                }
 
165
                                tmp_iov = iov_copy;
 
166
                        }
 
167
 
 
168
                        PR_ASSERT(tmp_iov == iov_copy);
 
169
 
 
170
                        /* fill in the first partial read */
 
171
                        iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
 
172
                        iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
 
173
                        index++;
 
174
 
 
175
                        /* copy the remaining vectors */
 
176
                        for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
 
177
                                iov_copy[iov_cnt].iov_base = iov[index].iov_base;
 
178
                                iov_copy[iov_cnt].iov_len = iov[index].iov_len;
 
179
                        }
 
180
                }
 
181
        }
 
182
 
 
183
        if (iov_copy != local_iov)
 
184
                PR_DELETE(iov_copy);
 
185
        return count;
 
186
}
 
187
 
 
188
/************************************************************************/
 
189
 
 
190
PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
 
191
{
 
192
PRFileDesc *fd;
 
193
 
 
194
        if (!_pr_initialized) _PR_ImplicitInitialization();
 
195
        fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 
196
        if (fd != NULL) {
 
197
                _PR_MD_MAKE_NONBLOCK(fd);
 
198
                _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
 
199
        } else
 
200
                _PR_MD_CLOSE_SOCKET(osfd);
 
201
        return(fd);
 
202
}
 
203
 
 
204
PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
 
205
{
 
206
PRFileDesc *fd;
 
207
 
 
208
        if (!_pr_initialized) _PR_ImplicitInitialization();
 
209
        fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
 
210
        if (fd != NULL) {
 
211
                _PR_MD_MAKE_NONBLOCK(fd);
 
212
                _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
 
213
        } else
 
214
                _PR_MD_CLOSE_SOCKET(osfd);
 
215
        return(fd);
 
216
}
 
217
 
 
218
 
 
219
static const PRIOMethods* PR_GetSocketPollFdMethods(void);
 
220
 
 
221
PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
 
222
{
 
223
    PRFileDesc *fd;
 
224
 
 
225
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
226
 
 
227
    fd = _PR_Getfd();
 
228
 
 
229
    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
230
    else
 
231
    {
 
232
        fd->secret->md.osfd = osfd;
 
233
        fd->secret->inheritable = _PR_TRI_FALSE;
 
234
        fd->secret->state = _PR_FILEDESC_OPEN;
 
235
        fd->methods = PR_GetSocketPollFdMethods();
 
236
    }
 
237
 
 
238
    return fd;
 
239
}  /* PR_CreateSocketPollFD */
 
240
 
 
241
PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
 
242
{
 
243
    if (NULL == fd)
 
244
    {
 
245
        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 
246
        return PR_FAILURE;
 
247
    }
 
248
    fd->secret->state = _PR_FILEDESC_CLOSED;
 
249
    _PR_Putfd(fd);
 
250
    return PR_SUCCESS;
 
251
}  /* PR_DestroySocketPollFd */
 
252
 
 
253
static PRStatus PR_CALLBACK SocketConnect(
 
254
    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
 
255
{
 
256
        PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
 
257
    const PRNetAddr *addrp = addr;
 
258
#if defined(_PR_INET6)
 
259
        PRNetAddr addrCopy;
 
260
#endif
 
261
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
262
 
 
263
        if (_PR_PENDING_INTERRUPT(me)) {
 
264
                me->flags &= ~_PR_INTERRUPT;
 
265
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
266
                return PR_FAILURE;
 
267
        }
 
268
#if defined(_PR_INET6)
 
269
        if (addr->raw.family == PR_AF_INET6) {
 
270
                addrCopy = *addr;
 
271
                addrCopy.raw.family = AF_INET6;
 
272
                addrp = &addrCopy;
 
273
        }
 
274
#endif
 
275
 
 
276
        rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
 
277
        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
 
278
        if (rv == 0)
 
279
                return PR_SUCCESS;
 
280
        else
 
281
                return PR_FAILURE;
 
282
}
 
283
 
 
284
static PRStatus PR_CALLBACK SocketConnectContinue(
 
285
    PRFileDesc *fd, PRInt16 out_flags)
 
286
{
 
287
    PRInt32 osfd;
 
288
    int err;
 
289
 
 
290
    if (out_flags & PR_POLL_NVAL) {
 
291
        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 
292
        return PR_FAILURE;
 
293
    }
 
294
    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
 
295
        PR_ASSERT(out_flags == 0);
 
296
        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
 
297
        return PR_FAILURE;
 
298
    }
 
299
 
 
300
    osfd = fd->secret->md.osfd;
 
301
 
 
302
#if defined(XP_UNIX)
 
303
 
 
304
    err = _MD_unix_get_nonblocking_connect_error(osfd);
 
305
    if (err != 0) {
 
306
        _PR_MD_MAP_CONNECT_ERROR(err);
 
307
        return PR_FAILURE;
 
308
    }
 
309
    return PR_SUCCESS;
 
310
 
 
311
#elif defined(WIN32) || defined(WIN16)
 
312
 
 
313
#if defined(WIN32)
 
314
    /*
 
315
     * The sleep circumvents a bug in Win32 WinSock.
 
316
     * See Microsoft Knowledge Base article ID: Q165989.
 
317
     */
 
318
    Sleep(0);
 
319
#endif /* WIN32 */
 
320
 
 
321
    if (out_flags & PR_POLL_EXCEPT) {
 
322
        int len = sizeof(err);
 
323
        if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
 
324
                == SOCKET_ERROR) {
 
325
            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
 
326
            return PR_FAILURE;
 
327
        }
 
328
        if (err != 0) {
 
329
            _PR_MD_MAP_CONNECT_ERROR(err);
 
330
        } else {
 
331
            PR_SetError(PR_UNKNOWN_ERROR, 0);
 
332
        }
 
333
        return PR_FAILURE;
 
334
    }
 
335
 
 
336
    PR_ASSERT(out_flags & PR_POLL_WRITE);
 
337
    return PR_SUCCESS;
 
338
 
 
339
#elif defined(XP_OS2)
 
340
 
 
341
    err = _MD_os2_get_nonblocking_connect_error(osfd);
 
342
    if (err != 0) {
 
343
        _PR_MD_MAP_CONNECT_ERROR(err);
 
344
        return PR_FAILURE;
 
345
    }
 
346
    return PR_SUCCESS;
 
347
 
 
348
#elif defined(XP_MAC)
 
349
 
 
350
    err = _MD_mac_get_nonblocking_connect_error(fd);
 
351
    if (err == -1)
 
352
        return PR_FAILURE;
 
353
        else     
 
354
                return PR_SUCCESS;
 
355
 
 
356
#elif defined(XP_BEOS)
 
357
 
 
358
#ifdef BONE_VERSION  /* bug 122364 */
 
359
    /* temporary workaround until getsockopt(SO_ERROR) works in BONE */
 
360
    if (out_flags & PR_POLL_EXCEPT) {
 
361
        PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
 
362
        return PR_FAILURE;
 
363
    }
 
364
    PR_ASSERT(out_flags & PR_POLL_WRITE);
 
365
    return PR_SUCCESS;
 
366
#else
 
367
    err = _MD_beos_get_nonblocking_connect_error(fd);
 
368
    if( err != 0 ) {
 
369
        _PR_MD_MAP_CONNECT_ERROR(err);
 
370
        return PR_FAILURE;
 
371
    }
 
372
    else
 
373
        return PR_SUCCESS;
 
374
#endif /* BONE_VERSION */
 
375
 
 
376
#else
 
377
    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
 
378
    return PR_FAILURE;
 
379
#endif
 
380
}
 
381
 
 
382
PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
 
383
{
 
384
    /* Find the NSPR layer and invoke its connectcontinue method */
 
385
    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
 
386
 
 
387
    if (NULL == bottom) {
 
388
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
389
        return PR_FAILURE;
 
390
    }
 
391
    return SocketConnectContinue(bottom, pd->out_flags);
 
392
}
 
393
 
 
394
static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
 
395
PRIntervalTime timeout)
 
396
{
 
397
        PRInt32 osfd;
 
398
        PRFileDesc *fd2;
 
399
        PRUint32 al;
 
400
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
401
#ifdef WINNT
 
402
        PRNetAddr addrCopy;
 
403
#endif
 
404
 
 
405
        if (_PR_PENDING_INTERRUPT(me)) {
 
406
                me->flags &= ~_PR_INTERRUPT;
 
407
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
408
                return 0;
 
409
        }
 
410
        if (_PR_IO_PENDING(me)) {
 
411
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
412
                return 0;
 
413
        }
 
414
 
 
415
#ifdef WINNT
 
416
        if (addr == NULL) {
 
417
                addr = &addrCopy;
 
418
        }
 
419
#endif
 
420
        al = sizeof(PRNetAddr);
 
421
        osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
 
422
        if (osfd == -1)
 
423
                return 0;
 
424
 
 
425
        fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 
426
        if (!fd2) {
 
427
                _PR_MD_CLOSE_SOCKET(osfd);
 
428
                return NULL;
 
429
        }
 
430
 
 
431
        fd2->secret->nonblocking = fd->secret->nonblocking;
 
432
        fd2->secret->inheritable = fd->secret->inheritable;
 
433
#ifdef WINNT
 
434
        if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
 
435
                /*
 
436
                 * The new socket has been associated with an I/O
 
437
                 * completion port.  There is no going back.
 
438
                 */
 
439
                fd2->secret->md.io_model_committed = PR_TRUE;
 
440
        }
 
441
        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
 
442
        fd2->secret->md.accepted_socket = PR_TRUE;
 
443
        memcpy(&fd2->secret->md.peer_addr, addr, al);
 
444
#endif
 
445
 
 
446
        /*
 
447
         * On some platforms, the new socket created by accept()
 
448
         * inherits the nonblocking (or overlapped io) attribute
 
449
         * of the listening socket.  As an optimization, these
 
450
         * platforms can skip the following _PR_MD_MAKE_NONBLOCK
 
451
         * call.
 
452
         * 
 
453
         * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK
 
454
         * (which maps to _MD_makenonblock, see macsockotpt.c)
 
455
         * installs the async notifier routine needed to make blocking
 
456
         * I/O work properly.
 
457
         */
 
458
#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
 
459
        _PR_MD_MAKE_NONBLOCK(fd2);
 
460
#endif
 
461
 
 
462
#ifdef _PR_INET6
 
463
        if (addr && (AF_INET6 == addr->raw.family))
 
464
        addr->raw.family = PR_AF_INET6;
 
465
#endif
 
466
        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
 
467
        PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
 
468
 
 
469
        return fd2;
 
470
}
 
471
 
 
472
#ifdef WINNT
 
473
PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
 
474
PRIntervalTime timeout)
 
475
{
 
476
        PRInt32 osfd;
 
477
        PRFileDesc *fd2;
 
478
        PRIntn al;
 
479
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
480
        PRNetAddr addrCopy;
 
481
 
 
482
        if (_PR_PENDING_INTERRUPT(me)) {
 
483
                me->flags &= ~_PR_INTERRUPT;
 
484
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
485
                return 0;
 
486
        }
 
487
        if (_PR_IO_PENDING(me)) {
 
488
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
489
                return 0;
 
490
        }
 
491
 
 
492
                if (addr == NULL) {
 
493
                        addr = &addrCopy;
 
494
                }
 
495
                al = PR_NETADDR_SIZE(addr);
 
496
                osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
 
497
                if (osfd == -1) {
 
498
                        return 0;
 
499
                }
 
500
 
 
501
        fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 
502
        if (!fd2) {
 
503
                _PR_MD_CLOSE_SOCKET(osfd);
 
504
        } else {
 
505
                fd2->secret->nonblocking = fd->secret->nonblocking;
 
506
                fd2->secret->md.io_model_committed = PR_TRUE;
 
507
                PR_ASSERT(al == PR_NETADDR_SIZE(addr));
 
508
                fd2->secret->md.accepted_socket = PR_TRUE;
 
509
                memcpy(&fd2->secret->md.peer_addr, addr, al);
 
510
#ifdef _PR_INET6
 
511
                if (AF_INET6 == addr->raw.family)
 
512
                addr->raw.family = PR_AF_INET6;
 
513
#endif
 
514
        }
 
515
        return fd2;
 
516
}
 
517
#endif /* WINNT */
 
518
 
 
519
 
 
520
static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
 
521
{
 
522
        PRInt32 result;
 
523
    const PRNetAddr *addrp = addr;
 
524
#if defined(_PR_INET6)
 
525
        PRNetAddr addrCopy;
 
526
#endif
 
527
 
 
528
        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
 
529
 
 
530
#ifdef XP_UNIX
 
531
        if (addr->raw.family == AF_UNIX) {
 
532
                /* Disallow relative pathnames */
 
533
                if (addr->local.path[0] != '/') {
 
534
                        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
535
                        return PR_FAILURE;
 
536
                }
 
537
        }
 
538
#endif /* XP_UNIX */
 
539
 
 
540
#if defined(_PR_INET6)
 
541
        if (addr->raw.family == PR_AF_INET6) {
 
542
                addrCopy = *addr;
 
543
                addrCopy.raw.family = AF_INET6;
 
544
                addrp = &addrCopy;
 
545
        }
 
546
#endif
 
547
        result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
 
548
        if (result < 0) {
 
549
                return PR_FAILURE;
 
550
        }
 
551
        return PR_SUCCESS;
 
552
}
 
553
 
 
554
static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
 
555
{
 
556
        PRInt32 result;
 
557
 
 
558
        result = _PR_MD_LISTEN(fd, backlog);
 
559
        if (result < 0) {
 
560
                return PR_FAILURE;
 
561
        }
 
562
        return PR_SUCCESS;
 
563
}
 
564
 
 
565
static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
 
566
{
 
567
        PRInt32 result;
 
568
 
 
569
        result = _PR_MD_SHUTDOWN(fd, how);
 
570
        if (result < 0) {
 
571
                return PR_FAILURE;
 
572
        }
 
573
        return PR_SUCCESS;
 
574
}
 
575
 
 
576
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
 
577
PRIntervalTime timeout)
 
578
{
 
579
        PRInt32 rv;
 
580
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
581
 
 
582
        if ((flags != 0) && (flags != PR_MSG_PEEK)) {
 
583
                PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
584
                return -1;
 
585
        }
 
586
        if (_PR_PENDING_INTERRUPT(me)) {
 
587
                me->flags &= ~_PR_INTERRUPT;
 
588
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
589
                return -1;
 
590
        }
 
591
        if (_PR_IO_PENDING(me)) {
 
592
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
593
                return -1;
 
594
        }
 
595
 
 
596
        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d flags=%d",
 
597
                                                                fd, fd->secret->md.osfd, buf, amount, flags));
 
598
 
 
599
#ifdef _PR_HAVE_PEEK_BUFFER
 
600
        if (fd->secret->peekBytes != 0) {
 
601
                rv = (amount < fd->secret->peekBytes) ?
 
602
                        amount : fd->secret->peekBytes;
 
603
                memcpy(buf, fd->secret->peekBuffer, rv);
 
604
                if (flags == 0) {
 
605
                        /* consume the bytes in the peek buffer */
 
606
                        fd->secret->peekBytes -= rv;
 
607
                        if (fd->secret->peekBytes != 0) {
 
608
                                memmove(fd->secret->peekBuffer,
 
609
                                        fd->secret->peekBuffer + rv,
 
610
                                        fd->secret->peekBytes);
 
611
                        }
 
612
                }
 
613
                return rv;
 
614
        }
 
615
 
 
616
        /* allocate peek buffer, if necessary */
 
617
        if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
 
618
                PR_ASSERT(0 == fd->secret->peekBytes);
 
619
                /* impose a max size on the peek buffer */
 
620
                if (amount > _PR_PEEK_BUFFER_MAX) {
 
621
                        amount = _PR_PEEK_BUFFER_MAX;
 
622
                }
 
623
                if (fd->secret->peekBufSize < amount) {
 
624
                        if (fd->secret->peekBuffer) {
 
625
                                PR_Free(fd->secret->peekBuffer);
 
626
                        }
 
627
                        fd->secret->peekBufSize = amount;
 
628
                        fd->secret->peekBuffer = PR_Malloc(amount);
 
629
                        if (NULL == fd->secret->peekBuffer) {
 
630
                                fd->secret->peekBufSize = 0;
 
631
                                PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
632
                                return -1;
 
633
                        }
 
634
                }
 
635
        }
 
636
#endif
 
637
 
 
638
        rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
 
639
        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
 
640
                rv, PR_GetError(), PR_GetOSError()));
 
641
 
 
642
#ifdef _PR_HAVE_PEEK_BUFFER
 
643
        if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
 
644
                if (rv > 0) {
 
645
                        memcpy(fd->secret->peekBuffer, buf, rv);
 
646
                        fd->secret->peekBytes = rv;
 
647
                }
 
648
        }
 
649
#endif
 
650
 
 
651
        return rv;
 
652
}
 
653
 
 
654
static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
 
655
{
 
656
        return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
 
657
}
 
658
 
 
659
static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
 
660
PRIntn flags, PRIntervalTime timeout)
 
661
{
 
662
        PRInt32 temp, count;
 
663
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
664
 
 
665
        if (_PR_PENDING_INTERRUPT(me)) {
 
666
                me->flags &= ~_PR_INTERRUPT;
 
667
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
668
                return -1;
 
669
        }
 
670
        if (_PR_IO_PENDING(me)) {
 
671
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
672
                return -1;
 
673
        }
 
674
 
 
675
        count = 0;
 
676
        while (amount > 0) {
 
677
                PR_LOG(_pr_io_lm, PR_LOG_MAX,
 
678
                    ("send: fd=%p osfd=%d buf=%p amount=%d",
 
679
                    fd, fd->secret->md.osfd, buf, amount));
 
680
                temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
 
681
                if (temp < 0) {
 
682
                                        count = -1;
 
683
                                        break;
 
684
                                }
 
685
 
 
686
                count += temp;
 
687
                if (fd->secret->nonblocking) {
 
688
                        break;
 
689
                }
 
690
                buf = (const void*) ((const char*)buf + temp);
 
691
 
 
692
                amount -= temp;
 
693
        }
 
694
        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
 
695
        return count;
 
696
}
 
697
 
 
698
static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
 
699
{
 
700
        return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
 
701
}
 
702
 
 
703
static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
 
704
{
 
705
        if (!fd || !fd->secret
 
706
                        || (fd->secret->state != _PR_FILEDESC_OPEN
 
707
                        && fd->secret->state != _PR_FILEDESC_CLOSED)) {
 
708
                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 
709
                return PR_FAILURE;
 
710
        }
 
711
 
 
712
        if (fd->secret->state == _PR_FILEDESC_OPEN) {
 
713
                if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
 
714
                        return PR_FAILURE;
 
715
                }
 
716
                fd->secret->state = _PR_FILEDESC_CLOSED;
 
717
        }
 
718
 
 
719
#ifdef _PR_HAVE_PEEK_BUFFER
 
720
        if (fd->secret->peekBuffer) {
 
721
                PR_ASSERT(fd->secret->peekBufSize > 0);
 
722
                PR_DELETE(fd->secret->peekBuffer);
 
723
                fd->secret->peekBufSize = 0;
 
724
                fd->secret->peekBytes = 0;
 
725
        }
 
726
#endif
 
727
 
 
728
        PR_FreeFileDesc(fd);
 
729
        return PR_SUCCESS;
 
730
}
 
731
 
 
732
static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
 
733
{
 
734
        PRInt32 rv;
 
735
#ifdef _PR_HAVE_PEEK_BUFFER
 
736
        if (fd->secret->peekBytes != 0) {
 
737
                return fd->secret->peekBytes;
 
738
        }
 
739
#endif
 
740
        rv =  _PR_MD_SOCKETAVAILABLE(fd);
 
741
        return rv;              
 
742
}
 
743
 
 
744
static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
 
745
{
 
746
    PRInt64 rv;
 
747
#ifdef _PR_HAVE_PEEK_BUFFER
 
748
    if (fd->secret->peekBytes != 0) {
 
749
        LL_I2L(rv, fd->secret->peekBytes);
 
750
        return rv;
 
751
    }
 
752
#endif
 
753
    LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
 
754
        return rv;              
 
755
}
 
756
 
 
757
static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
 
758
{
 
759
#if defined(XP_MAC)
 
760
#pragma unused (fd)
 
761
#endif
 
762
 
 
763
        return PR_SUCCESS;
 
764
}
 
765
 
 
766
static PRInt32 PR_CALLBACK SocketSendTo(
 
767
    PRFileDesc *fd, const void *buf, PRInt32 amount,
 
768
    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
 
769
{
 
770
        PRInt32 temp, count;
 
771
    const PRNetAddr *addrp = addr;
 
772
#if defined(_PR_INET6)
 
773
        PRNetAddr addrCopy;
 
774
#endif
 
775
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
776
 
 
777
        if (_PR_PENDING_INTERRUPT(me)) {
 
778
                me->flags &= ~_PR_INTERRUPT;
 
779
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
780
                return -1;
 
781
        }
 
782
        if (_PR_IO_PENDING(me)) {
 
783
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
784
                return -1;
 
785
        }
 
786
 
 
787
        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
 
788
#if defined(_PR_INET6)
 
789
        if (addr->raw.family == PR_AF_INET6) {
 
790
                addrCopy = *addr;
 
791
                addrCopy.raw.family = AF_INET6;
 
792
                addrp = &addrCopy;
 
793
        }
 
794
#endif
 
795
 
 
796
        count = 0;
 
797
        while (amount > 0) {
 
798
                temp = _PR_MD_SENDTO(fd, buf, amount, flags,
 
799
                    addrp, PR_NETADDR_SIZE(addr), timeout);
 
800
                if (temp < 0) {
 
801
                                        count = -1;
 
802
                                        break;
 
803
                                }
 
804
                count += temp;
 
805
                if (fd->secret->nonblocking) {
 
806
                        break;
 
807
                }
 
808
                buf = (const void*) ((const char*)buf + temp);
 
809
                amount -= temp;
 
810
        }
 
811
        return count;
 
812
}
 
813
 
 
814
static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
 
815
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
 
816
{
 
817
        PRInt32 rv;
 
818
        PRUint32 al;
 
819
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
820
 
 
821
        if (_PR_PENDING_INTERRUPT(me)) {
 
822
                me->flags &= ~_PR_INTERRUPT;
 
823
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
824
                return -1;
 
825
        }
 
826
        if (_PR_IO_PENDING(me)) {
 
827
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
828
                return -1;
 
829
        }
 
830
 
 
831
        al = sizeof(PRNetAddr);
 
832
        rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
 
833
#ifdef _PR_INET6
 
834
        if (addr && (AF_INET6 == addr->raw.family))
 
835
        addr->raw.family = PR_AF_INET6;
 
836
#endif
 
837
        return rv;
 
838
}
 
839
 
 
840
static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
 
841
PRNetAddr **raddr, void *buf, PRInt32 amount,
 
842
PRIntervalTime timeout)
 
843
{
 
844
        PRInt32 rv;
 
845
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
846
 
 
847
        if (_PR_PENDING_INTERRUPT(me)) {
 
848
                me->flags &= ~_PR_INTERRUPT;
 
849
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
850
                return -1;
 
851
        }
 
852
        if (_PR_IO_PENDING(me)) {
 
853
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
854
                return -1;
 
855
        }
 
856
        /* The socket must be in blocking mode. */
 
857
        if (sd->secret->nonblocking) {
 
858
                PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
859
                return -1;
 
860
        }
 
861
        *nd = NULL;
 
862
 
 
863
#if defined(WINNT)
 
864
        {
 
865
        PRInt32 newSock;
 
866
        PRNetAddr *raddrCopy;
 
867
 
 
868
        if (raddr == NULL) {
 
869
                raddr = &raddrCopy;
 
870
        }
 
871
        rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
 
872
        if (rv < 0) {
 
873
                rv = -1;
 
874
        } else {
 
875
                /* Successfully accepted and read; create the new PRFileDesc */
 
876
                *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
 
877
                if (*nd == 0) {
 
878
                        _PR_MD_CLOSE_SOCKET(newSock);
 
879
                        /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
880
                        rv = -1;
 
881
                } else {
 
882
                        (*nd)->secret->md.io_model_committed = PR_TRUE;
 
883
                        (*nd)->secret->md.accepted_socket = PR_TRUE;
 
884
                        memcpy(&(*nd)->secret->md.peer_addr, *raddr,
 
885
                                PR_NETADDR_SIZE(*raddr));
 
886
#ifdef _PR_INET6
 
887
                        if (AF_INET6 == *raddr->raw.family)
 
888
                        *raddr->raw.family = PR_AF_INET6;
 
889
#endif
 
890
                }
 
891
        }
 
892
        }
 
893
#else
 
894
        rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
 
895
#endif
 
896
        return rv;
 
897
}
 
898
 
 
899
#ifdef WINNT
 
900
PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
 
901
PRNetAddr **raddr, void *buf, PRInt32 amount,
 
902
PRIntervalTime timeout)
 
903
{
 
904
        PRInt32 rv;
 
905
        PRInt32 newSock;
 
906
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
907
        PRNetAddr *raddrCopy;
 
908
 
 
909
        if (_PR_PENDING_INTERRUPT(me)) {
 
910
                me->flags &= ~_PR_INTERRUPT;
 
911
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
912
                return -1;
 
913
        }
 
914
        if (_PR_IO_PENDING(me)) {
 
915
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
916
                return -1;
 
917
        }
 
918
        *nd = NULL;
 
919
 
 
920
        if (raddr == NULL) {
 
921
                raddr = &raddrCopy;
 
922
        }
 
923
        rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
 
924
            timeout, PR_TRUE, NULL, NULL);
 
925
        if (rv < 0) {
 
926
                rv = -1;
 
927
        } else {
 
928
                /* Successfully accepted and read; create the new PRFileDesc */
 
929
                *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
 
930
                if (*nd == 0) {
 
931
                        _PR_MD_CLOSE_SOCKET(newSock);
 
932
                        /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
933
                        rv = -1;
 
934
                } else {
 
935
                        (*nd)->secret->md.io_model_committed = PR_TRUE;
 
936
                        (*nd)->secret->md.accepted_socket = PR_TRUE;
 
937
                        memcpy(&(*nd)->secret->md.peer_addr, *raddr,
 
938
                                PR_NETADDR_SIZE(*raddr));
 
939
#ifdef _PR_INET6
 
940
                        if (AF_INET6 == *raddr->raw.family)
 
941
                        *raddr->raw.family = PR_AF_INET6;
 
942
#endif
 
943
                }
 
944
        }
 
945
        return rv;
 
946
}
 
947
 
 
948
PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
 
949
PRFileDesc *sd, PRFileDesc **nd, 
 
950
PRNetAddr **raddr, void *buf, PRInt32 amount,
 
951
PRIntervalTime timeout,
 
952
_PR_AcceptTimeoutCallback callback,
 
953
void *callbackArg)
 
954
{
 
955
        PRInt32 rv;
 
956
        PRInt32 newSock;
 
957
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
958
        PRNetAddr *raddrCopy;
 
959
 
 
960
        if (_PR_PENDING_INTERRUPT(me)) {
 
961
                me->flags &= ~_PR_INTERRUPT;
 
962
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
963
                return -1;
 
964
        }
 
965
        if (_PR_IO_PENDING(me)) {
 
966
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
967
                return -1;
 
968
        }
 
969
        *nd = NULL;
 
970
 
 
971
        if (raddr == NULL) {
 
972
                raddr = &raddrCopy;
 
973
        }
 
974
        rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
 
975
            timeout, PR_TRUE, callback, callbackArg);
 
976
        if (rv < 0) {
 
977
                rv = -1;
 
978
        } else {
 
979
                /* Successfully accepted and read; create the new PRFileDesc */
 
980
                *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
 
981
                if (*nd == 0) {
 
982
                        _PR_MD_CLOSE_SOCKET(newSock);
 
983
                        /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
984
                        rv = -1;
 
985
                } else {
 
986
                        (*nd)->secret->md.io_model_committed = PR_TRUE;
 
987
                        (*nd)->secret->md.accepted_socket = PR_TRUE;
 
988
                        memcpy(&(*nd)->secret->md.peer_addr, *raddr,
 
989
                                PR_NETADDR_SIZE(*raddr));
 
990
#ifdef _PR_INET6
 
991
                        if (AF_INET6 == *raddr->raw.family)
 
992
                        *raddr->raw.family = PR_AF_INET6;
 
993
#endif
 
994
                }
 
995
        }
 
996
        return rv;
 
997
}
 
998
#endif /* WINNT */
 
999
 
 
1000
#ifdef WINNT
 
1001
PR_IMPLEMENT(void)
 
1002
PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
 
1003
{
 
1004
        _PR_MD_UPDATE_ACCEPT_CONTEXT(
 
1005
                socket->secret->md.osfd, acceptSocket->secret->md.osfd);
 
1006
}
 
1007
#endif /* WINNT */
 
1008
 
 
1009
static PRInt32 PR_CALLBACK SocketSendFile(
 
1010
    PRFileDesc *sd, PRSendFileData *sfd,
 
1011
    PRTransmitFileFlags flags, PRIntervalTime timeout)
 
1012
{
 
1013
        PRInt32 rv;
 
1014
        PRThread *me = _PR_MD_CURRENT_THREAD();
 
1015
 
 
1016
        if (_PR_PENDING_INTERRUPT(me)) {
 
1017
                me->flags &= ~_PR_INTERRUPT;
 
1018
                PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
 
1019
                return -1;
 
1020
        }
 
1021
        if (_PR_IO_PENDING(me)) {
 
1022
                PR_SetError(PR_IO_PENDING_ERROR, 0);
 
1023
                return -1;
 
1024
        }
 
1025
        /* The socket must be in blocking mode. */
 
1026
        if (sd->secret->nonblocking) {
 
1027
                PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
1028
                return -1;
 
1029
        }
 
1030
#if defined(WINNT)
 
1031
        rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
 
1032
        if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
 
1033
                /*
 
1034
                 * This should be kept the same as SocketClose, except
 
1035
                 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
 
1036
                 * not be called because the socket will be recycled.
 
1037
                 */
 
1038
                PR_FreeFileDesc(sd);
 
1039
        }
 
1040
#else
 
1041
        rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
 
1042
#endif  /* WINNT */
 
1043
 
 
1044
        return rv;
 
1045
}
 
1046
 
 
1047
static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
 
1048
const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
 
1049
PRIntervalTime timeout)
 
1050
{
 
1051
        PRSendFileData sfd;
 
1052
 
 
1053
        sfd.fd = fd;
 
1054
        sfd.file_offset = 0;
 
1055
        sfd.file_nbytes = 0;
 
1056
        sfd.header = headers;
 
1057
        sfd.hlen = hlen;
 
1058
        sfd.trailer = NULL;
 
1059
        sfd.tlen = 0;
 
1060
 
 
1061
        return(SocketSendFile(sd, &sfd, flags, timeout));
 
1062
}
 
1063
 
 
1064
static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
 
1065
{
 
1066
        PRInt32 result;
 
1067
        PRUint32 addrlen;
 
1068
 
 
1069
        addrlen = sizeof(PRNetAddr);
 
1070
        result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
 
1071
        if (result < 0) {
 
1072
                return PR_FAILURE;
 
1073
        }
 
1074
#ifdef _PR_INET6
 
1075
        if (AF_INET6 == addr->raw.family)
 
1076
        addr->raw.family = PR_AF_INET6;
 
1077
#endif
 
1078
        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
 
1079
        PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
 
1080
        return PR_SUCCESS;
 
1081
}
 
1082
 
 
1083
static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
 
1084
{
 
1085
        PRInt32 result;
 
1086
        PRUint32 addrlen;
 
1087
 
 
1088
        addrlen = sizeof(PRNetAddr);
 
1089
        result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
 
1090
        if (result < 0) {
 
1091
                return PR_FAILURE;
 
1092
        }
 
1093
#ifdef _PR_INET6
 
1094
        if (AF_INET6 == addr->raw.family)
 
1095
        addr->raw.family = PR_AF_INET6;
 
1096
#endif
 
1097
        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
 
1098
        PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
 
1099
        return PR_SUCCESS;
 
1100
}
 
1101
 
 
1102
static PRInt16 PR_CALLBACK SocketPoll(
 
1103
    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
 
1104
{
 
1105
#ifdef XP_MAC
 
1106
#pragma unused( fd, in_flags )
 
1107
#endif
 
1108
    *out_flags = 0;
 
1109
    return in_flags;
 
1110
}  /* SocketPoll */
 
1111
 
 
1112
static PRIOMethods tcpMethods = {
 
1113
        PR_DESC_SOCKET_TCP,
 
1114
        SocketClose,
 
1115
        SocketRead,
 
1116
        SocketWrite,
 
1117
        SocketAvailable,
 
1118
        SocketAvailable64,
 
1119
        SocketSync,
 
1120
        (PRSeekFN)_PR_InvalidInt,
 
1121
        (PRSeek64FN)_PR_InvalidInt64,
 
1122
        (PRFileInfoFN)_PR_InvalidStatus,
 
1123
        (PRFileInfo64FN)_PR_InvalidStatus,
 
1124
        SocketWritev,
 
1125
        SocketConnect,
 
1126
        SocketAccept,
 
1127
        SocketBind,
 
1128
        SocketListen,
 
1129
        SocketShutdown,
 
1130
        SocketRecv,
 
1131
        SocketSend,
 
1132
        (PRRecvfromFN)_PR_InvalidInt,
 
1133
        (PRSendtoFN)_PR_InvalidInt,
 
1134
        SocketPoll,
 
1135
        SocketAcceptRead,
 
1136
        SocketTransmitFile,
 
1137
        SocketGetName,
 
1138
        SocketGetPeerName,
 
1139
        (PRReservedFN)_PR_InvalidInt,
 
1140
        (PRReservedFN)_PR_InvalidInt,
 
1141
        _PR_SocketGetSocketOption,
 
1142
        _PR_SocketSetSocketOption,
 
1143
    SocketSendFile, 
 
1144
    SocketConnectContinue,
 
1145
    (PRReservedFN)_PR_InvalidInt, 
 
1146
    (PRReservedFN)_PR_InvalidInt, 
 
1147
    (PRReservedFN)_PR_InvalidInt, 
 
1148
    (PRReservedFN)_PR_InvalidInt
 
1149
};
 
1150
 
 
1151
static PRIOMethods udpMethods = {
 
1152
        PR_DESC_SOCKET_UDP,
 
1153
        SocketClose,
 
1154
        SocketRead,
 
1155
        SocketWrite,
 
1156
        SocketAvailable,
 
1157
        SocketAvailable64,
 
1158
        SocketSync,
 
1159
        (PRSeekFN)_PR_InvalidInt,
 
1160
        (PRSeek64FN)_PR_InvalidInt64,
 
1161
        (PRFileInfoFN)_PR_InvalidStatus,
 
1162
        (PRFileInfo64FN)_PR_InvalidStatus,
 
1163
        SocketWritev,
 
1164
        SocketConnect,
 
1165
        (PRAcceptFN)_PR_InvalidDesc,
 
1166
        SocketBind,
 
1167
        SocketListen,
 
1168
        SocketShutdown,
 
1169
        SocketRecv,
 
1170
        SocketSend,
 
1171
        SocketRecvFrom,
 
1172
        SocketSendTo,
 
1173
        SocketPoll,
 
1174
        (PRAcceptreadFN)_PR_InvalidInt,
 
1175
        (PRTransmitfileFN)_PR_InvalidInt,
 
1176
        SocketGetName,
 
1177
        SocketGetPeerName,
 
1178
        (PRReservedFN)_PR_InvalidInt,
 
1179
        (PRReservedFN)_PR_InvalidInt,
 
1180
        _PR_SocketGetSocketOption,
 
1181
        _PR_SocketSetSocketOption,
 
1182
    (PRSendfileFN)_PR_InvalidInt, 
 
1183
    (PRConnectcontinueFN)_PR_InvalidStatus, 
 
1184
    (PRReservedFN)_PR_InvalidInt, 
 
1185
    (PRReservedFN)_PR_InvalidInt, 
 
1186
    (PRReservedFN)_PR_InvalidInt, 
 
1187
    (PRReservedFN)_PR_InvalidInt
 
1188
};
 
1189
 
 
1190
 
 
1191
static PRIOMethods socketpollfdMethods = {
 
1192
    (PRDescType) 0,
 
1193
    (PRCloseFN)_PR_InvalidStatus,
 
1194
    (PRReadFN)_PR_InvalidInt,
 
1195
    (PRWriteFN)_PR_InvalidInt,
 
1196
    (PRAvailableFN)_PR_InvalidInt,
 
1197
    (PRAvailable64FN)_PR_InvalidInt64,
 
1198
    (PRFsyncFN)_PR_InvalidStatus,
 
1199
    (PRSeekFN)_PR_InvalidInt,
 
1200
    (PRSeek64FN)_PR_InvalidInt64,
 
1201
    (PRFileInfoFN)_PR_InvalidStatus,
 
1202
    (PRFileInfo64FN)_PR_InvalidStatus,
 
1203
    (PRWritevFN)_PR_InvalidInt,        
 
1204
    (PRConnectFN)_PR_InvalidStatus,        
 
1205
    (PRAcceptFN)_PR_InvalidDesc,        
 
1206
    (PRBindFN)_PR_InvalidStatus,        
 
1207
    (PRListenFN)_PR_InvalidStatus,        
 
1208
    (PRShutdownFN)_PR_InvalidStatus,    
 
1209
    (PRRecvFN)_PR_InvalidInt,        
 
1210
    (PRSendFN)_PR_InvalidInt,        
 
1211
    (PRRecvfromFN)_PR_InvalidInt,    
 
1212
    (PRSendtoFN)_PR_InvalidInt,        
 
1213
        SocketPoll,
 
1214
    (PRAcceptreadFN)_PR_InvalidInt,   
 
1215
    (PRTransmitfileFN)_PR_InvalidInt, 
 
1216
    (PRGetsocknameFN)_PR_InvalidStatus,    
 
1217
    (PRGetpeernameFN)_PR_InvalidStatus,    
 
1218
    (PRReservedFN)_PR_InvalidInt,    
 
1219
    (PRReservedFN)_PR_InvalidInt,    
 
1220
    (PRGetsocketoptionFN)_PR_InvalidStatus,
 
1221
    (PRSetsocketoptionFN)_PR_InvalidStatus,
 
1222
    (PRSendfileFN)_PR_InvalidInt, 
 
1223
    (PRConnectcontinueFN)_PR_InvalidStatus, 
 
1224
    (PRReservedFN)_PR_InvalidInt, 
 
1225
    (PRReservedFN)_PR_InvalidInt, 
 
1226
    (PRReservedFN)_PR_InvalidInt, 
 
1227
    (PRReservedFN)_PR_InvalidInt
 
1228
};
 
1229
 
 
1230
PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
 
1231
{
 
1232
        return &tcpMethods;
 
1233
}
 
1234
 
 
1235
PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
 
1236
{
 
1237
        return &udpMethods;
 
1238
}
 
1239
 
 
1240
static const PRIOMethods* PR_GetSocketPollFdMethods()
 
1241
{
 
1242
    return &socketpollfdMethods;
 
1243
}  /* PR_GetSocketPollFdMethods */
 
1244
 
 
1245
#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
 
1246
PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
 
1247
 
 
1248
#if defined(_PR_INET6_PROBE)
 
1249
 
 
1250
PR_EXTERN(PRBool) _pr_ipv6_is_present;
 
1251
 
 
1252
PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
 
1253
{
 
1254
PRInt32 osfd;
 
1255
 
 
1256
        osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
 
1257
        if (osfd != -1) {
 
1258
                _PR_MD_CLOSE_SOCKET(osfd);
 
1259
                return PR_TRUE;
 
1260
        }
 
1261
        return PR_FALSE;
 
1262
}
 
1263
#endif  /* _PR_INET6_PROBE */
 
1264
 
 
1265
#endif
 
1266
 
 
1267
PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
 
1268
{
 
1269
        PRInt32 osfd;
 
1270
        PRFileDesc *fd;
 
1271
        PRInt32 tmp_domain = domain;
 
1272
 
 
1273
        if (!_pr_initialized) _PR_ImplicitInitialization();
 
1274
        if (PR_AF_INET != domain
 
1275
                        && PR_AF_INET6 != domain
 
1276
#if defined(XP_UNIX) || defined(XP_OS2)
 
1277
                        && PR_AF_LOCAL != domain
 
1278
#endif
 
1279
                        ) {
 
1280
                PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
 
1281
                return NULL;
 
1282
        }
 
1283
 
 
1284
#if defined(_PR_INET6_PROBE)
 
1285
        if (PR_AF_INET6 == domain) {
 
1286
                if (_pr_ipv6_is_present == PR_FALSE) 
 
1287
                        domain = AF_INET;
 
1288
                else
 
1289
                        domain = AF_INET6;
 
1290
        }
 
1291
#elif defined(_PR_INET6)
 
1292
        if (PR_AF_INET6 == domain)
 
1293
                domain = AF_INET6;
 
1294
#else
 
1295
        if (PR_AF_INET6 == domain)
 
1296
                domain = AF_INET;
 
1297
#endif  /* _PR_INET6 */
 
1298
        osfd = _PR_MD_SOCKET(domain, type, proto);
 
1299
        if (osfd == -1) {
 
1300
                return 0;
 
1301
        }
 
1302
        if (type == SOCK_STREAM)
 
1303
                fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
 
1304
        else
 
1305
                fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
 
1306
        /*
 
1307
         * Make the sockets non-blocking
 
1308
         */
 
1309
        if (fd != NULL) {
 
1310
                _PR_MD_MAKE_NONBLOCK(fd);
 
1311
                _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
 
1312
#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
 
1313
                /*
 
1314
                 * For platforms with no support for IPv6 
 
1315
                 * create layered socket for IPv4-mapped IPv6 addresses
 
1316
                 */
 
1317
                if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
 
1318
                        if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
 
1319
                                PR_Close(fd);
 
1320
                                fd = NULL;
 
1321
                        }
 
1322
                }
 
1323
#endif
 
1324
        } else
 
1325
                _PR_MD_CLOSE_SOCKET(osfd);
 
1326
 
 
1327
        return fd;
 
1328
}
 
1329
 
 
1330
PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
 
1331
{
 
1332
        PRInt32 domain = AF_INET;
 
1333
 
 
1334
        return PR_Socket(domain, SOCK_STREAM, 0);
 
1335
}
 
1336
 
 
1337
PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
 
1338
{
 
1339
        PRInt32 domain = AF_INET;
 
1340
 
 
1341
        return PR_Socket(domain, SOCK_DGRAM, 0);
 
1342
}
 
1343
 
 
1344
PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
 
1345
{
 
1346
        return PR_Socket(af, SOCK_STREAM, 0);
 
1347
}
 
1348
 
 
1349
PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
 
1350
{
 
1351
        return PR_Socket(af, SOCK_DGRAM, 0);
 
1352
}
 
1353
 
 
1354
PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
 
1355
{
 
1356
#ifdef XP_UNIX
 
1357
        PRInt32 rv, osfd[2];
 
1358
 
 
1359
        if (!_pr_initialized) _PR_ImplicitInitialization();
 
1360
 
 
1361
        rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
 
1362
        if (rv == -1) {
 
1363
                return PR_FAILURE;
 
1364
        }
 
1365
 
 
1366
        f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
 
1367
        if (!f[0]) {
 
1368
                _PR_MD_CLOSE_SOCKET(osfd[0]);
 
1369
                _PR_MD_CLOSE_SOCKET(osfd[1]);
 
1370
                /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
1371
                return PR_FAILURE;
 
1372
        }
 
1373
        f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
 
1374
        if (!f[1]) {
 
1375
                PR_Close(f[0]);
 
1376
                _PR_MD_CLOSE_SOCKET(osfd[1]);
 
1377
                /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
1378
                return PR_FAILURE;
 
1379
        }
 
1380
        _PR_MD_MAKE_NONBLOCK(f[0]);
 
1381
        _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
 
1382
        _PR_MD_MAKE_NONBLOCK(f[1]);
 
1383
        _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
 
1384
        return PR_SUCCESS;
 
1385
#elif defined(WINNT)
 
1386
    /*
 
1387
     * A socket pair is often used for interprocess communication,
 
1388
     * so we need to make sure neither socket is associated with
 
1389
     * the I/O completion port; otherwise it can't be used by a
 
1390
     * child process.
 
1391
     *
 
1392
     * The default implementation below cannot be used for NT
 
1393
     * because PR_Accept would have associated the I/O completion
 
1394
     * port with the listening and accepted sockets.
 
1395
     */
 
1396
    SOCKET listenSock;
 
1397
    SOCKET osfd[2];
 
1398
    struct sockaddr_in selfAddr, peerAddr;
 
1399
    int addrLen;
 
1400
 
 
1401
    if (!_pr_initialized) _PR_ImplicitInitialization();
 
1402
 
 
1403
    osfd[0] = osfd[1] = INVALID_SOCKET;
 
1404
    listenSock = socket(AF_INET, SOCK_STREAM, 0);
 
1405
    if (listenSock == INVALID_SOCKET) {
 
1406
        goto failed;
 
1407
    }
 
1408
    selfAddr.sin_family = AF_INET;
 
1409
    selfAddr.sin_port = 0;
 
1410
    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
 
1411
    addrLen = sizeof(selfAddr);
 
1412
    if (bind(listenSock, (struct sockaddr *) &selfAddr,
 
1413
            addrLen) == SOCKET_ERROR) {
 
1414
        goto failed;
 
1415
    }
 
1416
    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
 
1417
            &addrLen) == SOCKET_ERROR) {
 
1418
        goto failed;
 
1419
    }
 
1420
    if (listen(listenSock, 5) == SOCKET_ERROR) {
 
1421
        goto failed;
 
1422
    }
 
1423
    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
 
1424
    if (osfd[0] == INVALID_SOCKET) {
 
1425
        goto failed;
 
1426
    }
 
1427
    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
1428
 
 
1429
    /*
 
1430
     * Only a thread is used to do the connect and accept.
 
1431
     * I am relying on the fact that connect returns
 
1432
     * successfully as soon as the connect request is put
 
1433
     * into the listen queue (but before accept is called).
 
1434
     * This is the behavior of the BSD socket code.  If
 
1435
     * connect does not return until accept is called, we
 
1436
     * will need to create another thread to call connect.
 
1437
     */
 
1438
    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
 
1439
            addrLen) == SOCKET_ERROR) {
 
1440
        goto failed;
 
1441
    }
 
1442
    /*
 
1443
     * A malicious local process may connect to the listening
 
1444
     * socket, so we need to verify that the accepted connection
 
1445
     * is made from our own socket osfd[0].
 
1446
     */
 
1447
    if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
 
1448
            &addrLen) == SOCKET_ERROR) {
 
1449
        goto failed;
 
1450
    }
 
1451
    osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
 
1452
    if (osfd[1] == INVALID_SOCKET) {
 
1453
        goto failed;
 
1454
    }
 
1455
    if (peerAddr.sin_port != selfAddr.sin_port) {
 
1456
        /* the connection we accepted is not from osfd[0] */
 
1457
        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
 
1458
        goto failed;
 
1459
    }
 
1460
    closesocket(listenSock);
 
1461
 
 
1462
    f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
 
1463
    if (!f[0]) {
 
1464
        closesocket(osfd[0]);
 
1465
        closesocket(osfd[1]);
 
1466
        /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
1467
        return PR_FAILURE;
 
1468
    }
 
1469
    f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
 
1470
    if (!f[1]) {
 
1471
        PR_Close(f[0]);
 
1472
        closesocket(osfd[1]);
 
1473
        /* PR_AllocFileDesc() has invoked PR_SetError(). */
 
1474
        return PR_FAILURE;
 
1475
    }
 
1476
    _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
 
1477
    _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
 
1478
    return PR_SUCCESS;
 
1479
 
 
1480
failed:
 
1481
    if (listenSock != INVALID_SOCKET) {
 
1482
        closesocket(listenSock);
 
1483
    }
 
1484
    if (osfd[0] != INVALID_SOCKET) {
 
1485
        closesocket(osfd[0]);
 
1486
    }
 
1487
    if (osfd[1] != INVALID_SOCKET) {
 
1488
        closesocket(osfd[1]);
 
1489
    }
 
1490
    return PR_FAILURE;
 
1491
#else /* not Unix or NT */
 
1492
    /*
 
1493
     * default implementation
 
1494
     */
 
1495
    PRFileDesc *listenSock;
 
1496
    PRNetAddr selfAddr, peerAddr;
 
1497
    PRUint16 port;
 
1498
 
 
1499
    f[0] = f[1] = NULL;
 
1500
    listenSock = PR_NewTCPSocket();
 
1501
    if (listenSock == NULL) {
 
1502
        goto failed;
 
1503
    }
 
1504
    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
 
1505
    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
 
1506
        goto failed;
 
1507
    }
 
1508
    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
 
1509
        goto failed;
 
1510
    }
 
1511
    port = ntohs(selfAddr.inet.port);
 
1512
    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
 
1513
        goto failed;
 
1514
    }
 
1515
    f[0] = PR_NewTCPSocket();
 
1516
    if (f[0] == NULL) {
 
1517
        goto failed;
 
1518
    }
 
1519
#ifdef _PR_CONNECT_DOES_NOT_BIND
 
1520
    /*
 
1521
     * If connect does not implicitly bind the socket (e.g., on
 
1522
     * BeOS), we have to bind the socket so that we can get its
 
1523
     * port with getsockname later.
 
1524
     */
 
1525
    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
 
1526
    if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
 
1527
        goto failed;
 
1528
    }
 
1529
#endif
 
1530
    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
 
1531
 
 
1532
    /*
 
1533
     * Only a thread is used to do the connect and accept.
 
1534
     * I am relying on the fact that PR_Connect returns
 
1535
     * successfully as soon as the connect request is put
 
1536
     * into the listen queue (but before PR_Accept is called).
 
1537
     * This is the behavior of the BSD socket code.  If
 
1538
     * connect does not return until accept is called, we
 
1539
     * will need to create another thread to call connect.
 
1540
     */
 
1541
    if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
 
1542
            == PR_FAILURE) {
 
1543
        goto failed;
 
1544
    }
 
1545
    /*
 
1546
     * A malicious local process may connect to the listening
 
1547
     * socket, so we need to verify that the accepted connection
 
1548
     * is made from our own socket f[0].
 
1549
     */
 
1550
    if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
 
1551
        goto failed;
 
1552
    }
 
1553
    f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
 
1554
    if (f[1] == NULL) {
 
1555
        goto failed;
 
1556
    }
 
1557
    if (peerAddr.inet.port != selfAddr.inet.port) {
 
1558
        /* the connection we accepted is not from f[0] */
 
1559
        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
 
1560
        goto failed;
 
1561
    }
 
1562
    PR_Close(listenSock);
 
1563
    return PR_SUCCESS;
 
1564
 
 
1565
failed:
 
1566
    if (listenSock) {
 
1567
        PR_Close(listenSock);
 
1568
    }
 
1569
    if (f[0]) {
 
1570
        PR_Close(f[0]);
 
1571
    }
 
1572
    if (f[1]) {
 
1573
        PR_Close(f[1]);
 
1574
    }
 
1575
    return PR_FAILURE;
 
1576
#endif
 
1577
}
 
1578
 
 
1579
PR_IMPLEMENT(PRInt32)
 
1580
PR_FileDesc2NativeHandle(PRFileDesc *fd)
 
1581
{
 
1582
    if (fd) {
 
1583
        fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
 
1584
    }
 
1585
    if (!fd) {
 
1586
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
 
1587
        return -1;
 
1588
    }
 
1589
    return fd->secret->md.osfd;
 
1590
}
 
1591
 
 
1592
PR_IMPLEMENT(void)
 
1593
PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
 
1594
{
 
1595
        if (fd)
 
1596
                fd->secret->md.osfd = handle;
 
1597
}
 
1598
 
 
1599
/*
 
1600
** Select compatibility
 
1601
**
 
1602
*/
 
1603
 
 
1604
PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
 
1605
{
 
1606
        memset(set, 0, sizeof(PR_fd_set));
 
1607
}
 
1608
 
 
1609
PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
 
1610
{
 
1611
        PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
 
1612
 
 
1613
        set->harray[set->hsize++] = fh;
 
1614
}
 
1615
 
 
1616
PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
 
1617
{
 
1618
        PRUint32 index, index2;
 
1619
 
 
1620
        for (index = 0; index<set->hsize; index++)
 
1621
                if (set->harray[index] == fh) {
 
1622
                        for (index2=index; index2 < (set->hsize-1); index2++) {
 
1623
                                set->harray[index2] = set->harray[index2+1];
 
1624
                        }
 
1625
                        set->hsize--;
 
1626
                        break;
 
1627
                }
 
1628
}
 
1629
 
 
1630
PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
 
1631
{
 
1632
        PRUint32 index;
 
1633
        for (index = 0; index<set->hsize; index++)
 
1634
                if (set->harray[index] == fh) {
 
1635
                        return 1;
 
1636
                }
 
1637
        return 0;
 
1638
}
 
1639
 
 
1640
PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
 
1641
{
 
1642
        PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
 
1643
 
 
1644
        set->narray[set->nsize++] = fd;
 
1645
}
 
1646
 
 
1647
PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
 
1648
{
 
1649
        PRUint32 index, index2;
 
1650
 
 
1651
        for (index = 0; index<set->nsize; index++)
 
1652
                if (set->narray[index] == fd) {
 
1653
                        for (index2=index; index2 < (set->nsize-1); index2++) {
 
1654
                                set->narray[index2] = set->narray[index2+1];
 
1655
                        }
 
1656
                        set->nsize--;
 
1657
                        break;
 
1658
                }
 
1659
}
 
1660
 
 
1661
PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
 
1662
{
 
1663
        PRUint32 index;
 
1664
        for (index = 0; index<set->nsize; index++)
 
1665
                if (set->narray[index] == fd) {
 
1666
                        return 1;
 
1667
                }
 
1668
        return 0;
 
1669
}
 
1670
 
 
1671
 
 
1672
#if !defined(NEED_SELECT)
 
1673
#if !defined(XP_MAC)
 
1674
#include "obsolete/probslet.h"
 
1675
#else
 
1676
#include "probslet.h"
 
1677
#endif
 
1678
 
 
1679
#define PD_INCR 20
 
1680
 
 
1681
static PRPollDesc *_pr_setfd(
 
1682
    PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
 
1683
{
 
1684
    PRUintn fsidx, pdidx;
 
1685
    PRPollDesc *poll = polldesc;
 
1686
 
 
1687
    if (NULL == set) return poll;
 
1688
 
 
1689
        /* First set the pr file handle osfds */
 
1690
        for (fsidx = 0; fsidx < set->hsize; fsidx++)
 
1691
        {
 
1692
            for (pdidx = 0; 1; pdidx++)
 
1693
        {
 
1694
            if ((PRFileDesc*)-1 == poll[pdidx].fd)
 
1695
            {
 
1696
                /* our vector is full - extend and condition it */
 
1697
                poll = (PRPollDesc*)PR_Realloc(
 
1698
                    poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
 
1699
                if (NULL == poll) goto out_of_memory;
 
1700
                memset(
 
1701
                    poll + pdidx * sizeof(PRPollDesc),
 
1702
                    0, PD_INCR * sizeof(PRPollDesc));
 
1703
                poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
 
1704
            }
 
1705
            if ((NULL == poll[pdidx].fd)
 
1706
            || (poll[pdidx].fd == set->harray[fsidx]))
 
1707
            {
 
1708
                /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
 
1709
                /* either empty or prevously defined */
 
1710
                poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
 
1711
                poll[pdidx].in_flags |= flags;  /* possibly redundant */
 
1712
                break;
 
1713
            }
 
1714
        }
 
1715
        }
 
1716
 
 
1717
#if 0
 
1718
        /* Second set the native osfds */
 
1719
        for (fsidx = 0; fsidx < set->nsize; fsidx++)
 
1720
        {
 
1721
            for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
 
1722
        {
 
1723
            if ((PRFileDesc*)-1 == poll[pdidx].fd)
 
1724
            {
 
1725
                /* our vector is full - extend and condition it */
 
1726
                poll = PR_Realloc(
 
1727
                    poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
 
1728
                if (NULL == poll) goto out_of_memory;
 
1729
                memset(
 
1730
                    poll + pdidx * sizeof(PRPollDesc),
 
1731
                    0, PD_INCR * sizeof(PRPollDesc));
 
1732
                poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
 
1733
            }
 
1734
            if ((NULL == poll[pdidx].fd)
 
1735
            || (poll[pdidx].fd == set->narray[fsidx]))
 
1736
            {
 
1737
                /* either empty or prevously defined */
 
1738
                poll[pdidx].fd = set->narray[fsidx];
 
1739
                PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
 
1740
                poll[pdidx].in_flags |= flags;
 
1741
                break;
 
1742
            }
 
1743
        }
 
1744
        }
 
1745
#endif /* 0 */
 
1746
 
 
1747
        return poll;
 
1748
 
 
1749
out_of_memory:
 
1750
    if (NULL != polldesc) PR_DELETE(polldesc);
 
1751
    return NULL;
 
1752
}  /* _pr_setfd */
 
1753
 
 
1754
#endif /* !defined(NEED_SELECT) */
 
1755
 
 
1756
PR_IMPLEMENT(PRInt32) PR_Select(
 
1757
    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
 
1758
    PR_fd_set *pr_ex, PRIntervalTime timeout)
 
1759
{
 
1760
 
 
1761
#if !defined(NEED_SELECT)
 
1762
    PRInt32 npds = 0; 
 
1763
    /*
 
1764
    ** Find out how many fds are represented in the three lists.
 
1765
    ** Then allocate a polling descriptor for the logical union
 
1766
    ** (there can't be any overlapping) and call PR_Poll().
 
1767
    */
 
1768
 
 
1769
    PRPollDesc *copy, *poll;
 
1770
 
 
1771
    static PRBool warning = PR_TRUE;
 
1772
    if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
 
1773
 
 
1774
    /* try to get an initial guesss at how much space we need */
 
1775
    npds = 0;
 
1776
    if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
 
1777
        npds = pr_rd->hsize + pr_rd->nsize;
 
1778
    if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
 
1779
        npds = pr_wr->hsize + pr_wr->nsize;
 
1780
    if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
 
1781
        npds = pr_ex->hsize + pr_ex->nsize;
 
1782
 
 
1783
    if (0 == npds)
 
1784
    {
 
1785
        PR_Sleep(timeout);
 
1786
        return 0;
 
1787
    }
 
1788
 
 
1789
    copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
 
1790
    if (NULL == poll) goto out_of_memory;
 
1791
    poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
 
1792
 
 
1793
    poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
 
1794
    if (NULL == poll) goto out_of_memory;
 
1795
    poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
 
1796
    if (NULL == poll) goto out_of_memory;
 
1797
    poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
 
1798
    if (NULL == poll) goto out_of_memory;
 
1799
    unused = 0;
 
1800
    while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
 
1801
    {
 
1802
        ++unused;
 
1803
    }
 
1804
 
 
1805
    PR_ASSERT(unused > 0);
 
1806
    npds = PR_Poll(poll, unused, timeout);
 
1807
 
 
1808
    if (npds > 0)
 
1809
    {
 
1810
        /* Copy the results back into the fd sets */
 
1811
        if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
 
1812
        if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
 
1813
        if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
 
1814
        for (copy = &poll[unused - 1]; copy >= poll; --copy)
 
1815
        {
 
1816
            if (copy->out_flags & PR_POLL_NVAL)
 
1817
            {
 
1818
                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 
1819
                npds = -1;
 
1820
                break;
 
1821
            }
 
1822
            if (copy->out_flags & PR_POLL_READ)
 
1823
                if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
 
1824
            if (copy->out_flags & PR_POLL_WRITE)
 
1825
                if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
 
1826
            if (copy->out_flags & PR_POLL_EXCEPT)
 
1827
                if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
 
1828
        }
 
1829
    }
 
1830
    PR_DELETE(poll);
 
1831
 
 
1832
    return npds;
 
1833
out_of_memory:
 
1834
    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
 
1835
    return -1;    
 
1836
 
 
1837
#endif /* !defined(NEED_SELECT) */
 
1838
    
 
1839
}