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
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.
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 ***** */
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)
53 #include <string.h> /* for memset() */
54 #include <sys/types.h>
58 #include <sys/socket.h>
62 #include <sys/ioctl.h>
64 #include <sys/utsname.h> /* for uname */
66 #if defined(SOLARIS) || defined(UNIXWARE)
67 #include <sys/filio.h> /* to pick up FIONREAD */
69 #ifdef _PR_POLL_AVAILABLE
73 /* To pick up sysconf() */
75 #include <dlfcn.h> /* for dlopen */
77 /* To pick up getrlimit() etc. */
79 #include <sys/resource.h>
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().
91 #include <sys/sendfile.h>
93 #define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
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 */
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 */
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
133 #define HAVE_SEND_FILE
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>
148 * Structure for the send_file() system call
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 */
185 #include <sys/sendfile.h>
190 #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
192 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
198 #ifdef _PR_IPV6_V6ONLY_PROBE
199 static PRBool _pr_ipv6_v6only_on_by_default
;
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 *
215 #error "Cannot determine architecture"
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. */
230 PRBool
IsValidNetAddr(const PRNetAddr
*addr
)
233 && (addr
->raw
.family
!= AF_UNIX
)
234 && (addr
->raw
.family
!= PR_AF_INET6
)
235 && (addr
->raw
.family
!= AF_INET
)) {
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.
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
)) {
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)
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)) \
297 typedef PRSize pt_SockLen
;
299 typedef PRIntn pt_SockLen
;
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
,
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 */
318 PRSize amount
; /* #3 - size of 'buffer', or */
319 pt_SockLen
*addr_len
; /* - length of address */
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 */
331 union { PRIntn flags
; } arg4
; /* #4 - read/write flags */
332 union { PRNetAddr
*addr
; } arg5
; /* #5 - send/recv address */
338 int filedesc
; /* descriptor of file to send */
339 int nbytes_to_send
; /* size of header and file */
346 int nbytes_to_send
; /* size of header and file */
353 int in_fd
; /* descriptor of file to send */
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
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 */
375 PTDebug pt_debug
; /* this is shared between several modules */
377 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc
*debug_out
, const char *msg
)
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
);
393 debug_out
, "\tstarted: %s[%lld]\n", buffer
, elapsed
);
395 debug_out
, "\tlocks [created: %u, destroyed: %u]\n",
396 stats
.locks_created
, stats
.locks_destroyed
);
398 debug_out
, "\tlocks [acquired: %u, released: %u]\n",
399 stats
.locks_acquired
, stats
.locks_released
);
401 debug_out
, "\tcvars [created: %u, destroyed: %u]\n",
402 stats
.cvars_created
, stats
.cvars_destroyed
);
404 debug_out
, "\tcvars [notified: %u, delayed_delete: %u]\n",
405 stats
.cvars_notified
, stats
.delayed_cv_deletes
);
406 } /* PT_FPrintStats */
410 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc
*debug_out
, const char *msg
)
413 } /* PT_FPrintStats */
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
)
427 fd_set rd
, wr
, *rdp
, *wrp
;
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
;
444 if (op
->event
& POLLIN
) {
446 FD_SET(op
->arg1
.osfd
, &rd
);
450 if (op
->event
& POLLOUT
) {
452 FD_SET(op
->arg1
.osfd
, &wr
);
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
;
468 if ((-1 == rv
) && ((errno
== EINTR
) || (errno
== EAGAIN
)))
469 continue; /* go around the loop again */
475 if ((op
->event
& POLLIN
) && FD_ISSET(op
->arg1
.osfd
, &rd
))
477 if ((op
->event
& POLLOUT
) && FD_ISSET(op
->arg1
.osfd
, &wr
))
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
);
491 now
= epoch
= PR_IntervalNow();
492 remaining
= op
->timeout
;
497 if (op
->event
& POLLIN
) {
499 FD_SET(op
->arg1
.osfd
, &rd
);
503 if (op
->event
& POLLOUT
) {
505 FD_SET(op
->arg1
.osfd
, &wr
);
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
;
532 if ((op
->event
& POLLIN
) && FD_ISSET(op
->arg1
.osfd
, &rd
))
534 if ((op
->event
& POLLOUT
) && FD_ISSET(op
->arg1
.osfd
, &wr
))
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
)
546 now
+= PR_MillisecondsToInterval(msecs
);
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
;
555 remaining
= op
->timeout
- elapsed
;
557 op
->result
.code
= -1;
558 op
->syserrno
= errno
;
559 op
->status
= pt_continuation_done
;
561 } while (pt_continuation_done
!= op
->status
);
565 } /* pt_poll_now_with_select */
567 #endif /* _PR_POLL_WITH_SELECT */
569 static void pt_poll_now(pt_Continuation
*op
)
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
);
587 switch (op
->timeout
) {
588 case PR_INTERVAL_NO_TIMEOUT
:
589 msecs
= PT_DEFAULT_POLL_MSEC
;
593 struct pollfd tmp_pfd
;
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
;
610 if ((-1 == rv
) && ((errno
== EINTR
) || (errno
== EAGAIN
)))
611 continue; /* go around the loop again */
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
)))
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
;
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
);
639 now
= epoch
= PR_IntervalNow();
640 remaining
= op
->timeout
;
644 struct pollfd tmp_pfd
;
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
;
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
)))
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
;
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
)
694 now
+= PR_MillisecondsToInterval(msecs
);
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
;
704 remaining
= op
->timeout
- elapsed
;
706 op
->result
.code
= -1;
707 op
->syserrno
= errno
;
708 op
->status
= pt_continuation_done
;
710 } while (pt_continuation_done
!= op
->status
);
716 static PRIntn
pt_Continue(pt_Continuation
*op
)
718 op
->status
= pt_continuation_pending
; /* set default value */
720 * let each thread call poll directly
723 PR_ASSERT(pt_continuation_done
== op
->status
);
724 return op
->result
.code
;
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;
738 return PR_TRUE
; /* this one is cooked */
739 } /* pt_connect_cont */
741 static PRBool
pt_accept_cont(pt_Continuation
*op
, PRInt16 revents
)
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 */
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
)) ?
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.
778 if (0 == op
->arg4
.flags
)
779 op
->result
.code
= read(
780 op
->arg1
.osfd
, op
->arg2
.buffer
, op
->arg3
.amount
);
782 op
->result
.code
= recv(
783 op
->arg1
.osfd
, op
->arg2
.buffer
, op
->arg3
.amount
, op
->arg4
.flags
);
785 op
->result
.code
= recv(
786 op
->arg1
.osfd
, op
->arg2
.buffer
, op
->arg3
.amount
, op
->arg4
.flags
);
788 op
->syserrno
= errno
;
789 return ((-1 == op
->result
.code
) &&
790 (EWOULDBLOCK
== op
->syserrno
|| EAGAIN
== op
->syserrno
)) ?
794 static PRBool
pt_send_cont(pt_Continuation
*op
, PRInt16 revents
)
798 PRInt32 tmp_amount
= op
->arg3
.amount
;
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
809 bytes
= write(op
->arg1
.osfd
, op
->arg2
.buffer
, tmp_amount
);
812 op
->arg1
.osfd
, op
->arg2
.buffer
, op
->arg3
.amount
, op
->arg4
.flags
);
814 op
->syserrno
= errno
;
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
))
825 tmp_amount
= tmp_amount
/2; /* half the bytes */
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;
845 else return PR_FALSE
;
848 static PRBool
pt_write_cont(pt_Continuation
*op
, PRInt16 revents
)
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
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;
874 else return PR_FALSE
;
875 } /* pt_write_cont */
877 static PRBool
pt_writev_cont(pt_Continuation
*op
, PRInt16 revents
)
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
888 bytes
= writev(op
->arg1
.osfd
, iov
, op
->arg3
.amount
);
889 op
->syserrno
= errno
;
890 if (bytes
>= 0) /* this is progress */
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;
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;
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
)) ?
952 } /* pt_recvfrom_cont */
955 static PRBool
pt_aix_sendfile_cont(pt_Continuation
*op
, PRInt16 revents
)
957 struct sf_parms
*sf_struct
= (struct sf_parms
*) op
->arg2
.buffer
;
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
;
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;
988 if (rv
== 1) { /* more data to send */
997 static PRBool
pt_hpux_sendfile_cont(pt_Continuation
*op
, PRInt16 revents
)
999 struct iovec
*hdtrl
= (struct iovec
*) op
->arg2
.buffer
;
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
;
1008 op
->result
.code
+= count
;
1009 } else if (op
->syserrno
!= EWOULDBLOCK
&& op
->syserrno
!= EAGAIN
) {
1010 op
->result
.code
= -1;
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
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
;
1058 static PRBool
pt_solaris_sendfile_cont(pt_Continuation
*op
, PRInt16 revents
)
1060 struct sendfilevec
*vec
= (struct sendfilevec
*) op
->arg2
.buffer
;
1064 count
= SOLARIS_SENDFILEV(op
->arg1
.osfd
, vec
, op
->arg3
.amount
, &xferred
);
1065 op
->syserrno
= errno
;
1066 PR_ASSERT((count
== -1) || (count
== xferred
));
1069 if (op
->syserrno
!= EWOULDBLOCK
&& op
->syserrno
!= EAGAIN
1070 && op
->syserrno
!= EINTR
) {
1071 op
->result
.code
= -1;
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 */
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
;
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
;
1108 #endif /* SOLARIS */
1111 static PRBool
pt_linux_sendfile_cont(pt_Continuation
*op
, PRInt16 revents
)
1116 oldoffset
= op
->offset
;
1117 rv
= sendfile(op
->arg1
.osfd
, op
->in_fd
, &op
->offset
, op
->count
);
1118 op
->syserrno
= errno
;
1121 if (op
->syserrno
!= EWOULDBLOCK
&& op
->syserrno
!= EAGAIN
) {
1122 op
->result
.code
= -1;
1127 PR_ASSERT(rv
== op
->offset
- oldoffset
);
1128 op
->result
.code
+= rv
;
1129 if (rv
< op
->count
) {
1137 void _PR_InitIO(void)
1140 memset(&pt_debug
, 0, sizeof(PTDebug
));
1141 pt_debug
.timeStarted
= PR_Now();
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.
1166 osfd
= socket(AF_INET6
, SOCK_STREAM
, 0);
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
;
1180 void _PR_CleanupIO(void)
1182 _PR_Putfd(_pr_stdin
);
1184 _PR_Putfd(_pr_stdout
);
1186 _PR_Putfd(_pr_stderr
);
1189 _PR_CleanupFdCache();
1193 PR_DestroyCondVar(_pr_flock_cv
);
1194 _pr_flock_cv
= NULL
;
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();
1217 case PR_StandardInput
: result
= _pr_stdin
; break;
1218 case PR_StandardOutput
: result
= _pr_stdout
; break;
1219 case PR_StandardError
: result
= _pr_stderr
; break;
1221 (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
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
;
1240 } /* pt_TestAbort */
1242 static void pt_MapError(void (*mapper
)(PRIntn
), PRIntn syserrno
)
1247 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0); break;
1249 PR_SetError(PR_IO_TIMEOUT_ERROR
, 0); break;
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);
1264 if (pt_TestAbort()) return PR_FAILURE
;
1266 if (_PR_FILEDESC_OPEN
== fd
->secret
->state
)
1268 if (-1 == close(fd
->secret
->md
.osfd
))
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
1283 pt_MapError(_PR_MD_MAP_CLOSE_ERROR
, errno
);
1287 pt_MapError(_PR_MD_MAP_CLOSE_ERROR
, errno
);
1291 fd
->secret
->state
= _PR_FILEDESC_CLOSED
;
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
);
1306 if ((bytes
== -1) && (syserrno
== EWOULDBLOCK
|| syserrno
== EAGAIN
)
1307 && (!fd
->secret
->nonblocking
))
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
;
1320 pt_MapError(_PR_MD_MAP_READ_ERROR
, syserrno
);
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
);
1334 if ( (bytes
>= 0) && (bytes
< amount
) && (!fd
->secret
->nonblocking
) )
1336 buf
= (char *) buf
+ bytes
;
1338 fNeedContinue
= PR_TRUE
;
1340 if ( (bytes
== -1) && (syserrno
== EWOULDBLOCK
|| syserrno
== EAGAIN
)
1341 && (!fd
->secret
->nonblocking
) )
1344 fNeedContinue
= PR_TRUE
;
1347 if (fNeedContinue
== PR_TRUE
)
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
;
1361 pt_MapError(_PR_MD_MAP_WRITE_ERROR
, syserrno
);
1365 static PRInt32
pt_Writev(
1366 PRFileDesc
*fd
, const PRIOVec
*iov
, PRInt32 iov_len
, PRIntervalTime timeout
)
1369 PRBool fNeedContinue
= PR_FALSE
;
1370 PRInt32 syserrno
, bytes
, rv
= -1;
1371 struct iovec osiov_local
[PR_MAX_IOVECTOR_SIZE
], *osiov
;
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
);
1396 if (!fd
->secret
->nonblocking
)
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);
1420 if (PR_INTERVAL_NO_WAIT
== timeout
)
1423 syserrno
= ETIMEDOUT
;
1425 else fNeedContinue
= PR_TRUE
;
1428 else if (syserrno
== EWOULDBLOCK
|| syserrno
== EAGAIN
)
1430 if (PR_INTERVAL_NO_WAIT
== timeout
) syserrno
= ETIMEDOUT
;
1434 fNeedContinue
= PR_TRUE
;
1439 if (fNeedContinue
== PR_TRUE
)
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
);
1457 static PRInt32
pt_Seek(PRFileDesc
*fd
, PRInt32 offset
, PRSeekWhence whence
)
1459 return _PR_MD_LSEEK(fd
, offset
, whence
);
1462 static PRInt64
pt_Seek64(PRFileDesc
*fd
, PRInt64 offset
, PRSeekWhence whence
)
1464 return _PR_MD_LSEEK64(fd
, offset
, whence
);
1467 static PRInt32
pt_Available_f(PRFileDesc
*fd
)
1469 PRInt32 result
, cur
, end
;
1471 cur
= _PR_MD_LSEEK(fd
, 0, PR_SEEK_CUR
);
1474 end
= _PR_MD_LSEEK(fd
, 0, PR_SEEK_END
);
1476 if ((cur
< 0) || (end
< 0)) {
1481 _PR_MD_LSEEK(fd
, cur
, PR_SEEK_SET
);
1484 } /* pt_Available_f */
1486 static PRInt64
pt_Available64_f(PRFileDesc
*fd
)
1488 PRInt64 result
, cur
, end
;
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
);
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
);
1513 pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR
, errno
);
1515 } /* pt_Available_s */
1517 static PRInt64
pt_Available64_s(PRFileDesc
*fd
)
1520 LL_I2L(rv
, pt_Available_s(fd
));
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
;
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
;
1541 static PRStatus
pt_Fsync(PRFileDesc
*fd
)
1544 if (pt_TestAbort()) return PR_FAILURE
;
1546 rv
= fsync(fd
->secret
->md
.osfd
);
1548 pt_MapError(_PR_MD_MAP_FSYNC_ERROR
, errno
);
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
;
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
) {
1572 #ifndef _PR_HAVE_SOCKADDR_LEN
1574 addrCopy
.raw
.family
= AF_INET6
;
1580 #ifdef _PR_HAVE_SOCKADDR_LEN
1582 ((struct sockaddr
*)&addrCopy
)->sa_len
= addr_len
;
1583 ((struct sockaddr
*)&addrCopy
)->sa_family
= md_af
;
1586 rv
= connect(fd
->secret
->md
.osfd
, (struct sockaddr
*)addrp
, addr_len
);
1588 if ((-1 == rv
) && (EINPROGRESS
== syserrno
) && (!fd
->secret
->nonblocking
))
1590 if (PR_INTERVAL_NO_WAIT
== timeout
) syserrno
= ETIMEDOUT
;
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
;
1605 pt_MapError(_PR_MD_MAP_CONNECT_ERROR
, syserrno
);
1611 static PRStatus
pt_ConnectContinue(
1612 PRFileDesc
*fd
, PRInt16 out_flags
)
1617 if (out_flags
& PR_POLL_NVAL
)
1619 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
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);
1629 osfd
= fd
->secret
->md
.osfd
;
1631 err
= _MD_unix_get_nonblocking_connect_error(osfd
);
1634 _PR_MD_MAP_CONNECT_ERROR(err
);
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
);
1647 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
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
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
);
1674 osfd
= accept(fd
->secret
->md
.osfd
, (struct sockaddr
*)addr
, &addr_len
);
1679 if (fd
->secret
->nonblocking
) goto failed
;
1681 if (EWOULDBLOCK
!= syserrno
&& EAGAIN
!= syserrno
1682 && ECONNABORTED
!= syserrno
)
1686 if (PR_INTERVAL_NO_WAIT
== timeout
) syserrno
= ETIMEDOUT
;
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 */
1706 addr
->raw
.family
= ((struct sockaddr
*)addr
)->sa_family
;
1708 #endif /* _PR_HAVE_SOCKADDR_LEN */
1710 if (addr
&& (AF_INET6
== addr
->raw
.family
))
1711 addr
->raw
.family
= PR_AF_INET6
;
1713 newfd
= pt_SetMethods(osfd
, PR_DESC_SOCKET_TCP
, PR_TRUE
, PR_FALSE
);
1714 if (newfd
== NULL
) close(osfd
); /* $$$ whoops! this doesn't work $$$ */
1717 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
1718 PR_ASSERT(IsValidNetAddrLen(addr
, addr_len
) == PR_TRUE
);
1721 * On Linux, experiments showed that the accepted sockets
1722 * inherit the TCP_NODELAY socket option of the listening
1725 newfd
->secret
->md
.tcp_nodelay
= fd
->secret
->md
.tcp_nodelay
;
1731 pt_MapError(_PR_MD_MAP_ACCEPT_ERROR
, syserrno
);
1735 static PRStatus
pt_Bind(PRFileDesc
*fd
, const PRNetAddr
*addr
)
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
;
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);
1758 #if defined(_PR_INET6)
1759 if (addr
->raw
.family
== PR_AF_INET6
) {
1761 #ifndef _PR_HAVE_SOCKADDR_LEN
1763 addrCopy
.raw
.family
= AF_INET6
;
1769 addr_len
= PR_NETADDR_SIZE(addr
);
1770 #ifdef _PR_HAVE_SOCKADDR_LEN
1772 ((struct sockaddr
*)&addrCopy
)->sa_len
= addr_len
;
1773 ((struct sockaddr
*)&addrCopy
)->sa_family
= md_af
;
1776 rv
= bind(fd
->secret
->md
.osfd
, (struct sockaddr
*)addrp
, addr_len
);
1779 pt_MapError(_PR_MD_MAP_BIND_ERROR
, errno
);
1785 static PRStatus
pt_Listen(PRFileDesc
*fd
, PRIntn backlog
)
1789 if (pt_TestAbort()) return PR_FAILURE
;
1791 rv
= listen(fd
->secret
->md
.osfd
, backlog
);
1793 pt_MapError(_PR_MD_MAP_LISTEN_ERROR
, errno
);
1799 static PRStatus
pt_Shutdown(PRFileDesc
*fd
, PRIntn how
)
1802 if (pt_TestAbort()) return PR_FAILURE
;
1804 rv
= shutdown(fd
->secret
->md
.osfd
, how
);
1807 pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR
, errno
);
1813 static PRInt16
pt_Poll(PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
)
1819 static PRInt32
pt_Recv(
1820 PRFileDesc
*fd
, void *buf
, PRInt32 amount
,
1821 PRIntn flags
, PRIntervalTime timeout
)
1823 PRInt32 syserrno
, bytes
= -1;
1828 else if (PR_MSG_PEEK
== flags
)
1832 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1836 if (pt_TestAbort()) return bytes
;
1838 /* recv() is a much slower call on pre-2.6 Solaris than read(). */
1839 #if defined(SOLARIS)
1841 bytes
= read(fd
->secret
->md
.osfd
, buf
, amount
);
1843 bytes
= recv(fd
->secret
->md
.osfd
, buf
, amount
, osflags
);
1845 bytes
= recv(fd
->secret
->md
.osfd
, buf
, amount
, osflags
);
1849 if ((bytes
== -1) && (syserrno
== EWOULDBLOCK
|| syserrno
== EAGAIN
)
1850 && (!fd
->secret
->nonblocking
))
1852 if (PR_INTERVAL_NO_WAIT
== timeout
) syserrno
= ETIMEDOUT
;
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
;
1868 pt_MapError(_PR_MD_MAP_RECV_ERROR
, syserrno
);
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
;
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 *)
1897 #define PT_SENDBUF_CAST
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
);
1910 bytes
= write(fd
->secret
->md
.osfd
, PT_SENDBUF_CAST buf
, tmp_amount
);
1912 bytes
= send(fd
->secret
->md
.osfd
, PT_SENDBUF_CAST buf
, amount
, flags
);
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
))
1925 tmp_amount
= tmp_amount
/2; /* half the bytes */
1931 if ( (bytes
>= 0) && (bytes
< amount
) && (!fd
->secret
->nonblocking
) )
1933 if (PR_INTERVAL_NO_WAIT
== timeout
)
1936 syserrno
= ETIMEDOUT
;
1940 buf
= (char *) buf
+ 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
;
1952 fNeedContinue
= PR_TRUE
;
1956 if (fNeedContinue
== PR_TRUE
)
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
;
1971 pt_MapError(_PR_MD_MAP_SEND_ERROR
, syserrno
);
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
;
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
) {
2000 #ifndef _PR_HAVE_SOCKADDR_LEN
2002 addrCopy
.raw
.family
= AF_INET6
;
2008 addr_len
= PR_NETADDR_SIZE(addr
);
2009 #ifdef _PR_HAVE_SOCKADDR_LEN
2011 ((struct sockaddr
*)&addrCopy
)->sa_len
= addr_len
;
2012 ((struct sockaddr
*)&addrCopy
)->sa_family
= md_af
;
2016 fd
->secret
->md
.osfd
, buf
, amount
, flags
,
2017 (struct sockaddr
*)addrp
, addr_len
);
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
)
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
;
2041 pt_MapError(_PR_MD_MAP_SENDTO_ERROR
, syserrno
);
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
;
2055 fd
->secret
->md
.osfd
, buf
, amount
, flags
,
2056 (struct sockaddr
*)addr
, &addr_len
);
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
)
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
2083 /* ignore the sa_len field of struct sockaddr */
2086 addr
->raw
.family
= ((struct sockaddr
*)addr
)->sa_family
;
2089 #endif /* _PR_HAVE_SOCKADDR_LEN */
2091 if (addr
&& (AF_INET6
== addr
->raw
.family
))
2092 addr
->raw
.family
= PR_AF_INET6
;
2095 pt_MapError(_PR_MD_MAP_RECVFROM_ERROR
, syserrno
);
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");
2111 * pt_AIXDispatchSendFile
2113 static PRInt32
pt_AIXDispatchSendFile(PRFileDesc
*sd
, PRSendFileData
*sfd
,
2114 PRTransmitFileFlags flags
, PRIntervalTime timeout
)
2118 rv
= pthread_once(&pt_aix_sendfile_once_block
,
2119 pt_aix_sendfile_init_routine
);
2121 if (pt_aix_sendfile_fptr
) {
2122 return pt_AIXSendFile(sd
, sfd
, flags
, timeout
);
2124 return PR_EmulateSendFile(sd
, sfd
, flags
, timeout
);
2127 #endif /* !HAVE_SEND_FILE */
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
;
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;
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
));
2176 rv
= AIX_SEND_FILE(&sd
->secret
->md
.osfd
, &sf_struct
, send_flags
);
2177 } while (rv
== -1 && (syserrno
= errno
) == EINTR
);
2180 if (syserrno
== EAGAIN
|| syserrno
== EWOULDBLOCK
) {
2181 count
= 0; /* Not a real error. Need to continue. */
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))) {
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
;
2212 pt_MapError(_MD_aix_map_sendfile_error
, syserrno
);
2215 if (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
) {
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
)));
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 */
2251 if (sfd
->file_nbytes
== 0) {
2253 if (fstat(sfd
->fd
->secret
->md
.osfd
, &statbuf
) == -1) {
2254 _PR_MD_MAP_FSTAT_ERROR(errno
);
2257 file_nbytes_to_send
= statbuf
.st_size
- sfd
->file_offset
;
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.
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
)) {
2283 if (count
!= -1 && count
< nbytes_to_send
) {
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
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
;
2335 pt_MapError(_MD_hpux_map_sendfile_error
, syserrno
);
2338 if (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
) {
2341 PR_ASSERT(count
== nbytes_to_send
);
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];
2374 if (sfd
->file_nbytes
== 0) {
2376 if (fstat(sfd
->fd
->secret
->md
.osfd
, &statbuf
) == -1) {
2377 _PR_MD_MAP_FSTAT_ERROR(errno
);
2380 file_nbytes_to_send
= statbuf
.st_size
- sfd
->file_offset
;
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
;
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
;
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
;
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
,
2424 PR_ASSERT((count
== -1) || (count
== xferred
));
2428 if (syserrno
== EINTR
2429 || syserrno
== EAGAIN
|| syserrno
== EWOULDBLOCK
) {
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 .
2439 syserrno
= 0; /* will be treated as EOF */
2442 if (count
!= -1 && count
< nbytes_to_send
) {
2444 struct sendfilevec
*vec
= sfv_struct
;
2445 PRInt32 rem
= count
;
2447 while (rem
>= vec
->sfv_len
) {
2448 rem
-= vec
->sfv_len
;
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
;
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
;
2473 pt_MapError(_MD_solaris_map_sendfile_error
, syserrno
);
2476 if (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
) {
2479 PR_ASSERT(count
== nbytes_to_send
);
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)
2489 PRBool close_it
= PR_FALSE
;
2492 * We do not want to unload libsendfile.so. This handle is leaked
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
));
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
));
2520 * pt_SolarisDispatchSendFile
2522 static PRInt32
pt_SolarisDispatchSendFile(PRFileDesc
*sd
, PRSendFileData
*sfd
,
2523 PRTransmitFileFlags flags
, PRIntervalTime timeout
)
2527 rv
= pthread_once(&pt_solaris_sendfilev_once_block
,
2528 pt_solaris_sendfilev_init_routine
);
2530 if (pt_solaris_sendfilev_fptr
) {
2531 return pt_SolarisSendFile(sd
, sfd
, flags
, timeout
);
2533 return PR_EmulateSendFile(sd
, sfd
, flags
, timeout
);
2536 #endif /* !HAVE_SENDFILEV */
2538 #endif /* SOLARIS */
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
;
2564 PRBool tcp_cork_enabled
= PR_FALSE
;
2567 if (sfd
->file_nbytes
== 0) {
2569 if (fstat(sfd
->fd
->secret
->md
.osfd
, &statbuf
) == -1) {
2570 _PR_MD_MAP_FSTAT_ERROR(errno
);
2573 file_nbytes_to_send
= statbuf
.st_size
- sfd
->file_offset
;
2575 file_nbytes_to_send
= sfd
->file_nbytes
;
2578 if ((sfd
->hlen
!= 0 || sfd
->tlen
!= 0)
2579 && sd
->secret
->md
.tcp_nodelay
== 0) {
2581 if (setsockopt(sd
->secret
->md
.osfd
, SOL_TCP
, TCP_CORK
,
2582 &tcp_cork
, sizeof tcp_cork
) == 0) {
2583 tcp_cork_enabled
= PR_TRUE
;
2586 if (syserrno
!= EINVAL
) {
2587 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno
);
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
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
);
2609 if (file_nbytes_to_send
!= 0) {
2610 offset
= sfd
->file_offset
;
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
);
2616 if (syserrno
!= EAGAIN
&& syserrno
!= EWOULDBLOCK
) {
2617 _MD_linux_map_sendfile_error(syserrno
);
2623 PR_ASSERT(rv
== offset
- sfd
->file_offset
);
2626 if (rv
< file_nbytes_to_send
) {
2629 op
.arg1
.osfd
= sd
->secret
->md
.osfd
;
2630 op
.in_fd
= sfd
->fd
->secret
->md
.osfd
;
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
;
2640 pt_MapError(_MD_linux_map_sendfile_error
, syserrno
);
2646 if (sfd
->tlen
!= 0) {
2647 rv
= PR_Send(sd
, sfd
->trailer
, sfd
->tlen
, 0, timeout
);
2656 if (tcp_cork_enabled
) {
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
);
2665 if (flags
& PR_TRANSMITFILE_CLOSE_SOCKET
) {
2668 PR_ASSERT(count
== sfd
->hlen
+ sfd
->tlen
+ file_nbytes_to_send
);
2675 extern int _pr_aix_send_file_use_disabled
;
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);
2690 return(pt_HPUXSendFile(sd
, sfd
, flags
, timeout
));
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
));
2703 return(pt_AIXSendFile(sd
, sfd
, flags
, timeout
));
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
));
2712 return(pt_SolarisDispatchSendFile(sd
, sfd
, flags
, timeout
));
2713 #endif /* HAVE_SENDFILEV */
2714 #elif defined(LINUX)
2715 return(pt_LinuxSendFile(sd
, sfd
, flags
, timeout
));
2717 return(PR_EmulateSendFile(sd
, sfd
, flags
, timeout
));
2721 static PRInt32
pt_TransmitFile(
2722 PRFileDesc
*sd
, PRFileDesc
*fd
, const void *headers
,
2723 PRInt32 hlen
, PRTransmitFileFlags flags
, PRIntervalTime timeout
)
2728 sfd
.file_offset
= 0;
2729 sfd
.file_nbytes
= 0;
2730 sfd
.header
= headers
;
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
)
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);
2752 rv
= PR_EmulateAcceptRead(sd
, nd
, raddr
, buf
, amount
, timeout
);
2754 } /* pt_AcceptRead */
2756 static PRStatus
pt_GetSockName(PRFileDesc
*fd
, PRNetAddr
*addr
)
2759 pt_SockLen addr_len
= sizeof(PRNetAddr
);
2761 if (pt_TestAbort()) return PR_FAILURE
;
2764 fd
->secret
->md
.osfd
, (struct sockaddr
*)addr
, &addr_len
);
2766 pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR
, errno
);
2769 #ifdef _PR_HAVE_SOCKADDR_LEN
2770 /* ignore the sa_len field of struct sockaddr */
2773 addr
->raw
.family
= ((struct sockaddr
*)addr
)->sa_family
;
2775 #endif /* _PR_HAVE_SOCKADDR_LEN */
2777 if (AF_INET6
== addr
->raw
.family
)
2778 addr
->raw
.family
= PR_AF_INET6
;
2780 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
2781 PR_ASSERT(IsValidNetAddrLen(addr
, addr_len
) == PR_TRUE
);
2784 } /* pt_GetSockName */
2786 static PRStatus
pt_GetPeerName(PRFileDesc
*fd
, PRNetAddr
*addr
)
2789 pt_SockLen addr_len
= sizeof(PRNetAddr
);
2791 if (pt_TestAbort()) return PR_FAILURE
;
2794 fd
->secret
->md
.osfd
, (struct sockaddr
*)addr
, &addr_len
);
2797 pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR
, errno
);
2800 #ifdef _PR_HAVE_SOCKADDR_LEN
2801 /* ignore the sa_len field of struct sockaddr */
2804 addr
->raw
.family
= ((struct sockaddr
*)addr
)->sa_family
;
2806 #endif /* _PR_HAVE_SOCKADDR_LEN */
2808 if (AF_INET6
== addr
->raw
.family
)
2809 addr
->raw
.family
= PR_AF_INET6
;
2811 PR_ASSERT(IsValidNetAddr(addr
) == PR_TRUE
);
2812 PR_ASSERT(IsValidNetAddrLen(addr
, addr_len
) == PR_TRUE
);
2815 } /* pt_GetPeerName */
2817 static PRStatus
pt_GetSocketOption(PRFileDesc
*fd
, PRSocketOptionData
*data
)
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
;
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
);
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
);
2851 case PR_SockOpt_Reuseaddr
:
2852 case PR_SockOpt_Keepalive
:
2853 case PR_SockOpt_NoDelay
:
2854 case PR_SockOpt_Broadcast
:
2857 length
= sizeof(PRIntn
);
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
;
2864 case PR_SockOpt_McastLoopback
:
2867 length
= sizeof(xbool
);
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
;
2875 case PR_SockOpt_RecvBufferSize
:
2876 case PR_SockOpt_SendBufferSize
:
2877 case PR_SockOpt_MaxSegment
:
2880 length
= sizeof(PRIntn
);
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
;
2887 case PR_SockOpt_IpTimeToLive
:
2888 case PR_SockOpt_IpTypeOfService
:
2890 length
= sizeof(PRUintn
);
2892 fd
->secret
->md
.osfd
, level
, name
,
2893 (char*)&data
->value
.ip_ttl
, &length
);
2894 PR_ASSERT((-1 == rv
) || (sizeof(PRIntn
) == length
));
2897 case PR_SockOpt_McastTimeToLive
:
2900 length
= sizeof(ttl
);
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
;
2908 case PR_SockOpt_AddMember
:
2909 case PR_SockOpt_DropMember
:
2911 struct ip_mreq mreq
;
2912 length
= sizeof(mreq
);
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
;
2922 case PR_SockOpt_McastInterface
:
2924 length
= sizeof(data
->value
.mcast_if
.inet
.ip
);
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
));
2933 PR_NOT_REACHED("Unknown socket option");
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
)
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
;
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
);
2967 fd
->secret
->md
.osfd
, level
, name
, (char*)&linger
, sizeof(linger
));
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;
2977 fd
->secret
->md
.osfd
, level
, name
,
2978 (char*)&value
, sizeof(PRIntn
));
2980 /* for pt_LinuxSendFile */
2981 if (name
== TCP_NODELAY
&& rv
== 0) {
2982 fd
->secret
->md
.tcp_nodelay
= value
;
2987 case PR_SockOpt_McastLoopback
:
2989 PRUint8 xbool
= data
->value
.mcast_loopback
? 1 : 0;
2991 fd
->secret
->md
.osfd
, level
, name
,
2992 (char*)&xbool
, sizeof(xbool
));
2995 case PR_SockOpt_RecvBufferSize
:
2996 case PR_SockOpt_SendBufferSize
:
2997 case PR_SockOpt_MaxSegment
:
2999 PRIntn value
= data
->value
.recv_buffer_size
;
3001 fd
->secret
->md
.osfd
, level
, name
,
3002 (char*)&value
, sizeof(PRIntn
));
3005 case PR_SockOpt_IpTimeToLive
:
3006 case PR_SockOpt_IpTypeOfService
:
3009 fd
->secret
->md
.osfd
, level
, name
,
3010 (char*)&data
->value
.ip_ttl
, sizeof(PRUintn
));
3013 case PR_SockOpt_McastTimeToLive
:
3015 PRUint8 ttl
= data
->value
.mcast_ttl
;
3017 fd
->secret
->md
.osfd
, level
, name
,
3018 (char*)&ttl
, sizeof(ttl
));
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
;
3030 fd
->secret
->md
.osfd
, level
, name
,
3031 (char*)&mreq
, sizeof(mreq
));
3034 case PR_SockOpt_McastInterface
:
3037 fd
->secret
->md
.osfd
, level
, name
,
3038 (char*)&data
->value
.mcast_if
.inet
.ip
,
3039 sizeof(data
->value
.mcast_if
.inet
.ip
));
3043 PR_NOT_REACHED("Unknown socket option");
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
= {
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
,
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
= {
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
,
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
= {
3141 (PRSeekFN
)_PR_InvalidInt
,
3142 (PRSeek64FN
)_PR_InvalidInt64
,
3143 (PRFileInfoFN
)_PR_InvalidStatus
,
3144 (PRFileInfo64FN
)_PR_InvalidStatus
,
3153 (PRRecvfromFN
)_PR_InvalidInt
,
3154 (PRSendtoFN
)_PR_InvalidInt
,
3160 (PRReservedFN
)_PR_InvalidInt
,
3161 (PRReservedFN
)_PR_InvalidInt
,
3166 (PRReservedFN
)_PR_InvalidInt
,
3167 (PRReservedFN
)_PR_InvalidInt
,
3168 (PRReservedFN
)_PR_InvalidInt
,
3169 (PRReservedFN
)_PR_InvalidInt
3172 static PRIOMethods _pr_udp_methods
= {
3180 (PRSeekFN
)_PR_InvalidInt
,
3181 (PRSeek64FN
)_PR_InvalidInt64
,
3182 (PRFileInfoFN
)_PR_InvalidStatus
,
3183 (PRFileInfo64FN
)_PR_InvalidStatus
,
3186 (PRAcceptFN
)_PR_InvalidDesc
,
3195 (PRAcceptreadFN
)_PR_InvalidInt
,
3196 (PRTransmitfileFN
)_PR_InvalidInt
,
3199 (PRReservedFN
)_PR_InvalidInt
,
3200 (PRReservedFN
)_PR_InvalidInt
,
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
= {
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
,
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
3257 #error "Can't determine architecture"
3261 * Put a Unix file descriptor in non-blocking mode.
3263 static void pt_MakeFdNonblock(PRIntn osfd
)
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.
3286 static void pt_MakeSocketNonblock(PRIntn osfd
)
3289 (void)ioctl(osfd
, FIOSNBIO
, &one
);
3292 #define pt_MakeSocketNonblock pt_MakeFdNonblock
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);
3303 fd
->secret
->md
.osfd
= osfd
;
3304 fd
->secret
->state
= _PR_FILEDESC_OPEN
;
3305 if (imported
) fd
->secret
->inheritable
= _PR_TRI_UNKNOWN
;
3308 /* By default, a Unix fd is not closed on exec. */
3311 flags
= fcntl(osfd
, F_GETFD
, 0);
3312 PR_ASSERT(0 == flags
);
3314 fd
->secret
->inheritable
= _PR_TRI_TRUE
;
3319 fd
->methods
= PR_GetFileMethods();
3321 case PR_DESC_SOCKET_TCP
:
3322 fd
->methods
= PR_GetTCPMethods();
3323 #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
3324 if (!isAcceptedSocket
) pt_MakeSocketNonblock(osfd
);
3326 pt_MakeSocketNonblock(osfd
);
3329 case PR_DESC_SOCKET_UDP
:
3330 fd
->methods
= PR_GetUDPMethods();
3331 pt_MakeFdNonblock(osfd
);
3334 fd
->methods
= PR_GetPipeMethods();
3335 pt_MakeFdNonblock(osfd
);
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 */
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
;
3390 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
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()
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).
3409 if (uname(&u
) != 0 || atoi(u
.release
) < 7)
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);
3427 #endif /* _PR_INET6_PROBE */
3430 PR_IMPLEMENT(PRFileDesc
*) PR_Socket(PRInt32 domain
, PRInt32 type
, PRInt32 proto
)
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);
3448 if (type
== SOCK_STREAM
) ftype
= PR_DESC_SOCKET_TCP
;
3449 else if (type
== SOCK_DGRAM
) ftype
= PR_DESC_SOCKET_UDP
;
3452 (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR
, 0);
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
)
3462 if (PR_AF_INET6
== domain
)
3466 osfd
= socket(domain
, type
, proto
);
3467 if (osfd
== -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR
, errno
);
3470 #ifdef _PR_IPV6_V6ONLY_PROBE
3471 if ((domain
== AF_INET6
) && _pr_ipv6_v6only_on_by_default
)
3474 (void)setsockopt(osfd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
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
;
3484 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
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
)) {
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
)
3525 #elif defined(O_FSYNC)
3528 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
3533 ** We have to hold the lock across the creation in order to
3534 ** enforce the sematics of PR_Rename(). (see the latter for
3537 if (flags
& PR_CREATE_FILE
)
3540 if (NULL
!=_pr_rename_lock
)
3541 PR_Lock(_pr_rename_lock
);
3544 osfd
= _md_iovector
._open64(name
, osflags
, mode
);
3547 if ((flags
& PR_CREATE_FILE
) && (NULL
!=_pr_rename_lock
))
3548 PR_Unlock(_pr_rename_lock
);
3551 pt_MapError(_PR_MD_MAP_OPEN_ERROR
, syserrno
);
3554 fd
= pt_SetMethods(osfd
, PR_DESC_FILE
, PR_FALSE
, PR_FALSE
);
3555 if (fd
== NULL
) close(osfd
); /* $$$ whoops! this is bad $$$ */
3560 PR_IMPLEMENT(PRFileDesc
*) PR_Open(const char *name
, PRIntn flags
, PRIntn mode
)
3562 return PR_OpenFile(name
, flags
, mode
);
3565 PR_IMPLEMENT(PRStatus
) PR_Delete(const char *name
)
3569 if (!_pr_initialized
) _PR_ImplicitInitialization();
3571 if (pt_TestAbort()) return PR_FAILURE
;
3576 pt_MapError(_PR_MD_MAP_UNLINK_ERROR
, errno
);
3582 PR_IMPLEMENT(PRStatus
) PR_Access(const char *name
, PRAccessHow how
)
3586 if (pt_TestAbort()) return PR_FAILURE
;
3590 case PR_ACCESS_READ_OK
:
3591 rv
= access(name
, R_OK
);
3593 case PR_ACCESS_WRITE_OK
:
3594 rv
= access(name
, W_OK
);
3596 case PR_ACCESS_EXISTS
:
3598 rv
= access(name
, F_OK
);
3600 if (0 == rv
) return PR_SUCCESS
;
3601 pt_MapError(_PR_MD_MAP_ACCESS_ERROR
, errno
);
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
)
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
)
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
3635 PR_Lock(_pr_rename_lock
);
3636 rv
= access(to
, F_OK
);
3639 PR_SetError(PR_FILE_EXISTS_ERROR
, 0);
3644 rv
= rename(from
, to
);
3646 pt_MapError(_PR_MD_MAP_RENAME_ERROR
, errno
);
3648 PR_Unlock(_pr_rename_lock
);
3649 return (-1 == rv
) ? PR_FAILURE
: PR_SUCCESS
;
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
);
3669 PR_IMPLEMENT(PRStatus
) PR_MakeDir(const char *name
, PRIntn mode
)
3673 if (pt_TestAbort()) return PR_FAILURE
;
3676 ** This lock is used to enforce rename semantics as described
3679 if (NULL
!=_pr_rename_lock
)
3680 PR_Lock(_pr_rename_lock
);
3681 rv
= mkdir(name
, mode
);
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
;
3690 PR_IMPLEMENT(PRStatus
) PR_MkDir(const char *name
, PRIntn mode
)
3692 return PR_MakeDir(name
, mode
);
3695 PR_IMPLEMENT(PRStatus
) PR_RmDir(const char *name
)
3699 if (pt_TestAbort()) return PR_FAILURE
;
3705 pt_MapError(_PR_MD_MAP_RMDIR_ERROR
, errno
);
3711 PR_IMPLEMENT(PRDir
*) PR_OpenDir(const char *name
)
3716 if (pt_TestAbort()) return dir
;
3718 osdir
= opendir(name
);
3720 pt_MapError(_PR_MD_MAP_OPENDIR_ERROR
, errno
);
3723 dir
= PR_NEWZAP(PRDir
);
3727 (void)closedir(osdir
);
3732 static PRInt32
_pr_poll_with_poll(
3733 PRPollDesc
*pds
, PRIntn npds
, PRIntervalTime timeout
)
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
);
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
;
3759 PRThread
*me
= PR_GetCurrentThread();
3760 if (npds
> me
->syspoll_count
)
3762 PR_Free(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);
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
)(
3787 pds
[index
].in_flags
& ~PR_POLL_WRITE
,
3790 if (pds
[index
].in_flags
& PR_POLL_WRITE
)
3792 in_flags_write
= (pds
[index
].fd
->methods
->poll
)(
3794 pds
[index
].in_flags
& ~PR_POLL_READ
,
3797 if ((0 != (in_flags_read
& out_flags_read
))
3798 || (0 != (in_flags_write
& out_flags_write
)))
3800 /* this one is ready right now */
3804 * We will return without calling the system
3805 * poll function. So zero the out_flags
3806 * fields of all the poll descriptors before
3810 for (i
= 0; i
< index
; i
++)
3812 pds
[i
].out_flags
= 0;
3816 pds
[index
].out_flags
= out_flags_read
| out_flags_write
;
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
))
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
;
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 */
3877 /* make poll() ignore this entry */
3878 syspoll
[index
].fd
= -1;
3879 syspoll
[index
].events
= 0;
3880 pds
[index
].out_flags
= 0;
3887 case PR_INTERVAL_NO_WAIT
: msecs
= 0; break;
3888 case PR_INTERVAL_NO_TIMEOUT
: msecs
= -1; break;
3890 msecs
= PR_IntervalToMilliseconds(timeout
);
3891 start
= PR_IntervalNow();
3895 ready
= poll(syspoll
, npds
, msecs
);
3898 PRIntn oserror
= errno
;
3900 if (EINTR
== oserror
)
3902 if (timeout
== PR_INTERVAL_NO_TIMEOUT
)
3904 else if (timeout
== PR_INTERVAL_NO_WAIT
)
3905 ready
= 0; /* don't retry, just time out */
3908 elapsed
= (PRIntervalTime
) (PR_IntervalNow()
3910 if (elapsed
> timeout
)
3911 ready
= 0; /* timed out */
3914 remaining
= timeout
- elapsed
;
3915 msecs
= PR_IntervalToMilliseconds(remaining
);
3922 _PR_MD_MAP_POLL_ERROR(oserror
);
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
;
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
)
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
);
4002 #define STACK_POLL_DESC_COUNT 64
4003 int stack_selectfd
[STACK_POLL_DESC_COUNT
];
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
;
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);
4026 me
->selectfd_count
= npds
;
4028 selectfd
= me
->selectfd_list
;
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
)(
4045 pds
[index
].in_flags
& ~PR_POLL_WRITE
,
4048 if (pds
[index
].in_flags
& PR_POLL_WRITE
)
4050 in_flags_write
= (pds
[index
].fd
->methods
->poll
)(
4052 pds
[index
].in_flags
& ~PR_POLL_READ
,
4055 if ((0 != (in_flags_read
& out_flags_read
))
4056 || (0 != (in_flags_write
& out_flags_write
)))
4058 /* this one is ready right now */
4062 * We will return without calling the system
4063 * poll function. So zero the out_flags
4064 * fields of all the poll descriptors before
4068 for (i
= 0; i
< index
; i
++)
4070 pds
[i
].out_flags
= 0;
4074 pds
[index
].out_flags
= out_flags_read
| out_flags_write
;
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
))
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
)
4134 FD_SET(bottom
->secret
->md
.osfd
, &rd
);
4139 FD_SET(bottom
->secret
->md
.osfd
, &wr
);
4144 FD_SET(bottom
->secret
->md
.osfd
, &ex
);
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 */
4166 pds
[index
].out_flags
= 0;
4171 if (maxfd
>= FD_SETSIZE
)
4174 * maxfd too large to be used with select, fall back to
4177 return(_pr_poll_with_poll(pds
, npds
, timeout
));
4181 case PR_INTERVAL_NO_WAIT
:
4186 case PR_INTERVAL_NO_TIMEOUT
:
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
;
4194 start
= PR_IntervalNow();
4198 ready
= select(maxfd
+ 1, rdp
, wrp
, exp
, tvp
);
4201 PRIntn oserror
= errno
;
4203 if ((EINTR
== oserror
) || (EAGAIN
== oserror
))
4205 if (timeout
== PR_INTERVAL_NO_TIMEOUT
)
4207 else if (timeout
== PR_INTERVAL_NO_WAIT
)
4208 ready
= 0; /* don't retry, just time out */
4211 elapsed
= (PRIntervalTime
) (PR_IntervalNow()
4213 if (elapsed
> timeout
)
4214 ready
= 0; /* timed out */
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
) *
4225 } else if (EBADF
== oserror
)
4227 /* find all the bad fds */
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
;
4243 _PR_MD_MAP_SELECT_ERROR(oserror
);
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
;
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
));
4297 return(_pr_poll_with_poll(pds
, npds
, timeout
));
4301 PR_IMPLEMENT(PRDirEntry
*) PR_ReadDir(PRDir
*dir
, PRDirFlags flags
)
4305 if (pt_TestAbort()) return NULL
;
4310 dp
= readdir(dir
->md
.d
);
4313 pt_MapError(_PR_MD_MAP_READDIR_ERROR
, errno
);
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]))
4327 dir
->d
.name
= dp
->d_name
;
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])
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
);
4366 fds
[0] = pt_SetMethods(osfd
[0], PR_DESC_SOCKET_TCP
, PR_FALSE
, PR_FALSE
);
4367 if (fds
[0] == NULL
) {
4372 fds
[1] = pt_SetMethods(osfd
[1], PR_DESC_SOCKET_TCP
, PR_FALSE
, PR_FALSE
);
4373 if (fds
[1] == NULL
) {
4379 } /* PR_NewTCPSocketPair */
4381 PR_IMPLEMENT(PRStatus
) PR_CreatePipe(
4382 PRFileDesc
**readPipe
,
4383 PRFileDesc
**writePipe
4388 if (pt_TestAbort()) return PR_FAILURE
;
4390 if (pipe(pipefd
) == -1)
4392 /* XXX map pipe error */
4393 PR_SetError(PR_UNKNOWN_ERROR
, errno
);
4396 *readPipe
= pt_SetMethods(pipefd
[0], PR_DESC_PIPE
, PR_FALSE
, PR_FALSE
);
4397 if (NULL
== *readPipe
)
4403 *writePipe
= pt_SetMethods(pipefd
[1], PR_DESC_PIPE
, PR_FALSE
, PR_FALSE
);
4404 if (NULL
== *writePipe
)
4406 PR_Close(*readPipe
);
4414 ** Set the inheritance attribute of a file descriptor.
4416 PR_IMPLEMENT(PRStatus
) PR_SetFDInheritable(
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);
4429 if (fd
->secret
->inheritable
!= inheritable
)
4431 if (fcntl(fd
->secret
->md
.osfd
, F_SETFD
,
4432 inheritable
? 0 : FD_CLOEXEC
) == -1)
4436 fd
->secret
->inheritable
= (_PRTriStateBool
) inheritable
;
4441 /*****************************************************************************/
4442 /***************************** I/O friends methods ***************************/
4443 /*****************************************************************************/
4445 PR_IMPLEMENT(PRFileDesc
*) PR_ImportFile(PRInt32 osfd
)
4449 if (!_pr_initialized
) _PR_ImplicitInitialization();
4450 fd
= pt_SetMethods(osfd
, PR_DESC_FILE
, PR_FALSE
, PR_TRUE
);
4451 if (NULL
== fd
) close(osfd
);
4453 } /* PR_ImportFile */
4455 PR_IMPLEMENT(PRFileDesc
*) PR_ImportPipe(PRInt32 osfd
)
4459 if (!_pr_initialized
) _PR_ImplicitInitialization();
4460 fd
= pt_SetMethods(osfd
, PR_DESC_PIPE
, PR_FALSE
, PR_TRUE
);
4461 if (NULL
== fd
) close(osfd
);
4463 } /* PR_ImportPipe */
4465 PR_IMPLEMENT(PRFileDesc
*) PR_ImportTCPSocket(PRInt32 osfd
)
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
;
4476 } /* PR_ImportTCPSocket */
4478 PR_IMPLEMENT(PRFileDesc
*) PR_ImportUDPSocket(PRInt32 osfd
)
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
);
4486 } /* PR_ImportUDPSocket */
4488 PR_IMPLEMENT(PRFileDesc
*) PR_CreateSocketPollFd(PRInt32 osfd
)
4492 if (!_pr_initialized
) _PR_ImplicitInitialization();
4496 if (fd
== NULL
) PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
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();
4506 } /* PR_CreateSocketPollFD */
4508 PR_IMPLEMENT(PRStatus
) PR_DestroySocketPollFd(PRFileDesc
*fd
)
4512 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
4515 fd
->secret
->state
= _PR_FILEDESC_CLOSED
;
4518 } /* PR_DestroySocketPollFd */
4520 PR_IMPLEMENT(PRInt32
) PR_FileDesc2NativeHandle(PRFileDesc
*bottom
)
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
;
4528 } /* PR_FileDesc2NativeHandle */
4530 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc
*fd
,
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
);
4556 fd
->secret
->lockCount
+= 1;
4558 PR_Unlock(_pr_flock_lock
);
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
);
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
);
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)
4609 if ( getrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
4612 return rlim
.rlim_max
;
4613 #elif defined(AIX) || defined(VMS)
4614 return sysconf(_SC_OPEN_MAX
);
4618 PR_IMPLEMENT(PRInt32
) PR_SetSysfdTableSize(PRIntn table_size
)
4620 #if defined(XP_UNIX) && !defined(AIX) && !defined(VMS)
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
;
4631 rlim
.rlim_cur
= table_size
;
4633 if ( setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
4636 return rlim
.rlim_cur
;
4637 #elif defined(AIX) || defined(VMS)
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
);
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];
4697 PR_IMPLEMENT(PRInt32
) PR_FD_ISSET(PRFileDesc
*fh
, PR_fd_set
*set
)
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
) {
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];
4734 PR_IMPLEMENT(PRInt32
) PR_FD_NISSET(PRInt32 fd
, PR_fd_set
*set
)
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
) {
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>
4754 _PR_getset(PR_fd_set
*pr_set
, fd_set
*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
];
4780 _PR_setset(PR_fd_set
*pr_set
, fd_set
*set
)
4782 PRUint32 index
, last_used
;
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
)
4807 struct timeval tv
, *tvp
;
4808 PRInt32 max
, max_fd
;
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");
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
) {
4831 tv
.tv_sec
= (PRInt32
)PR_IntervalToSeconds(timeout
);
4832 tv
.tv_usec
= (PRInt32
)PR_IntervalToMicroseconds(
4833 timeout
- PR_SecondsToInterval(tv
.tv_sec
));
4835 start
= PR_IntervalNow();
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
) {
4846 elapsed
= (PRIntervalTime
) (PR_IntervalNow() - start
);
4847 if (elapsed
> timeout
) {
4848 rv
= 0; /* timed out */
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
));
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
);
4868 #endif /* defined(_PR_PTHREADS) */
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);
4879 PR_IMPLEMENT(PRStatus
) PR_CloseDirUTF16(PRDir
*dir
)
4881 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
4885 PR_IMPLEMENT(PRDirUTF16
*) PR_OpenDirUTF16(const PRUnichar
*name
)
4887 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
4891 PR_IMPLEMENT(PRDirEntryUTF16
*) PR_ReadDirUTF16(PRDirUTF16
*dir
, PRDirFlags flags
)
4893 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
4897 PR_IMPLEMENT(PRStatus
) PR_GetFileInfo64UTF16(const PRUnichar
*fn
, PRFileInfo64
*info
)
4899 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
4902 /* ================ UTF16 Interfaces ================================ */
4903 #endif /* MOZ_UNICODE */