Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / nsprpub / pr / src / io / prsocket.c
blobb3a2573efdb99711d2b4396b07ed35dc575007a0
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/. */
6 #include "primpl.h"
8 #include <string.h>
10 #if defined(_WIN64)
11 # ifndef SO_UPDATE_CONNECT_CONTEXT
12 # define SO_UPDATE_CONNECT_CONTEXT 0x7010
13 # endif
14 #endif
16 /************************************************************************/
18 /* These two functions are only used in assertions. */
19 #if defined(DEBUG)
21 PRBool IsValidNetAddr(const PRNetAddr* addr) {
22 if ((addr != NULL)
23 # if defined(XP_UNIX)
24 && (addr->raw.family != PR_AF_LOCAL)
25 # endif
26 && (addr->raw.family != PR_AF_INET6) &&
27 (addr->raw.family != PR_AF_INET)) {
28 return PR_FALSE;
30 return PR_TRUE;
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.
38 if ((addr != NULL)
39 # if defined(XP_UNIX)
40 && (addr->raw.family != AF_UNIX)
41 # endif
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)) {
52 return PR_TRUE;
54 # endif
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)).
61 # if defined(QNX)
62 if (sizeof(PRNetAddr) == addr_len) {
63 return PR_TRUE;
65 # endif
66 return PR_FALSE;
68 return PR_TRUE;
71 #endif /* DEBUG */
73 static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc* fd, const PRIOVec* iov,
74 PRInt32 iov_size,
75 PRIntervalTime timeout) {
76 PRThread* me = _PR_MD_CURRENT_THREAD();
77 int w = 0;
78 const PRIOVec* tmp_iov;
79 #define LOCAL_MAXIOV 8
80 PRIOVec local_iov[LOCAL_MAXIOV];
81 PRIOVec* iov_copy = NULL;
82 int tmp_out;
83 int index, iov_cnt;
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);
89 return -1;
91 if (_PR_IO_PENDING(me)) {
92 PR_SetError(PR_IO_PENDING_ERROR, 0);
93 return -1;
97 * Assume the first writev will succeed. Copy iov's only on
98 * failure.
100 tmp_iov = iov;
101 for (index = 0; index < iov_size; index++) {
102 sz += iov[index].iov_len;
105 iov_cnt = iov_size;
107 while (sz > 0) {
108 w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
109 if (w < 0) {
110 count = -1;
111 break;
113 count += w;
114 if (fd->secret->nonblocking) {
115 break;
117 sz -= w;
119 if (sz > 0) {
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);
138 return -1;
140 tmp_iov = iov_copy;
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;
148 index++;
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) {
159 PR_DELETE(iov_copy);
161 return count;
164 /************************************************************************/
166 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PROsfd osfd) {
167 PRFileDesc* fd;
169 if (!_pr_initialized) {
170 _PR_ImplicitInitialization();
172 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
173 if (fd != NULL) {
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;
182 #endif
183 } else {
184 _PR_MD_CLOSE_SOCKET(osfd);
186 return (fd);
189 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PROsfd osfd) {
190 PRFileDesc* fd;
192 if (!_pr_initialized) {
193 _PR_ImplicitInitialization();
195 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
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);
202 return (fd);
205 static const PRIOMethods* PR_GetSocketPollFdMethods(void);
207 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd) {
208 PRFileDesc* fd;
210 if (!_pr_initialized) {
211 _PR_ImplicitInitialization();
214 fd = _PR_Getfd();
216 if (fd == NULL) {
217 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
218 } else {
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();
225 return fd;
226 } /* PR_CreateSocketPollFD */
228 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc* fd) {
229 if (NULL == fd) {
230 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
231 return PR_FAILURE;
233 fd->secret->state = _PR_FILEDESC_CLOSED;
234 _PR_Putfd(fd);
235 return PR_SUCCESS;
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)
243 PRNetAddr addrCopy;
244 #endif
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);
250 return PR_FAILURE;
252 #if defined(_PR_INET6)
253 if (addr->raw.family == PR_AF_INET6) {
254 addrCopy = *addr;
255 addrCopy.raw.family = AF_INET6;
256 addrp = &addrCopy;
258 #endif
260 rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
261 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
262 if (rv == 0) {
263 return PR_SUCCESS;
264 } else {
265 return PR_FAILURE;
269 static PRStatus PR_CALLBACK SocketConnectContinue(PRFileDesc* fd,
270 PRInt16 out_flags) {
271 PROsfd osfd;
272 int err;
274 if (out_flags & PR_POLL_NVAL) {
275 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
276 return PR_FAILURE;
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);
281 return PR_FAILURE;
284 osfd = fd->secret->md.osfd;
286 #if defined(XP_UNIX)
288 err = _MD_unix_get_nonblocking_connect_error(osfd);
289 if (err != 0) {
290 _PR_MD_MAP_CONNECT_ERROR(err);
291 return PR_FAILURE;
293 return PR_SUCCESS;
295 #elif defined(WIN32)
297 if (out_flags & PR_POLL_EXCEPT) {
298 int len = sizeof(err);
299 if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char*)&err, &len) ==
300 SOCKET_ERROR) {
301 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
302 return PR_FAILURE;
304 if (err != 0) {
305 _PR_MD_MAP_CONNECT_ERROR(err);
306 } else {
307 # if defined(_WIN64)
308 if (fd->secret->overlappedActive) {
309 PRInt32 rvSent;
310 if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent,
311 FALSE) == FALSE) {
312 err = WSAGetLastError();
313 PR_LOG(
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;
322 if (err == 0) {
323 PR_SetError(PR_UNKNOWN_ERROR, 0);
325 # else
326 PR_SetError(PR_UNKNOWN_ERROR, 0);
327 # endif
329 return PR_FAILURE;
332 PR_ASSERT(out_flags & PR_POLL_WRITE);
334 # if defined(_WIN64)
335 if (fd->secret->alreadyConnected) {
336 fd->secret->alreadyConnected = PR_FALSE;
338 /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
339 * input/output.
340 * To get result we need to use GetOverlappedResult. */
341 if (fd->secret->overlappedActive) {
342 PR_ASSERT(fd->secret->nonblocking);
343 PRInt32 rvSent;
344 if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE) ==
345 TRUE) {
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,
353 0) != 0) {
354 err = WSAGetLastError();
355 PR_LOG(_pr_io_lm, PR_LOG_MIN,
356 ("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT "
357 "failed %d\n",
358 err));
359 _PR_MD_MAP_SETSOCKOPT_ERROR(err);
360 return PR_FAILURE;
362 return PR_SUCCESS;
363 } else {
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;
370 return PR_FAILURE;
371 } else {
372 PR_SetError(PR_IN_PROGRESS_ERROR, 0);
373 return PR_FAILURE;
377 # endif
379 return PR_SUCCESS;
381 #else
382 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
383 return PR_FAILURE;
384 #endif
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);
393 return PR_FAILURE;
395 return SocketConnectContinue(bottom, pd->out_flags);
398 static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc* fd, PRNetAddr* addr,
399 PRIntervalTime timeout) {
400 PROsfd osfd;
401 PRFileDesc* fd2;
402 PRUint32 al;
403 PRThread* me = _PR_MD_CURRENT_THREAD();
404 #ifdef WINNT
405 PRNetAddr addrCopy;
406 #endif
408 if (_PR_PENDING_INTERRUPT(me)) {
409 me->flags &= ~_PR_INTERRUPT;
410 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
411 return 0;
413 if (_PR_IO_PENDING(me)) {
414 PR_SetError(PR_IO_PENDING_ERROR, 0);
415 return 0;
418 #ifdef WINNT
419 if (addr == NULL) {
420 addr = &addrCopy;
422 #endif
423 al = sizeof(PRNetAddr);
424 osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
425 if (osfd == -1) {
426 return 0;
429 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
430 if (!fd2) {
431 _PR_MD_CLOSE_SOCKET(osfd);
432 return NULL;
435 fd2->secret->nonblocking = fd->secret->nonblocking;
436 fd2->secret->inheritable = fd->secret->inheritable;
437 #ifdef WINNT
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);
448 #endif
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
455 * call.
457 #if !defined(SOLARIS) && !defined(WINNT)
458 _PR_MD_MAKE_NONBLOCK(fd2);
459 #endif
461 #ifdef _PR_INET6
462 if (addr && (AF_INET6 == addr->raw.family)) {
463 addr->raw.family = PR_AF_INET6;
465 #endif
466 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
467 PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
469 return fd2;
472 #ifdef WINNT
473 PR_IMPLEMENT(PRFileDesc*)
474 PR_NTFast_Accept(PRFileDesc* fd, PRNetAddr* addr, PRIntervalTime timeout) {
475 PROsfd osfd;
476 PRFileDesc* fd2;
477 PRIntn al;
478 PRThread* me = _PR_MD_CURRENT_THREAD();
479 PRNetAddr addrCopy;
481 if (_PR_PENDING_INTERRUPT(me)) {
482 me->flags &= ~_PR_INTERRUPT;
483 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
484 return 0;
486 if (_PR_IO_PENDING(me)) {
487 PR_SetError(PR_IO_PENDING_ERROR, 0);
488 return 0;
491 if (addr == NULL) {
492 addr = &addrCopy;
494 al = PR_NETADDR_SIZE(addr);
495 osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
496 if (osfd == -1) {
497 return 0;
500 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
501 if (!fd2) {
502 _PR_MD_CLOSE_SOCKET(osfd);
503 } else {
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);
509 # ifdef _PR_INET6
510 if (AF_INET6 == addr->raw.family) {
511 addr->raw.family = PR_AF_INET6;
513 # endif
514 # ifdef _PR_NEED_SECRET_AF
515 fd2->secret->af = fd->secret->af;
516 # endif
518 return fd2;
520 #endif /* WINNT */
522 static PRStatus PR_CALLBACK SocketBind(PRFileDesc* fd, const PRNetAddr* addr) {
523 PRInt32 result;
524 const PRNetAddr* addrp = addr;
525 #if defined(_PR_INET6)
526 PRNetAddr addrCopy;
527 #endif
529 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
531 #ifdef XP_UNIX
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);
536 return PR_FAILURE;
539 #endif /* XP_UNIX */
541 #if defined(_PR_INET6)
542 if (addr->raw.family == PR_AF_INET6) {
543 addrCopy = *addr;
544 addrCopy.raw.family = AF_INET6;
545 addrp = &addrCopy;
547 #endif
548 result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
549 if (result < 0) {
550 return PR_FAILURE;
552 return PR_SUCCESS;
555 static PRStatus PR_CALLBACK SocketListen(PRFileDesc* fd, PRIntn backlog) {
556 PRInt32 result;
558 result = _PR_MD_LISTEN(fd, backlog);
559 if (result < 0) {
560 return PR_FAILURE;
562 return PR_SUCCESS;
565 static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc* fd, PRIntn how) {
566 PRInt32 result;
568 result = _PR_MD_SHUTDOWN(fd, how);
569 if (result < 0) {
570 return PR_FAILURE;
572 return PR_SUCCESS;
575 static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc* fd, void* buf, PRInt32 amount,
576 PRIntn flags, PRIntervalTime timeout) {
577 PRInt32 rv;
578 PRThread* me = _PR_MD_CURRENT_THREAD();
580 if ((flags != 0) && (flags != PR_MSG_PEEK)) {
581 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
582 return -1;
584 if (_PR_PENDING_INTERRUPT(me)) {
585 me->flags &= ~_PR_INTERRUPT;
586 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
587 return -1;
589 if (_PR_IO_PENDING(me)) {
590 PR_SetError(PR_IO_PENDING_ERROR, 0);
591 return -1;
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);
602 if (flags == 0) {
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);
610 return rv;
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);
629 return -1;
633 #endif
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(),
638 PR_GetOSError()));
640 #ifdef _PR_HAVE_PEEK_BUFFER
641 if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
642 if (rv > 0) {
643 memcpy(fd->secret->peekBuffer, buf, rv);
644 fd->secret->peekBytes = rv;
647 #endif
649 return rv;
652 static PRInt32 PR_CALLBACK SocketRead(PRFileDesc* fd, void* buf,
653 PRInt32 amount) {
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) {
660 PRInt32 temp, count;
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);
666 return -1;
668 if (_PR_IO_PENDING(me)) {
669 PR_SetError(PR_IO_PENDING_ERROR, 0);
670 return -1;
673 count = 0;
674 while (amount > 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);
679 if (temp < 0) {
680 count = -1;
681 break;
684 count += temp;
685 if (fd->secret->nonblocking) {
686 break;
688 buf = (const void*)((const char*)buf + temp);
690 amount -= temp;
692 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
693 return count;
696 static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc* fd, const void* buf,
697 PRInt32 amount) {
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);
706 return PR_FAILURE;
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"));
718 } else {
719 DWORD err = WSAGetLastError();
720 PR_LOG(_pr_io_lm, PR_LOG_MIN,
721 ("SocketClose - CancelIo failed err=%x\n", err));
724 DWORD rvSent;
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"));
730 } else {
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);
744 if (!forWaiting) {
745 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
746 return PR_FAILURE;
748 forWaiting->fd = fd;
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);
755 return PR_SUCCESS;
757 #endif
759 if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
760 return PR_FAILURE;
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;
772 #endif
774 PR_FreeFileDesc(fd);
775 return PR_SUCCESS;
778 static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc* fd) {
779 PRInt32 rv;
780 #ifdef _PR_HAVE_PEEK_BUFFER
781 if (fd->secret->peekBytes != 0) {
782 return fd->secret->peekBytes;
784 #endif
785 rv = _PR_MD_SOCKETAVAILABLE(fd);
786 return rv;
789 static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc* fd) {
790 PRInt64 rv;
791 #ifdef _PR_HAVE_PEEK_BUFFER
792 if (fd->secret->peekBytes != 0) {
793 LL_I2L(rv, fd->secret->peekBytes);
794 return rv;
796 #endif
797 LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
798 return rv;
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) {
807 PRInt32 temp, count;
808 const PRNetAddr* addrp = addr;
809 #if defined(_PR_INET6)
810 PRNetAddr addrCopy;
811 #endif
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);
817 return -1;
819 if (_PR_IO_PENDING(me)) {
820 PR_SetError(PR_IO_PENDING_ERROR, 0);
821 return -1;
824 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
825 #if defined(_PR_INET6)
826 if (addr->raw.family == PR_AF_INET6) {
827 addrCopy = *addr;
828 addrCopy.raw.family = AF_INET6;
829 addrp = &addrCopy;
831 #endif
833 count = 0;
834 do {
835 temp = _PR_MD_SENDTO(fd, buf, amount, flags, addrp, PR_NETADDR_SIZE(addr),
836 timeout);
837 if (temp < 0) {
838 count = -1;
839 break;
841 count += temp;
842 if (fd->secret->nonblocking) {
843 break;
845 buf = (const void*)((const char*)buf + temp);
846 amount -= temp;
847 } while (amount > 0);
848 return count;
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) {
856 PRInt32 temp, count;
857 const PRNetAddr* addrp = addr;
858 # if defined(_PR_INET6)
859 PRNetAddr addrCopy;
860 # endif
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);
866 return -1;
868 if (_PR_IO_PENDING(me)) {
869 PR_SetError(PR_IO_PENDING_ERROR, 0);
870 return -1;
873 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
874 # if defined(_PR_INET6)
875 if (addr->raw.family == PR_AF_INET6) {
876 addrCopy = *addr;
877 addrCopy.raw.family = AF_INET6;
878 addrp = &addrCopy;
880 # endif
882 count = 0;
883 while (amount > 0) {
884 temp = _PR_MD_TCPSENDTO(fd, buf, amount, flags, addrp,
885 PR_NETADDR_SIZE(addr), timeout);
886 if (temp < 0) {
887 count = -1;
888 break;
890 count += temp;
891 if (fd->secret->nonblocking) {
892 break;
894 buf = (const void*)((const char*)buf + temp);
895 amount -= temp;
897 return count;
899 #endif
901 static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc* fd, void* buf,
902 PRInt32 amount, PRIntn flags,
903 PRNetAddr* addr,
904 PRIntervalTime timeout) {
905 PRInt32 rv;
906 PRUint32 al;
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);
912 return -1;
914 if (_PR_IO_PENDING(me)) {
915 PR_SetError(PR_IO_PENDING_ERROR, 0);
916 return -1;
919 al = sizeof(PRNetAddr);
920 rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
921 #ifdef _PR_INET6
922 if (addr && (AF_INET6 == addr->raw.family)) {
923 addr->raw.family = PR_AF_INET6;
925 #endif
926 return rv;
929 static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc* sd, PRFileDesc** nd,
930 PRNetAddr** raddr, void* buf,
931 PRInt32 amount,
932 PRIntervalTime timeout) {
933 PRInt32 rv;
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);
939 return -1;
941 if (_PR_IO_PENDING(me)) {
942 PR_SetError(PR_IO_PENDING_ERROR, 0);
943 return -1;
945 /* The socket must be in blocking mode. */
946 if (sd->secret->nonblocking) {
947 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
948 return -1;
950 *nd = NULL;
952 #if defined(WINNT)
954 PROsfd newSock;
955 PRNetAddr* raddrCopy;
957 if (raddr == NULL) {
958 raddr = &raddrCopy;
960 rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
961 if (rv < 0) {
962 rv = -1;
963 } else {
964 /* Successfully accepted and read; create the new PRFileDesc */
965 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
966 if (*nd == 0) {
967 _PR_MD_CLOSE_SOCKET(newSock);
968 /* PR_AllocFileDesc() has invoked PR_SetError(). */
969 rv = -1;
970 } else {
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));
974 # ifdef _PR_INET6
975 if (AF_INET6 == *raddr->raw.family) {
976 *raddr->raw.family = PR_AF_INET6;
978 # endif
982 #else
983 rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
984 #endif
985 return rv;
988 #ifdef WINNT
989 PR_IMPLEMENT(PRInt32)
990 PR_NTFast_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, PRNetAddr** raddr,
991 void* buf, PRInt32 amount, PRIntervalTime timeout) {
992 PRInt32 rv;
993 PROsfd newSock;
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);
1000 return -1;
1002 if (_PR_IO_PENDING(me)) {
1003 PR_SetError(PR_IO_PENDING_ERROR, 0);
1004 return -1;
1006 *nd = NULL;
1008 if (raddr == NULL) {
1009 raddr = &raddrCopy;
1011 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout,
1012 PR_TRUE, NULL, NULL);
1013 if (rv < 0) {
1014 rv = -1;
1015 } else {
1016 /* Successfully accepted and read; create the new PRFileDesc */
1017 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
1018 if (*nd == 0) {
1019 _PR_MD_CLOSE_SOCKET(newSock);
1020 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1021 rv = -1;
1022 } else {
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));
1026 # ifdef _PR_INET6
1027 if (AF_INET6 == *raddr->raw.family) {
1028 *raddr->raw.family = PR_AF_INET6;
1030 # endif
1031 # ifdef _PR_NEED_SECRET_AF
1032 (*nd)->secret->af = sd->secret->af;
1033 # endif
1036 return rv;
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) {
1045 PRInt32 rv;
1046 PROsfd newSock;
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);
1053 return -1;
1055 if (_PR_IO_PENDING(me)) {
1056 PR_SetError(PR_IO_PENDING_ERROR, 0);
1057 return -1;
1059 *nd = NULL;
1061 if (raddr == NULL) {
1062 raddr = &raddrCopy;
1064 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout,
1065 PR_TRUE, callback, callbackArg);
1066 if (rv < 0) {
1067 rv = -1;
1068 } else {
1069 /* Successfully accepted and read; create the new PRFileDesc */
1070 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
1071 if (*nd == 0) {
1072 _PR_MD_CLOSE_SOCKET(newSock);
1073 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1074 rv = -1;
1075 } else {
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));
1079 # ifdef _PR_INET6
1080 if (AF_INET6 == *raddr->raw.family) {
1081 *raddr->raw.family = PR_AF_INET6;
1083 # endif
1084 # ifdef _PR_NEED_SECRET_AF
1085 (*nd)->secret->af = sd->secret->af;
1086 # endif
1089 return rv;
1091 #endif /* WINNT */
1093 #ifdef WINNT
1094 PR_IMPLEMENT(void)
1095 PR_NTFast_UpdateAcceptContext(PRFileDesc* socket, PRFileDesc* acceptSocket) {
1096 _PR_MD_UPDATE_ACCEPT_CONTEXT(socket->secret->md.osfd,
1097 acceptSocket->secret->md.osfd);
1099 #endif /* WINNT */
1101 static PRInt32 PR_CALLBACK SocketSendFile(PRFileDesc* sd, PRSendFileData* sfd,
1102 PRTransmitFileFlags flags,
1103 PRIntervalTime timeout) {
1104 PRInt32 rv;
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);
1110 return -1;
1112 if (_PR_IO_PENDING(me)) {
1113 PR_SetError(PR_IO_PENDING_ERROR, 0);
1114 return -1;
1116 /* The socket must be in blocking mode. */
1117 if (sd->secret->nonblocking) {
1118 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1119 return -1;
1121 #if defined(WINNT)
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);
1131 #else
1132 rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
1133 #endif /* WINNT */
1135 return rv;
1138 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc* sd, PRFileDesc* fd,
1139 const void* headers, PRInt32 hlen,
1140 PRTransmitFileFlags flags,
1141 PRIntervalTime timeout) {
1142 PRSendFileData sfd;
1144 sfd.fd = fd;
1145 sfd.file_offset = 0;
1146 sfd.file_nbytes = 0;
1147 sfd.header = headers;
1148 sfd.hlen = hlen;
1149 sfd.trailer = NULL;
1150 sfd.tlen = 0;
1152 return (SocketSendFile(sd, &sfd, flags, timeout));
1155 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc* fd, PRNetAddr* addr) {
1156 PRInt32 result;
1157 PRUint32 addrlen;
1159 addrlen = sizeof(PRNetAddr);
1160 result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
1161 if (result < 0) {
1162 return PR_FAILURE;
1164 #ifdef _PR_INET6
1165 if (AF_INET6 == addr->raw.family) {
1166 addr->raw.family = PR_AF_INET6;
1168 #endif
1169 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1170 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
1171 return PR_SUCCESS;
1174 static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc* fd, PRNetAddr* addr) {
1175 PRInt32 result;
1176 PRUint32 addrlen;
1178 addrlen = sizeof(PRNetAddr);
1179 result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
1180 if (result < 0) {
1181 return PR_FAILURE;
1183 #ifdef _PR_INET6
1184 if (AF_INET6 == addr->raw.family) {
1185 addr->raw.family = PR_AF_INET6;
1187 #endif
1188 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1189 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
1190 return PR_SUCCESS;
1193 static PRInt16 PR_CALLBACK SocketPoll(PRFileDesc* fd, PRInt16 in_flags,
1194 PRInt16* out_flags) {
1195 *out_flags = 0;
1197 #if defined(_WIN64)
1198 if (in_flags & PR_POLL_WRITE) {
1199 if (fd->secret->alreadyConnected) {
1200 *out_flags = PR_POLL_WRITE;
1201 return PR_POLL_WRITE;
1204 #endif
1205 return in_flags;
1206 } /* SocketPoll */
1208 static PRIOMethods tcpMethods = {
1209 PR_DESC_SOCKET_TCP,
1210 SocketClose,
1211 SocketRead,
1212 SocketWrite,
1213 SocketAvailable,
1214 SocketAvailable64,
1215 SocketSync,
1216 (PRSeekFN)_PR_InvalidInt,
1217 (PRSeek64FN)_PR_InvalidInt64,
1218 (PRFileInfoFN)_PR_InvalidStatus,
1219 (PRFileInfo64FN)_PR_InvalidStatus,
1220 SocketWritev,
1221 SocketConnect,
1222 SocketAccept,
1223 SocketBind,
1224 SocketListen,
1225 SocketShutdown,
1226 SocketRecv,
1227 SocketSend,
1228 (PRRecvfromFN)_PR_InvalidInt,
1229 #if defined(_WIN64) && defined(WIN95)
1230 SocketTCPSendTo, /* This is for fast open. We imitate Linux interface. */
1231 #else
1232 (PRSendtoFN)_PR_InvalidInt,
1233 #endif
1234 SocketPoll,
1235 SocketAcceptRead,
1236 SocketTransmitFile,
1237 SocketGetName,
1238 SocketGetPeerName,
1239 (PRReservedFN)_PR_InvalidInt,
1240 (PRReservedFN)_PR_InvalidInt,
1241 _PR_SocketGetSocketOption,
1242 _PR_SocketSetSocketOption,
1243 SocketSendFile,
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,
1251 SocketClose,
1252 SocketRead,
1253 SocketWrite,
1254 SocketAvailable,
1255 SocketAvailable64,
1256 SocketSync,
1257 (PRSeekFN)_PR_InvalidInt,
1258 (PRSeek64FN)_PR_InvalidInt64,
1259 (PRFileInfoFN)_PR_InvalidStatus,
1260 (PRFileInfo64FN)_PR_InvalidStatus,
1261 SocketWritev,
1262 SocketConnect,
1263 (PRAcceptFN)_PR_InvalidDesc,
1264 SocketBind,
1265 SocketListen,
1266 SocketShutdown,
1267 SocketRecv,
1268 SocketSend,
1269 SocketRecvFrom,
1270 SocketSendTo,
1271 SocketPoll,
1272 (PRAcceptreadFN)_PR_InvalidInt,
1273 (PRTransmitfileFN)_PR_InvalidInt,
1274 SocketGetName,
1275 SocketGetPeerName,
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 = {
1288 (PRDescType)0,
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,
1309 SocketPoll,
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() {
1341 PROsfd osfd;
1343 osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
1344 if (osfd != -1) {
1345 _PR_MD_CLOSE_SOCKET(osfd);
1346 return PR_TRUE;
1348 return PR_FALSE;
1350 # endif /* _PR_INET6_PROBE */
1352 #endif
1354 PR_IMPLEMENT(PRFileDesc*)
1355 PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) {
1356 PROsfd osfd;
1357 PRFileDesc* fd;
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
1366 #endif
1368 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
1369 return NULL;
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) {
1378 domain = AF_INET6;
1380 #else
1381 if (PR_AF_INET6 == domain) {
1382 domain = AF_INET;
1384 #endif /* _PR_INET6 */
1385 osfd = _PR_MD_SOCKET(domain, type, proto);
1386 if (osfd == -1) {
1387 return 0;
1389 if (type == SOCK_STREAM) {
1390 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
1391 } else {
1392 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
1395 * Make the sockets non-blocking
1397 if (fd != NULL) {
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;
1402 #endif
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)) {
1410 PR_Close(fd);
1411 fd = NULL;
1414 #endif
1415 } else {
1416 _PR_MD_CLOSE_SOCKET(osfd);
1419 return fd;
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[]) {
1443 #ifdef XP_UNIX
1444 PRInt32 rv, osfd[2];
1446 if (!_pr_initialized) {
1447 _PR_ImplicitInitialization();
1450 rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
1451 if (rv == -1) {
1452 return PR_FAILURE;
1455 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
1456 if (!f[0]) {
1457 _PR_MD_CLOSE_SOCKET(osfd[0]);
1458 _PR_MD_CLOSE_SOCKET(osfd[1]);
1459 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1460 return PR_FAILURE;
1462 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
1463 if (!f[1]) {
1464 PR_Close(f[0]);
1465 _PR_MD_CLOSE_SOCKET(osfd[1]);
1466 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1467 return PR_FAILURE;
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);
1473 return PR_SUCCESS;
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
1479 * child process.
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.
1485 SOCKET listenSock;
1486 SOCKET osfd[2];
1487 struct sockaddr_in selfAddr, peerAddr;
1488 int addrLen;
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) {
1497 goto failed;
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) {
1504 goto failed;
1506 if (getsockname(listenSock, (struct sockaddr*)&selfAddr, &addrLen) ==
1507 SOCKET_ERROR) {
1508 goto failed;
1510 if (listen(listenSock, 5) == SOCKET_ERROR) {
1511 goto failed;
1513 osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
1514 if (osfd[0] == INVALID_SOCKET) {
1515 goto failed;
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) {
1529 goto failed;
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) ==
1537 SOCKET_ERROR) {
1538 goto failed;
1540 osfd[1] = accept(listenSock, (struct sockaddr*)&peerAddr, &addrLen);
1541 if (osfd[1] == INVALID_SOCKET) {
1542 goto failed;
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);
1547 goto failed;
1549 closesocket(listenSock);
1551 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
1552 if (!f[0]) {
1553 closesocket(osfd[0]);
1554 closesocket(osfd[1]);
1555 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1556 return PR_FAILURE;
1558 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
1559 if (!f[1]) {
1560 PR_Close(f[0]);
1561 closesocket(osfd[1]);
1562 /* PR_AllocFileDesc() has invoked PR_SetError(). */
1563 return PR_FAILURE;
1565 _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
1566 _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
1567 return PR_SUCCESS;
1569 failed:
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]);
1579 return PR_FAILURE;
1580 #else /* not Unix or NT */
1582 * default implementation
1584 PRFileDesc* listenSock;
1585 PRNetAddr selfAddr, peerAddr;
1586 PRUint16 port;
1588 f[0] = f[1] = NULL;
1589 listenSock = PR_NewTCPSocket();
1590 if (listenSock == NULL) {
1591 goto failed;
1593 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
1594 if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
1595 goto failed;
1597 if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
1598 goto failed;
1600 port = ntohs(selfAddr.inet.port);
1601 if (PR_Listen(listenSock, 5) == PR_FAILURE) {
1602 goto failed;
1604 f[0] = PR_NewTCPSocket();
1605 if (f[0] == NULL) {
1606 goto failed;
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) {
1616 goto failed;
1618 # endif
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) {
1631 goto failed;
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) {
1639 goto failed;
1641 f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
1642 if (f[1] == NULL) {
1643 goto failed;
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);
1648 goto failed;
1650 PR_Close(listenSock);
1651 return PR_SUCCESS;
1653 failed:
1654 if (listenSock) {
1655 PR_Close(listenSock);
1657 if (f[0]) {
1658 PR_Close(f[0]);
1660 if (f[1]) {
1661 PR_Close(f[1]);
1663 return PR_FAILURE;
1664 #endif
1667 PR_IMPLEMENT(PROsfd)
1668 PR_FileDesc2NativeHandle(PRFileDesc* fd) {
1669 if (fd) {
1670 fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
1672 if (!fd) {
1673 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1674 return -1;
1676 return fd->secret->md.osfd;
1679 PR_IMPLEMENT(void)
1680 PR_ChangeFileDescNativeHandle(PRFileDesc* fd, PROsfd handle) {
1681 if (fd) {
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];
1709 set->hsize--;
1710 break;
1714 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc* fh, PR_fd_set* set) {
1715 PRUint32 index;
1716 for (index = 0; index < set->hsize; index++)
1717 if (set->harray[index] == fh) {
1718 return 1;
1720 return 0;
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];
1737 set->nsize--;
1738 break;
1742 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set* set) {
1743 PRUint32 index;
1744 for (index = 0; index < set->nsize; index++)
1745 if (set->narray[index] == fd) {
1746 return 1;
1748 return 0;
1751 #if !defined(NEED_SELECT)
1752 # include "obsolete/probslet.h"
1754 # define PD_INCR 20
1756 static PRPollDesc* _pr_setfd(PR_fd_set* set, PRInt16 flags,
1757 PRPollDesc* polldesc) {
1758 PRUintn fsidx, pdidx;
1759 PRPollDesc* poll = polldesc;
1761 if (NULL == set) {
1762 return poll;
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));
1772 if (NULL == poll) {
1773 goto out_of_memory;
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 */
1784 break;
1789 # if 0
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 */
1798 poll = PR_Realloc(
1799 poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
1800 if (NULL == poll) {
1801 goto out_of_memory;
1803 memset(
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;
1815 break;
1819 # endif /* 0 */
1821 return poll;
1823 out_of_memory:
1824 if (NULL != polldesc) {
1825 PR_DELETE(polldesc);
1827 return NULL;
1828 } /* _pr_setfd */
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)
1836 PRInt32 npds = 0;
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;
1846 if (warning) {
1847 warning = _PR_Obsolete("PR_Select()", "PR_Poll()");
1850 /* try to get an initial guesss at how much space we need */
1851 npds = 0;
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;
1862 if (0 == npds) {
1863 PR_Sleep(timeout);
1864 return 0;
1867 copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
1868 if (NULL == poll) {
1869 goto out_of_memory;
1871 poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
1873 poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
1874 if (NULL == poll) {
1875 goto out_of_memory;
1877 poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
1878 if (NULL == poll) {
1879 goto out_of_memory;
1881 poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
1882 if (NULL == poll) {
1883 goto out_of_memory;
1885 unused = 0;
1886 while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) {
1887 ++unused;
1890 PR_ASSERT(unused > 0);
1891 npds = PR_Poll(poll, unused, timeout);
1893 if (npds > 0) {
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);
1907 npds = -1;
1908 break;
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;
1924 PR_DELETE(poll);
1926 return npds;
1927 out_of_memory:
1928 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
1929 return -1;
1931 #endif /* !defined(NEED_SELECT) */