nsprpub/pr/src/pthreads/ptio.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7 ** File:   ptio.c
     8 ** Descritpion:  Implemenation of I/O methods for pthreads
     9 */
    11 #if defined(_PR_PTHREADS)
    13 #if defined(_PR_POLL_WITH_SELECT)
    14 #if !(defined(HPUX) && defined(_USE_BIG_FDS))
    15 /* set fd limit for select(), before including system header files */
    16 #define FD_SETSIZE (16 * 1024)
    17 #endif
    18 #endif
    20 #include <pthread.h>
    21 #include <string.h>  /* for memset() */
    22 #include <sys/types.h>
    23 #include <dirent.h>
    24 #include <fcntl.h>
    25 #include <unistd.h>
    26 #include <sys/socket.h>
    27 #include <sys/stat.h>
    28 #include <sys/uio.h>
    29 #include <sys/file.h>
    30 #include <sys/ioctl.h>
    31 #if defined(DARWIN)
    32 #include <sys/utsname.h> /* for uname */
    33 #endif
    34 #if defined(SOLARIS) || defined(UNIXWARE)
    35 #include <sys/filio.h>  /* to pick up FIONREAD */
    36 #endif
    37 #ifdef _PR_POLL_AVAILABLE
    38 #include <poll.h>
    39 #endif
    40 #ifdef AIX
    41 /* To pick up sysconf() */
    42 #include <unistd.h>
    43 #include <dlfcn.h>  /* for dlopen */
    44 #else
    45 /* To pick up getrlimit() etc. */
    46 #include <sys/time.h>
    47 #include <sys/resource.h>
    48 #endif
    50 #ifdef SOLARIS
    51 /*
    52  * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
    53  * Code built this way won't run on a system without sendfilev().
    54  * We can define HAVE_SENDFILEV by default when the minimum release
    55  * of Solaris that NSPR supports has sendfilev().
    56  */
    57 #ifdef HAVE_SENDFILEV
    59 #include <sys/sendfile.h>
    61 #define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
    63 #else
    65 #include <dlfcn.h>  /* for dlopen */
    67 /*
    68  * Match the definitions in <sys/sendfile.h>.
    69  */
    70 typedef struct sendfilevec {
    71     int sfv_fd;       /* input fd */
    72     uint_t sfv_flag;  /* flags */
    73     off_t sfv_off;    /* offset to start reading from */
    74     size_t sfv_len;   /* amount of data */
    75 } sendfilevec_t;
    77 #define SFV_FD_SELF (-2)
    79 /*
    80  * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
    81  */
    82 static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
    84 #define SOLARIS_SENDFILEV(a, b, c, d) \
    85         (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
    87 #endif /* HAVE_SENDFILEV */
    88 #endif /* SOLARIS */
    90 /*
    91  * The send_file() system call is available in AIX 4.3.2 or later.
    92  * If this file is compiled on an older AIX system, it attempts to
    93  * look up the send_file symbol at run time to determine whether
    94  * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
    95  * send_file().  On AIX 4.3.2 or later, we can safely skip this
    96  * runtime function dispatching and just use the send_file based
    97  * implementation.
    98  */
    99 #ifdef AIX
   100 #ifdef SF_CLOSE
   101 #define HAVE_SEND_FILE
   102 #endif
   104 #ifdef HAVE_SEND_FILE
   106 #define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
   108 #else /* HAVE_SEND_FILE */
   110 /*
   111  * The following definitions match those in <sys/socket.h>
   112  * on AIX 4.3.2.
   113  */
   115 /*
   116  * Structure for the send_file() system call
   117  */
   118 struct sf_parms {
   119     /* --------- header parms ---------- */
   120     void      *header_data;         /* Input/Output. Points to header buf */
   121     uint_t    header_length;        /* Input/Output. Length of the header */
   122     /* --------- file parms ------------ */
   123     int       file_descriptor;      /* Input. File descriptor of the file */
   124     unsigned long long file_size;   /* Output. Size of the file */
   125     unsigned long long file_offset; /* Input/Output. Starting offset */
   126     long long file_bytes;           /* Input/Output. no. of bytes to send */
   127     /* --------- trailer parms --------- */
   128     void      *trailer_data;        /* Input/Output. Points to trailer buf */
   129     uint_t    trailer_length;       /* Input/Output. Length of the trailer */
   130     /* --------- return info ----------- */
   131     unsigned long long bytes_sent;  /* Output. no. of bytes sent */
   132 };
   134 /*
   135  * Flags for the send_file() system call
   136  */
   137 #define SF_CLOSE        0x00000001      /* close the socket after completion */
   138 #define SF_REUSE        0x00000002      /* reuse socket. not supported */
   139 #define SF_DONT_CACHE   0x00000004      /* don't apply network buffer cache */
   140 #define SF_SYNC_CACHE   0x00000008      /* sync/update network buffer cache */
   142 /*
   143  * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
   144  */
   145 static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
   147 #define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
   149 #endif /* HAVE_SEND_FILE */
   150 #endif /* AIX */
   152 #ifdef LINUX
   153 #include <sys/sendfile.h>
   154 #endif
   156 #include "primpl.h"
   158 #ifdef HAVE_NETINET_TCP_H
   159 #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
   160 #endif
   162 #ifdef LINUX
   163 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
   164 #ifndef TCP_CORK
   165 #define TCP_CORK 3
   166 #endif
   167 #endif
   169 #ifdef _PR_IPV6_V6ONLY_PROBE
   170 static PRBool _pr_ipv6_v6only_on_by_default;
   171 #endif
   173 #if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
   174 #define _PRSelectFdSetArg_t int *
   175 #elif defined(AIX4_1)
   176 #define _PRSelectFdSetArg_t void *
   177 #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
   178     || defined(OSF1) || defined(SOLARIS) \
   179     || defined(HPUX10_30) || defined(HPUX11) \
   180     || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
   181     || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
   182     || defined(BSDI) || defined(NTO) || defined(DARWIN) \
   183     || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN)
   184 #define _PRSelectFdSetArg_t fd_set *
   185 #else
   186 #error "Cannot determine architecture"
   187 #endif
   189 #if defined(SOLARIS)            
   190 #ifndef PROTO_SDP
   191 /* on solaris, SDP is a new type of protocol */
   192 #define PROTO_SDP   257
   193 #endif 
   194 #define _PR_HAVE_SDP
   195 #elif defined(LINUX)
   196 #ifndef AF_INET_SDP
   197 /* on linux, SDP is a new type of address family */
   198 #define AF_INET_SDP 27
   199 #endif
   200 #define _PR_HAVE_SDP
   201 #endif /* LINUX */
   203 static PRFileDesc *pt_SetMethods(
   204     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
   206 static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
   207 static PRCondVar *_pr_flock_cv;  /* For PR_LockFile() etc. */
   208 static PRLock *_pr_rename_lock;  /* For PR_Rename() */
   210 /**************************************************************************/
   212 /* These two functions are only used in assertions. */
   213 #if defined(DEBUG)
   215 PRBool IsValidNetAddr(const PRNetAddr *addr)
   216 {
   217     if ((addr != NULL)
   218             && (addr->raw.family != AF_UNIX)
   219             && (addr->raw.family != PR_AF_INET6)
   220             && (addr->raw.family != AF_INET)) {
   221         return PR_FALSE;
   222     }
   223     return PR_TRUE;
   224 }
   226 static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
   227 {
   228     /*
   229      * The definition of the length of a Unix domain socket address
   230      * is not uniform, so we don't check it.
   231      */
   232     if ((addr != NULL)
   233             && (addr->raw.family != AF_UNIX)
   234             && (PR_NETADDR_SIZE(addr) != addr_len)) {
   235 #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
   236         /*
   237          * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
   238          * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
   239          * field and is 28 bytes.  It is possible for socket functions
   240          * to return an addr_len greater than sizeof(struct sockaddr_in6).
   241          * We need to allow that.  (Bugzilla bug #77264)
   242          */
   243         if ((PR_AF_INET6 == addr->raw.family)
   244                 && (sizeof(addr->ipv6) == addr_len)) {
   245             return PR_TRUE;
   246         }
   247 #endif
   248         return PR_FALSE;
   249     }
   250     return PR_TRUE;
   251 }
   253 #endif /* DEBUG */
   255 /*****************************************************************************/
   256 /************************* I/O Continuation machinery ************************/
   257 /*****************************************************************************/
   259 /*
   260  * The polling interval defines the maximum amount of time that a thread
   261  * might hang up before an interrupt is noticed.
   262  */
   263 #define PT_DEFAULT_POLL_MSEC 5000
   264 #if defined(_PR_POLL_WITH_SELECT)
   265 #define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
   266 #define PT_DEFAULT_SELECT_USEC							\
   267 		((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
   268 #endif
   270 /*
   271  * pt_SockLen is the type for the length of a socket address
   272  * structure, used in the address length argument to bind,
   273  * connect, accept, getsockname, getpeername, etc.  Posix.1g
   274  * defines this type as socklen_t.  It is size_t or int on
   275  * most current systems.
   276  */
   277 #if defined(HAVE_SOCKLEN_T) \
   278     || (defined(__GLIBC__) && __GLIBC__ >= 2)
   279 typedef socklen_t pt_SockLen;
   280 #elif (defined(AIX) && !defined(AIX4_1)) 
   281 typedef PRSize pt_SockLen;
   282 #else
   283 typedef PRIntn pt_SockLen;
   284 #endif
   286 typedef struct pt_Continuation pt_Continuation;
   287 typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
   289 typedef enum pr_ContuationStatus
   290 {
   291     pt_continuation_pending,
   292     pt_continuation_done
   293 } pr_ContuationStatus;
   295 struct pt_Continuation
   296 {
   297     /* The building of the continuation operation */
   298     ContinuationFn function;                /* what function to continue */
   299     union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
   300     union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
   301     union {
   302         PRSize amount;                      /* #3 - size of 'buffer', or */
   303         pt_SockLen *addr_len;                  /*    - length of address */
   304 #ifdef HPUX11
   305         /*
   306          * For sendfile()
   307          */
   308 		struct file_spec {		
   309         	off_t offset;                       /* offset in file to send */
   310         	size_t nbytes;                      /* length of file data to send */
   311         	size_t st_size;                     /* file size */
   312 		} file_spec;
   313 #endif
   314     } arg3;
   315     union { PRIntn flags; } arg4;           /* #4 - read/write flags */
   316     union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
   318 #ifdef HPUX11
   319     /*
   320      * For sendfile()
   321      */
   322     int filedesc;                           /* descriptor of file to send */
   323     int nbytes_to_send;                     /* size of header and file */
   324 #endif  /* HPUX11 */
   326 #ifdef SOLARIS
   327     /*
   328      * For sendfilev()
   329      */
   330     int nbytes_to_send;                     /* size of header and file */
   331 #endif  /* SOLARIS */
   333 #ifdef LINUX
   334     /*
   335      * For sendfile()
   336      */
   337     int in_fd;                              /* descriptor of file to send */
   338     off_t offset;
   339     size_t count;
   340 #endif  /* LINUX */
   342     PRIntervalTime timeout;                 /* client (relative) timeout */
   344     PRInt16 event;                           /* flags for poll()'s events */
   346     /*
   347     ** The representation and notification of the results of the operation.
   348     ** These function can either return an int return code or a pointer to
   349     ** some object.
   350     */
   351     union { PRSize code; void *object; } result;
   353     PRIntn syserrno;                        /* in case it failed, why (errno) */
   354     pr_ContuationStatus status;             /* the status of the operation */
   355 };
   357 #if defined(DEBUG)
   359 PTDebug pt_debug;  /* this is shared between several modules */
   361 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
   362 {
   363     PTDebug stats;
   364     char buffer[100];
   365     PRExplodedTime tod;
   366     PRInt64 elapsed, aMil;
   367     stats = pt_debug;  /* a copy */
   368     PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
   369     (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
   371     LL_SUB(elapsed, PR_Now(), stats.timeStarted);
   372     LL_I2L(aMil, 1000000);
   373     LL_DIV(elapsed, elapsed, aMil);
   375     if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
   376     PR_fprintf(
   377         debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
   378     PR_fprintf(
   379         debug_out, "\tlocks [created: %u, destroyed: %u]\n",
   380         stats.locks_created, stats.locks_destroyed);
   381     PR_fprintf(
   382         debug_out, "\tlocks [acquired: %u, released: %u]\n",
   383         stats.locks_acquired, stats.locks_released);
   384     PR_fprintf(
   385         debug_out, "\tcvars [created: %u, destroyed: %u]\n",
   386         stats.cvars_created, stats.cvars_destroyed);
   387     PR_fprintf(
   388         debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
   389         stats.cvars_notified, stats.delayed_cv_deletes);
   390 }  /* PT_FPrintStats */
   392 #else
   394 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
   395 {
   396     /* do nothing */
   397 }  /* PT_FPrintStats */
   399 #endif  /* DEBUG */
   401 #if defined(_PR_POLL_WITH_SELECT)
   402 /*
   403  * OSF1 and HPUX report the POLLHUP event for a socket when the
   404  * shutdown(SHUT_WR) operation is called for the remote end, even though
   405  * the socket is still writeable. Use select(), instead of poll(), to
   406  * workaround this problem.
   407  */
   408 static void pt_poll_now_with_select(pt_Continuation *op)
   409 {
   410     PRInt32 msecs;
   411 	fd_set rd, wr, *rdp, *wrp;
   412 	struct timeval tv;
   413 	PRIntervalTime epoch, now, elapsed, remaining;
   414 	PRBool wait_for_remaining;
   415     PRThread *self = PR_GetCurrentThread();
   417 	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
   418 	PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
   420     switch (op->timeout) {
   421         case PR_INTERVAL_NO_TIMEOUT:
   422 			tv.tv_sec = PT_DEFAULT_SELECT_SEC;
   423 			tv.tv_usec = PT_DEFAULT_SELECT_USEC;
   424 			do
   425 			{
   426 				PRIntn rv;
   428 				if (op->event & POLLIN) {
   429 					FD_ZERO(&rd);
   430 					FD_SET(op->arg1.osfd, &rd);
   431 					rdp = &rd;
   432 				} else
   433 					rdp = NULL;
   434 				if (op->event & POLLOUT) {
   435 					FD_ZERO(&wr);
   436 					FD_SET(op->arg1.osfd, &wr);
   437 					wrp = &wr;
   438 				} else
   439 					wrp = NULL;
   441 				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
   443 				if (_PT_THREAD_INTERRUPTED(self))
   444 				{
   445 					self->state &= ~PT_THREAD_ABORTED;
   446 					op->result.code = -1;
   447 					op->syserrno = EINTR;
   448 					op->status = pt_continuation_done;
   449 					return;
   450 				}
   452 				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
   453 					continue; /* go around the loop again */
   455 				if (rv > 0)
   456 				{
   457 					PRInt16 revents = 0;
   459 					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
   460 						revents |= POLLIN;
   461 					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
   462 						revents |= POLLOUT;
   464 					if (op->function(op, revents))
   465 						op->status = pt_continuation_done;
   466 				} else if (rv == -1) {
   467 					op->result.code = -1;
   468 					op->syserrno = errno;
   469 					op->status = pt_continuation_done;
   470 				}
   471 				/* else, select timed out */
   472 			} while (pt_continuation_done != op->status);
   473 			break;
   474         default:
   475             now = epoch = PR_IntervalNow();
   476             remaining = op->timeout;
   477 			do
   478 			{
   479 				PRIntn rv;
   481 				if (op->event & POLLIN) {
   482 					FD_ZERO(&rd);
   483 					FD_SET(op->arg1.osfd, &rd);
   484 					rdp = &rd;
   485 				} else
   486 					rdp = NULL;
   487 				if (op->event & POLLOUT) {
   488 					FD_ZERO(&wr);
   489 					FD_SET(op->arg1.osfd, &wr);
   490 					wrp = &wr;
   491 				} else
   492 					wrp = NULL;
   494     			wait_for_remaining = PR_TRUE;
   495     			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
   496 				if (msecs > PT_DEFAULT_POLL_MSEC) {
   497 					wait_for_remaining = PR_FALSE;
   498 					msecs = PT_DEFAULT_POLL_MSEC;
   499 				}
   500 				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
   501 				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
   502 				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
   504 				if (_PT_THREAD_INTERRUPTED(self))
   505 				{
   506 					self->state &= ~PT_THREAD_ABORTED;
   507 					op->result.code = -1;
   508 					op->syserrno = EINTR;
   509 					op->status = pt_continuation_done;
   510 					return;
   511 				}
   513 				if (rv > 0) {
   514 					PRInt16 revents = 0;
   516 					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
   517 						revents |= POLLIN;
   518 					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
   519 						revents |= POLLOUT;
   521 					if (op->function(op, revents))
   522 						op->status = pt_continuation_done;
   524 				} else if ((rv == 0) ||
   525 						((errno == EINTR) || (errno == EAGAIN))) {
   526 					if (rv == 0) {	/* select timed out */
   527 						if (wait_for_remaining)
   528 							now += remaining;
   529 						else
   530 							now += PR_MillisecondsToInterval(msecs);
   531 					} else
   532 						now = PR_IntervalNow();
   533 					elapsed = (PRIntervalTime) (now - epoch);
   534 					if (elapsed >= op->timeout) {
   535 						op->result.code = -1;
   536 						op->syserrno = ETIMEDOUT;
   537 						op->status = pt_continuation_done;
   538 					} else
   539 						remaining = op->timeout - elapsed;
   540 				} else {
   541 					op->result.code = -1;
   542 					op->syserrno = errno;
   543 					op->status = pt_continuation_done;
   544 				}
   545 			} while (pt_continuation_done != op->status);
   546             break;
   547     }
   549 }  /* pt_poll_now_with_select */
   551 #endif	/* _PR_POLL_WITH_SELECT */
   553 static void pt_poll_now(pt_Continuation *op)
   554 {
   555     PRInt32 msecs;
   556 	PRIntervalTime epoch, now, elapsed, remaining;
   557 	PRBool wait_for_remaining;
   558     PRThread *self = PR_GetCurrentThread();
   560 	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
   561 #if defined (_PR_POLL_WITH_SELECT)
   562 	/*
   563  	 * If the fd is small enough call the select-based poll operation
   564 	 */
   565 	if (op->arg1.osfd < FD_SETSIZE) {
   566 		pt_poll_now_with_select(op);
   567 		return;
   568 	}
   569 #endif
   571     switch (op->timeout) {
   572         case PR_INTERVAL_NO_TIMEOUT:
   573 			msecs = PT_DEFAULT_POLL_MSEC;
   574 			do
   575 			{
   576 				PRIntn rv;
   577 				struct pollfd tmp_pfd;
   579 				tmp_pfd.revents = 0;
   580 				tmp_pfd.fd = op->arg1.osfd;
   581 				tmp_pfd.events = op->event;
   583 				rv = poll(&tmp_pfd, 1, msecs);
   585 				if (_PT_THREAD_INTERRUPTED(self))
   586 				{
   587 					self->state &= ~PT_THREAD_ABORTED;
   588 					op->result.code = -1;
   589 					op->syserrno = EINTR;
   590 					op->status = pt_continuation_done;
   591 					return;
   592 				}
   594 				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
   595 					continue; /* go around the loop again */
   597 				if (rv > 0)
   598 				{
   599 					PRInt16 events = tmp_pfd.events;
   600 					PRInt16 revents = tmp_pfd.revents;
   602 					if ((revents & POLLNVAL)  /* busted in all cases */
   603 					|| ((events & POLLOUT) && (revents & POLLHUP)))
   604 						/* write op & hup */
   605 					{
   606 						op->result.code = -1;
   607 						if (POLLNVAL & revents) op->syserrno = EBADF;
   608 						else if (POLLHUP & revents) op->syserrno = EPIPE;
   609 						op->status = pt_continuation_done;
   610 					} else {
   611 						if (op->function(op, revents))
   612 							op->status = pt_continuation_done;
   613 					}
   614 				} else if (rv == -1) {
   615 					op->result.code = -1;
   616 					op->syserrno = errno;
   617 					op->status = pt_continuation_done;
   618 				}
   619 				/* else, poll timed out */
   620 			} while (pt_continuation_done != op->status);
   621 			break;
   622         default:
   623             now = epoch = PR_IntervalNow();
   624             remaining = op->timeout;
   625 			do
   626 			{
   627 				PRIntn rv;
   628 				struct pollfd tmp_pfd;
   630 				tmp_pfd.revents = 0;
   631 				tmp_pfd.fd = op->arg1.osfd;
   632 				tmp_pfd.events = op->event;
   634     			wait_for_remaining = PR_TRUE;
   635     			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
   636 				if (msecs > PT_DEFAULT_POLL_MSEC)
   637 				{
   638 					wait_for_remaining = PR_FALSE;
   639 					msecs = PT_DEFAULT_POLL_MSEC;
   640 				}
   641 				rv = poll(&tmp_pfd, 1, msecs);
   643 				if (_PT_THREAD_INTERRUPTED(self))
   644 				{
   645 					self->state &= ~PT_THREAD_ABORTED;
   646 					op->result.code = -1;
   647 					op->syserrno = EINTR;
   648 					op->status = pt_continuation_done;
   649 					return;
   650 				}
   652 				if (rv > 0)
   653 				{
   654 					PRInt16 events = tmp_pfd.events;
   655 					PRInt16 revents = tmp_pfd.revents;
   657 					if ((revents & POLLNVAL)  /* busted in all cases */
   658 						|| ((events & POLLOUT) && (revents & POLLHUP))) 
   659 											/* write op & hup */
   660 					{
   661 						op->result.code = -1;
   662 						if (POLLNVAL & revents) op->syserrno = EBADF;
   663 						else if (POLLHUP & revents) op->syserrno = EPIPE;
   664 						op->status = pt_continuation_done;
   665 					} else {
   666 						if (op->function(op, revents))
   667 						{
   668 							op->status = pt_continuation_done;
   669 						}
   670 					}
   671 				} else if ((rv == 0) ||
   672 						((errno == EINTR) || (errno == EAGAIN))) {
   673 					if (rv == 0)	/* poll timed out */
   674 					{
   675 						if (wait_for_remaining)
   676 							now += remaining;
   677 						else
   678 							now += PR_MillisecondsToInterval(msecs);
   679 					}
   680 					else
   681 						now = PR_IntervalNow();
   682 					elapsed = (PRIntervalTime) (now - epoch);
   683 					if (elapsed >= op->timeout) {
   684 						op->result.code = -1;
   685 						op->syserrno = ETIMEDOUT;
   686 						op->status = pt_continuation_done;
   687 					} else
   688 						remaining = op->timeout - elapsed;
   689 				} else {
   690 					op->result.code = -1;
   691 					op->syserrno = errno;
   692 					op->status = pt_continuation_done;
   693 				}
   694 			} while (pt_continuation_done != op->status);
   695             break;
   696     }
   698 }  /* pt_poll_now */
   700 static PRIntn pt_Continue(pt_Continuation *op)
   701 {
   702     op->status = pt_continuation_pending;  /* set default value */
   703 	/*
   704 	 * let each thread call poll directly
   705 	 */
   706 	pt_poll_now(op);
   707 	PR_ASSERT(pt_continuation_done == op->status);
   708     return op->result.code;
   709 }  /* pt_Continue */
   711 /*****************************************************************************/
   712 /*********************** specific continuation functions *********************/
   713 /*****************************************************************************/
   714 static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
   715 {
   716     op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
   717     if (op->syserrno != 0) {
   718         op->result.code = -1;
   719     } else {
   720         op->result.code = 0;
   721     }
   722     return PR_TRUE; /* this one is cooked */
   723 }  /* pt_connect_cont */
   725 static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
   726 {
   727     op->syserrno = 0;
   728     op->result.code = accept(
   729         op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
   730     if (-1 == op->result.code)
   731     {
   732         op->syserrno = errno;
   733         if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
   734             return PR_FALSE;  /* do nothing - this one ain't finished */
   735     }
   736     return PR_TRUE;
   737 }  /* pt_accept_cont */
   739 static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
   740 {
   741     /*
   742      * Any number of bytes will complete the operation. It need
   743      * not (and probably will not) satisfy the request. The only
   744      * error we continue is EWOULDBLOCK|EAGAIN.
   745      */
   746     op->result.code = read(
   747         op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   748     op->syserrno = errno;
   749     return ((-1 == op->result.code) && 
   750             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   751         PR_FALSE : PR_TRUE;
   752 }  /* pt_read_cont */
   754 static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
   755 {
   756     /*
   757      * Any number of bytes will complete the operation. It need
   758      * not (and probably will not) satisfy the request. The only
   759      * error we continue is EWOULDBLOCK|EAGAIN.
   760      */
   761 #if defined(SOLARIS)
   762     if (0 == op->arg4.flags)
   763         op->result.code = read(
   764             op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   765     else
   766         op->result.code = recv(
   767             op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   768 #else
   769     op->result.code = recv(
   770         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   771 #endif
   772     op->syserrno = errno;
   773     return ((-1 == op->result.code) && 
   774             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   775         PR_FALSE : PR_TRUE;
   776 }  /* pt_recv_cont */
   778 static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
   779 {
   780     PRIntn bytes;
   781 #if defined(SOLARIS)
   782     PRInt32 tmp_amount = op->arg3.amount;
   783 #endif
   784     /*
   785      * We want to write the entire amount out, no matter how many
   786      * tries it takes. Keep advancing the buffer and the decrementing
   787      * the amount until the amount goes away. Return the total bytes
   788      * (which should be the original amount) when finished (or an
   789      * error).
   790      */
   791 #if defined(SOLARIS)
   792 retry:
   793     bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
   794 #else
   795     bytes = send(
   796         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   797 #endif
   798     op->syserrno = errno;
   800 #if defined(SOLARIS)
   801     /*
   802      * The write system call has been reported to return the ERANGE error
   803      * on occasion. Try to write in smaller chunks to workaround this bug.
   804      */
   805     if ((bytes == -1) && (op->syserrno == ERANGE))
   806     {
   807         if (tmp_amount > 1)
   808         {
   809             tmp_amount = tmp_amount/2;  /* half the bytes */
   810             goto retry;
   811         }
   812     }
   813 #endif
   815     if (bytes >= 0)  /* this is progress */
   816     {
   817         char *bp = (char*)op->arg2.buffer;
   818         bp += bytes;  /* adjust the buffer pointer */
   819         op->arg2.buffer = bp;
   820         op->result.code += bytes;  /* accumulate the number sent */
   821         op->arg3.amount -= bytes;  /* and reduce the required count */
   822         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   823     }
   824     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   825     {
   826         op->result.code = -1;
   827         return PR_TRUE;
   828     }
   829     else return PR_FALSE;
   830 }  /* pt_send_cont */
   832 static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
   833 {
   834     PRIntn bytes;
   835     /*
   836      * We want to write the entire amount out, no matter how many
   837      * tries it takes. Keep advancing the buffer and the decrementing
   838      * the amount until the amount goes away. Return the total bytes
   839      * (which should be the original amount) when finished (or an
   840      * error).
   841      */
   842     bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   843     op->syserrno = errno;
   844     if (bytes >= 0)  /* this is progress */
   845     {
   846         char *bp = (char*)op->arg2.buffer;
   847         bp += bytes;  /* adjust the buffer pointer */
   848         op->arg2.buffer = bp;
   849         op->result.code += bytes;  /* accumulate the number sent */
   850         op->arg3.amount -= bytes;  /* and reduce the required count */
   851         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   852     }
   853     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   854     {
   855         op->result.code = -1;
   856         return PR_TRUE;
   857     }
   858     else return PR_FALSE;
   859 }  /* pt_write_cont */
   861 static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
   862 {
   863     PRIntn bytes;
   864     struct iovec *iov = (struct iovec*)op->arg2.buffer;
   865     /*
   866      * Same rules as write, but continuing seems to be a bit more
   867      * complicated. As the number of bytes sent grows, we have to
   868      * redefine the vector we're pointing at. We might have to
   869      * modify an individual vector parms or we might have to eliminate
   870      * a pair altogether.
   871      */
   872     bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
   873     op->syserrno = errno;
   874     if (bytes >= 0)  /* this is progress */
   875     {
   876         PRIntn iov_index;
   877         op->result.code += bytes;  /* accumulate the number sent */
   878         for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
   879         {
   880             /* how much progress did we make in the i/o vector? */
   881             if (bytes < iov[iov_index].iov_len)
   882             {
   883                 /* this element's not done yet */
   884                 char **bp = (char**)&(iov[iov_index].iov_base);
   885                 iov[iov_index].iov_len -= bytes;  /* there's that much left */
   886                 *bp += bytes;  /* starting there */
   887                 break;  /* go off and do that */
   888             }
   889             bytes -= iov[iov_index].iov_len;  /* that element's consumed */
   890         }
   891         op->arg2.buffer = &iov[iov_index];  /* new start of array */
   892         op->arg3.amount -= iov_index;  /* and array length */
   893         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   894     }
   895     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   896     {
   897         op->result.code = -1;
   898         return PR_TRUE;
   899     }
   900     else return PR_FALSE;
   901 }  /* pt_writev_cont */
   903 static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
   904 {
   905     PRIntn bytes = sendto(
   906         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
   907         (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
   908     op->syserrno = errno;
   909     if (bytes >= 0)  /* this is progress */
   910     {
   911         char *bp = (char*)op->arg2.buffer;
   912         bp += bytes;  /* adjust the buffer pointer */
   913         op->arg2.buffer = bp;
   914         op->result.code += bytes;  /* accumulate the number sent */
   915         op->arg3.amount -= bytes;  /* and reduce the required count */
   916         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   917     }
   918     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   919     {
   920         op->result.code = -1;
   921         return PR_TRUE;
   922     }
   923     else return PR_FALSE;
   924 }  /* pt_sendto_cont */
   926 static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
   927 {
   928     pt_SockLen addr_len = sizeof(PRNetAddr);
   929     op->result.code = recvfrom(
   930         op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
   931         op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
   932     op->syserrno = errno;
   933     return ((-1 == op->result.code) && 
   934             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   935         PR_FALSE : PR_TRUE;
   936 }  /* pt_recvfrom_cont */
   938 #ifdef AIX
   939 static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
   940 {
   941     struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
   942     ssize_t rv;
   943 	unsigned long long saved_file_offset;
   944 	long long saved_file_bytes;
   946 	saved_file_offset = sf_struct->file_offset;
   947 	saved_file_bytes = sf_struct->file_bytes;
   948 	sf_struct->bytes_sent = 0;
   950 	if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
   951 	PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
   952 									sf_struct->file_size);
   953     rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
   954     op->syserrno = errno;
   956     if (rv != -1) {
   957         op->result.code += sf_struct->bytes_sent;
   958 		/*
   959 		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
   960 		 * being updated. So, 'file_bytes' is maintained by NSPR to
   961 		 * avoid conflict when this bug is fixed in AIX, in the future.
   962 		 */
   963 		if (saved_file_bytes != -1)
   964 			saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
   965 		sf_struct->file_bytes = saved_file_bytes;
   966     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
   967         op->result.code = -1;
   968     } else {
   969         return PR_FALSE;
   970     }
   972     if (rv == 1) {    /* more data to send */
   973         return PR_FALSE;
   974     }
   976     return PR_TRUE;
   977 }
   978 #endif  /* AIX */
   980 #ifdef HPUX11
   981 static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
   982 {
   983     struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
   984     int count;
   986     count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
   987 			op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
   988     PR_ASSERT(count <= op->nbytes_to_send);
   989     op->syserrno = errno;
   991     if (count != -1) {
   992         op->result.code += count;
   993     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
   994         op->result.code = -1;
   995     } else {
   996         return PR_FALSE;
   997     }
   998     if (count != -1 && count < op->nbytes_to_send) {
   999         if (count < hdtrl[0].iov_len) {
  1000 			/* header not sent */
  1002             hdtrl[0].iov_base = ((char *) hdtrl[0].iov_base) + count;
  1003             hdtrl[0].iov_len -= count;
  1005         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
  1006 			/* header sent, file not sent */
  1007             PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
  1009             hdtrl[0].iov_base = NULL;
  1010             hdtrl[0].iov_len = 0;
  1012             op->arg3.file_spec.offset += file_nbytes_sent;
  1013             op->arg3.file_spec.nbytes -= file_nbytes_sent;
  1014         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
  1015 											hdtrl[1].iov_len)) {
  1016             PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
  1017                                          op->arg3.file_spec.nbytes);
  1019 			/* header sent, file sent, trailer not sent */
  1021             hdtrl[0].iov_base = NULL;
  1022             hdtrl[0].iov_len = 0;
  1023 			/*
  1024 			 * set file offset and len so that no more file data is
  1025 			 * sent
  1026 			 */
  1027             op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
  1028             op->arg3.file_spec.nbytes = 0;
  1030             hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
  1031             hdtrl[1].iov_len -= trailer_nbytes_sent;
  1033         op->nbytes_to_send -= count;
  1034         return PR_FALSE;
  1037     return PR_TRUE;
  1039 #endif  /* HPUX11 */
  1041 #ifdef SOLARIS  
  1042 static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
  1044     struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
  1045     size_t xferred;
  1046     ssize_t count;
  1048     count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
  1049     op->syserrno = errno;
  1050     PR_ASSERT((count == -1) || (count == xferred));
  1052     if (count == -1) {
  1053         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
  1054                 && op->syserrno != EINTR) {
  1055             op->result.code = -1;
  1056             return PR_TRUE;
  1058         count = xferred;
  1059     } else if (count == 0) {
  1060         /* 
  1061          * We are now at EOF. The file was truncated. Solaris sendfile is
  1062          * supposed to return 0 and no error in this case, though some versions
  1063          * may return -1 and EINVAL .
  1064          */
  1065         op->result.code = -1;
  1066         op->syserrno = 0; /* will be treated as EOF */
  1067         return PR_TRUE;
  1069     PR_ASSERT(count <= op->nbytes_to_send);
  1071     op->result.code += count;
  1072     if (count < op->nbytes_to_send) {
  1073         op->nbytes_to_send -= count;
  1075         while (count >= vec->sfv_len) {
  1076             count -= vec->sfv_len;
  1077             vec++;
  1078             op->arg3.amount--;
  1080         PR_ASSERT(op->arg3.amount > 0);
  1082         vec->sfv_off += count;
  1083         vec->sfv_len -= count;
  1084         PR_ASSERT(vec->sfv_len > 0);
  1085         op->arg2.buffer = vec;
  1087         return PR_FALSE;
  1090     return PR_TRUE;
  1092 #endif  /* SOLARIS */
  1094 #ifdef LINUX 
  1095 static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
  1097     ssize_t rv;
  1098     off_t oldoffset;
  1100     oldoffset = op->offset;
  1101     rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
  1102     op->syserrno = errno;
  1104     if (rv == -1) {
  1105         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
  1106             op->result.code = -1;
  1107             return PR_TRUE;
  1109         rv = 0;
  1111     PR_ASSERT(rv == op->offset - oldoffset);
  1112     op->result.code += rv;
  1113     if (rv < op->count) {
  1114         op->count -= rv;
  1115         return PR_FALSE;
  1117     return PR_TRUE;
  1119 #endif  /* LINUX */
  1121 void _PR_InitIO(void)
  1123 #if defined(DEBUG)
  1124     memset(&pt_debug, 0, sizeof(PTDebug));
  1125     pt_debug.timeStarted = PR_Now();
  1126 #endif
  1128     _pr_flock_lock = PR_NewLock();
  1129     PR_ASSERT(NULL != _pr_flock_lock);
  1130     _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
  1131     PR_ASSERT(NULL != _pr_flock_cv);
  1132     _pr_rename_lock = PR_NewLock();
  1133     PR_ASSERT(NULL != _pr_rename_lock); 
  1135     _PR_InitFdCache();  /* do that */   
  1137     _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1138     _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1139     _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1140     PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
  1142 #ifdef _PR_IPV6_V6ONLY_PROBE
  1143     /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
  1144      * is turned on by default, contrary to what RFC 3493, Section
  1145      * 5.3 says.  So we have to turn it off.  Find out whether we
  1146      * are running on such a system.
  1147      */
  1149         int osfd;
  1150         osfd = socket(AF_INET6, SOCK_STREAM, 0);
  1151         if (osfd != -1) {
  1152             int on;
  1153             socklen_t optlen = sizeof(on);
  1154             if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
  1155                     &on, &optlen) == 0) {
  1156                 _pr_ipv6_v6only_on_by_default = on;
  1158             close(osfd);
  1161 #endif
  1162 }  /* _PR_InitIO */
  1164 void _PR_CleanupIO(void)
  1166     _PR_Putfd(_pr_stdin);
  1167     _pr_stdin = NULL;
  1168     _PR_Putfd(_pr_stdout);
  1169     _pr_stdout = NULL;
  1170     _PR_Putfd(_pr_stderr); 
  1171     _pr_stderr = NULL;
  1173     _PR_CleanupFdCache();
  1175     if (_pr_flock_cv)
  1177         PR_DestroyCondVar(_pr_flock_cv);
  1178         _pr_flock_cv = NULL;
  1180     if (_pr_flock_lock)
  1182         PR_DestroyLock(_pr_flock_lock);
  1183         _pr_flock_lock = NULL;
  1185     if (_pr_rename_lock)
  1187         PR_DestroyLock(_pr_rename_lock);
  1188         _pr_rename_lock = NULL;
  1190 }  /* _PR_CleanupIO */
  1192 PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
  1194     PRFileDesc *result = NULL;
  1195     PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
  1197     if (!_pr_initialized) _PR_ImplicitInitialization();
  1199     switch (osfd)
  1201         case PR_StandardInput: result = _pr_stdin; break;
  1202         case PR_StandardOutput: result = _pr_stdout; break;
  1203         case PR_StandardError: result = _pr_stderr; break;
  1204         default:
  1205             (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1207     return result;
  1208 }  /* PR_GetSpecialFD */
  1210 /*****************************************************************************/
  1211 /***************************** I/O private methods ***************************/
  1212 /*****************************************************************************/
  1214 static PRBool pt_TestAbort(void)
  1216     PRThread *me = PR_GetCurrentThread();
  1217     if(_PT_THREAD_INTERRUPTED(me))
  1219         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  1220         me->state &= ~PT_THREAD_ABORTED;
  1221         return PR_TRUE;
  1223     return PR_FALSE;
  1224 }  /* pt_TestAbort */
  1226 static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
  1228     switch (syserrno)
  1230         case EINTR:
  1231             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
  1232         case ETIMEDOUT:
  1233             PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
  1234         default:
  1235             mapper(syserrno);
  1237 }  /* pt_MapError */
  1239 static PRStatus pt_Close(PRFileDesc *fd)
  1241     if ((NULL == fd) || (NULL == fd->secret)
  1242         || ((_PR_FILEDESC_OPEN != fd->secret->state)
  1243         && (_PR_FILEDESC_CLOSED != fd->secret->state)))
  1245         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1246         return PR_FAILURE;
  1248     if (pt_TestAbort()) return PR_FAILURE;
  1250     if (_PR_FILEDESC_OPEN == fd->secret->state)
  1252         if (-1 == close(fd->secret->md.osfd))
  1254 #ifdef OSF1
  1255             /*
  1256              * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
  1257              * system call, when called to close a TCP socket, may
  1258              * return -1 with errno set to EINVAL but the system call
  1259              * does close the socket successfully.  An application
  1260              * may safely ignore the EINVAL error.  This bug is fixed
  1261              * on Tru64 UNIX V5.1A and later.  The defect tracking
  1262              * number is QAR 81431.
  1263              */
  1264             if (PR_DESC_SOCKET_TCP != fd->methods->file_type
  1265             || EINVAL != errno)
  1267                 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
  1268                 return PR_FAILURE;
  1270 #else
  1271             pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
  1272             return PR_FAILURE;
  1273 #endif
  1275         fd->secret->state = _PR_FILEDESC_CLOSED;
  1277     _PR_Putfd(fd);
  1278     return PR_SUCCESS;
  1279 }  /* pt_Close */
  1281 static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
  1283     PRInt32 syserrno, bytes = -1;
  1285     if (pt_TestAbort()) return bytes;
  1287     bytes = read(fd->secret->md.osfd, buf, amount);
  1288     syserrno = errno;
  1290     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1291         && (!fd->secret->nonblocking))
  1293         pt_Continuation op;
  1294         op.arg1.osfd = fd->secret->md.osfd;
  1295         op.arg2.buffer = buf;
  1296         op.arg3.amount = amount;
  1297         op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1298         op.function = pt_read_cont;
  1299         op.event = POLLIN | POLLPRI;
  1300         bytes = pt_Continue(&op);
  1301         syserrno = op.syserrno;
  1303     if (bytes < 0)
  1304         pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
  1305     return bytes;
  1306 }  /* pt_Read */
  1308 static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
  1310     PRInt32 syserrno, bytes = -1;
  1311     PRBool fNeedContinue = PR_FALSE;
  1313     if (pt_TestAbort()) return bytes;
  1315     bytes = write(fd->secret->md.osfd, buf, amount);
  1316     syserrno = errno;
  1318     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1320         buf = (char *) buf + bytes;
  1321         amount -= bytes;
  1322         fNeedContinue = PR_TRUE;
  1324     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1325         && (!fd->secret->nonblocking) )
  1327         bytes = 0;
  1328         fNeedContinue = PR_TRUE;
  1331     if (fNeedContinue == PR_TRUE)
  1333         pt_Continuation op;
  1334         op.arg1.osfd = fd->secret->md.osfd;
  1335         op.arg2.buffer = (void*)buf;
  1336         op.arg3.amount = amount;
  1337         op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1338         op.result.code = bytes;  /* initialize the number sent */
  1339         op.function = pt_write_cont;
  1340         op.event = POLLOUT | POLLPRI;
  1341         bytes = pt_Continue(&op);
  1342         syserrno = op.syserrno;
  1344     if (bytes == -1)
  1345         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
  1346     return bytes;
  1347 }  /* pt_Write */
  1349 static PRInt32 pt_Writev(
  1350     PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
  1352     PRIntn iov_index;
  1353     PRBool fNeedContinue = PR_FALSE;
  1354     PRInt32 syserrno, bytes, rv = -1;
  1355     struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
  1356     int osiov_len;
  1358     if (pt_TestAbort()) return rv;
  1360     /* Ensured by PR_Writev */
  1361     PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
  1363     /*
  1364      * We can't pass iov to writev because PRIOVec and struct iovec
  1365      * may not be binary compatible.  Make osiov a copy of iov and
  1366      * pass osiov to writev.  We can modify osiov if we need to
  1367      * continue the operation.
  1368      */
  1369     osiov = osiov_local;
  1370     osiov_len = iov_len;
  1371     for (iov_index = 0; iov_index < osiov_len; iov_index++)
  1373         osiov[iov_index].iov_base = iov[iov_index].iov_base;
  1374         osiov[iov_index].iov_len = iov[iov_index].iov_len;
  1377     rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
  1378     syserrno = errno;
  1380     if (!fd->secret->nonblocking)
  1382         if (bytes >= 0)
  1384             /*
  1385              * If we moved some bytes, how does that implicate the
  1386              * i/o vector list?  In other words, exactly where are
  1387              * we within that array?  What are the parameters for
  1388              * resumption?  Maybe we're done!
  1389              */
  1390             for ( ;osiov_len > 0; osiov++, osiov_len--)
  1392                 if (bytes < osiov->iov_len)
  1394                     /* this one's not done yet */
  1395                     osiov->iov_base = (char*)osiov->iov_base + bytes;
  1396                     osiov->iov_len -= bytes;
  1397                     break;  /* go off and do that */
  1399                 bytes -= osiov->iov_len;  /* this one's done cooked */
  1401             PR_ASSERT(osiov_len > 0 || bytes == 0);
  1402             if (osiov_len > 0)
  1404                 if (PR_INTERVAL_NO_WAIT == timeout)
  1406                     rv = -1;
  1407                     syserrno = ETIMEDOUT;
  1409                 else fNeedContinue = PR_TRUE;
  1412         else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1414             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1415             else
  1417                 rv = 0;
  1418                 fNeedContinue = PR_TRUE;
  1423     if (fNeedContinue == PR_TRUE)
  1425         pt_Continuation op;
  1427         op.arg1.osfd = fd->secret->md.osfd;
  1428         op.arg2.buffer = (void*)osiov;
  1429         op.arg3.amount = osiov_len;
  1430         op.timeout = timeout;
  1431         op.result.code = rv;
  1432         op.function = pt_writev_cont;
  1433         op.event = POLLOUT | POLLPRI;
  1434         rv = pt_Continue(&op);
  1435         syserrno = op.syserrno;
  1437     if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
  1438     return rv;
  1439 }  /* pt_Writev */
  1441 static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
  1443     return _PR_MD_LSEEK(fd, offset, whence);
  1444 }  /* pt_Seek */
  1446 static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
  1448     return _PR_MD_LSEEK64(fd, offset, whence);
  1449 }  /* pt_Seek64 */
  1451 static PRInt32 pt_Available_f(PRFileDesc *fd)
  1453     PRInt32 result, cur, end;
  1455     cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
  1457     if (cur >= 0)
  1458         end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
  1460     if ((cur < 0) || (end < 0)) {
  1461         return -1;
  1464     result = end - cur;
  1465     _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
  1467     return result;
  1468 }  /* pt_Available_f */
  1470 static PRInt64 pt_Available64_f(PRFileDesc *fd)
  1472     PRInt64 result, cur, end;
  1473     PRInt64 minus_one;
  1475     LL_I2L(minus_one, -1);
  1476     cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
  1478     if (LL_GE_ZERO(cur))
  1479         end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
  1481     if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
  1483     LL_SUB(result, end, cur);
  1484     (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
  1486     return result;
  1487 }  /* pt_Available64_f */
  1489 static PRInt32 pt_Available_s(PRFileDesc *fd)
  1491     PRInt32 rv, bytes = -1;
  1492     if (pt_TestAbort()) return bytes;
  1494     rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
  1496     if (rv == -1)
  1497         pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
  1498     return bytes;
  1499 }  /* pt_Available_s */
  1501 static PRInt64 pt_Available64_s(PRFileDesc *fd)
  1503     PRInt64 rv;
  1504     LL_I2L(rv, pt_Available_s(fd));
  1505     return rv;
  1506 }  /* pt_Available64_s */
  1508 static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
  1510     PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
  1511     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1512 }  /* pt_FileInfo */
  1514 static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
  1516     PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
  1517     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1518 }  /* pt_FileInfo64 */
  1520 static PRStatus pt_Synch(PRFileDesc *fd)
  1522     return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
  1523 } /* pt_Synch */
  1525 static PRStatus pt_Fsync(PRFileDesc *fd)
  1527     PRIntn rv = -1;
  1528     if (pt_TestAbort()) return PR_FAILURE;
  1530     rv = fsync(fd->secret->md.osfd);
  1531     if (rv < 0) {
  1532         pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
  1533         return PR_FAILURE;
  1535     return PR_SUCCESS;
  1536 }  /* pt_Fsync */
  1538 static PRStatus pt_Connect(
  1539     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  1541     PRIntn rv = -1, syserrno;
  1542     pt_SockLen addr_len;
  1543 	const PRNetAddr *addrp = addr;
  1544 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1545 	PRUint16 md_af = addr->raw.family;
  1546     PRNetAddr addrCopy;
  1547 #endif
  1549     if (pt_TestAbort()) return PR_FAILURE;
  1551     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1552     addr_len = PR_NETADDR_SIZE(addr);
  1553 #if defined(_PR_INET6)
  1554 	if (addr->raw.family == PR_AF_INET6) {
  1555 		md_af = AF_INET6;
  1556 #ifndef _PR_HAVE_SOCKADDR_LEN
  1557 		addrCopy = *addr;
  1558 		addrCopy.raw.family = AF_INET6;
  1559 		addrp = &addrCopy;
  1560 #endif
  1562 #endif
  1564 #ifdef _PR_HAVE_SOCKADDR_LEN
  1565     addrCopy = *addr;
  1566     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  1567     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  1568     addrp = &addrCopy;
  1569 #endif
  1570     rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
  1571     syserrno = errno;
  1572     if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
  1574         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1575         else
  1577             pt_Continuation op;
  1578             op.arg1.osfd = fd->secret->md.osfd;
  1579             op.arg2.buffer = (void*)addrp;
  1580             op.arg3.amount = addr_len;
  1581             op.timeout = timeout;
  1582             op.function = pt_connect_cont;
  1583             op.event = POLLOUT | POLLPRI;
  1584             rv = pt_Continue(&op);
  1585             syserrno = op.syserrno;
  1588     if (-1 == rv) {
  1589         pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
  1590         return PR_FAILURE;
  1592     return PR_SUCCESS;
  1593 }  /* pt_Connect */
  1595 static PRStatus pt_ConnectContinue(
  1596     PRFileDesc *fd, PRInt16 out_flags)
  1598     int err;
  1599     PRInt32 osfd;
  1601     if (out_flags & PR_POLL_NVAL)
  1603         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1604         return PR_FAILURE;
  1606     if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR
  1607         | PR_POLL_HUP)) == 0)
  1609         PR_ASSERT(out_flags == 0);
  1610         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
  1611         return PR_FAILURE;
  1614     osfd = fd->secret->md.osfd;
  1616     err = _MD_unix_get_nonblocking_connect_error(osfd);
  1617     if (err != 0)
  1619         _PR_MD_MAP_CONNECT_ERROR(err);
  1620         return PR_FAILURE;
  1622     return PR_SUCCESS;
  1623 }  /* pt_ConnectContinue */
  1625 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
  1627     /* Find the NSPR layer and invoke its connectcontinue method */
  1628     PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
  1630     if (NULL == bottom)
  1632         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1633         return PR_FAILURE;
  1635     return pt_ConnectContinue(bottom, pd->out_flags);
  1636 }  /* PR_GetConnectStatus */
  1638 static PRFileDesc* pt_Accept(
  1639     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
  1641     PRFileDesc *newfd = NULL;
  1642     PRIntn syserrno, osfd = -1;
  1643     pt_SockLen addr_len = sizeof(PRNetAddr);
  1644 #ifdef SYMBIAN
  1645     PRNetAddr dummy_addr;
  1646 #endif
  1648     if (pt_TestAbort()) return newfd;
  1650 #ifdef SYMBIAN
  1651     /* On Symbian OS, accept crashes if addr is NULL. */
  1652     if (!addr)
  1653         addr = &dummy_addr;
  1654 #endif
  1656 #ifdef _PR_STRICT_ADDR_LEN
  1657     if (addr)
  1659         /*
  1660          * Set addr->raw.family just so that we can use the
  1661          * PR_NETADDR_SIZE macro.
  1662          */
  1663         addr->raw.family = fd->secret->af;
  1664         addr_len = PR_NETADDR_SIZE(addr);
  1666 #endif
  1668     osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1669     syserrno = errno;
  1671     if (osfd == -1)
  1673         if (fd->secret->nonblocking) goto failed;
  1675         if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
  1676         && ECONNABORTED != syserrno)
  1677             goto failed;
  1678         else
  1680             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1681             else
  1683                 pt_Continuation op;
  1684                 op.arg1.osfd = fd->secret->md.osfd;
  1685                 op.arg2.buffer = addr;
  1686                 op.arg3.addr_len = &addr_len;
  1687                 op.timeout = timeout;
  1688                 op.function = pt_accept_cont;
  1689                 op.event = POLLIN | POLLPRI;
  1690                 osfd = pt_Continue(&op);
  1691                 syserrno = op.syserrno;
  1693             if (osfd < 0) goto failed;
  1696 #ifdef _PR_HAVE_SOCKADDR_LEN
  1697     /* ignore the sa_len field of struct sockaddr */
  1698     if (addr)
  1700         addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  1702 #endif /* _PR_HAVE_SOCKADDR_LEN */
  1703 #ifdef _PR_INET6
  1704 	if (addr && (AF_INET6 == addr->raw.family))
  1705         addr->raw.family = PR_AF_INET6;
  1706 #endif
  1707     newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
  1708     if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
  1709     else
  1711         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1712         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  1713 #ifdef LINUX
  1714         /*
  1715          * On Linux, experiments showed that the accepted sockets
  1716          * inherit the TCP_NODELAY socket option of the listening
  1717          * socket.
  1718          */
  1719         newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
  1720 #endif
  1722     return newfd;
  1724 failed:
  1725     pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
  1726     return NULL;
  1727 }  /* pt_Accept */
  1729 static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
  1731     PRIntn rv;
  1732     pt_SockLen addr_len;
  1733 	const PRNetAddr *addrp = addr;
  1734 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1735 	PRUint16 md_af = addr->raw.family;
  1736     PRNetAddr addrCopy;
  1737 #endif
  1739     if (pt_TestAbort()) return PR_FAILURE;
  1741     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1742     if (addr->raw.family == AF_UNIX)
  1744         /* Disallow relative pathnames */
  1745         if (addr->local.path[0] != '/')
  1747             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1748             return PR_FAILURE;
  1752 #if defined(_PR_INET6)
  1753 	if (addr->raw.family == PR_AF_INET6) {
  1754 		md_af = AF_INET6;
  1755 #ifndef _PR_HAVE_SOCKADDR_LEN
  1756 		addrCopy = *addr;
  1757 		addrCopy.raw.family = AF_INET6;
  1758 		addrp = &addrCopy;
  1759 #endif
  1761 #endif
  1763     addr_len = PR_NETADDR_SIZE(addr);
  1764 #ifdef _PR_HAVE_SOCKADDR_LEN
  1765     addrCopy = *addr;
  1766     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  1767     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  1768     addrp = &addrCopy;
  1769 #endif
  1770     rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
  1772     if (rv == -1) {
  1773         pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
  1774         return PR_FAILURE;
  1776     return PR_SUCCESS;
  1777 }  /* pt_Bind */
  1779 static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
  1781     PRIntn rv;
  1783     if (pt_TestAbort()) return PR_FAILURE;
  1785     rv = listen(fd->secret->md.osfd, backlog);
  1786     if (rv == -1) {
  1787         pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
  1788         return PR_FAILURE;
  1790     return PR_SUCCESS;
  1791 }  /* pt_Listen */
  1793 static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
  1795     PRIntn rv = -1;
  1796     if (pt_TestAbort()) return PR_FAILURE;
  1798     rv = shutdown(fd->secret->md.osfd, how);
  1800     if (rv == -1) {
  1801         pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
  1802         return PR_FAILURE;
  1804     return PR_SUCCESS;
  1805 }  /* pt_Shutdown */
  1807 static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  1809     *out_flags = 0;
  1810     return in_flags;
  1811 }  /* pt_Poll */
  1813 static PRInt32 pt_Recv(
  1814     PRFileDesc *fd, void *buf, PRInt32 amount,
  1815     PRIntn flags, PRIntervalTime timeout)
  1817     PRInt32 syserrno, bytes = -1;
  1818     PRIntn osflags;
  1820     if (0 == flags)
  1821         osflags = 0;
  1822     else if (PR_MSG_PEEK == flags)
  1824 #ifdef SYMBIAN
  1825         /* MSG_PEEK doesn't work as expected. */
  1826         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1827         return bytes;
  1828 #else
  1829         osflags = MSG_PEEK;
  1830 #endif
  1832     else
  1834         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1835         return bytes;
  1838     if (pt_TestAbort()) return bytes;
  1840     /* recv() is a much slower call on pre-2.6 Solaris than read(). */
  1841 #if defined(SOLARIS)
  1842     if (0 == osflags)
  1843         bytes = read(fd->secret->md.osfd, buf, amount);
  1844     else
  1845         bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
  1846 #else
  1847     bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
  1848 #endif
  1849     syserrno = errno;
  1851     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1852         && (!fd->secret->nonblocking))
  1854         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1855         else
  1857             pt_Continuation op;
  1858             op.arg1.osfd = fd->secret->md.osfd;
  1859             op.arg2.buffer = buf;
  1860             op.arg3.amount = amount;
  1861             op.arg4.flags = osflags;
  1862             op.timeout = timeout;
  1863             op.function = pt_recv_cont;
  1864             op.event = POLLIN | POLLPRI;
  1865             bytes = pt_Continue(&op);
  1866             syserrno = op.syserrno;
  1869     if (bytes < 0)
  1870         pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
  1871     return bytes;
  1872 }  /* pt_Recv */
  1874 static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
  1876     return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1877 }  /* pt_SocketRead */
  1879 static PRInt32 pt_Send(
  1880     PRFileDesc *fd, const void *buf, PRInt32 amount,
  1881     PRIntn flags, PRIntervalTime timeout)
  1883     PRInt32 syserrno, bytes = -1;
  1884     PRBool fNeedContinue = PR_FALSE;
  1885 #if defined(SOLARIS)
  1886 	PRInt32 tmp_amount = amount;
  1887 #endif
  1889     /*
  1890      * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
  1891      * which has the following:
  1892      *     #  define send        cma_send
  1893      *     extern int  cma_send (int , void *, int, int );
  1894      * So we need to cast away the 'const' of argument #2 for send().
  1895      */
  1896 #if defined (HPUX) && defined(_PR_DCETHREADS)
  1897 #define PT_SENDBUF_CAST (void *)
  1898 #else
  1899 #define PT_SENDBUF_CAST
  1900 #endif
  1902     if (pt_TestAbort()) return bytes;
  1904     /*
  1905      * On pre-2.6 Solaris, send() is much slower than write().
  1906      * On 2.6 and beyond, with in-kernel sockets, send() and
  1907      * write() are fairly equivalent in performance.
  1908      */
  1909 #if defined(SOLARIS)
  1910     PR_ASSERT(0 == flags);
  1911 retry:
  1912     bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
  1913 #else
  1914     bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
  1915 #endif
  1916     syserrno = errno;
  1918 #if defined(SOLARIS)
  1919     /*
  1920      * The write system call has been reported to return the ERANGE error
  1921      * on occasion. Try to write in smaller chunks to workaround this bug.
  1922      */
  1923     if ((bytes == -1) && (syserrno == ERANGE))
  1925         if (tmp_amount > 1)
  1927             tmp_amount = tmp_amount/2;  /* half the bytes */
  1928             goto retry;
  1931 #endif
  1933     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1935         if (PR_INTERVAL_NO_WAIT == timeout)
  1937             bytes = -1;
  1938             syserrno = ETIMEDOUT;
  1940         else
  1942             buf = (char *) buf + bytes;
  1943             amount -= bytes;
  1944             fNeedContinue = PR_TRUE;
  1947     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1948         && (!fd->secret->nonblocking) )
  1950         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1951         else
  1953             bytes = 0;
  1954             fNeedContinue = PR_TRUE;
  1958     if (fNeedContinue == PR_TRUE)
  1960         pt_Continuation op;
  1961         op.arg1.osfd = fd->secret->md.osfd;
  1962         op.arg2.buffer = (void*)buf;
  1963         op.arg3.amount = amount;
  1964         op.arg4.flags = flags;
  1965         op.timeout = timeout;
  1966         op.result.code = bytes;  /* initialize the number sent */
  1967         op.function = pt_send_cont;
  1968         op.event = POLLOUT | POLLPRI;
  1969         bytes = pt_Continue(&op);
  1970         syserrno = op.syserrno;
  1972     if (bytes == -1)
  1973         pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
  1974     return bytes;
  1975 }  /* pt_Send */
  1977 static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
  1979     return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1980 }  /* pt_SocketWrite */
  1982 static PRInt32 pt_SendTo(
  1983     PRFileDesc *fd, const void *buf,
  1984     PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
  1985     PRIntervalTime timeout)
  1987     PRInt32 syserrno, bytes = -1;
  1988     PRBool fNeedContinue = PR_FALSE;
  1989     pt_SockLen addr_len;
  1990 	const PRNetAddr *addrp = addr;
  1991 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1992 	PRUint16 md_af = addr->raw.family;
  1993     PRNetAddr addrCopy;
  1994 #endif
  1996     if (pt_TestAbort()) return bytes;
  1998     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1999 #if defined(_PR_INET6)
  2000 	if (addr->raw.family == PR_AF_INET6) {
  2001 		md_af = AF_INET6;
  2002 #ifndef _PR_HAVE_SOCKADDR_LEN
  2003 		addrCopy = *addr;
  2004 		addrCopy.raw.family = AF_INET6;
  2005 		addrp = &addrCopy;
  2006 #endif
  2008 #endif
  2010     addr_len = PR_NETADDR_SIZE(addr);
  2011 #ifdef _PR_HAVE_SOCKADDR_LEN
  2012     addrCopy = *addr;
  2013     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  2014     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  2015     addrp = &addrCopy;
  2016 #endif
  2017     bytes = sendto(
  2018         fd->secret->md.osfd, buf, amount, flags,
  2019         (struct sockaddr*)addrp, addr_len);
  2020     syserrno = errno;
  2021     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  2022         && (!fd->secret->nonblocking) )
  2024         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  2025         else fNeedContinue = PR_TRUE;
  2027     if (fNeedContinue == PR_TRUE)
  2029         pt_Continuation op;
  2030         op.arg1.osfd = fd->secret->md.osfd;
  2031         op.arg2.buffer = (void*)buf;
  2032         op.arg3.amount = amount;
  2033         op.arg4.flags = flags;
  2034         op.arg5.addr = (PRNetAddr*)addrp;
  2035         op.timeout = timeout;
  2036         op.result.code = 0;  /* initialize the number sent */
  2037         op.function = pt_sendto_cont;
  2038         op.event = POLLOUT | POLLPRI;
  2039         bytes = pt_Continue(&op);
  2040         syserrno = op.syserrno;
  2042     if (bytes < 0)
  2043         pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
  2044     return bytes;
  2045 }  /* pt_SendTo */
  2047 static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
  2048     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
  2050     PRBool fNeedContinue = PR_FALSE;
  2051     PRInt32 syserrno, bytes = -1;
  2052     pt_SockLen addr_len = sizeof(PRNetAddr);
  2054     if (pt_TestAbort()) return bytes;
  2056     bytes = recvfrom(
  2057         fd->secret->md.osfd, buf, amount, flags,
  2058         (struct sockaddr*)addr, &addr_len);
  2059     syserrno = errno;
  2061     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  2062         && (!fd->secret->nonblocking) )
  2064         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  2065         else fNeedContinue = PR_TRUE;
  2068     if (fNeedContinue == PR_TRUE)
  2070         pt_Continuation op;
  2071         op.arg1.osfd = fd->secret->md.osfd;
  2072         op.arg2.buffer = buf;
  2073         op.arg3.amount = amount;
  2074         op.arg4.flags = flags;
  2075         op.arg5.addr = addr;
  2076         op.timeout = timeout;
  2077         op.function = pt_recvfrom_cont;
  2078         op.event = POLLIN | POLLPRI;
  2079         bytes = pt_Continue(&op);
  2080         syserrno = op.syserrno;
  2082     if (bytes >= 0)
  2084 #ifdef _PR_HAVE_SOCKADDR_LEN
  2085         /* ignore the sa_len field of struct sockaddr */
  2086         if (addr)
  2088             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  2090 #endif /* _PR_HAVE_SOCKADDR_LEN */
  2091 #ifdef _PR_INET6
  2092         if (addr && (AF_INET6 == addr->raw.family))
  2093             addr->raw.family = PR_AF_INET6;
  2094 #endif
  2096     else
  2097         pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
  2098     return bytes;
  2099 }  /* pt_RecvFrom */
  2101 #ifdef AIX
  2102 #ifndef HAVE_SEND_FILE
  2103 static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
  2105 static void pt_aix_sendfile_init_routine(void)
  2107     void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
  2108     pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
  2109     dlclose(handle);
  2112 /* 
  2113  * pt_AIXDispatchSendFile
  2114  */
  2115 static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  2116 	  PRTransmitFileFlags flags, PRIntervalTime timeout)
  2118     int rv;
  2120     rv = pthread_once(&pt_aix_sendfile_once_block,
  2121             pt_aix_sendfile_init_routine);
  2122     PR_ASSERT(0 == rv);
  2123     if (pt_aix_sendfile_fptr) {
  2124         return pt_AIXSendFile(sd, sfd, flags, timeout);
  2125     } else {
  2126         return PR_EmulateSendFile(sd, sfd, flags, timeout);
  2129 #endif /* !HAVE_SEND_FILE */
  2132 /*
  2133  * pt_AIXSendFile
  2135  *    Send file sfd->fd across socket sd. If specified, header and trailer
  2136  *    buffers are sent before and after the file, respectively. 
  2138  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  2140  *    return number of bytes sent or -1 on error
  2142  *      This implementation takes advantage of the send_file() system
  2143  *      call available in AIX 4.3.2.
  2144  */
  2146 static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
  2147 		PRTransmitFileFlags flags, PRIntervalTime timeout)
  2149     struct sf_parms sf_struct;
  2150     uint_t send_flags;
  2151     ssize_t rv;
  2152     int syserrno;
  2153     PRInt32 count;
  2154 	unsigned long long saved_file_offset;
  2155 	long long saved_file_bytes;
  2157     sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
  2158     sf_struct.header_length = sfd->hlen;
  2159     sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
  2160     sf_struct.file_size = 0;
  2161     sf_struct.file_offset = sfd->file_offset;
  2162     if (sfd->file_nbytes == 0)
  2163     	sf_struct.file_bytes = -1;
  2164 	else
  2165     	sf_struct.file_bytes = sfd->file_nbytes;
  2166     sf_struct.trailer_data = (void *) sfd->trailer;
  2167     sf_struct.trailer_length = sfd->tlen;
  2168     sf_struct.bytes_sent = 0;
  2170 	saved_file_offset = sf_struct.file_offset;
  2171     saved_file_bytes = sf_struct.file_bytes;
  2173     send_flags = 0;			/* flags processed at the end */
  2175     /* The first argument to send_file() is int*. */
  2176     PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
  2177     do {
  2178         rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
  2179     } while (rv == -1 && (syserrno = errno) == EINTR);
  2181     if (rv == -1) {
  2182         if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
  2183             count = 0; /* Not a real error.  Need to continue. */
  2184         } else {
  2185             count = -1;
  2187     } else {
  2188         count = sf_struct.bytes_sent;
  2189 		/*
  2190 		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
  2191 		 * being updated. So, 'file_bytes' is maintained by NSPR to
  2192 		 * avoid conflict when this bug is fixed in AIX, in the future.
  2193 		 */
  2194 		if (saved_file_bytes != -1)
  2195 			saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
  2196 		sf_struct.file_bytes = saved_file_bytes;
  2199     if ((rv == 1) || ((rv == -1) && (count == 0))) {
  2200         pt_Continuation op;
  2202         op.arg1.osfd = sd->secret->md.osfd;
  2203         op.arg2.buffer = &sf_struct;
  2204         op.arg4.flags = send_flags;
  2205         op.result.code = count;
  2206         op.timeout = timeout;
  2207         op.function = pt_aix_sendfile_cont;
  2208         op.event = POLLOUT | POLLPRI;
  2209         count = pt_Continue(&op);
  2210         syserrno = op.syserrno;
  2213     if (count == -1) {
  2214         pt_MapError(_MD_aix_map_sendfile_error, syserrno);
  2215         return -1;
  2217     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  2218         PR_Close(sd);
  2220 	PR_ASSERT(count == (sfd->hlen + sfd->tlen +
  2221 						((sfd->file_nbytes ==  0) ?
  2222 						sf_struct.file_size - sfd->file_offset :
  2223 						sfd->file_nbytes)));
  2224     return count;
  2226 #endif /* AIX */
  2228 #ifdef HPUX11
  2229 /*
  2230  * pt_HPUXSendFile
  2232  *    Send file sfd->fd across socket sd. If specified, header and trailer
  2233  *    buffers are sent before and after the file, respectively.
  2235  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  2237  *    return number of bytes sent or -1 on error
  2239  *      This implementation takes advantage of the sendfile() system
  2240  *      call available in HP-UX B.11.00.
  2241  */
  2243 static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
  2244 		PRTransmitFileFlags flags, PRIntervalTime timeout)
  2246     struct stat statbuf;
  2247     size_t nbytes_to_send, file_nbytes_to_send;
  2248     struct iovec hdtrl[2];  /* optional header and trailer buffers */
  2249     int send_flags;
  2250     PRInt32 count;
  2251     int syserrno;
  2253     if (sfd->file_nbytes == 0) {
  2254         /* Get file size */
  2255         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  2256             _PR_MD_MAP_FSTAT_ERROR(errno);
  2257             return -1;
  2259         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  2260     } else {
  2261         file_nbytes_to_send = sfd->file_nbytes;
  2263     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
  2265     hdtrl[0].iov_base = (void *) sfd->header;  /* cast away the 'const' */
  2266     hdtrl[0].iov_len = sfd->hlen;
  2267     hdtrl[1].iov_base = (void *) sfd->trailer;
  2268     hdtrl[1].iov_len = sfd->tlen;
  2269     /*
  2270      * SF_DISCONNECT seems to close the socket even if sendfile()
  2271      * only does a partial send on a nonblocking socket.  This
  2272      * would prevent the subsequent sendfile() calls on that socket
  2273      * from working.  So we don't use the SD_DISCONNECT flag.
  2274      */
  2275     send_flags = 0;
  2277     do {
  2278         count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
  2279                 sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
  2280     } while (count == -1 && (syserrno = errno) == EINTR);
  2282     if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
  2283         count = 0;
  2285     if (count != -1 && count < nbytes_to_send) {
  2286         pt_Continuation op;
  2288         if (count < sfd->hlen) {
  2289 			/* header not sent */
  2291             hdtrl[0].iov_base = ((char *) sfd->header) + count;
  2292             hdtrl[0].iov_len = sfd->hlen - count;
  2293             op.arg3.file_spec.offset = sfd->file_offset;
  2294             op.arg3.file_spec.nbytes = file_nbytes_to_send;
  2295         } else if (count < (sfd->hlen + file_nbytes_to_send)) {
  2296 			/* header sent, file not sent */
  2298             hdtrl[0].iov_base = NULL;
  2299             hdtrl[0].iov_len = 0;
  2301             op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
  2302             op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
  2303         } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
  2304 			PRUint32 trailer_nbytes_sent;
  2306 			/* header sent, file sent, trailer not sent */
  2308             hdtrl[0].iov_base = NULL;
  2309             hdtrl[0].iov_len = 0;
  2310 			/*
  2311 			 * set file offset and len so that no more file data is
  2312 			 * sent
  2313 			 */
  2314             op.arg3.file_spec.offset = statbuf.st_size;
  2315             op.arg3.file_spec.nbytes = 0;
  2317 			trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
  2318             hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
  2319             hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
  2322         op.arg1.osfd = sd->secret->md.osfd;
  2323         op.filedesc = sfd->fd->secret->md.osfd;
  2324         op.arg2.buffer = hdtrl;
  2325         op.arg3.file_spec.st_size = statbuf.st_size;
  2326         op.arg4.flags = send_flags;
  2327         op.nbytes_to_send = nbytes_to_send - count;
  2328         op.result.code = count;
  2329         op.timeout = timeout;
  2330         op.function = pt_hpux_sendfile_cont;
  2331         op.event = POLLOUT | POLLPRI;
  2332         count = pt_Continue(&op);
  2333         syserrno = op.syserrno;
  2336     if (count == -1) {
  2337         pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
  2338         return -1;
  2340     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  2341         PR_Close(sd);
  2343     PR_ASSERT(count == nbytes_to_send);
  2344     return count;
  2347 #endif  /* HPUX11 */
  2349 #ifdef SOLARIS 
  2351 /*
  2352  *    pt_SolarisSendFile
  2354  *    Send file sfd->fd across socket sd. If specified, header and trailer
  2355  *    buffers are sent before and after the file, respectively.
  2357  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  2359  *    return number of bytes sent or -1 on error
  2361  *    This implementation takes advantage of the sendfilev() system
  2362  *    call available in Solaris 8.
  2363  */
  2365 static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  2366                 PRTransmitFileFlags flags, PRIntervalTime timeout)
  2368     struct stat statbuf;
  2369     size_t nbytes_to_send, file_nbytes_to_send;	
  2370     struct sendfilevec sfv_struct[3];  
  2371     int sfvcnt = 0;	
  2372     size_t xferred;
  2373     PRInt32 count;
  2374     int syserrno;
  2376     if (sfd->file_nbytes == 0) {
  2377         /* Get file size */
  2378         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  2379             _PR_MD_MAP_FSTAT_ERROR(errno);
  2380             return -1;
  2382         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  2383     } else {
  2384         file_nbytes_to_send = sfd->file_nbytes;
  2387     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
  2389     if (sfd->hlen != 0) {
  2390         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
  2391         sfv_struct[sfvcnt].sfv_flag = 0;
  2392         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; 
  2393         sfv_struct[sfvcnt].sfv_len = sfd->hlen;
  2394         sfvcnt++;
  2397     if (file_nbytes_to_send != 0) {
  2398         sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
  2399         sfv_struct[sfvcnt].sfv_flag = 0;
  2400         sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
  2401         sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
  2402         sfvcnt++;
  2405     if (sfd->tlen != 0) {
  2406         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
  2407         sfv_struct[sfvcnt].sfv_flag = 0;
  2408         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; 
  2409         sfv_struct[sfvcnt].sfv_len = sfd->tlen;
  2410         sfvcnt++;
  2413     if (0 == sfvcnt) {
  2414         count = 0;
  2415         goto done;
  2418     /*
  2419      * Strictly speaking, we may have sent some bytes when the
  2420      * sendfilev() is interrupted and we should retry it from an
  2421      * updated offset.  We are not doing that here.
  2422      */
  2423     count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
  2424             sfvcnt, &xferred);
  2426     PR_ASSERT((count == -1) || (count == xferred));
  2428     if (count == -1) {
  2429         syserrno = errno;
  2430         if (syserrno == EINTR
  2431                 || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
  2432             count = xferred;
  2434     } else if (count == 0) {
  2435         /*
  2436          * We are now at EOF. The file was truncated. Solaris sendfile is
  2437          * supposed to return 0 and no error in this case, though some versions
  2438          * may return -1 and EINVAL .
  2439          */
  2440         count = -1;
  2441         syserrno = 0;  /* will be treated as EOF */
  2444     if (count != -1 && count < nbytes_to_send) {
  2445         pt_Continuation op;
  2446         struct sendfilevec *vec = sfv_struct;
  2447         PRInt32 rem = count;
  2449         while (rem >= vec->sfv_len) {
  2450             rem -= vec->sfv_len;
  2451             vec++;
  2452             sfvcnt--;
  2454         PR_ASSERT(sfvcnt > 0);
  2456         vec->sfv_off += rem;
  2457         vec->sfv_len -= rem;
  2458         PR_ASSERT(vec->sfv_len > 0);
  2460         op.arg1.osfd = sd->secret->md.osfd;
  2461         op.arg2.buffer = vec;
  2462         op.arg3.amount = sfvcnt;
  2463         op.arg4.flags = 0;
  2464         op.nbytes_to_send = nbytes_to_send - count;
  2465         op.result.code = count;
  2466         op.timeout = timeout;
  2467         op.function = pt_solaris_sendfile_cont;
  2468         op.event = POLLOUT | POLLPRI;
  2469         count = pt_Continue(&op);
  2470         syserrno = op.syserrno;
  2473 done:
  2474     if (count == -1) {
  2475         pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
  2476         return -1;
  2478     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  2479         PR_Close(sd);
  2481     PR_ASSERT(count == nbytes_to_send);
  2482     return count;
  2485 #ifndef HAVE_SENDFILEV
  2486 static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
  2488 static void pt_solaris_sendfilev_init_routine(void)
  2490     void *handle;
  2491     PRBool close_it = PR_FALSE;
  2493     /*
  2494      * We do not want to unload libsendfile.so.  This handle is leaked
  2495      * intentionally.
  2496      */
  2497     handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
  2498     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  2499         ("dlopen(libsendfile.so) returns %p", handle));
  2501     if (NULL == handle) {
  2502         /*
  2503          * The dlopen(0, mode) call is to allow for the possibility that
  2504          * sendfilev() may become part of a standard system library in a
  2505          * future Solaris release.
  2506          */
  2507         handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
  2508         PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  2509             ("dlopen(0) returns %p", handle));
  2510         close_it = PR_TRUE;
  2512     pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
  2513     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  2514         ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
  2516     if (close_it) {
  2517         dlclose(handle);
  2521 /* 
  2522  * pt_SolarisDispatchSendFile
  2523  */
  2524 static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  2525 	  PRTransmitFileFlags flags, PRIntervalTime timeout)
  2527     int rv;
  2529     rv = pthread_once(&pt_solaris_sendfilev_once_block,
  2530             pt_solaris_sendfilev_init_routine);
  2531     PR_ASSERT(0 == rv);
  2532     if (pt_solaris_sendfilev_fptr) {
  2533         return pt_SolarisSendFile(sd, sfd, flags, timeout);
  2534     } else {
  2535         return PR_EmulateSendFile(sd, sfd, flags, timeout);
  2538 #endif /* !HAVE_SENDFILEV */
  2540 #endif  /* SOLARIS */
  2542 #ifdef LINUX
  2543 /*
  2544  * pt_LinuxSendFile
  2546  *    Send file sfd->fd across socket sd. If specified, header and trailer
  2547  *    buffers are sent before and after the file, respectively.
  2549  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  2551  *    return number of bytes sent or -1 on error
  2553  *      This implementation takes advantage of the sendfile() system
  2554  *      call available in Linux kernel 2.2 or higher.
  2555  */
  2557 static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  2558                 PRTransmitFileFlags flags, PRIntervalTime timeout)
  2560     struct stat statbuf;
  2561     size_t file_nbytes_to_send;	
  2562     PRInt32 count = 0;
  2563     ssize_t rv;
  2564     int syserrno;
  2565     off_t offset;
  2566     PRBool tcp_cork_enabled = PR_FALSE;
  2567     int tcp_cork;
  2569     if (sfd->file_nbytes == 0) {
  2570         /* Get file size */
  2571         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  2572             _PR_MD_MAP_FSTAT_ERROR(errno);
  2573             return -1;
  2575         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  2576     } else {
  2577         file_nbytes_to_send = sfd->file_nbytes;
  2580     if ((sfd->hlen != 0 || sfd->tlen != 0)
  2581             && sd->secret->md.tcp_nodelay == 0) {
  2582         tcp_cork = 1;
  2583         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
  2584                 &tcp_cork, sizeof tcp_cork) == 0) {
  2585             tcp_cork_enabled = PR_TRUE;
  2586         } else {
  2587             syserrno = errno;
  2588             if (syserrno != EINVAL) {
  2589                 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
  2590                 return -1;
  2592             /*
  2593              * The most likely reason for the EINVAL error is that
  2594              * TCP_NODELAY is set (with a function other than
  2595              * PR_SetSocketOption).  This is not fatal, so we keep
  2596              * on going.
  2597              */
  2598             PR_LOG(_pr_io_lm, PR_LOG_WARNING,
  2599                 ("pt_LinuxSendFile: "
  2600                 "setsockopt(TCP_CORK) failed with EINVAL\n"));
  2604     if (sfd->hlen != 0) {
  2605         count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
  2606         if (count == -1) {
  2607             goto failed;
  2611     if (file_nbytes_to_send != 0) {
  2612         offset = sfd->file_offset;
  2613         do {
  2614             rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
  2615                 &offset, file_nbytes_to_send);
  2616         } while (rv == -1 && (syserrno = errno) == EINTR);
  2617         if (rv == -1) {
  2618             if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
  2619                 _MD_linux_map_sendfile_error(syserrno);
  2620                 count = -1;
  2621                 goto failed;
  2623             rv = 0;
  2625         PR_ASSERT(rv == offset - sfd->file_offset);
  2626         count += rv;
  2628         if (rv < file_nbytes_to_send) {
  2629             pt_Continuation op;
  2631             op.arg1.osfd = sd->secret->md.osfd;
  2632             op.in_fd = sfd->fd->secret->md.osfd;
  2633             op.offset = offset;
  2634             op.count = file_nbytes_to_send - rv;
  2635             op.result.code = count;
  2636             op.timeout = timeout;
  2637             op.function = pt_linux_sendfile_cont;
  2638             op.event = POLLOUT | POLLPRI;
  2639             count = pt_Continue(&op);
  2640             syserrno = op.syserrno;
  2641             if (count == -1) {
  2642                 pt_MapError(_MD_linux_map_sendfile_error, syserrno);
  2643                 goto failed;
  2648     if (sfd->tlen != 0) {
  2649         rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
  2650         if (rv == -1) {
  2651             count = -1;
  2652             goto failed;
  2654         count += rv;
  2657 failed:
  2658     if (tcp_cork_enabled) {
  2659         tcp_cork = 0;
  2660         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
  2661                 &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
  2662             _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
  2663             count = -1;
  2666     if (count != -1) {
  2667         if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  2668             PR_Close(sd);
  2670         PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
  2672     return count;
  2674 #endif  /* LINUX */
  2676 #ifdef AIX
  2677 extern	int _pr_aix_send_file_use_disabled;
  2678 #endif
  2680 static PRInt32 pt_SendFile(
  2681     PRFileDesc *sd, PRSendFileData *sfd,
  2682     PRTransmitFileFlags flags, PRIntervalTime timeout)
  2684     if (pt_TestAbort()) return -1;
  2685     /* The socket must be in blocking mode. */
  2686     if (sd->secret->nonblocking)
  2688         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2689         return -1;
  2691 #ifdef HPUX11
  2692     return(pt_HPUXSendFile(sd, sfd, flags, timeout));
  2693 #elif defined(AIX)
  2694 #ifdef HAVE_SEND_FILE
  2695 	/*
  2696 	 * A bug in AIX 4.3.2 results in corruption of data transferred by
  2697 	 * send_file(); AIX patch PTF U463956 contains the fix.  A user can
  2698 	 * disable the use of send_file function in NSPR, when this patch is
  2699 	 * not installed on the system, by setting the envionment variable
  2700 	 * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
  2701 	 */
  2702 	if (_pr_aix_send_file_use_disabled)
  2703 		return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  2704 	else
  2705     	return(pt_AIXSendFile(sd, sfd, flags, timeout));
  2706 #else
  2707 	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  2708     /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
  2709 #endif /* HAVE_SEND_FILE */
  2710 #elif defined(SOLARIS)
  2711 #ifdef HAVE_SENDFILEV
  2712     	return(pt_SolarisSendFile(sd, sfd, flags, timeout));
  2713 #else
  2714 	return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
  2715 #endif /* HAVE_SENDFILEV */
  2716 #elif defined(LINUX)
  2717     	return(pt_LinuxSendFile(sd, sfd, flags, timeout));
  2718 #else
  2719 	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  2720 #endif
  2723 static PRInt32 pt_TransmitFile(
  2724     PRFileDesc *sd, PRFileDesc *fd, const void *headers,
  2725     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
  2727 	PRSendFileData sfd;
  2729 	sfd.fd = fd;
  2730 	sfd.file_offset = 0;
  2731 	sfd.file_nbytes = 0;
  2732 	sfd.header = headers;
  2733 	sfd.hlen = hlen;
  2734 	sfd.trailer = NULL;
  2735 	sfd.tlen = 0;
  2737 	return(pt_SendFile(sd, &sfd, flags, timeout));
  2738 }  /* pt_TransmitFile */
  2740 static PRInt32 pt_AcceptRead(
  2741     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
  2742     void *buf, PRInt32 amount, PRIntervalTime timeout)
  2744     PRInt32 rv = -1;
  2746     if (pt_TestAbort()) return rv;
  2747     /* The socket must be in blocking mode. */
  2748     if (sd->secret->nonblocking)
  2750         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  2751         return rv;
  2754     rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
  2755     return rv;
  2756 }  /* pt_AcceptRead */
  2758 static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
  2760     PRIntn rv = -1;
  2761     pt_SockLen addr_len = sizeof(PRNetAddr);
  2763     if (pt_TestAbort()) return PR_FAILURE;
  2765     rv = getsockname(
  2766         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  2767     if (rv == -1) {
  2768         pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
  2769         return PR_FAILURE;
  2770     } else {
  2771 #ifdef _PR_HAVE_SOCKADDR_LEN
  2772         /* ignore the sa_len field of struct sockaddr */
  2773         if (addr)
  2775             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  2777 #endif /* _PR_HAVE_SOCKADDR_LEN */
  2778 #ifdef _PR_INET6
  2779 		if (AF_INET6 == addr->raw.family)
  2780 			addr->raw.family = PR_AF_INET6;
  2781 #endif
  2782         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  2783         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  2784         return PR_SUCCESS;
  2786 }  /* pt_GetSockName */
  2788 static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  2790     PRIntn rv = -1;
  2791     pt_SockLen addr_len = sizeof(PRNetAddr);
  2793     if (pt_TestAbort()) return PR_FAILURE;
  2795     rv = getpeername(
  2796         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  2798     if (rv == -1) {
  2799         pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
  2800         return PR_FAILURE;
  2801     } else {
  2802 #ifdef _PR_HAVE_SOCKADDR_LEN
  2803         /* ignore the sa_len field of struct sockaddr */
  2804         if (addr)
  2806             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  2808 #endif /* _PR_HAVE_SOCKADDR_LEN */
  2809 #ifdef _PR_INET6
  2810 		if (AF_INET6 == addr->raw.family)
  2811         	addr->raw.family = PR_AF_INET6;
  2812 #endif
  2813         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  2814         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  2815         return PR_SUCCESS;
  2817 }  /* pt_GetPeerName */
  2819 static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
  2821     PRIntn rv;
  2822     pt_SockLen length;
  2823     PRInt32 level, name;
  2825     /*
  2826      * PR_SockOpt_Nonblocking is a special case that does not
  2827      * translate to a getsockopt() call
  2828      */
  2829     if (PR_SockOpt_Nonblocking == data->option)
  2831         data->value.non_blocking = fd->secret->nonblocking;
  2832         return PR_SUCCESS;
  2835     rv = _PR_MapOptionName(data->option, &level, &name);
  2836     if (PR_SUCCESS == rv)
  2838         switch (data->option)
  2840             case PR_SockOpt_Linger:
  2842                 struct linger linger;
  2843                 length = sizeof(linger);
  2844                 rv = getsockopt(
  2845                     fd->secret->md.osfd, level, name, (char *) &linger, &length);
  2846                 PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
  2847                 data->value.linger.polarity =
  2848                     (linger.l_onoff) ? PR_TRUE : PR_FALSE;
  2849                 data->value.linger.linger =
  2850                     PR_SecondsToInterval(linger.l_linger);
  2851                 break;
  2853             case PR_SockOpt_Reuseaddr:
  2854             case PR_SockOpt_Keepalive:
  2855             case PR_SockOpt_NoDelay:
  2856             case PR_SockOpt_Broadcast:
  2857             case PR_SockOpt_Reuseport:
  2859                 PRIntn value;
  2860                 length = sizeof(PRIntn);
  2861                 rv = getsockopt(
  2862                     fd->secret->md.osfd, level, name, (char*)&value, &length);
  2863                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2864                 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
  2865                 break;
  2867             case PR_SockOpt_McastLoopback:
  2869                 PRUint8 xbool;
  2870                 length = sizeof(xbool);
  2871                 rv = getsockopt(
  2872                     fd->secret->md.osfd, level, name,
  2873                     (char*)&xbool, &length);
  2874                 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
  2875                 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
  2876                 break;
  2878             case PR_SockOpt_RecvBufferSize:
  2879             case PR_SockOpt_SendBufferSize:
  2880             case PR_SockOpt_MaxSegment:
  2882                 PRIntn value;
  2883                 length = sizeof(PRIntn);
  2884                 rv = getsockopt(
  2885                     fd->secret->md.osfd, level, name, (char*)&value, &length);
  2886                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2887                 data->value.recv_buffer_size = value;
  2888                 break;
  2890             case PR_SockOpt_IpTimeToLive:
  2891             case PR_SockOpt_IpTypeOfService:
  2893                 length = sizeof(PRUintn);
  2894                 rv = getsockopt(
  2895                     fd->secret->md.osfd, level, name,
  2896                     (char*)&data->value.ip_ttl, &length);
  2897                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  2898                 break;
  2900             case PR_SockOpt_McastTimeToLive:
  2902                 PRUint8 ttl;
  2903                 length = sizeof(ttl);
  2904                 rv = getsockopt(
  2905                     fd->secret->md.osfd, level, name,
  2906                     (char*)&ttl, &length);
  2907                 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
  2908                 data->value.mcast_ttl = ttl;
  2909                 break;
  2911             case PR_SockOpt_AddMember:
  2912             case PR_SockOpt_DropMember:
  2914                 struct ip_mreq mreq;
  2915                 length = sizeof(mreq);
  2916                 rv = getsockopt(
  2917                     fd->secret->md.osfd, level, name, (char*)&mreq, &length);
  2918                 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
  2919                 data->value.add_member.mcaddr.inet.ip =
  2920                     mreq.imr_multiaddr.s_addr;
  2921                 data->value.add_member.ifaddr.inet.ip =
  2922                     mreq.imr_interface.s_addr;
  2923                 break;
  2925             case PR_SockOpt_McastInterface:
  2927                 length = sizeof(data->value.mcast_if.inet.ip);
  2928                 rv = getsockopt(
  2929                     fd->secret->md.osfd, level, name,
  2930                     (char*)&data->value.mcast_if.inet.ip, &length);
  2931                 PR_ASSERT((-1 == rv)
  2932                     || (sizeof(data->value.mcast_if.inet.ip) == length));
  2933                 break;
  2935             default:
  2936                 PR_NOT_REACHED("Unknown socket option");
  2937                 break;
  2939         if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
  2941     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  2942 }  /* pt_GetSocketOption */
  2944 static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
  2946     PRIntn rv;
  2947     PRInt32 level, name;
  2949     /*
  2950      * PR_SockOpt_Nonblocking is a special case that does not
  2951      * translate to a setsockopt call.
  2952      */
  2953     if (PR_SockOpt_Nonblocking == data->option)
  2955         fd->secret->nonblocking = data->value.non_blocking;
  2956         return PR_SUCCESS;
  2959     rv = _PR_MapOptionName(data->option, &level, &name);
  2960     if (PR_SUCCESS == rv)
  2962         switch (data->option)
  2964             case PR_SockOpt_Linger:
  2966                 struct linger linger;
  2967                 linger.l_onoff = data->value.linger.polarity;
  2968                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
  2969                 rv = setsockopt(
  2970                     fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
  2971                 break;
  2973             case PR_SockOpt_Reuseaddr:
  2974             case PR_SockOpt_Keepalive:
  2975             case PR_SockOpt_NoDelay:
  2976             case PR_SockOpt_Broadcast:
  2977             case PR_SockOpt_Reuseport:
  2979                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
  2980                 rv = setsockopt(
  2981                     fd->secret->md.osfd, level, name,
  2982                     (char*)&value, sizeof(PRIntn));
  2983 #ifdef LINUX
  2984                 /* for pt_LinuxSendFile */
  2985                 if (name == TCP_NODELAY && rv == 0) {
  2986                     fd->secret->md.tcp_nodelay = value;
  2988 #endif
  2989                 break;
  2991             case PR_SockOpt_McastLoopback:
  2993                 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
  2994                 rv = setsockopt(
  2995                     fd->secret->md.osfd, level, name,
  2996                     (char*)&xbool, sizeof(xbool));
  2997                 break;
  2999             case PR_SockOpt_RecvBufferSize:
  3000             case PR_SockOpt_SendBufferSize:
  3001             case PR_SockOpt_MaxSegment:
  3003                 PRIntn value = data->value.recv_buffer_size;
  3004                 rv = setsockopt(
  3005                     fd->secret->md.osfd, level, name,
  3006                     (char*)&value, sizeof(PRIntn));
  3007                 break;
  3009             case PR_SockOpt_IpTimeToLive:
  3010             case PR_SockOpt_IpTypeOfService:
  3012                 rv = setsockopt(
  3013                     fd->secret->md.osfd, level, name,
  3014                     (char*)&data->value.ip_ttl, sizeof(PRUintn));
  3015                 break;
  3017             case PR_SockOpt_McastTimeToLive:
  3019                 PRUint8 ttl = data->value.mcast_ttl;
  3020                 rv = setsockopt(
  3021                     fd->secret->md.osfd, level, name,
  3022                     (char*)&ttl, sizeof(ttl));
  3023                 break;
  3025             case PR_SockOpt_AddMember:
  3026             case PR_SockOpt_DropMember:
  3028                 struct ip_mreq mreq;
  3029                 mreq.imr_multiaddr.s_addr =
  3030                     data->value.add_member.mcaddr.inet.ip;
  3031                 mreq.imr_interface.s_addr =
  3032                     data->value.add_member.ifaddr.inet.ip;
  3033                 rv = setsockopt(
  3034                     fd->secret->md.osfd, level, name,
  3035                     (char*)&mreq, sizeof(mreq));
  3036                 break;
  3038             case PR_SockOpt_McastInterface:
  3040                 rv = setsockopt(
  3041                     fd->secret->md.osfd, level, name,
  3042                     (char*)&data->value.mcast_if.inet.ip,
  3043                     sizeof(data->value.mcast_if.inet.ip));
  3044                 break;
  3046             default:
  3047                 PR_NOT_REACHED("Unknown socket option");
  3048                 break;
  3050         if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
  3052     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  3053 }  /* pt_SetSocketOption */
  3055 /*****************************************************************************/
  3056 /****************************** I/O method objects ***************************/
  3057 /*****************************************************************************/
  3059 static PRIOMethods _pr_file_methods = {
  3060     PR_DESC_FILE,
  3061     pt_Close,
  3062     pt_Read,
  3063     pt_Write,
  3064     pt_Available_f,
  3065     pt_Available64_f,
  3066     pt_Fsync,
  3067     pt_Seek,
  3068     pt_Seek64,
  3069     pt_FileInfo,
  3070     pt_FileInfo64,
  3071     (PRWritevFN)_PR_InvalidInt,        
  3072     (PRConnectFN)_PR_InvalidStatus,        
  3073     (PRAcceptFN)_PR_InvalidDesc,        
  3074     (PRBindFN)_PR_InvalidStatus,        
  3075     (PRListenFN)_PR_InvalidStatus,        
  3076     (PRShutdownFN)_PR_InvalidStatus,    
  3077     (PRRecvFN)_PR_InvalidInt,        
  3078     (PRSendFN)_PR_InvalidInt,        
  3079     (PRRecvfromFN)_PR_InvalidInt,    
  3080     (PRSendtoFN)_PR_InvalidInt,        
  3081     pt_Poll,
  3082     (PRAcceptreadFN)_PR_InvalidInt,   
  3083     (PRTransmitfileFN)_PR_InvalidInt, 
  3084     (PRGetsocknameFN)_PR_InvalidStatus,    
  3085     (PRGetpeernameFN)_PR_InvalidStatus,    
  3086     (PRReservedFN)_PR_InvalidInt,    
  3087     (PRReservedFN)_PR_InvalidInt,    
  3088     (PRGetsocketoptionFN)_PR_InvalidStatus,
  3089     (PRSetsocketoptionFN)_PR_InvalidStatus,
  3090     (PRSendfileFN)_PR_InvalidInt, 
  3091     (PRConnectcontinueFN)_PR_InvalidStatus, 
  3092     (PRReservedFN)_PR_InvalidInt, 
  3093     (PRReservedFN)_PR_InvalidInt, 
  3094     (PRReservedFN)_PR_InvalidInt, 
  3095     (PRReservedFN)_PR_InvalidInt
  3096 };
  3098 static PRIOMethods _pr_pipe_methods = {
  3099     PR_DESC_PIPE,
  3100     pt_Close,
  3101     pt_Read,
  3102     pt_Write,
  3103     pt_Available_s,
  3104     pt_Available64_s,
  3105     pt_Synch,
  3106     (PRSeekFN)_PR_InvalidInt,
  3107     (PRSeek64FN)_PR_InvalidInt64,
  3108     (PRFileInfoFN)_PR_InvalidStatus,
  3109     (PRFileInfo64FN)_PR_InvalidStatus,
  3110     (PRWritevFN)_PR_InvalidInt,        
  3111     (PRConnectFN)_PR_InvalidStatus,        
  3112     (PRAcceptFN)_PR_InvalidDesc,        
  3113     (PRBindFN)_PR_InvalidStatus,        
  3114     (PRListenFN)_PR_InvalidStatus,        
  3115     (PRShutdownFN)_PR_InvalidStatus,    
  3116     (PRRecvFN)_PR_InvalidInt,        
  3117     (PRSendFN)_PR_InvalidInt,        
  3118     (PRRecvfromFN)_PR_InvalidInt,    
  3119     (PRSendtoFN)_PR_InvalidInt,        
  3120     pt_Poll,
  3121     (PRAcceptreadFN)_PR_InvalidInt,   
  3122     (PRTransmitfileFN)_PR_InvalidInt, 
  3123     (PRGetsocknameFN)_PR_InvalidStatus,    
  3124     (PRGetpeernameFN)_PR_InvalidStatus,    
  3125     (PRReservedFN)_PR_InvalidInt,    
  3126     (PRReservedFN)_PR_InvalidInt,    
  3127     (PRGetsocketoptionFN)_PR_InvalidStatus,
  3128     (PRSetsocketoptionFN)_PR_InvalidStatus,
  3129     (PRSendfileFN)_PR_InvalidInt, 
  3130     (PRConnectcontinueFN)_PR_InvalidStatus, 
  3131     (PRReservedFN)_PR_InvalidInt, 
  3132     (PRReservedFN)_PR_InvalidInt, 
  3133     (PRReservedFN)_PR_InvalidInt, 
  3134     (PRReservedFN)_PR_InvalidInt
  3135 };
  3137 static PRIOMethods _pr_tcp_methods = {
  3138     PR_DESC_SOCKET_TCP,
  3139     pt_Close,
  3140     pt_SocketRead,
  3141     pt_SocketWrite,
  3142     pt_Available_s,
  3143     pt_Available64_s,
  3144     pt_Synch,
  3145     (PRSeekFN)_PR_InvalidInt,
  3146     (PRSeek64FN)_PR_InvalidInt64,
  3147     (PRFileInfoFN)_PR_InvalidStatus,
  3148     (PRFileInfo64FN)_PR_InvalidStatus,
  3149     pt_Writev,
  3150     pt_Connect,
  3151     pt_Accept,
  3152     pt_Bind,
  3153     pt_Listen,
  3154     pt_Shutdown,
  3155     pt_Recv,
  3156     pt_Send,
  3157     (PRRecvfromFN)_PR_InvalidInt,
  3158     (PRSendtoFN)_PR_InvalidInt,
  3159     pt_Poll,
  3160     pt_AcceptRead,
  3161     pt_TransmitFile,
  3162     pt_GetSockName,
  3163     pt_GetPeerName,
  3164     (PRReservedFN)_PR_InvalidInt,
  3165     (PRReservedFN)_PR_InvalidInt,
  3166     pt_GetSocketOption,
  3167     pt_SetSocketOption,
  3168     pt_SendFile, 
  3169     pt_ConnectContinue,
  3170     (PRReservedFN)_PR_InvalidInt, 
  3171     (PRReservedFN)_PR_InvalidInt, 
  3172     (PRReservedFN)_PR_InvalidInt, 
  3173     (PRReservedFN)_PR_InvalidInt
  3174 };
  3176 static PRIOMethods _pr_udp_methods = {
  3177     PR_DESC_SOCKET_UDP,
  3178     pt_Close,
  3179     pt_SocketRead,
  3180     pt_SocketWrite,
  3181     pt_Available_s,
  3182     pt_Available64_s,
  3183     pt_Synch,
  3184     (PRSeekFN)_PR_InvalidInt,
  3185     (PRSeek64FN)_PR_InvalidInt64,
  3186     (PRFileInfoFN)_PR_InvalidStatus,
  3187     (PRFileInfo64FN)_PR_InvalidStatus,
  3188     pt_Writev,
  3189     pt_Connect,
  3190     (PRAcceptFN)_PR_InvalidDesc,
  3191     pt_Bind,
  3192     pt_Listen,
  3193     pt_Shutdown,
  3194     pt_Recv,
  3195     pt_Send,
  3196     pt_RecvFrom,
  3197     pt_SendTo,
  3198     pt_Poll,
  3199     (PRAcceptreadFN)_PR_InvalidInt,
  3200     (PRTransmitfileFN)_PR_InvalidInt,
  3201     pt_GetSockName,
  3202     pt_GetPeerName,
  3203     (PRReservedFN)_PR_InvalidInt,
  3204     (PRReservedFN)_PR_InvalidInt,
  3205     pt_GetSocketOption,
  3206     pt_SetSocketOption,
  3207     (PRSendfileFN)_PR_InvalidInt, 
  3208     (PRConnectcontinueFN)_PR_InvalidStatus, 
  3209     (PRReservedFN)_PR_InvalidInt, 
  3210     (PRReservedFN)_PR_InvalidInt, 
  3211     (PRReservedFN)_PR_InvalidInt, 
  3212     (PRReservedFN)_PR_InvalidInt
  3213 };
  3215 static PRIOMethods _pr_socketpollfd_methods = {
  3216     (PRDescType) 0,
  3217     (PRCloseFN)_PR_InvalidStatus,
  3218     (PRReadFN)_PR_InvalidInt,
  3219     (PRWriteFN)_PR_InvalidInt,
  3220     (PRAvailableFN)_PR_InvalidInt,
  3221     (PRAvailable64FN)_PR_InvalidInt64,
  3222     (PRFsyncFN)_PR_InvalidStatus,
  3223     (PRSeekFN)_PR_InvalidInt,
  3224     (PRSeek64FN)_PR_InvalidInt64,
  3225     (PRFileInfoFN)_PR_InvalidStatus,
  3226     (PRFileInfo64FN)_PR_InvalidStatus,
  3227     (PRWritevFN)_PR_InvalidInt,        
  3228     (PRConnectFN)_PR_InvalidStatus,        
  3229     (PRAcceptFN)_PR_InvalidDesc,        
  3230     (PRBindFN)_PR_InvalidStatus,        
  3231     (PRListenFN)_PR_InvalidStatus,        
  3232     (PRShutdownFN)_PR_InvalidStatus,    
  3233     (PRRecvFN)_PR_InvalidInt,        
  3234     (PRSendFN)_PR_InvalidInt,        
  3235     (PRRecvfromFN)_PR_InvalidInt,    
  3236     (PRSendtoFN)_PR_InvalidInt,        
  3237 	pt_Poll,
  3238     (PRAcceptreadFN)_PR_InvalidInt,   
  3239     (PRTransmitfileFN)_PR_InvalidInt, 
  3240     (PRGetsocknameFN)_PR_InvalidStatus,    
  3241     (PRGetpeernameFN)_PR_InvalidStatus,    
  3242     (PRReservedFN)_PR_InvalidInt,    
  3243     (PRReservedFN)_PR_InvalidInt,    
  3244     (PRGetsocketoptionFN)_PR_InvalidStatus,
  3245     (PRSetsocketoptionFN)_PR_InvalidStatus,
  3246     (PRSendfileFN)_PR_InvalidInt, 
  3247     (PRConnectcontinueFN)_PR_InvalidStatus, 
  3248     (PRReservedFN)_PR_InvalidInt, 
  3249     (PRReservedFN)_PR_InvalidInt, 
  3250     (PRReservedFN)_PR_InvalidInt, 
  3251     (PRReservedFN)_PR_InvalidInt
  3252 };
  3254 #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
  3255     || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
  3256     || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
  3257     || defined(OPENBSD) || defined(BSDI) || defined(NTO) \
  3258     || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) \
  3259     || defined(SYMBIAN)
  3260 #define _PR_FCNTL_FLAGS O_NONBLOCK
  3261 #else
  3262 #error "Can't determine architecture"
  3263 #endif
  3265 /*
  3266  * Put a Unix file descriptor in non-blocking mode.
  3267  */
  3268 static void pt_MakeFdNonblock(PRIntn osfd)
  3270     PRIntn flags;
  3271     flags = fcntl(osfd, F_GETFL, 0);
  3272     flags |= _PR_FCNTL_FLAGS;
  3273     (void)fcntl(osfd, F_SETFL, flags);
  3276 /*
  3277  * Put a Unix socket fd in non-blocking mode that can
  3278  * ideally be inherited by an accepted socket.
  3280  * Why doesn't pt_MakeFdNonblock do?  This is to deal with
  3281  * the special case of HP-UX.  HP-UX has three kinds of
  3282  * non-blocking modes for sockets: the fcntl() O_NONBLOCK
  3283  * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
  3284  * the ioctl() FIOSNBIO form of non-blocking mode is
  3285  * inherited by an accepted socket.
  3287  * Other platforms just use the generic pt_MakeFdNonblock
  3288  * to put a socket in non-blocking mode.
  3289  */
  3290 #ifdef HPUX
  3291 static void pt_MakeSocketNonblock(PRIntn osfd)
  3293     PRIntn one = 1;
  3294     (void)ioctl(osfd, FIOSNBIO, &one);
  3296 #else
  3297 #define pt_MakeSocketNonblock pt_MakeFdNonblock
  3298 #endif
  3300 static PRFileDesc *pt_SetMethods(
  3301     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
  3303     PRFileDesc *fd = _PR_Getfd();
  3305     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  3306     else
  3308         fd->secret->md.osfd = osfd;
  3309         fd->secret->state = _PR_FILEDESC_OPEN;
  3310         if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
  3311         else
  3313             /* By default, a Unix fd is not closed on exec. */
  3314 #ifdef DEBUG
  3315             PRIntn flags;
  3316             flags = fcntl(osfd, F_GETFD, 0);
  3317             PR_ASSERT(0 == flags);
  3318 #endif
  3319             fd->secret->inheritable = _PR_TRI_TRUE;
  3321         switch (type)
  3323             case PR_DESC_FILE:
  3324                 fd->methods = PR_GetFileMethods();
  3325                 break;
  3326             case PR_DESC_SOCKET_TCP:
  3327                 fd->methods = PR_GetTCPMethods();
  3328 #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
  3329                 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
  3330 #else
  3331                 pt_MakeSocketNonblock(osfd);
  3332 #endif
  3333                 break;
  3334             case PR_DESC_SOCKET_UDP:
  3335                 fd->methods = PR_GetUDPMethods();
  3336                 pt_MakeFdNonblock(osfd);
  3337                 break;
  3338             case PR_DESC_PIPE:
  3339                 fd->methods = PR_GetPipeMethods();
  3340                 pt_MakeFdNonblock(osfd);
  3341                 break;
  3342             default:
  3343                 break;
  3346     return fd;
  3347 }  /* pt_SetMethods */
  3349 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
  3351     return &_pr_file_methods;
  3352 }  /* PR_GetFileMethods */
  3354 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
  3356     return &_pr_pipe_methods;
  3357 }  /* PR_GetPipeMethods */
  3359 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
  3361     return &_pr_tcp_methods;
  3362 }  /* PR_GetTCPMethods */
  3364 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
  3366     return &_pr_udp_methods;
  3367 }  /* PR_GetUDPMethods */
  3369 static const PRIOMethods* PR_GetSocketPollFdMethods(void)
  3371     return &_pr_socketpollfd_methods;
  3372 }  /* PR_GetSocketPollFdMethods */
  3374 PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
  3375     PRInt32 osfd, const PRIOMethods *methods)
  3377     PRFileDesc *fd = _PR_Getfd();
  3379     if (NULL == fd) goto failed;
  3381     fd->methods = methods;
  3382     fd->secret->md.osfd = osfd;
  3383     /* Make fd non-blocking */
  3384     if (osfd > 2)
  3386         /* Don't mess around with stdin, stdout or stderr */
  3387         if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
  3388         else pt_MakeFdNonblock(osfd);
  3390     fd->secret->state = _PR_FILEDESC_OPEN;
  3391     fd->secret->inheritable = _PR_TRI_UNKNOWN;
  3392     return fd;
  3394 failed:
  3395     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  3396     return fd;
  3397 }  /* PR_AllocFileDesc */
  3399 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
  3400 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
  3401 #if defined(_PR_INET6_PROBE)
  3402 extern PRBool _pr_ipv6_is_present(void);
  3403 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
  3405     int osfd;
  3407 #if defined(DARWIN)
  3408     /*
  3409      * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
  3410      * lesser versions is not ready for general use (see bug 222031).
  3411      */
  3413         struct utsname u;
  3414         if (uname(&u) != 0 || atoi(u.release) < 7)
  3415             return PR_FALSE;
  3417 #endif
  3419     /*
  3420      * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
  3421      * suggests that we call open("/dev/ip6", O_RDWR) to determine
  3422      * whether IPv6 APIs and the IPv6 stack are on the system.
  3423      * Our portable test below seems to work fine, so I am using it.
  3424      */
  3425     osfd = socket(AF_INET6, SOCK_STREAM, 0);
  3426     if (osfd != -1) {
  3427         close(osfd);
  3428         return PR_TRUE;
  3430     return PR_FALSE;
  3432 #endif	/* _PR_INET6_PROBE */
  3433 #endif
  3435 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
  3437     PRIntn osfd;
  3438     PRDescType ftype;
  3439     PRFileDesc *fd = NULL;
  3440 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
  3441     PRInt32 tmp_domain = domain;
  3442 #endif
  3444     if (!_pr_initialized) _PR_ImplicitInitialization();
  3446     if (pt_TestAbort()) return NULL;
  3448     if (PF_INET != domain
  3449         && PR_AF_INET6 != domain
  3450 #if defined(_PR_HAVE_SDP)
  3451         && PR_AF_INET_SDP != domain
  3452 #if defined(SOLARIS)
  3453         && PR_AF_INET6_SDP != domain
  3454 #endif /* SOLARIS */
  3455 #endif /* _PR_HAVE_SDP */
  3456         && PF_UNIX != domain)
  3458         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  3459         return fd;
  3461 	if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
  3462 	else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
  3463 	else
  3465 		(void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  3466 		return fd;
  3468 #if defined(_PR_HAVE_SDP)
  3469 #if defined(LINUX)
  3470     if (PR_AF_INET_SDP == domain)
  3471         domain = AF_INET_SDP;
  3472 #elif defined(SOLARIS)
  3473     if (PR_AF_INET_SDP == domain) {
  3474         domain = AF_INET;
  3475         proto = PROTO_SDP;
  3476     } else if(PR_AF_INET6_SDP == domain) {
  3477         domain = AF_INET6;
  3478         proto = PROTO_SDP;
  3480 #endif /* SOLARIS */
  3481 #endif /* _PR_HAVE_SDP */
  3482 #if defined(_PR_INET6_PROBE)
  3483 	if (PR_AF_INET6 == domain)
  3484 		domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
  3485 #elif defined(_PR_INET6) 
  3486 	if (PR_AF_INET6 == domain)
  3487 		domain = AF_INET6;
  3488 #else
  3489 	if (PR_AF_INET6 == domain)
  3490 		domain = AF_INET;
  3491 #endif
  3493     osfd = socket(domain, type, proto);
  3494     if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
  3495     else
  3497 #ifdef _PR_IPV6_V6ONLY_PROBE
  3498         if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
  3500             int on = 0;
  3501             (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
  3502                     &on, sizeof(on));
  3504 #endif
  3505         fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
  3506         if (fd == NULL) close(osfd);
  3508 #ifdef _PR_NEED_SECRET_AF
  3509     if (fd != NULL) fd->secret->af = domain;
  3510 #endif
  3511 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
  3512 	if (fd != NULL) {
  3513 		/*
  3514 		 * For platforms with no support for IPv6 
  3515 		 * create layered socket for IPv4-mapped IPv6 addresses
  3516 		 */
  3517 		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
  3518 			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
  3519 				PR_Close(fd);
  3520 				fd = NULL;
  3524 #endif
  3525     return fd;
  3526 }  /* PR_Socket */
  3528 /*****************************************************************************/
  3529 /****************************** I/O public methods ***************************/
  3530 /*****************************************************************************/
  3532 PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
  3533     const char *name, PRIntn flags, PRIntn mode)
  3535     PRFileDesc *fd = NULL;
  3536     PRIntn syserrno, osfd = -1, osflags = 0;;
  3538     if (!_pr_initialized) _PR_ImplicitInitialization();
  3540     if (pt_TestAbort()) return NULL;
  3542     if (flags & PR_RDONLY) osflags |= O_RDONLY;
  3543     if (flags & PR_WRONLY) osflags |= O_WRONLY;
  3544     if (flags & PR_RDWR) osflags |= O_RDWR;
  3545     if (flags & PR_APPEND) osflags |= O_APPEND;
  3546     if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
  3547     if (flags & PR_EXCL) osflags |= O_EXCL;
  3548     if (flags & PR_SYNC)
  3550 #if defined(O_SYNC)
  3551         osflags |= O_SYNC;
  3552 #elif defined(O_FSYNC)
  3553         osflags |= O_FSYNC;
  3554 #else
  3555 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
  3556 #endif
  3559     /*
  3560     ** We have to hold the lock across the creation in order to
  3561     ** enforce the sematics of PR_Rename(). (see the latter for
  3562     ** more details)
  3563     */
  3564     if (flags & PR_CREATE_FILE)
  3566         osflags |= O_CREAT;
  3567         if (NULL !=_pr_rename_lock)
  3568             PR_Lock(_pr_rename_lock);
  3571     osfd = _md_iovector._open64(name, osflags, mode);
  3572     syserrno = errno;
  3574     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
  3575         PR_Unlock(_pr_rename_lock);
  3577     if (osfd == -1)
  3578         pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
  3579     else
  3581         fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
  3582         if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
  3584     return fd;
  3585 }  /* PR_OpenFile */
  3587 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
  3589     return PR_OpenFile(name, flags, mode);
  3590 }  /* PR_Open */
  3592 PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
  3594     PRIntn rv = -1;
  3596     if (!_pr_initialized) _PR_ImplicitInitialization();
  3598     if (pt_TestAbort()) return PR_FAILURE;
  3600     rv = unlink(name);
  3602     if (rv == -1) {
  3603         pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
  3604         return PR_FAILURE;
  3605     } else
  3606         return PR_SUCCESS;
  3607 }  /* PR_Delete */
  3609 PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
  3611     PRIntn rv;
  3613     if (pt_TestAbort()) return PR_FAILURE;
  3615     switch (how)
  3617     case PR_ACCESS_READ_OK:
  3618         rv =  access(name, R_OK);
  3619         break;
  3620     case PR_ACCESS_WRITE_OK:
  3621         rv = access(name, W_OK);
  3622         break;
  3623     case PR_ACCESS_EXISTS:
  3624     default:
  3625         rv = access(name, F_OK);
  3627     if (0 == rv) return PR_SUCCESS;
  3628     pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
  3629     return PR_FAILURE;
  3631 }  /* PR_Access */
  3633 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
  3635     PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
  3636     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  3637 }  /* PR_GetFileInfo */
  3639 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
  3641     PRInt32 rv;
  3643     if (!_pr_initialized) _PR_ImplicitInitialization();
  3644     rv = _PR_MD_GETFILEINFO64(fn, info);
  3645     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  3646 }  /* PR_GetFileInfo64 */
  3648 PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
  3650     PRIntn rv = -1;
  3652     if (pt_TestAbort()) return PR_FAILURE;
  3654     /*
  3655     ** We have to acquire a lock here to stiffle anybody trying to create
  3656     ** a new file at the same time. And we have to hold that lock while we
  3657     ** test to see if the file exists and do the rename. The other place
  3658     ** where the lock is held is in PR_Open() when possibly creating a 
  3659     ** new file.
  3660     */
  3662     PR_Lock(_pr_rename_lock);
  3663     rv = access(to, F_OK);
  3664     if (0 == rv)
  3666         PR_SetError(PR_FILE_EXISTS_ERROR, 0);
  3667         rv = -1;
  3669     else
  3671         rv = rename(from, to);
  3672         if (rv == -1)
  3673             pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
  3675     PR_Unlock(_pr_rename_lock);
  3676     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  3677 }  /* PR_Rename */
  3679 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
  3681     if (pt_TestAbort()) return PR_FAILURE;
  3683     if (NULL != dir->md.d)
  3685         if (closedir(dir->md.d) == -1)
  3687             _PR_MD_MAP_CLOSEDIR_ERROR(errno);
  3688             return PR_FAILURE;
  3690         dir->md.d = NULL;
  3691         PR_DELETE(dir);
  3693     return PR_SUCCESS;
  3694 }  /* PR_CloseDir */
  3696 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
  3698     PRInt32 rv = -1;
  3700     if (pt_TestAbort()) return PR_FAILURE;
  3702     /*
  3703     ** This lock is used to enforce rename semantics as described
  3704     ** in PR_Rename.
  3705     */
  3706     if (NULL !=_pr_rename_lock)
  3707         PR_Lock(_pr_rename_lock);
  3708     rv = mkdir(name, mode);
  3709     if (-1 == rv)
  3710         pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
  3711     if (NULL !=_pr_rename_lock)
  3712         PR_Unlock(_pr_rename_lock);
  3714     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  3715 }  /* PR_Makedir */
  3717 PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
  3719     return PR_MakeDir(name, mode);
  3720 }  /* PR_Mkdir */
  3722 PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
  3724     PRInt32 rv;
  3726     if (pt_TestAbort()) return PR_FAILURE;
  3728     rv = rmdir(name);
  3729     if (0 == rv) {
  3730     return PR_SUCCESS;
  3731     } else {
  3732     pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
  3733     return PR_FAILURE;
  3735 }  /* PR_Rmdir */
  3738 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
  3740     DIR *osdir;
  3741     PRDir *dir = NULL;
  3743     if (pt_TestAbort()) return dir;
  3745     osdir = opendir(name);
  3746     if (osdir == NULL)
  3747         pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
  3748     else
  3750         dir = PR_NEWZAP(PRDir);
  3751         if (dir)
  3752             dir->md.d = osdir;
  3753         else
  3754             (void)closedir(osdir);
  3756     return dir;
  3757 }  /* PR_OpenDir */
  3759 static PRInt32 _pr_poll_with_poll(
  3760     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  3762     PRInt32 ready = 0;
  3763     /*
  3764      * For restarting poll() if it is interrupted by a signal.
  3765      * We use these variables to figure out how much time has
  3766      * elapsed and how much of the timeout still remains.
  3767      */
  3768     PRIntervalTime start, elapsed, remaining;
  3770     if (pt_TestAbort()) return -1;
  3772     if (0 == npds) PR_Sleep(timeout);
  3773     else
  3775 #define STACK_POLL_DESC_COUNT 64
  3776         struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
  3777         struct pollfd *syspoll;
  3778         PRIntn index, msecs;
  3780         if (npds <= STACK_POLL_DESC_COUNT)
  3782             syspoll = stack_syspoll;
  3784         else
  3786             PRThread *me = PR_GetCurrentThread();
  3787             if (npds > me->syspoll_count)
  3789                 PR_Free(me->syspoll_list);
  3790                 me->syspoll_list =
  3791                     (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
  3792                 if (NULL == me->syspoll_list)
  3794                     me->syspoll_count = 0;
  3795                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  3796                     return -1;
  3798                 me->syspoll_count = npds;
  3800             syspoll = me->syspoll_list;
  3803         for (index = 0; index < npds; ++index)
  3805             PRInt16 in_flags_read = 0, in_flags_write = 0;
  3806             PRInt16 out_flags_read = 0, out_flags_write = 0;
  3808             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  3810                 if (pds[index].in_flags & PR_POLL_READ)
  3812                     in_flags_read = (pds[index].fd->methods->poll)(
  3813                         pds[index].fd,
  3814                         pds[index].in_flags & ~PR_POLL_WRITE,
  3815                         &out_flags_read);
  3817                 if (pds[index].in_flags & PR_POLL_WRITE)
  3819                     in_flags_write = (pds[index].fd->methods->poll)(
  3820                         pds[index].fd,
  3821                         pds[index].in_flags & ~PR_POLL_READ,
  3822                         &out_flags_write);
  3824                 if ((0 != (in_flags_read & out_flags_read))
  3825                 || (0 != (in_flags_write & out_flags_write)))
  3827                     /* this one is ready right now */
  3828                     if (0 == ready)
  3830                         /*
  3831                          * We will return without calling the system
  3832                          * poll function.  So zero the out_flags
  3833                          * fields of all the poll descriptors before
  3834                          * this one.
  3835                          */
  3836                         int i;
  3837                         for (i = 0; i < index; i++)
  3839                             pds[i].out_flags = 0;
  3842                     ready += 1;
  3843                     pds[index].out_flags = out_flags_read | out_flags_write;
  3845                 else
  3847                     /* now locate the NSPR layer at the bottom of the stack */
  3848                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
  3849                         pds[index].fd, PR_NSPR_IO_LAYER);
  3850                     PR_ASSERT(NULL != bottom);  /* what to do about that? */
  3851                     pds[index].out_flags = 0;  /* pre-condition */
  3852                     if ((NULL != bottom)
  3853                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
  3855                         if (0 == ready)
  3857                             syspoll[index].fd = bottom->secret->md.osfd;
  3858                             syspoll[index].events = 0;
  3859                             if (in_flags_read & PR_POLL_READ)
  3861                                 pds[index].out_flags |=
  3862                                     _PR_POLL_READ_SYS_READ;
  3863                                 syspoll[index].events |= POLLIN;
  3865                             if (in_flags_read & PR_POLL_WRITE)
  3867                                 pds[index].out_flags |=
  3868                                     _PR_POLL_READ_SYS_WRITE;
  3869                                 syspoll[index].events |= POLLOUT;
  3871                             if (in_flags_write & PR_POLL_READ)
  3873                                 pds[index].out_flags |=
  3874                                     _PR_POLL_WRITE_SYS_READ;
  3875                                 syspoll[index].events |= POLLIN;
  3877                             if (in_flags_write & PR_POLL_WRITE)
  3879                                 pds[index].out_flags |=
  3880                                     _PR_POLL_WRITE_SYS_WRITE;
  3881                                 syspoll[index].events |= POLLOUT;
  3883                             if (pds[index].in_flags & PR_POLL_EXCEPT)
  3884                                 syspoll[index].events |= POLLPRI;
  3887                     else
  3889                         if (0 == ready)
  3891                             int i;
  3892                             for (i = 0; i < index; i++)
  3894                                 pds[i].out_flags = 0;
  3897                         ready += 1;  /* this will cause an abrupt return */
  3898                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
  3902             else
  3904                 /* make poll() ignore this entry */
  3905                 syspoll[index].fd = -1;
  3906                 syspoll[index].events = 0;
  3907                 pds[index].out_flags = 0;
  3910         if (0 == ready)
  3912             switch (timeout)
  3914             case PR_INTERVAL_NO_WAIT: msecs = 0; break;
  3915             case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
  3916             default:
  3917                 msecs = PR_IntervalToMilliseconds(timeout);
  3918                 start = PR_IntervalNow();
  3921 retry:
  3922             ready = poll(syspoll, npds, msecs);
  3923             if (-1 == ready)
  3925                 PRIntn oserror = errno;
  3927                 if (EINTR == oserror)
  3929                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
  3930                         goto retry;
  3931                     else if (timeout == PR_INTERVAL_NO_WAIT)
  3932                         ready = 0;  /* don't retry, just time out */
  3933                     else
  3935                         elapsed = (PRIntervalTime) (PR_IntervalNow()
  3936                                 - start);
  3937                         if (elapsed > timeout)
  3938                             ready = 0;  /* timed out */
  3939                         else
  3941                             remaining = timeout - elapsed;
  3942                             msecs = PR_IntervalToMilliseconds(remaining);
  3943                             goto retry;
  3947                 else
  3949                     _PR_MD_MAP_POLL_ERROR(oserror);
  3952             else if (ready > 0)
  3954                 for (index = 0; index < npds; ++index)
  3956                     PRInt16 out_flags = 0;
  3957                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  3959                         if (0 != syspoll[index].revents)
  3961                             if (syspoll[index].revents & POLLIN)
  3963                                 if (pds[index].out_flags
  3964                                 & _PR_POLL_READ_SYS_READ)
  3966                                     out_flags |= PR_POLL_READ;
  3968                                 if (pds[index].out_flags
  3969                                 & _PR_POLL_WRITE_SYS_READ)
  3971                                     out_flags |= PR_POLL_WRITE;
  3974                             if (syspoll[index].revents & POLLOUT)
  3976                                 if (pds[index].out_flags
  3977                                 & _PR_POLL_READ_SYS_WRITE)
  3979                                     out_flags |= PR_POLL_READ;
  3981                                 if (pds[index].out_flags
  3982                                 & _PR_POLL_WRITE_SYS_WRITE)
  3984                                     out_flags |= PR_POLL_WRITE;
  3987                             if (syspoll[index].revents & POLLPRI)
  3988                                 out_flags |= PR_POLL_EXCEPT;
  3989                             if (syspoll[index].revents & POLLERR)
  3990                                 out_flags |= PR_POLL_ERR;
  3991                             if (syspoll[index].revents & POLLNVAL)
  3992                                 out_flags |= PR_POLL_NVAL;
  3993                             if (syspoll[index].revents & POLLHUP)
  3994                                 out_flags |= PR_POLL_HUP;
  3997                     pds[index].out_flags = out_flags;
  4002     return ready;
  4004 } /* _pr_poll_with_poll */
  4006 #if defined(_PR_POLL_WITH_SELECT)
  4007 /*
  4008  * OSF1 and HPUX report the POLLHUP event for a socket when the
  4009  * shutdown(SHUT_WR) operation is called for the remote end, even though
  4010  * the socket is still writeable. Use select(), instead of poll(), to
  4011  * workaround this problem.
  4012  */
  4013 static PRInt32 _pr_poll_with_select(
  4014     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  4016     PRInt32 ready = 0;
  4017     /*
  4018      * For restarting select() if it is interrupted by a signal.
  4019      * We use these variables to figure out how much time has
  4020      * elapsed and how much of the timeout still remains.
  4021      */
  4022     PRIntervalTime start, elapsed, remaining;
  4024     if (pt_TestAbort()) return -1;
  4026     if (0 == npds) PR_Sleep(timeout);
  4027     else
  4029 #define STACK_POLL_DESC_COUNT 64
  4030         int stack_selectfd[STACK_POLL_DESC_COUNT];
  4031         int *selectfd;
  4032 		fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
  4033 		struct timeval tv, *tvp;
  4034         PRIntn index, msecs, maxfd = 0;
  4036         if (npds <= STACK_POLL_DESC_COUNT)
  4038             selectfd = stack_selectfd;
  4040         else
  4042             PRThread *me = PR_GetCurrentThread();
  4043             if (npds > me->selectfd_count)
  4045                 PR_Free(me->selectfd_list);
  4046                 me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
  4047                 if (NULL == me->selectfd_list)
  4049                     me->selectfd_count = 0;
  4050                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  4051                     return -1;
  4053                 me->selectfd_count = npds;
  4055             selectfd = me->selectfd_list;
  4057 		FD_ZERO(&rd);
  4058 		FD_ZERO(&wr);
  4059 		FD_ZERO(&ex);
  4061         for (index = 0; index < npds; ++index)
  4063             PRInt16 in_flags_read = 0, in_flags_write = 0;
  4064             PRInt16 out_flags_read = 0, out_flags_write = 0;
  4066             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  4068                 if (pds[index].in_flags & PR_POLL_READ)
  4070                     in_flags_read = (pds[index].fd->methods->poll)(
  4071                         pds[index].fd,
  4072                         pds[index].in_flags & ~PR_POLL_WRITE,
  4073                         &out_flags_read);
  4075                 if (pds[index].in_flags & PR_POLL_WRITE)
  4077                     in_flags_write = (pds[index].fd->methods->poll)(
  4078                         pds[index].fd,
  4079                         pds[index].in_flags & ~PR_POLL_READ,
  4080                         &out_flags_write);
  4082                 if ((0 != (in_flags_read & out_flags_read))
  4083                 || (0 != (in_flags_write & out_flags_write)))
  4085                     /* this one is ready right now */
  4086                     if (0 == ready)
  4088                         /*
  4089                          * We will return without calling the system
  4090                          * poll function.  So zero the out_flags
  4091                          * fields of all the poll descriptors before
  4092                          * this one.
  4093                          */
  4094                         int i;
  4095                         for (i = 0; i < index; i++)
  4097                             pds[i].out_flags = 0;
  4100                     ready += 1;
  4101                     pds[index].out_flags = out_flags_read | out_flags_write;
  4103                 else
  4105                     /* now locate the NSPR layer at the bottom of the stack */
  4106                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
  4107                         pds[index].fd, PR_NSPR_IO_LAYER);
  4108                     PR_ASSERT(NULL != bottom);  /* what to do about that? */
  4109                     pds[index].out_flags = 0;  /* pre-condition */
  4110                     if ((NULL != bottom)
  4111                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
  4113                         if (0 == ready)
  4115                             PRBool add_to_rd = PR_FALSE;
  4116                             PRBool add_to_wr = PR_FALSE;
  4117                             PRBool add_to_ex = PR_FALSE;
  4119                             selectfd[index] = bottom->secret->md.osfd;
  4120                             if (in_flags_read & PR_POLL_READ)
  4122                                 pds[index].out_flags |=
  4123                                     _PR_POLL_READ_SYS_READ;
  4124                                 add_to_rd = PR_TRUE;
  4126                             if (in_flags_read & PR_POLL_WRITE)
  4128                                 pds[index].out_flags |=
  4129                                     _PR_POLL_READ_SYS_WRITE;
  4130                                 add_to_wr = PR_TRUE;
  4132                             if (in_flags_write & PR_POLL_READ)
  4134                                 pds[index].out_flags |=
  4135                                     _PR_POLL_WRITE_SYS_READ;
  4136                                 add_to_rd = PR_TRUE;
  4138                             if (in_flags_write & PR_POLL_WRITE)
  4140                                 pds[index].out_flags |=
  4141                                     _PR_POLL_WRITE_SYS_WRITE;
  4142                                 add_to_wr = PR_TRUE;
  4144                             if (pds[index].in_flags & PR_POLL_EXCEPT)
  4146                                 add_to_ex = PR_TRUE;
  4148                             if ((selectfd[index] > maxfd) &&
  4149                                     (add_to_rd || add_to_wr || add_to_ex))
  4151                                 maxfd = selectfd[index];
  4152                                 /*
  4153                                  * If maxfd is too large to be used with
  4154                                  * select, fall back to calling poll.
  4155                                  */
  4156                                 if (maxfd >= FD_SETSIZE)
  4157                                     break;
  4159                             if (add_to_rd)
  4161                                 FD_SET(bottom->secret->md.osfd, &rd);
  4162                                 rdp = &rd;
  4164                             if (add_to_wr)
  4166                                 FD_SET(bottom->secret->md.osfd, &wr);
  4167                                 wrp = &wr;
  4169                             if (add_to_ex)
  4171                                 FD_SET(bottom->secret->md.osfd, &ex);
  4172                                 exp = &ex;
  4176                     else
  4178                         if (0 == ready)
  4180                             int i;
  4181                             for (i = 0; i < index; i++)
  4183                                 pds[i].out_flags = 0;
  4186                         ready += 1;  /* this will cause an abrupt return */
  4187                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
  4191             else
  4193                 pds[index].out_flags = 0;
  4196         if (0 == ready)
  4198 			if (maxfd >= FD_SETSIZE)
  4200 				/*
  4201 				 * maxfd too large to be used with select, fall back to
  4202 				 * calling poll
  4203 				 */
  4204 				return(_pr_poll_with_poll(pds, npds, timeout));
  4206             switch (timeout)
  4208             case PR_INTERVAL_NO_WAIT:
  4209 				tv.tv_sec = 0;
  4210 				tv.tv_usec = 0;
  4211 				tvp = &tv;
  4212 				break;
  4213             case PR_INTERVAL_NO_TIMEOUT:
  4214 				tvp = NULL;
  4215 				break;
  4216             default:
  4217                 msecs = PR_IntervalToMilliseconds(timeout);
  4218 				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
  4219 				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
  4220 				tvp = &tv;
  4221                 start = PR_IntervalNow();
  4224 retry:
  4225             ready = select(maxfd + 1, rdp, wrp, exp, tvp);
  4226             if (-1 == ready)
  4228                 PRIntn oserror = errno;
  4230                 if ((EINTR == oserror) || (EAGAIN == oserror))
  4232                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
  4233                         goto retry;
  4234                     else if (timeout == PR_INTERVAL_NO_WAIT)
  4235                         ready = 0;  /* don't retry, just time out */
  4236                     else
  4238                         elapsed = (PRIntervalTime) (PR_IntervalNow()
  4239                                 - start);
  4240                         if (elapsed > timeout)
  4241                             ready = 0;  /* timed out */
  4242                         else
  4244                             remaining = timeout - elapsed;
  4245                             msecs = PR_IntervalToMilliseconds(remaining);
  4246 							tv.tv_sec = msecs/PR_MSEC_PER_SEC;
  4247 							tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
  4248 													PR_USEC_PER_MSEC;
  4249                             goto retry;
  4252                 } else if (EBADF == oserror)
  4254 					/* find all the bad fds */
  4255 					ready = 0;
  4256                 	for (index = 0; index < npds; ++index)
  4258                     	pds[index].out_flags = 0;
  4259             			if ((NULL != pds[index].fd) &&
  4260 											(0 != pds[index].in_flags))
  4262 							if (fcntl(selectfd[index], F_GETFL, 0) == -1)
  4264                     			pds[index].out_flags = PR_POLL_NVAL;
  4265 								ready++;
  4269                 } else 
  4270                     _PR_MD_MAP_SELECT_ERROR(oserror);
  4272             else if (ready > 0)
  4274                 for (index = 0; index < npds; ++index)
  4276                     PRInt16 out_flags = 0;
  4277                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  4279 						if (FD_ISSET(selectfd[index], &rd))
  4281 							if (pds[index].out_flags
  4282 							& _PR_POLL_READ_SYS_READ)
  4284 								out_flags |= PR_POLL_READ;
  4286 							if (pds[index].out_flags
  4287 							& _PR_POLL_WRITE_SYS_READ)
  4289 								out_flags |= PR_POLL_WRITE;
  4292 						if (FD_ISSET(selectfd[index], &wr))
  4294 							if (pds[index].out_flags
  4295 							& _PR_POLL_READ_SYS_WRITE)
  4297 								out_flags |= PR_POLL_READ;
  4299 							if (pds[index].out_flags
  4300 							& _PR_POLL_WRITE_SYS_WRITE)
  4302 								out_flags |= PR_POLL_WRITE;
  4305 						if (FD_ISSET(selectfd[index], &ex))
  4306 							out_flags |= PR_POLL_EXCEPT;
  4308                     pds[index].out_flags = out_flags;
  4313     return ready;
  4315 } /* _pr_poll_with_select */
  4316 #endif	/* _PR_POLL_WITH_SELECT */
  4318 PR_IMPLEMENT(PRInt32) PR_Poll(
  4319     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  4321 #if defined(_PR_POLL_WITH_SELECT)
  4322 	return(_pr_poll_with_select(pds, npds, timeout));
  4323 #else
  4324 	return(_pr_poll_with_poll(pds, npds, timeout));
  4325 #endif
  4328 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
  4330     struct dirent *dp;
  4332     if (pt_TestAbort()) return NULL;
  4334     for (;;)
  4336         errno = 0;
  4337         dp = readdir(dir->md.d);
  4338         if (NULL == dp)
  4340             pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
  4341             return NULL;
  4343         if ((flags & PR_SKIP_DOT)
  4344             && ('.' == dp->d_name[0])
  4345             && (0 == dp->d_name[1])) continue;
  4346         if ((flags & PR_SKIP_DOT_DOT)
  4347             && ('.' == dp->d_name[0])
  4348             && ('.' == dp->d_name[1])
  4349             && (0 == dp->d_name[2])) continue;
  4350         if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
  4351             continue;
  4352         break;
  4354     dir->d.name = dp->d_name;
  4355     return &dir->d;
  4356 }  /* PR_ReadDir */
  4358 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
  4360     PRIntn domain = PF_INET;
  4362     return PR_Socket(domain, SOCK_DGRAM, 0);
  4363 }  /* PR_NewUDPSocket */
  4365 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
  4367     PRIntn domain = PF_INET;
  4369     return PR_Socket(domain, SOCK_STREAM, 0);
  4370 }  /* PR_NewTCPSocket */
  4372 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
  4374     return PR_Socket(af, SOCK_DGRAM, 0);
  4375 }  /* PR_NewUDPSocket */
  4377 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
  4379     return PR_Socket(af, SOCK_STREAM, 0);
  4380 }  /* PR_NewTCPSocket */
  4382 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
  4384 #ifdef SYMBIAN
  4385     /*
  4386      * For the platforms that don't have socketpair.
  4388      * Copied from prsocket.c, with the parameter f[] renamed fds[] and the
  4389      * _PR_CONNECT_DOES_NOT_BIND code removed.
  4390      */
  4391     PRFileDesc *listenSock;
  4392     PRNetAddr selfAddr, peerAddr;
  4393     PRUint16 port;
  4395     fds[0] = fds[1] = NULL;
  4396     listenSock = PR_NewTCPSocket();
  4397     if (listenSock == NULL) {
  4398         goto failed;
  4400     PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
  4401     if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
  4402         goto failed;
  4404     if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
  4405         goto failed;
  4407     port = ntohs(selfAddr.inet.port);
  4408     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
  4409         goto failed;
  4411     fds[0] = PR_NewTCPSocket();
  4412     if (fds[0] == NULL) {
  4413         goto failed;
  4415     PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
  4417     /*
  4418      * Only a thread is used to do the connect and accept.
  4419      * I am relying on the fact that PR_Connect returns
  4420      * successfully as soon as the connect request is put
  4421      * into the listen queue (but before PR_Accept is called).
  4422      * This is the behavior of the BSD socket code.  If
  4423      * connect does not return until accept is called, we
  4424      * will need to create another thread to call connect.
  4425      */
  4426     if (PR_Connect(fds[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
  4427             == PR_FAILURE) {
  4428         goto failed;
  4430     /*
  4431      * A malicious local process may connect to the listening
  4432      * socket, so we need to verify that the accepted connection
  4433      * is made from our own socket fds[0].
  4434      */
  4435     if (PR_GetSockName(fds[0], &selfAddr) == PR_FAILURE) {
  4436         goto failed;
  4438     fds[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
  4439     if (fds[1] == NULL) {
  4440         goto failed;
  4442     if (peerAddr.inet.port != selfAddr.inet.port) {
  4443         /* the connection we accepted is not from fds[0] */
  4444         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  4445         goto failed;
  4447     PR_Close(listenSock);
  4448     return PR_SUCCESS;
  4450 failed:
  4451     if (listenSock) {
  4452         PR_Close(listenSock);
  4454     if (fds[0]) {
  4455         PR_Close(fds[0]);
  4457     if (fds[1]) {
  4458         PR_Close(fds[1]);
  4460     return PR_FAILURE;
  4461 #else
  4462     PRInt32 osfd[2];
  4464     if (pt_TestAbort()) return PR_FAILURE;
  4466     if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
  4467         pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
  4468         return PR_FAILURE;
  4471     fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
  4472     if (fds[0] == NULL) {
  4473         close(osfd[0]);
  4474         close(osfd[1]);
  4475         return PR_FAILURE;
  4477     fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
  4478     if (fds[1] == NULL) {
  4479         PR_Close(fds[0]);
  4480         close(osfd[1]);
  4481         return PR_FAILURE;
  4483     return PR_SUCCESS;
  4484 #endif
  4485 }  /* PR_NewTCPSocketPair */
  4487 PR_IMPLEMENT(PRStatus) PR_CreatePipe(
  4488     PRFileDesc **readPipe,
  4489     PRFileDesc **writePipe
  4492     int pipefd[2];
  4494     if (pt_TestAbort()) return PR_FAILURE;
  4496     if (pipe(pipefd) == -1)
  4498     /* XXX map pipe error */
  4499         PR_SetError(PR_UNKNOWN_ERROR, errno);
  4500         return PR_FAILURE;
  4502     *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
  4503     if (NULL == *readPipe)
  4505         close(pipefd[0]);
  4506         close(pipefd[1]);
  4507         return PR_FAILURE;
  4509     *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
  4510     if (NULL == *writePipe)
  4512         PR_Close(*readPipe);
  4513         close(pipefd[1]);
  4514         return PR_FAILURE;
  4516     return PR_SUCCESS;
  4519 /*
  4520 ** Set the inheritance attribute of a file descriptor.
  4521 */
  4522 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
  4523     PRFileDesc *fd,
  4524     PRBool inheritable)
  4526     /*
  4527      * Only a non-layered, NSPR file descriptor can be inherited
  4528      * by a child process.
  4529      */
  4530     if (fd->identity != PR_NSPR_IO_LAYER)
  4532         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  4533         return PR_FAILURE;
  4535     if (fd->secret->inheritable != inheritable)
  4537         if (fcntl(fd->secret->md.osfd, F_SETFD,
  4538         inheritable ? 0 : FD_CLOEXEC) == -1)
  4540             _PR_MD_MAP_DEFAULT_ERROR(errno);
  4541             return PR_FAILURE;
  4543         fd->secret->inheritable = (_PRTriStateBool) inheritable;
  4545     return PR_SUCCESS;
  4548 /*****************************************************************************/
  4549 /***************************** I/O friends methods ***************************/
  4550 /*****************************************************************************/
  4552 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
  4554     PRFileDesc *fd;
  4556     if (!_pr_initialized) _PR_ImplicitInitialization();
  4557     fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  4558     if (NULL == fd) close(osfd);
  4559     return fd;
  4560 }  /* PR_ImportFile */
  4562 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
  4564     PRFileDesc *fd;
  4566     if (!_pr_initialized) _PR_ImplicitInitialization();
  4567     fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
  4568     if (NULL == fd) close(osfd);
  4569     return fd;
  4570 }  /* PR_ImportPipe */
  4572 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
  4574     PRFileDesc *fd;
  4576     if (!_pr_initialized) _PR_ImplicitInitialization();
  4577     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
  4578     if (NULL == fd) close(osfd);
  4579 #ifdef _PR_NEED_SECRET_AF
  4580     if (NULL != fd) fd->secret->af = PF_INET;
  4581 #endif
  4582     return fd;
  4583 }  /* PR_ImportTCPSocket */
  4585 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
  4587     PRFileDesc *fd;
  4589     if (!_pr_initialized) _PR_ImplicitInitialization();
  4590     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
  4591     if (NULL == fd) close(osfd);
  4592     return fd;
  4593 }  /* PR_ImportUDPSocket */
  4595 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
  4597     PRFileDesc *fd;
  4599     if (!_pr_initialized) _PR_ImplicitInitialization();
  4601     fd = _PR_Getfd();
  4603     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  4604     else
  4606         fd->secret->md.osfd = osfd;
  4607         fd->secret->inheritable = _PR_TRI_FALSE;
  4608     	fd->secret->state = _PR_FILEDESC_OPEN;
  4609         fd->methods = PR_GetSocketPollFdMethods();
  4612     return fd;
  4613 }  /* PR_CreateSocketPollFD */
  4615 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
  4617     if (NULL == fd)
  4619         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  4620         return PR_FAILURE;
  4622     fd->secret->state = _PR_FILEDESC_CLOSED;
  4623     _PR_Putfd(fd);
  4624     return PR_SUCCESS;
  4625 }  /* PR_DestroySocketPollFd */
  4627 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
  4629     PRInt32 osfd = -1;
  4630     bottom = (NULL == bottom) ?
  4631         NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
  4632     if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  4633     else osfd = bottom->secret->md.osfd;
  4634     return osfd;
  4635 }  /* PR_FileDesc2NativeHandle */
  4637 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
  4638     PRInt32 handle)
  4640     if (fd) fd->secret->md.osfd = handle;
  4641 }  /*  PR_ChangeFileDescNativeHandle*/
  4643 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
  4645     PRStatus status = PR_SUCCESS;
  4647     if (pt_TestAbort()) return PR_FAILURE;
  4649     PR_Lock(_pr_flock_lock);
  4650     while (-1 == fd->secret->lockCount)
  4651         PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
  4652     if (0 == fd->secret->lockCount)
  4654         fd->secret->lockCount = -1;
  4655         PR_Unlock(_pr_flock_lock);
  4656         status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
  4657         PR_Lock(_pr_flock_lock);
  4658         fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
  4659         PR_NotifyAllCondVar(_pr_flock_cv);
  4661     else
  4663         fd->secret->lockCount += 1;
  4665     PR_Unlock(_pr_flock_lock);
  4667     return status;
  4668 }  /* PR_LockFile */
  4670 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
  4672     PRStatus status = PR_SUCCESS;
  4674     if (pt_TestAbort()) return PR_FAILURE;
  4676     PR_Lock(_pr_flock_lock);
  4677     if (0 == fd->secret->lockCount)
  4679         status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
  4680         if (PR_SUCCESS == status) fd->secret->lockCount = 1;
  4682     else fd->secret->lockCount += 1;
  4683     PR_Unlock(_pr_flock_lock);
  4685     return status;
  4686 }  /* PR_TLockFile */
  4688 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
  4690     PRStatus status = PR_SUCCESS;
  4692     if (pt_TestAbort()) return PR_FAILURE;
  4694     PR_Lock(_pr_flock_lock);
  4695     if (fd->secret->lockCount == 1)
  4697         status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
  4698         if (PR_SUCCESS == status) fd->secret->lockCount = 0;
  4700     else fd->secret->lockCount -= 1;
  4701     PR_Unlock(_pr_flock_lock);
  4703     return status;
  4706 /*
  4707  * The next two entry points should not be in the API, but they are
  4708  * defined here for historical (or hysterical) reasons.
  4709  */
  4711 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
  4713 #if defined(AIX) || defined(SYMBIAN)
  4714     return sysconf(_SC_OPEN_MAX);
  4715 #else
  4716     struct rlimit rlim;
  4718     if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  4719        return -1;
  4721     return rlim.rlim_max;
  4722 #endif
  4725 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
  4727 #if defined(AIX) || defined(SYMBIAN)
  4728     return -1;
  4729 #else
  4730     struct rlimit rlim;
  4731     PRInt32 tableMax = PR_GetSysfdTableMax();
  4733     if (tableMax < 0) return -1;
  4734     rlim.rlim_max = tableMax;
  4736     /* Grow as much as we can; even if too big */
  4737     if ( rlim.rlim_max < table_size )
  4738         rlim.rlim_cur = rlim.rlim_max;
  4739     else
  4740         rlim.rlim_cur = table_size;
  4742     if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  4743         return -1;
  4745     return rlim.rlim_cur;
  4746 #endif
  4749 /*
  4750  * PR_Stat is supported for backward compatibility; some existing Java
  4751  * code uses it.  New code should use PR_GetFileInfo.
  4752  */
  4754 #ifndef NO_NSPR_10_SUPPORT
  4755 PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
  4757     static PRBool unwarned = PR_TRUE;
  4758     if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
  4760     if (pt_TestAbort()) return -1;
  4762     if (-1 == stat(name, buf)) {
  4763         pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
  4764         return -1;
  4765     } else {
  4766         return 0;
  4769 #endif /* ! NO_NSPR_10_SUPPORT */
  4772 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
  4774     static PRBool unwarned = PR_TRUE;
  4775     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
  4776     memset(set, 0, sizeof(PR_fd_set));
  4779 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
  4781     static PRBool unwarned = PR_TRUE;
  4782     if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
  4783     PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
  4785     set->harray[set->hsize++] = fh;
  4788 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
  4790     PRUint32 index, index2;
  4791     static PRBool unwarned = PR_TRUE;
  4792     if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
  4794     for (index = 0; index<set->hsize; index++)
  4795        if (set->harray[index] == fh) {
  4796            for (index2=index; index2 < (set->hsize-1); index2++) {
  4797                set->harray[index2] = set->harray[index2+1];
  4799            set->hsize--;
  4800            break;
  4804 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
  4806     PRUint32 index;
  4807     static PRBool unwarned = PR_TRUE;
  4808     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
  4809     for (index = 0; index<set->hsize; index++)
  4810        if (set->harray[index] == fh) {
  4811            return 1;
  4813     return 0;
  4816 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
  4818     static PRBool unwarned = PR_TRUE;
  4819     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
  4820     PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
  4822     set->narray[set->nsize++] = fd;
  4825 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
  4827     PRUint32 index, index2;
  4828     static PRBool unwarned = PR_TRUE;
  4829     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
  4831     for (index = 0; index<set->nsize; index++)
  4832        if (set->narray[index] == fd) {
  4833            for (index2=index; index2 < (set->nsize-1); index2++) {
  4834                set->narray[index2] = set->narray[index2+1];
  4836            set->nsize--;
  4837            break;
  4841 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
  4843     PRUint32 index;
  4844     static PRBool unwarned = PR_TRUE;
  4845     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
  4846     for (index = 0; index<set->nsize; index++)
  4847        if (set->narray[index] == fd) {
  4848            return 1;
  4850     return 0;
  4853 #include <sys/types.h>
  4854 #include <sys/time.h>
  4855 #if !defined(HPUX) \
  4856     && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
  4857 #include <sys/select.h>
  4858 #endif
  4860 static PRInt32
  4861 _PR_getset(PR_fd_set *pr_set, fd_set *set)
  4863     PRUint32 index;
  4864     PRInt32 max = 0;
  4866     if (!pr_set)
  4867         return 0;
  4869     FD_ZERO(set);
  4871     /* First set the pr file handle osfds */
  4872     for (index=0; index<pr_set->hsize; index++) {
  4873         FD_SET(pr_set->harray[index]->secret->md.osfd, set);
  4874         if (pr_set->harray[index]->secret->md.osfd > max)
  4875             max = pr_set->harray[index]->secret->md.osfd;
  4877     /* Second set the native osfds */
  4878     for (index=0; index<pr_set->nsize; index++) {
  4879         FD_SET(pr_set->narray[index], set);
  4880         if (pr_set->narray[index] > max)
  4881             max = pr_set->narray[index];
  4883     return max;
  4886 static void
  4887 _PR_setset(PR_fd_set *pr_set, fd_set *set)
  4889     PRUint32 index, last_used;
  4891     if (!pr_set)
  4892         return;
  4894     for (last_used=0, index=0; index<pr_set->hsize; index++) {
  4895         if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
  4896             pr_set->harray[last_used++] = pr_set->harray[index];
  4899     pr_set->hsize = last_used;
  4901     for (last_used=0, index=0; index<pr_set->nsize; index++) {
  4902         if ( FD_ISSET(pr_set->narray[index], set) ) {
  4903             pr_set->narray[last_used++] = pr_set->narray[index];
  4906     pr_set->nsize = last_used;
  4909 PR_IMPLEMENT(PRInt32) PR_Select(
  4910     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
  4911     PR_fd_set *pr_ex, PRIntervalTime timeout)
  4913     fd_set rd, wr, ex;
  4914     struct timeval tv, *tvp;
  4915     PRInt32 max, max_fd;
  4916     PRInt32 rv;
  4917     /*
  4918      * For restarting select() if it is interrupted by a Unix signal.
  4919      * We use these variables to figure out how much time has elapsed
  4920      * and how much of the timeout still remains.
  4921      */
  4922     PRIntervalTime start, elapsed, remaining;
  4924     static PRBool unwarned = PR_TRUE;
  4925     if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
  4927     FD_ZERO(&rd);
  4928     FD_ZERO(&wr);
  4929     FD_ZERO(&ex);
  4931     max_fd = _PR_getset(pr_rd, &rd);
  4932     max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
  4933     max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
  4935     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  4936         tvp = NULL;
  4937     } else {
  4938         tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
  4939         tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  4940                 timeout - PR_SecondsToInterval(tv.tv_sec));
  4941         tvp = &tv;
  4942         start = PR_IntervalNow();
  4945 retry:
  4946     rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
  4947         (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
  4949     if (rv == -1 && errno == EINTR) {
  4950         if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  4951             goto retry;
  4952         } else {
  4953             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
  4954             if (elapsed > timeout) {
  4955                 rv = 0;  /* timed out */
  4956             } else {
  4957                 remaining = timeout - elapsed;
  4958                 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
  4959                 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  4960                         remaining - PR_SecondsToInterval(tv.tv_sec));
  4961                 goto retry;
  4966     if (rv > 0) {
  4967         _PR_setset(pr_rd, &rd);
  4968         _PR_setset(pr_wr, &wr);
  4969         _PR_setset(pr_ex, &ex);
  4970     } else if (rv == -1) {
  4971         pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
  4973     return rv;
  4975 #endif /* defined(_PR_PTHREADS) */
  4977 #ifdef MOZ_UNICODE 
  4978 /* ================ UTF16 Interfaces ================================ */
  4979 PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
  4980     const PRUnichar *name, PRIntn flags, PRIntn mode)
  4982     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  4983     return NULL;
  4986 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
  4988     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  4989     return PR_FAILURE;
  4992 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
  4994     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  4995     return NULL;
  4998 PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
  5000     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  5001     return NULL;
  5004 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
  5006     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  5007     return PR_FAILURE;
  5009 /* ================ UTF16 Interfaces ================================ */
  5010 #endif /* MOZ_UNICODE */
  5012 /* ptio.c */

mercurial