1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 # ifndef SO_UPDATE_CONNECT_CONTEXT
12 # define SO_UPDATE_CONNECT_CONTEXT 0x7010
16 /************************************************************************/
18 /* These two functions are only used in assertions. */
21 PRBool
IsValidNetAddr(const PRNetAddr
* addr
) {
24 && (addr
->raw
.family
!= PR_AF_LOCAL
)
26 && (addr
->raw
.family
!= PR_AF_INET6
) &&
27 (addr
->raw
.family
!= PR_AF_INET
)) {
33 static PRBool
IsValidNetAddrLen(const PRNetAddr
* addr
, PRInt32 addr_len
) {
35 * The definition of the length of a Unix domain socket address
36 * is not uniform, so we don't check it.
40 && (addr
->raw
.family
!= AF_UNIX
)
42 && (PR_NETADDR_SIZE(addr
) != addr_len
)) {
43 # if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
45 * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2
46 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
47 * field and is 28 bytes. It is possible for socket functions
48 * to return an addr_len greater than sizeof(struct sockaddr_in6).
49 * We need to allow that. (Bugzilla bug #77264)
51 if ((PR_AF_INET6
== addr
->raw
.family
) && (sizeof(addr
->ipv6
) == addr_len
)) {
56 * The accept(), getsockname(), etc. calls on some platforms
57 * do not set the actual socket address length on return.
58 * In this case, we verifiy addr_len is still the value we
59 * passed in (i.e., sizeof(PRNetAddr)).
62 if (sizeof(PRNetAddr
) == addr_len
) {
73 static PRInt32 PR_CALLBACK
SocketWritev(PRFileDesc
* fd
, const PRIOVec
* iov
,
75 PRIntervalTime timeout
) {
76 PRThread
* me
= _PR_MD_CURRENT_THREAD();
78 const PRIOVec
* tmp_iov
;
79 #define LOCAL_MAXIOV 8
80 PRIOVec local_iov
[LOCAL_MAXIOV
];
81 PRIOVec
* iov_copy
= NULL
;
84 int count
= 0, sz
= 0; /* 'count' is the return value. */
86 if (_PR_PENDING_INTERRUPT(me
)) {
87 me
->flags
&= ~_PR_INTERRUPT
;
88 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
91 if (_PR_IO_PENDING(me
)) {
92 PR_SetError(PR_IO_PENDING_ERROR
, 0);
97 * Assume the first writev will succeed. Copy iov's only on
101 for (index
= 0; index
< iov_size
; index
++) {
102 sz
+= iov
[index
].iov_len
;
108 w
= _PR_MD_WRITEV(fd
, tmp_iov
, iov_cnt
, timeout
);
114 if (fd
->secret
->nonblocking
) {
120 /* find the next unwritten vector */
121 for (index
= 0, tmp_out
= count
; tmp_out
>= iov
[index
].iov_len
;
122 tmp_out
-= iov
[index
].iov_len
, index
++) {
124 } /* nothing to execute */
126 if (tmp_iov
== iov
) {
128 * The first writev failed so we
129 * must copy iov's around.
130 * Avoid calloc/free if there
131 * are few enough iov's.
133 if (iov_size
- index
<= LOCAL_MAXIOV
) {
134 iov_copy
= local_iov
;
135 } else if ((iov_copy
= (PRIOVec
*)PR_CALLOC((iov_size
- index
) *
136 sizeof *iov_copy
)) == NULL
) {
137 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
143 PR_ASSERT(tmp_iov
== iov_copy
);
145 /* fill in the first partial read */
146 iov_copy
[0].iov_base
= &(((char*)iov
[index
].iov_base
)[tmp_out
]);
147 iov_copy
[0].iov_len
= iov
[index
].iov_len
- tmp_out
;
150 /* copy the remaining vectors */
151 for (iov_cnt
= 1; index
< iov_size
; iov_cnt
++, index
++) {
152 iov_copy
[iov_cnt
].iov_base
= iov
[index
].iov_base
;
153 iov_copy
[iov_cnt
].iov_len
= iov
[index
].iov_len
;
158 if (iov_copy
!= local_iov
) {
164 /************************************************************************/
166 PR_IMPLEMENT(PRFileDesc
*) PR_ImportTCPSocket(PROsfd osfd
) {
169 if (!_pr_initialized
) {
170 _PR_ImplicitInitialization();
172 fd
= PR_AllocFileDesc(osfd
, PR_GetTCPMethods());
174 _PR_MD_MAKE_NONBLOCK(fd
);
175 _PR_MD_INIT_FD_INHERITABLE(fd
, PR_TRUE
);
176 #ifdef _PR_NEED_SECRET_AF
177 /* this means we can only import IPv4 sockets here.
178 * but this is what the function in ptio.c does.
179 * We need a way to import IPv6 sockets, too.
181 fd
->secret
->af
= AF_INET
;
184 _PR_MD_CLOSE_SOCKET(osfd
);
189 PR_IMPLEMENT(PRFileDesc
*) PR_ImportUDPSocket(PROsfd osfd
) {
192 if (!_pr_initialized
) {
193 _PR_ImplicitInitialization();
195 fd
= PR_AllocFileDesc(osfd
, PR_GetUDPMethods());
197 _PR_MD_MAKE_NONBLOCK(fd
);
198 _PR_MD_INIT_FD_INHERITABLE(fd
, PR_TRUE
);
200 _PR_MD_CLOSE_SOCKET(osfd
);
205 static const PRIOMethods
* PR_GetSocketPollFdMethods(void);
207 PR_IMPLEMENT(PRFileDesc
*) PR_CreateSocketPollFd(PROsfd osfd
) {
210 if (!_pr_initialized
) {
211 _PR_ImplicitInitialization();
217 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
219 fd
->secret
->md
.osfd
= osfd
;
220 fd
->secret
->inheritable
= _PR_TRI_FALSE
;
221 fd
->secret
->state
= _PR_FILEDESC_OPEN
;
222 fd
->methods
= PR_GetSocketPollFdMethods();
226 } /* PR_CreateSocketPollFD */
228 PR_IMPLEMENT(PRStatus
) PR_DestroySocketPollFd(PRFileDesc
* fd
) {
230 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
233 fd
->secret
->state
= _PR_FILEDESC_CLOSED
;
236 } /* PR_DestroySocketPollFd */
238 static PRStatus PR_CALLBACK
SocketConnect(PRFileDesc
* fd
, const PRNetAddr
* addr
,
239 PRIntervalTime timeout
) {
240 PRInt32 rv
; /* Return value of _PR_MD_CONNECT */
241 const PRNetAddr
* addrp
= addr
;
242 #if defined(_PR_INET6)
245 PRThread
* me
= _PR_MD_CURRENT_THREAD();
247 if (_PR_PENDING_INTERRUPT(me
)) {
248 me
->flags
&= ~_PR_INTERRUPT
;
249 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
252 #if defined(_PR_INET6)
253 if (addr
->raw
.family
== PR_AF_INET6
) {
255 addrCopy
.raw
.family
= AF_INET6
;
260 rv
= _PR_MD_CONNECT(fd
, addrp
, PR_NETADDR_SIZE(addr
), timeout
);
261 PR_LOG(_pr_io_lm
, PR_LOG_MAX
, ("connect -> %d", rv
));
269 static PRStatus PR_CALLBACK
SocketConnectContinue(PRFileDesc
* fd
,
274 if (out_flags
& PR_POLL_NVAL
) {
275 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
278 if ((out_flags
& (PR_POLL_WRITE
| PR_POLL_EXCEPT
| PR_POLL_ERR
)) == 0) {
279 PR_ASSERT(out_flags
== 0);
280 PR_SetError(PR_IN_PROGRESS_ERROR
, 0);
284 osfd
= fd
->secret
->md
.osfd
;
288 err
= _MD_unix_get_nonblocking_connect_error(osfd
);
290 _PR_MD_MAP_CONNECT_ERROR(err
);
297 if (out_flags
& PR_POLL_EXCEPT
) {
298 int len
= sizeof(err
);
299 if (getsockopt(osfd
, (int)SOL_SOCKET
, SO_ERROR
, (char*)&err
, &len
) ==
301 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
305 _PR_MD_MAP_CONNECT_ERROR(err
);
308 if (fd
->secret
->overlappedActive
) {
310 if (GetOverlappedResult((HANDLE
)osfd
, &fd
->secret
->ol
, &rvSent
,
312 err
= WSAGetLastError();
314 _pr_io_lm
, PR_LOG_MIN
,
315 ("SocketConnectContinue GetOverlappedResult failed %d\n", err
));
316 if (err
!= ERROR_IO_INCOMPLETE
) {
317 _PR_MD_MAP_CONNECT_ERROR(err
);
318 fd
->secret
->overlappedActive
= PR_FALSE
;
323 PR_SetError(PR_UNKNOWN_ERROR
, 0);
326 PR_SetError(PR_UNKNOWN_ERROR
, 0);
332 PR_ASSERT(out_flags
& PR_POLL_WRITE
);
335 if (fd
->secret
->alreadyConnected
) {
336 fd
->secret
->alreadyConnected
= PR_FALSE
;
338 /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
340 * To get result we need to use GetOverlappedResult. */
341 if (fd
->secret
->overlappedActive
) {
342 PR_ASSERT(fd
->secret
->nonblocking
);
344 if (GetOverlappedResult((HANDLE
)osfd
, &fd
->secret
->ol
, &rvSent
, FALSE
) ==
346 fd
->secret
->overlappedActive
= PR_FALSE
;
347 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
348 ("SocketConnectContinue GetOverlappedResult succeeded\n"));
349 /* When ConnectEx is used, all previously set socket options and
350 * property are not enabled and to enable them
351 * SO_UPDATE_CONNECT_CONTEXT option need to be set. */
352 if (setsockopt((SOCKET
)osfd
, SOL_SOCKET
, SO_UPDATE_CONNECT_CONTEXT
, NULL
,
354 err
= WSAGetLastError();
355 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
356 ("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT "
359 _PR_MD_MAP_SETSOCKOPT_ERROR(err
);
364 err
= WSAGetLastError();
365 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
366 ("SocketConnectContinue GetOverlappedResult failed %d\n", err
));
367 if (err
!= ERROR_IO_INCOMPLETE
) {
368 _PR_MD_MAP_CONNECT_ERROR(err
);
369 fd
->secret
->overlappedActive
= PR_FALSE
;
372 PR_SetError(PR_IN_PROGRESS_ERROR
, 0);
382 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
387 PR_IMPLEMENT(PRStatus
) PR_GetConnectStatus(const PRPollDesc
* pd
) {
388 /* Find the NSPR layer and invoke its connectcontinue method */
389 PRFileDesc
* bottom
= PR_GetIdentitiesLayer(pd
->fd
, PR_NSPR_IO_LAYER
);
391 if (NULL
== bottom
) {
392 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
395 return SocketConnectContinue(bottom
, pd
->out_flags
);
398 static PRFileDesc
* PR_CALLBACK
SocketAccept(PRFileDesc
* fd
, PRNetAddr
* addr
,
399 PRIntervalTime timeout
) {
403 PRThread
* me
= _PR_MD_CURRENT_THREAD();
408 if (_PR_PENDING_INTERRUPT(me
)) {
409 me
->flags
&= ~_PR_INTERRUPT
;
410 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
413 if (_PR_IO_PENDING(me
)) {
414 PR_SetError(PR_IO_PENDING_ERROR
, 0);
423 al
= sizeof(PRNetAddr
);
424 osfd
= _PR_MD_ACCEPT(fd
, addr
, &al
, timeout
);
429 fd2
= PR_AllocFileDesc(osfd
, PR_GetTCPMethods());
431 _PR_MD_CLOSE_SOCKET(osfd
);
435 fd2
->secret
->nonblocking
= fd
->secret
->nonblocking
;
436 fd2
->secret
->inheritable
= fd
->secret
->inheritable
;
438 if (!fd2
->secret
->nonblocking
&& fd2
->secret
->inheritable
!= _PR_TRI_TRUE
) {
440 * The new socket has been associated with an I/O
441 * completion port. There is no going back.
443 fd2
->secret
->md
.io_model_committed
= PR_TRUE
;
445 PR_ASSERT(al
== PR_NETADDR_SIZE(addr
));
446 fd2
->secret
->md
.accepted_socket
= PR_TRUE
;
447 memcpy(&fd2
->secret
->md
.peer_addr
, addr
, al
);
451 * On some platforms, the new socket created by accept()
452 * inherits the nonblocking (or overlapped io) attribute
453 * of the listening socket. As an optimization, these
454 * platforms can skip the following _PR_MD_MAKE_NONBLOCK
457 #if !defined(SOLARIS) && !defined(WINNT)
458 _PR_MD_MAKE_NONBLOCK(fd2
);
462 if (addr
&& (AF_INET6
== addr
->raw
.family
)) {
463 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
*)
474 PR_NTFast_Accept(PRFileDesc
* fd
, PRNetAddr
* addr
, PRIntervalTime timeout
) {
478 PRThread
* me
= _PR_MD_CURRENT_THREAD();
481 if (_PR_PENDING_INTERRUPT(me
)) {
482 me
->flags
&= ~_PR_INTERRUPT
;
483 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
486 if (_PR_IO_PENDING(me
)) {
487 PR_SetError(PR_IO_PENDING_ERROR
, 0);
494 al
= PR_NETADDR_SIZE(addr
);
495 osfd
= _PR_MD_FAST_ACCEPT(fd
, addr
, &al
, timeout
, PR_TRUE
, NULL
, NULL
);
500 fd2
= PR_AllocFileDesc(osfd
, PR_GetTCPMethods());
502 _PR_MD_CLOSE_SOCKET(osfd
);
504 fd2
->secret
->nonblocking
= fd
->secret
->nonblocking
;
505 fd2
->secret
->md
.io_model_committed
= PR_TRUE
;
506 PR_ASSERT(al
== PR_NETADDR_SIZE(addr
));
507 fd2
->secret
->md
.accepted_socket
= PR_TRUE
;
508 memcpy(&fd2
->secret
->md
.peer_addr
, addr
, al
);
510 if (AF_INET6
== addr
->raw
.family
) {
511 addr
->raw
.family
= PR_AF_INET6
;
514 # ifdef _PR_NEED_SECRET_AF
515 fd2
->secret
->af
= fd
->secret
->af
;
522 static PRStatus PR_CALLBACK
SocketBind(PRFileDesc
* fd
, const PRNetAddr
* addr
) {
524 const PRNetAddr
* addrp
= addr
;
525 #if defined(_PR_INET6)
529 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
532 if (addr
->raw
.family
== AF_UNIX
) {
533 /* Disallow relative pathnames */
534 if (addr
->local
.path
[0] != '/') {
535 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
541 #if defined(_PR_INET6)
542 if (addr
->raw
.family
== PR_AF_INET6
) {
544 addrCopy
.raw
.family
= AF_INET6
;
548 result
= _PR_MD_BIND(fd
, addrp
, PR_NETADDR_SIZE(addr
));
555 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
) {
568 result
= _PR_MD_SHUTDOWN(fd
, how
);
575 static PRInt32 PR_CALLBACK
SocketRecv(PRFileDesc
* fd
, void* buf
, PRInt32 amount
,
576 PRIntn flags
, PRIntervalTime timeout
) {
578 PRThread
* me
= _PR_MD_CURRENT_THREAD();
580 if ((flags
!= 0) && (flags
!= PR_MSG_PEEK
)) {
581 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
584 if (_PR_PENDING_INTERRUPT(me
)) {
585 me
->flags
&= ~_PR_INTERRUPT
;
586 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
589 if (_PR_IO_PENDING(me
)) {
590 PR_SetError(PR_IO_PENDING_ERROR
, 0);
594 PR_LOG(_pr_io_lm
, PR_LOG_MAX
,
595 ("recv: fd=%p osfd=%" PR_PRIdOSFD
" buf=%p amount=%d flags=%d", fd
,
596 fd
->secret
->md
.osfd
, buf
, amount
, flags
));
598 #ifdef _PR_HAVE_PEEK_BUFFER
599 if (fd
->secret
->peekBytes
!= 0) {
600 rv
= (amount
< fd
->secret
->peekBytes
) ? amount
: fd
->secret
->peekBytes
;
601 memcpy(buf
, fd
->secret
->peekBuffer
, rv
);
603 /* consume the bytes in the peek buffer */
604 fd
->secret
->peekBytes
-= rv
;
605 if (fd
->secret
->peekBytes
!= 0) {
606 memmove(fd
->secret
->peekBuffer
, fd
->secret
->peekBuffer
+ rv
,
607 fd
->secret
->peekBytes
);
613 /* allocate peek buffer, if necessary */
614 if ((PR_MSG_PEEK
== flags
) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd
)) {
615 PR_ASSERT(0 == fd
->secret
->peekBytes
);
616 /* impose a max size on the peek buffer */
617 if (amount
> _PR_PEEK_BUFFER_MAX
) {
618 amount
= _PR_PEEK_BUFFER_MAX
;
620 if (fd
->secret
->peekBufSize
< amount
) {
621 if (fd
->secret
->peekBuffer
) {
622 PR_Free(fd
->secret
->peekBuffer
);
624 fd
->secret
->peekBufSize
= amount
;
625 fd
->secret
->peekBuffer
= PR_Malloc(amount
);
626 if (NULL
== fd
->secret
->peekBuffer
) {
627 fd
->secret
->peekBufSize
= 0;
628 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
635 rv
= _PR_MD_RECV(fd
, buf
, amount
, flags
, timeout
);
636 PR_LOG(_pr_io_lm
, PR_LOG_MAX
,
637 ("recv -> %d, error = %d, os error = %d", rv
, PR_GetError(),
640 #ifdef _PR_HAVE_PEEK_BUFFER
641 if ((PR_MSG_PEEK
== flags
) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd
)) {
643 memcpy(fd
->secret
->peekBuffer
, buf
, rv
);
644 fd
->secret
->peekBytes
= rv
;
652 static PRInt32 PR_CALLBACK
SocketRead(PRFileDesc
* fd
, void* buf
,
654 return SocketRecv(fd
, buf
, amount
, 0, PR_INTERVAL_NO_TIMEOUT
);
657 static PRInt32 PR_CALLBACK
SocketSend(PRFileDesc
* fd
, const void* buf
,
658 PRInt32 amount
, PRIntn flags
,
659 PRIntervalTime timeout
) {
661 PRThread
* me
= _PR_MD_CURRENT_THREAD();
663 if (_PR_PENDING_INTERRUPT(me
)) {
664 me
->flags
&= ~_PR_INTERRUPT
;
665 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
668 if (_PR_IO_PENDING(me
)) {
669 PR_SetError(PR_IO_PENDING_ERROR
, 0);
675 PR_LOG(_pr_io_lm
, PR_LOG_MAX
,
676 ("send: fd=%p osfd=%" PR_PRIdOSFD
" buf=%p amount=%d", fd
,
677 fd
->secret
->md
.osfd
, buf
, amount
));
678 temp
= _PR_MD_SEND(fd
, buf
, amount
, flags
, timeout
);
685 if (fd
->secret
->nonblocking
) {
688 buf
= (const void*)((const char*)buf
+ temp
);
692 PR_LOG(_pr_io_lm
, PR_LOG_MAX
, ("send -> %d", count
));
696 static PRInt32 PR_CALLBACK
SocketWrite(PRFileDesc
* fd
, const void* buf
,
698 return SocketSend(fd
, buf
, amount
, 0, PR_INTERVAL_NO_TIMEOUT
);
701 static PRStatus PR_CALLBACK
SocketClose(PRFileDesc
* fd
) {
702 if (!fd
|| !fd
->secret
||
703 (fd
->secret
->state
!= _PR_FILEDESC_OPEN
&&
704 fd
->secret
->state
!= _PR_FILEDESC_CLOSED
)) {
705 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
709 if (fd
->secret
->state
== _PR_FILEDESC_OPEN
) {
710 #if defined(_WIN64) && defined(WIN95)
711 /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
712 * input/output. Before closing such a socket we must cancelIO.
714 if (fd
->secret
->overlappedActive
) {
715 PR_ASSERT(fd
->secret
->nonblocking
);
716 if (CancelIo((HANDLE
)fd
->secret
->md
.osfd
) == TRUE
) {
717 PR_LOG(_pr_io_lm
, PR_LOG_MIN
, ("SocketClose - CancelIo succeeded\n"));
719 DWORD err
= WSAGetLastError();
720 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
721 ("SocketClose - CancelIo failed err=%x\n", err
));
725 if (GetOverlappedResult((HANDLE
)fd
->secret
->md
.osfd
, &fd
->secret
->ol
,
726 &rvSent
, FALSE
) == TRUE
) {
727 fd
->secret
->overlappedActive
= PR_FALSE
;
728 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
729 ("SocketClose GetOverlappedResult succeeded\n"));
731 DWORD err
= WSAGetLastError();
732 PR_LOG(_pr_io_lm
, PR_LOG_MIN
,
733 ("SocketClose GetOverlappedResult failed %d\n", err
));
734 if (err
!= ERROR_IO_INCOMPLETE
) {
735 _PR_MD_MAP_CONNECT_ERROR(err
);
736 fd
->secret
->overlappedActive
= PR_FALSE
;
741 if (fd
->secret
->overlappedActive
&& _fd_waiting_for_overlapped_done_lock
) {
742 // Put osfd into the list to be checked later.
743 PRFileDescList
* forWaiting
= PR_NEW(PRFileDescList
);
745 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
750 PR_Lock(_fd_waiting_for_overlapped_done_lock
);
751 forWaiting
->next
= _fd_waiting_for_overlapped_done
;
752 _fd_waiting_for_overlapped_done
= forWaiting
;
753 PR_Unlock(_fd_waiting_for_overlapped_done_lock
);
759 if (_PR_MD_CLOSE_SOCKET(fd
->secret
->md
.osfd
) < 0) {
762 fd
->secret
->state
= _PR_FILEDESC_CLOSED
;
765 #ifdef _PR_HAVE_PEEK_BUFFER
766 if (fd
->secret
->peekBuffer
) {
767 PR_ASSERT(fd
->secret
->peekBufSize
> 0);
768 PR_DELETE(fd
->secret
->peekBuffer
);
769 fd
->secret
->peekBufSize
= 0;
770 fd
->secret
->peekBytes
= 0;
778 static PRInt32 PR_CALLBACK
SocketAvailable(PRFileDesc
* fd
) {
780 #ifdef _PR_HAVE_PEEK_BUFFER
781 if (fd
->secret
->peekBytes
!= 0) {
782 return fd
->secret
->peekBytes
;
785 rv
= _PR_MD_SOCKETAVAILABLE(fd
);
789 static PRInt64 PR_CALLBACK
SocketAvailable64(PRFileDesc
* fd
) {
791 #ifdef _PR_HAVE_PEEK_BUFFER
792 if (fd
->secret
->peekBytes
!= 0) {
793 LL_I2L(rv
, fd
->secret
->peekBytes
);
797 LL_I2L(rv
, _PR_MD_SOCKETAVAILABLE(fd
));
801 static PRStatus PR_CALLBACK
SocketSync(PRFileDesc
* fd
) { return PR_SUCCESS
; }
803 static PRInt32 PR_CALLBACK
SocketSendTo(PRFileDesc
* fd
, const void* buf
,
804 PRInt32 amount
, PRIntn flags
,
805 const PRNetAddr
* addr
,
806 PRIntervalTime timeout
) {
808 const PRNetAddr
* addrp
= addr
;
809 #if defined(_PR_INET6)
812 PRThread
* me
= _PR_MD_CURRENT_THREAD();
814 if (_PR_PENDING_INTERRUPT(me
)) {
815 me
->flags
&= ~_PR_INTERRUPT
;
816 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
819 if (_PR_IO_PENDING(me
)) {
820 PR_SetError(PR_IO_PENDING_ERROR
, 0);
824 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
825 #if defined(_PR_INET6)
826 if (addr
->raw
.family
== PR_AF_INET6
) {
828 addrCopy
.raw
.family
= AF_INET6
;
835 temp
= _PR_MD_SENDTO(fd
, buf
, amount
, flags
, addrp
, PR_NETADDR_SIZE(addr
),
842 if (fd
->secret
->nonblocking
) {
845 buf
= (const void*)((const char*)buf
+ temp
);
847 } while (amount
> 0);
851 #if defined(_WIN64) && defined(WIN95)
852 static PRInt32 PR_CALLBACK
SocketTCPSendTo(PRFileDesc
* fd
, const void* buf
,
853 PRInt32 amount
, PRIntn flags
,
854 const PRNetAddr
* addr
,
855 PRIntervalTime timeout
) {
857 const PRNetAddr
* addrp
= addr
;
858 # if defined(_PR_INET6)
861 PRThread
* me
= _PR_MD_CURRENT_THREAD();
863 if (_PR_PENDING_INTERRUPT(me
)) {
864 me
->flags
&= ~_PR_INTERRUPT
;
865 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
868 if (_PR_IO_PENDING(me
)) {
869 PR_SetError(PR_IO_PENDING_ERROR
, 0);
873 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
874 # if defined(_PR_INET6)
875 if (addr
->raw
.family
== PR_AF_INET6
) {
877 addrCopy
.raw
.family
= AF_INET6
;
884 temp
= _PR_MD_TCPSENDTO(fd
, buf
, amount
, flags
, addrp
,
885 PR_NETADDR_SIZE(addr
), timeout
);
891 if (fd
->secret
->nonblocking
) {
894 buf
= (const void*)((const char*)buf
+ temp
);
901 static PRInt32 PR_CALLBACK
SocketRecvFrom(PRFileDesc
* fd
, void* buf
,
902 PRInt32 amount
, PRIntn flags
,
904 PRIntervalTime timeout
) {
907 PRThread
* me
= _PR_MD_CURRENT_THREAD();
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);
919 al
= sizeof(PRNetAddr
);
920 rv
= _PR_MD_RECVFROM(fd
, buf
, amount
, flags
, addr
, &al
, timeout
);
922 if (addr
&& (AF_INET6
== addr
->raw
.family
)) {
923 addr
->raw
.family
= PR_AF_INET6
;
929 static PRInt32 PR_CALLBACK
SocketAcceptRead(PRFileDesc
* sd
, PRFileDesc
** nd
,
930 PRNetAddr
** raddr
, void* buf
,
932 PRIntervalTime timeout
) {
934 PRThread
* me
= _PR_MD_CURRENT_THREAD();
936 if (_PR_PENDING_INTERRUPT(me
)) {
937 me
->flags
&= ~_PR_INTERRUPT
;
938 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
941 if (_PR_IO_PENDING(me
)) {
942 PR_SetError(PR_IO_PENDING_ERROR
, 0);
945 /* The socket must be in blocking mode. */
946 if (sd
->secret
->nonblocking
) {
947 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
955 PRNetAddr
* raddrCopy
;
960 rv
= _PR_MD_ACCEPT_READ(sd
, &newSock
, raddr
, buf
, amount
, timeout
);
964 /* Successfully accepted and read; create the new PRFileDesc */
965 *nd
= PR_AllocFileDesc(newSock
, PR_GetTCPMethods());
967 _PR_MD_CLOSE_SOCKET(newSock
);
968 /* PR_AllocFileDesc() has invoked PR_SetError(). */
971 (*nd
)->secret
->md
.io_model_committed
= PR_TRUE
;
972 (*nd
)->secret
->md
.accepted_socket
= PR_TRUE
;
973 memcpy(&(*nd
)->secret
->md
.peer_addr
, *raddr
, PR_NETADDR_SIZE(*raddr
));
975 if (AF_INET6
== *raddr
->raw
.family
) {
976 *raddr
->raw
.family
= PR_AF_INET6
;
983 rv
= PR_EmulateAcceptRead(sd
, nd
, raddr
, buf
, amount
, timeout
);
989 PR_IMPLEMENT(PRInt32
)
990 PR_NTFast_AcceptRead(PRFileDesc
* sd
, PRFileDesc
** nd
, PRNetAddr
** raddr
,
991 void* buf
, PRInt32 amount
, PRIntervalTime timeout
) {
994 PRThread
* me
= _PR_MD_CURRENT_THREAD();
995 PRNetAddr
* raddrCopy
;
997 if (_PR_PENDING_INTERRUPT(me
)) {
998 me
->flags
&= ~_PR_INTERRUPT
;
999 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
1002 if (_PR_IO_PENDING(me
)) {
1003 PR_SetError(PR_IO_PENDING_ERROR
, 0);
1008 if (raddr
== NULL
) {
1011 rv
= _PR_MD_FAST_ACCEPT_READ(sd
, &newSock
, raddr
, buf
, amount
, timeout
,
1012 PR_TRUE
, NULL
, NULL
);
1016 /* Successfully accepted and read; create the new PRFileDesc */
1017 *nd
= PR_AllocFileDesc(newSock
, PR_GetTCPMethods());
1019 _PR_MD_CLOSE_SOCKET(newSock
);
1020 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1023 (*nd
)->secret
->md
.io_model_committed
= PR_TRUE
;
1024 (*nd
)->secret
->md
.accepted_socket
= PR_TRUE
;
1025 memcpy(&(*nd
)->secret
->md
.peer_addr
, *raddr
, PR_NETADDR_SIZE(*raddr
));
1027 if (AF_INET6
== *raddr
->raw
.family
) {
1028 *raddr
->raw
.family
= PR_AF_INET6
;
1031 # ifdef _PR_NEED_SECRET_AF
1032 (*nd
)->secret
->af
= sd
->secret
->af
;
1039 PR_IMPLEMENT(PRInt32
)
1040 PR_NTFast_AcceptRead_WithTimeoutCallback(PRFileDesc
* sd
, PRFileDesc
** nd
,
1041 PRNetAddr
** raddr
, void* buf
,
1042 PRInt32 amount
, PRIntervalTime timeout
,
1043 _PR_AcceptTimeoutCallback callback
,
1044 void* callbackArg
) {
1047 PRThread
* me
= _PR_MD_CURRENT_THREAD();
1048 PRNetAddr
* raddrCopy
;
1050 if (_PR_PENDING_INTERRUPT(me
)) {
1051 me
->flags
&= ~_PR_INTERRUPT
;
1052 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
1055 if (_PR_IO_PENDING(me
)) {
1056 PR_SetError(PR_IO_PENDING_ERROR
, 0);
1061 if (raddr
== NULL
) {
1064 rv
= _PR_MD_FAST_ACCEPT_READ(sd
, &newSock
, raddr
, buf
, amount
, timeout
,
1065 PR_TRUE
, callback
, callbackArg
);
1069 /* Successfully accepted and read; create the new PRFileDesc */
1070 *nd
= PR_AllocFileDesc(newSock
, PR_GetTCPMethods());
1072 _PR_MD_CLOSE_SOCKET(newSock
);
1073 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1076 (*nd
)->secret
->md
.io_model_committed
= PR_TRUE
;
1077 (*nd
)->secret
->md
.accepted_socket
= PR_TRUE
;
1078 memcpy(&(*nd
)->secret
->md
.peer_addr
, *raddr
, PR_NETADDR_SIZE(*raddr
));
1080 if (AF_INET6
== *raddr
->raw
.family
) {
1081 *raddr
->raw
.family
= PR_AF_INET6
;
1084 # ifdef _PR_NEED_SECRET_AF
1085 (*nd
)->secret
->af
= sd
->secret
->af
;
1095 PR_NTFast_UpdateAcceptContext(PRFileDesc
* socket
, PRFileDesc
* acceptSocket
) {
1096 _PR_MD_UPDATE_ACCEPT_CONTEXT(socket
->secret
->md
.osfd
,
1097 acceptSocket
->secret
->md
.osfd
);
1101 static PRInt32 PR_CALLBACK
SocketSendFile(PRFileDesc
* sd
, PRSendFileData
* sfd
,
1102 PRTransmitFileFlags flags
,
1103 PRIntervalTime timeout
) {
1105 PRThread
* me
= _PR_MD_CURRENT_THREAD();
1107 if (_PR_PENDING_INTERRUPT(me
)) {
1108 me
->flags
&= ~_PR_INTERRUPT
;
1109 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
1112 if (_PR_IO_PENDING(me
)) {
1113 PR_SetError(PR_IO_PENDING_ERROR
, 0);
1116 /* The socket must be in blocking mode. */
1117 if (sd
->secret
->nonblocking
) {
1118 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1122 rv
= _PR_MD_SENDFILE(sd
, sfd
, flags
, timeout
);
1123 if ((rv
>= 0) && (flags
== PR_TRANSMITFILE_CLOSE_SOCKET
)) {
1125 * This should be kept the same as SocketClose, except
1126 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
1127 * not be called because the socket will be recycled.
1129 PR_FreeFileDesc(sd
);
1132 rv
= PR_EmulateSendFile(sd
, sfd
, flags
, timeout
);
1138 static PRInt32 PR_CALLBACK
SocketTransmitFile(PRFileDesc
* sd
, PRFileDesc
* fd
,
1139 const void* headers
, PRInt32 hlen
,
1140 PRTransmitFileFlags flags
,
1141 PRIntervalTime timeout
) {
1145 sfd
.file_offset
= 0;
1146 sfd
.file_nbytes
= 0;
1147 sfd
.header
= headers
;
1152 return (SocketSendFile(sd
, &sfd
, flags
, timeout
));
1155 static PRStatus PR_CALLBACK
SocketGetName(PRFileDesc
* fd
, PRNetAddr
* addr
) {
1159 addrlen
= sizeof(PRNetAddr
);
1160 result
= _PR_MD_GETSOCKNAME(fd
, addr
, &addrlen
);
1165 if (AF_INET6
== addr
->raw
.family
) {
1166 addr
->raw
.family
= PR_AF_INET6
;
1169 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
1170 PR_ASSERT(IsValidNetAddrLen(addr
, addrlen
) == PR_TRUE
);
1174 static PRStatus PR_CALLBACK
SocketGetPeerName(PRFileDesc
* fd
, PRNetAddr
* addr
) {
1178 addrlen
= sizeof(PRNetAddr
);
1179 result
= _PR_MD_GETPEERNAME(fd
, addr
, &addrlen
);
1184 if (AF_INET6
== addr
->raw
.family
) {
1185 addr
->raw
.family
= PR_AF_INET6
;
1188 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
1189 PR_ASSERT(IsValidNetAddrLen(addr
, addrlen
) == PR_TRUE
);
1193 static PRInt16 PR_CALLBACK
SocketPoll(PRFileDesc
* fd
, PRInt16 in_flags
,
1194 PRInt16
* out_flags
) {
1198 if (in_flags
& PR_POLL_WRITE
) {
1199 if (fd
->secret
->alreadyConnected
) {
1200 *out_flags
= PR_POLL_WRITE
;
1201 return PR_POLL_WRITE
;
1208 static PRIOMethods tcpMethods
= {
1216 (PRSeekFN
)_PR_InvalidInt
,
1217 (PRSeek64FN
)_PR_InvalidInt64
,
1218 (PRFileInfoFN
)_PR_InvalidStatus
,
1219 (PRFileInfo64FN
)_PR_InvalidStatus
,
1228 (PRRecvfromFN
)_PR_InvalidInt
,
1229 #if defined(_WIN64) && defined(WIN95)
1230 SocketTCPSendTo
, /* This is for fast open. We imitate Linux interface. */
1232 (PRSendtoFN
)_PR_InvalidInt
,
1239 (PRReservedFN
)_PR_InvalidInt
,
1240 (PRReservedFN
)_PR_InvalidInt
,
1241 _PR_SocketGetSocketOption
,
1242 _PR_SocketSetSocketOption
,
1244 SocketConnectContinue
,
1245 (PRReservedFN
)_PR_InvalidInt
,
1246 (PRReservedFN
)_PR_InvalidInt
,
1247 (PRReservedFN
)_PR_InvalidInt
,
1248 (PRReservedFN
)_PR_InvalidInt
};
1250 static PRIOMethods udpMethods
= {PR_DESC_SOCKET_UDP
,
1257 (PRSeekFN
)_PR_InvalidInt
,
1258 (PRSeek64FN
)_PR_InvalidInt64
,
1259 (PRFileInfoFN
)_PR_InvalidStatus
,
1260 (PRFileInfo64FN
)_PR_InvalidStatus
,
1263 (PRAcceptFN
)_PR_InvalidDesc
,
1272 (PRAcceptreadFN
)_PR_InvalidInt
,
1273 (PRTransmitfileFN
)_PR_InvalidInt
,
1276 (PRReservedFN
)_PR_InvalidInt
,
1277 (PRReservedFN
)_PR_InvalidInt
,
1278 _PR_SocketGetSocketOption
,
1279 _PR_SocketSetSocketOption
,
1280 (PRSendfileFN
)_PR_InvalidInt
,
1281 (PRConnectcontinueFN
)_PR_InvalidStatus
,
1282 (PRReservedFN
)_PR_InvalidInt
,
1283 (PRReservedFN
)_PR_InvalidInt
,
1284 (PRReservedFN
)_PR_InvalidInt
,
1285 (PRReservedFN
)_PR_InvalidInt
};
1287 static PRIOMethods socketpollfdMethods
= {
1289 (PRCloseFN
)_PR_InvalidStatus
,
1290 (PRReadFN
)_PR_InvalidInt
,
1291 (PRWriteFN
)_PR_InvalidInt
,
1292 (PRAvailableFN
)_PR_InvalidInt
,
1293 (PRAvailable64FN
)_PR_InvalidInt64
,
1294 (PRFsyncFN
)_PR_InvalidStatus
,
1295 (PRSeekFN
)_PR_InvalidInt
,
1296 (PRSeek64FN
)_PR_InvalidInt64
,
1297 (PRFileInfoFN
)_PR_InvalidStatus
,
1298 (PRFileInfo64FN
)_PR_InvalidStatus
,
1299 (PRWritevFN
)_PR_InvalidInt
,
1300 (PRConnectFN
)_PR_InvalidStatus
,
1301 (PRAcceptFN
)_PR_InvalidDesc
,
1302 (PRBindFN
)_PR_InvalidStatus
,
1303 (PRListenFN
)_PR_InvalidStatus
,
1304 (PRShutdownFN
)_PR_InvalidStatus
,
1305 (PRRecvFN
)_PR_InvalidInt
,
1306 (PRSendFN
)_PR_InvalidInt
,
1307 (PRRecvfromFN
)_PR_InvalidInt
,
1308 (PRSendtoFN
)_PR_InvalidInt
,
1310 (PRAcceptreadFN
)_PR_InvalidInt
,
1311 (PRTransmitfileFN
)_PR_InvalidInt
,
1312 (PRGetsocknameFN
)_PR_InvalidStatus
,
1313 (PRGetpeernameFN
)_PR_InvalidStatus
,
1314 (PRReservedFN
)_PR_InvalidInt
,
1315 (PRReservedFN
)_PR_InvalidInt
,
1316 (PRGetsocketoptionFN
)_PR_InvalidStatus
,
1317 (PRSetsocketoptionFN
)_PR_InvalidStatus
,
1318 (PRSendfileFN
)_PR_InvalidInt
,
1319 (PRConnectcontinueFN
)_PR_InvalidStatus
,
1320 (PRReservedFN
)_PR_InvalidInt
,
1321 (PRReservedFN
)_PR_InvalidInt
,
1322 (PRReservedFN
)_PR_InvalidInt
,
1323 (PRReservedFN
)_PR_InvalidInt
};
1325 PR_IMPLEMENT(const PRIOMethods
*) PR_GetTCPMethods() { return &tcpMethods
; }
1327 PR_IMPLEMENT(const PRIOMethods
*) PR_GetUDPMethods() { return &udpMethods
; }
1329 static const PRIOMethods
* PR_GetSocketPollFdMethods() {
1330 return &socketpollfdMethods
;
1331 } /* PR_GetSocketPollFdMethods */
1333 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
1334 PR_EXTERN(PRStatus
) _pr_push_ipv6toipv4_layer(PRFileDesc
* fd
);
1336 # if defined(_PR_INET6_PROBE)
1338 extern PRBool
_pr_ipv6_is_present(void);
1340 PR_IMPLEMENT(PRBool
) _pr_test_ipv6_socket() {
1343 osfd
= _PR_MD_SOCKET(AF_INET6
, SOCK_STREAM
, 0);
1345 _PR_MD_CLOSE_SOCKET(osfd
);
1350 # endif /* _PR_INET6_PROBE */
1354 PR_IMPLEMENT(PRFileDesc
*)
1355 PR_Socket(PRInt32 domain
, PRInt32 type
, PRInt32 proto
) {
1358 PRInt32 tmp_domain
= domain
;
1360 if (!_pr_initialized
) {
1361 _PR_ImplicitInitialization();
1363 if (PR_AF_INET
!= domain
&& PR_AF_INET6
!= domain
1364 #if defined(XP_UNIX)
1365 && PR_AF_LOCAL
!= domain
1368 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR
, 0);
1372 #if defined(_PR_INET6_PROBE)
1373 if (PR_AF_INET6
== domain
) {
1374 domain
= _pr_ipv6_is_present() ? AF_INET6
: AF_INET
;
1376 #elif defined(_PR_INET6)
1377 if (PR_AF_INET6
== domain
) {
1381 if (PR_AF_INET6
== domain
) {
1384 #endif /* _PR_INET6 */
1385 osfd
= _PR_MD_SOCKET(domain
, type
, proto
);
1389 if (type
== SOCK_STREAM
) {
1390 fd
= PR_AllocFileDesc(osfd
, PR_GetTCPMethods());
1392 fd
= PR_AllocFileDesc(osfd
, PR_GetUDPMethods());
1395 * Make the sockets non-blocking
1398 _PR_MD_MAKE_NONBLOCK(fd
);
1399 _PR_MD_INIT_FD_INHERITABLE(fd
, PR_FALSE
);
1400 #ifdef _PR_NEED_SECRET_AF
1401 fd
->secret
->af
= domain
;
1403 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
1405 * For platforms with no support for IPv6
1406 * create layered socket for IPv4-mapped IPv6 addresses
1408 if (PR_AF_INET6
== tmp_domain
&& PR_AF_INET
== domain
) {
1409 if (PR_FAILURE
== _pr_push_ipv6toipv4_layer(fd
)) {
1416 _PR_MD_CLOSE_SOCKET(osfd
);
1422 PR_IMPLEMENT(PRFileDesc
*) PR_NewTCPSocket(void) {
1423 PRInt32 domain
= AF_INET
;
1425 return PR_Socket(domain
, SOCK_STREAM
, 0);
1428 PR_IMPLEMENT(PRFileDesc
*) PR_NewUDPSocket(void) {
1429 PRInt32 domain
= AF_INET
;
1431 return PR_Socket(domain
, SOCK_DGRAM
, 0);
1434 PR_IMPLEMENT(PRFileDesc
*) PR_OpenTCPSocket(PRIntn af
) {
1435 return PR_Socket(af
, SOCK_STREAM
, 0);
1438 PR_IMPLEMENT(PRFileDesc
*) PR_OpenUDPSocket(PRIntn af
) {
1439 return PR_Socket(af
, SOCK_DGRAM
, 0);
1442 PR_IMPLEMENT(PRStatus
) PR_NewTCPSocketPair(PRFileDesc
* f
[]) {
1444 PRInt32 rv
, osfd
[2];
1446 if (!_pr_initialized
) {
1447 _PR_ImplicitInitialization();
1450 rv
= _PR_MD_SOCKETPAIR(AF_UNIX
, SOCK_STREAM
, 0, osfd
);
1455 f
[0] = PR_AllocFileDesc(osfd
[0], PR_GetTCPMethods());
1457 _PR_MD_CLOSE_SOCKET(osfd
[0]);
1458 _PR_MD_CLOSE_SOCKET(osfd
[1]);
1459 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1462 f
[1] = PR_AllocFileDesc(osfd
[1], PR_GetTCPMethods());
1465 _PR_MD_CLOSE_SOCKET(osfd
[1]);
1466 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1469 _PR_MD_MAKE_NONBLOCK(f
[0]);
1470 _PR_MD_INIT_FD_INHERITABLE(f
[0], PR_FALSE
);
1471 _PR_MD_MAKE_NONBLOCK(f
[1]);
1472 _PR_MD_INIT_FD_INHERITABLE(f
[1], PR_FALSE
);
1474 #elif defined(WINNT)
1476 * A socket pair is often used for interprocess communication,
1477 * so we need to make sure neither socket is associated with
1478 * the I/O completion port; otherwise it can't be used by a
1481 * The default implementation below cannot be used for NT
1482 * because PR_Accept would have associated the I/O completion
1483 * port with the listening and accepted sockets.
1487 struct sockaddr_in selfAddr
, peerAddr
;
1490 if (!_pr_initialized
) {
1491 _PR_ImplicitInitialization();
1494 osfd
[0] = osfd
[1] = INVALID_SOCKET
;
1495 listenSock
= socket(AF_INET
, SOCK_STREAM
, 0);
1496 if (listenSock
== INVALID_SOCKET
) {
1499 selfAddr
.sin_family
= AF_INET
;
1500 selfAddr
.sin_port
= 0;
1501 selfAddr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
); /* BugZilla: 35408 */
1502 addrLen
= sizeof(selfAddr
);
1503 if (bind(listenSock
, (struct sockaddr
*)&selfAddr
, addrLen
) == SOCKET_ERROR
) {
1506 if (getsockname(listenSock
, (struct sockaddr
*)&selfAddr
, &addrLen
) ==
1510 if (listen(listenSock
, 5) == SOCKET_ERROR
) {
1513 osfd
[0] = socket(AF_INET
, SOCK_STREAM
, 0);
1514 if (osfd
[0] == INVALID_SOCKET
) {
1517 selfAddr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
1520 * Only a thread is used to do the connect and accept.
1521 * I am relying on the fact that connect returns
1522 * successfully as soon as the connect request is put
1523 * into the listen queue (but before accept is called).
1524 * This is the behavior of the BSD socket code. If
1525 * connect does not return until accept is called, we
1526 * will need to create another thread to call connect.
1528 if (connect(osfd
[0], (struct sockaddr
*)&selfAddr
, addrLen
) == SOCKET_ERROR
) {
1532 * A malicious local process may connect to the listening
1533 * socket, so we need to verify that the accepted connection
1534 * is made from our own socket osfd[0].
1536 if (getsockname(osfd
[0], (struct sockaddr
*)&selfAddr
, &addrLen
) ==
1540 osfd
[1] = accept(listenSock
, (struct sockaddr
*)&peerAddr
, &addrLen
);
1541 if (osfd
[1] == INVALID_SOCKET
) {
1544 if (peerAddr
.sin_port
!= selfAddr
.sin_port
) {
1545 /* the connection we accepted is not from osfd[0] */
1546 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR
, 0);
1549 closesocket(listenSock
);
1551 f
[0] = PR_AllocFileDesc(osfd
[0], PR_GetTCPMethods());
1553 closesocket(osfd
[0]);
1554 closesocket(osfd
[1]);
1555 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1558 f
[1] = PR_AllocFileDesc(osfd
[1], PR_GetTCPMethods());
1561 closesocket(osfd
[1]);
1562 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1565 _PR_MD_INIT_FD_INHERITABLE(f
[0], PR_FALSE
);
1566 _PR_MD_INIT_FD_INHERITABLE(f
[1], PR_FALSE
);
1570 if (listenSock
!= INVALID_SOCKET
) {
1571 closesocket(listenSock
);
1573 if (osfd
[0] != INVALID_SOCKET
) {
1574 closesocket(osfd
[0]);
1576 if (osfd
[1] != INVALID_SOCKET
) {
1577 closesocket(osfd
[1]);
1580 #else /* not Unix or NT */
1582 * default implementation
1584 PRFileDesc
* listenSock
;
1585 PRNetAddr selfAddr
, peerAddr
;
1589 listenSock
= PR_NewTCPSocket();
1590 if (listenSock
== NULL
) {
1593 PR_InitializeNetAddr(PR_IpAddrLoopback
, 0, &selfAddr
); /* BugZilla: 35408 */
1594 if (PR_Bind(listenSock
, &selfAddr
) == PR_FAILURE
) {
1597 if (PR_GetSockName(listenSock
, &selfAddr
) == PR_FAILURE
) {
1600 port
= ntohs(selfAddr
.inet
.port
);
1601 if (PR_Listen(listenSock
, 5) == PR_FAILURE
) {
1604 f
[0] = PR_NewTCPSocket();
1608 # ifdef _PR_CONNECT_DOES_NOT_BIND
1610 * If connect does not implicitly bind the socket (e.g., on
1611 * BeOS), we have to bind the socket so that we can get its
1612 * port with getsockname later.
1614 PR_InitializeNetAddr(PR_IpAddrLoopback
, 0, &selfAddr
);
1615 if (PR_Bind(f
[0], &selfAddr
) == PR_FAILURE
) {
1619 PR_InitializeNetAddr(PR_IpAddrLoopback
, port
, &selfAddr
);
1622 * Only a thread is used to do the connect and accept.
1623 * I am relying on the fact that PR_Connect returns
1624 * successfully as soon as the connect request is put
1625 * into the listen queue (but before PR_Accept is called).
1626 * This is the behavior of the BSD socket code. If
1627 * connect does not return until accept is called, we
1628 * will need to create another thread to call connect.
1630 if (PR_Connect(f
[0], &selfAddr
, PR_INTERVAL_NO_TIMEOUT
) == PR_FAILURE
) {
1634 * A malicious local process may connect to the listening
1635 * socket, so we need to verify that the accepted connection
1636 * is made from our own socket f[0].
1638 if (PR_GetSockName(f
[0], &selfAddr
) == PR_FAILURE
) {
1641 f
[1] = PR_Accept(listenSock
, &peerAddr
, PR_INTERVAL_NO_TIMEOUT
);
1645 if (peerAddr
.inet
.port
!= selfAddr
.inet
.port
) {
1646 /* the connection we accepted is not from f[0] */
1647 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR
, 0);
1650 PR_Close(listenSock
);
1655 PR_Close(listenSock
);
1667 PR_IMPLEMENT(PROsfd
)
1668 PR_FileDesc2NativeHandle(PRFileDesc
* fd
) {
1670 fd
= PR_GetIdentitiesLayer(fd
, PR_NSPR_IO_LAYER
);
1673 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1676 return fd
->secret
->md
.osfd
;
1680 PR_ChangeFileDescNativeHandle(PRFileDesc
* fd
, PROsfd handle
) {
1682 fd
->secret
->md
.osfd
= handle
;
1687 ** Select compatibility
1691 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set
* set
) {
1692 memset(set
, 0, sizeof(PR_fd_set
));
1695 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc
* fh
, PR_fd_set
* set
) {
1696 PR_ASSERT(set
->hsize
< PR_MAX_SELECT_DESC
);
1698 set
->harray
[set
->hsize
++] = fh
;
1701 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc
* fh
, PR_fd_set
* set
) {
1702 PRUint32 index
, index2
;
1704 for (index
= 0; index
< set
->hsize
; index
++)
1705 if (set
->harray
[index
] == fh
) {
1706 for (index2
= index
; index2
< (set
->hsize
- 1); index2
++) {
1707 set
->harray
[index2
] = set
->harray
[index2
+ 1];
1714 PR_IMPLEMENT(PRInt32
) PR_FD_ISSET(PRFileDesc
* fh
, PR_fd_set
* set
) {
1716 for (index
= 0; index
< set
->hsize
; index
++)
1717 if (set
->harray
[index
] == fh
) {
1723 PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd
, PR_fd_set
* set
) {
1724 PR_ASSERT(set
->nsize
< PR_MAX_SELECT_DESC
);
1726 set
->narray
[set
->nsize
++] = fd
;
1729 PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd
, PR_fd_set
* set
) {
1730 PRUint32 index
, index2
;
1732 for (index
= 0; index
< set
->nsize
; index
++)
1733 if (set
->narray
[index
] == fd
) {
1734 for (index2
= index
; index2
< (set
->nsize
- 1); index2
++) {
1735 set
->narray
[index2
] = set
->narray
[index2
+ 1];
1742 PR_IMPLEMENT(PRInt32
) PR_FD_NISSET(PROsfd fd
, PR_fd_set
* set
) {
1744 for (index
= 0; index
< set
->nsize
; index
++)
1745 if (set
->narray
[index
] == fd
) {
1751 #if !defined(NEED_SELECT)
1752 # include "obsolete/probslet.h"
1756 static PRPollDesc
* _pr_setfd(PR_fd_set
* set
, PRInt16 flags
,
1757 PRPollDesc
* polldesc
) {
1758 PRUintn fsidx
, pdidx
;
1759 PRPollDesc
* poll
= polldesc
;
1765 /* First set the pr file handle osfds */
1766 for (fsidx
= 0; fsidx
< set
->hsize
; fsidx
++) {
1767 for (pdidx
= 0; 1; pdidx
++) {
1768 if ((PRFileDesc
*)-1 == poll
[pdidx
].fd
) {
1769 /* our vector is full - extend and condition it */
1770 poll
= (PRPollDesc
*)PR_Realloc(
1771 poll
, (pdidx
+ 1 + PD_INCR
) * sizeof(PRPollDesc
));
1775 memset(poll
+ pdidx
* sizeof(PRPollDesc
), 0,
1776 PD_INCR
* sizeof(PRPollDesc
));
1777 poll
[pdidx
+ PD_INCR
].fd
= (PRFileDesc
*)-1;
1779 if ((NULL
== poll
[pdidx
].fd
) || (poll
[pdidx
].fd
== set
->harray
[fsidx
])) {
1780 /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
1781 /* either empty or prevously defined */
1782 poll
[pdidx
].fd
= set
->harray
[fsidx
]; /* possibly redundant */
1783 poll
[pdidx
].in_flags
|= flags
; /* possibly redundant */
1790 /* Second set the native osfds */
1791 for (fsidx
= 0; fsidx
< set
->nsize
; fsidx
++)
1793 for (pdidx
= 0; ((PRFileDesc
*)-1 != poll
[pdidx
].fd
); pdidx
++)
1795 if ((PRFileDesc
*)-1 == poll
[pdidx
].fd
)
1797 /* our vector is full - extend and condition it */
1799 poll
, (pdidx
+ PD_INCR
) * sizeof(PRPollDesc
));
1804 poll
+ pdidx
* sizeof(PRPollDesc
),
1805 0, PD_INCR
* sizeof(PRPollDesc
));
1806 poll
[(pdidx
+ PD_INCR
)].fd
= (PRFileDesc
*)-1;
1808 if ((NULL
== poll
[pdidx
].fd
)
1809 || (poll
[pdidx
].fd
== set
->narray
[fsidx
]))
1811 /* either empty or prevously defined */
1812 poll
[pdidx
].fd
= set
->narray
[fsidx
];
1813 PR_ASSERT(0 == (poll
[pdidx
].in_flags
& flags
));
1814 poll
[pdidx
].in_flags
|= flags
;
1824 if (NULL
!= polldesc
) {
1825 PR_DELETE(polldesc
);
1830 #endif /* !defined(NEED_SELECT) */
1832 PR_IMPLEMENT(PRInt32
)
1833 PR_Select(PRInt32 unused
, PR_fd_set
* pr_rd
, PR_fd_set
* pr_wr
, PR_fd_set
* pr_ex
,
1834 PRIntervalTime timeout
) {
1835 #if !defined(NEED_SELECT)
1838 ** Find out how many fds are represented in the three lists.
1839 ** Then allocate a polling descriptor for the logical union
1840 ** (there can't be any overlapping) and call PR_Poll().
1843 PRPollDesc
*copy
, *poll
;
1845 static PRBool warning
= PR_TRUE
;
1847 warning
= _PR_Obsolete("PR_Select()", "PR_Poll()");
1850 /* try to get an initial guesss at how much space we need */
1852 if ((NULL
!= pr_rd
) && ((pr_rd
->hsize
+ pr_rd
->nsize
- npds
) > 0)) {
1853 npds
= pr_rd
->hsize
+ pr_rd
->nsize
;
1855 if ((NULL
!= pr_wr
) && ((pr_wr
->hsize
+ pr_wr
->nsize
- npds
) > 0)) {
1856 npds
= pr_wr
->hsize
+ pr_wr
->nsize
;
1858 if ((NULL
!= pr_ex
) && ((pr_ex
->hsize
+ pr_ex
->nsize
- npds
) > 0)) {
1859 npds
= pr_ex
->hsize
+ pr_ex
->nsize
;
1867 copy
= poll
= (PRPollDesc
*)PR_Calloc(npds
+ PD_INCR
, sizeof(PRPollDesc
));
1871 poll
[npds
+ PD_INCR
- 1].fd
= (PRFileDesc
*)-1;
1873 poll
= _pr_setfd(pr_rd
, PR_POLL_READ
, poll
);
1877 poll
= _pr_setfd(pr_wr
, PR_POLL_WRITE
, poll
);
1881 poll
= _pr_setfd(pr_ex
, PR_POLL_EXCEPT
, poll
);
1886 while (NULL
!= poll
[unused
].fd
&& (PRFileDesc
*)-1 != poll
[unused
].fd
) {
1890 PR_ASSERT(unused
> 0);
1891 npds
= PR_Poll(poll
, unused
, timeout
);
1894 /* Copy the results back into the fd sets */
1895 if (NULL
!= pr_rd
) {
1896 pr_rd
->nsize
= pr_rd
->hsize
= 0;
1898 if (NULL
!= pr_wr
) {
1899 pr_wr
->nsize
= pr_wr
->hsize
= 0;
1901 if (NULL
!= pr_ex
) {
1902 pr_ex
->nsize
= pr_ex
->hsize
= 0;
1904 for (copy
= &poll
[unused
- 1]; copy
>= poll
; --copy
) {
1905 if (copy
->out_flags
& PR_POLL_NVAL
) {
1906 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
1910 if (copy
->out_flags
& PR_POLL_READ
)
1911 if (NULL
!= pr_rd
) {
1912 pr_rd
->harray
[pr_rd
->hsize
++] = copy
->fd
;
1914 if (copy
->out_flags
& PR_POLL_WRITE
)
1915 if (NULL
!= pr_wr
) {
1916 pr_wr
->harray
[pr_wr
->hsize
++] = copy
->fd
;
1918 if (copy
->out_flags
& PR_POLL_EXCEPT
)
1919 if (NULL
!= pr_ex
) {
1920 pr_ex
->harray
[pr_ex
->hsize
++] = copy
->fd
;
1928 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
1931 #endif /* !defined(NEED_SELECT) */