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