nspr: import 3.0 RC1 cutoff from CVS
[mozilla-nspr.git] / nsprpub / pr / src / pthreads / ptio.c
blob62febde289d7ab86e85240bb82d34dbedefe076e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 ** File: ptio.c
40 ** Descritpion: Implemenation of I/O methods for pthreads
43 #if defined(_PR_PTHREADS)
45 #if defined(_PR_POLL_WITH_SELECT)
46 #if !(defined(HPUX) && defined(_USE_BIG_FDS))
47 /* set fd limit for select(), before including system header files */
48 #define FD_SETSIZE (16 * 1024)
49 #endif
50 #endif
52 #include <pthread.h>
53 #include <string.h> /* for memset() */
54 #include <sys/types.h>
55 #include <dirent.h>
56 #include <fcntl.h>
57 #include <unistd.h>
58 #include <sys/socket.h>
59 #include <sys/stat.h>
60 #include <sys/uio.h>
61 #include <sys/file.h>
62 #include <sys/ioctl.h>
63 #if defined(DARWIN)
64 #include <sys/utsname.h> /* for uname */
65 #endif
66 #if defined(SOLARIS) || defined(UNIXWARE)
67 #include <sys/filio.h> /* to pick up FIONREAD */
68 #endif
69 #ifdef _PR_POLL_AVAILABLE
70 #include <poll.h>
71 #endif
72 #ifdef AIX
73 /* To pick up sysconf() */
74 #include <unistd.h>
75 #include <dlfcn.h> /* for dlopen */
76 #else
77 /* To pick up getrlimit() etc. */
78 #include <sys/time.h>
79 #include <sys/resource.h>
80 #endif
82 #ifdef SOLARIS
84 * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
85 * Code built this way won't run on a system without sendfilev().
86 * We can define HAVE_SENDFILEV by default when the minimum release
87 * of Solaris that NSPR supports has sendfilev().
89 #ifdef HAVE_SENDFILEV
91 #include <sys/sendfile.h>
93 #define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
95 #else
97 #include <dlfcn.h> /* for dlopen */
100 * Match the definitions in <sys/sendfile.h>.
102 typedef struct sendfilevec {
103 int sfv_fd; /* input fd */
104 uint_t sfv_flag; /* flags */
105 off_t sfv_off; /* offset to start reading from */
106 size_t sfv_len; /* amount of data */
107 } sendfilevec_t;
109 #define SFV_FD_SELF (-2)
112 * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
114 static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
116 #define SOLARIS_SENDFILEV(a, b, c, d) \
117 (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
119 #endif /* HAVE_SENDFILEV */
120 #endif /* SOLARIS */
123 * The send_file() system call is available in AIX 4.3.2 or later.
124 * If this file is compiled on an older AIX system, it attempts to
125 * look up the send_file symbol at run time to determine whether
126 * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
127 * send_file(). On AIX 4.3.2 or later, we can safely skip this
128 * runtime function dispatching and just use the send_file based
129 * implementation.
131 #ifdef AIX
132 #ifdef SF_CLOSE
133 #define HAVE_SEND_FILE
134 #endif
136 #ifdef HAVE_SEND_FILE
138 #define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
140 #else /* HAVE_SEND_FILE */
143 * The following definitions match those in <sys/socket.h>
144 * on AIX 4.3.2.
148 * Structure for the send_file() system call
150 struct sf_parms {
151 /* --------- header parms ---------- */
152 void *header_data; /* Input/Output. Points to header buf */
153 uint_t header_length; /* Input/Output. Length of the header */
154 /* --------- file parms ------------ */
155 int file_descriptor; /* Input. File descriptor of the file */
156 unsigned long long file_size; /* Output. Size of the file */
157 unsigned long long file_offset; /* Input/Output. Starting offset */
158 long long file_bytes; /* Input/Output. no. of bytes to send */
159 /* --------- trailer parms --------- */
160 void *trailer_data; /* Input/Output. Points to trailer buf */
161 uint_t trailer_length; /* Input/Output. Length of the trailer */
162 /* --------- return info ----------- */
163 unsigned long long bytes_sent; /* Output. no. of bytes sent */
167 * Flags for the send_file() system call
169 #define SF_CLOSE 0x00000001 /* close the socket after completion */
170 #define SF_REUSE 0x00000002 /* reuse socket. not supported */
171 #define SF_DONT_CACHE 0x00000004 /* don't apply network buffer cache */
172 #define SF_SYNC_CACHE 0x00000008 /* sync/update network buffer cache */
175 * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
177 static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
179 #define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
181 #endif /* HAVE_SEND_FILE */
182 #endif /* AIX */
184 #ifdef LINUX
185 #include <sys/sendfile.h>
186 #endif
188 #include "primpl.h"
190 #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
191 #ifdef LINUX
192 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
193 #ifndef TCP_CORK
194 #define TCP_CORK 3
195 #endif
196 #endif
198 #ifdef _PR_IPV6_V6ONLY_PROBE
199 static PRBool _pr_ipv6_v6only_on_by_default;
200 #endif
202 #if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
203 #define _PRSelectFdSetArg_t int *
204 #elif defined(AIX4_1)
205 #define _PRSelectFdSetArg_t void *
206 #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
207 || defined(OSF1) || defined(SOLARIS) \
208 || defined(HPUX10_30) || defined(HPUX11) \
209 || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
210 || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
211 || defined(BSDI) || defined(VMS) || defined(NTO) || defined(DARWIN) \
212 || defined(UNIXWARE) || defined(RISCOS)
213 #define _PRSelectFdSetArg_t fd_set *
214 #else
215 #error "Cannot determine architecture"
216 #endif
218 static PRFileDesc *pt_SetMethods(
219 PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
221 static PRLock *_pr_flock_lock; /* For PR_LockFile() etc. */
222 static PRCondVar *_pr_flock_cv; /* For PR_LockFile() etc. */
223 static PRLock *_pr_rename_lock; /* For PR_Rename() */
225 /**************************************************************************/
227 /* These two functions are only used in assertions. */
228 #if defined(DEBUG)
230 PRBool IsValidNetAddr(const PRNetAddr *addr)
232 if ((addr != NULL)
233 && (addr->raw.family != AF_UNIX)
234 && (addr->raw.family != PR_AF_INET6)
235 && (addr->raw.family != AF_INET)) {
236 return PR_FALSE;
238 return PR_TRUE;
241 static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
244 * The definition of the length of a Unix domain socket address
245 * is not uniform, so we don't check it.
247 if ((addr != NULL)
248 && (addr->raw.family != AF_UNIX)
249 && (PR_NETADDR_SIZE(addr) != addr_len)) {
250 #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
252 * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2
253 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
254 * field and is 28 bytes. It is possible for socket functions
255 * to return an addr_len greater than sizeof(struct sockaddr_in6).
256 * We need to allow that. (Bugzilla bug #77264)
258 if ((PR_AF_INET6 == addr->raw.family)
259 && (sizeof(addr->ipv6) == addr_len)) {
260 return PR_TRUE;
262 #endif
263 return PR_FALSE;
265 return PR_TRUE;
268 #endif /* DEBUG */
270 /*****************************************************************************/
271 /************************* I/O Continuation machinery ************************/
272 /*****************************************************************************/
275 * The polling interval defines the maximum amount of time that a thread
276 * might hang up before an interrupt is noticed.
278 #define PT_DEFAULT_POLL_MSEC 5000
279 #if defined(_PR_POLL_WITH_SELECT)
280 #define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
281 #define PT_DEFAULT_SELECT_USEC \
282 ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
283 #endif
286 * pt_SockLen is the type for the length of a socket address
287 * structure, used in the address length argument to bind,
288 * connect, accept, getsockname, getpeername, etc. Posix.1g
289 * defines this type as socklen_t. It is size_t or int on
290 * most current systems.
292 #if defined(HAVE_SOCKLEN_T) \
293 || (defined(__GLIBC__) && __GLIBC__ >= 2)
294 typedef socklen_t pt_SockLen;
295 #elif (defined(AIX) && !defined(AIX4_1)) \
296 || defined(VMS)
297 typedef PRSize pt_SockLen;
298 #else
299 typedef PRIntn pt_SockLen;
300 #endif
302 typedef struct pt_Continuation pt_Continuation;
303 typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
305 typedef enum pr_ContuationStatus
307 pt_continuation_pending,
308 pt_continuation_done
309 } pr_ContuationStatus;
311 struct pt_Continuation
313 /* The building of the continuation operation */
314 ContinuationFn function; /* what function to continue */
315 union { PRIntn osfd; } arg1; /* #1 - the op's fd */
316 union { void* buffer; } arg2; /* #2 - primary transfer buffer */
317 union {
318 PRSize amount; /* #3 - size of 'buffer', or */
319 pt_SockLen *addr_len; /* - length of address */
320 #ifdef HPUX11
322 * For sendfile()
324 struct file_spec {
325 off_t offset; /* offset in file to send */
326 size_t nbytes; /* length of file data to send */
327 size_t st_size; /* file size */
328 } file_spec;
329 #endif
330 } arg3;
331 union { PRIntn flags; } arg4; /* #4 - read/write flags */
332 union { PRNetAddr *addr; } arg5; /* #5 - send/recv address */
334 #ifdef HPUX11
336 * For sendfile()
338 int filedesc; /* descriptor of file to send */
339 int nbytes_to_send; /* size of header and file */
340 #endif /* HPUX11 */
342 #ifdef SOLARIS
344 * For sendfilev()
346 int nbytes_to_send; /* size of header and file */
347 #endif /* SOLARIS */
349 #ifdef LINUX
351 * For sendfile()
353 int in_fd; /* descriptor of file to send */
354 off_t offset;
355 size_t count;
356 #endif /* LINUX */
358 PRIntervalTime timeout; /* client (relative) timeout */
360 PRInt16 event; /* flags for poll()'s events */
363 ** The representation and notification of the results of the operation.
364 ** These function can either return an int return code or a pointer to
365 ** some object.
367 union { PRSize code; void *object; } result;
369 PRIntn syserrno; /* in case it failed, why (errno) */
370 pr_ContuationStatus status; /* the status of the operation */
373 #if defined(DEBUG)
375 PTDebug pt_debug; /* this is shared between several modules */
377 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
379 PTDebug stats;
380 char buffer[100];
381 PRExplodedTime tod;
382 PRInt64 elapsed, aMil;
383 stats = pt_debug; /* a copy */
384 PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
385 (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
387 LL_SUB(elapsed, PR_Now(), stats.timeStarted);
388 LL_I2L(aMil, 1000000);
389 LL_DIV(elapsed, elapsed, aMil);
391 if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
392 PR_fprintf(
393 debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
394 PR_fprintf(
395 debug_out, "\tlocks [created: %u, destroyed: %u]\n",
396 stats.locks_created, stats.locks_destroyed);
397 PR_fprintf(
398 debug_out, "\tlocks [acquired: %u, released: %u]\n",
399 stats.locks_acquired, stats.locks_released);
400 PR_fprintf(
401 debug_out, "\tcvars [created: %u, destroyed: %u]\n",
402 stats.cvars_created, stats.cvars_destroyed);
403 PR_fprintf(
404 debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
405 stats.cvars_notified, stats.delayed_cv_deletes);
406 } /* PT_FPrintStats */
408 #else
410 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
412 /* do nothing */
413 } /* PT_FPrintStats */
415 #endif /* DEBUG */
417 #if defined(_PR_POLL_WITH_SELECT)
419 * OSF1 and HPUX report the POLLHUP event for a socket when the
420 * shutdown(SHUT_WR) operation is called for the remote end, even though
421 * the socket is still writeable. Use select(), instead of poll(), to
422 * workaround this problem.
424 static void pt_poll_now_with_select(pt_Continuation *op)
426 PRInt32 msecs;
427 fd_set rd, wr, *rdp, *wrp;
428 struct timeval tv;
429 PRIntervalTime epoch, now, elapsed, remaining;
430 PRBool wait_for_remaining;
431 PRThread *self = PR_GetCurrentThread();
433 PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
434 PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
436 switch (op->timeout) {
437 case PR_INTERVAL_NO_TIMEOUT:
438 tv.tv_sec = PT_DEFAULT_SELECT_SEC;
439 tv.tv_usec = PT_DEFAULT_SELECT_USEC;
442 PRIntn rv;
444 if (op->event & POLLIN) {
445 FD_ZERO(&rd);
446 FD_SET(op->arg1.osfd, &rd);
447 rdp = &rd;
448 } else
449 rdp = NULL;
450 if (op->event & POLLOUT) {
451 FD_ZERO(&wr);
452 FD_SET(op->arg1.osfd, &wr);
453 wrp = &wr;
454 } else
455 wrp = NULL;
457 rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
459 if (self->state & PT_THREAD_ABORTED)
461 self->state &= ~PT_THREAD_ABORTED;
462 op->result.code = -1;
463 op->syserrno = EINTR;
464 op->status = pt_continuation_done;
465 return;
468 if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
469 continue; /* go around the loop again */
471 if (rv > 0)
473 PRInt16 revents = 0;
475 if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
476 revents |= POLLIN;
477 if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
478 revents |= POLLOUT;
480 if (op->function(op, revents))
481 op->status = pt_continuation_done;
482 } else if (rv == -1) {
483 op->result.code = -1;
484 op->syserrno = errno;
485 op->status = pt_continuation_done;
487 /* else, select timed out */
488 } while (pt_continuation_done != op->status);
489 break;
490 default:
491 now = epoch = PR_IntervalNow();
492 remaining = op->timeout;
495 PRIntn rv;
497 if (op->event & POLLIN) {
498 FD_ZERO(&rd);
499 FD_SET(op->arg1.osfd, &rd);
500 rdp = &rd;
501 } else
502 rdp = NULL;
503 if (op->event & POLLOUT) {
504 FD_ZERO(&wr);
505 FD_SET(op->arg1.osfd, &wr);
506 wrp = &wr;
507 } else
508 wrp = NULL;
510 wait_for_remaining = PR_TRUE;
511 msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
512 if (msecs > PT_DEFAULT_POLL_MSEC) {
513 wait_for_remaining = PR_FALSE;
514 msecs = PT_DEFAULT_POLL_MSEC;
516 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
517 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
518 rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
520 if (self->state & PT_THREAD_ABORTED)
522 self->state &= ~PT_THREAD_ABORTED;
523 op->result.code = -1;
524 op->syserrno = EINTR;
525 op->status = pt_continuation_done;
526 return;
529 if (rv > 0) {
530 PRInt16 revents = 0;
532 if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
533 revents |= POLLIN;
534 if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
535 revents |= POLLOUT;
537 if (op->function(op, revents))
538 op->status = pt_continuation_done;
540 } else if ((rv == 0) ||
541 ((errno == EINTR) || (errno == EAGAIN))) {
542 if (rv == 0) { /* select timed out */
543 if (wait_for_remaining)
544 now += remaining;
545 else
546 now += PR_MillisecondsToInterval(msecs);
547 } else
548 now = PR_IntervalNow();
549 elapsed = (PRIntervalTime) (now - epoch);
550 if (elapsed >= op->timeout) {
551 op->result.code = -1;
552 op->syserrno = ETIMEDOUT;
553 op->status = pt_continuation_done;
554 } else
555 remaining = op->timeout - elapsed;
556 } else {
557 op->result.code = -1;
558 op->syserrno = errno;
559 op->status = pt_continuation_done;
561 } while (pt_continuation_done != op->status);
562 break;
565 } /* pt_poll_now_with_select */
567 #endif /* _PR_POLL_WITH_SELECT */
569 static void pt_poll_now(pt_Continuation *op)
571 PRInt32 msecs;
572 PRIntervalTime epoch, now, elapsed, remaining;
573 PRBool wait_for_remaining;
574 PRThread *self = PR_GetCurrentThread();
576 PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
577 #if defined (_PR_POLL_WITH_SELECT)
579 * If the fd is small enough call the select-based poll operation
581 if (op->arg1.osfd < FD_SETSIZE) {
582 pt_poll_now_with_select(op);
583 return;
585 #endif
587 switch (op->timeout) {
588 case PR_INTERVAL_NO_TIMEOUT:
589 msecs = PT_DEFAULT_POLL_MSEC;
592 PRIntn rv;
593 struct pollfd tmp_pfd;
595 tmp_pfd.revents = 0;
596 tmp_pfd.fd = op->arg1.osfd;
597 tmp_pfd.events = op->event;
599 rv = poll(&tmp_pfd, 1, msecs);
601 if (self->state & PT_THREAD_ABORTED)
603 self->state &= ~PT_THREAD_ABORTED;
604 op->result.code = -1;
605 op->syserrno = EINTR;
606 op->status = pt_continuation_done;
607 return;
610 if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
611 continue; /* go around the loop again */
613 if (rv > 0)
615 PRInt16 events = tmp_pfd.events;
616 PRInt16 revents = tmp_pfd.revents;
618 if ((revents & POLLNVAL) /* busted in all cases */
619 || ((events & POLLOUT) && (revents & POLLHUP)))
620 /* write op & hup */
622 op->result.code = -1;
623 if (POLLNVAL & revents) op->syserrno = EBADF;
624 else if (POLLHUP & revents) op->syserrno = EPIPE;
625 op->status = pt_continuation_done;
626 } else {
627 if (op->function(op, revents))
628 op->status = pt_continuation_done;
630 } else if (rv == -1) {
631 op->result.code = -1;
632 op->syserrno = errno;
633 op->status = pt_continuation_done;
635 /* else, poll timed out */
636 } while (pt_continuation_done != op->status);
637 break;
638 default:
639 now = epoch = PR_IntervalNow();
640 remaining = op->timeout;
643 PRIntn rv;
644 struct pollfd tmp_pfd;
646 tmp_pfd.revents = 0;
647 tmp_pfd.fd = op->arg1.osfd;
648 tmp_pfd.events = op->event;
650 wait_for_remaining = PR_TRUE;
651 msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
652 if (msecs > PT_DEFAULT_POLL_MSEC)
654 wait_for_remaining = PR_FALSE;
655 msecs = PT_DEFAULT_POLL_MSEC;
657 rv = poll(&tmp_pfd, 1, msecs);
659 if (self->state & PT_THREAD_ABORTED)
661 self->state &= ~PT_THREAD_ABORTED;
662 op->result.code = -1;
663 op->syserrno = EINTR;
664 op->status = pt_continuation_done;
665 return;
668 if (rv > 0)
670 PRInt16 events = tmp_pfd.events;
671 PRInt16 revents = tmp_pfd.revents;
673 if ((revents & POLLNVAL) /* busted in all cases */
674 || ((events & POLLOUT) && (revents & POLLHUP)))
675 /* write op & hup */
677 op->result.code = -1;
678 if (POLLNVAL & revents) op->syserrno = EBADF;
679 else if (POLLHUP & revents) op->syserrno = EPIPE;
680 op->status = pt_continuation_done;
681 } else {
682 if (op->function(op, revents))
684 op->status = pt_continuation_done;
687 } else if ((rv == 0) ||
688 ((errno == EINTR) || (errno == EAGAIN))) {
689 if (rv == 0) /* poll timed out */
691 if (wait_for_remaining)
692 now += remaining;
693 else
694 now += PR_MillisecondsToInterval(msecs);
696 else
697 now = PR_IntervalNow();
698 elapsed = (PRIntervalTime) (now - epoch);
699 if (elapsed >= op->timeout) {
700 op->result.code = -1;
701 op->syserrno = ETIMEDOUT;
702 op->status = pt_continuation_done;
703 } else
704 remaining = op->timeout - elapsed;
705 } else {
706 op->result.code = -1;
707 op->syserrno = errno;
708 op->status = pt_continuation_done;
710 } while (pt_continuation_done != op->status);
711 break;
714 } /* pt_poll_now */
716 static PRIntn pt_Continue(pt_Continuation *op)
718 op->status = pt_continuation_pending; /* set default value */
720 * let each thread call poll directly
722 pt_poll_now(op);
723 PR_ASSERT(pt_continuation_done == op->status);
724 return op->result.code;
725 } /* pt_Continue */
727 /*****************************************************************************/
728 /*********************** specific continuation functions *********************/
729 /*****************************************************************************/
730 static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
732 op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
733 if (op->syserrno != 0) {
734 op->result.code = -1;
735 } else {
736 op->result.code = 0;
738 return PR_TRUE; /* this one is cooked */
739 } /* pt_connect_cont */
741 static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
743 op->syserrno = 0;
744 op->result.code = accept(
745 op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
746 if (-1 == op->result.code)
748 op->syserrno = errno;
749 if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
750 return PR_FALSE; /* do nothing - this one ain't finished */
752 return PR_TRUE;
753 } /* pt_accept_cont */
755 static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
758 * Any number of bytes will complete the operation. It need
759 * not (and probably will not) satisfy the request. The only
760 * error we continue is EWOULDBLOCK|EAGAIN.
762 op->result.code = read(
763 op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
764 op->syserrno = errno;
765 return ((-1 == op->result.code) &&
766 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
767 PR_FALSE : PR_TRUE;
768 } /* pt_read_cont */
770 static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
773 * Any number of bytes will complete the operation. It need
774 * not (and probably will not) satisfy the request. The only
775 * error we continue is EWOULDBLOCK|EAGAIN.
777 #if defined(SOLARIS)
778 if (0 == op->arg4.flags)
779 op->result.code = read(
780 op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
781 else
782 op->result.code = recv(
783 op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
784 #else
785 op->result.code = recv(
786 op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
787 #endif
788 op->syserrno = errno;
789 return ((-1 == op->result.code) &&
790 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
791 PR_FALSE : PR_TRUE;
792 } /* pt_recv_cont */
794 static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
796 PRIntn bytes;
797 #if defined(SOLARIS)
798 PRInt32 tmp_amount = op->arg3.amount;
799 #endif
801 * We want to write the entire amount out, no matter how many
802 * tries it takes. Keep advancing the buffer and the decrementing
803 * the amount until the amount goes away. Return the total bytes
804 * (which should be the original amount) when finished (or an
805 * error).
807 #if defined(SOLARIS)
808 retry:
809 bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
810 #else
811 bytes = send(
812 op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
813 #endif
814 op->syserrno = errno;
816 #if defined(SOLARIS)
818 * The write system call has been reported to return the ERANGE error
819 * on occasion. Try to write in smaller chunks to workaround this bug.
821 if ((bytes == -1) && (op->syserrno == ERANGE))
823 if (tmp_amount > 1)
825 tmp_amount = tmp_amount/2; /* half the bytes */
826 goto retry;
829 #endif
831 if (bytes >= 0) /* this is progress */
833 char *bp = (char*)op->arg2.buffer;
834 bp += bytes; /* adjust the buffer pointer */
835 op->arg2.buffer = bp;
836 op->result.code += bytes; /* accumulate the number sent */
837 op->arg3.amount -= bytes; /* and reduce the required count */
838 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
840 else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
842 op->result.code = -1;
843 return PR_TRUE;
845 else return PR_FALSE;
846 } /* pt_send_cont */
848 static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
850 PRIntn bytes;
852 * We want to write the entire amount out, no matter how many
853 * tries it takes. Keep advancing the buffer and the decrementing
854 * the amount until the amount goes away. Return the total bytes
855 * (which should be the original amount) when finished (or an
856 * error).
858 bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
859 op->syserrno = errno;
860 if (bytes >= 0) /* this is progress */
862 char *bp = (char*)op->arg2.buffer;
863 bp += bytes; /* adjust the buffer pointer */
864 op->arg2.buffer = bp;
865 op->result.code += bytes; /* accumulate the number sent */
866 op->arg3.amount -= bytes; /* and reduce the required count */
867 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
869 else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
871 op->result.code = -1;
872 return PR_TRUE;
874 else return PR_FALSE;
875 } /* pt_write_cont */
877 static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
879 PRIntn bytes;
880 struct iovec *iov = (struct iovec*)op->arg2.buffer;
882 * Same rules as write, but continuing seems to be a bit more
883 * complicated. As the number of bytes sent grows, we have to
884 * redefine the vector we're pointing at. We might have to
885 * modify an individual vector parms or we might have to eliminate
886 * a pair altogether.
888 bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
889 op->syserrno = errno;
890 if (bytes >= 0) /* this is progress */
892 PRIntn iov_index;
893 op->result.code += bytes; /* accumulate the number sent */
894 for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
896 /* how much progress did we make in the i/o vector? */
897 if (bytes < iov[iov_index].iov_len)
899 /* this element's not done yet */
900 char **bp = (char**)&(iov[iov_index].iov_base);
901 iov[iov_index].iov_len -= bytes; /* there's that much left */
902 *bp += bytes; /* starting there */
903 break; /* go off and do that */
905 bytes -= iov[iov_index].iov_len; /* that element's consumed */
907 op->arg2.buffer = &iov[iov_index]; /* new start of array */
908 op->arg3.amount -= iov_index; /* and array length */
909 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
911 else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
913 op->result.code = -1;
914 return PR_TRUE;
916 else return PR_FALSE;
917 } /* pt_writev_cont */
919 static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
921 PRIntn bytes = sendto(
922 op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
923 (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
924 op->syserrno = errno;
925 if (bytes >= 0) /* this is progress */
927 char *bp = (char*)op->arg2.buffer;
928 bp += bytes; /* adjust the buffer pointer */
929 op->arg2.buffer = bp;
930 op->result.code += bytes; /* accumulate the number sent */
931 op->arg3.amount -= bytes; /* and reduce the required count */
932 return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
934 else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
936 op->result.code = -1;
937 return PR_TRUE;
939 else return PR_FALSE;
940 } /* pt_sendto_cont */
942 static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
944 pt_SockLen addr_len = sizeof(PRNetAddr);
945 op->result.code = recvfrom(
946 op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
947 op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
948 op->syserrno = errno;
949 return ((-1 == op->result.code) &&
950 (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
951 PR_FALSE : PR_TRUE;
952 } /* pt_recvfrom_cont */
954 #ifdef AIX
955 static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
957 struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
958 ssize_t rv;
959 unsigned long long saved_file_offset;
960 long long saved_file_bytes;
962 saved_file_offset = sf_struct->file_offset;
963 saved_file_bytes = sf_struct->file_bytes;
964 sf_struct->bytes_sent = 0;
966 if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
967 PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
968 sf_struct->file_size);
969 rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
970 op->syserrno = errno;
972 if (rv != -1) {
973 op->result.code += sf_struct->bytes_sent;
975 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
976 * being updated. So, 'file_bytes' is maintained by NSPR to
977 * avoid conflict when this bug is fixed in AIX, in the future.
979 if (saved_file_bytes != -1)
980 saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
981 sf_struct->file_bytes = saved_file_bytes;
982 } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
983 op->result.code = -1;
984 } else {
985 return PR_FALSE;
988 if (rv == 1) { /* more data to send */
989 return PR_FALSE;
992 return PR_TRUE;
994 #endif /* AIX */
996 #ifdef HPUX11
997 static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
999 struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
1000 int count;
1002 count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
1003 op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
1004 PR_ASSERT(count <= op->nbytes_to_send);
1005 op->syserrno = errno;
1007 if (count != -1) {
1008 op->result.code += count;
1009 } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
1010 op->result.code = -1;
1011 } else {
1012 return PR_FALSE;
1014 if (count != -1 && count < op->nbytes_to_send) {
1015 if (count < hdtrl[0].iov_len) {
1016 /* header not sent */
1018 hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count;
1019 hdtrl[0].iov_len -= count;
1021 } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
1022 /* header sent, file not sent */
1023 PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
1025 hdtrl[0].iov_base = NULL;
1026 hdtrl[0].iov_len = 0;
1028 op->arg3.file_spec.offset += file_nbytes_sent;
1029 op->arg3.file_spec.nbytes -= file_nbytes_sent;
1030 } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
1031 hdtrl[1].iov_len)) {
1032 PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
1033 op->arg3.file_spec.nbytes);
1035 /* header sent, file sent, trailer not sent */
1037 hdtrl[0].iov_base = NULL;
1038 hdtrl[0].iov_len = 0;
1040 * set file offset and len so that no more file data is
1041 * sent
1043 op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
1044 op->arg3.file_spec.nbytes = 0;
1046 hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
1047 hdtrl[1].iov_len -= trailer_nbytes_sent;
1049 op->nbytes_to_send -= count;
1050 return PR_FALSE;
1053 return PR_TRUE;
1055 #endif /* HPUX11 */
1057 #ifdef SOLARIS
1058 static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
1060 struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
1061 size_t xferred;
1062 ssize_t count;
1064 count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
1065 op->syserrno = errno;
1066 PR_ASSERT((count == -1) || (count == xferred));
1068 if (count == -1) {
1069 if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
1070 && op->syserrno != EINTR) {
1071 op->result.code = -1;
1072 return PR_TRUE;
1074 count = xferred;
1075 } else if (count == 0) {
1077 * We are now at EOF. The file was truncated. Solaris sendfile is
1078 * supposed to return 0 and no error in this case, though some versions
1079 * may return -1 and EINVAL .
1081 op->result.code = -1;
1082 op->syserrno = 0; /* will be treated as EOF */
1083 return PR_TRUE;
1085 PR_ASSERT(count <= op->nbytes_to_send);
1087 op->result.code += count;
1088 if (count < op->nbytes_to_send) {
1089 op->nbytes_to_send -= count;
1091 while (count >= vec->sfv_len) {
1092 count -= vec->sfv_len;
1093 vec++;
1094 op->arg3.amount--;
1096 PR_ASSERT(op->arg3.amount > 0);
1098 vec->sfv_off += count;
1099 vec->sfv_len -= count;
1100 PR_ASSERT(vec->sfv_len > 0);
1101 op->arg2.buffer = vec;
1103 return PR_FALSE;
1106 return PR_TRUE;
1108 #endif /* SOLARIS */
1110 #ifdef LINUX
1111 static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
1113 ssize_t rv;
1114 off_t oldoffset;
1116 oldoffset = op->offset;
1117 rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
1118 op->syserrno = errno;
1120 if (rv == -1) {
1121 if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
1122 op->result.code = -1;
1123 return PR_TRUE;
1125 rv = 0;
1127 PR_ASSERT(rv == op->offset - oldoffset);
1128 op->result.code += rv;
1129 if (rv < op->count) {
1130 op->count -= rv;
1131 return PR_FALSE;
1133 return PR_TRUE;
1135 #endif /* LINUX */
1137 void _PR_InitIO(void)
1139 #if defined(DEBUG)
1140 memset(&pt_debug, 0, sizeof(PTDebug));
1141 pt_debug.timeStarted = PR_Now();
1142 #endif
1144 _pr_flock_lock = PR_NewLock();
1145 PR_ASSERT(NULL != _pr_flock_lock);
1146 _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
1147 PR_ASSERT(NULL != _pr_flock_cv);
1148 _pr_rename_lock = PR_NewLock();
1149 PR_ASSERT(NULL != _pr_rename_lock);
1151 _PR_InitFdCache(); /* do that */
1153 _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1154 _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1155 _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
1156 PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
1158 #ifdef _PR_IPV6_V6ONLY_PROBE
1159 /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
1160 * is turned on by default, contrary to what RFC 3493, Section
1161 * 5.3 says. So we have to turn it off. Find out whether we
1162 * are running on such a system.
1165 int osfd;
1166 osfd = socket(AF_INET6, SOCK_STREAM, 0);
1167 if (osfd != -1) {
1168 int on;
1169 int optlen = sizeof(on);
1170 if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
1171 &on, &optlen) == 0) {
1172 _pr_ipv6_v6only_on_by_default = on;
1174 close(osfd);
1177 #endif
1178 } /* _PR_InitIO */
1180 void _PR_CleanupIO(void)
1182 _PR_Putfd(_pr_stdin);
1183 _pr_stdin = NULL;
1184 _PR_Putfd(_pr_stdout);
1185 _pr_stdout = NULL;
1186 _PR_Putfd(_pr_stderr);
1187 _pr_stderr = NULL;
1189 _PR_CleanupFdCache();
1191 if (_pr_flock_cv)
1193 PR_DestroyCondVar(_pr_flock_cv);
1194 _pr_flock_cv = NULL;
1196 if (_pr_flock_lock)
1198 PR_DestroyLock(_pr_flock_lock);
1199 _pr_flock_lock = NULL;
1201 if (_pr_rename_lock)
1203 PR_DestroyLock(_pr_rename_lock);
1204 _pr_rename_lock = NULL;
1206 } /* _PR_CleanupIO */
1208 PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
1210 PRFileDesc *result = NULL;
1211 PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
1213 if (!_pr_initialized) _PR_ImplicitInitialization();
1215 switch (osfd)
1217 case PR_StandardInput: result = _pr_stdin; break;
1218 case PR_StandardOutput: result = _pr_stdout; break;
1219 case PR_StandardError: result = _pr_stderr; break;
1220 default:
1221 (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1223 return result;
1224 } /* PR_GetSpecialFD */
1226 /*****************************************************************************/
1227 /***************************** I/O private methods ***************************/
1228 /*****************************************************************************/
1230 static PRBool pt_TestAbort(void)
1232 PRThread *me = PR_GetCurrentThread();
1233 if(_PT_THREAD_INTERRUPTED(me))
1235 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
1236 me->state &= ~PT_THREAD_ABORTED;
1237 return PR_TRUE;
1239 return PR_FALSE;
1240 } /* pt_TestAbort */
1242 static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
1244 switch (syserrno)
1246 case EINTR:
1247 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
1248 case ETIMEDOUT:
1249 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
1250 default:
1251 mapper(syserrno);
1253 } /* pt_MapError */
1255 static PRStatus pt_Close(PRFileDesc *fd)
1257 if ((NULL == fd) || (NULL == fd->secret)
1258 || ((_PR_FILEDESC_OPEN != fd->secret->state)
1259 && (_PR_FILEDESC_CLOSED != fd->secret->state)))
1261 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1262 return PR_FAILURE;
1264 if (pt_TestAbort()) return PR_FAILURE;
1266 if (_PR_FILEDESC_OPEN == fd->secret->state)
1268 if (-1 == close(fd->secret->md.osfd))
1270 #ifdef OSF1
1272 * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
1273 * system call, when called to close a TCP socket, may
1274 * return -1 with errno set to EINVAL but the system call
1275 * does close the socket successfully. An application
1276 * may safely ignore the EINVAL error. This bug is fixed
1277 * on Tru64 UNIX V5.1A and later. The defect tracking
1278 * number is QAR 81431.
1280 if (PR_DESC_SOCKET_TCP != fd->methods->file_type
1281 || EINVAL != errno)
1283 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
1284 return PR_FAILURE;
1286 #else
1287 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
1288 return PR_FAILURE;
1289 #endif
1291 fd->secret->state = _PR_FILEDESC_CLOSED;
1293 _PR_Putfd(fd);
1294 return PR_SUCCESS;
1295 } /* pt_Close */
1297 static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
1299 PRInt32 syserrno, bytes = -1;
1301 if (pt_TestAbort()) return bytes;
1303 bytes = read(fd->secret->md.osfd, buf, amount);
1304 syserrno = errno;
1306 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
1307 && (!fd->secret->nonblocking))
1309 pt_Continuation op;
1310 op.arg1.osfd = fd->secret->md.osfd;
1311 op.arg2.buffer = buf;
1312 op.arg3.amount = amount;
1313 op.timeout = PR_INTERVAL_NO_TIMEOUT;
1314 op.function = pt_read_cont;
1315 op.event = POLLIN | POLLPRI;
1316 bytes = pt_Continue(&op);
1317 syserrno = op.syserrno;
1319 if (bytes < 0)
1320 pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
1321 return bytes;
1322 } /* pt_Read */
1324 static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
1326 PRInt32 syserrno, bytes = -1;
1327 PRBool fNeedContinue = PR_FALSE;
1329 if (pt_TestAbort()) return bytes;
1331 bytes = write(fd->secret->md.osfd, buf, amount);
1332 syserrno = errno;
1334 if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
1336 buf = (char *) buf + bytes;
1337 amount -= bytes;
1338 fNeedContinue = PR_TRUE;
1340 if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
1341 && (!fd->secret->nonblocking) )
1343 bytes = 0;
1344 fNeedContinue = PR_TRUE;
1347 if (fNeedContinue == PR_TRUE)
1349 pt_Continuation op;
1350 op.arg1.osfd = fd->secret->md.osfd;
1351 op.arg2.buffer = (void*)buf;
1352 op.arg3.amount = amount;
1353 op.timeout = PR_INTERVAL_NO_TIMEOUT;
1354 op.result.code = bytes; /* initialize the number sent */
1355 op.function = pt_write_cont;
1356 op.event = POLLOUT | POLLPRI;
1357 bytes = pt_Continue(&op);
1358 syserrno = op.syserrno;
1360 if (bytes == -1)
1361 pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
1362 return bytes;
1363 } /* pt_Write */
1365 static PRInt32 pt_Writev(
1366 PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
1368 PRIntn iov_index;
1369 PRBool fNeedContinue = PR_FALSE;
1370 PRInt32 syserrno, bytes, rv = -1;
1371 struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
1372 int osiov_len;
1374 if (pt_TestAbort()) return rv;
1376 /* Ensured by PR_Writev */
1377 PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
1380 * We can't pass iov to writev because PRIOVec and struct iovec
1381 * may not be binary compatible. Make osiov a copy of iov and
1382 * pass osiov to writev. We can modify osiov if we need to
1383 * continue the operation.
1385 osiov = osiov_local;
1386 osiov_len = iov_len;
1387 for (iov_index = 0; iov_index < osiov_len; iov_index++)
1389 osiov[iov_index].iov_base = iov[iov_index].iov_base;
1390 osiov[iov_index].iov_len = iov[iov_index].iov_len;
1393 rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
1394 syserrno = errno;
1396 if (!fd->secret->nonblocking)
1398 if (bytes >= 0)
1401 * If we moved some bytes, how does that implicate the
1402 * i/o vector list? In other words, exactly where are
1403 * we within that array? What are the parameters for
1404 * resumption? Maybe we're done!
1406 for ( ;osiov_len > 0; osiov++, osiov_len--)
1408 if (bytes < osiov->iov_len)
1410 /* this one's not done yet */
1411 osiov->iov_base = (char*)osiov->iov_base + bytes;
1412 osiov->iov_len -= bytes;
1413 break; /* go off and do that */
1415 bytes -= osiov->iov_len; /* this one's done cooked */
1417 PR_ASSERT(osiov_len > 0 || bytes == 0);
1418 if (osiov_len > 0)
1420 if (PR_INTERVAL_NO_WAIT == timeout)
1422 rv = -1;
1423 syserrno = ETIMEDOUT;
1425 else fNeedContinue = PR_TRUE;
1428 else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
1430 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
1431 else
1433 rv = 0;
1434 fNeedContinue = PR_TRUE;
1439 if (fNeedContinue == PR_TRUE)
1441 pt_Continuation op;
1443 op.arg1.osfd = fd->secret->md.osfd;
1444 op.arg2.buffer = (void*)osiov;
1445 op.arg3.amount = osiov_len;
1446 op.timeout = timeout;
1447 op.result.code = rv;
1448 op.function = pt_writev_cont;
1449 op.event = POLLOUT | POLLPRI;
1450 rv = pt_Continue(&op);
1451 syserrno = op.syserrno;
1453 if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
1454 return rv;
1455 } /* pt_Writev */
1457 static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
1459 return _PR_MD_LSEEK(fd, offset, whence);
1460 } /* pt_Seek */
1462 static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
1464 return _PR_MD_LSEEK64(fd, offset, whence);
1465 } /* pt_Seek64 */
1467 static PRInt32 pt_Available_f(PRFileDesc *fd)
1469 PRInt32 result, cur, end;
1471 cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
1473 if (cur >= 0)
1474 end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
1476 if ((cur < 0) || (end < 0)) {
1477 return -1;
1480 result = end - cur;
1481 _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
1483 return result;
1484 } /* pt_Available_f */
1486 static PRInt64 pt_Available64_f(PRFileDesc *fd)
1488 PRInt64 result, cur, end;
1489 PRInt64 minus_one;
1491 LL_I2L(minus_one, -1);
1492 cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
1494 if (LL_GE_ZERO(cur))
1495 end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
1497 if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
1499 LL_SUB(result, end, cur);
1500 (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
1502 return result;
1503 } /* pt_Available64_f */
1505 static PRInt32 pt_Available_s(PRFileDesc *fd)
1507 PRInt32 rv, bytes = -1;
1508 if (pt_TestAbort()) return bytes;
1510 rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
1512 if (rv == -1)
1513 pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
1514 return bytes;
1515 } /* pt_Available_s */
1517 static PRInt64 pt_Available64_s(PRFileDesc *fd)
1519 PRInt64 rv;
1520 LL_I2L(rv, pt_Available_s(fd));
1521 return rv;
1522 } /* pt_Available64_s */
1524 static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
1526 PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
1527 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
1528 } /* pt_FileInfo */
1530 static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
1532 PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
1533 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
1534 } /* pt_FileInfo64 */
1536 static PRStatus pt_Synch(PRFileDesc *fd)
1538 return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
1539 } /* pt_Synch */
1541 static PRStatus pt_Fsync(PRFileDesc *fd)
1543 PRIntn rv = -1;
1544 if (pt_TestAbort()) return PR_FAILURE;
1546 rv = fsync(fd->secret->md.osfd);
1547 if (rv < 0) {
1548 pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
1549 return PR_FAILURE;
1551 return PR_SUCCESS;
1552 } /* pt_Fsync */
1554 static PRStatus pt_Connect(
1555 PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
1557 PRIntn rv = -1, syserrno;
1558 pt_SockLen addr_len;
1559 const PRNetAddr *addrp = addr;
1560 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1561 PRUint16 md_af = addr->raw.family;
1562 PRNetAddr addrCopy;
1563 #endif
1565 if (pt_TestAbort()) return PR_FAILURE;
1567 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1568 addr_len = PR_NETADDR_SIZE(addr);
1569 #if defined(_PR_INET6)
1570 if (addr->raw.family == PR_AF_INET6) {
1571 md_af = AF_INET6;
1572 #ifndef _PR_HAVE_SOCKADDR_LEN
1573 addrCopy = *addr;
1574 addrCopy.raw.family = AF_INET6;
1575 addrp = &addrCopy;
1576 #endif
1578 #endif
1580 #ifdef _PR_HAVE_SOCKADDR_LEN
1581 addrCopy = *addr;
1582 ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
1583 ((struct sockaddr*)&addrCopy)->sa_family = md_af;
1584 addrp = &addrCopy;
1585 #endif
1586 rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
1587 syserrno = errno;
1588 if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
1590 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
1591 else
1593 pt_Continuation op;
1594 op.arg1.osfd = fd->secret->md.osfd;
1595 op.arg2.buffer = (void*)addrp;
1596 op.arg3.amount = addr_len;
1597 op.timeout = timeout;
1598 op.function = pt_connect_cont;
1599 op.event = POLLOUT | POLLPRI;
1600 rv = pt_Continue(&op);
1601 syserrno = op.syserrno;
1604 if (-1 == rv) {
1605 pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
1606 return PR_FAILURE;
1608 return PR_SUCCESS;
1609 } /* pt_Connect */
1611 static PRStatus pt_ConnectContinue(
1612 PRFileDesc *fd, PRInt16 out_flags)
1614 int err;
1615 PRInt32 osfd;
1617 if (out_flags & PR_POLL_NVAL)
1619 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1620 return PR_FAILURE;
1622 if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0)
1624 PR_ASSERT(out_flags == 0);
1625 PR_SetError(PR_IN_PROGRESS_ERROR, 0);
1626 return PR_FAILURE;
1629 osfd = fd->secret->md.osfd;
1631 err = _MD_unix_get_nonblocking_connect_error(osfd);
1632 if (err != 0)
1634 _PR_MD_MAP_CONNECT_ERROR(err);
1635 return PR_FAILURE;
1637 return PR_SUCCESS;
1638 } /* pt_ConnectContinue */
1640 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
1642 /* Find the NSPR layer and invoke its connectcontinue method */
1643 PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
1645 if (NULL == bottom)
1647 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1648 return PR_FAILURE;
1650 return pt_ConnectContinue(bottom, pd->out_flags);
1651 } /* PR_GetConnectStatus */
1653 static PRFileDesc* pt_Accept(
1654 PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
1656 PRFileDesc *newfd = NULL;
1657 PRIntn syserrno, osfd = -1;
1658 pt_SockLen addr_len = sizeof(PRNetAddr);
1660 if (pt_TestAbort()) return newfd;
1662 #ifdef _PR_STRICT_ADDR_LEN
1663 if (addr)
1666 * Set addr->raw.family just so that we can use the
1667 * PR_NETADDR_SIZE macro.
1669 addr->raw.family = fd->secret->af;
1670 addr_len = PR_NETADDR_SIZE(addr);
1672 #endif
1674 osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
1675 syserrno = errno;
1677 if (osfd == -1)
1679 if (fd->secret->nonblocking) goto failed;
1681 if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
1682 && ECONNABORTED != syserrno)
1683 goto failed;
1684 else
1686 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
1687 else
1689 pt_Continuation op;
1690 op.arg1.osfd = fd->secret->md.osfd;
1691 op.arg2.buffer = addr;
1692 op.arg3.addr_len = &addr_len;
1693 op.timeout = timeout;
1694 op.function = pt_accept_cont;
1695 op.event = POLLIN | POLLPRI;
1696 osfd = pt_Continue(&op);
1697 syserrno = op.syserrno;
1699 if (osfd < 0) goto failed;
1702 #ifdef _PR_HAVE_SOCKADDR_LEN
1703 /* ignore the sa_len field of struct sockaddr */
1704 if (addr)
1706 addr->raw.family = ((struct sockaddr*)addr)->sa_family;
1708 #endif /* _PR_HAVE_SOCKADDR_LEN */
1709 #ifdef _PR_INET6
1710 if (addr && (AF_INET6 == addr->raw.family))
1711 addr->raw.family = PR_AF_INET6;
1712 #endif
1713 newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
1714 if (newfd == NULL) close(osfd); /* $$$ whoops! this doesn't work $$$ */
1715 else
1717 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1718 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
1719 #ifdef LINUX
1721 * On Linux, experiments showed that the accepted sockets
1722 * inherit the TCP_NODELAY socket option of the listening
1723 * socket.
1725 newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
1726 #endif
1728 return newfd;
1730 failed:
1731 pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
1732 return NULL;
1733 } /* pt_Accept */
1735 static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
1737 PRIntn rv;
1738 pt_SockLen addr_len;
1739 const PRNetAddr *addrp = addr;
1740 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1741 PRUint16 md_af = addr->raw.family;
1742 PRNetAddr addrCopy;
1743 #endif
1745 if (pt_TestAbort()) return PR_FAILURE;
1747 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1748 if (addr->raw.family == AF_UNIX)
1750 /* Disallow relative pathnames */
1751 if (addr->local.path[0] != '/')
1753 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1754 return PR_FAILURE;
1758 #if defined(_PR_INET6)
1759 if (addr->raw.family == PR_AF_INET6) {
1760 md_af = AF_INET6;
1761 #ifndef _PR_HAVE_SOCKADDR_LEN
1762 addrCopy = *addr;
1763 addrCopy.raw.family = AF_INET6;
1764 addrp = &addrCopy;
1765 #endif
1767 #endif
1769 addr_len = PR_NETADDR_SIZE(addr);
1770 #ifdef _PR_HAVE_SOCKADDR_LEN
1771 addrCopy = *addr;
1772 ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
1773 ((struct sockaddr*)&addrCopy)->sa_family = md_af;
1774 addrp = &addrCopy;
1775 #endif
1776 rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
1778 if (rv == -1) {
1779 pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
1780 return PR_FAILURE;
1782 return PR_SUCCESS;
1783 } /* pt_Bind */
1785 static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
1787 PRIntn rv;
1789 if (pt_TestAbort()) return PR_FAILURE;
1791 rv = listen(fd->secret->md.osfd, backlog);
1792 if (rv == -1) {
1793 pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
1794 return PR_FAILURE;
1796 return PR_SUCCESS;
1797 } /* pt_Listen */
1799 static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
1801 PRIntn rv = -1;
1802 if (pt_TestAbort()) return PR_FAILURE;
1804 rv = shutdown(fd->secret->md.osfd, how);
1806 if (rv == -1) {
1807 pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
1808 return PR_FAILURE;
1810 return PR_SUCCESS;
1811 } /* pt_Shutdown */
1813 static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
1815 *out_flags = 0;
1816 return in_flags;
1817 } /* pt_Poll */
1819 static PRInt32 pt_Recv(
1820 PRFileDesc *fd, void *buf, PRInt32 amount,
1821 PRIntn flags, PRIntervalTime timeout)
1823 PRInt32 syserrno, bytes = -1;
1824 PRIntn osflags;
1826 if (0 == flags)
1827 osflags = 0;
1828 else if (PR_MSG_PEEK == flags)
1829 osflags = MSG_PEEK;
1830 else
1832 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1833 return bytes;
1836 if (pt_TestAbort()) return bytes;
1838 /* recv() is a much slower call on pre-2.6 Solaris than read(). */
1839 #if defined(SOLARIS)
1840 if (0 == osflags)
1841 bytes = read(fd->secret->md.osfd, buf, amount);
1842 else
1843 bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
1844 #else
1845 bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
1846 #endif
1847 syserrno = errno;
1849 if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
1850 && (!fd->secret->nonblocking))
1852 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
1853 else
1855 pt_Continuation op;
1856 op.arg1.osfd = fd->secret->md.osfd;
1857 op.arg2.buffer = buf;
1858 op.arg3.amount = amount;
1859 op.arg4.flags = osflags;
1860 op.timeout = timeout;
1861 op.function = pt_recv_cont;
1862 op.event = POLLIN | POLLPRI;
1863 bytes = pt_Continue(&op);
1864 syserrno = op.syserrno;
1867 if (bytes < 0)
1868 pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
1869 return bytes;
1870 } /* pt_Recv */
1872 static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
1874 return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1875 } /* pt_SocketRead */
1877 static PRInt32 pt_Send(
1878 PRFileDesc *fd, const void *buf, PRInt32 amount,
1879 PRIntn flags, PRIntervalTime timeout)
1881 PRInt32 syserrno, bytes = -1;
1882 PRBool fNeedContinue = PR_FALSE;
1883 #if defined(SOLARIS)
1884 PRInt32 tmp_amount = amount;
1885 #endif
1888 * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
1889 * which has the following:
1890 * # define send cma_send
1891 * extern int cma_send (int , void *, int, int );
1892 * So we need to cast away the 'const' of argument #2 for send().
1894 #if defined (HPUX) && defined(_PR_DCETHREADS)
1895 #define PT_SENDBUF_CAST (void *)
1896 #else
1897 #define PT_SENDBUF_CAST
1898 #endif
1900 if (pt_TestAbort()) return bytes;
1903 * On pre-2.6 Solaris, send() is much slower than write().
1904 * On 2.6 and beyond, with in-kernel sockets, send() and
1905 * write() are fairly equivalent in performance.
1907 #if defined(SOLARIS)
1908 PR_ASSERT(0 == flags);
1909 retry:
1910 bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
1911 #else
1912 bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
1913 #endif
1914 syserrno = errno;
1916 #if defined(SOLARIS)
1918 * The write system call has been reported to return the ERANGE error
1919 * on occasion. Try to write in smaller chunks to workaround this bug.
1921 if ((bytes == -1) && (syserrno == ERANGE))
1923 if (tmp_amount > 1)
1925 tmp_amount = tmp_amount/2; /* half the bytes */
1926 goto retry;
1929 #endif
1931 if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
1933 if (PR_INTERVAL_NO_WAIT == timeout)
1935 bytes = -1;
1936 syserrno = ETIMEDOUT;
1938 else
1940 buf = (char *) buf + bytes;
1941 amount -= bytes;
1942 fNeedContinue = PR_TRUE;
1945 if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
1946 && (!fd->secret->nonblocking) )
1948 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
1949 else
1951 bytes = 0;
1952 fNeedContinue = PR_TRUE;
1956 if (fNeedContinue == PR_TRUE)
1958 pt_Continuation op;
1959 op.arg1.osfd = fd->secret->md.osfd;
1960 op.arg2.buffer = (void*)buf;
1961 op.arg3.amount = amount;
1962 op.arg4.flags = flags;
1963 op.timeout = timeout;
1964 op.result.code = bytes; /* initialize the number sent */
1965 op.function = pt_send_cont;
1966 op.event = POLLOUT | POLLPRI;
1967 bytes = pt_Continue(&op);
1968 syserrno = op.syserrno;
1970 if (bytes == -1)
1971 pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
1972 return bytes;
1973 } /* pt_Send */
1975 static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
1977 return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1978 } /* pt_SocketWrite */
1980 static PRInt32 pt_SendTo(
1981 PRFileDesc *fd, const void *buf,
1982 PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
1983 PRIntervalTime timeout)
1985 PRInt32 syserrno, bytes = -1;
1986 PRBool fNeedContinue = PR_FALSE;
1987 pt_SockLen addr_len;
1988 const PRNetAddr *addrp = addr;
1989 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
1990 PRUint16 md_af = addr->raw.family;
1991 PRNetAddr addrCopy;
1992 #endif
1994 if (pt_TestAbort()) return bytes;
1996 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
1997 #if defined(_PR_INET6)
1998 if (addr->raw.family == PR_AF_INET6) {
1999 md_af = AF_INET6;
2000 #ifndef _PR_HAVE_SOCKADDR_LEN
2001 addrCopy = *addr;
2002 addrCopy.raw.family = AF_INET6;
2003 addrp = &addrCopy;
2004 #endif
2006 #endif
2008 addr_len = PR_NETADDR_SIZE(addr);
2009 #ifdef _PR_HAVE_SOCKADDR_LEN
2010 addrCopy = *addr;
2011 ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
2012 ((struct sockaddr*)&addrCopy)->sa_family = md_af;
2013 addrp = &addrCopy;
2014 #endif
2015 bytes = sendto(
2016 fd->secret->md.osfd, buf, amount, flags,
2017 (struct sockaddr*)addrp, addr_len);
2018 syserrno = errno;
2019 if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
2020 && (!fd->secret->nonblocking) )
2022 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
2023 else fNeedContinue = PR_TRUE;
2025 if (fNeedContinue == PR_TRUE)
2027 pt_Continuation op;
2028 op.arg1.osfd = fd->secret->md.osfd;
2029 op.arg2.buffer = (void*)buf;
2030 op.arg3.amount = amount;
2031 op.arg4.flags = flags;
2032 op.arg5.addr = (PRNetAddr*)addrp;
2033 op.timeout = timeout;
2034 op.result.code = 0; /* initialize the number sent */
2035 op.function = pt_sendto_cont;
2036 op.event = POLLOUT | POLLPRI;
2037 bytes = pt_Continue(&op);
2038 syserrno = op.syserrno;
2040 if (bytes < 0)
2041 pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
2042 return bytes;
2043 } /* pt_SendTo */
2045 static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
2046 PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
2048 PRBool fNeedContinue = PR_FALSE;
2049 PRInt32 syserrno, bytes = -1;
2050 pt_SockLen addr_len = sizeof(PRNetAddr);
2052 if (pt_TestAbort()) return bytes;
2054 bytes = recvfrom(
2055 fd->secret->md.osfd, buf, amount, flags,
2056 (struct sockaddr*)addr, &addr_len);
2057 syserrno = errno;
2059 if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
2060 && (!fd->secret->nonblocking) )
2062 if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
2063 else fNeedContinue = PR_TRUE;
2066 if (fNeedContinue == PR_TRUE)
2068 pt_Continuation op;
2069 op.arg1.osfd = fd->secret->md.osfd;
2070 op.arg2.buffer = buf;
2071 op.arg3.amount = amount;
2072 op.arg4.flags = flags;
2073 op.arg5.addr = addr;
2074 op.timeout = timeout;
2075 op.function = pt_recvfrom_cont;
2076 op.event = POLLIN | POLLPRI;
2077 bytes = pt_Continue(&op);
2078 syserrno = op.syserrno;
2080 #ifdef _PR_HAVE_SOCKADDR_LEN
2081 if (bytes >= 0)
2083 /* ignore the sa_len field of struct sockaddr */
2084 if (addr)
2086 addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2089 #endif /* _PR_HAVE_SOCKADDR_LEN */
2090 #ifdef _PR_INET6
2091 if (addr && (AF_INET6 == addr->raw.family))
2092 addr->raw.family = PR_AF_INET6;
2093 #endif
2094 if (bytes < 0)
2095 pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
2096 return bytes;
2097 } /* pt_RecvFrom */
2099 #ifdef AIX
2100 #ifndef HAVE_SEND_FILE
2101 static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
2103 static void pt_aix_sendfile_init_routine(void)
2105 void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
2106 pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
2107 dlclose(handle);
2111 * pt_AIXDispatchSendFile
2113 static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2114 PRTransmitFileFlags flags, PRIntervalTime timeout)
2116 int rv;
2118 rv = pthread_once(&pt_aix_sendfile_once_block,
2119 pt_aix_sendfile_init_routine);
2120 PR_ASSERT(0 == rv);
2121 if (pt_aix_sendfile_fptr) {
2122 return pt_AIXSendFile(sd, sfd, flags, timeout);
2123 } else {
2124 return PR_EmulateSendFile(sd, sfd, flags, timeout);
2127 #endif /* !HAVE_SEND_FILE */
2131 * pt_AIXSendFile
2133 * Send file sfd->fd across socket sd. If specified, header and trailer
2134 * buffers are sent before and after the file, respectively.
2136 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2138 * return number of bytes sent or -1 on error
2140 * This implementation takes advantage of the send_file() system
2141 * call available in AIX 4.3.2.
2144 static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2145 PRTransmitFileFlags flags, PRIntervalTime timeout)
2147 struct sf_parms sf_struct;
2148 uint_t send_flags;
2149 ssize_t rv;
2150 int syserrno;
2151 PRInt32 count;
2152 unsigned long long saved_file_offset;
2153 long long saved_file_bytes;
2155 sf_struct.header_data = (void *) sfd->header; /* cast away the 'const' */
2156 sf_struct.header_length = sfd->hlen;
2157 sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
2158 sf_struct.file_size = 0;
2159 sf_struct.file_offset = sfd->file_offset;
2160 if (sfd->file_nbytes == 0)
2161 sf_struct.file_bytes = -1;
2162 else
2163 sf_struct.file_bytes = sfd->file_nbytes;
2164 sf_struct.trailer_data = (void *) sfd->trailer;
2165 sf_struct.trailer_length = sfd->tlen;
2166 sf_struct.bytes_sent = 0;
2168 saved_file_offset = sf_struct.file_offset;
2169 saved_file_bytes = sf_struct.file_bytes;
2171 send_flags = 0; /* flags processed at the end */
2173 /* The first argument to send_file() is int*. */
2174 PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
2175 do {
2176 rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
2177 } while (rv == -1 && (syserrno = errno) == EINTR);
2179 if (rv == -1) {
2180 if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
2181 count = 0; /* Not a real error. Need to continue. */
2182 } else {
2183 count = -1;
2185 } else {
2186 count = sf_struct.bytes_sent;
2188 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
2189 * being updated. So, 'file_bytes' is maintained by NSPR to
2190 * avoid conflict when this bug is fixed in AIX, in the future.
2192 if (saved_file_bytes != -1)
2193 saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
2194 sf_struct.file_bytes = saved_file_bytes;
2197 if ((rv == 1) || ((rv == -1) && (count == 0))) {
2198 pt_Continuation op;
2200 op.arg1.osfd = sd->secret->md.osfd;
2201 op.arg2.buffer = &sf_struct;
2202 op.arg4.flags = send_flags;
2203 op.result.code = count;
2204 op.timeout = timeout;
2205 op.function = pt_aix_sendfile_cont;
2206 op.event = POLLOUT | POLLPRI;
2207 count = pt_Continue(&op);
2208 syserrno = op.syserrno;
2211 if (count == -1) {
2212 pt_MapError(_MD_aix_map_sendfile_error, syserrno);
2213 return -1;
2215 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2216 PR_Close(sd);
2218 PR_ASSERT(count == (sfd->hlen + sfd->tlen +
2219 ((sfd->file_nbytes == 0) ?
2220 sf_struct.file_size - sfd->file_offset :
2221 sfd->file_nbytes)));
2222 return count;
2224 #endif /* AIX */
2226 #ifdef HPUX11
2228 * pt_HPUXSendFile
2230 * Send file sfd->fd across socket sd. If specified, header and trailer
2231 * buffers are sent before and after the file, respectively.
2233 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2235 * return number of bytes sent or -1 on error
2237 * This implementation takes advantage of the sendfile() system
2238 * call available in HP-UX B.11.00.
2241 static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2242 PRTransmitFileFlags flags, PRIntervalTime timeout)
2244 struct stat statbuf;
2245 size_t nbytes_to_send, file_nbytes_to_send;
2246 struct iovec hdtrl[2]; /* optional header and trailer buffers */
2247 int send_flags;
2248 PRInt32 count;
2249 int syserrno;
2251 if (sfd->file_nbytes == 0) {
2252 /* Get file size */
2253 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2254 _PR_MD_MAP_FSTAT_ERROR(errno);
2255 return -1;
2257 file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2258 } else {
2259 file_nbytes_to_send = sfd->file_nbytes;
2261 nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
2263 hdtrl[0].iov_base = (void *) sfd->header; /* cast away the 'const' */
2264 hdtrl[0].iov_len = sfd->hlen;
2265 hdtrl[1].iov_base = (void *) sfd->trailer;
2266 hdtrl[1].iov_len = sfd->tlen;
2268 * SF_DISCONNECT seems to close the socket even if sendfile()
2269 * only does a partial send on a nonblocking socket. This
2270 * would prevent the subsequent sendfile() calls on that socket
2271 * from working. So we don't use the SD_DISCONNECT flag.
2273 send_flags = 0;
2275 do {
2276 count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
2277 sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
2278 } while (count == -1 && (syserrno = errno) == EINTR);
2280 if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
2281 count = 0;
2283 if (count != -1 && count < nbytes_to_send) {
2284 pt_Continuation op;
2286 if (count < sfd->hlen) {
2287 /* header not sent */
2289 hdtrl[0].iov_base = ((char *) sfd->header) + count;
2290 hdtrl[0].iov_len = sfd->hlen - count;
2291 op.arg3.file_spec.offset = sfd->file_offset;
2292 op.arg3.file_spec.nbytes = file_nbytes_to_send;
2293 } else if (count < (sfd->hlen + file_nbytes_to_send)) {
2294 /* header sent, file not sent */
2296 hdtrl[0].iov_base = NULL;
2297 hdtrl[0].iov_len = 0;
2299 op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
2300 op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
2301 } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
2302 PRUint32 trailer_nbytes_sent;
2304 /* header sent, file sent, trailer not sent */
2306 hdtrl[0].iov_base = NULL;
2307 hdtrl[0].iov_len = 0;
2309 * set file offset and len so that no more file data is
2310 * sent
2312 op.arg3.file_spec.offset = statbuf.st_size;
2313 op.arg3.file_spec.nbytes = 0;
2315 trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
2316 hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
2317 hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
2320 op.arg1.osfd = sd->secret->md.osfd;
2321 op.filedesc = sfd->fd->secret->md.osfd;
2322 op.arg2.buffer = hdtrl;
2323 op.arg3.file_spec.st_size = statbuf.st_size;
2324 op.arg4.flags = send_flags;
2325 op.nbytes_to_send = nbytes_to_send - count;
2326 op.result.code = count;
2327 op.timeout = timeout;
2328 op.function = pt_hpux_sendfile_cont;
2329 op.event = POLLOUT | POLLPRI;
2330 count = pt_Continue(&op);
2331 syserrno = op.syserrno;
2334 if (count == -1) {
2335 pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
2336 return -1;
2338 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2339 PR_Close(sd);
2341 PR_ASSERT(count == nbytes_to_send);
2342 return count;
2345 #endif /* HPUX11 */
2347 #ifdef SOLARIS
2350 * pt_SolarisSendFile
2352 * Send file sfd->fd across socket sd. If specified, header and trailer
2353 * buffers are sent before and after the file, respectively.
2355 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2357 * return number of bytes sent or -1 on error
2359 * This implementation takes advantage of the sendfilev() system
2360 * call available in Solaris 8.
2363 static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2364 PRTransmitFileFlags flags, PRIntervalTime timeout)
2366 struct stat statbuf;
2367 size_t nbytes_to_send, file_nbytes_to_send;
2368 struct sendfilevec sfv_struct[3];
2369 int sfvcnt = 0;
2370 size_t xferred;
2371 PRInt32 count;
2372 int syserrno;
2374 if (sfd->file_nbytes == 0) {
2375 /* Get file size */
2376 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2377 _PR_MD_MAP_FSTAT_ERROR(errno);
2378 return -1;
2380 file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2381 } else {
2382 file_nbytes_to_send = sfd->file_nbytes;
2385 nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
2387 if (sfd->hlen != 0) {
2388 sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
2389 sfv_struct[sfvcnt].sfv_flag = 0;
2390 sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header;
2391 sfv_struct[sfvcnt].sfv_len = sfd->hlen;
2392 sfvcnt++;
2395 if (file_nbytes_to_send != 0) {
2396 sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
2397 sfv_struct[sfvcnt].sfv_flag = 0;
2398 sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
2399 sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
2400 sfvcnt++;
2403 if (sfd->tlen != 0) {
2404 sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
2405 sfv_struct[sfvcnt].sfv_flag = 0;
2406 sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer;
2407 sfv_struct[sfvcnt].sfv_len = sfd->tlen;
2408 sfvcnt++;
2411 if (0 == sfvcnt) {
2412 count = 0;
2413 goto done;
2417 * Strictly speaking, we may have sent some bytes when the
2418 * sendfilev() is interrupted and we should retry it from an
2419 * updated offset. We are not doing that here.
2421 count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
2422 sfvcnt, &xferred);
2424 PR_ASSERT((count == -1) || (count == xferred));
2426 if (count == -1) {
2427 syserrno = errno;
2428 if (syserrno == EINTR
2429 || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
2430 count = xferred;
2432 } else if (count == 0) {
2434 * We are now at EOF. The file was truncated. Solaris sendfile is
2435 * supposed to return 0 and no error in this case, though some versions
2436 * may return -1 and EINVAL .
2438 count = -1;
2439 syserrno = 0; /* will be treated as EOF */
2442 if (count != -1 && count < nbytes_to_send) {
2443 pt_Continuation op;
2444 struct sendfilevec *vec = sfv_struct;
2445 PRInt32 rem = count;
2447 while (rem >= vec->sfv_len) {
2448 rem -= vec->sfv_len;
2449 vec++;
2450 sfvcnt--;
2452 PR_ASSERT(sfvcnt > 0);
2454 vec->sfv_off += rem;
2455 vec->sfv_len -= rem;
2456 PR_ASSERT(vec->sfv_len > 0);
2458 op.arg1.osfd = sd->secret->md.osfd;
2459 op.arg2.buffer = vec;
2460 op.arg3.amount = sfvcnt;
2461 op.arg4.flags = 0;
2462 op.nbytes_to_send = nbytes_to_send - count;
2463 op.result.code = count;
2464 op.timeout = timeout;
2465 op.function = pt_solaris_sendfile_cont;
2466 op.event = POLLOUT | POLLPRI;
2467 count = pt_Continue(&op);
2468 syserrno = op.syserrno;
2471 done:
2472 if (count == -1) {
2473 pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
2474 return -1;
2476 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2477 PR_Close(sd);
2479 PR_ASSERT(count == nbytes_to_send);
2480 return count;
2483 #ifndef HAVE_SENDFILEV
2484 static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
2486 static void pt_solaris_sendfilev_init_routine(void)
2488 void *handle;
2489 PRBool close_it = PR_FALSE;
2492 * We do not want to unload libsendfile.so. This handle is leaked
2493 * intentionally.
2495 handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
2496 PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
2497 ("dlopen(libsendfile.so) returns %p", handle));
2499 if (NULL == handle) {
2501 * The dlopen(0, mode) call is to allow for the possibility that
2502 * sendfilev() may become part of a standard system library in a
2503 * future Solaris release.
2505 handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
2506 PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
2507 ("dlopen(0) returns %p", handle));
2508 close_it = PR_TRUE;
2510 pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
2511 PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
2512 ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
2514 if (close_it) {
2515 dlclose(handle);
2520 * pt_SolarisDispatchSendFile
2522 static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2523 PRTransmitFileFlags flags, PRIntervalTime timeout)
2525 int rv;
2527 rv = pthread_once(&pt_solaris_sendfilev_once_block,
2528 pt_solaris_sendfilev_init_routine);
2529 PR_ASSERT(0 == rv);
2530 if (pt_solaris_sendfilev_fptr) {
2531 return pt_SolarisSendFile(sd, sfd, flags, timeout);
2532 } else {
2533 return PR_EmulateSendFile(sd, sfd, flags, timeout);
2536 #endif /* !HAVE_SENDFILEV */
2538 #endif /* SOLARIS */
2540 #ifdef LINUX
2542 * pt_LinuxSendFile
2544 * Send file sfd->fd across socket sd. If specified, header and trailer
2545 * buffers are sent before and after the file, respectively.
2547 * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
2549 * return number of bytes sent or -1 on error
2551 * This implementation takes advantage of the sendfile() system
2552 * call available in Linux kernel 2.2 or higher.
2555 static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
2556 PRTransmitFileFlags flags, PRIntervalTime timeout)
2558 struct stat statbuf;
2559 size_t file_nbytes_to_send;
2560 PRInt32 count = 0;
2561 ssize_t rv;
2562 int syserrno;
2563 off_t offset;
2564 PRBool tcp_cork_enabled = PR_FALSE;
2565 int tcp_cork;
2567 if (sfd->file_nbytes == 0) {
2568 /* Get file size */
2569 if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
2570 _PR_MD_MAP_FSTAT_ERROR(errno);
2571 return -1;
2573 file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
2574 } else {
2575 file_nbytes_to_send = sfd->file_nbytes;
2578 if ((sfd->hlen != 0 || sfd->tlen != 0)
2579 && sd->secret->md.tcp_nodelay == 0) {
2580 tcp_cork = 1;
2581 if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
2582 &tcp_cork, sizeof tcp_cork) == 0) {
2583 tcp_cork_enabled = PR_TRUE;
2584 } else {
2585 syserrno = errno;
2586 if (syserrno != EINVAL) {
2587 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
2588 return -1;
2591 * The most likely reason for the EINVAL error is that
2592 * TCP_NODELAY is set (with a function other than
2593 * PR_SetSocketOption). This is not fatal, so we keep
2594 * on going.
2596 PR_LOG(_pr_io_lm, PR_LOG_WARNING,
2597 ("pt_LinuxSendFile: "
2598 "setsockopt(TCP_CORK) failed with EINVAL\n"));
2602 if (sfd->hlen != 0) {
2603 count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
2604 if (count == -1) {
2605 goto failed;
2609 if (file_nbytes_to_send != 0) {
2610 offset = sfd->file_offset;
2611 do {
2612 rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
2613 &offset, file_nbytes_to_send);
2614 } while (rv == -1 && (syserrno = errno) == EINTR);
2615 if (rv == -1) {
2616 if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
2617 _MD_linux_map_sendfile_error(syserrno);
2618 count = -1;
2619 goto failed;
2621 rv = 0;
2623 PR_ASSERT(rv == offset - sfd->file_offset);
2624 count += rv;
2626 if (rv < file_nbytes_to_send) {
2627 pt_Continuation op;
2629 op.arg1.osfd = sd->secret->md.osfd;
2630 op.in_fd = sfd->fd->secret->md.osfd;
2631 op.offset = offset;
2632 op.count = file_nbytes_to_send - rv;
2633 op.result.code = count;
2634 op.timeout = timeout;
2635 op.function = pt_linux_sendfile_cont;
2636 op.event = POLLOUT | POLLPRI;
2637 count = pt_Continue(&op);
2638 syserrno = op.syserrno;
2639 if (count == -1) {
2640 pt_MapError(_MD_linux_map_sendfile_error, syserrno);
2641 goto failed;
2646 if (sfd->tlen != 0) {
2647 rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
2648 if (rv == -1) {
2649 count = -1;
2650 goto failed;
2652 count += rv;
2655 failed:
2656 if (tcp_cork_enabled) {
2657 tcp_cork = 0;
2658 if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
2659 &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
2660 _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
2661 count = -1;
2664 if (count != -1) {
2665 if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
2666 PR_Close(sd);
2668 PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
2670 return count;
2672 #endif /* LINUX */
2674 #ifdef AIX
2675 extern int _pr_aix_send_file_use_disabled;
2676 #endif
2678 static PRInt32 pt_SendFile(
2679 PRFileDesc *sd, PRSendFileData *sfd,
2680 PRTransmitFileFlags flags, PRIntervalTime timeout)
2682 if (pt_TestAbort()) return -1;
2683 /* The socket must be in blocking mode. */
2684 if (sd->secret->nonblocking)
2686 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2687 return -1;
2689 #ifdef HPUX11
2690 return(pt_HPUXSendFile(sd, sfd, flags, timeout));
2691 #elif defined(AIX)
2692 #ifdef HAVE_SEND_FILE
2694 * A bug in AIX 4.3.2 results in corruption of data transferred by
2695 * send_file(); AIX patch PTF U463956 contains the fix. A user can
2696 * disable the use of send_file function in NSPR, when this patch is
2697 * not installed on the system, by setting the envionment variable
2698 * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
2700 if (_pr_aix_send_file_use_disabled)
2701 return(PR_EmulateSendFile(sd, sfd, flags, timeout));
2702 else
2703 return(pt_AIXSendFile(sd, sfd, flags, timeout));
2704 #else
2705 return(PR_EmulateSendFile(sd, sfd, flags, timeout));
2706 /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
2707 #endif /* HAVE_SEND_FILE */
2708 #elif defined(SOLARIS)
2709 #ifdef HAVE_SENDFILEV
2710 return(pt_SolarisSendFile(sd, sfd, flags, timeout));
2711 #else
2712 return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
2713 #endif /* HAVE_SENDFILEV */
2714 #elif defined(LINUX)
2715 return(pt_LinuxSendFile(sd, sfd, flags, timeout));
2716 #else
2717 return(PR_EmulateSendFile(sd, sfd, flags, timeout));
2718 #endif
2721 static PRInt32 pt_TransmitFile(
2722 PRFileDesc *sd, PRFileDesc *fd, const void *headers,
2723 PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
2725 PRSendFileData sfd;
2727 sfd.fd = fd;
2728 sfd.file_offset = 0;
2729 sfd.file_nbytes = 0;
2730 sfd.header = headers;
2731 sfd.hlen = hlen;
2732 sfd.trailer = NULL;
2733 sfd.tlen = 0;
2735 return(pt_SendFile(sd, &sfd, flags, timeout));
2736 } /* pt_TransmitFile */
2738 static PRInt32 pt_AcceptRead(
2739 PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
2740 void *buf, PRInt32 amount, PRIntervalTime timeout)
2742 PRInt32 rv = -1;
2744 if (pt_TestAbort()) return rv;
2745 /* The socket must be in blocking mode. */
2746 if (sd->secret->nonblocking)
2748 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2749 return rv;
2752 rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
2753 return rv;
2754 } /* pt_AcceptRead */
2756 static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
2758 PRIntn rv = -1;
2759 pt_SockLen addr_len = sizeof(PRNetAddr);
2761 if (pt_TestAbort()) return PR_FAILURE;
2763 rv = getsockname(
2764 fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
2765 if (rv == -1) {
2766 pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
2767 return PR_FAILURE;
2768 } else {
2769 #ifdef _PR_HAVE_SOCKADDR_LEN
2770 /* ignore the sa_len field of struct sockaddr */
2771 if (addr)
2773 addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2775 #endif /* _PR_HAVE_SOCKADDR_LEN */
2776 #ifdef _PR_INET6
2777 if (AF_INET6 == addr->raw.family)
2778 addr->raw.family = PR_AF_INET6;
2779 #endif
2780 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
2781 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
2782 return PR_SUCCESS;
2784 } /* pt_GetSockName */
2786 static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
2788 PRIntn rv = -1;
2789 pt_SockLen addr_len = sizeof(PRNetAddr);
2791 if (pt_TestAbort()) return PR_FAILURE;
2793 rv = getpeername(
2794 fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
2796 if (rv == -1) {
2797 pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
2798 return PR_FAILURE;
2799 } else {
2800 #ifdef _PR_HAVE_SOCKADDR_LEN
2801 /* ignore the sa_len field of struct sockaddr */
2802 if (addr)
2804 addr->raw.family = ((struct sockaddr*)addr)->sa_family;
2806 #endif /* _PR_HAVE_SOCKADDR_LEN */
2807 #ifdef _PR_INET6
2808 if (AF_INET6 == addr->raw.family)
2809 addr->raw.family = PR_AF_INET6;
2810 #endif
2811 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
2812 PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
2813 return PR_SUCCESS;
2815 } /* pt_GetPeerName */
2817 static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
2819 PRIntn rv;
2820 pt_SockLen length;
2821 PRInt32 level, name;
2824 * PR_SockOpt_Nonblocking is a special case that does not
2825 * translate to a getsockopt() call
2827 if (PR_SockOpt_Nonblocking == data->option)
2829 data->value.non_blocking = fd->secret->nonblocking;
2830 return PR_SUCCESS;
2833 rv = _PR_MapOptionName(data->option, &level, &name);
2834 if (PR_SUCCESS == rv)
2836 switch (data->option)
2838 case PR_SockOpt_Linger:
2840 struct linger linger;
2841 length = sizeof(linger);
2842 rv = getsockopt(
2843 fd->secret->md.osfd, level, name, (char *) &linger, &length);
2844 PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
2845 data->value.linger.polarity =
2846 (linger.l_onoff) ? PR_TRUE : PR_FALSE;
2847 data->value.linger.linger =
2848 PR_SecondsToInterval(linger.l_linger);
2849 break;
2851 case PR_SockOpt_Reuseaddr:
2852 case PR_SockOpt_Keepalive:
2853 case PR_SockOpt_NoDelay:
2854 case PR_SockOpt_Broadcast:
2856 PRIntn value;
2857 length = sizeof(PRIntn);
2858 rv = getsockopt(
2859 fd->secret->md.osfd, level, name, (char*)&value, &length);
2860 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2861 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
2862 break;
2864 case PR_SockOpt_McastLoopback:
2866 PRUint8 xbool;
2867 length = sizeof(xbool);
2868 rv = getsockopt(
2869 fd->secret->md.osfd, level, name,
2870 (char*)&xbool, &length);
2871 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
2872 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
2873 break;
2875 case PR_SockOpt_RecvBufferSize:
2876 case PR_SockOpt_SendBufferSize:
2877 case PR_SockOpt_MaxSegment:
2879 PRIntn value;
2880 length = sizeof(PRIntn);
2881 rv = getsockopt(
2882 fd->secret->md.osfd, level, name, (char*)&value, &length);
2883 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2884 data->value.recv_buffer_size = value;
2885 break;
2887 case PR_SockOpt_IpTimeToLive:
2888 case PR_SockOpt_IpTypeOfService:
2890 length = sizeof(PRUintn);
2891 rv = getsockopt(
2892 fd->secret->md.osfd, level, name,
2893 (char*)&data->value.ip_ttl, &length);
2894 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2895 break;
2897 case PR_SockOpt_McastTimeToLive:
2899 PRUint8 ttl;
2900 length = sizeof(ttl);
2901 rv = getsockopt(
2902 fd->secret->md.osfd, level, name,
2903 (char*)&ttl, &length);
2904 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
2905 data->value.mcast_ttl = ttl;
2906 break;
2908 case PR_SockOpt_AddMember:
2909 case PR_SockOpt_DropMember:
2911 struct ip_mreq mreq;
2912 length = sizeof(mreq);
2913 rv = getsockopt(
2914 fd->secret->md.osfd, level, name, (char*)&mreq, &length);
2915 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
2916 data->value.add_member.mcaddr.inet.ip =
2917 mreq.imr_multiaddr.s_addr;
2918 data->value.add_member.ifaddr.inet.ip =
2919 mreq.imr_interface.s_addr;
2920 break;
2922 case PR_SockOpt_McastInterface:
2924 length = sizeof(data->value.mcast_if.inet.ip);
2925 rv = getsockopt(
2926 fd->secret->md.osfd, level, name,
2927 (char*)&data->value.mcast_if.inet.ip, &length);
2928 PR_ASSERT((-1 == rv)
2929 || (sizeof(data->value.mcast_if.inet.ip) == length));
2930 break;
2932 default:
2933 PR_NOT_REACHED("Unknown socket option");
2934 break;
2936 if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
2938 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
2939 } /* pt_GetSocketOption */
2941 static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
2943 PRIntn rv;
2944 PRInt32 level, name;
2947 * PR_SockOpt_Nonblocking is a special case that does not
2948 * translate to a setsockopt call.
2950 if (PR_SockOpt_Nonblocking == data->option)
2952 fd->secret->nonblocking = data->value.non_blocking;
2953 return PR_SUCCESS;
2956 rv = _PR_MapOptionName(data->option, &level, &name);
2957 if (PR_SUCCESS == rv)
2959 switch (data->option)
2961 case PR_SockOpt_Linger:
2963 struct linger linger;
2964 linger.l_onoff = data->value.linger.polarity;
2965 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
2966 rv = setsockopt(
2967 fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
2968 break;
2970 case PR_SockOpt_Reuseaddr:
2971 case PR_SockOpt_Keepalive:
2972 case PR_SockOpt_NoDelay:
2973 case PR_SockOpt_Broadcast:
2975 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
2976 rv = setsockopt(
2977 fd->secret->md.osfd, level, name,
2978 (char*)&value, sizeof(PRIntn));
2979 #ifdef LINUX
2980 /* for pt_LinuxSendFile */
2981 if (name == TCP_NODELAY && rv == 0) {
2982 fd->secret->md.tcp_nodelay = value;
2984 #endif
2985 break;
2987 case PR_SockOpt_McastLoopback:
2989 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
2990 rv = setsockopt(
2991 fd->secret->md.osfd, level, name,
2992 (char*)&xbool, sizeof(xbool));
2993 break;
2995 case PR_SockOpt_RecvBufferSize:
2996 case PR_SockOpt_SendBufferSize:
2997 case PR_SockOpt_MaxSegment:
2999 PRIntn value = data->value.recv_buffer_size;
3000 rv = setsockopt(
3001 fd->secret->md.osfd, level, name,
3002 (char*)&value, sizeof(PRIntn));
3003 break;
3005 case PR_SockOpt_IpTimeToLive:
3006 case PR_SockOpt_IpTypeOfService:
3008 rv = setsockopt(
3009 fd->secret->md.osfd, level, name,
3010 (char*)&data->value.ip_ttl, sizeof(PRUintn));
3011 break;
3013 case PR_SockOpt_McastTimeToLive:
3015 PRUint8 ttl = data->value.mcast_ttl;
3016 rv = setsockopt(
3017 fd->secret->md.osfd, level, name,
3018 (char*)&ttl, sizeof(ttl));
3019 break;
3021 case PR_SockOpt_AddMember:
3022 case PR_SockOpt_DropMember:
3024 struct ip_mreq mreq;
3025 mreq.imr_multiaddr.s_addr =
3026 data->value.add_member.mcaddr.inet.ip;
3027 mreq.imr_interface.s_addr =
3028 data->value.add_member.ifaddr.inet.ip;
3029 rv = setsockopt(
3030 fd->secret->md.osfd, level, name,
3031 (char*)&mreq, sizeof(mreq));
3032 break;
3034 case PR_SockOpt_McastInterface:
3036 rv = setsockopt(
3037 fd->secret->md.osfd, level, name,
3038 (char*)&data->value.mcast_if.inet.ip,
3039 sizeof(data->value.mcast_if.inet.ip));
3040 break;
3042 default:
3043 PR_NOT_REACHED("Unknown socket option");
3044 break;
3046 if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
3048 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3049 } /* pt_SetSocketOption */
3051 /*****************************************************************************/
3052 /****************************** I/O method objects ***************************/
3053 /*****************************************************************************/
3055 static PRIOMethods _pr_file_methods = {
3056 PR_DESC_FILE,
3057 pt_Close,
3058 pt_Read,
3059 pt_Write,
3060 pt_Available_f,
3061 pt_Available64_f,
3062 pt_Fsync,
3063 pt_Seek,
3064 pt_Seek64,
3065 pt_FileInfo,
3066 pt_FileInfo64,
3067 (PRWritevFN)_PR_InvalidInt,
3068 (PRConnectFN)_PR_InvalidStatus,
3069 (PRAcceptFN)_PR_InvalidDesc,
3070 (PRBindFN)_PR_InvalidStatus,
3071 (PRListenFN)_PR_InvalidStatus,
3072 (PRShutdownFN)_PR_InvalidStatus,
3073 (PRRecvFN)_PR_InvalidInt,
3074 (PRSendFN)_PR_InvalidInt,
3075 (PRRecvfromFN)_PR_InvalidInt,
3076 (PRSendtoFN)_PR_InvalidInt,
3077 pt_Poll,
3078 (PRAcceptreadFN)_PR_InvalidInt,
3079 (PRTransmitfileFN)_PR_InvalidInt,
3080 (PRGetsocknameFN)_PR_InvalidStatus,
3081 (PRGetpeernameFN)_PR_InvalidStatus,
3082 (PRReservedFN)_PR_InvalidInt,
3083 (PRReservedFN)_PR_InvalidInt,
3084 (PRGetsocketoptionFN)_PR_InvalidStatus,
3085 (PRSetsocketoptionFN)_PR_InvalidStatus,
3086 (PRSendfileFN)_PR_InvalidInt,
3087 (PRConnectcontinueFN)_PR_InvalidStatus,
3088 (PRReservedFN)_PR_InvalidInt,
3089 (PRReservedFN)_PR_InvalidInt,
3090 (PRReservedFN)_PR_InvalidInt,
3091 (PRReservedFN)_PR_InvalidInt
3094 static PRIOMethods _pr_pipe_methods = {
3095 PR_DESC_PIPE,
3096 pt_Close,
3097 pt_Read,
3098 pt_Write,
3099 pt_Available_s,
3100 pt_Available64_s,
3101 pt_Synch,
3102 (PRSeekFN)_PR_InvalidInt,
3103 (PRSeek64FN)_PR_InvalidInt64,
3104 (PRFileInfoFN)_PR_InvalidStatus,
3105 (PRFileInfo64FN)_PR_InvalidStatus,
3106 (PRWritevFN)_PR_InvalidInt,
3107 (PRConnectFN)_PR_InvalidStatus,
3108 (PRAcceptFN)_PR_InvalidDesc,
3109 (PRBindFN)_PR_InvalidStatus,
3110 (PRListenFN)_PR_InvalidStatus,
3111 (PRShutdownFN)_PR_InvalidStatus,
3112 (PRRecvFN)_PR_InvalidInt,
3113 (PRSendFN)_PR_InvalidInt,
3114 (PRRecvfromFN)_PR_InvalidInt,
3115 (PRSendtoFN)_PR_InvalidInt,
3116 pt_Poll,
3117 (PRAcceptreadFN)_PR_InvalidInt,
3118 (PRTransmitfileFN)_PR_InvalidInt,
3119 (PRGetsocknameFN)_PR_InvalidStatus,
3120 (PRGetpeernameFN)_PR_InvalidStatus,
3121 (PRReservedFN)_PR_InvalidInt,
3122 (PRReservedFN)_PR_InvalidInt,
3123 (PRGetsocketoptionFN)_PR_InvalidStatus,
3124 (PRSetsocketoptionFN)_PR_InvalidStatus,
3125 (PRSendfileFN)_PR_InvalidInt,
3126 (PRConnectcontinueFN)_PR_InvalidStatus,
3127 (PRReservedFN)_PR_InvalidInt,
3128 (PRReservedFN)_PR_InvalidInt,
3129 (PRReservedFN)_PR_InvalidInt,
3130 (PRReservedFN)_PR_InvalidInt
3133 static PRIOMethods _pr_tcp_methods = {
3134 PR_DESC_SOCKET_TCP,
3135 pt_Close,
3136 pt_SocketRead,
3137 pt_SocketWrite,
3138 pt_Available_s,
3139 pt_Available64_s,
3140 pt_Synch,
3141 (PRSeekFN)_PR_InvalidInt,
3142 (PRSeek64FN)_PR_InvalidInt64,
3143 (PRFileInfoFN)_PR_InvalidStatus,
3144 (PRFileInfo64FN)_PR_InvalidStatus,
3145 pt_Writev,
3146 pt_Connect,
3147 pt_Accept,
3148 pt_Bind,
3149 pt_Listen,
3150 pt_Shutdown,
3151 pt_Recv,
3152 pt_Send,
3153 (PRRecvfromFN)_PR_InvalidInt,
3154 (PRSendtoFN)_PR_InvalidInt,
3155 pt_Poll,
3156 pt_AcceptRead,
3157 pt_TransmitFile,
3158 pt_GetSockName,
3159 pt_GetPeerName,
3160 (PRReservedFN)_PR_InvalidInt,
3161 (PRReservedFN)_PR_InvalidInt,
3162 pt_GetSocketOption,
3163 pt_SetSocketOption,
3164 pt_SendFile,
3165 pt_ConnectContinue,
3166 (PRReservedFN)_PR_InvalidInt,
3167 (PRReservedFN)_PR_InvalidInt,
3168 (PRReservedFN)_PR_InvalidInt,
3169 (PRReservedFN)_PR_InvalidInt
3172 static PRIOMethods _pr_udp_methods = {
3173 PR_DESC_SOCKET_UDP,
3174 pt_Close,
3175 pt_SocketRead,
3176 pt_SocketWrite,
3177 pt_Available_s,
3178 pt_Available64_s,
3179 pt_Synch,
3180 (PRSeekFN)_PR_InvalidInt,
3181 (PRSeek64FN)_PR_InvalidInt64,
3182 (PRFileInfoFN)_PR_InvalidStatus,
3183 (PRFileInfo64FN)_PR_InvalidStatus,
3184 pt_Writev,
3185 pt_Connect,
3186 (PRAcceptFN)_PR_InvalidDesc,
3187 pt_Bind,
3188 pt_Listen,
3189 pt_Shutdown,
3190 pt_Recv,
3191 pt_Send,
3192 pt_RecvFrom,
3193 pt_SendTo,
3194 pt_Poll,
3195 (PRAcceptreadFN)_PR_InvalidInt,
3196 (PRTransmitfileFN)_PR_InvalidInt,
3197 pt_GetSockName,
3198 pt_GetPeerName,
3199 (PRReservedFN)_PR_InvalidInt,
3200 (PRReservedFN)_PR_InvalidInt,
3201 pt_GetSocketOption,
3202 pt_SetSocketOption,
3203 (PRSendfileFN)_PR_InvalidInt,
3204 (PRConnectcontinueFN)_PR_InvalidStatus,
3205 (PRReservedFN)_PR_InvalidInt,
3206 (PRReservedFN)_PR_InvalidInt,
3207 (PRReservedFN)_PR_InvalidInt,
3208 (PRReservedFN)_PR_InvalidInt
3211 static PRIOMethods _pr_socketpollfd_methods = {
3212 (PRDescType) 0,
3213 (PRCloseFN)_PR_InvalidStatus,
3214 (PRReadFN)_PR_InvalidInt,
3215 (PRWriteFN)_PR_InvalidInt,
3216 (PRAvailableFN)_PR_InvalidInt,
3217 (PRAvailable64FN)_PR_InvalidInt64,
3218 (PRFsyncFN)_PR_InvalidStatus,
3219 (PRSeekFN)_PR_InvalidInt,
3220 (PRSeek64FN)_PR_InvalidInt64,
3221 (PRFileInfoFN)_PR_InvalidStatus,
3222 (PRFileInfo64FN)_PR_InvalidStatus,
3223 (PRWritevFN)_PR_InvalidInt,
3224 (PRConnectFN)_PR_InvalidStatus,
3225 (PRAcceptFN)_PR_InvalidDesc,
3226 (PRBindFN)_PR_InvalidStatus,
3227 (PRListenFN)_PR_InvalidStatus,
3228 (PRShutdownFN)_PR_InvalidStatus,
3229 (PRRecvFN)_PR_InvalidInt,
3230 (PRSendFN)_PR_InvalidInt,
3231 (PRRecvfromFN)_PR_InvalidInt,
3232 (PRSendtoFN)_PR_InvalidInt,
3233 pt_Poll,
3234 (PRAcceptreadFN)_PR_InvalidInt,
3235 (PRTransmitfileFN)_PR_InvalidInt,
3236 (PRGetsocknameFN)_PR_InvalidStatus,
3237 (PRGetpeernameFN)_PR_InvalidStatus,
3238 (PRReservedFN)_PR_InvalidInt,
3239 (PRReservedFN)_PR_InvalidInt,
3240 (PRGetsocketoptionFN)_PR_InvalidStatus,
3241 (PRSetsocketoptionFN)_PR_InvalidStatus,
3242 (PRSendfileFN)_PR_InvalidInt,
3243 (PRConnectcontinueFN)_PR_InvalidStatus,
3244 (PRReservedFN)_PR_InvalidInt,
3245 (PRReservedFN)_PR_InvalidInt,
3246 (PRReservedFN)_PR_InvalidInt,
3247 (PRReservedFN)_PR_InvalidInt
3250 #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
3251 || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
3252 || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
3253 || defined(OPENBSD) || defined(BSDI) || defined(VMS) || defined(NTO) \
3254 || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS)
3255 #define _PR_FCNTL_FLAGS O_NONBLOCK
3256 #else
3257 #error "Can't determine architecture"
3258 #endif
3261 * Put a Unix file descriptor in non-blocking mode.
3263 static void pt_MakeFdNonblock(PRIntn osfd)
3265 PRIntn flags;
3266 flags = fcntl(osfd, F_GETFL, 0);
3267 flags |= _PR_FCNTL_FLAGS;
3268 (void)fcntl(osfd, F_SETFL, flags);
3272 * Put a Unix socket fd in non-blocking mode that can
3273 * ideally be inherited by an accepted socket.
3275 * Why doesn't pt_MakeFdNonblock do? This is to deal with
3276 * the special case of HP-UX. HP-UX has three kinds of
3277 * non-blocking modes for sockets: the fcntl() O_NONBLOCK
3278 * and O_NDELAY flags and ioctl() FIOSNBIO request. Only
3279 * the ioctl() FIOSNBIO form of non-blocking mode is
3280 * inherited by an accepted socket.
3282 * Other platforms just use the generic pt_MakeFdNonblock
3283 * to put a socket in non-blocking mode.
3285 #ifdef HPUX
3286 static void pt_MakeSocketNonblock(PRIntn osfd)
3288 PRIntn one = 1;
3289 (void)ioctl(osfd, FIOSNBIO, &one);
3291 #else
3292 #define pt_MakeSocketNonblock pt_MakeFdNonblock
3293 #endif
3295 static PRFileDesc *pt_SetMethods(
3296 PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
3298 PRFileDesc *fd = _PR_Getfd();
3300 if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3301 else
3303 fd->secret->md.osfd = osfd;
3304 fd->secret->state = _PR_FILEDESC_OPEN;
3305 if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
3306 else
3308 /* By default, a Unix fd is not closed on exec. */
3309 #ifdef DEBUG
3310 PRIntn flags;
3311 flags = fcntl(osfd, F_GETFD, 0);
3312 PR_ASSERT(0 == flags);
3313 #endif
3314 fd->secret->inheritable = _PR_TRI_TRUE;
3316 switch (type)
3318 case PR_DESC_FILE:
3319 fd->methods = PR_GetFileMethods();
3320 break;
3321 case PR_DESC_SOCKET_TCP:
3322 fd->methods = PR_GetTCPMethods();
3323 #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
3324 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
3325 #else
3326 pt_MakeSocketNonblock(osfd);
3327 #endif
3328 break;
3329 case PR_DESC_SOCKET_UDP:
3330 fd->methods = PR_GetUDPMethods();
3331 pt_MakeFdNonblock(osfd);
3332 break;
3333 case PR_DESC_PIPE:
3334 fd->methods = PR_GetPipeMethods();
3335 pt_MakeFdNonblock(osfd);
3336 break;
3337 default:
3338 break;
3341 return fd;
3342 } /* pt_SetMethods */
3344 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
3346 return &_pr_file_methods;
3347 } /* PR_GetFileMethods */
3349 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
3351 return &_pr_pipe_methods;
3352 } /* PR_GetPipeMethods */
3354 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
3356 return &_pr_tcp_methods;
3357 } /* PR_GetTCPMethods */
3359 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
3361 return &_pr_udp_methods;
3362 } /* PR_GetUDPMethods */
3364 static const PRIOMethods* PR_GetSocketPollFdMethods(void)
3366 return &_pr_socketpollfd_methods;
3367 } /* PR_GetSocketPollFdMethods */
3369 PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
3370 PRInt32 osfd, const PRIOMethods *methods)
3372 PRFileDesc *fd = _PR_Getfd();
3374 if (NULL == fd) goto failed;
3376 fd->methods = methods;
3377 fd->secret->md.osfd = osfd;
3378 /* Make fd non-blocking */
3379 if (osfd > 2)
3381 /* Don't mess around with stdin, stdout or stderr */
3382 if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
3383 else pt_MakeFdNonblock(osfd);
3385 fd->secret->state = _PR_FILEDESC_OPEN;
3386 fd->secret->inheritable = _PR_TRI_UNKNOWN;
3387 return fd;
3389 failed:
3390 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3391 return fd;
3392 } /* PR_AllocFileDesc */
3394 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
3395 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
3396 #if defined(_PR_INET6_PROBE)
3397 extern PRBool _pr_ipv6_is_present(void);
3398 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
3400 PRInt32 osfd;
3402 #if defined(DARWIN)
3404 * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3). IPv6 on
3405 * lesser versions is not ready for general use (see bug 222031).
3408 struct utsname u;
3409 if (uname(&u) != 0 || atoi(u.release) < 7)
3410 return PR_FALSE;
3412 #endif
3415 * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
3416 * suggests that we call open("/dev/ip6", O_RDWR) to determine
3417 * whether IPv6 APIs and the IPv6 stack are on the system.
3418 * Our portable test below seems to work fine, so I am using it.
3420 osfd = socket(AF_INET6, SOCK_STREAM, 0);
3421 if (osfd != -1) {
3422 close(osfd);
3423 return PR_TRUE;
3425 return PR_FALSE;
3427 #endif /* _PR_INET6_PROBE */
3428 #endif
3430 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
3432 PRIntn osfd;
3433 PRDescType ftype;
3434 PRFileDesc *fd = NULL;
3435 PRInt32 tmp_domain = domain;
3437 if (!_pr_initialized) _PR_ImplicitInitialization();
3439 if (pt_TestAbort()) return NULL;
3441 if (PF_INET != domain
3442 && PR_AF_INET6 != domain
3443 && PF_UNIX != domain)
3445 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3446 return fd;
3448 if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
3449 else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
3450 else
3452 (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3453 return fd;
3455 #if defined(_PR_INET6_PROBE)
3456 if (PR_AF_INET6 == domain)
3457 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
3458 #elif defined(_PR_INET6)
3459 if (PR_AF_INET6 == domain)
3460 domain = AF_INET6;
3461 #else
3462 if (PR_AF_INET6 == domain)
3463 domain = AF_INET;
3464 #endif
3466 osfd = socket(domain, type, proto);
3467 if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
3468 else
3470 #ifdef _PR_IPV6_V6ONLY_PROBE
3471 if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
3473 int on = 0;
3474 (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
3475 &on, sizeof(on));
3477 #endif
3478 fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
3479 if (fd == NULL) close(osfd);
3481 #ifdef _PR_NEED_SECRET_AF
3482 if (fd != NULL) fd->secret->af = domain;
3483 #endif
3484 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
3485 if (fd != NULL) {
3487 * For platforms with no support for IPv6
3488 * create layered socket for IPv4-mapped IPv6 addresses
3490 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
3491 if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
3492 PR_Close(fd);
3493 fd = NULL;
3497 #endif
3498 return fd;
3499 } /* PR_Socket */
3501 /*****************************************************************************/
3502 /****************************** I/O public methods ***************************/
3503 /*****************************************************************************/
3505 PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
3506 const char *name, PRIntn flags, PRIntn mode)
3508 PRFileDesc *fd = NULL;
3509 PRIntn syserrno, osfd = -1, osflags = 0;;
3511 if (!_pr_initialized) _PR_ImplicitInitialization();
3513 if (pt_TestAbort()) return NULL;
3515 if (flags & PR_RDONLY) osflags |= O_RDONLY;
3516 if (flags & PR_WRONLY) osflags |= O_WRONLY;
3517 if (flags & PR_RDWR) osflags |= O_RDWR;
3518 if (flags & PR_APPEND) osflags |= O_APPEND;
3519 if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
3520 if (flags & PR_EXCL) osflags |= O_EXCL;
3521 if (flags & PR_SYNC)
3523 #if defined(O_SYNC)
3524 osflags |= O_SYNC;
3525 #elif defined(O_FSYNC)
3526 osflags |= O_FSYNC;
3527 #else
3528 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
3529 #endif
3533 ** We have to hold the lock across the creation in order to
3534 ** enforce the sematics of PR_Rename(). (see the latter for
3535 ** more details)
3537 if (flags & PR_CREATE_FILE)
3539 osflags |= O_CREAT;
3540 if (NULL !=_pr_rename_lock)
3541 PR_Lock(_pr_rename_lock);
3544 osfd = _md_iovector._open64(name, osflags, mode);
3545 syserrno = errno;
3547 if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
3548 PR_Unlock(_pr_rename_lock);
3550 if (osfd == -1)
3551 pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
3552 else
3554 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
3555 if (fd == NULL) close(osfd); /* $$$ whoops! this is bad $$$ */
3557 return fd;
3558 } /* PR_OpenFile */
3560 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
3562 return PR_OpenFile(name, flags, mode);
3563 } /* PR_Open */
3565 PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
3567 PRIntn rv = -1;
3569 if (!_pr_initialized) _PR_ImplicitInitialization();
3571 if (pt_TestAbort()) return PR_FAILURE;
3573 rv = unlink(name);
3575 if (rv == -1) {
3576 pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
3577 return PR_FAILURE;
3578 } else
3579 return PR_SUCCESS;
3580 } /* PR_Delete */
3582 PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
3584 PRIntn rv;
3586 if (pt_TestAbort()) return PR_FAILURE;
3588 switch (how)
3590 case PR_ACCESS_READ_OK:
3591 rv = access(name, R_OK);
3592 break;
3593 case PR_ACCESS_WRITE_OK:
3594 rv = access(name, W_OK);
3595 break;
3596 case PR_ACCESS_EXISTS:
3597 default:
3598 rv = access(name, F_OK);
3600 if (0 == rv) return PR_SUCCESS;
3601 pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
3602 return PR_FAILURE;
3604 } /* PR_Access */
3606 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
3608 PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
3609 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3610 } /* PR_GetFileInfo */
3612 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
3614 PRInt32 rv;
3616 if (!_pr_initialized) _PR_ImplicitInitialization();
3617 rv = _PR_MD_GETFILEINFO64(fn, info);
3618 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3619 } /* PR_GetFileInfo64 */
3621 PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
3623 PRIntn rv = -1;
3625 if (pt_TestAbort()) return PR_FAILURE;
3628 ** We have to acquire a lock here to stiffle anybody trying to create
3629 ** a new file at the same time. And we have to hold that lock while we
3630 ** test to see if the file exists and do the rename. The other place
3631 ** where the lock is held is in PR_Open() when possibly creating a
3632 ** new file.
3635 PR_Lock(_pr_rename_lock);
3636 rv = access(to, F_OK);
3637 if (0 == rv)
3639 PR_SetError(PR_FILE_EXISTS_ERROR, 0);
3640 rv = -1;
3642 else
3644 rv = rename(from, to);
3645 if (rv == -1)
3646 pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
3648 PR_Unlock(_pr_rename_lock);
3649 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3650 } /* PR_Rename */
3652 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
3654 if (pt_TestAbort()) return PR_FAILURE;
3656 if (NULL != dir->md.d)
3658 if (closedir(dir->md.d) == -1)
3660 _PR_MD_MAP_CLOSEDIR_ERROR(errno);
3661 return PR_FAILURE;
3663 dir->md.d = NULL;
3664 PR_DELETE(dir);
3666 return PR_SUCCESS;
3667 } /* PR_CloseDir */
3669 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
3671 PRInt32 rv = -1;
3673 if (pt_TestAbort()) return PR_FAILURE;
3676 ** This lock is used to enforce rename semantics as described
3677 ** in PR_Rename.
3679 if (NULL !=_pr_rename_lock)
3680 PR_Lock(_pr_rename_lock);
3681 rv = mkdir(name, mode);
3682 if (-1 == rv)
3683 pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
3684 if (NULL !=_pr_rename_lock)
3685 PR_Unlock(_pr_rename_lock);
3687 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3688 } /* PR_Makedir */
3690 PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
3692 return PR_MakeDir(name, mode);
3693 } /* PR_Mkdir */
3695 PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
3697 PRInt32 rv;
3699 if (pt_TestAbort()) return PR_FAILURE;
3701 rv = rmdir(name);
3702 if (0 == rv) {
3703 return PR_SUCCESS;
3704 } else {
3705 pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
3706 return PR_FAILURE;
3708 } /* PR_Rmdir */
3711 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
3713 DIR *osdir;
3714 PRDir *dir = NULL;
3716 if (pt_TestAbort()) return dir;
3718 osdir = opendir(name);
3719 if (osdir == NULL)
3720 pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
3721 else
3723 dir = PR_NEWZAP(PRDir);
3724 if (dir)
3725 dir->md.d = osdir;
3726 else
3727 (void)closedir(osdir);
3729 return dir;
3730 } /* PR_OpenDir */
3732 static PRInt32 _pr_poll_with_poll(
3733 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
3735 PRInt32 ready = 0;
3737 * For restarting poll() if it is interrupted by a signal.
3738 * We use these variables to figure out how much time has
3739 * elapsed and how much of the timeout still remains.
3741 PRIntervalTime start, elapsed, remaining;
3743 if (pt_TestAbort()) return -1;
3745 if (0 == npds) PR_Sleep(timeout);
3746 else
3748 #define STACK_POLL_DESC_COUNT 64
3749 struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
3750 struct pollfd *syspoll;
3751 PRIntn index, msecs;
3753 if (npds <= STACK_POLL_DESC_COUNT)
3755 syspoll = stack_syspoll;
3757 else
3759 PRThread *me = PR_GetCurrentThread();
3760 if (npds > me->syspoll_count)
3762 PR_Free(me->syspoll_list);
3763 me->syspoll_list =
3764 (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
3765 if (NULL == me->syspoll_list)
3767 me->syspoll_count = 0;
3768 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3769 return -1;
3771 me->syspoll_count = npds;
3773 syspoll = me->syspoll_list;
3776 for (index = 0; index < npds; ++index)
3778 PRInt16 in_flags_read = 0, in_flags_write = 0;
3779 PRInt16 out_flags_read = 0, out_flags_write = 0;
3781 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
3783 if (pds[index].in_flags & PR_POLL_READ)
3785 in_flags_read = (pds[index].fd->methods->poll)(
3786 pds[index].fd,
3787 pds[index].in_flags & ~PR_POLL_WRITE,
3788 &out_flags_read);
3790 if (pds[index].in_flags & PR_POLL_WRITE)
3792 in_flags_write = (pds[index].fd->methods->poll)(
3793 pds[index].fd,
3794 pds[index].in_flags & ~PR_POLL_READ,
3795 &out_flags_write);
3797 if ((0 != (in_flags_read & out_flags_read))
3798 || (0 != (in_flags_write & out_flags_write)))
3800 /* this one is ready right now */
3801 if (0 == ready)
3804 * We will return without calling the system
3805 * poll function. So zero the out_flags
3806 * fields of all the poll descriptors before
3807 * this one.
3809 int i;
3810 for (i = 0; i < index; i++)
3812 pds[i].out_flags = 0;
3815 ready += 1;
3816 pds[index].out_flags = out_flags_read | out_flags_write;
3818 else
3820 /* now locate the NSPR layer at the bottom of the stack */
3821 PRFileDesc *bottom = PR_GetIdentitiesLayer(
3822 pds[index].fd, PR_NSPR_IO_LAYER);
3823 PR_ASSERT(NULL != bottom); /* what to do about that? */
3824 pds[index].out_flags = 0; /* pre-condition */
3825 if ((NULL != bottom)
3826 && (_PR_FILEDESC_OPEN == bottom->secret->state))
3828 if (0 == ready)
3830 syspoll[index].fd = bottom->secret->md.osfd;
3831 syspoll[index].events = 0;
3832 if (in_flags_read & PR_POLL_READ)
3834 pds[index].out_flags |=
3835 _PR_POLL_READ_SYS_READ;
3836 syspoll[index].events |= POLLIN;
3838 if (in_flags_read & PR_POLL_WRITE)
3840 pds[index].out_flags |=
3841 _PR_POLL_READ_SYS_WRITE;
3842 syspoll[index].events |= POLLOUT;
3844 if (in_flags_write & PR_POLL_READ)
3846 pds[index].out_flags |=
3847 _PR_POLL_WRITE_SYS_READ;
3848 syspoll[index].events |= POLLIN;
3850 if (in_flags_write & PR_POLL_WRITE)
3852 pds[index].out_flags |=
3853 _PR_POLL_WRITE_SYS_WRITE;
3854 syspoll[index].events |= POLLOUT;
3856 if (pds[index].in_flags & PR_POLL_EXCEPT)
3857 syspoll[index].events |= POLLPRI;
3860 else
3862 if (0 == ready)
3864 int i;
3865 for (i = 0; i < index; i++)
3867 pds[i].out_flags = 0;
3870 ready += 1; /* this will cause an abrupt return */
3871 pds[index].out_flags = PR_POLL_NVAL; /* bogii */
3875 else
3877 /* make poll() ignore this entry */
3878 syspoll[index].fd = -1;
3879 syspoll[index].events = 0;
3880 pds[index].out_flags = 0;
3883 if (0 == ready)
3885 switch (timeout)
3887 case PR_INTERVAL_NO_WAIT: msecs = 0; break;
3888 case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
3889 default:
3890 msecs = PR_IntervalToMilliseconds(timeout);
3891 start = PR_IntervalNow();
3894 retry:
3895 ready = poll(syspoll, npds, msecs);
3896 if (-1 == ready)
3898 PRIntn oserror = errno;
3900 if (EINTR == oserror)
3902 if (timeout == PR_INTERVAL_NO_TIMEOUT)
3903 goto retry;
3904 else if (timeout == PR_INTERVAL_NO_WAIT)
3905 ready = 0; /* don't retry, just time out */
3906 else
3908 elapsed = (PRIntervalTime) (PR_IntervalNow()
3909 - start);
3910 if (elapsed > timeout)
3911 ready = 0; /* timed out */
3912 else
3914 remaining = timeout - elapsed;
3915 msecs = PR_IntervalToMilliseconds(remaining);
3916 goto retry;
3920 else
3922 _PR_MD_MAP_POLL_ERROR(oserror);
3925 else if (ready > 0)
3927 for (index = 0; index < npds; ++index)
3929 PRInt16 out_flags = 0;
3930 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
3932 if (0 != syspoll[index].revents)
3934 if (syspoll[index].revents & POLLIN)
3936 if (pds[index].out_flags
3937 & _PR_POLL_READ_SYS_READ)
3939 out_flags |= PR_POLL_READ;
3941 if (pds[index].out_flags
3942 & _PR_POLL_WRITE_SYS_READ)
3944 out_flags |= PR_POLL_WRITE;
3947 if (syspoll[index].revents & POLLOUT)
3949 if (pds[index].out_flags
3950 & _PR_POLL_READ_SYS_WRITE)
3952 out_flags |= PR_POLL_READ;
3954 if (pds[index].out_flags
3955 & _PR_POLL_WRITE_SYS_WRITE)
3957 out_flags |= PR_POLL_WRITE;
3960 if (syspoll[index].revents & POLLPRI)
3961 out_flags |= PR_POLL_EXCEPT;
3962 if (syspoll[index].revents & POLLERR)
3963 out_flags |= PR_POLL_ERR;
3964 if (syspoll[index].revents & POLLNVAL)
3965 out_flags |= PR_POLL_NVAL;
3966 if (syspoll[index].revents & POLLHUP)
3967 out_flags |= PR_POLL_HUP;
3970 pds[index].out_flags = out_flags;
3975 return ready;
3977 } /* _pr_poll_with_poll */
3979 #if defined(_PR_POLL_WITH_SELECT)
3981 * OSF1 and HPUX report the POLLHUP event for a socket when the
3982 * shutdown(SHUT_WR) operation is called for the remote end, even though
3983 * the socket is still writeable. Use select(), instead of poll(), to
3984 * workaround this problem.
3986 static PRInt32 _pr_poll_with_select(
3987 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
3989 PRInt32 ready = 0;
3991 * For restarting select() if it is interrupted by a signal.
3992 * We use these variables to figure out how much time has
3993 * elapsed and how much of the timeout still remains.
3995 PRIntervalTime start, elapsed, remaining;
3997 if (pt_TestAbort()) return -1;
3999 if (0 == npds) PR_Sleep(timeout);
4000 else
4002 #define STACK_POLL_DESC_COUNT 64
4003 int stack_selectfd[STACK_POLL_DESC_COUNT];
4004 int *selectfd;
4005 fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
4006 struct timeval tv, *tvp;
4007 PRIntn index, msecs, maxfd = 0;
4009 if (npds <= STACK_POLL_DESC_COUNT)
4011 selectfd = stack_selectfd;
4013 else
4015 PRThread *me = PR_GetCurrentThread();
4016 if (npds > me->selectfd_count)
4018 PR_Free(me->selectfd_list);
4019 me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
4020 if (NULL == me->selectfd_list)
4022 me->selectfd_count = 0;
4023 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4024 return -1;
4026 me->selectfd_count = npds;
4028 selectfd = me->selectfd_list;
4030 FD_ZERO(&rd);
4031 FD_ZERO(&wr);
4032 FD_ZERO(&ex);
4034 for (index = 0; index < npds; ++index)
4036 PRInt16 in_flags_read = 0, in_flags_write = 0;
4037 PRInt16 out_flags_read = 0, out_flags_write = 0;
4039 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
4041 if (pds[index].in_flags & PR_POLL_READ)
4043 in_flags_read = (pds[index].fd->methods->poll)(
4044 pds[index].fd,
4045 pds[index].in_flags & ~PR_POLL_WRITE,
4046 &out_flags_read);
4048 if (pds[index].in_flags & PR_POLL_WRITE)
4050 in_flags_write = (pds[index].fd->methods->poll)(
4051 pds[index].fd,
4052 pds[index].in_flags & ~PR_POLL_READ,
4053 &out_flags_write);
4055 if ((0 != (in_flags_read & out_flags_read))
4056 || (0 != (in_flags_write & out_flags_write)))
4058 /* this one is ready right now */
4059 if (0 == ready)
4062 * We will return without calling the system
4063 * poll function. So zero the out_flags
4064 * fields of all the poll descriptors before
4065 * this one.
4067 int i;
4068 for (i = 0; i < index; i++)
4070 pds[i].out_flags = 0;
4073 ready += 1;
4074 pds[index].out_flags = out_flags_read | out_flags_write;
4076 else
4078 /* now locate the NSPR layer at the bottom of the stack */
4079 PRFileDesc *bottom = PR_GetIdentitiesLayer(
4080 pds[index].fd, PR_NSPR_IO_LAYER);
4081 PR_ASSERT(NULL != bottom); /* what to do about that? */
4082 pds[index].out_flags = 0; /* pre-condition */
4083 if ((NULL != bottom)
4084 && (_PR_FILEDESC_OPEN == bottom->secret->state))
4086 if (0 == ready)
4088 PRBool add_to_rd = PR_FALSE;
4089 PRBool add_to_wr = PR_FALSE;
4090 PRBool add_to_ex = PR_FALSE;
4092 selectfd[index] = bottom->secret->md.osfd;
4093 if (in_flags_read & PR_POLL_READ)
4095 pds[index].out_flags |=
4096 _PR_POLL_READ_SYS_READ;
4097 add_to_rd = PR_TRUE;
4099 if (in_flags_read & PR_POLL_WRITE)
4101 pds[index].out_flags |=
4102 _PR_POLL_READ_SYS_WRITE;
4103 add_to_wr = PR_TRUE;
4105 if (in_flags_write & PR_POLL_READ)
4107 pds[index].out_flags |=
4108 _PR_POLL_WRITE_SYS_READ;
4109 add_to_rd = PR_TRUE;
4111 if (in_flags_write & PR_POLL_WRITE)
4113 pds[index].out_flags |=
4114 _PR_POLL_WRITE_SYS_WRITE;
4115 add_to_wr = PR_TRUE;
4117 if (pds[index].in_flags & PR_POLL_EXCEPT)
4119 add_to_ex = PR_TRUE;
4121 if ((selectfd[index] > maxfd) &&
4122 (add_to_rd || add_to_wr || add_to_ex))
4124 maxfd = selectfd[index];
4126 * If maxfd is too large to be used with
4127 * select, fall back to calling poll.
4129 if (maxfd >= FD_SETSIZE)
4130 break;
4132 if (add_to_rd)
4134 FD_SET(bottom->secret->md.osfd, &rd);
4135 rdp = &rd;
4137 if (add_to_wr)
4139 FD_SET(bottom->secret->md.osfd, &wr);
4140 wrp = &wr;
4142 if (add_to_ex)
4144 FD_SET(bottom->secret->md.osfd, &ex);
4145 exp = &ex;
4149 else
4151 if (0 == ready)
4153 int i;
4154 for (i = 0; i < index; i++)
4156 pds[i].out_flags = 0;
4159 ready += 1; /* this will cause an abrupt return */
4160 pds[index].out_flags = PR_POLL_NVAL; /* bogii */
4164 else
4166 pds[index].out_flags = 0;
4169 if (0 == ready)
4171 if (maxfd >= FD_SETSIZE)
4174 * maxfd too large to be used with select, fall back to
4175 * calling poll
4177 return(_pr_poll_with_poll(pds, npds, timeout));
4179 switch (timeout)
4181 case PR_INTERVAL_NO_WAIT:
4182 tv.tv_sec = 0;
4183 tv.tv_usec = 0;
4184 tvp = &tv;
4185 break;
4186 case PR_INTERVAL_NO_TIMEOUT:
4187 tvp = NULL;
4188 break;
4189 default:
4190 msecs = PR_IntervalToMilliseconds(timeout);
4191 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
4192 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
4193 tvp = &tv;
4194 start = PR_IntervalNow();
4197 retry:
4198 ready = select(maxfd + 1, rdp, wrp, exp, tvp);
4199 if (-1 == ready)
4201 PRIntn oserror = errno;
4203 if ((EINTR == oserror) || (EAGAIN == oserror))
4205 if (timeout == PR_INTERVAL_NO_TIMEOUT)
4206 goto retry;
4207 else if (timeout == PR_INTERVAL_NO_WAIT)
4208 ready = 0; /* don't retry, just time out */
4209 else
4211 elapsed = (PRIntervalTime) (PR_IntervalNow()
4212 - start);
4213 if (elapsed > timeout)
4214 ready = 0; /* timed out */
4215 else
4217 remaining = timeout - elapsed;
4218 msecs = PR_IntervalToMilliseconds(remaining);
4219 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
4220 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
4221 PR_USEC_PER_MSEC;
4222 goto retry;
4225 } else if (EBADF == oserror)
4227 /* find all the bad fds */
4228 ready = 0;
4229 for (index = 0; index < npds; ++index)
4231 pds[index].out_flags = 0;
4232 if ((NULL != pds[index].fd) &&
4233 (0 != pds[index].in_flags))
4235 if (fcntl(selectfd[index], F_GETFL, 0) == -1)
4237 pds[index].out_flags = PR_POLL_NVAL;
4238 ready++;
4242 } else
4243 _PR_MD_MAP_SELECT_ERROR(oserror);
4245 else if (ready > 0)
4247 for (index = 0; index < npds; ++index)
4249 PRInt16 out_flags = 0;
4250 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
4252 if (FD_ISSET(selectfd[index], &rd))
4254 if (pds[index].out_flags
4255 & _PR_POLL_READ_SYS_READ)
4257 out_flags |= PR_POLL_READ;
4259 if (pds[index].out_flags
4260 & _PR_POLL_WRITE_SYS_READ)
4262 out_flags |= PR_POLL_WRITE;
4265 if (FD_ISSET(selectfd[index], &wr))
4267 if (pds[index].out_flags
4268 & _PR_POLL_READ_SYS_WRITE)
4270 out_flags |= PR_POLL_READ;
4272 if (pds[index].out_flags
4273 & _PR_POLL_WRITE_SYS_WRITE)
4275 out_flags |= PR_POLL_WRITE;
4278 if (FD_ISSET(selectfd[index], &ex))
4279 out_flags |= PR_POLL_EXCEPT;
4281 pds[index].out_flags = out_flags;
4286 return ready;
4288 } /* _pr_poll_with_select */
4289 #endif /* _PR_POLL_WITH_SELECT */
4291 PR_IMPLEMENT(PRInt32) PR_Poll(
4292 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
4294 #if defined(_PR_POLL_WITH_SELECT)
4295 return(_pr_poll_with_select(pds, npds, timeout));
4296 #else
4297 return(_pr_poll_with_poll(pds, npds, timeout));
4298 #endif
4301 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
4303 struct dirent *dp;
4305 if (pt_TestAbort()) return NULL;
4307 for (;;)
4309 errno = 0;
4310 dp = readdir(dir->md.d);
4311 if (NULL == dp)
4313 pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
4314 return NULL;
4316 if ((flags & PR_SKIP_DOT)
4317 && ('.' == dp->d_name[0])
4318 && (0 == dp->d_name[1])) continue;
4319 if ((flags & PR_SKIP_DOT_DOT)
4320 && ('.' == dp->d_name[0])
4321 && ('.' == dp->d_name[1])
4322 && (0 == dp->d_name[2])) continue;
4323 if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
4324 continue;
4325 break;
4327 dir->d.name = dp->d_name;
4328 return &dir->d;
4329 } /* PR_ReadDir */
4331 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
4333 PRIntn domain = PF_INET;
4335 return PR_Socket(domain, SOCK_DGRAM, 0);
4336 } /* PR_NewUDPSocket */
4338 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
4340 PRIntn domain = PF_INET;
4342 return PR_Socket(domain, SOCK_STREAM, 0);
4343 } /* PR_NewTCPSocket */
4345 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
4347 return PR_Socket(af, SOCK_DGRAM, 0);
4348 } /* PR_NewUDPSocket */
4350 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
4352 return PR_Socket(af, SOCK_STREAM, 0);
4353 } /* PR_NewTCPSocket */
4355 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
4357 PRInt32 osfd[2];
4359 if (pt_TestAbort()) return PR_FAILURE;
4361 if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
4362 pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
4363 return PR_FAILURE;
4366 fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4367 if (fds[0] == NULL) {
4368 close(osfd[0]);
4369 close(osfd[1]);
4370 return PR_FAILURE;
4372 fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4373 if (fds[1] == NULL) {
4374 PR_Close(fds[0]);
4375 close(osfd[1]);
4376 return PR_FAILURE;
4378 return PR_SUCCESS;
4379 } /* PR_NewTCPSocketPair */
4381 PR_IMPLEMENT(PRStatus) PR_CreatePipe(
4382 PRFileDesc **readPipe,
4383 PRFileDesc **writePipe
4386 int pipefd[2];
4388 if (pt_TestAbort()) return PR_FAILURE;
4390 if (pipe(pipefd) == -1)
4392 /* XXX map pipe error */
4393 PR_SetError(PR_UNKNOWN_ERROR, errno);
4394 return PR_FAILURE;
4396 *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4397 if (NULL == *readPipe)
4399 close(pipefd[0]);
4400 close(pipefd[1]);
4401 return PR_FAILURE;
4403 *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4404 if (NULL == *writePipe)
4406 PR_Close(*readPipe);
4407 close(pipefd[1]);
4408 return PR_FAILURE;
4410 return PR_SUCCESS;
4414 ** Set the inheritance attribute of a file descriptor.
4416 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
4417 PRFileDesc *fd,
4418 PRBool inheritable)
4421 * Only a non-layered, NSPR file descriptor can be inherited
4422 * by a child process.
4424 if (fd->identity != PR_NSPR_IO_LAYER)
4426 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4427 return PR_FAILURE;
4429 if (fd->secret->inheritable != inheritable)
4431 if (fcntl(fd->secret->md.osfd, F_SETFD,
4432 inheritable ? 0 : FD_CLOEXEC) == -1)
4434 return PR_FAILURE;
4436 fd->secret->inheritable = (_PRTriStateBool) inheritable;
4438 return PR_SUCCESS;
4441 /*****************************************************************************/
4442 /***************************** I/O friends methods ***************************/
4443 /*****************************************************************************/
4445 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
4447 PRFileDesc *fd;
4449 if (!_pr_initialized) _PR_ImplicitInitialization();
4450 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
4451 if (NULL == fd) close(osfd);
4452 return fd;
4453 } /* PR_ImportFile */
4455 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
4457 PRFileDesc *fd;
4459 if (!_pr_initialized) _PR_ImplicitInitialization();
4460 fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
4461 if (NULL == fd) close(osfd);
4462 return fd;
4463 } /* PR_ImportPipe */
4465 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
4467 PRFileDesc *fd;
4469 if (!_pr_initialized) _PR_ImplicitInitialization();
4470 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
4471 if (NULL == fd) close(osfd);
4472 #ifdef _PR_NEED_SECRET_AF
4473 if (NULL != fd) fd->secret->af = PF_INET;
4474 #endif
4475 return fd;
4476 } /* PR_ImportTCPSocket */
4478 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
4480 PRFileDesc *fd;
4482 if (!_pr_initialized) _PR_ImplicitInitialization();
4483 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
4484 if (NULL != fd) close(osfd);
4485 return fd;
4486 } /* PR_ImportUDPSocket */
4488 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
4490 PRFileDesc *fd;
4492 if (!_pr_initialized) _PR_ImplicitInitialization();
4494 fd = _PR_Getfd();
4496 if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4497 else
4499 fd->secret->md.osfd = osfd;
4500 fd->secret->inheritable = _PR_TRI_FALSE;
4501 fd->secret->state = _PR_FILEDESC_OPEN;
4502 fd->methods = PR_GetSocketPollFdMethods();
4505 return fd;
4506 } /* PR_CreateSocketPollFD */
4508 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
4510 if (NULL == fd)
4512 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
4513 return PR_FAILURE;
4515 fd->secret->state = _PR_FILEDESC_CLOSED;
4516 _PR_Putfd(fd);
4517 return PR_SUCCESS;
4518 } /* PR_DestroySocketPollFd */
4520 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
4522 PRInt32 osfd = -1;
4523 bottom = (NULL == bottom) ?
4524 NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
4525 if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4526 else osfd = bottom->secret->md.osfd;
4527 return osfd;
4528 } /* PR_FileDesc2NativeHandle */
4530 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
4531 PRInt32 handle)
4533 if (fd) fd->secret->md.osfd = handle;
4534 } /* PR_ChangeFileDescNativeHandle*/
4536 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
4538 PRStatus status = PR_SUCCESS;
4540 if (pt_TestAbort()) return PR_FAILURE;
4542 PR_Lock(_pr_flock_lock);
4543 while (-1 == fd->secret->lockCount)
4544 PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
4545 if (0 == fd->secret->lockCount)
4547 fd->secret->lockCount = -1;
4548 PR_Unlock(_pr_flock_lock);
4549 status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
4550 PR_Lock(_pr_flock_lock);
4551 fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
4552 PR_NotifyAllCondVar(_pr_flock_cv);
4554 else
4556 fd->secret->lockCount += 1;
4558 PR_Unlock(_pr_flock_lock);
4560 return status;
4561 } /* PR_LockFile */
4563 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
4565 PRStatus status = PR_SUCCESS;
4567 if (pt_TestAbort()) return PR_FAILURE;
4569 PR_Lock(_pr_flock_lock);
4570 if (0 == fd->secret->lockCount)
4572 status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
4573 if (PR_SUCCESS == status) fd->secret->lockCount = 1;
4575 else fd->secret->lockCount += 1;
4576 PR_Unlock(_pr_flock_lock);
4578 return status;
4579 } /* PR_TLockFile */
4581 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
4583 PRStatus status = PR_SUCCESS;
4585 if (pt_TestAbort()) return PR_FAILURE;
4587 PR_Lock(_pr_flock_lock);
4588 if (fd->secret->lockCount == 1)
4590 status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
4591 if (PR_SUCCESS == status) fd->secret->lockCount = 0;
4593 else fd->secret->lockCount -= 1;
4594 PR_Unlock(_pr_flock_lock);
4596 return status;
4600 * The next two entry points should not be in the API, but they are
4601 * defined here for historical (or hysterical) reasons.
4604 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
4606 #if defined(XP_UNIX) && !defined(AIX) && !defined(VMS)
4607 struct rlimit rlim;
4609 if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0)
4610 return -1;
4612 return rlim.rlim_max;
4613 #elif defined(AIX) || defined(VMS)
4614 return sysconf(_SC_OPEN_MAX);
4615 #endif
4618 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
4620 #if defined(XP_UNIX) && !defined(AIX) && !defined(VMS)
4621 struct rlimit rlim;
4622 PRInt32 tableMax = PR_GetSysfdTableMax();
4624 if (tableMax < 0) return -1;
4625 rlim.rlim_max = tableMax;
4627 /* Grow as much as we can; even if too big */
4628 if ( rlim.rlim_max < table_size )
4629 rlim.rlim_cur = rlim.rlim_max;
4630 else
4631 rlim.rlim_cur = table_size;
4633 if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0)
4634 return -1;
4636 return rlim.rlim_cur;
4637 #elif defined(AIX) || defined(VMS)
4638 return -1;
4639 #endif
4643 * PR_Stat is supported for backward compatibility; some existing Java
4644 * code uses it. New code should use PR_GetFileInfo.
4647 #ifndef NO_NSPR_10_SUPPORT
4648 PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
4650 static PRBool unwarned = PR_TRUE;
4651 if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
4653 if (pt_TestAbort()) return -1;
4655 if (-1 == stat(name, buf)) {
4656 pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
4657 return -1;
4658 } else {
4659 return 0;
4662 #endif /* ! NO_NSPR_10_SUPPORT */
4665 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
4667 static PRBool unwarned = PR_TRUE;
4668 if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
4669 memset(set, 0, sizeof(PR_fd_set));
4672 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
4674 static PRBool unwarned = PR_TRUE;
4675 if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
4676 PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
4678 set->harray[set->hsize++] = fh;
4681 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
4683 PRUint32 index, index2;
4684 static PRBool unwarned = PR_TRUE;
4685 if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
4687 for (index = 0; index<set->hsize; index++)
4688 if (set->harray[index] == fh) {
4689 for (index2=index; index2 < (set->hsize-1); index2++) {
4690 set->harray[index2] = set->harray[index2+1];
4692 set->hsize--;
4693 break;
4697 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
4699 PRUint32 index;
4700 static PRBool unwarned = PR_TRUE;
4701 if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
4702 for (index = 0; index<set->hsize; index++)
4703 if (set->harray[index] == fh) {
4704 return 1;
4706 return 0;
4709 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
4711 static PRBool unwarned = PR_TRUE;
4712 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
4713 PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
4715 set->narray[set->nsize++] = fd;
4718 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
4720 PRUint32 index, index2;
4721 static PRBool unwarned = PR_TRUE;
4722 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
4724 for (index = 0; index<set->nsize; index++)
4725 if (set->narray[index] == fd) {
4726 for (index2=index; index2 < (set->nsize-1); index2++) {
4727 set->narray[index2] = set->narray[index2+1];
4729 set->nsize--;
4730 break;
4734 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
4736 PRUint32 index;
4737 static PRBool unwarned = PR_TRUE;
4738 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
4739 for (index = 0; index<set->nsize; index++)
4740 if (set->narray[index] == fd) {
4741 return 1;
4743 return 0;
4746 #include <sys/types.h>
4747 #include <sys/time.h>
4748 #if !defined(SUNOS4) && !defined(HPUX) \
4749 && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
4750 #include <sys/select.h>
4751 #endif
4753 static PRInt32
4754 _PR_getset(PR_fd_set *pr_set, fd_set *set)
4756 PRUint32 index;
4757 PRInt32 max = 0;
4759 if (!pr_set)
4760 return 0;
4762 FD_ZERO(set);
4764 /* First set the pr file handle osfds */
4765 for (index=0; index<pr_set->hsize; index++) {
4766 FD_SET(pr_set->harray[index]->secret->md.osfd, set);
4767 if (pr_set->harray[index]->secret->md.osfd > max)
4768 max = pr_set->harray[index]->secret->md.osfd;
4770 /* Second set the native osfds */
4771 for (index=0; index<pr_set->nsize; index++) {
4772 FD_SET(pr_set->narray[index], set);
4773 if (pr_set->narray[index] > max)
4774 max = pr_set->narray[index];
4776 return max;
4779 static void
4780 _PR_setset(PR_fd_set *pr_set, fd_set *set)
4782 PRUint32 index, last_used;
4784 if (!pr_set)
4785 return;
4787 for (last_used=0, index=0; index<pr_set->hsize; index++) {
4788 if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
4789 pr_set->harray[last_used++] = pr_set->harray[index];
4792 pr_set->hsize = last_used;
4794 for (last_used=0, index=0; index<pr_set->nsize; index++) {
4795 if ( FD_ISSET(pr_set->narray[index], set) ) {
4796 pr_set->narray[last_used++] = pr_set->narray[index];
4799 pr_set->nsize = last_used;
4802 PR_IMPLEMENT(PRInt32) PR_Select(
4803 PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr,
4804 PR_fd_set *pr_ex, PRIntervalTime timeout)
4806 fd_set rd, wr, ex;
4807 struct timeval tv, *tvp;
4808 PRInt32 max, max_fd;
4809 PRInt32 rv;
4811 * For restarting select() if it is interrupted by a Unix signal.
4812 * We use these variables to figure out how much time has elapsed
4813 * and how much of the timeout still remains.
4815 PRIntervalTime start, elapsed, remaining;
4817 static PRBool unwarned = PR_TRUE;
4818 if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
4820 FD_ZERO(&rd);
4821 FD_ZERO(&wr);
4822 FD_ZERO(&ex);
4824 max_fd = _PR_getset(pr_rd, &rd);
4825 max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
4826 max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
4828 if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4829 tvp = NULL;
4830 } else {
4831 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
4832 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4833 timeout - PR_SecondsToInterval(tv.tv_sec));
4834 tvp = &tv;
4835 start = PR_IntervalNow();
4838 retry:
4839 rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
4840 (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
4842 if (rv == -1 && errno == EINTR) {
4843 if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4844 goto retry;
4845 } else {
4846 elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
4847 if (elapsed > timeout) {
4848 rv = 0; /* timed out */
4849 } else {
4850 remaining = timeout - elapsed;
4851 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
4852 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4853 remaining - PR_SecondsToInterval(tv.tv_sec));
4854 goto retry;
4859 if (rv > 0) {
4860 _PR_setset(pr_rd, &rd);
4861 _PR_setset(pr_wr, &wr);
4862 _PR_setset(pr_ex, &ex);
4863 } else if (rv == -1) {
4864 pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
4866 return rv;
4868 #endif /* defined(_PR_PTHREADS) */
4870 #ifdef MOZ_UNICODE
4871 /* ================ UTF16 Interfaces ================================ */
4872 PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
4873 const PRUnichar *name, PRIntn flags, PRIntn mode)
4875 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4876 return NULL;
4879 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
4881 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4882 return PR_FAILURE;
4885 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
4887 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4888 return NULL;
4891 PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
4893 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4894 return NULL;
4897 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
4899 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4900 return PR_FAILURE;
4902 /* ================ UTF16 Interfaces ================================ */
4903 #endif /* MOZ_UNICODE */
4905 /* ptio.c */