1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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/
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.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
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
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
39
/************************************************************************/
41
/* These two functions are only used in assertions. */
44
PRBool IsValidNetAddr(const PRNetAddr *addr)
47
#if defined(XP_UNIX) || defined(XP_OS2)
48
&& (addr->raw.family != PR_AF_LOCAL)
50
&& (addr->raw.family != PR_AF_INET6)
51
&& (addr->raw.family != PR_AF_INET)) {
57
static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
60
* The definition of the length of a Unix domain socket address
61
* is not uniform, so we don't check it.
64
#if defined(XP_UNIX) || defined(XP_OS2)
65
&& (addr->raw.family != AF_UNIX)
67
&& (PR_NETADDR_SIZE(addr) != addr_len)) {
68
#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
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)
76
if ((PR_AF_INET6 == addr->raw.family)
77
&& (sizeof(addr->ipv6) == addr_len)) {
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)).
88
if (sizeof(PRNetAddr) == addr_len) {
99
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
100
PRInt32 iov_size, PRIntervalTime timeout)
102
PRThread *me = _PR_MD_CURRENT_THREAD();
104
const PRIOVec *tmp_iov;
105
#define LOCAL_MAXIOV 8
106
PRIOVec local_iov[LOCAL_MAXIOV];
107
PRIOVec *iov_copy = NULL;
110
int count=0, sz = 0; /* 'count' is the return value. */
112
if (_PR_PENDING_INTERRUPT(me)) {
113
me->flags &= ~_PR_INTERRUPT;
114
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
117
if (_PR_IO_PENDING(me)) {
118
PR_SetError(PR_IO_PENDING_ERROR, 0);
123
* Assume the first writev will succeed. Copy iov's only on
127
for (index = 0; index < iov_size; index++)
128
sz += iov[index].iov_len;
134
w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
140
if (fd->secret->nonblocking) {
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 */
151
if (tmp_iov == iov) {
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.
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);
168
PR_ASSERT(tmp_iov == iov_copy);
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;
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;
183
if (iov_copy != local_iov)
188
/************************************************************************/
190
PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
194
if (!_pr_initialized) _PR_ImplicitInitialization();
195
fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
197
_PR_MD_MAKE_NONBLOCK(fd);
198
_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
200
_PR_MD_CLOSE_SOCKET(osfd);
204
PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
208
if (!_pr_initialized) _PR_ImplicitInitialization();
209
fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
211
_PR_MD_MAKE_NONBLOCK(fd);
212
_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
214
_PR_MD_CLOSE_SOCKET(osfd);
219
static const PRIOMethods* PR_GetSocketPollFdMethods(void);
221
PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
225
if (!_pr_initialized) _PR_ImplicitInitialization();
229
if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
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();
239
} /* PR_CreateSocketPollFD */
241
PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
245
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
248
fd->secret->state = _PR_FILEDESC_CLOSED;
251
} /* PR_DestroySocketPollFd */
253
static PRStatus PR_CALLBACK SocketConnect(
254
PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
256
PRInt32 rv; /* Return value of _PR_MD_CONNECT */
257
const PRNetAddr *addrp = addr;
258
#if defined(_PR_INET6)
261
PRThread *me = _PR_MD_CURRENT_THREAD();
263
if (_PR_PENDING_INTERRUPT(me)) {
264
me->flags &= ~_PR_INTERRUPT;
265
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
268
#if defined(_PR_INET6)
269
if (addr->raw.family == PR_AF_INET6) {
271
addrCopy.raw.family = AF_INET6;
276
rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
277
PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
284
static PRStatus PR_CALLBACK SocketConnectContinue(
285
PRFileDesc *fd, PRInt16 out_flags)
290
if (out_flags & PR_POLL_NVAL) {
291
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
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);
300
osfd = fd->secret->md.osfd;
304
err = _MD_unix_get_nonblocking_connect_error(osfd);
306
_PR_MD_MAP_CONNECT_ERROR(err);
311
#elif defined(WIN32) || defined(WIN16)
315
* The sleep circumvents a bug in Win32 WinSock.
316
* See Microsoft Knowledge Base article ID: Q165989.
321
if (out_flags & PR_POLL_EXCEPT) {
322
int len = sizeof(err);
323
if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
325
_PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
329
_PR_MD_MAP_CONNECT_ERROR(err);
331
PR_SetError(PR_UNKNOWN_ERROR, 0);
336
PR_ASSERT(out_flags & PR_POLL_WRITE);
339
#elif defined(XP_OS2)
341
err = _MD_os2_get_nonblocking_connect_error(osfd);
343
_PR_MD_MAP_CONNECT_ERROR(err);
348
#elif defined(XP_MAC)
350
err = _MD_mac_get_nonblocking_connect_error(fd);
356
#elif defined(XP_BEOS)
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);
364
PR_ASSERT(out_flags & PR_POLL_WRITE);
367
err = _MD_beos_get_nonblocking_connect_error(fd);
369
_PR_MD_MAP_CONNECT_ERROR(err);
374
#endif /* BONE_VERSION */
377
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
382
PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
384
/* Find the NSPR layer and invoke its connectcontinue method */
385
PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
387
if (NULL == bottom) {
388
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
391
return SocketConnectContinue(bottom, pd->out_flags);
394
static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
395
PRIntervalTime timeout)
400
PRThread *me = _PR_MD_CURRENT_THREAD();
405
if (_PR_PENDING_INTERRUPT(me)) {
406
me->flags &= ~_PR_INTERRUPT;
407
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
410
if (_PR_IO_PENDING(me)) {
411
PR_SetError(PR_IO_PENDING_ERROR, 0);
420
al = sizeof(PRNetAddr);
421
osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
425
fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
427
_PR_MD_CLOSE_SOCKET(osfd);
431
fd2->secret->nonblocking = fd->secret->nonblocking;
432
fd2->secret->inheritable = fd->secret->inheritable;
434
if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
436
* The new socket has been associated with an I/O
437
* completion port. There is no going back.
439
fd2->secret->md.io_model_committed = PR_TRUE;
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);
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
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
458
#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
459
_PR_MD_MAKE_NONBLOCK(fd2);
463
if (addr && (AF_INET6 == addr->raw.family))
464
addr->raw.family = PR_AF_INET6;
466
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
467
PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
473
PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
474
PRIntervalTime timeout)
479
PRThread *me = _PR_MD_CURRENT_THREAD();
482
if (_PR_PENDING_INTERRUPT(me)) {
483
me->flags &= ~_PR_INTERRUPT;
484
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
487
if (_PR_IO_PENDING(me)) {
488
PR_SetError(PR_IO_PENDING_ERROR, 0);
495
al = PR_NETADDR_SIZE(addr);
496
osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
501
fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
503
_PR_MD_CLOSE_SOCKET(osfd);
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);
511
if (AF_INET6 == addr->raw.family)
512
addr->raw.family = PR_AF_INET6;
520
static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
523
const PRNetAddr *addrp = addr;
524
#if defined(_PR_INET6)
528
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
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);
540
#if defined(_PR_INET6)
541
if (addr->raw.family == PR_AF_INET6) {
543
addrCopy.raw.family = AF_INET6;
547
result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
554
static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
558
result = _PR_MD_LISTEN(fd, backlog);
565
static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
569
result = _PR_MD_SHUTDOWN(fd, how);
576
static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
577
PRIntervalTime timeout)
580
PRThread *me = _PR_MD_CURRENT_THREAD();
582
if ((flags != 0) && (flags != PR_MSG_PEEK)) {
583
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
586
if (_PR_PENDING_INTERRUPT(me)) {
587
me->flags &= ~_PR_INTERRUPT;
588
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
591
if (_PR_IO_PENDING(me)) {
592
PR_SetError(PR_IO_PENDING_ERROR, 0);
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));
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);
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);
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;
623
if (fd->secret->peekBufSize < amount) {
624
if (fd->secret->peekBuffer) {
625
PR_Free(fd->secret->peekBuffer);
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);
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()));
642
#ifdef _PR_HAVE_PEEK_BUFFER
643
if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
645
memcpy(fd->secret->peekBuffer, buf, rv);
646
fd->secret->peekBytes = rv;
654
static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
656
return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
659
static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
660
PRIntn flags, PRIntervalTime timeout)
663
PRThread *me = _PR_MD_CURRENT_THREAD();
665
if (_PR_PENDING_INTERRUPT(me)) {
666
me->flags &= ~_PR_INTERRUPT;
667
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
670
if (_PR_IO_PENDING(me)) {
671
PR_SetError(PR_IO_PENDING_ERROR, 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);
687
if (fd->secret->nonblocking) {
690
buf = (const void*) ((const char*)buf + temp);
694
PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
698
static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
700
return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
703
static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
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);
712
if (fd->secret->state == _PR_FILEDESC_OPEN) {
713
if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
716
fd->secret->state = _PR_FILEDESC_CLOSED;
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;
732
static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
735
#ifdef _PR_HAVE_PEEK_BUFFER
736
if (fd->secret->peekBytes != 0) {
737
return fd->secret->peekBytes;
740
rv = _PR_MD_SOCKETAVAILABLE(fd);
744
static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
747
#ifdef _PR_HAVE_PEEK_BUFFER
748
if (fd->secret->peekBytes != 0) {
749
LL_I2L(rv, fd->secret->peekBytes);
753
LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
757
static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
766
static PRInt32 PR_CALLBACK SocketSendTo(
767
PRFileDesc *fd, const void *buf, PRInt32 amount,
768
PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
771
const PRNetAddr *addrp = addr;
772
#if defined(_PR_INET6)
775
PRThread *me = _PR_MD_CURRENT_THREAD();
777
if (_PR_PENDING_INTERRUPT(me)) {
778
me->flags &= ~_PR_INTERRUPT;
779
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
782
if (_PR_IO_PENDING(me)) {
783
PR_SetError(PR_IO_PENDING_ERROR, 0);
787
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
788
#if defined(_PR_INET6)
789
if (addr->raw.family == PR_AF_INET6) {
791
addrCopy.raw.family = AF_INET6;
798
temp = _PR_MD_SENDTO(fd, buf, amount, flags,
799
addrp, PR_NETADDR_SIZE(addr), timeout);
805
if (fd->secret->nonblocking) {
808
buf = (const void*) ((const char*)buf + temp);
814
static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
815
PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
819
PRThread *me = _PR_MD_CURRENT_THREAD();
821
if (_PR_PENDING_INTERRUPT(me)) {
822
me->flags &= ~_PR_INTERRUPT;
823
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
826
if (_PR_IO_PENDING(me)) {
827
PR_SetError(PR_IO_PENDING_ERROR, 0);
831
al = sizeof(PRNetAddr);
832
rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
834
if (addr && (AF_INET6 == addr->raw.family))
835
addr->raw.family = PR_AF_INET6;
840
static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd,
841
PRNetAddr **raddr, void *buf, PRInt32 amount,
842
PRIntervalTime timeout)
845
PRThread *me = _PR_MD_CURRENT_THREAD();
847
if (_PR_PENDING_INTERRUPT(me)) {
848
me->flags &= ~_PR_INTERRUPT;
849
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
852
if (_PR_IO_PENDING(me)) {
853
PR_SetError(PR_IO_PENDING_ERROR, 0);
856
/* The socket must be in blocking mode. */
857
if (sd->secret->nonblocking) {
858
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
866
PRNetAddr *raddrCopy;
871
rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
875
/* Successfully accepted and read; create the new PRFileDesc */
876
*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
878
_PR_MD_CLOSE_SOCKET(newSock);
879
/* PR_AllocFileDesc() has invoked PR_SetError(). */
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));
887
if (AF_INET6 == *raddr->raw.family)
888
*raddr->raw.family = PR_AF_INET6;
894
rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
900
PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
901
PRNetAddr **raddr, void *buf, PRInt32 amount,
902
PRIntervalTime timeout)
906
PRThread *me = _PR_MD_CURRENT_THREAD();
907
PRNetAddr *raddrCopy;
909
if (_PR_PENDING_INTERRUPT(me)) {
910
me->flags &= ~_PR_INTERRUPT;
911
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
914
if (_PR_IO_PENDING(me)) {
915
PR_SetError(PR_IO_PENDING_ERROR, 0);
923
rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
924
timeout, PR_TRUE, NULL, NULL);
928
/* Successfully accepted and read; create the new PRFileDesc */
929
*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
931
_PR_MD_CLOSE_SOCKET(newSock);
932
/* PR_AllocFileDesc() has invoked PR_SetError(). */
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));
940
if (AF_INET6 == *raddr->raw.family)
941
*raddr->raw.family = PR_AF_INET6;
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,
957
PRThread *me = _PR_MD_CURRENT_THREAD();
958
PRNetAddr *raddrCopy;
960
if (_PR_PENDING_INTERRUPT(me)) {
961
me->flags &= ~_PR_INTERRUPT;
962
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
965
if (_PR_IO_PENDING(me)) {
966
PR_SetError(PR_IO_PENDING_ERROR, 0);
974
rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
975
timeout, PR_TRUE, callback, callbackArg);
979
/* Successfully accepted and read; create the new PRFileDesc */
980
*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
982
_PR_MD_CLOSE_SOCKET(newSock);
983
/* PR_AllocFileDesc() has invoked PR_SetError(). */
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));
991
if (AF_INET6 == *raddr->raw.family)
992
*raddr->raw.family = PR_AF_INET6;
1002
PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
1004
_PR_MD_UPDATE_ACCEPT_CONTEXT(
1005
socket->secret->md.osfd, acceptSocket->secret->md.osfd);
1009
static PRInt32 PR_CALLBACK SocketSendFile(
1010
PRFileDesc *sd, PRSendFileData *sfd,
1011
PRTransmitFileFlags flags, PRIntervalTime timeout)
1014
PRThread *me = _PR_MD_CURRENT_THREAD();
1016
if (_PR_PENDING_INTERRUPT(me)) {
1017
me->flags &= ~_PR_INTERRUPT;
1018
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
1021
if (_PR_IO_PENDING(me)) {
1022
PR_SetError(PR_IO_PENDING_ERROR, 0);
1025
/* The socket must be in blocking mode. */
1026
if (sd->secret->nonblocking) {
1027
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1031
rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
1032
if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
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.
1038
PR_FreeFileDesc(sd);
1041
rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
1047
static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd,
1048
const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
1049
PRIntervalTime timeout)
1054
sfd.file_offset = 0;
1055
sfd.file_nbytes = 0;
1056
sfd.header = headers;
1061
return(SocketSendFile(sd, &sfd, flags, timeout));
1064
static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
1069
addrlen = sizeof(PRNetAddr);
1070
result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
1075
if (AF_INET6 == addr->raw.family)
1076
addr->raw.family = PR_AF_INET6;
1078
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1079
PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
1083
static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
1088
addrlen = sizeof(PRNetAddr);
1089
result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
1094
if (AF_INET6 == addr->raw.family)
1095
addr->raw.family = PR_AF_INET6;
1097
PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1098
PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
1102
static PRInt16 PR_CALLBACK SocketPoll(
1103
PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
1106
#pragma unused( fd, in_flags )
1112
static PRIOMethods tcpMethods = {
1120
(PRSeekFN)_PR_InvalidInt,
1121
(PRSeek64FN)_PR_InvalidInt64,
1122
(PRFileInfoFN)_PR_InvalidStatus,
1123
(PRFileInfo64FN)_PR_InvalidStatus,
1132
(PRRecvfromFN)_PR_InvalidInt,
1133
(PRSendtoFN)_PR_InvalidInt,
1139
(PRReservedFN)_PR_InvalidInt,
1140
(PRReservedFN)_PR_InvalidInt,
1141
_PR_SocketGetSocketOption,
1142
_PR_SocketSetSocketOption,
1144
SocketConnectContinue,
1145
(PRReservedFN)_PR_InvalidInt,
1146
(PRReservedFN)_PR_InvalidInt,
1147
(PRReservedFN)_PR_InvalidInt,
1148
(PRReservedFN)_PR_InvalidInt
1151
static PRIOMethods udpMethods = {
1159
(PRSeekFN)_PR_InvalidInt,
1160
(PRSeek64FN)_PR_InvalidInt64,
1161
(PRFileInfoFN)_PR_InvalidStatus,
1162
(PRFileInfo64FN)_PR_InvalidStatus,
1165
(PRAcceptFN)_PR_InvalidDesc,
1174
(PRAcceptreadFN)_PR_InvalidInt,
1175
(PRTransmitfileFN)_PR_InvalidInt,
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
1191
static PRIOMethods socketpollfdMethods = {
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,
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
1230
PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
1235
PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
1240
static const PRIOMethods* PR_GetSocketPollFdMethods()
1242
return &socketpollfdMethods;
1243
} /* PR_GetSocketPollFdMethods */
1245
#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
1246
PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
1248
#if defined(_PR_INET6_PROBE)
1250
PR_EXTERN(PRBool) _pr_ipv6_is_present;
1252
PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
1256
osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
1258
_PR_MD_CLOSE_SOCKET(osfd);
1263
#endif /* _PR_INET6_PROBE */
1267
PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
1271
PRInt32 tmp_domain = domain;
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
1280
PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
1284
#if defined(_PR_INET6_PROBE)
1285
if (PR_AF_INET6 == domain) {
1286
if (_pr_ipv6_is_present == PR_FALSE)
1291
#elif defined(_PR_INET6)
1292
if (PR_AF_INET6 == domain)
1295
if (PR_AF_INET6 == domain)
1297
#endif /* _PR_INET6 */
1298
osfd = _PR_MD_SOCKET(domain, type, proto);
1302
if (type == SOCK_STREAM)
1303
fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
1305
fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
1307
* Make the sockets non-blocking
1310
_PR_MD_MAKE_NONBLOCK(fd);
1311
_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
1312
#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
1314
* For platforms with no support for IPv6
1315
* create layered socket for IPv4-mapped IPv6 addresses
1317
if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
1318
if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
1325
_PR_MD_CLOSE_SOCKET(osfd);
1330
PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
1332
PRInt32 domain = AF_INET;
1334
return PR_Socket(domain, SOCK_STREAM, 0);
1337
PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
1339
PRInt32 domain = AF_INET;
1341
return PR_Socket(domain, SOCK_DGRAM, 0);
1344
PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
1346
return PR_Socket(af, SOCK_STREAM, 0);
1349
PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
1351
return PR_Socket(af, SOCK_DGRAM, 0);
1354
PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
1357
PRInt32 rv, osfd[2];
1359
if (!_pr_initialized) _PR_ImplicitInitialization();
1361
rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
1366
f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
1368
_PR_MD_CLOSE_SOCKET(osfd[0]);
1369
_PR_MD_CLOSE_SOCKET(osfd[1]);
1370
/* PR_AllocFileDesc() has invoked PR_SetError(). */
1373
f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
1376
_PR_MD_CLOSE_SOCKET(osfd[1]);
1377
/* PR_AllocFileDesc() has invoked PR_SetError(). */
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);
1385
#elif defined(WINNT)
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
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.
1398
struct sockaddr_in selfAddr, peerAddr;
1401
if (!_pr_initialized) _PR_ImplicitInitialization();
1403
osfd[0] = osfd[1] = INVALID_SOCKET;
1404
listenSock = socket(AF_INET, SOCK_STREAM, 0);
1405
if (listenSock == INVALID_SOCKET) {
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) {
1416
if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
1417
&addrLen) == SOCKET_ERROR) {
1420
if (listen(listenSock, 5) == SOCKET_ERROR) {
1423
osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
1424
if (osfd[0] == INVALID_SOCKET) {
1427
selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
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.
1438
if (connect(osfd[0], (struct sockaddr *) &selfAddr,
1439
addrLen) == SOCKET_ERROR) {
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].
1447
if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
1448
&addrLen) == SOCKET_ERROR) {
1451
osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
1452
if (osfd[1] == INVALID_SOCKET) {
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);
1460
closesocket(listenSock);
1462
f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
1464
closesocket(osfd[0]);
1465
closesocket(osfd[1]);
1466
/* PR_AllocFileDesc() has invoked PR_SetError(). */
1469
f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
1472
closesocket(osfd[1]);
1473
/* PR_AllocFileDesc() has invoked PR_SetError(). */
1476
_PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
1477
_PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
1481
if (listenSock != INVALID_SOCKET) {
1482
closesocket(listenSock);
1484
if (osfd[0] != INVALID_SOCKET) {
1485
closesocket(osfd[0]);
1487
if (osfd[1] != INVALID_SOCKET) {
1488
closesocket(osfd[1]);
1491
#else /* not Unix or NT */
1493
* default implementation
1495
PRFileDesc *listenSock;
1496
PRNetAddr selfAddr, peerAddr;
1500
listenSock = PR_NewTCPSocket();
1501
if (listenSock == NULL) {
1504
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
1505
if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
1508
if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
1511
port = ntohs(selfAddr.inet.port);
1512
if (PR_Listen(listenSock, 5) == PR_FAILURE) {
1515
f[0] = PR_NewTCPSocket();
1519
#ifdef _PR_CONNECT_DOES_NOT_BIND
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.
1525
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
1526
if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
1530
PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
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.
1541
if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
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].
1550
if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
1553
f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
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);
1562
PR_Close(listenSock);
1567
PR_Close(listenSock);
1579
PR_IMPLEMENT(PRInt32)
1580
PR_FileDesc2NativeHandle(PRFileDesc *fd)
1583
fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
1586
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1589
return fd->secret->md.osfd;
1593
PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
1596
fd->secret->md.osfd = handle;
1600
** Select compatibility
1604
PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
1606
memset(set, 0, sizeof(PR_fd_set));
1609
PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
1611
PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
1613
set->harray[set->hsize++] = fh;
1616
PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
1618
PRUint32 index, index2;
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];
1630
PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
1633
for (index = 0; index<set->hsize; index++)
1634
if (set->harray[index] == fh) {
1640
PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
1642
PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
1644
set->narray[set->nsize++] = fd;
1647
PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
1649
PRUint32 index, index2;
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];
1661
PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
1664
for (index = 0; index<set->nsize; index++)
1665
if (set->narray[index] == fd) {
1672
#if !defined(NEED_SELECT)
1673
#if !defined(XP_MAC)
1674
#include "obsolete/probslet.h"
1676
#include "probslet.h"
1681
static PRPollDesc *_pr_setfd(
1682
PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
1684
PRUintn fsidx, pdidx;
1685
PRPollDesc *poll = polldesc;
1687
if (NULL == set) return poll;
1689
/* First set the pr file handle osfds */
1690
for (fsidx = 0; fsidx < set->hsize; fsidx++)
1692
for (pdidx = 0; 1; pdidx++)
1694
if ((PRFileDesc*)-1 == poll[pdidx].fd)
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;
1701
poll + pdidx * sizeof(PRPollDesc),
1702
0, PD_INCR * sizeof(PRPollDesc));
1703
poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
1705
if ((NULL == poll[pdidx].fd)
1706
|| (poll[pdidx].fd == set->harray[fsidx]))
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 */
1718
/* Second set the native osfds */
1719
for (fsidx = 0; fsidx < set->nsize; fsidx++)
1721
for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
1723
if ((PRFileDesc*)-1 == poll[pdidx].fd)
1725
/* our vector is full - extend and condition it */
1727
poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
1728
if (NULL == poll) goto out_of_memory;
1730
poll + pdidx * sizeof(PRPollDesc),
1731
0, PD_INCR * sizeof(PRPollDesc));
1732
poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
1734
if ((NULL == poll[pdidx].fd)
1735
|| (poll[pdidx].fd == set->narray[fsidx]))
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;
1750
if (NULL != polldesc) PR_DELETE(polldesc);
1754
#endif /* !defined(NEED_SELECT) */
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)
1761
#if !defined(NEED_SELECT)
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().
1769
PRPollDesc *copy, *poll;
1771
static PRBool warning = PR_TRUE;
1772
if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
1774
/* try to get an initial guesss at how much space we need */
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;
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;
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;
1800
while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
1805
PR_ASSERT(unused > 0);
1806
npds = PR_Poll(poll, unused, timeout);
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)
1816
if (copy->out_flags & PR_POLL_NVAL)
1818
PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
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;
1834
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
1837
#endif /* !defined(NEED_SELECT) */