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