LCOV - code coverage report
Current view: top level - nsprpub/pr/src/pthreads - ptio.c (source / functions) Hit Total Coverage
Test: output.info Lines: 366 1493 24.5 %
Date: 2017-07-14 16:53:18 Functions: 36 89 40.4 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : /*
       7             : ** File:   ptio.c
       8             : ** Descritpion:  Implemenation of I/O methods for pthreads
       9             : */
      10             : 
      11             : #if defined(_PR_PTHREADS)
      12             : 
      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
      19             : 
      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
      49             : 
      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
      58             : 
      59             : #include <sys/sendfile.h>
      60             : 
      61             : #define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
      62             : 
      63             : #else
      64             : 
      65             : #include <dlfcn.h>  /* for dlopen */
      66             : 
      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;
      76             : 
      77             : #define SFV_FD_SELF (-2)
      78             : 
      79             : /*
      80             :  * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
      81             :  */
      82             : static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
      83             : 
      84             : #define SOLARIS_SENDFILEV(a, b, c, d) \
      85             :         (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
      86             : 
      87             : #endif /* HAVE_SENDFILEV */
      88             : #endif /* SOLARIS */
      89             : 
      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
     103             : 
     104             : #ifdef HAVE_SEND_FILE
     105             : 
     106             : #define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
     107             : 
     108             : #else /* HAVE_SEND_FILE */
     109             : 
     110             : /*
     111             :  * The following definitions match those in <sys/socket.h>
     112             :  * on AIX 4.3.2.
     113             :  */
     114             : 
     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             : };
     133             : 
     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 */
     141             : 
     142             : /*
     143             :  * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
     144             :  */
     145             : static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
     146             : 
     147             : #define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
     148             : 
     149             : #endif /* HAVE_SEND_FILE */
     150             : #endif /* AIX */
     151             : 
     152             : #ifdef LINUX
     153             : #include <sys/sendfile.h>
     154             : #endif
     155             : 
     156             : #include "primpl.h"
     157             : 
     158             : #ifdef HAVE_NETINET_TCP_H
     159             : #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
     160             : #endif
     161             : 
     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             : #ifndef MSG_FASTOPEN
     168             : #define MSG_FASTOPEN    0x20000000
     169             : #endif
     170             : #endif
     171             : 
     172             : #ifdef _PR_IPV6_V6ONLY_PROBE
     173             : static PRBool _pr_ipv6_v6only_on_by_default;
     174             : #endif
     175             : 
     176             : #if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
     177             : #define _PRSelectFdSetArg_t int *
     178             : #elif defined(AIX4_1)
     179             : #define _PRSelectFdSetArg_t void *
     180             : #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
     181             :     || defined(OSF1) || defined(SOLARIS) \
     182             :     || defined(HPUX10_30) || defined(HPUX11) \
     183             :     || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
     184             :     || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
     185             :     || defined(BSDI) || defined(NTO) || defined(DARWIN) \
     186             :     || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN)
     187             : #define _PRSelectFdSetArg_t fd_set *
     188             : #else
     189             : #error "Cannot determine architecture"
     190             : #endif
     191             : 
     192             : #if defined(SOLARIS)            
     193             : #ifndef PROTO_SDP
     194             : /* on solaris, SDP is a new type of protocol */
     195             : #define PROTO_SDP   257
     196             : #endif 
     197             : #define _PR_HAVE_SDP
     198             : #elif defined(LINUX)
     199             : #ifndef AF_INET_SDP
     200             : /* on linux, SDP is a new type of address family */
     201             : #define AF_INET_SDP 27
     202             : #endif
     203             : #define _PR_HAVE_SDP
     204             : #endif /* LINUX */
     205             : 
     206             : static PRFileDesc *pt_SetMethods(
     207             :     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
     208             : 
     209             : static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
     210             : static PRCondVar *_pr_flock_cv;  /* For PR_LockFile() etc. */
     211             : static PRLock *_pr_rename_lock;  /* For PR_Rename() */
     212             : 
     213             : /**************************************************************************/
     214             : 
     215             : /* These two functions are only used in assertions. */
     216             : #if defined(DEBUG)
     217             : 
     218           6 : PRBool IsValidNetAddr(const PRNetAddr *addr)
     219             : {
     220           6 :     if ((addr != NULL)
     221           6 :             && (addr->raw.family != AF_UNIX)
     222           6 :             && (addr->raw.family != PR_AF_INET6)
     223           6 :             && (addr->raw.family != AF_INET)) {
     224           0 :         return PR_FALSE;
     225             :     }
     226           6 :     return PR_TRUE;
     227             : }
     228             : 
     229           3 : static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
     230             : {
     231             :     /*
     232             :      * The definition of the length of a Unix domain socket address
     233             :      * is not uniform, so we don't check it.
     234             :      */
     235           3 :     if ((addr != NULL)
     236           3 :             && (addr->raw.family != AF_UNIX)
     237           3 :             && (PR_NETADDR_SIZE(addr) != addr_len)) {
     238             : #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
     239             :         /*
     240             :          * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
     241             :          * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
     242             :          * field and is 28 bytes.  It is possible for socket functions
     243             :          * to return an addr_len greater than sizeof(struct sockaddr_in6).
     244             :          * We need to allow that.  (Bugzilla bug #77264)
     245             :          */
     246             :         if ((PR_AF_INET6 == addr->raw.family)
     247             :                 && (sizeof(addr->ipv6) == addr_len)) {
     248             :             return PR_TRUE;
     249             :         }
     250             : #endif
     251           0 :         return PR_FALSE;
     252             :     }
     253           3 :     return PR_TRUE;
     254             : }
     255             : 
     256             : #endif /* DEBUG */
     257             : 
     258             : /*****************************************************************************/
     259             : /************************* I/O Continuation machinery ************************/
     260             : /*****************************************************************************/
     261             : 
     262             : /*
     263             :  * The polling interval defines the maximum amount of time that a thread
     264             :  * might hang up before an interrupt is noticed.
     265             :  */
     266             : #define PT_DEFAULT_POLL_MSEC 5000
     267             : #if defined(_PR_POLL_WITH_SELECT)
     268             : #define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
     269             : #define PT_DEFAULT_SELECT_USEC                                                  \
     270             :                 ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
     271             : #endif
     272             : 
     273             : /*
     274             :  * pt_SockLen is the type for the length of a socket address
     275             :  * structure, used in the address length argument to bind,
     276             :  * connect, accept, getsockname, getpeername, etc.  Posix.1g
     277             :  * defines this type as socklen_t.  It is size_t or int on
     278             :  * most current systems.
     279             :  */
     280             : #if defined(HAVE_SOCKLEN_T) \
     281             :     || (defined(__GLIBC__) && __GLIBC__ >= 2)
     282             : typedef socklen_t pt_SockLen;
     283             : #elif (defined(AIX) && !defined(AIX4_1)) 
     284             : typedef PRSize pt_SockLen;
     285             : #else
     286             : typedef PRIntn pt_SockLen;
     287             : #endif
     288             : 
     289             : typedef struct pt_Continuation pt_Continuation;
     290             : typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
     291             : 
     292             : typedef enum pr_ContuationStatus
     293             : {
     294             :     pt_continuation_pending,
     295             :     pt_continuation_done
     296             : } pr_ContuationStatus;
     297             : 
     298             : struct pt_Continuation
     299             : {
     300             :     /* The building of the continuation operation */
     301             :     ContinuationFn function;                /* what function to continue */
     302             :     union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
     303             :     union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
     304             :     union {
     305             :         PRSize amount;                      /* #3 - size of 'buffer', or */
     306             :         pt_SockLen *addr_len;                  /*    - length of address */
     307             : #ifdef HPUX11
     308             :         /*
     309             :          * For sendfile()
     310             :          */
     311             :                 struct file_spec {              
     312             :                 off_t offset;                       /* offset in file to send */
     313             :                 size_t nbytes;                      /* length of file data to send */
     314             :                 size_t st_size;                     /* file size */
     315             :                 } file_spec;
     316             : #endif
     317             :     } arg3;
     318             :     union { PRIntn flags; } arg4;           /* #4 - read/write flags */
     319             :     union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
     320             : 
     321             : #ifdef HPUX11
     322             :     /*
     323             :      * For sendfile()
     324             :      */
     325             :     int filedesc;                           /* descriptor of file to send */
     326             :     int nbytes_to_send;                     /* size of header and file */
     327             : #endif  /* HPUX11 */
     328             :     
     329             : #ifdef SOLARIS
     330             :     /*
     331             :      * For sendfilev()
     332             :      */
     333             :     int nbytes_to_send;                     /* size of header and file */
     334             : #endif  /* SOLARIS */
     335             : 
     336             : #ifdef LINUX
     337             :     /*
     338             :      * For sendfile()
     339             :      */
     340             :     int in_fd;                              /* descriptor of file to send */
     341             :     off_t offset;
     342             :     size_t count;
     343             : #endif  /* LINUX */
     344             :  
     345             :     PRIntervalTime timeout;                 /* client (relative) timeout */
     346             : 
     347             :     PRInt16 event;                           /* flags for poll()'s events */
     348             : 
     349             :     /*
     350             :     ** The representation and notification of the results of the operation.
     351             :     ** These function can either return an int return code or a pointer to
     352             :     ** some object.
     353             :     */
     354             :     union { PRSize code; void *object; } result;
     355             : 
     356             :     PRIntn syserrno;                        /* in case it failed, why (errno) */
     357             :     pr_ContuationStatus status;             /* the status of the operation */
     358             : };
     359             : 
     360             : #if defined(DEBUG)
     361             : 
     362             : PTDebug pt_debug;  /* this is shared between several modules */
     363             : 
     364           0 : PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
     365             : {
     366             :     PTDebug stats;
     367             :     char buffer[100];
     368             :     PRExplodedTime tod;
     369             :     PRInt64 elapsed, aMil;
     370           0 :     stats = pt_debug;  /* a copy */
     371           0 :     PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
     372           0 :     (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
     373             : 
     374           0 :     LL_SUB(elapsed, PR_Now(), stats.timeStarted);
     375           0 :     LL_I2L(aMil, 1000000);
     376           0 :     LL_DIV(elapsed, elapsed, aMil);
     377             :     
     378           0 :     if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
     379           0 :     PR_fprintf(
     380             :         debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
     381           0 :     PR_fprintf(
     382             :         debug_out, "\tlocks [created: %u, destroyed: %u]\n",
     383             :         stats.locks_created, stats.locks_destroyed);
     384           0 :     PR_fprintf(
     385             :         debug_out, "\tlocks [acquired: %u, released: %u]\n",
     386             :         stats.locks_acquired, stats.locks_released);
     387           0 :     PR_fprintf(
     388             :         debug_out, "\tcvars [created: %u, destroyed: %u]\n",
     389             :         stats.cvars_created, stats.cvars_destroyed);
     390           0 :     PR_fprintf(
     391             :         debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
     392             :         stats.cvars_notified, stats.delayed_cv_deletes);
     393           0 : }  /* PT_FPrintStats */
     394             : 
     395             : #else
     396             : 
     397             : PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
     398             : {
     399             :     /* do nothing */
     400             : }  /* PT_FPrintStats */
     401             : 
     402             : #endif  /* DEBUG */
     403             : 
     404             : #if defined(_PR_POLL_WITH_SELECT)
     405             : /*
     406             :  * OSF1 and HPUX report the POLLHUP event for a socket when the
     407             :  * shutdown(SHUT_WR) operation is called for the remote end, even though
     408             :  * the socket is still writeable. Use select(), instead of poll(), to
     409             :  * workaround this problem.
     410             :  */
     411             : static void pt_poll_now_with_select(pt_Continuation *op)
     412             : {
     413             :     PRInt32 msecs;
     414             :         fd_set rd, wr, *rdp, *wrp;
     415             :         struct timeval tv;
     416             :         PRIntervalTime epoch, now, elapsed, remaining;
     417             :         PRBool wait_for_remaining;
     418             :     PRThread *self = PR_GetCurrentThread();
     419             :     
     420             :         PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
     421             :         PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
     422             : 
     423             :     switch (op->timeout) {
     424             :         case PR_INTERVAL_NO_TIMEOUT:
     425             :                         tv.tv_sec = PT_DEFAULT_SELECT_SEC;
     426             :                         tv.tv_usec = PT_DEFAULT_SELECT_USEC;
     427             :                         do
     428             :                         {
     429             :                                 PRIntn rv;
     430             : 
     431             :                                 if (op->event & POLLIN) {
     432             :                                         FD_ZERO(&rd);
     433             :                                         FD_SET(op->arg1.osfd, &rd);
     434             :                                         rdp = &rd;
     435             :                                 } else
     436             :                                         rdp = NULL;
     437             :                                 if (op->event & POLLOUT) {
     438             :                                         FD_ZERO(&wr);
     439             :                                         FD_SET(op->arg1.osfd, &wr);
     440             :                                         wrp = &wr;
     441             :                                 } else
     442             :                                         wrp = NULL;
     443             : 
     444             :                                 rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
     445             : 
     446             :                                 if (_PT_THREAD_INTERRUPTED(self))
     447             :                                 {
     448             :                                         self->state &= ~PT_THREAD_ABORTED;
     449             :                                         op->result.code = -1;
     450             :                                         op->syserrno = EINTR;
     451             :                                         op->status = pt_continuation_done;
     452             :                                         return;
     453             :                                 }
     454             : 
     455             :                                 if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
     456             :                                         continue; /* go around the loop again */
     457             : 
     458             :                                 if (rv > 0)
     459             :                                 {
     460             :                                         PRInt16 revents = 0;
     461             : 
     462             :                                         if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
     463             :                                                 revents |= POLLIN;
     464             :                                         if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
     465             :                                                 revents |= POLLOUT;
     466             :                                                 
     467             :                                         if (op->function(op, revents))
     468             :                                                 op->status = pt_continuation_done;
     469             :                                 } else if (rv == -1) {
     470             :                                         op->result.code = -1;
     471             :                                         op->syserrno = errno;
     472             :                                         op->status = pt_continuation_done;
     473             :                                 }
     474             :                                 /* else, select timed out */
     475             :                         } while (pt_continuation_done != op->status);
     476             :                         break;
     477             :         default:
     478             :             now = epoch = PR_IntervalNow();
     479             :             remaining = op->timeout;
     480             :                         do
     481             :                         {
     482             :                                 PRIntn rv;
     483             : 
     484             :                                 if (op->event & POLLIN) {
     485             :                                         FD_ZERO(&rd);
     486             :                                         FD_SET(op->arg1.osfd, &rd);
     487             :                                         rdp = &rd;
     488             :                                 } else
     489             :                                         rdp = NULL;
     490             :                                 if (op->event & POLLOUT) {
     491             :                                         FD_ZERO(&wr);
     492             :                                         FD_SET(op->arg1.osfd, &wr);
     493             :                                         wrp = &wr;
     494             :                                 } else
     495             :                                         wrp = NULL;
     496             : 
     497             :                         wait_for_remaining = PR_TRUE;
     498             :                         msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
     499             :                                 if (msecs > PT_DEFAULT_POLL_MSEC) {
     500             :                                         wait_for_remaining = PR_FALSE;
     501             :                                         msecs = PT_DEFAULT_POLL_MSEC;
     502             :                                 }
     503             :                                 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
     504             :                                 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
     505             :                                 rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
     506             : 
     507             :                                 if (_PT_THREAD_INTERRUPTED(self))
     508             :                                 {
     509             :                                         self->state &= ~PT_THREAD_ABORTED;
     510             :                                         op->result.code = -1;
     511             :                                         op->syserrno = EINTR;
     512             :                                         op->status = pt_continuation_done;
     513             :                                         return;
     514             :                                 }
     515             : 
     516             :                                 if (rv > 0) {
     517             :                                         PRInt16 revents = 0;
     518             : 
     519             :                                         if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
     520             :                                                 revents |= POLLIN;
     521             :                                         if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
     522             :                                                 revents |= POLLOUT;
     523             :                                                 
     524             :                                         if (op->function(op, revents))
     525             :                                                 op->status = pt_continuation_done;
     526             : 
     527             :                                 } else if ((rv == 0) ||
     528             :                                                 ((errno == EINTR) || (errno == EAGAIN))) {
     529             :                                         if (rv == 0) {  /* select timed out */
     530             :                                                 if (wait_for_remaining)
     531             :                                                         now += remaining;
     532             :                                                 else
     533             :                                                         now += PR_MillisecondsToInterval(msecs);
     534             :                                         } else
     535             :                                                 now = PR_IntervalNow();
     536             :                                         elapsed = (PRIntervalTime) (now - epoch);
     537             :                                         if (elapsed >= op->timeout) {
     538             :                                                 op->result.code = -1;
     539             :                                                 op->syserrno = ETIMEDOUT;
     540             :                                                 op->status = pt_continuation_done;
     541             :                                         } else
     542             :                                                 remaining = op->timeout - elapsed;
     543             :                                 } else {
     544             :                                         op->result.code = -1;
     545             :                                         op->syserrno = errno;
     546             :                                         op->status = pt_continuation_done;
     547             :                                 }
     548             :                         } while (pt_continuation_done != op->status);
     549             :             break;
     550             :     }
     551             : 
     552             : }  /* pt_poll_now_with_select */
     553             : 
     554             : #endif  /* _PR_POLL_WITH_SELECT */
     555             : 
     556           0 : static void pt_poll_now(pt_Continuation *op)
     557             : {
     558             :     PRInt32 msecs;
     559             :         PRIntervalTime epoch, now, elapsed, remaining;
     560             :         PRBool wait_for_remaining;
     561           0 :     PRThread *self = PR_GetCurrentThread();
     562             :     
     563           0 :         PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
     564             : #if defined (_PR_POLL_WITH_SELECT)
     565             :         /*
     566             :          * If the fd is small enough call the select-based poll operation
     567             :          */
     568             :         if (op->arg1.osfd < FD_SETSIZE) {
     569             :                 pt_poll_now_with_select(op);
     570             :                 return;
     571             :         }
     572             : #endif
     573             : 
     574           0 :     switch (op->timeout) {
     575             :         case PR_INTERVAL_NO_TIMEOUT:
     576           0 :                         msecs = PT_DEFAULT_POLL_MSEC;
     577             :                         do
     578             :                         {
     579             :                                 PRIntn rv;
     580             :                                 struct pollfd tmp_pfd;
     581             : 
     582           0 :                                 tmp_pfd.revents = 0;
     583           0 :                                 tmp_pfd.fd = op->arg1.osfd;
     584           0 :                                 tmp_pfd.events = op->event;
     585             : 
     586           0 :                                 rv = poll(&tmp_pfd, 1, msecs);
     587             :                                 
     588           0 :                                 if (_PT_THREAD_INTERRUPTED(self))
     589             :                                 {
     590           0 :                                         self->state &= ~PT_THREAD_ABORTED;
     591           0 :                                         op->result.code = -1;
     592           0 :                                         op->syserrno = EINTR;
     593           0 :                                         op->status = pt_continuation_done;
     594           0 :                                         return;
     595             :                                 }
     596             : 
     597           0 :                                 if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
     598           0 :                                         continue; /* go around the loop again */
     599             : 
     600           0 :                                 if (rv > 0)
     601             :                                 {
     602           0 :                                         PRInt16 events = tmp_pfd.events;
     603           0 :                                         PRInt16 revents = tmp_pfd.revents;
     604             : 
     605           0 :                                         if ((revents & POLLNVAL)  /* busted in all cases */
     606           0 :                                         || ((events & POLLOUT) && (revents & POLLHUP)))
     607             :                                                 /* write op & hup */
     608             :                                         {
     609           0 :                                                 op->result.code = -1;
     610           0 :                                                 if (POLLNVAL & revents) op->syserrno = EBADF;
     611           0 :                                                 else if (POLLHUP & revents) op->syserrno = EPIPE;
     612           0 :                                                 op->status = pt_continuation_done;
     613             :                                         } else {
     614           0 :                                                 if (op->function(op, revents))
     615           0 :                                                         op->status = pt_continuation_done;
     616             :                                         }
     617           0 :                                 } else if (rv == -1) {
     618           0 :                                         op->result.code = -1;
     619           0 :                                         op->syserrno = errno;
     620           0 :                                         op->status = pt_continuation_done;
     621             :                                 }
     622             :                                 /* else, poll timed out */
     623           0 :                         } while (pt_continuation_done != op->status);
     624           0 :                         break;
     625             :         default:
     626           0 :             now = epoch = PR_IntervalNow();
     627           0 :             remaining = op->timeout;
     628             :                         do
     629             :                         {
     630             :                                 PRIntn rv;
     631             :                                 struct pollfd tmp_pfd;
     632             : 
     633           0 :                                 tmp_pfd.revents = 0;
     634           0 :                                 tmp_pfd.fd = op->arg1.osfd;
     635           0 :                                 tmp_pfd.events = op->event;
     636             : 
     637           0 :                         wait_for_remaining = PR_TRUE;
     638           0 :                         msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
     639           0 :                                 if (msecs > PT_DEFAULT_POLL_MSEC)
     640             :                                 {
     641           0 :                                         wait_for_remaining = PR_FALSE;
     642           0 :                                         msecs = PT_DEFAULT_POLL_MSEC;
     643             :                                 }
     644           0 :                                 rv = poll(&tmp_pfd, 1, msecs);
     645             :                                 
     646           0 :                                 if (_PT_THREAD_INTERRUPTED(self))
     647             :                                 {
     648           0 :                                         self->state &= ~PT_THREAD_ABORTED;
     649           0 :                                         op->result.code = -1;
     650           0 :                                         op->syserrno = EINTR;
     651           0 :                                         op->status = pt_continuation_done;
     652           0 :                                         return;
     653             :                                 }
     654             : 
     655           0 :                                 if (rv > 0)
     656             :                                 {
     657           0 :                                         PRInt16 events = tmp_pfd.events;
     658           0 :                                         PRInt16 revents = tmp_pfd.revents;
     659             : 
     660           0 :                                         if ((revents & POLLNVAL)  /* busted in all cases */
     661           0 :                                                 || ((events & POLLOUT) && (revents & POLLHUP))) 
     662             :                                                                                         /* write op & hup */
     663             :                                         {
     664           0 :                                                 op->result.code = -1;
     665           0 :                                                 if (POLLNVAL & revents) op->syserrno = EBADF;
     666           0 :                                                 else if (POLLHUP & revents) op->syserrno = EPIPE;
     667           0 :                                                 op->status = pt_continuation_done;
     668             :                                         } else {
     669           0 :                                                 if (op->function(op, revents))
     670             :                                                 {
     671           0 :                                                         op->status = pt_continuation_done;
     672             :                                                 }
     673             :                                         }
     674           0 :                                 } else if ((rv == 0) ||
     675           0 :                                                 ((errno == EINTR) || (errno == EAGAIN))) {
     676           0 :                                         if (rv == 0)    /* poll timed out */
     677             :                                         {
     678           0 :                                                 if (wait_for_remaining)
     679           0 :                                                         now += remaining;
     680             :                                                 else
     681           0 :                                                         now += PR_MillisecondsToInterval(msecs);
     682             :                                         }
     683             :                                         else
     684           0 :                                                 now = PR_IntervalNow();
     685           0 :                                         elapsed = (PRIntervalTime) (now - epoch);
     686           0 :                                         if (elapsed >= op->timeout) {
     687           0 :                                                 op->result.code = -1;
     688           0 :                                                 op->syserrno = ETIMEDOUT;
     689           0 :                                                 op->status = pt_continuation_done;
     690             :                                         } else
     691           0 :                                                 remaining = op->timeout - elapsed;
     692             :                                 } else {
     693           0 :                                         op->result.code = -1;
     694           0 :                                         op->syserrno = errno;
     695           0 :                                         op->status = pt_continuation_done;
     696             :                                 }
     697           0 :                         } while (pt_continuation_done != op->status);
     698           0 :             break;
     699             :     }
     700             : 
     701             : }  /* pt_poll_now */
     702             : 
     703           0 : static PRIntn pt_Continue(pt_Continuation *op)
     704             : {
     705           0 :     op->status = pt_continuation_pending;  /* set default value */
     706             :         /*
     707             :          * let each thread call poll directly
     708             :          */
     709           0 :         pt_poll_now(op);
     710           0 :         PR_ASSERT(pt_continuation_done == op->status);
     711           0 :     return op->result.code;
     712             : }  /* pt_Continue */
     713             : 
     714             : /*****************************************************************************/
     715             : /*********************** specific continuation functions *********************/
     716             : /*****************************************************************************/
     717           0 : static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
     718             : {
     719           0 :     op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
     720           0 :     if (op->syserrno != 0) {
     721           0 :         op->result.code = -1;
     722             :     } else {
     723           0 :         op->result.code = 0;
     724             :     }
     725           0 :     return PR_TRUE; /* this one is cooked */
     726             : }  /* pt_connect_cont */
     727             : 
     728           0 : static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
     729             : {
     730           0 :     op->syserrno = 0;
     731           0 :     op->result.code = accept(
     732           0 :         op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
     733           0 :     if (-1 == op->result.code)
     734             :     {
     735           0 :         op->syserrno = errno;
     736           0 :         if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
     737           0 :             return PR_FALSE;  /* do nothing - this one ain't finished */
     738             :     }
     739           0 :     return PR_TRUE;
     740             : }  /* pt_accept_cont */
     741             : 
     742           0 : static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
     743             : {
     744             :     /*
     745             :      * Any number of bytes will complete the operation. It need
     746             :      * not (and probably will not) satisfy the request. The only
     747             :      * error we continue is EWOULDBLOCK|EAGAIN.
     748             :      */
     749           0 :     op->result.code = read(
     750             :         op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
     751           0 :     op->syserrno = errno;
     752           0 :     return ((-1 == op->result.code) && 
     753           0 :             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
     754           0 :         PR_FALSE : PR_TRUE;
     755             : }  /* pt_read_cont */
     756             : 
     757           0 : static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
     758             : {
     759             :     /*
     760             :      * Any number of bytes will complete the operation. It need
     761             :      * not (and probably will not) satisfy the request. The only
     762             :      * error we continue is EWOULDBLOCK|EAGAIN.
     763             :      */
     764             : #if defined(SOLARIS)
     765             :     if (0 == op->arg4.flags)
     766             :         op->result.code = read(
     767             :             op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
     768             :     else
     769             :         op->result.code = recv(
     770             :             op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
     771             : #else
     772           0 :     op->result.code = recv(
     773             :         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
     774             : #endif
     775           0 :     op->syserrno = errno;
     776           0 :     return ((-1 == op->result.code) && 
     777           0 :             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
     778           0 :         PR_FALSE : PR_TRUE;
     779             : }  /* pt_recv_cont */
     780             : 
     781           0 : static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
     782             : {
     783             :     PRIntn bytes;
     784             : #if defined(SOLARIS)
     785             :     PRInt32 tmp_amount = op->arg3.amount;
     786             : #endif
     787             :     /*
     788             :      * We want to write the entire amount out, no matter how many
     789             :      * tries it takes. Keep advancing the buffer and the decrementing
     790             :      * the amount until the amount goes away. Return the total bytes
     791             :      * (which should be the original amount) when finished (or an
     792             :      * error).
     793             :      */
     794             : #if defined(SOLARIS)
     795             : retry:
     796             :     bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
     797             : #else
     798           0 :     bytes = send(
     799           0 :         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
     800             : #endif
     801           0 :     op->syserrno = errno;
     802             : 
     803             : #if defined(SOLARIS)
     804             :     /*
     805             :      * The write system call has been reported to return the ERANGE error
     806             :      * on occasion. Try to write in smaller chunks to workaround this bug.
     807             :      */
     808             :     if ((bytes == -1) && (op->syserrno == ERANGE))
     809             :     {
     810             :         if (tmp_amount > 1)
     811             :         {
     812             :             tmp_amount = tmp_amount/2;  /* half the bytes */
     813             :             goto retry;
     814             :         }
     815             :     }
     816             : #endif
     817             : 
     818           0 :     if (bytes >= 0)  /* this is progress */
     819             :     {
     820           0 :         char *bp = (char*)op->arg2.buffer;
     821           0 :         bp += bytes;  /* adjust the buffer pointer */
     822           0 :         op->arg2.buffer = bp;
     823           0 :         op->result.code += bytes;  /* accumulate the number sent */
     824           0 :         op->arg3.amount -= bytes;  /* and reduce the required count */
     825           0 :         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
     826             :     }
     827           0 :     if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
     828             :     {
     829           0 :         op->result.code = -1;
     830           0 :         return PR_TRUE;
     831             :     }
     832           0 :     else return PR_FALSE;
     833             : }  /* pt_send_cont */
     834             : 
     835           0 : static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
     836             : {
     837             :     PRIntn bytes;
     838             :     /*
     839             :      * We want to write the entire amount out, no matter how many
     840             :      * tries it takes. Keep advancing the buffer and the decrementing
     841             :      * the amount until the amount goes away. Return the total bytes
     842             :      * (which should be the original amount) when finished (or an
     843             :      * error).
     844             :      */
     845           0 :     bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
     846           0 :     op->syserrno = errno;
     847           0 :     if (bytes >= 0)  /* this is progress */
     848             :     {
     849           0 :         char *bp = (char*)op->arg2.buffer;
     850           0 :         bp += bytes;  /* adjust the buffer pointer */
     851           0 :         op->arg2.buffer = bp;
     852           0 :         op->result.code += bytes;  /* accumulate the number sent */
     853           0 :         op->arg3.amount -= bytes;  /* and reduce the required count */
     854           0 :         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
     855             :     }
     856           0 :     if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
     857             :     {
     858           0 :         op->result.code = -1;
     859           0 :         return PR_TRUE;
     860             :     }
     861           0 :     else return PR_FALSE;
     862             : }  /* pt_write_cont */
     863             : 
     864           0 : static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
     865             : {
     866             :     PRIntn bytes;
     867           0 :     struct iovec *iov = (struct iovec*)op->arg2.buffer;
     868             :     /*
     869             :      * Same rules as write, but continuing seems to be a bit more
     870             :      * complicated. As the number of bytes sent grows, we have to
     871             :      * redefine the vector we're pointing at. We might have to
     872             :      * modify an individual vector parms or we might have to eliminate
     873             :      * a pair altogether.
     874             :      */
     875           0 :     bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
     876           0 :     op->syserrno = errno;
     877           0 :     if (bytes >= 0)  /* this is progress */
     878             :     {
     879             :         PRIntn iov_index;
     880           0 :         op->result.code += bytes;  /* accumulate the number sent */
     881           0 :         for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
     882             :         {
     883             :             /* how much progress did we make in the i/o vector? */
     884           0 :             if (bytes < iov[iov_index].iov_len)
     885             :             {
     886             :                 /* this element's not done yet */
     887           0 :                 char **bp = (char**)&(iov[iov_index].iov_base);
     888           0 :                 iov[iov_index].iov_len -= bytes;  /* there's that much left */
     889           0 :                 *bp += bytes;  /* starting there */
     890           0 :                 break;  /* go off and do that */
     891             :             }
     892           0 :             bytes -= iov[iov_index].iov_len;  /* that element's consumed */
     893             :         }
     894           0 :         op->arg2.buffer = &iov[iov_index];  /* new start of array */
     895           0 :         op->arg3.amount -= iov_index;  /* and array length */
     896           0 :         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
     897             :     }
     898           0 :     if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
     899             :     {
     900           0 :         op->result.code = -1;
     901           0 :         return PR_TRUE;
     902             :     }
     903           0 :     else return PR_FALSE;
     904             : }  /* pt_writev_cont */
     905             : 
     906           0 : static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
     907             : {
     908           0 :     PRIntn bytes = sendto(
     909           0 :         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
     910           0 :         (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
     911           0 :     op->syserrno = errno;
     912           0 :     if (bytes >= 0)  /* this is progress */
     913             :     {
     914           0 :         char *bp = (char*)op->arg2.buffer;
     915           0 :         bp += bytes;  /* adjust the buffer pointer */
     916           0 :         op->arg2.buffer = bp;
     917           0 :         op->result.code += bytes;  /* accumulate the number sent */
     918           0 :         op->arg3.amount -= bytes;  /* and reduce the required count */
     919           0 :         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
     920             :     }
     921           0 :     if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
     922             :     {
     923           0 :         op->result.code = -1;
     924           0 :         return PR_TRUE;
     925             :     }
     926           0 :     else return PR_FALSE;
     927             : }  /* pt_sendto_cont */
     928             : 
     929           0 : static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
     930             : {
     931           0 :     pt_SockLen addr_len = sizeof(PRNetAddr);
     932           0 :     op->result.code = recvfrom(
     933             :         op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
     934           0 :         op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
     935           0 :     op->syserrno = errno;
     936           0 :     return ((-1 == op->result.code) && 
     937           0 :             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
     938           0 :         PR_FALSE : PR_TRUE;
     939             : }  /* pt_recvfrom_cont */
     940             : 
     941             : #ifdef AIX
     942             : static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
     943             : {
     944             :     struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
     945             :     ssize_t rv;
     946             :         unsigned long long saved_file_offset;
     947             :         long long saved_file_bytes;
     948             : 
     949             :         saved_file_offset = sf_struct->file_offset;
     950             :         saved_file_bytes = sf_struct->file_bytes;
     951             :         sf_struct->bytes_sent = 0;
     952             : 
     953             :         if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
     954             :         PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
     955             :                                                                         sf_struct->file_size);
     956             :     rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
     957             :     op->syserrno = errno;
     958             : 
     959             :     if (rv != -1) {
     960             :         op->result.code += sf_struct->bytes_sent;
     961             :                 /*
     962             :                  * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
     963             :                  * being updated. So, 'file_bytes' is maintained by NSPR to
     964             :                  * avoid conflict when this bug is fixed in AIX, in the future.
     965             :                  */
     966             :                 if (saved_file_bytes != -1)
     967             :                         saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
     968             :                 sf_struct->file_bytes = saved_file_bytes;
     969             :     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
     970             :         op->result.code = -1;
     971             :     } else {
     972             :         return PR_FALSE;
     973             :     }
     974             : 
     975             :     if (rv == 1) {    /* more data to send */
     976             :         return PR_FALSE;
     977             :     }
     978             : 
     979             :     return PR_TRUE;
     980             : }
     981             : #endif  /* AIX */
     982             : 
     983             : #ifdef HPUX11
     984             : static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
     985             : {
     986             :     struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
     987             :     int count;
     988             : 
     989             :     count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
     990             :                         op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
     991             :     PR_ASSERT(count <= op->nbytes_to_send);
     992             :     op->syserrno = errno;
     993             : 
     994             :     if (count != -1) {
     995             :         op->result.code += count;
     996             :     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
     997             :         op->result.code = -1;
     998             :     } else {
     999             :         return PR_FALSE;
    1000             :     }
    1001             :     if (count != -1 && count < op->nbytes_to_send) {
    1002             :         if (count < hdtrl[0].iov_len) {
    1003             :                         /* header not sent */
    1004             : 
    1005             :             hdtrl[0].iov_base = ((char *) hdtrl[0].iov_base) + count;
    1006             :             hdtrl[0].iov_len -= count;
    1007             : 
    1008             :         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
    1009             :                         /* header sent, file not sent */
    1010             :             PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
    1011             : 
    1012             :             hdtrl[0].iov_base = NULL;
    1013             :             hdtrl[0].iov_len = 0;
    1014             : 
    1015             :             op->arg3.file_spec.offset += file_nbytes_sent;
    1016             :             op->arg3.file_spec.nbytes -= file_nbytes_sent;
    1017             :         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
    1018             :                                                                                         hdtrl[1].iov_len)) {
    1019             :             PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
    1020             :                                          op->arg3.file_spec.nbytes);
    1021             : 
    1022             :                         /* header sent, file sent, trailer not sent */
    1023             : 
    1024             :             hdtrl[0].iov_base = NULL;
    1025             :             hdtrl[0].iov_len = 0;
    1026             :                         /*
    1027             :                          * set file offset and len so that no more file data is
    1028             :                          * sent
    1029             :                          */
    1030             :             op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
    1031             :             op->arg3.file_spec.nbytes = 0;
    1032             : 
    1033             :             hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
    1034             :             hdtrl[1].iov_len -= trailer_nbytes_sent;
    1035             :                 }
    1036             :         op->nbytes_to_send -= count;
    1037             :         return PR_FALSE;
    1038             :     }
    1039             : 
    1040             :     return PR_TRUE;
    1041             : }
    1042             : #endif  /* HPUX11 */
    1043             : 
    1044             : #ifdef SOLARIS  
    1045             : static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
    1046             : {
    1047             :     struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
    1048             :     size_t xferred;
    1049             :     ssize_t count;
    1050             : 
    1051             :     count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
    1052             :     op->syserrno = errno;
    1053             :     PR_ASSERT((count == -1) || (count == xferred));
    1054             : 
    1055             :     if (count == -1) {
    1056             :         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
    1057             :                 && op->syserrno != EINTR) {
    1058             :             op->result.code = -1;
    1059             :             return PR_TRUE;
    1060             :         }
    1061             :         count = xferred;
    1062             :     } else if (count == 0) {
    1063             :         /* 
    1064             :          * We are now at EOF. The file was truncated. Solaris sendfile is
    1065             :          * supposed to return 0 and no error in this case, though some versions
    1066             :          * may return -1 and EINVAL .
    1067             :          */
    1068             :         op->result.code = -1;
    1069             :         op->syserrno = 0; /* will be treated as EOF */
    1070             :         return PR_TRUE;
    1071             :     }
    1072             :     PR_ASSERT(count <= op->nbytes_to_send);
    1073             :     
    1074             :     op->result.code += count;
    1075             :     if (count < op->nbytes_to_send) {
    1076             :         op->nbytes_to_send -= count;
    1077             : 
    1078             :         while (count >= vec->sfv_len) {
    1079             :             count -= vec->sfv_len;
    1080             :             vec++;
    1081             :             op->arg3.amount--;
    1082             :         }
    1083             :         PR_ASSERT(op->arg3.amount > 0);
    1084             : 
    1085             :         vec->sfv_off += count;
    1086             :         vec->sfv_len -= count;
    1087             :         PR_ASSERT(vec->sfv_len > 0);
    1088             :         op->arg2.buffer = vec;
    1089             : 
    1090             :         return PR_FALSE;
    1091             :     }
    1092             : 
    1093             :     return PR_TRUE;
    1094             : }
    1095             : #endif  /* SOLARIS */
    1096             : 
    1097             : #ifdef LINUX 
    1098           0 : static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
    1099             : {
    1100             :     ssize_t rv;
    1101             :     off_t oldoffset;
    1102             : 
    1103           0 :     oldoffset = op->offset;
    1104           0 :     rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
    1105           0 :     op->syserrno = errno;
    1106             : 
    1107           0 :     if (rv == -1) {
    1108           0 :         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
    1109           0 :             op->result.code = -1;
    1110           0 :             return PR_TRUE;
    1111             :         }
    1112           0 :         rv = 0;
    1113             :     }
    1114           0 :     PR_ASSERT(rv == op->offset - oldoffset);
    1115           0 :     op->result.code += rv;
    1116           0 :     if (rv < op->count) {
    1117           0 :         op->count -= rv;
    1118           0 :         return PR_FALSE;
    1119             :     }
    1120           0 :     return PR_TRUE;
    1121             : }
    1122             : #endif  /* LINUX */
    1123             : 
    1124           3 : void _PR_InitIO(void)
    1125             : {
    1126             : #if defined(DEBUG)
    1127           3 :     memset(&pt_debug, 0, sizeof(PTDebug));
    1128           3 :     pt_debug.timeStarted = PR_Now();
    1129             : #endif
    1130             : 
    1131           3 :     _pr_flock_lock = PR_NewLock();
    1132           3 :     PR_ASSERT(NULL != _pr_flock_lock);
    1133           3 :     _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
    1134           3 :     PR_ASSERT(NULL != _pr_flock_cv);
    1135           3 :     _pr_rename_lock = PR_NewLock();
    1136           3 :     PR_ASSERT(NULL != _pr_rename_lock); 
    1137             : 
    1138           3 :     _PR_InitFdCache();  /* do that */   
    1139             : 
    1140           3 :     _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    1141           3 :     _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    1142           3 :     _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    1143           3 :     PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
    1144             : 
    1145             : #ifdef _PR_IPV6_V6ONLY_PROBE
    1146             :     /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
    1147             :      * is turned on by default, contrary to what RFC 3493, Section
    1148             :      * 5.3 says.  So we have to turn it off.  Find out whether we
    1149             :      * are running on such a system.
    1150             :      */
    1151             :     {
    1152             :         int osfd;
    1153             :         osfd = socket(AF_INET6, SOCK_STREAM, 0);
    1154             :         if (osfd != -1) {
    1155             :             int on;
    1156             :             socklen_t optlen = sizeof(on);
    1157             :             if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
    1158             :                     &on, &optlen) == 0) {
    1159             :                 _pr_ipv6_v6only_on_by_default = on;
    1160             :             }
    1161             :             close(osfd);
    1162             :         }
    1163             :     }
    1164             : #endif
    1165           3 : }  /* _PR_InitIO */
    1166             : 
    1167           0 : void _PR_CleanupIO(void)
    1168             : {
    1169           0 :     _PR_Putfd(_pr_stdin);
    1170           0 :     _pr_stdin = NULL;
    1171           0 :     _PR_Putfd(_pr_stdout);
    1172           0 :     _pr_stdout = NULL;
    1173           0 :     _PR_Putfd(_pr_stderr); 
    1174           0 :     _pr_stderr = NULL;
    1175             : 
    1176           0 :     _PR_CleanupFdCache();
    1177             :     
    1178           0 :     if (_pr_flock_cv)
    1179             :     {
    1180           0 :         PR_DestroyCondVar(_pr_flock_cv);
    1181           0 :         _pr_flock_cv = NULL;
    1182             :     }
    1183           0 :     if (_pr_flock_lock)
    1184             :     {
    1185           0 :         PR_DestroyLock(_pr_flock_lock);
    1186           0 :         _pr_flock_lock = NULL;
    1187             :     }
    1188           0 :     if (_pr_rename_lock)
    1189             :     {
    1190           0 :         PR_DestroyLock(_pr_rename_lock);
    1191           0 :         _pr_rename_lock = NULL;
    1192             :     }
    1193           0 : }  /* _PR_CleanupIO */
    1194             : 
    1195             : PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
    1196             : {
    1197           0 :     PRFileDesc *result = NULL;
    1198           0 :     PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
    1199             : 
    1200           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    1201             :     
    1202           0 :     switch (osfd)
    1203             :     {
    1204           0 :         case PR_StandardInput: result = _pr_stdin; break;
    1205           0 :         case PR_StandardOutput: result = _pr_stdout; break;
    1206           0 :         case PR_StandardError: result = _pr_stderr; break;
    1207             :         default:
    1208           0 :             (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1209             :     }
    1210           0 :     return result;
    1211             : }  /* PR_GetSpecialFD */
    1212             : 
    1213             : /*****************************************************************************/
    1214             : /***************************** I/O private methods ***************************/
    1215             : /*****************************************************************************/
    1216             : 
    1217        4065 : static PRBool pt_TestAbort(void)
    1218             : {
    1219        4065 :     PRThread *me = PR_GetCurrentThread();
    1220        4065 :     if(_PT_THREAD_INTERRUPTED(me))
    1221             :     {
    1222           0 :         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    1223           0 :         me->state &= ~PT_THREAD_ABORTED;
    1224           0 :         return PR_TRUE;
    1225             :     }
    1226        4065 :     return PR_FALSE;
    1227             : }  /* pt_TestAbort */
    1228             : 
    1229          23 : static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
    1230             : {
    1231          23 :     switch (syserrno)
    1232             :     {
    1233             :         case EINTR:
    1234           0 :             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
    1235             :         case ETIMEDOUT:
    1236           0 :             PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
    1237             :         default:
    1238          23 :             mapper(syserrno);
    1239             :     }
    1240          23 : }  /* pt_MapError */
    1241             : 
    1242        1256 : static PRStatus pt_Close(PRFileDesc *fd)
    1243             : {
    1244        1256 :     if ((NULL == fd) || (NULL == fd->secret)
    1245        1256 :         || ((_PR_FILEDESC_OPEN != fd->secret->state)
    1246           0 :         && (_PR_FILEDESC_CLOSED != fd->secret->state)))
    1247             :     {
    1248           0 :         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    1249           0 :         return PR_FAILURE;
    1250             :     }
    1251        1256 :     if (pt_TestAbort()) return PR_FAILURE;
    1252             : 
    1253        1256 :     if (_PR_FILEDESC_OPEN == fd->secret->state)
    1254             :     {
    1255        1256 :         if (-1 == close(fd->secret->md.osfd))
    1256             :         {
    1257             : #ifdef OSF1
    1258             :             /*
    1259             :              * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
    1260             :              * system call, when called to close a TCP socket, may
    1261             :              * return -1 with errno set to EINVAL but the system call
    1262             :              * does close the socket successfully.  An application
    1263             :              * may safely ignore the EINVAL error.  This bug is fixed
    1264             :              * on Tru64 UNIX V5.1A and later.  The defect tracking
    1265             :              * number is QAR 81431.
    1266             :              */
    1267             :             if (PR_DESC_SOCKET_TCP != fd->methods->file_type
    1268             :             || EINVAL != errno)
    1269             :             {
    1270             :                 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
    1271             :                 return PR_FAILURE;
    1272             :             }
    1273             : #else
    1274           0 :             pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
    1275           0 :             return PR_FAILURE;
    1276             : #endif
    1277             :         }
    1278        1256 :         fd->secret->state = _PR_FILEDESC_CLOSED;
    1279             :     }
    1280        1256 :     _PR_Putfd(fd);
    1281        1256 :     return PR_SUCCESS;
    1282             : }  /* pt_Close */
    1283             : 
    1284        1281 : static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
    1285             : {
    1286        1281 :     PRInt32 syserrno, bytes = -1;
    1287             : 
    1288        1281 :     if (pt_TestAbort()) return bytes;
    1289             : 
    1290        1281 :     bytes = read(fd->secret->md.osfd, buf, amount);
    1291        1281 :     syserrno = errno;
    1292             : 
    1293        1281 :     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1294           0 :         && (!fd->secret->nonblocking))
    1295             :     {
    1296             :         pt_Continuation op;
    1297           0 :         op.arg1.osfd = fd->secret->md.osfd;
    1298           0 :         op.arg2.buffer = buf;
    1299           0 :         op.arg3.amount = amount;
    1300           0 :         op.timeout = PR_INTERVAL_NO_TIMEOUT;
    1301           0 :         op.function = pt_read_cont;
    1302           0 :         op.event = POLLIN | POLLPRI;
    1303           0 :         bytes = pt_Continue(&op);
    1304           0 :         syserrno = op.syserrno;
    1305             :     }
    1306        1281 :     if (bytes < 0)
    1307           0 :         pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
    1308        1281 :     return bytes;
    1309             : }  /* pt_Read */
    1310             : 
    1311         156 : static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
    1312             : {
    1313         156 :     PRInt32 syserrno, bytes = -1;
    1314         156 :     PRBool fNeedContinue = PR_FALSE;
    1315             : 
    1316         156 :     if (pt_TestAbort()) return bytes;
    1317             : 
    1318         156 :     bytes = write(fd->secret->md.osfd, buf, amount);
    1319         156 :     syserrno = errno;
    1320             : 
    1321         156 :     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
    1322             :     {
    1323           0 :         buf = (char *) buf + bytes;
    1324           0 :         amount -= bytes;
    1325           0 :         fNeedContinue = PR_TRUE;
    1326             :     }
    1327         156 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1328           0 :         && (!fd->secret->nonblocking) )
    1329             :     {
    1330           0 :         bytes = 0;
    1331           0 :         fNeedContinue = PR_TRUE;
    1332             :     }
    1333             : 
    1334         156 :     if (fNeedContinue == PR_TRUE)
    1335             :     {
    1336             :         pt_Continuation op;
    1337           0 :         op.arg1.osfd = fd->secret->md.osfd;
    1338           0 :         op.arg2.buffer = (void*)buf;
    1339           0 :         op.arg3.amount = amount;
    1340           0 :         op.timeout = PR_INTERVAL_NO_TIMEOUT;
    1341           0 :         op.result.code = bytes;  /* initialize the number sent */
    1342           0 :         op.function = pt_write_cont;
    1343           0 :         op.event = POLLOUT | POLLPRI;
    1344           0 :         bytes = pt_Continue(&op);
    1345           0 :         syserrno = op.syserrno;
    1346             :     }
    1347         156 :     if (bytes == -1)
    1348           0 :         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
    1349         156 :     return bytes;
    1350             : }  /* pt_Write */
    1351             : 
    1352           0 : static PRInt32 pt_Writev(
    1353             :     PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
    1354             : {
    1355             :     PRIntn iov_index;
    1356           0 :     PRBool fNeedContinue = PR_FALSE;
    1357           0 :     PRInt32 syserrno, bytes, rv = -1;
    1358             :     struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
    1359             :     int osiov_len;
    1360             : 
    1361           0 :     if (pt_TestAbort()) return rv;
    1362             : 
    1363             :     /* Ensured by PR_Writev */
    1364           0 :     PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
    1365             : 
    1366             :     /*
    1367             :      * We can't pass iov to writev because PRIOVec and struct iovec
    1368             :      * may not be binary compatible.  Make osiov a copy of iov and
    1369             :      * pass osiov to writev.  We can modify osiov if we need to
    1370             :      * continue the operation.
    1371             :      */
    1372           0 :     osiov = osiov_local;
    1373           0 :     osiov_len = iov_len;
    1374           0 :     for (iov_index = 0; iov_index < osiov_len; iov_index++)
    1375             :     {
    1376           0 :         osiov[iov_index].iov_base = iov[iov_index].iov_base;
    1377           0 :         osiov[iov_index].iov_len = iov[iov_index].iov_len;
    1378             :     }
    1379             : 
    1380           0 :     rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
    1381           0 :     syserrno = errno;
    1382             : 
    1383           0 :     if (!fd->secret->nonblocking)
    1384             :     {
    1385           0 :         if (bytes >= 0)
    1386             :         {
    1387             :             /*
    1388             :              * If we moved some bytes, how does that implicate the
    1389             :              * i/o vector list?  In other words, exactly where are
    1390             :              * we within that array?  What are the parameters for
    1391             :              * resumption?  Maybe we're done!
    1392             :              */
    1393           0 :             for ( ;osiov_len > 0; osiov++, osiov_len--)
    1394             :             {
    1395           0 :                 if (bytes < osiov->iov_len)
    1396             :                 {
    1397             :                     /* this one's not done yet */
    1398           0 :                     osiov->iov_base = (char*)osiov->iov_base + bytes;
    1399           0 :                     osiov->iov_len -= bytes;
    1400           0 :                     break;  /* go off and do that */
    1401             :                 }
    1402           0 :                 bytes -= osiov->iov_len;  /* this one's done cooked */
    1403             :             }
    1404           0 :             PR_ASSERT(osiov_len > 0 || bytes == 0);
    1405           0 :             if (osiov_len > 0)
    1406             :             {
    1407           0 :                 if (PR_INTERVAL_NO_WAIT == timeout)
    1408             :                 {
    1409           0 :                     rv = -1;
    1410           0 :                     syserrno = ETIMEDOUT;
    1411             :                 }
    1412           0 :                 else fNeedContinue = PR_TRUE;
    1413             :             }
    1414             :         }
    1415           0 :         else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1416             :         {
    1417           0 :             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    1418             :             else
    1419             :             {
    1420           0 :                 rv = 0;
    1421           0 :                 fNeedContinue = PR_TRUE;
    1422             :             }
    1423             :         }
    1424             :     }
    1425             : 
    1426           0 :     if (fNeedContinue == PR_TRUE)
    1427             :     {
    1428             :         pt_Continuation op;
    1429             : 
    1430           0 :         op.arg1.osfd = fd->secret->md.osfd;
    1431           0 :         op.arg2.buffer = (void*)osiov;
    1432           0 :         op.arg3.amount = osiov_len;
    1433           0 :         op.timeout = timeout;
    1434           0 :         op.result.code = rv;
    1435           0 :         op.function = pt_writev_cont;
    1436           0 :         op.event = POLLOUT | POLLPRI;
    1437           0 :         rv = pt_Continue(&op);
    1438           0 :         syserrno = op.syserrno;
    1439             :     }
    1440           0 :     if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
    1441           0 :     return rv;
    1442             : }  /* pt_Writev */
    1443             : 
    1444           2 : static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
    1445             : {
    1446           2 :     return _PR_MD_LSEEK(fd, offset, whence);
    1447             : }  /* pt_Seek */
    1448             : 
    1449          11 : static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
    1450             : {
    1451          11 :     return _PR_MD_LSEEK64(fd, offset, whence);
    1452             : }  /* pt_Seek64 */
    1453             : 
    1454           2 : static PRInt32 pt_Available_f(PRFileDesc *fd)
    1455             : {
    1456             :     PRInt32 result, cur, end;
    1457             : 
    1458           2 :     cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
    1459             : 
    1460           2 :     if (cur >= 0)
    1461           2 :         end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
    1462             : 
    1463           2 :     if ((cur < 0) || (end < 0)) {
    1464           0 :         return -1;
    1465             :     }
    1466             : 
    1467           2 :     result = end - cur;
    1468           2 :     _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
    1469             : 
    1470           2 :     return result;
    1471             : }  /* pt_Available_f */
    1472             : 
    1473         134 : static PRInt64 pt_Available64_f(PRFileDesc *fd)
    1474             : {
    1475             :     PRInt64 result, cur, end;
    1476             :     PRInt64 minus_one;
    1477             : 
    1478         134 :     LL_I2L(minus_one, -1);
    1479         134 :     cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
    1480             : 
    1481         134 :     if (LL_GE_ZERO(cur))
    1482         134 :         end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
    1483             : 
    1484         134 :     if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
    1485             : 
    1486         134 :     LL_SUB(result, end, cur);
    1487         134 :     (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
    1488             : 
    1489         134 :     return result;
    1490             : }  /* pt_Available64_f */
    1491             : 
    1492           1 : static PRInt32 pt_Available_s(PRFileDesc *fd)
    1493             : {
    1494           1 :     PRInt32 rv, bytes = -1;
    1495           1 :     if (pt_TestAbort()) return bytes;
    1496             : 
    1497           1 :     rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
    1498             : 
    1499           1 :     if (rv == -1)
    1500           0 :         pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
    1501           1 :     return bytes;
    1502             : }  /* pt_Available_s */
    1503             : 
    1504           0 : static PRInt64 pt_Available64_s(PRFileDesc *fd)
    1505             : {
    1506             :     PRInt64 rv;
    1507           0 :     LL_I2L(rv, pt_Available_s(fd));
    1508           0 :     return rv;
    1509             : }  /* pt_Available64_s */
    1510             : 
    1511           1 : static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
    1512             : {
    1513           1 :     PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
    1514           1 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    1515             : }  /* pt_FileInfo */
    1516             : 
    1517         941 : static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
    1518             : {
    1519         941 :     PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
    1520         941 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    1521             : }  /* pt_FileInfo64 */
    1522             : 
    1523           0 : static PRStatus pt_Synch(PRFileDesc *fd)
    1524             : {
    1525           0 :     return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
    1526             : } /* pt_Synch */
    1527             : 
    1528           6 : static PRStatus pt_Fsync(PRFileDesc *fd)
    1529             : {
    1530           6 :     PRIntn rv = -1;
    1531           6 :     if (pt_TestAbort()) return PR_FAILURE;
    1532             : 
    1533           6 :     rv = fsync(fd->secret->md.osfd);
    1534           6 :     if (rv < 0) {
    1535           0 :         pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
    1536           0 :         return PR_FAILURE;
    1537             :     }
    1538           6 :     return PR_SUCCESS;
    1539             : }  /* pt_Fsync */
    1540             : 
    1541           1 : static PRStatus pt_Connect(
    1542             :     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
    1543             : {
    1544           1 :     PRIntn rv = -1, syserrno;
    1545             :     pt_SockLen addr_len;
    1546           1 :         const PRNetAddr *addrp = addr;
    1547             : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
    1548             :     PRNetAddr addrCopy;
    1549             : #endif
    1550             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1551             :     PRUint16 md_af = addr->raw.family;
    1552             : #endif
    1553             : 
    1554           1 :     if (pt_TestAbort()) return PR_FAILURE;
    1555             : 
    1556           1 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    1557           1 :     addr_len = PR_NETADDR_SIZE(addr);
    1558             : #ifdef _PR_INET6
    1559           1 :     if (addr->raw.family == PR_AF_INET6) {
    1560             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1561             :         md_af = AF_INET6;
    1562             : #else
    1563           0 :         addrCopy = *addr;
    1564           0 :         addrCopy.raw.family = AF_INET6;
    1565           0 :         addrp = &addrCopy;
    1566             : #endif
    1567             :     }
    1568             : #endif
    1569             : 
    1570             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1571             :     addrCopy = *addr;
    1572             :     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
    1573             :     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
    1574             :     addrp = &addrCopy;
    1575             : #endif
    1576           1 :     rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
    1577           1 :     syserrno = errno;
    1578           1 :     if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
    1579             :     {
    1580           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    1581             :         else
    1582             :         {
    1583             :             pt_Continuation op;
    1584           0 :             op.arg1.osfd = fd->secret->md.osfd;
    1585           0 :             op.arg2.buffer = (void*)addrp;
    1586           0 :             op.arg3.amount = addr_len;
    1587           0 :             op.timeout = timeout;
    1588           0 :             op.function = pt_connect_cont;
    1589           0 :             op.event = POLLOUT | POLLPRI;
    1590           0 :             rv = pt_Continue(&op);
    1591           0 :             syserrno = op.syserrno;
    1592             :         }
    1593             :     }
    1594           1 :     if (-1 == rv) {
    1595           1 :         pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
    1596           1 :         return PR_FAILURE;
    1597             :     }
    1598           0 :     return PR_SUCCESS;
    1599             : }  /* pt_Connect */
    1600             : 
    1601           3 : static PRStatus pt_ConnectContinue(
    1602             :     PRFileDesc *fd, PRInt16 out_flags)
    1603             : {
    1604             :     int err;
    1605             :     PRInt32 osfd;
    1606             : 
    1607           3 :     if (out_flags & PR_POLL_NVAL)
    1608             :     {
    1609           0 :         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    1610           0 :         return PR_FAILURE;
    1611             :     }
    1612           3 :     if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR
    1613             :         | PR_POLL_HUP)) == 0)
    1614             :     {
    1615           0 :         PR_ASSERT(out_flags == 0);
    1616           0 :         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
    1617           0 :         return PR_FAILURE;
    1618             :     }
    1619             : 
    1620           3 :     osfd = fd->secret->md.osfd;
    1621             : 
    1622           3 :     err = _MD_unix_get_nonblocking_connect_error(osfd);
    1623           3 :     if (err != 0)
    1624             :     {
    1625           0 :         _PR_MD_MAP_CONNECT_ERROR(err);
    1626           0 :         return PR_FAILURE;
    1627             :     }
    1628           3 :     return PR_SUCCESS;
    1629             : }  /* pt_ConnectContinue */
    1630             : 
    1631             : PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
    1632             : {
    1633             :     /* Find the NSPR layer and invoke its connectcontinue method */
    1634           0 :     PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
    1635             : 
    1636           0 :     if (NULL == bottom)
    1637             :     {
    1638           0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1639           0 :         return PR_FAILURE;
    1640             :     }
    1641           0 :     return pt_ConnectContinue(bottom, pd->out_flags);
    1642             : }  /* PR_GetConnectStatus */
    1643             : 
    1644           0 : static PRFileDesc* pt_Accept(
    1645             :     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
    1646             : {
    1647           0 :     PRFileDesc *newfd = NULL;
    1648           0 :     PRIntn syserrno, osfd = -1;
    1649           0 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    1650             : #ifdef SYMBIAN
    1651             :     PRNetAddr dummy_addr;
    1652             : #endif
    1653             : 
    1654           0 :     if (pt_TestAbort()) return newfd;
    1655             : 
    1656             : #ifdef SYMBIAN
    1657             :     /* On Symbian OS, accept crashes if addr is NULL. */
    1658             :     if (!addr)
    1659             :         addr = &dummy_addr;
    1660             : #endif
    1661             : 
    1662             : #ifdef _PR_STRICT_ADDR_LEN
    1663             :     if (addr)
    1664             :     {
    1665             :         /*
    1666             :          * Set addr->raw.family just so that we can use the
    1667             :          * PR_NETADDR_SIZE macro.
    1668             :          */
    1669             :         addr->raw.family = fd->secret->af;
    1670             :         addr_len = PR_NETADDR_SIZE(addr);
    1671             :     }
    1672             : #endif
    1673             : 
    1674           0 :     osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
    1675           0 :     syserrno = errno;
    1676             : 
    1677           0 :     if (osfd == -1)
    1678             :     {
    1679           0 :         if (fd->secret->nonblocking) goto failed;
    1680             : 
    1681           0 :         if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
    1682           0 :         && ECONNABORTED != syserrno)
    1683             :             goto failed;
    1684             :         else
    1685             :         {
    1686           0 :             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    1687             :             else
    1688             :             {
    1689             :                 pt_Continuation op;
    1690           0 :                 op.arg1.osfd = fd->secret->md.osfd;
    1691           0 :                 op.arg2.buffer = addr;
    1692           0 :                 op.arg3.addr_len = &addr_len;
    1693           0 :                 op.timeout = timeout;
    1694           0 :                 op.function = pt_accept_cont;
    1695           0 :                 op.event = POLLIN | POLLPRI;
    1696           0 :                 osfd = pt_Continue(&op);
    1697           0 :                 syserrno = op.syserrno;
    1698             :             }
    1699           0 :             if (osfd < 0) goto failed;
    1700             :         }
    1701             :     }
    1702             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1703             :     /* ignore the sa_len field of struct sockaddr */
    1704             :     if (addr)
    1705             :     {
    1706             :         addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    1707             :     }
    1708             : #endif /* _PR_HAVE_SOCKADDR_LEN */
    1709             : #ifdef _PR_INET6
    1710           0 :         if (addr && (AF_INET6 == addr->raw.family))
    1711           0 :         addr->raw.family = PR_AF_INET6;
    1712             : #endif
    1713           0 :     newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
    1714           0 :     if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
    1715             :     else
    1716             :     {
    1717           0 :         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    1718           0 :         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
    1719             : #ifdef LINUX
    1720             :         /*
    1721             :          * On Linux, experiments showed that the accepted sockets
    1722             :          * inherit the TCP_NODELAY socket option of the listening
    1723             :          * socket.
    1724             :          */
    1725           0 :         newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
    1726             : #endif
    1727             :     }
    1728           0 :     return newfd;
    1729             : 
    1730             : failed:
    1731           0 :     pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
    1732           0 :     return NULL;
    1733             : }  /* pt_Accept */
    1734             : 
    1735           0 : static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
    1736             : {
    1737             :     PRIntn rv;
    1738             :     pt_SockLen addr_len;
    1739           0 :         const PRNetAddr *addrp = addr;
    1740             : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
    1741             :     PRNetAddr addrCopy;
    1742             : #endif
    1743             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1744             :     PRUint16 md_af = addr->raw.family;
    1745             : #endif
    1746             : 
    1747           0 :     if (pt_TestAbort()) return PR_FAILURE;
    1748             : 
    1749           0 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    1750           0 :     if (addr->raw.family == AF_UNIX)
    1751             :     {
    1752             :         /* Disallow relative pathnames */
    1753           0 :         if (addr->local.path[0] != '/')
    1754             :         {
    1755           0 :             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1756           0 :             return PR_FAILURE;
    1757             :         }
    1758             :     }
    1759             : 
    1760             : #ifdef _PR_INET6
    1761           0 :     if (addr->raw.family == PR_AF_INET6) {
    1762             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1763             :         md_af = AF_INET6;
    1764             : #else
    1765           0 :         addrCopy = *addr;
    1766           0 :         addrCopy.raw.family = AF_INET6;
    1767           0 :         addrp = &addrCopy;
    1768             : #endif
    1769             :     }
    1770             : #endif
    1771             : 
    1772           0 :     addr_len = PR_NETADDR_SIZE(addr);
    1773             : #ifdef _PR_HAVE_SOCKADDR_LEN
    1774             :     addrCopy = *addr;
    1775             :     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
    1776             :     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
    1777             :     addrp = &addrCopy;
    1778             : #endif
    1779           0 :     rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
    1780             : 
    1781           0 :     if (rv == -1) {
    1782           0 :         pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
    1783           0 :         return PR_FAILURE;
    1784             :     }
    1785           0 :     return PR_SUCCESS;
    1786             : }  /* pt_Bind */
    1787             : 
    1788           0 : static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
    1789             : {
    1790             :     PRIntn rv;
    1791             : 
    1792           0 :     if (pt_TestAbort()) return PR_FAILURE;
    1793             : 
    1794           0 :     rv = listen(fd->secret->md.osfd, backlog);
    1795           0 :     if (rv == -1) {
    1796           0 :         pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
    1797           0 :         return PR_FAILURE;
    1798             :     }
    1799           0 :     return PR_SUCCESS;
    1800             : }  /* pt_Listen */
    1801             : 
    1802           0 : static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
    1803             : {
    1804           0 :     PRIntn rv = -1;
    1805           0 :     if (pt_TestAbort()) return PR_FAILURE;
    1806             : 
    1807           0 :     rv = shutdown(fd->secret->md.osfd, how);
    1808             : 
    1809           0 :     if (rv == -1) {
    1810           0 :         pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
    1811           0 :         return PR_FAILURE;
    1812             :     }
    1813           0 :     return PR_SUCCESS;
    1814             : }  /* pt_Shutdown */
    1815             : 
    1816          81 : static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
    1817             : {
    1818          81 :     *out_flags = 0;
    1819          81 :     return in_flags;
    1820             : }  /* pt_Poll */
    1821             : 
    1822          16 : static PRInt32 pt_Recv(
    1823             :     PRFileDesc *fd, void *buf, PRInt32 amount,
    1824             :     PRIntn flags, PRIntervalTime timeout)
    1825             : {
    1826          16 :     PRInt32 syserrno, bytes = -1;
    1827             :     PRIntn osflags;
    1828             : 
    1829          16 :     if (0 == flags)
    1830          15 :         osflags = 0;
    1831           1 :     else if (PR_MSG_PEEK == flags)
    1832             :     {
    1833             : #ifdef SYMBIAN
    1834             :         /* MSG_PEEK doesn't work as expected. */
    1835             :         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    1836             :         return bytes;
    1837             : #else
    1838           1 :         osflags = MSG_PEEK;
    1839             : #endif
    1840             :     }
    1841             :     else
    1842             :     {
    1843           0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    1844           0 :         return bytes;
    1845             :     }
    1846             : 
    1847          16 :     if (pt_TestAbort()) return bytes;
    1848             : 
    1849             :     /* recv() is a much slower call on pre-2.6 Solaris than read(). */
    1850             : #if defined(SOLARIS)
    1851             :     if (0 == osflags)
    1852             :         bytes = read(fd->secret->md.osfd, buf, amount);
    1853             :     else
    1854             :         bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
    1855             : #else
    1856          16 :     bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
    1857             : #endif
    1858          16 :     syserrno = errno;
    1859             : 
    1860          16 :     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1861           3 :         && (!fd->secret->nonblocking))
    1862             :     {
    1863           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    1864             :         else
    1865             :         {
    1866             :             pt_Continuation op;
    1867           0 :             op.arg1.osfd = fd->secret->md.osfd;
    1868           0 :             op.arg2.buffer = buf;
    1869           0 :             op.arg3.amount = amount;
    1870           0 :             op.arg4.flags = osflags;
    1871           0 :             op.timeout = timeout;
    1872           0 :             op.function = pt_recv_cont;
    1873           0 :             op.event = POLLIN | POLLPRI;
    1874           0 :             bytes = pt_Continue(&op);
    1875           0 :             syserrno = op.syserrno;
    1876             :         }
    1877             :     }
    1878          16 :     if (bytes < 0)
    1879           3 :         pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
    1880          16 :     return bytes;
    1881             : }  /* pt_Recv */
    1882             : 
    1883           1 : static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
    1884             : {
    1885           1 :     return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    1886             : }  /* pt_SocketRead */
    1887             : 
    1888           3 : static PRInt32 pt_Send(
    1889             :     PRFileDesc *fd, const void *buf, PRInt32 amount,
    1890             :     PRIntn flags, PRIntervalTime timeout)
    1891             : {
    1892           3 :     PRInt32 syserrno, bytes = -1;
    1893           3 :     PRBool fNeedContinue = PR_FALSE;
    1894             : #if defined(SOLARIS)
    1895             :         PRInt32 tmp_amount = amount;
    1896             : #endif
    1897             : 
    1898             :     /*
    1899             :      * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
    1900             :      * which has the following:
    1901             :      *     #  define send        cma_send
    1902             :      *     extern int  cma_send (int , void *, int, int );
    1903             :      * So we need to cast away the 'const' of argument #2 for send().
    1904             :      */
    1905             : #if defined (HPUX) && defined(_PR_DCETHREADS)
    1906             : #define PT_SENDBUF_CAST (void *)
    1907             : #else
    1908             : #define PT_SENDBUF_CAST
    1909             : #endif
    1910             : 
    1911           3 :     if (pt_TestAbort()) return bytes;
    1912             : 
    1913             :     /*
    1914             :      * On pre-2.6 Solaris, send() is much slower than write().
    1915             :      * On 2.6 and beyond, with in-kernel sockets, send() and
    1916             :      * write() are fairly equivalent in performance.
    1917             :      */
    1918             : #if defined(SOLARIS)
    1919             :     PR_ASSERT(0 == flags);
    1920             : retry:
    1921             :     bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
    1922             : #else
    1923           3 :     bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
    1924             : #endif
    1925           3 :     syserrno = errno;
    1926             : 
    1927             : #if defined(SOLARIS)
    1928             :     /*
    1929             :      * The write system call has been reported to return the ERANGE error
    1930             :      * on occasion. Try to write in smaller chunks to workaround this bug.
    1931             :      */
    1932             :     if ((bytes == -1) && (syserrno == ERANGE))
    1933             :     {
    1934             :         if (tmp_amount > 1)
    1935             :         {
    1936             :             tmp_amount = tmp_amount/2;  /* half the bytes */
    1937             :             goto retry;
    1938             :         }
    1939             :     }
    1940             : #endif
    1941             : 
    1942           3 :     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
    1943             :     {
    1944           0 :         if (PR_INTERVAL_NO_WAIT == timeout)
    1945             :         {
    1946           0 :             bytes = -1;
    1947           0 :             syserrno = ETIMEDOUT;
    1948             :         }
    1949             :         else
    1950             :         {
    1951           0 :             buf = (char *) buf + bytes;
    1952           0 :             amount -= bytes;
    1953           0 :             fNeedContinue = PR_TRUE;
    1954             :         }
    1955             :     }
    1956           3 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1957           0 :         && (!fd->secret->nonblocking) )
    1958             :     {
    1959           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    1960             :         else
    1961             :         {
    1962           0 :             bytes = 0;
    1963           0 :             fNeedContinue = PR_TRUE;
    1964             :         }
    1965             :     }
    1966             : 
    1967           3 :     if (fNeedContinue == PR_TRUE)
    1968             :     {
    1969             :         pt_Continuation op;
    1970           0 :         op.arg1.osfd = fd->secret->md.osfd;
    1971           0 :         op.arg2.buffer = (void*)buf;
    1972           0 :         op.arg3.amount = amount;
    1973           0 :         op.arg4.flags = flags;
    1974           0 :         op.timeout = timeout;
    1975           0 :         op.result.code = bytes;  /* initialize the number sent */
    1976           0 :         op.function = pt_send_cont;
    1977           0 :         op.event = POLLOUT | POLLPRI;
    1978           0 :         bytes = pt_Continue(&op);
    1979           0 :         syserrno = op.syserrno;
    1980             :     }
    1981           3 :     if (bytes == -1)
    1982           0 :         pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
    1983           3 :     return bytes;
    1984             : }  /* pt_Send */
    1985             : 
    1986           1 : static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
    1987             : {
    1988           1 :     return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    1989             : }  /* pt_SocketWrite */
    1990             : 
    1991           0 : static PRInt32 pt_SendTo(
    1992             :     PRFileDesc *fd, const void *buf,
    1993             :     PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
    1994             :     PRIntervalTime timeout)
    1995             : {
    1996           0 :     PRInt32 syserrno, bytes = -1;
    1997           0 :     PRBool fNeedContinue = PR_FALSE;
    1998             :     pt_SockLen addr_len;
    1999           0 :         const PRNetAddr *addrp = addr;
    2000             : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
    2001             :     PRNetAddr addrCopy;
    2002             : #endif
    2003             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2004             :     PRUint16 md_af = addr->raw.family;
    2005             : #endif
    2006             : 
    2007           0 :     if (pt_TestAbort()) return bytes;
    2008             : 
    2009           0 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    2010             : #ifdef _PR_INET6
    2011           0 :     if (addr->raw.family == PR_AF_INET6) {
    2012             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2013             :         md_af = AF_INET6;
    2014             : #else
    2015           0 :         addrCopy = *addr;
    2016           0 :         addrCopy.raw.family = AF_INET6;
    2017           0 :         addrp = &addrCopy;
    2018             : #endif
    2019             :     }
    2020             : #endif
    2021             : 
    2022           0 :     addr_len = PR_NETADDR_SIZE(addr);
    2023             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2024             :     addrCopy = *addr;
    2025             :     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
    2026             :     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
    2027             :     addrp = &addrCopy;
    2028             : #endif
    2029           0 :     bytes = sendto(
    2030           0 :         fd->secret->md.osfd, buf, amount, flags,
    2031             :         (struct sockaddr*)addrp, addr_len);
    2032           0 :     syserrno = errno;
    2033           0 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    2034           0 :         && (!fd->secret->nonblocking) )
    2035             :     {
    2036           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    2037           0 :         else fNeedContinue = PR_TRUE;
    2038             :     }
    2039           0 :     if (fNeedContinue == PR_TRUE)
    2040             :     {
    2041             :         pt_Continuation op;
    2042           0 :         op.arg1.osfd = fd->secret->md.osfd;
    2043           0 :         op.arg2.buffer = (void*)buf;
    2044           0 :         op.arg3.amount = amount;
    2045           0 :         op.arg4.flags = flags;
    2046           0 :         op.arg5.addr = (PRNetAddr*)addrp;
    2047           0 :         op.timeout = timeout;
    2048           0 :         op.result.code = 0;  /* initialize the number sent */
    2049           0 :         op.function = pt_sendto_cont;
    2050           0 :         op.event = POLLOUT | POLLPRI;
    2051           0 :         bytes = pt_Continue(&op);
    2052           0 :         syserrno = op.syserrno;
    2053             :     }
    2054           0 :     if (bytes < 0)
    2055           0 :         pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
    2056           0 :     return bytes;
    2057             : }  /* pt_SendTo */
    2058             : 
    2059             : #if defined(LINUX) || defined(DARWIN)
    2060             : /* Linux uses SendTo to send data during TCP Fast Open. OSX uses connectx, but
    2061             :  * we will make it imitate the Linux's interface. */
    2062           2 : static PRInt32 pt_TCP_SendTo(
    2063             :     PRFileDesc *fd, const void *buf,
    2064             :     PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
    2065             :     PRIntervalTime timeout)
    2066             : {
    2067             : #if defined(LINUX) || HAS_CONNECTX
    2068           2 :     PRInt32 syserrno, bytes = -1;
    2069           2 :     PRBool fNeedContinue = PR_FALSE;
    2070             :     pt_SockLen addr_len;
    2071           2 :     const PRNetAddr *addrp = addr;
    2072             : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
    2073             :     PRNetAddr addrCopy;
    2074             : #endif
    2075             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2076             :     PRUint16 md_af = addr->raw.family;
    2077             : #endif
    2078             : 
    2079           2 :     if (pt_TestAbort()) return bytes;
    2080             : 
    2081           2 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    2082           2 :     addr_len = PR_NETADDR_SIZE(addr);
    2083             : #if defined(_PR_INET6)
    2084           2 :     if (addr->raw.family == PR_AF_INET6) {
    2085             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2086             :         md_af = AF_INET6;
    2087             : #else
    2088             :         /* If _PR_INET6 is defined and it is PR_AF_INET6 we set family
    2089             :          * to AF_INET6. */
    2090           0 :         addrCopy = *addr;
    2091           0 :         addrCopy.raw.family = AF_INET6;
    2092           0 :         addrp = &addrCopy;
    2093             : #endif
    2094             :     }
    2095             : #endif
    2096             : 
    2097             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2098             :     /* if _PR_HAVE_SOCKADDR_LEN is defined and it is PR_AF_INET6 we set family
    2099             :      * to AF_INET6 and we set address length. */
    2100             :     addrCopy = *addr;
    2101             :     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
    2102             :     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
    2103             :     addrp = &addrCopy;
    2104             : #endif
    2105             : 
    2106             : #ifndef HAS_CONNECTX
    2107           4 :     bytes = sendto(
    2108           2 :         fd->secret->md.osfd, buf, amount, MSG_FASTOPEN,
    2109             :         (struct sockaddr*)addrp, addr_len);
    2110             : #else
    2111             :     sa_endpoints_t endpoints;
    2112             :     endpoints.sae_srcif = 0;
    2113             :     endpoints.sae_srcaddr = NULL;
    2114             :     endpoints.sae_srcaddrlen = 0;
    2115             :     endpoints.sae_dstaddr = (struct sockaddr *)addrp;
    2116             :     endpoints.sae_dstaddrlen = addr_len;
    2117             :     struct iovec iov[1];
    2118             :     iov[0].iov_base = buf;
    2119             :     iov[0].iov_len = amount;
    2120             :     PRInt32 rv = connectx(fd->secret->md.osfd, &endpoints, SAE_ASSOCID_ANY,
    2121             :                          CONNECT_DATA_IDEMPOTENT, iov, 1, &bytes, NULL);
    2122             : #endif
    2123           2 :     syserrno = errno;
    2124           2 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    2125           0 :         && (!fd->secret->nonblocking) ) {
    2126           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    2127           0 :         else fNeedContinue = PR_TRUE;
    2128             :     }
    2129           2 :     if (fNeedContinue == PR_TRUE) {
    2130             :         pt_Continuation op;
    2131           0 :         op.arg1.osfd = fd->secret->md.osfd;
    2132           0 :         op.arg2.buffer = (void*)buf;
    2133           0 :         op.arg3.amount = amount;
    2134           0 :         op.arg4.flags = flags;
    2135           0 :         op.arg5.addr = (PRNetAddr*)addrp;
    2136           0 :         op.timeout = timeout;
    2137           0 :         op.result.code = 0;  /* initialize the number sent */
    2138           0 :         op.function = pt_sendto_cont;
    2139           0 :         op.event = POLLOUT | POLLPRI;
    2140           0 :         bytes = pt_Continue(&op);
    2141           0 :         syserrno = op.syserrno;
    2142             :     }
    2143           2 :     if (bytes < 0) {
    2144           2 :         pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
    2145             :     }
    2146           2 :     return bytes;
    2147             : #else /* !HAS_CONNECTX */
    2148             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    2149             :     return -1;
    2150             : #endif
    2151             : }  /* pt_TCP_SendTo */
    2152             : #endif /* LINUX || DARWIN */
    2153             : 
    2154           0 : static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
    2155             :     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
    2156             : {
    2157           0 :     PRBool fNeedContinue = PR_FALSE;
    2158           0 :     PRInt32 syserrno, bytes = -1;
    2159           0 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    2160             : 
    2161           0 :     if (pt_TestAbort()) return bytes;
    2162             : 
    2163           0 :     bytes = recvfrom(
    2164           0 :         fd->secret->md.osfd, buf, amount, flags,
    2165             :         (struct sockaddr*)addr, &addr_len);
    2166           0 :     syserrno = errno;
    2167             : 
    2168           0 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    2169           0 :         && (!fd->secret->nonblocking) )
    2170             :     {
    2171           0 :         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
    2172           0 :         else fNeedContinue = PR_TRUE;
    2173             :     }
    2174             : 
    2175           0 :     if (fNeedContinue == PR_TRUE)
    2176             :     {
    2177             :         pt_Continuation op;
    2178           0 :         op.arg1.osfd = fd->secret->md.osfd;
    2179           0 :         op.arg2.buffer = buf;
    2180           0 :         op.arg3.amount = amount;
    2181           0 :         op.arg4.flags = flags;
    2182           0 :         op.arg5.addr = addr;
    2183           0 :         op.timeout = timeout;
    2184           0 :         op.function = pt_recvfrom_cont;
    2185           0 :         op.event = POLLIN | POLLPRI;
    2186           0 :         bytes = pt_Continue(&op);
    2187           0 :         syserrno = op.syserrno;
    2188             :     }
    2189           0 :     if (bytes >= 0)
    2190             :     {
    2191             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2192             :         /* ignore the sa_len field of struct sockaddr */
    2193             :         if (addr)
    2194             :         {
    2195             :             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    2196             :         }
    2197             : #endif /* _PR_HAVE_SOCKADDR_LEN */
    2198             : #ifdef _PR_INET6
    2199           0 :         if (addr && (AF_INET6 == addr->raw.family))
    2200           0 :             addr->raw.family = PR_AF_INET6;
    2201             : #endif
    2202             :     }
    2203             :     else
    2204           0 :         pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
    2205           0 :     return bytes;
    2206             : }  /* pt_RecvFrom */
    2207             : 
    2208             : #ifdef AIX
    2209             : #ifndef HAVE_SEND_FILE
    2210             : static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
    2211             : 
    2212             : static void pt_aix_sendfile_init_routine(void)
    2213             : {
    2214             :     void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
    2215             :     pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
    2216             :     dlclose(handle);
    2217             : }
    2218             : 
    2219             : /* 
    2220             :  * pt_AIXDispatchSendFile
    2221             :  */
    2222             : static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
    2223             :           PRTransmitFileFlags flags, PRIntervalTime timeout)
    2224             : {
    2225             :     int rv;
    2226             : 
    2227             :     rv = pthread_once(&pt_aix_sendfile_once_block,
    2228             :             pt_aix_sendfile_init_routine);
    2229             :     PR_ASSERT(0 == rv);
    2230             :     if (pt_aix_sendfile_fptr) {
    2231             :         return pt_AIXSendFile(sd, sfd, flags, timeout);
    2232             :     } else {
    2233             :         return PR_EmulateSendFile(sd, sfd, flags, timeout);
    2234             :     }
    2235             : }
    2236             : #endif /* !HAVE_SEND_FILE */
    2237             : 
    2238             : 
    2239             : /*
    2240             :  * pt_AIXSendFile
    2241             :  *
    2242             :  *    Send file sfd->fd across socket sd. If specified, header and trailer
    2243             :  *    buffers are sent before and after the file, respectively. 
    2244             :  *
    2245             :  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
    2246             :  *    
    2247             :  *    return number of bytes sent or -1 on error
    2248             :  *
    2249             :  *      This implementation takes advantage of the send_file() system
    2250             :  *      call available in AIX 4.3.2.
    2251             :  */
    2252             : 
    2253             : static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
    2254             :                 PRTransmitFileFlags flags, PRIntervalTime timeout)
    2255             : {
    2256             :     struct sf_parms sf_struct;
    2257             :     uint_t send_flags;
    2258             :     ssize_t rv;
    2259             :     int syserrno;
    2260             :     PRInt32 count;
    2261             :         unsigned long long saved_file_offset;
    2262             :         long long saved_file_bytes;
    2263             : 
    2264             :     sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
    2265             :     sf_struct.header_length = sfd->hlen;
    2266             :     sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
    2267             :     sf_struct.file_size = 0;
    2268             :     sf_struct.file_offset = sfd->file_offset;
    2269             :     if (sfd->file_nbytes == 0)
    2270             :         sf_struct.file_bytes = -1;
    2271             :         else
    2272             :         sf_struct.file_bytes = sfd->file_nbytes;
    2273             :     sf_struct.trailer_data = (void *) sfd->trailer;
    2274             :     sf_struct.trailer_length = sfd->tlen;
    2275             :     sf_struct.bytes_sent = 0;
    2276             : 
    2277             :         saved_file_offset = sf_struct.file_offset;
    2278             :     saved_file_bytes = sf_struct.file_bytes;
    2279             : 
    2280             :     send_flags = 0;                     /* flags processed at the end */
    2281             : 
    2282             :     /* The first argument to send_file() is int*. */
    2283             :     PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
    2284             :     do {
    2285             :         rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
    2286             :     } while (rv == -1 && (syserrno = errno) == EINTR);
    2287             : 
    2288             :     if (rv == -1) {
    2289             :         if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
    2290             :             count = 0; /* Not a real error.  Need to continue. */
    2291             :         } else {
    2292             :             count = -1;
    2293             :         }
    2294             :     } else {
    2295             :         count = sf_struct.bytes_sent;
    2296             :                 /*
    2297             :                  * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
    2298             :                  * being updated. So, 'file_bytes' is maintained by NSPR to
    2299             :                  * avoid conflict when this bug is fixed in AIX, in the future.
    2300             :                  */
    2301             :                 if (saved_file_bytes != -1)
    2302             :                         saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
    2303             :                 sf_struct.file_bytes = saved_file_bytes;
    2304             :     }
    2305             : 
    2306             :     if ((rv == 1) || ((rv == -1) && (count == 0))) {
    2307             :         pt_Continuation op;
    2308             : 
    2309             :         op.arg1.osfd = sd->secret->md.osfd;
    2310             :         op.arg2.buffer = &sf_struct;
    2311             :         op.arg4.flags = send_flags;
    2312             :         op.result.code = count;
    2313             :         op.timeout = timeout;
    2314             :         op.function = pt_aix_sendfile_cont;
    2315             :         op.event = POLLOUT | POLLPRI;
    2316             :         count = pt_Continue(&op);
    2317             :         syserrno = op.syserrno;
    2318             :     }
    2319             : 
    2320             :     if (count == -1) {
    2321             :         pt_MapError(_MD_aix_map_sendfile_error, syserrno);
    2322             :         return -1;
    2323             :     }
    2324             :     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
    2325             :         PR_Close(sd);
    2326             :     }
    2327             :         PR_ASSERT(count == (sfd->hlen + sfd->tlen +
    2328             :                                                 ((sfd->file_nbytes ==  0) ?
    2329             :                                                 sf_struct.file_size - sfd->file_offset :
    2330             :                                                 sfd->file_nbytes)));
    2331             :     return count;
    2332             : }
    2333             : #endif /* AIX */
    2334             : 
    2335             : #ifdef HPUX11
    2336             : /*
    2337             :  * pt_HPUXSendFile
    2338             :  *
    2339             :  *    Send file sfd->fd across socket sd. If specified, header and trailer
    2340             :  *    buffers are sent before and after the file, respectively.
    2341             :  *
    2342             :  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
    2343             :  *    
    2344             :  *    return number of bytes sent or -1 on error
    2345             :  *
    2346             :  *      This implementation takes advantage of the sendfile() system
    2347             :  *      call available in HP-UX B.11.00.
    2348             :  */
    2349             : 
    2350             : static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
    2351             :                 PRTransmitFileFlags flags, PRIntervalTime timeout)
    2352             : {
    2353             :     struct stat statbuf;
    2354             :     size_t nbytes_to_send, file_nbytes_to_send;
    2355             :     struct iovec hdtrl[2];  /* optional header and trailer buffers */
    2356             :     int send_flags;
    2357             :     PRInt32 count;
    2358             :     int syserrno;
    2359             : 
    2360             :     if (sfd->file_nbytes == 0) {
    2361             :         /* Get file size */
    2362             :         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
    2363             :             _PR_MD_MAP_FSTAT_ERROR(errno);
    2364             :             return -1;
    2365             :         }               
    2366             :         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
    2367             :     } else {
    2368             :         file_nbytes_to_send = sfd->file_nbytes;
    2369             :     }
    2370             :     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
    2371             : 
    2372             :     hdtrl[0].iov_base = (void *) sfd->header;  /* cast away the 'const' */
    2373             :     hdtrl[0].iov_len = sfd->hlen;
    2374             :     hdtrl[1].iov_base = (void *) sfd->trailer;
    2375             :     hdtrl[1].iov_len = sfd->tlen;
    2376             :     /*
    2377             :      * SF_DISCONNECT seems to close the socket even if sendfile()
    2378             :      * only does a partial send on a nonblocking socket.  This
    2379             :      * would prevent the subsequent sendfile() calls on that socket
    2380             :      * from working.  So we don't use the SD_DISCONNECT flag.
    2381             :      */
    2382             :     send_flags = 0;
    2383             : 
    2384             :     do {
    2385             :         count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
    2386             :                 sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
    2387             :     } while (count == -1 && (syserrno = errno) == EINTR);
    2388             : 
    2389             :     if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
    2390             :         count = 0;
    2391             :     }
    2392             :     if (count != -1 && count < nbytes_to_send) {
    2393             :         pt_Continuation op;
    2394             : 
    2395             :         if (count < sfd->hlen) {
    2396             :                         /* header not sent */
    2397             : 
    2398             :             hdtrl[0].iov_base = ((char *) sfd->header) + count;
    2399             :             hdtrl[0].iov_len = sfd->hlen - count;
    2400             :             op.arg3.file_spec.offset = sfd->file_offset;
    2401             :             op.arg3.file_spec.nbytes = file_nbytes_to_send;
    2402             :         } else if (count < (sfd->hlen + file_nbytes_to_send)) {
    2403             :                         /* header sent, file not sent */
    2404             : 
    2405             :             hdtrl[0].iov_base = NULL;
    2406             :             hdtrl[0].iov_len = 0;
    2407             : 
    2408             :             op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
    2409             :             op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
    2410             :         } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
    2411             :                         PRUint32 trailer_nbytes_sent;
    2412             : 
    2413             :                         /* header sent, file sent, trailer not sent */
    2414             : 
    2415             :             hdtrl[0].iov_base = NULL;
    2416             :             hdtrl[0].iov_len = 0;
    2417             :                         /*
    2418             :                          * set file offset and len so that no more file data is
    2419             :                          * sent
    2420             :                          */
    2421             :             op.arg3.file_spec.offset = statbuf.st_size;
    2422             :             op.arg3.file_spec.nbytes = 0;
    2423             : 
    2424             :                         trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
    2425             :             hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
    2426             :             hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
    2427             :                 }
    2428             : 
    2429             :         op.arg1.osfd = sd->secret->md.osfd;
    2430             :         op.filedesc = sfd->fd->secret->md.osfd;
    2431             :         op.arg2.buffer = hdtrl;
    2432             :         op.arg3.file_spec.st_size = statbuf.st_size;
    2433             :         op.arg4.flags = send_flags;
    2434             :         op.nbytes_to_send = nbytes_to_send - count;
    2435             :         op.result.code = count;
    2436             :         op.timeout = timeout;
    2437             :         op.function = pt_hpux_sendfile_cont;
    2438             :         op.event = POLLOUT | POLLPRI;
    2439             :         count = pt_Continue(&op);
    2440             :         syserrno = op.syserrno;
    2441             :     }
    2442             : 
    2443             :     if (count == -1) {
    2444             :         pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
    2445             :         return -1;
    2446             :     }
    2447             :     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
    2448             :         PR_Close(sd);
    2449             :     }
    2450             :     PR_ASSERT(count == nbytes_to_send);
    2451             :     return count;
    2452             : }
    2453             : 
    2454             : #endif  /* HPUX11 */
    2455             : 
    2456             : #ifdef SOLARIS 
    2457             : 
    2458             : /*
    2459             :  *    pt_SolarisSendFile
    2460             :  *
    2461             :  *    Send file sfd->fd across socket sd. If specified, header and trailer
    2462             :  *    buffers are sent before and after the file, respectively.
    2463             :  *
    2464             :  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
    2465             :  *
    2466             :  *    return number of bytes sent or -1 on error
    2467             :  *
    2468             :  *    This implementation takes advantage of the sendfilev() system
    2469             :  *    call available in Solaris 8.
    2470             :  */
    2471             : 
    2472             : static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
    2473             :                 PRTransmitFileFlags flags, PRIntervalTime timeout)
    2474             : {
    2475             :     struct stat statbuf;
    2476             :     size_t nbytes_to_send, file_nbytes_to_send; 
    2477             :     struct sendfilevec sfv_struct[3];  
    2478             :     int sfvcnt = 0;     
    2479             :     size_t xferred;
    2480             :     PRInt32 count;
    2481             :     int syserrno;
    2482             : 
    2483             :     if (sfd->file_nbytes == 0) {
    2484             :         /* Get file size */
    2485             :         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
    2486             :             _PR_MD_MAP_FSTAT_ERROR(errno);
    2487             :             return -1;
    2488             :         }               
    2489             :         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
    2490             :     } else {
    2491             :         file_nbytes_to_send = sfd->file_nbytes;
    2492             :     }
    2493             : 
    2494             :     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
    2495             : 
    2496             :     if (sfd->hlen != 0) {
    2497             :         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
    2498             :         sfv_struct[sfvcnt].sfv_flag = 0;
    2499             :         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; 
    2500             :         sfv_struct[sfvcnt].sfv_len = sfd->hlen;
    2501             :         sfvcnt++;
    2502             :     }
    2503             : 
    2504             :     if (file_nbytes_to_send != 0) {
    2505             :         sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
    2506             :         sfv_struct[sfvcnt].sfv_flag = 0;
    2507             :         sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
    2508             :         sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
    2509             :         sfvcnt++;
    2510             :     }
    2511             : 
    2512             :     if (sfd->tlen != 0) {
    2513             :         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
    2514             :         sfv_struct[sfvcnt].sfv_flag = 0;
    2515             :         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; 
    2516             :         sfv_struct[sfvcnt].sfv_len = sfd->tlen;
    2517             :         sfvcnt++;
    2518             :     }
    2519             : 
    2520             :     if (0 == sfvcnt) {
    2521             :         count = 0;
    2522             :         goto done;
    2523             :     }
    2524             :            
    2525             :     /*
    2526             :      * Strictly speaking, we may have sent some bytes when the
    2527             :      * sendfilev() is interrupted and we should retry it from an
    2528             :      * updated offset.  We are not doing that here.
    2529             :      */
    2530             :     count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
    2531             :             sfvcnt, &xferred);
    2532             : 
    2533             :     PR_ASSERT((count == -1) || (count == xferred));
    2534             : 
    2535             :     if (count == -1) {
    2536             :         syserrno = errno;
    2537             :         if (syserrno == EINTR
    2538             :                 || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
    2539             :             count = xferred;
    2540             :         }
    2541             :     } else if (count == 0) {
    2542             :         /*
    2543             :          * We are now at EOF. The file was truncated. Solaris sendfile is
    2544             :          * supposed to return 0 and no error in this case, though some versions
    2545             :          * may return -1 and EINVAL .
    2546             :          */
    2547             :         count = -1;
    2548             :         syserrno = 0;  /* will be treated as EOF */
    2549             :     }
    2550             : 
    2551             :     if (count != -1 && count < nbytes_to_send) {
    2552             :         pt_Continuation op;
    2553             :         struct sendfilevec *vec = sfv_struct;
    2554             :         PRInt32 rem = count;
    2555             : 
    2556             :         while (rem >= vec->sfv_len) {
    2557             :             rem -= vec->sfv_len;
    2558             :             vec++;
    2559             :             sfvcnt--;
    2560             :         }
    2561             :         PR_ASSERT(sfvcnt > 0);
    2562             : 
    2563             :         vec->sfv_off += rem;
    2564             :         vec->sfv_len -= rem;
    2565             :         PR_ASSERT(vec->sfv_len > 0);
    2566             : 
    2567             :         op.arg1.osfd = sd->secret->md.osfd;
    2568             :         op.arg2.buffer = vec;
    2569             :         op.arg3.amount = sfvcnt;
    2570             :         op.arg4.flags = 0;
    2571             :         op.nbytes_to_send = nbytes_to_send - count;
    2572             :         op.result.code = count;
    2573             :         op.timeout = timeout;
    2574             :         op.function = pt_solaris_sendfile_cont;
    2575             :         op.event = POLLOUT | POLLPRI;
    2576             :         count = pt_Continue(&op);
    2577             :         syserrno = op.syserrno;
    2578             :     }
    2579             : 
    2580             : done:
    2581             :     if (count == -1) {
    2582             :         pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
    2583             :         return -1;
    2584             :     }
    2585             :     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
    2586             :         PR_Close(sd);
    2587             :     }
    2588             :     PR_ASSERT(count == nbytes_to_send);
    2589             :     return count;
    2590             : }
    2591             : 
    2592             : #ifndef HAVE_SENDFILEV
    2593             : static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
    2594             : 
    2595             : static void pt_solaris_sendfilev_init_routine(void)
    2596             : {
    2597             :     void *handle;
    2598             :     PRBool close_it = PR_FALSE;
    2599             :  
    2600             :     /*
    2601             :      * We do not want to unload libsendfile.so.  This handle is leaked
    2602             :      * intentionally.
    2603             :      */
    2604             :     handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
    2605             :     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
    2606             :         ("dlopen(libsendfile.so) returns %p", handle));
    2607             : 
    2608             :     if (NULL == handle) {
    2609             :         /*
    2610             :          * The dlopen(0, mode) call is to allow for the possibility that
    2611             :          * sendfilev() may become part of a standard system library in a
    2612             :          * future Solaris release.
    2613             :          */
    2614             :         handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
    2615             :         PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
    2616             :             ("dlopen(0) returns %p", handle));
    2617             :         close_it = PR_TRUE;
    2618             :     }
    2619             :     pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
    2620             :     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
    2621             :         ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
    2622             :     
    2623             :     if (close_it) {
    2624             :         dlclose(handle);
    2625             :     }
    2626             : }
    2627             : 
    2628             : /* 
    2629             :  * pt_SolarisDispatchSendFile
    2630             :  */
    2631             : static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
    2632             :           PRTransmitFileFlags flags, PRIntervalTime timeout)
    2633             : {
    2634             :     int rv;
    2635             : 
    2636             :     rv = pthread_once(&pt_solaris_sendfilev_once_block,
    2637             :             pt_solaris_sendfilev_init_routine);
    2638             :     PR_ASSERT(0 == rv);
    2639             :     if (pt_solaris_sendfilev_fptr) {
    2640             :         return pt_SolarisSendFile(sd, sfd, flags, timeout);
    2641             :     } else {
    2642             :         return PR_EmulateSendFile(sd, sfd, flags, timeout);
    2643             :     }
    2644             : }
    2645             : #endif /* !HAVE_SENDFILEV */
    2646             : 
    2647             : #endif  /* SOLARIS */
    2648             : 
    2649             : #ifdef LINUX
    2650             : /*
    2651             :  * pt_LinuxSendFile
    2652             :  *
    2653             :  *    Send file sfd->fd across socket sd. If specified, header and trailer
    2654             :  *    buffers are sent before and after the file, respectively.
    2655             :  *
    2656             :  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
    2657             :  *    
    2658             :  *    return number of bytes sent or -1 on error
    2659             :  *
    2660             :  *      This implementation takes advantage of the sendfile() system
    2661             :  *      call available in Linux kernel 2.2 or higher.
    2662             :  */
    2663             : 
    2664           0 : static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
    2665             :                 PRTransmitFileFlags flags, PRIntervalTime timeout)
    2666             : {
    2667             :     struct stat statbuf;
    2668             :     size_t file_nbytes_to_send; 
    2669           0 :     PRInt32 count = 0;
    2670             :     ssize_t rv;
    2671             :     int syserrno;
    2672             :     off_t offset;
    2673           0 :     PRBool tcp_cork_enabled = PR_FALSE;
    2674             :     int tcp_cork;
    2675             : 
    2676           0 :     if (sfd->file_nbytes == 0) {
    2677             :         /* Get file size */
    2678           0 :         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
    2679           0 :             _PR_MD_MAP_FSTAT_ERROR(errno);
    2680           0 :             return -1;
    2681             :         }               
    2682           0 :         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
    2683             :     } else {
    2684           0 :         file_nbytes_to_send = sfd->file_nbytes;
    2685             :     }
    2686             : 
    2687           0 :     if ((sfd->hlen != 0 || sfd->tlen != 0)
    2688           0 :             && sd->secret->md.tcp_nodelay == 0) {
    2689           0 :         tcp_cork = 1;
    2690           0 :         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
    2691             :                 &tcp_cork, sizeof tcp_cork) == 0) {
    2692           0 :             tcp_cork_enabled = PR_TRUE;
    2693             :         } else {
    2694           0 :             syserrno = errno;
    2695           0 :             if (syserrno != EINVAL) {
    2696           0 :                 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
    2697           0 :                 return -1;
    2698             :             }
    2699             :             /*
    2700             :              * The most likely reason for the EINVAL error is that
    2701             :              * TCP_NODELAY is set (with a function other than
    2702             :              * PR_SetSocketOption).  This is not fatal, so we keep
    2703             :              * on going.
    2704             :              */
    2705           0 :             PR_LOG(_pr_io_lm, PR_LOG_WARNING,
    2706             :                 ("pt_LinuxSendFile: "
    2707             :                 "setsockopt(TCP_CORK) failed with EINVAL\n"));
    2708             :         }
    2709             :     }
    2710             : 
    2711           0 :     if (sfd->hlen != 0) {
    2712           0 :         count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
    2713           0 :         if (count == -1) {
    2714           0 :             goto failed;
    2715             :         }
    2716             :     }
    2717             : 
    2718           0 :     if (file_nbytes_to_send != 0) {
    2719           0 :         offset = sfd->file_offset;
    2720             :         do {
    2721           0 :             rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
    2722             :                 &offset, file_nbytes_to_send);
    2723           0 :         } while (rv == -1 && (syserrno = errno) == EINTR);
    2724           0 :         if (rv == -1) {
    2725           0 :             if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
    2726           0 :                 _MD_linux_map_sendfile_error(syserrno);
    2727           0 :                 count = -1;
    2728           0 :                 goto failed;
    2729             :             }
    2730           0 :             rv = 0;
    2731             :         }
    2732           0 :         PR_ASSERT(rv == offset - sfd->file_offset);
    2733           0 :         count += rv;
    2734             : 
    2735           0 :         if (rv < file_nbytes_to_send) {
    2736             :             pt_Continuation op;
    2737             : 
    2738           0 :             op.arg1.osfd = sd->secret->md.osfd;
    2739           0 :             op.in_fd = sfd->fd->secret->md.osfd;
    2740           0 :             op.offset = offset;
    2741           0 :             op.count = file_nbytes_to_send - rv;
    2742           0 :             op.result.code = count;
    2743           0 :             op.timeout = timeout;
    2744           0 :             op.function = pt_linux_sendfile_cont;
    2745           0 :             op.event = POLLOUT | POLLPRI;
    2746           0 :             count = pt_Continue(&op);
    2747           0 :             syserrno = op.syserrno;
    2748           0 :             if (count == -1) {
    2749           0 :                 pt_MapError(_MD_linux_map_sendfile_error, syserrno);
    2750           0 :                 goto failed;
    2751             :             }
    2752             :         }
    2753             :     }
    2754             : 
    2755           0 :     if (sfd->tlen != 0) {
    2756           0 :         rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
    2757           0 :         if (rv == -1) {
    2758           0 :             count = -1;
    2759           0 :             goto failed;
    2760             :         }
    2761           0 :         count += rv;
    2762             :     }
    2763             : 
    2764             : failed:
    2765           0 :     if (tcp_cork_enabled) {
    2766           0 :         tcp_cork = 0;
    2767           0 :         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
    2768           0 :                 &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
    2769           0 :             _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
    2770           0 :             count = -1;
    2771             :         }
    2772             :     }
    2773           0 :     if (count != -1) {
    2774           0 :         if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
    2775           0 :             PR_Close(sd);
    2776             :         }
    2777           0 :         PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
    2778             :     }
    2779           0 :     return count;
    2780             : }
    2781             : #endif  /* LINUX */
    2782             : 
    2783             : #ifdef AIX
    2784             : extern  int _pr_aix_send_file_use_disabled;
    2785             : #endif
    2786             : 
    2787           0 : static PRInt32 pt_SendFile(
    2788             :     PRFileDesc *sd, PRSendFileData *sfd,
    2789             :     PRTransmitFileFlags flags, PRIntervalTime timeout)
    2790             : {
    2791           0 :     if (pt_TestAbort()) return -1;
    2792             :     /* The socket must be in blocking mode. */
    2793           0 :     if (sd->secret->nonblocking)
    2794             :     {
    2795           0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2796           0 :         return -1;
    2797             :     }
    2798             : #ifdef HPUX11
    2799             :     return(pt_HPUXSendFile(sd, sfd, flags, timeout));
    2800             : #elif defined(AIX)
    2801             : #ifdef HAVE_SEND_FILE
    2802             :         /*
    2803             :          * A bug in AIX 4.3.2 results in corruption of data transferred by
    2804             :          * send_file(); AIX patch PTF U463956 contains the fix.  A user can
    2805             :          * disable the use of send_file function in NSPR, when this patch is
    2806             :          * not installed on the system, by setting the envionment variable
    2807             :          * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
    2808             :          */
    2809             :         if (_pr_aix_send_file_use_disabled)
    2810             :                 return(PR_EmulateSendFile(sd, sfd, flags, timeout));
    2811             :         else
    2812             :         return(pt_AIXSendFile(sd, sfd, flags, timeout));
    2813             : #else
    2814             :         return(PR_EmulateSendFile(sd, sfd, flags, timeout));
    2815             :     /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
    2816             : #endif /* HAVE_SEND_FILE */
    2817             : #elif defined(SOLARIS)
    2818             : #ifdef HAVE_SENDFILEV
    2819             :         return(pt_SolarisSendFile(sd, sfd, flags, timeout));
    2820             : #else
    2821             :         return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
    2822             : #endif /* HAVE_SENDFILEV */
    2823             : #elif defined(LINUX)
    2824           0 :         return(pt_LinuxSendFile(sd, sfd, flags, timeout));
    2825             : #else
    2826             :         return(PR_EmulateSendFile(sd, sfd, flags, timeout));
    2827             : #endif
    2828             : }
    2829             : 
    2830           0 : static PRInt32 pt_TransmitFile(
    2831             :     PRFileDesc *sd, PRFileDesc *fd, const void *headers,
    2832             :     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
    2833             : {
    2834             :         PRSendFileData sfd;
    2835             : 
    2836           0 :         sfd.fd = fd;
    2837           0 :         sfd.file_offset = 0;
    2838           0 :         sfd.file_nbytes = 0;
    2839           0 :         sfd.header = headers;
    2840           0 :         sfd.hlen = hlen;
    2841           0 :         sfd.trailer = NULL;
    2842           0 :         sfd.tlen = 0;
    2843             : 
    2844           0 :         return(pt_SendFile(sd, &sfd, flags, timeout));
    2845             : }  /* pt_TransmitFile */
    2846             : 
    2847           0 : static PRInt32 pt_AcceptRead(
    2848             :     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
    2849             :     void *buf, PRInt32 amount, PRIntervalTime timeout)
    2850             : {
    2851           0 :     PRInt32 rv = -1;
    2852             : 
    2853           0 :     if (pt_TestAbort()) return rv;
    2854             :     /* The socket must be in blocking mode. */
    2855           0 :     if (sd->secret->nonblocking)
    2856             :     {
    2857           0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    2858           0 :         return rv;
    2859             :     }
    2860             : 
    2861           0 :     rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
    2862           0 :     return rv;
    2863             : }  /* pt_AcceptRead */
    2864             : 
    2865           3 : static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
    2866             : {
    2867           3 :     PRIntn rv = -1;
    2868           3 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    2869             : 
    2870           3 :     if (pt_TestAbort()) return PR_FAILURE;
    2871             : 
    2872           6 :     rv = getsockname(
    2873           3 :         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
    2874           3 :     if (rv == -1) {
    2875           0 :         pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
    2876           0 :         return PR_FAILURE;
    2877             :     }
    2878             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2879             :     /* ignore the sa_len field of struct sockaddr */
    2880             :     if (addr)
    2881             :     {
    2882             :         addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    2883             :     }
    2884             : #endif /* _PR_HAVE_SOCKADDR_LEN */
    2885             : #ifdef _PR_INET6
    2886           3 :     if (AF_INET6 == addr->raw.family)
    2887           0 :         addr->raw.family = PR_AF_INET6;
    2888             : #endif
    2889           3 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    2890           3 :     PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
    2891           3 :     return PR_SUCCESS;
    2892             : }  /* pt_GetSockName */
    2893             : 
    2894           0 : static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
    2895             : {
    2896           0 :     PRIntn rv = -1;
    2897           0 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    2898             : 
    2899           0 :     if (pt_TestAbort()) return PR_FAILURE;
    2900             : 
    2901           0 :     rv = getpeername(
    2902           0 :         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
    2903             : 
    2904           0 :     if (rv == -1) {
    2905           0 :         pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
    2906           0 :         return PR_FAILURE;
    2907             :     }
    2908             : #ifdef _PR_HAVE_SOCKADDR_LEN
    2909             :     /* ignore the sa_len field of struct sockaddr */
    2910             :     if (addr)
    2911             :     {
    2912             :         addr->raw.family = ((struct sockaddr*)addr)->sa_family;
    2913             :     }
    2914             : #endif /* _PR_HAVE_SOCKADDR_LEN */
    2915             : #ifdef _PR_INET6
    2916           0 :     if (AF_INET6 == addr->raw.family)
    2917           0 :         addr->raw.family = PR_AF_INET6;
    2918             : #endif
    2919           0 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    2920           0 :     PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
    2921           0 :     return PR_SUCCESS;
    2922             : }  /* pt_GetPeerName */
    2923             : 
    2924           0 : static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
    2925             : {
    2926             :     PRIntn rv;
    2927             :     pt_SockLen length;
    2928             :     PRInt32 level, name;
    2929             : 
    2930             :     /*
    2931             :      * PR_SockOpt_Nonblocking is a special case that does not
    2932             :      * translate to a getsockopt() call
    2933             :      */
    2934           0 :     if (PR_SockOpt_Nonblocking == data->option)
    2935             :     {
    2936           0 :         data->value.non_blocking = fd->secret->nonblocking;
    2937           0 :         return PR_SUCCESS;
    2938             :     }
    2939             : 
    2940           0 :     rv = _PR_MapOptionName(data->option, &level, &name);
    2941           0 :     if (PR_SUCCESS == rv)
    2942             :     {
    2943           0 :         switch (data->option)
    2944             :         {
    2945             :             case PR_SockOpt_Linger:
    2946             :             {
    2947             :                 struct linger linger;
    2948           0 :                 length = sizeof(linger);
    2949           0 :                 rv = getsockopt(
    2950           0 :                     fd->secret->md.osfd, level, name, (char *) &linger, &length);
    2951           0 :                 PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
    2952           0 :                 data->value.linger.polarity =
    2953           0 :                     (linger.l_onoff) ? PR_TRUE : PR_FALSE;
    2954           0 :                 data->value.linger.linger =
    2955           0 :                     PR_SecondsToInterval(linger.l_linger);
    2956           0 :                 break;
    2957             :             }
    2958             :             case PR_SockOpt_Reuseaddr:
    2959             :             case PR_SockOpt_Keepalive:
    2960             :             case PR_SockOpt_NoDelay:
    2961             :             case PR_SockOpt_Broadcast:
    2962             :             case PR_SockOpt_Reuseport:
    2963             :             {
    2964             :                 PRIntn value;
    2965           0 :                 length = sizeof(PRIntn);
    2966           0 :                 rv = getsockopt(
    2967           0 :                     fd->secret->md.osfd, level, name, (char*)&value, &length);
    2968           0 :                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
    2969           0 :                 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
    2970           0 :                 break;
    2971             :             }
    2972             :             case PR_SockOpt_McastLoopback:
    2973             :             {
    2974             :                 PRUint8 xbool;
    2975           0 :                 length = sizeof(xbool);
    2976           0 :                 rv = getsockopt(
    2977           0 :                     fd->secret->md.osfd, level, name,
    2978             :                     (char*)&xbool, &length);
    2979           0 :                 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
    2980           0 :                 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
    2981           0 :                 break;
    2982             :             }
    2983             :             case PR_SockOpt_RecvBufferSize:
    2984             :             case PR_SockOpt_SendBufferSize:
    2985             :             case PR_SockOpt_MaxSegment:
    2986             :             {
    2987             :                 PRIntn value;
    2988           0 :                 length = sizeof(PRIntn);
    2989           0 :                 rv = getsockopt(
    2990           0 :                     fd->secret->md.osfd, level, name, (char*)&value, &length);
    2991           0 :                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
    2992           0 :                 data->value.recv_buffer_size = value;
    2993           0 :                 break;
    2994             :             }
    2995             :             case PR_SockOpt_IpTimeToLive:
    2996             :             case PR_SockOpt_IpTypeOfService:
    2997             :             {
    2998           0 :                 length = sizeof(PRUintn);
    2999           0 :                 rv = getsockopt(
    3000           0 :                     fd->secret->md.osfd, level, name,
    3001           0 :                     (char*)&data->value.ip_ttl, &length);
    3002           0 :                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
    3003           0 :                 break;
    3004             :             }
    3005             :             case PR_SockOpt_McastTimeToLive:
    3006             :             {
    3007             :                 PRUint8 ttl;
    3008           0 :                 length = sizeof(ttl);
    3009           0 :                 rv = getsockopt(
    3010           0 :                     fd->secret->md.osfd, level, name,
    3011             :                     (char*)&ttl, &length);
    3012           0 :                 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
    3013           0 :                 data->value.mcast_ttl = ttl;
    3014           0 :                 break;
    3015             :             }
    3016             :             case PR_SockOpt_AddMember:
    3017             :             case PR_SockOpt_DropMember:
    3018             :             {
    3019             :                 struct ip_mreq mreq;
    3020           0 :                 length = sizeof(mreq);
    3021           0 :                 rv = getsockopt(
    3022           0 :                     fd->secret->md.osfd, level, name, (char*)&mreq, &length);
    3023           0 :                 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
    3024           0 :                 data->value.add_member.mcaddr.inet.ip =
    3025           0 :                     mreq.imr_multiaddr.s_addr;
    3026           0 :                 data->value.add_member.ifaddr.inet.ip =
    3027           0 :                     mreq.imr_interface.s_addr;
    3028           0 :                 break;
    3029             :             }
    3030             :             case PR_SockOpt_McastInterface:
    3031             :             {
    3032           0 :                 length = sizeof(data->value.mcast_if.inet.ip);
    3033           0 :                 rv = getsockopt(
    3034           0 :                     fd->secret->md.osfd, level, name,
    3035           0 :                     (char*)&data->value.mcast_if.inet.ip, &length);
    3036           0 :                 PR_ASSERT((-1 == rv)
    3037             :                     || (sizeof(data->value.mcast_if.inet.ip) == length));
    3038           0 :                 break;
    3039             :             }
    3040             :             default:
    3041           0 :                 PR_NOT_REACHED("Unknown socket option");
    3042           0 :                 break;
    3043             :         }
    3044           0 :         if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
    3045             :     }
    3046           0 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    3047             : }  /* pt_GetSocketOption */
    3048             : 
    3049          11 : static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
    3050             : {
    3051             :     PRIntn rv;
    3052             :     PRInt32 level, name;
    3053             : 
    3054             :     /*
    3055             :      * PR_SockOpt_Nonblocking is a special case that does not
    3056             :      * translate to a setsockopt call.
    3057             :      */
    3058          11 :     if (PR_SockOpt_Nonblocking == data->option)
    3059             :     {
    3060           3 :         fd->secret->nonblocking = data->value.non_blocking;
    3061           3 :         return PR_SUCCESS;
    3062             :     }
    3063             : 
    3064           8 :     rv = _PR_MapOptionName(data->option, &level, &name);
    3065           8 :     if (PR_SUCCESS == rv)
    3066             :     {
    3067           8 :         switch (data->option)
    3068             :         {
    3069             :             case PR_SockOpt_Linger:
    3070             :             {
    3071             :                 struct linger linger;
    3072           0 :                 linger.l_onoff = data->value.linger.polarity;
    3073           0 :                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
    3074           0 :                 rv = setsockopt(
    3075           0 :                     fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
    3076           0 :                 break;
    3077             :             }
    3078             :             case PR_SockOpt_Reuseaddr:
    3079             :             case PR_SockOpt_Keepalive:
    3080             :             case PR_SockOpt_NoDelay:
    3081             :             case PR_SockOpt_Broadcast:
    3082             :             case PR_SockOpt_Reuseport:
    3083             :             {
    3084           8 :                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
    3085          16 :                 rv = setsockopt(
    3086           8 :                     fd->secret->md.osfd, level, name,
    3087             :                     (char*)&value, sizeof(PRIntn));
    3088             : #ifdef LINUX
    3089             :                 /* for pt_LinuxSendFile */
    3090           8 :                 if (name == TCP_NODELAY && rv == 0) {
    3091           3 :                     fd->secret->md.tcp_nodelay = value;
    3092             :                 }
    3093             : #endif
    3094           8 :                 break;
    3095             :             }
    3096             :             case PR_SockOpt_McastLoopback:
    3097             :             {
    3098           0 :                 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
    3099           0 :                 rv = setsockopt(
    3100           0 :                     fd->secret->md.osfd, level, name,
    3101             :                     (char*)&xbool, sizeof(xbool));
    3102           0 :                 break;
    3103             :             }
    3104             :             case PR_SockOpt_RecvBufferSize:
    3105             :             case PR_SockOpt_SendBufferSize:
    3106             :             case PR_SockOpt_MaxSegment:
    3107             :             {
    3108           0 :                 PRIntn value = data->value.recv_buffer_size;
    3109           0 :                 rv = setsockopt(
    3110           0 :                     fd->secret->md.osfd, level, name,
    3111             :                     (char*)&value, sizeof(PRIntn));
    3112           0 :                 break;
    3113             :             }
    3114             :             case PR_SockOpt_IpTimeToLive:
    3115             :             case PR_SockOpt_IpTypeOfService:
    3116             :             {
    3117           0 :                 rv = setsockopt(
    3118           0 :                     fd->secret->md.osfd, level, name,
    3119           0 :                     (char*)&data->value.ip_ttl, sizeof(PRUintn));
    3120           0 :                 break;
    3121             :             }
    3122             :             case PR_SockOpt_McastTimeToLive:
    3123             :             {
    3124           0 :                 PRUint8 ttl = data->value.mcast_ttl;
    3125           0 :                 rv = setsockopt(
    3126           0 :                     fd->secret->md.osfd, level, name,
    3127             :                     (char*)&ttl, sizeof(ttl));
    3128           0 :                 break;
    3129             :             }
    3130             :             case PR_SockOpt_AddMember:
    3131             :             case PR_SockOpt_DropMember:
    3132             :             {
    3133             :                 struct ip_mreq mreq;
    3134           0 :                 mreq.imr_multiaddr.s_addr =
    3135           0 :                     data->value.add_member.mcaddr.inet.ip;
    3136           0 :                 mreq.imr_interface.s_addr =
    3137           0 :                     data->value.add_member.ifaddr.inet.ip;
    3138           0 :                 rv = setsockopt(
    3139           0 :                     fd->secret->md.osfd, level, name,
    3140             :                     (char*)&mreq, sizeof(mreq));
    3141           0 :                 break;
    3142             :             }
    3143             :             case PR_SockOpt_McastInterface:
    3144             :             {
    3145           0 :                 rv = setsockopt(
    3146           0 :                     fd->secret->md.osfd, level, name,
    3147           0 :                     (char*)&data->value.mcast_if.inet.ip,
    3148             :                     sizeof(data->value.mcast_if.inet.ip));
    3149           0 :                 break;
    3150             :             }
    3151             :             default:
    3152           0 :                 PR_NOT_REACHED("Unknown socket option");
    3153           0 :                 break;
    3154             :         }
    3155           8 :         if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
    3156             :     }
    3157           8 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    3158             : }  /* pt_SetSocketOption */
    3159             : 
    3160             : /*****************************************************************************/
    3161             : /****************************** I/O method objects ***************************/
    3162             : /*****************************************************************************/
    3163             : 
    3164             : static PRIOMethods _pr_file_methods = {
    3165             :     PR_DESC_FILE,
    3166             :     pt_Close,
    3167             :     pt_Read,
    3168             :     pt_Write,
    3169             :     pt_Available_f,
    3170             :     pt_Available64_f,
    3171             :     pt_Fsync,
    3172             :     pt_Seek,
    3173             :     pt_Seek64,
    3174             :     pt_FileInfo,
    3175             :     pt_FileInfo64,
    3176             :     (PRWritevFN)_PR_InvalidInt,        
    3177             :     (PRConnectFN)_PR_InvalidStatus,        
    3178             :     (PRAcceptFN)_PR_InvalidDesc,        
    3179             :     (PRBindFN)_PR_InvalidStatus,        
    3180             :     (PRListenFN)_PR_InvalidStatus,        
    3181             :     (PRShutdownFN)_PR_InvalidStatus,    
    3182             :     (PRRecvFN)_PR_InvalidInt,        
    3183             :     (PRSendFN)_PR_InvalidInt,        
    3184             :     (PRRecvfromFN)_PR_InvalidInt,    
    3185             :     (PRSendtoFN)_PR_InvalidInt,        
    3186             :     pt_Poll,
    3187             :     (PRAcceptreadFN)_PR_InvalidInt,   
    3188             :     (PRTransmitfileFN)_PR_InvalidInt, 
    3189             :     (PRGetsocknameFN)_PR_InvalidStatus,    
    3190             :     (PRGetpeernameFN)_PR_InvalidStatus,    
    3191             :     (PRReservedFN)_PR_InvalidInt,    
    3192             :     (PRReservedFN)_PR_InvalidInt,    
    3193             :     (PRGetsocketoptionFN)_PR_InvalidStatus,
    3194             :     (PRSetsocketoptionFN)_PR_InvalidStatus,
    3195             :     (PRSendfileFN)_PR_InvalidInt, 
    3196             :     (PRConnectcontinueFN)_PR_InvalidStatus, 
    3197             :     (PRReservedFN)_PR_InvalidInt, 
    3198             :     (PRReservedFN)_PR_InvalidInt, 
    3199             :     (PRReservedFN)_PR_InvalidInt, 
    3200             :     (PRReservedFN)_PR_InvalidInt
    3201             : };
    3202             : 
    3203             : static PRIOMethods _pr_pipe_methods = {
    3204             :     PR_DESC_PIPE,
    3205             :     pt_Close,
    3206             :     pt_Read,
    3207             :     pt_Write,
    3208             :     pt_Available_s,
    3209             :     pt_Available64_s,
    3210             :     pt_Synch,
    3211             :     (PRSeekFN)_PR_InvalidInt,
    3212             :     (PRSeek64FN)_PR_InvalidInt64,
    3213             :     (PRFileInfoFN)_PR_InvalidStatus,
    3214             :     (PRFileInfo64FN)_PR_InvalidStatus,
    3215             :     (PRWritevFN)_PR_InvalidInt,        
    3216             :     (PRConnectFN)_PR_InvalidStatus,        
    3217             :     (PRAcceptFN)_PR_InvalidDesc,        
    3218             :     (PRBindFN)_PR_InvalidStatus,        
    3219             :     (PRListenFN)_PR_InvalidStatus,        
    3220             :     (PRShutdownFN)_PR_InvalidStatus,    
    3221             :     (PRRecvFN)_PR_InvalidInt,        
    3222             :     (PRSendFN)_PR_InvalidInt,        
    3223             :     (PRRecvfromFN)_PR_InvalidInt,    
    3224             :     (PRSendtoFN)_PR_InvalidInt,        
    3225             :     pt_Poll,
    3226             :     (PRAcceptreadFN)_PR_InvalidInt,   
    3227             :     (PRTransmitfileFN)_PR_InvalidInt, 
    3228             :     (PRGetsocknameFN)_PR_InvalidStatus,    
    3229             :     (PRGetpeernameFN)_PR_InvalidStatus,    
    3230             :     (PRReservedFN)_PR_InvalidInt,    
    3231             :     (PRReservedFN)_PR_InvalidInt,    
    3232             :     (PRGetsocketoptionFN)_PR_InvalidStatus,
    3233             :     (PRSetsocketoptionFN)_PR_InvalidStatus,
    3234             :     (PRSendfileFN)_PR_InvalidInt, 
    3235             :     (PRConnectcontinueFN)_PR_InvalidStatus, 
    3236             :     (PRReservedFN)_PR_InvalidInt, 
    3237             :     (PRReservedFN)_PR_InvalidInt, 
    3238             :     (PRReservedFN)_PR_InvalidInt, 
    3239             :     (PRReservedFN)_PR_InvalidInt
    3240             : };
    3241             : 
    3242             : static PRIOMethods _pr_tcp_methods = {
    3243             :     PR_DESC_SOCKET_TCP,
    3244             :     pt_Close,
    3245             :     pt_SocketRead,
    3246             :     pt_SocketWrite,
    3247             :     pt_Available_s,
    3248             :     pt_Available64_s,
    3249             :     pt_Synch,
    3250             :     (PRSeekFN)_PR_InvalidInt,
    3251             :     (PRSeek64FN)_PR_InvalidInt64,
    3252             :     (PRFileInfoFN)_PR_InvalidStatus,
    3253             :     (PRFileInfo64FN)_PR_InvalidStatus,
    3254             :     pt_Writev,
    3255             :     pt_Connect,
    3256             :     pt_Accept,
    3257             :     pt_Bind,
    3258             :     pt_Listen,
    3259             :     pt_Shutdown,
    3260             :     pt_Recv,
    3261             :     pt_Send,
    3262             :     (PRRecvfromFN)_PR_InvalidInt,
    3263             : #if defined(LINUX) || defined(DARWIN)
    3264             :     pt_TCP_SendTo, /* This is for TCP Fast Open. Linux uses SendTo function for this. OSX uses connectx, but we imitate Linux. */
    3265             : #else
    3266             :     (PRSendtoFN)_PR_InvalidInt,
    3267             : #endif
    3268             :     pt_Poll,
    3269             :     pt_AcceptRead,
    3270             :     pt_TransmitFile,
    3271             :     pt_GetSockName,
    3272             :     pt_GetPeerName,
    3273             :     (PRReservedFN)_PR_InvalidInt,
    3274             :     (PRReservedFN)_PR_InvalidInt,
    3275             :     pt_GetSocketOption,
    3276             :     pt_SetSocketOption,
    3277             :     pt_SendFile, 
    3278             :     pt_ConnectContinue,
    3279             :     (PRReservedFN)_PR_InvalidInt, 
    3280             :     (PRReservedFN)_PR_InvalidInt, 
    3281             :     (PRReservedFN)_PR_InvalidInt, 
    3282             :     (PRReservedFN)_PR_InvalidInt
    3283             : };
    3284             : 
    3285             : static PRIOMethods _pr_udp_methods = {
    3286             :     PR_DESC_SOCKET_UDP,
    3287             :     pt_Close,
    3288             :     pt_SocketRead,
    3289             :     pt_SocketWrite,
    3290             :     pt_Available_s,
    3291             :     pt_Available64_s,
    3292             :     pt_Synch,
    3293             :     (PRSeekFN)_PR_InvalidInt,
    3294             :     (PRSeek64FN)_PR_InvalidInt64,
    3295             :     (PRFileInfoFN)_PR_InvalidStatus,
    3296             :     (PRFileInfo64FN)_PR_InvalidStatus,
    3297             :     pt_Writev,
    3298             :     pt_Connect,
    3299             :     (PRAcceptFN)_PR_InvalidDesc,
    3300             :     pt_Bind,
    3301             :     pt_Listen,
    3302             :     pt_Shutdown,
    3303             :     pt_Recv,
    3304             :     pt_Send,
    3305             :     pt_RecvFrom,
    3306             :     pt_SendTo,
    3307             :     pt_Poll,
    3308             :     (PRAcceptreadFN)_PR_InvalidInt,
    3309             :     (PRTransmitfileFN)_PR_InvalidInt,
    3310             :     pt_GetSockName,
    3311             :     pt_GetPeerName,
    3312             :     (PRReservedFN)_PR_InvalidInt,
    3313             :     (PRReservedFN)_PR_InvalidInt,
    3314             :     pt_GetSocketOption,
    3315             :     pt_SetSocketOption,
    3316             :     (PRSendfileFN)_PR_InvalidInt, 
    3317             :     (PRConnectcontinueFN)_PR_InvalidStatus, 
    3318             :     (PRReservedFN)_PR_InvalidInt, 
    3319             :     (PRReservedFN)_PR_InvalidInt, 
    3320             :     (PRReservedFN)_PR_InvalidInt, 
    3321             :     (PRReservedFN)_PR_InvalidInt
    3322             : };
    3323             : 
    3324             : static PRIOMethods _pr_socketpollfd_methods = {
    3325             :     (PRDescType) 0,
    3326             :     (PRCloseFN)_PR_InvalidStatus,
    3327             :     (PRReadFN)_PR_InvalidInt,
    3328             :     (PRWriteFN)_PR_InvalidInt,
    3329             :     (PRAvailableFN)_PR_InvalidInt,
    3330             :     (PRAvailable64FN)_PR_InvalidInt64,
    3331             :     (PRFsyncFN)_PR_InvalidStatus,
    3332             :     (PRSeekFN)_PR_InvalidInt,
    3333             :     (PRSeek64FN)_PR_InvalidInt64,
    3334             :     (PRFileInfoFN)_PR_InvalidStatus,
    3335             :     (PRFileInfo64FN)_PR_InvalidStatus,
    3336             :     (PRWritevFN)_PR_InvalidInt,        
    3337             :     (PRConnectFN)_PR_InvalidStatus,        
    3338             :     (PRAcceptFN)_PR_InvalidDesc,        
    3339             :     (PRBindFN)_PR_InvalidStatus,        
    3340             :     (PRListenFN)_PR_InvalidStatus,        
    3341             :     (PRShutdownFN)_PR_InvalidStatus,    
    3342             :     (PRRecvFN)_PR_InvalidInt,        
    3343             :     (PRSendFN)_PR_InvalidInt,        
    3344             :     (PRRecvfromFN)_PR_InvalidInt,    
    3345             :     (PRSendtoFN)_PR_InvalidInt,        
    3346             :         pt_Poll,
    3347             :     (PRAcceptreadFN)_PR_InvalidInt,   
    3348             :     (PRTransmitfileFN)_PR_InvalidInt, 
    3349             :     (PRGetsocknameFN)_PR_InvalidStatus,    
    3350             :     (PRGetpeernameFN)_PR_InvalidStatus,    
    3351             :     (PRReservedFN)_PR_InvalidInt,    
    3352             :     (PRReservedFN)_PR_InvalidInt,    
    3353             :     (PRGetsocketoptionFN)_PR_InvalidStatus,
    3354             :     (PRSetsocketoptionFN)_PR_InvalidStatus,
    3355             :     (PRSendfileFN)_PR_InvalidInt, 
    3356             :     (PRConnectcontinueFN)_PR_InvalidStatus, 
    3357             :     (PRReservedFN)_PR_InvalidInt, 
    3358             :     (PRReservedFN)_PR_InvalidInt, 
    3359             :     (PRReservedFN)_PR_InvalidInt, 
    3360             :     (PRReservedFN)_PR_InvalidInt
    3361             : };
    3362             : 
    3363             : #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
    3364             :     || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
    3365             :     || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
    3366             :     || defined(OPENBSD) || defined(BSDI) || defined(NTO) \
    3367             :     || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) \
    3368             :     || defined(SYMBIAN)
    3369             : #define _PR_FCNTL_FLAGS O_NONBLOCK
    3370             : #else
    3371             : #error "Can't determine architecture"
    3372             : #endif
    3373             : 
    3374             : /*
    3375             :  * Put a Unix file descriptor in non-blocking mode.
    3376             :  */
    3377           9 : static void pt_MakeFdNonblock(PRIntn osfd)
    3378             : {
    3379             :     PRIntn flags;
    3380           9 :     flags = fcntl(osfd, F_GETFL, 0);
    3381           9 :     flags |= _PR_FCNTL_FLAGS;
    3382           9 :     (void)fcntl(osfd, F_SETFL, flags);
    3383           9 : }
    3384             : 
    3385             : /*
    3386             :  * Put a Unix socket fd in non-blocking mode that can
    3387             :  * ideally be inherited by an accepted socket.
    3388             :  *
    3389             :  * Why doesn't pt_MakeFdNonblock do?  This is to deal with
    3390             :  * the special case of HP-UX.  HP-UX has three kinds of
    3391             :  * non-blocking modes for sockets: the fcntl() O_NONBLOCK
    3392             :  * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
    3393             :  * the ioctl() FIOSNBIO form of non-blocking mode is
    3394             :  * inherited by an accepted socket.
    3395             :  *
    3396             :  * Other platforms just use the generic pt_MakeFdNonblock
    3397             :  * to put a socket in non-blocking mode.
    3398             :  */
    3399             : #ifdef HPUX
    3400             : static void pt_MakeSocketNonblock(PRIntn osfd)
    3401             : {
    3402             :     PRIntn one = 1;
    3403             :     (void)ioctl(osfd, FIOSNBIO, &one);
    3404             : }
    3405             : #else
    3406             : #define pt_MakeSocketNonblock pt_MakeFdNonblock
    3407             : #endif
    3408             : 
    3409        1279 : static PRFileDesc *pt_SetMethods(
    3410             :     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
    3411             : {
    3412        1279 :     PRFileDesc *fd = _PR_Getfd();
    3413             :     
    3414        1279 :     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    3415             :     else
    3416             :     {
    3417        1279 :         fd->secret->md.osfd = osfd;
    3418        1279 :         fd->secret->state = _PR_FILEDESC_OPEN;
    3419        1279 :         if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
    3420             :         else
    3421             :         {
    3422             :             /* By default, a Unix fd is not closed on exec. */
    3423             : #ifdef DEBUG
    3424             :             PRIntn flags;
    3425        1268 :             flags = fcntl(osfd, F_GETFD, 0);
    3426        1268 :             PR_ASSERT(0 == flags);
    3427             : #endif
    3428        1268 :             fd->secret->inheritable = _PR_TRI_TRUE;
    3429             :         }
    3430        1279 :         switch (type)
    3431             :         {
    3432             :             case PR_DESC_FILE:
    3433        1270 :                 fd->methods = PR_GetFileMethods();
    3434        1270 :                 break;
    3435             :             case PR_DESC_SOCKET_TCP:
    3436           3 :                 fd->methods = PR_GetTCPMethods();
    3437             : #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
    3438             :                 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
    3439             : #else
    3440           3 :                 pt_MakeSocketNonblock(osfd);
    3441             : #endif
    3442           3 :                 break;
    3443             :             case PR_DESC_SOCKET_UDP:
    3444           0 :                 fd->methods = PR_GetUDPMethods();
    3445           0 :                 pt_MakeFdNonblock(osfd);
    3446           0 :                 break;
    3447             :             case PR_DESC_PIPE:
    3448           6 :                 fd->methods = PR_GetPipeMethods();
    3449           6 :                 pt_MakeFdNonblock(osfd);
    3450           6 :                 break;
    3451             :             default:
    3452           0 :                 break;
    3453             :         }
    3454             :     }
    3455        1279 :     return fd;
    3456             : }  /* pt_SetMethods */
    3457             : 
    3458        1271 : PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
    3459             : {
    3460        1271 :     return &_pr_file_methods;
    3461             : }  /* PR_GetFileMethods */
    3462             : 
    3463           6 : PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
    3464             : {
    3465           6 :     return &_pr_pipe_methods;
    3466             : }  /* PR_GetPipeMethods */
    3467             : 
    3468           3 : PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
    3469             : {
    3470           3 :     return &_pr_tcp_methods;
    3471             : }  /* PR_GetTCPMethods */
    3472             : 
    3473           0 : PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
    3474             : {
    3475           0 :     return &_pr_udp_methods;
    3476             : }  /* PR_GetUDPMethods */
    3477             : 
    3478           0 : static const PRIOMethods* PR_GetSocketPollFdMethods(void)
    3479             : {
    3480           0 :     return &_pr_socketpollfd_methods;
    3481             : }  /* PR_GetSocketPollFdMethods */
    3482             : 
    3483           0 : PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
    3484             :     PRInt32 osfd, const PRIOMethods *methods)
    3485             : {
    3486           0 :     PRFileDesc *fd = _PR_Getfd();
    3487             : 
    3488           0 :     if (NULL == fd) goto failed;
    3489             : 
    3490           0 :     fd->methods = methods;
    3491           0 :     fd->secret->md.osfd = osfd;
    3492             :     /* Make fd non-blocking */
    3493           0 :     if (osfd > 2)
    3494             :     {
    3495             :         /* Don't mess around with stdin, stdout or stderr */
    3496           0 :         if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
    3497           0 :         else pt_MakeFdNonblock(osfd);
    3498             :     }
    3499           0 :     fd->secret->state = _PR_FILEDESC_OPEN;
    3500           0 :     fd->secret->inheritable = _PR_TRI_UNKNOWN;
    3501           0 :     return fd;
    3502             :     
    3503             : failed:
    3504           0 :     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    3505           0 :     return fd;
    3506             : }  /* PR_AllocFileDesc */
    3507             : 
    3508             : #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
    3509             : PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
    3510             : #if defined(_PR_INET6_PROBE)
    3511             : extern PRBool _pr_ipv6_is_present(void);
    3512           1 : PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
    3513             : {
    3514             :     int osfd;
    3515             : 
    3516             : #if defined(DARWIN)
    3517             :     /*
    3518             :      * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
    3519             :      * lesser versions is not ready for general use (see bug 222031).
    3520             :      */
    3521             :     {
    3522             :         struct utsname u;
    3523             :         if (uname(&u) != 0 || atoi(u.release) < 7)
    3524             :             return PR_FALSE;
    3525             :     }
    3526             : #endif
    3527             : 
    3528             :     /*
    3529             :      * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
    3530             :      * suggests that we call open("/dev/ip6", O_RDWR) to determine
    3531             :      * whether IPv6 APIs and the IPv6 stack are on the system.
    3532             :      * Our portable test below seems to work fine, so I am using it.
    3533             :      */
    3534           1 :     osfd = socket(AF_INET6, SOCK_STREAM, 0);
    3535           1 :     if (osfd != -1) {
    3536           1 :         close(osfd);
    3537           1 :         return PR_TRUE;
    3538             :     }
    3539           0 :     return PR_FALSE;
    3540             : }
    3541             : #endif  /* _PR_INET6_PROBE */
    3542             : #endif
    3543             : 
    3544           3 : PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
    3545             : {
    3546             :     PRIntn osfd;
    3547             :     PRDescType ftype;
    3548           3 :     PRFileDesc *fd = NULL;
    3549             : #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
    3550           3 :     PRInt32 tmp_domain = domain;
    3551             : #endif
    3552             : 
    3553           3 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3554             : 
    3555           3 :     if (pt_TestAbort()) return NULL;
    3556             : 
    3557           3 :     if (PF_INET != domain
    3558           0 :         && PR_AF_INET6 != domain
    3559             : #if defined(_PR_HAVE_SDP)
    3560           0 :         && PR_AF_INET_SDP != domain
    3561             : #if defined(SOLARIS)
    3562             :         && PR_AF_INET6_SDP != domain
    3563             : #endif /* SOLARIS */
    3564             : #endif /* _PR_HAVE_SDP */
    3565           0 :         && PF_UNIX != domain)
    3566             :     {
    3567           0 :         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
    3568           0 :         return fd;
    3569             :     }
    3570           3 :         if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
    3571           0 :         else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
    3572             :         else
    3573             :         {
    3574           0 :                 (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
    3575           0 :                 return fd;
    3576             :         }
    3577             : #if defined(_PR_HAVE_SDP)
    3578             : #if defined(LINUX)
    3579           3 :     if (PR_AF_INET_SDP == domain)
    3580           0 :         domain = AF_INET_SDP;
    3581             : #elif defined(SOLARIS)
    3582             :     if (PR_AF_INET_SDP == domain) {
    3583             :         domain = AF_INET;
    3584             :         proto = PROTO_SDP;
    3585             :     } else if(PR_AF_INET6_SDP == domain) {
    3586             :         domain = AF_INET6;
    3587             :         proto = PROTO_SDP;
    3588             :     }
    3589             : #endif /* SOLARIS */
    3590             : #endif /* _PR_HAVE_SDP */
    3591             : #if defined(_PR_INET6_PROBE)
    3592           3 :         if (PR_AF_INET6 == domain)
    3593           0 :                 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
    3594             : #elif defined(_PR_INET6) 
    3595             :         if (PR_AF_INET6 == domain)
    3596             :                 domain = AF_INET6;
    3597             : #else
    3598             :         if (PR_AF_INET6 == domain)
    3599             :                 domain = AF_INET;
    3600             : #endif
    3601             : 
    3602           3 :     osfd = socket(domain, type, proto);
    3603           3 :     if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
    3604             :     else
    3605             :     {
    3606             : #ifdef _PR_IPV6_V6ONLY_PROBE
    3607             :         if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
    3608             :         {
    3609             :             int on = 0;
    3610             :             (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
    3611             :                     &on, sizeof(on));
    3612             :         }
    3613             : #endif
    3614           3 :         fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
    3615           3 :         if (fd == NULL) close(osfd);
    3616             :     }
    3617             : #ifdef _PR_NEED_SECRET_AF
    3618             :     if (fd != NULL) fd->secret->af = domain;
    3619             : #endif
    3620             : #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
    3621           3 :         if (fd != NULL) {
    3622             :                 /*
    3623             :                  * For platforms with no support for IPv6 
    3624             :                  * create layered socket for IPv4-mapped IPv6 addresses
    3625             :                  */
    3626           3 :                 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
    3627           0 :                         if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
    3628           0 :                                 PR_Close(fd);
    3629           0 :                                 fd = NULL;
    3630             :                         }
    3631             :                 }
    3632             :         }
    3633             : #endif
    3634           3 :     return fd;
    3635             : }  /* PR_Socket */
    3636             : 
    3637             : /*****************************************************************************/
    3638             : /****************************** I/O public methods ***************************/
    3639             : /*****************************************************************************/
    3640             : 
    3641             : PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
    3642             :     const char *name, PRIntn flags, PRIntn mode)
    3643             : {
    3644        1276 :     PRFileDesc *fd = NULL;
    3645        1276 :     PRIntn syserrno, osfd = -1, osflags = 0;;
    3646             : 
    3647        1276 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3648             : 
    3649        1276 :     if (pt_TestAbort()) return NULL;
    3650             : 
    3651        1275 :     if (flags & PR_RDONLY) osflags |= O_RDONLY;
    3652        1275 :     if (flags & PR_WRONLY) osflags |= O_WRONLY;
    3653        1275 :     if (flags & PR_RDWR) osflags |= O_RDWR;
    3654        1275 :     if (flags & PR_APPEND) osflags |= O_APPEND;
    3655        1275 :     if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
    3656        1275 :     if (flags & PR_EXCL) osflags |= O_EXCL;
    3657        1275 :     if (flags & PR_SYNC)
    3658             :     {
    3659             : #if defined(O_SYNC)
    3660           0 :         osflags |= O_SYNC;
    3661             : #elif defined(O_FSYNC)
    3662             :         osflags |= O_FSYNC;
    3663             : #else
    3664             : #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
    3665             : #endif
    3666             :     }
    3667             : 
    3668             :     /*
    3669             :     ** We have to hold the lock across the creation in order to
    3670             :     ** enforce the sematics of PR_Rename(). (see the latter for
    3671             :     ** more details)
    3672             :     */
    3673        1275 :     if (flags & PR_CREATE_FILE)
    3674             :     {
    3675          38 :         osflags |= O_CREAT;
    3676          38 :         if (NULL !=_pr_rename_lock)
    3677          38 :             PR_Lock(_pr_rename_lock);
    3678             :     }
    3679             : 
    3680        1275 :     osfd = _md_iovector._open64(name, osflags, mode);
    3681        1276 :     syserrno = errno;
    3682             : 
    3683        1276 :     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
    3684          38 :         PR_Unlock(_pr_rename_lock);
    3685             : 
    3686        1276 :     if (osfd == -1)
    3687          17 :         pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
    3688             :     else
    3689             :     {
    3690        1259 :         fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
    3691        1259 :         if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
    3692             :     }
    3693        1276 :     return fd;
    3694             : }  /* PR_OpenFile */
    3695             : 
    3696             : PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
    3697             : {
    3698        1273 :     return PR_OpenFile(name, flags, mode);
    3699             : }  /* PR_Open */
    3700             : 
    3701             : PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
    3702             : {
    3703           0 :     PRIntn rv = -1;
    3704             : 
    3705           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3706             : 
    3707           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3708             : 
    3709           0 :     rv = unlink(name);
    3710             : 
    3711           0 :     if (rv == -1) {
    3712           0 :         pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
    3713           0 :         return PR_FAILURE;
    3714             :     }
    3715           0 :     return PR_SUCCESS;
    3716             : }  /* PR_Delete */
    3717             : 
    3718             : PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
    3719             : {
    3720             :     PRIntn rv;
    3721             : 
    3722           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3723             : 
    3724           0 :     switch (how)
    3725             :     {
    3726             :     case PR_ACCESS_READ_OK:
    3727           0 :         rv =  access(name, R_OK);
    3728           0 :         break;
    3729             :     case PR_ACCESS_WRITE_OK:
    3730           0 :         rv = access(name, W_OK);
    3731           0 :         break;
    3732             :     case PR_ACCESS_EXISTS:
    3733             :     default:
    3734           0 :         rv = access(name, F_OK);
    3735             :     }
    3736           0 :     if (0 == rv) return PR_SUCCESS;
    3737           0 :     pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
    3738           0 :     return PR_FAILURE;
    3739             :     
    3740             : }  /* PR_Access */
    3741             : 
    3742             : PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
    3743             : {
    3744           0 :     PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
    3745           0 :     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
    3746             : }  /* PR_GetFileInfo */
    3747             : 
    3748             : PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
    3749             : {
    3750             :     PRInt32 rv;
    3751             : 
    3752          26 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3753          26 :     rv = _PR_MD_GETFILEINFO64(fn, info);
    3754          26 :     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
    3755             : }  /* PR_GetFileInfo64 */
    3756             : 
    3757             : PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
    3758             : {
    3759           0 :     PRIntn rv = -1;
    3760             : 
    3761           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3762             : 
    3763             :     /*
    3764             :     ** We have to acquire a lock here to stiffle anybody trying to create
    3765             :     ** a new file at the same time. And we have to hold that lock while we
    3766             :     ** test to see if the file exists and do the rename. The other place
    3767             :     ** where the lock is held is in PR_Open() when possibly creating a 
    3768             :     ** new file.
    3769             :     */
    3770             : 
    3771           0 :     PR_Lock(_pr_rename_lock);
    3772           0 :     rv = access(to, F_OK);
    3773           0 :     if (0 == rv)
    3774             :     {
    3775           0 :         PR_SetError(PR_FILE_EXISTS_ERROR, 0);
    3776           0 :         rv = -1;
    3777             :     }
    3778             :     else
    3779             :     {
    3780           0 :         rv = rename(from, to);
    3781           0 :         if (rv == -1)
    3782           0 :             pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
    3783             :     }
    3784           0 :     PR_Unlock(_pr_rename_lock);
    3785           0 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    3786             : }  /* PR_Rename */
    3787             : 
    3788             : PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
    3789             : {
    3790           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3791             : 
    3792           0 :     if (NULL != dir->md.d)
    3793             :     {
    3794           0 :         if (closedir(dir->md.d) == -1)
    3795             :         {
    3796           0 :             _PR_MD_MAP_CLOSEDIR_ERROR(errno);
    3797           0 :             return PR_FAILURE;
    3798             :         }
    3799           0 :         dir->md.d = NULL;
    3800           0 :         PR_DELETE(dir);
    3801             :     }
    3802           0 :     return PR_SUCCESS;
    3803             : }  /* PR_CloseDir */
    3804             : 
    3805             : PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
    3806             : {
    3807           0 :     PRInt32 rv = -1;
    3808             : 
    3809           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3810             : 
    3811             :     /*
    3812             :     ** This lock is used to enforce rename semantics as described
    3813             :     ** in PR_Rename.
    3814             :     */
    3815           0 :     if (NULL !=_pr_rename_lock)
    3816           0 :         PR_Lock(_pr_rename_lock);
    3817           0 :     rv = mkdir(name, mode);
    3818           0 :     if (-1 == rv)
    3819           0 :         pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
    3820           0 :     if (NULL !=_pr_rename_lock)
    3821           0 :         PR_Unlock(_pr_rename_lock);
    3822             : 
    3823           0 :     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
    3824             : }  /* PR_Makedir */
    3825             : 
    3826             : PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
    3827             : {
    3828           0 :     return PR_MakeDir(name, mode);
    3829             : }  /* PR_Mkdir */
    3830             : 
    3831             : PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
    3832             : {
    3833             :     PRInt32 rv;
    3834             : 
    3835           0 :     if (pt_TestAbort()) return PR_FAILURE;
    3836             : 
    3837           0 :     rv = rmdir(name);
    3838           0 :     if (0 == rv) {
    3839           0 :         return PR_SUCCESS;
    3840             :     }
    3841           0 :     pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
    3842           0 :     return PR_FAILURE;
    3843             : }  /* PR_Rmdir */
    3844             : 
    3845             : 
    3846             : PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
    3847             : {
    3848             :     DIR *osdir;
    3849           0 :     PRDir *dir = NULL;
    3850             : 
    3851           0 :     if (pt_TestAbort()) return dir;
    3852             : 
    3853           0 :     osdir = opendir(name);
    3854           0 :     if (osdir == NULL)
    3855           0 :         pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
    3856             :     else
    3857             :     {
    3858           0 :         dir = PR_NEWZAP(PRDir);
    3859           0 :         if (dir)
    3860           0 :             dir->md.d = osdir;
    3861             :         else
    3862           0 :             (void)closedir(osdir);
    3863             :     }
    3864           0 :     return dir;
    3865             : }  /* PR_OpenDir */
    3866             : 
    3867          59 : static PRInt32 _pr_poll_with_poll(
    3868             :     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
    3869             : {
    3870          59 :     PRInt32 ready = 0;
    3871             :     /*
    3872             :      * For restarting poll() if it is interrupted by a signal.
    3873             :      * We use these variables to figure out how much time has
    3874             :      * elapsed and how much of the timeout still remains.
    3875             :      */
    3876          59 :     PRIntervalTime start = 0, elapsed, remaining;
    3877             : 
    3878          59 :     if (pt_TestAbort()) return -1;
    3879             : 
    3880          59 :     if (0 == npds) PR_Sleep(timeout);
    3881             :     else
    3882             :     {
    3883             : #define STACK_POLL_DESC_COUNT 64
    3884             :         struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
    3885             :         struct pollfd *syspoll;
    3886             :         PRIntn index, msecs;
    3887             : 
    3888          59 :         if (npds <= STACK_POLL_DESC_COUNT)
    3889             :         {
    3890          59 :             syspoll = stack_syspoll;
    3891             :         }
    3892             :         else
    3893             :         {
    3894           0 :             PRThread *me = PR_GetCurrentThread();
    3895           0 :             if (npds > me->syspoll_count)
    3896             :             {
    3897           0 :                 PR_Free(me->syspoll_list);
    3898           0 :                 me->syspoll_list =
    3899           0 :                     (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
    3900           0 :                 if (NULL == me->syspoll_list)
    3901             :                 {
    3902           0 :                     me->syspoll_count = 0;
    3903           0 :                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    3904           0 :                     return -1;
    3905             :                 }
    3906           0 :                 me->syspoll_count = npds;
    3907             :             }
    3908           0 :             syspoll = me->syspoll_list;
    3909             :         }
    3910             : 
    3911         137 :         for (index = 0; index < npds; ++index)
    3912             :         {
    3913          78 :             PRInt16 in_flags_read = 0, in_flags_write = 0;
    3914          78 :             PRInt16 out_flags_read = 0, out_flags_write = 0;
    3915             : 
    3916          78 :             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    3917             :             {
    3918          78 :                 if (pds[index].in_flags & PR_POLL_READ)
    3919             :                 {
    3920         225 :                     in_flags_read = (pds[index].fd->methods->poll)(
    3921          75 :                         pds[index].fd,
    3922          75 :                         pds[index].in_flags & ~PR_POLL_WRITE,
    3923             :                         &out_flags_read);
    3924             :                 }
    3925          78 :                 if (pds[index].in_flags & PR_POLL_WRITE)
    3926             :                 {
    3927          18 :                     in_flags_write = (pds[index].fd->methods->poll)(
    3928           6 :                         pds[index].fd,
    3929           6 :                         pds[index].in_flags & ~PR_POLL_READ,
    3930             :                         &out_flags_write);
    3931             :                 }
    3932         156 :                 if ((0 != (in_flags_read & out_flags_read))
    3933          78 :                 || (0 != (in_flags_write & out_flags_write)))
    3934             :                 {
    3935             :                     /* this one is ready right now */
    3936           0 :                     if (0 == ready)
    3937             :                     {
    3938             :                         /*
    3939             :                          * We will return without calling the system
    3940             :                          * poll function.  So zero the out_flags
    3941             :                          * fields of all the poll descriptors before
    3942             :                          * this one.
    3943             :                          */
    3944             :                         int i;
    3945           0 :                         for (i = 0; i < index; i++)
    3946             :                         {
    3947           0 :                             pds[i].out_flags = 0;
    3948             :                         }
    3949             :                     }
    3950           0 :                     ready += 1;
    3951           0 :                     pds[index].out_flags = out_flags_read | out_flags_write;
    3952             :                 }
    3953             :                 else
    3954             :                 {
    3955             :                     /* now locate the NSPR layer at the bottom of the stack */
    3956          78 :                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
    3957          78 :                         pds[index].fd, PR_NSPR_IO_LAYER);
    3958             :                     /* ignore a socket without PR_NSPR_IO_LAYER available */
    3959             : 
    3960          78 :                     pds[index].out_flags = 0;  /* pre-condition */
    3961          78 :                     if ((NULL != bottom)
    3962          78 :                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
    3963             :                     {
    3964         156 :                         if (0 == ready)
    3965             :                         {
    3966          78 :                             syspoll[index].fd = bottom->secret->md.osfd;
    3967          78 :                             syspoll[index].events = 0;
    3968          78 :                             if (in_flags_read & PR_POLL_READ)
    3969             :                             {
    3970          75 :                                 pds[index].out_flags |=
    3971             :                                     _PR_POLL_READ_SYS_READ;
    3972          75 :                                 syspoll[index].events |= POLLIN;
    3973             :                             }
    3974          78 :                             if (in_flags_read & PR_POLL_WRITE)
    3975             :                             {
    3976           2 :                                 pds[index].out_flags |=
    3977             :                                     _PR_POLL_READ_SYS_WRITE;
    3978           2 :                                 syspoll[index].events |= POLLOUT;
    3979             :                             }
    3980          78 :                             if (in_flags_write & PR_POLL_READ)
    3981             :                             {
    3982           0 :                                 pds[index].out_flags |=
    3983             :                                     _PR_POLL_WRITE_SYS_READ;
    3984           0 :                                 syspoll[index].events |= POLLIN;
    3985             :                             }
    3986          78 :                             if (in_flags_write & PR_POLL_WRITE)
    3987             :                             {
    3988           6 :                                 pds[index].out_flags |=
    3989             :                                     _PR_POLL_WRITE_SYS_WRITE;
    3990           6 :                                 syspoll[index].events |= POLLOUT;
    3991             :                             }
    3992          78 :                             if (pds[index].in_flags & PR_POLL_EXCEPT)
    3993          78 :                                 syspoll[index].events |= POLLPRI;
    3994             :                         }
    3995             :                     }
    3996             :                     else
    3997             :                     {
    3998           0 :                         if (0 == ready)
    3999             :                         {
    4000             :                             int i;
    4001           0 :                             for (i = 0; i < index; i++)
    4002             :                             {
    4003           0 :                                 pds[i].out_flags = 0;
    4004             :                             }
    4005             :                         }
    4006           0 :                         ready += 1;  /* this will cause an abrupt return */
    4007           0 :                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
    4008             :                     }
    4009             :                 }
    4010             :             }
    4011             :             else
    4012             :             {
    4013             :                 /* make poll() ignore this entry */
    4014           0 :                 syspoll[index].fd = -1;
    4015           0 :                 syspoll[index].events = 0;
    4016           0 :                 pds[index].out_flags = 0;
    4017             :             }
    4018             :         }
    4019          59 :         if (0 == ready)
    4020             :         {
    4021          59 :             switch (timeout)
    4022             :             {
    4023          12 :             case PR_INTERVAL_NO_WAIT: msecs = 0; break;
    4024          47 :             case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
    4025             :             default:
    4026           0 :                 msecs = PR_IntervalToMilliseconds(timeout);
    4027           0 :                 start = PR_IntervalNow();
    4028             :             }
    4029             : 
    4030             : retry:
    4031          59 :             ready = poll(syspoll, npds, msecs);
    4032          56 :             if (-1 == ready)
    4033             :             {
    4034           0 :                 PRIntn oserror = errno;
    4035             : 
    4036           0 :                 if (EINTR == oserror)
    4037             :                 {
    4038           0 :                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
    4039           0 :                         goto retry;
    4040           0 :                     else if (timeout == PR_INTERVAL_NO_WAIT)
    4041           0 :                         ready = 0;  /* don't retry, just time out */
    4042             :                     else
    4043             :                     {
    4044           0 :                         elapsed = (PRIntervalTime) (PR_IntervalNow()
    4045             :                                 - start);
    4046           0 :                         if (elapsed > timeout)
    4047           0 :                             ready = 0;  /* timed out */
    4048             :                         else
    4049             :                         {
    4050           0 :                             remaining = timeout - elapsed;
    4051           0 :                             msecs = PR_IntervalToMilliseconds(remaining);
    4052           0 :                             goto retry;
    4053             :                         }
    4054             :                     }
    4055             :                 }
    4056             :                 else
    4057             :                 {
    4058           0 :                     _PR_MD_MAP_POLL_ERROR(oserror);
    4059             :                 }
    4060             :             }
    4061          56 :             else if (ready > 0)
    4062             :             {
    4063         114 :                 for (index = 0; index < npds; ++index)
    4064             :                 {
    4065          65 :                     PRInt16 out_flags = 0;
    4066          65 :                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    4067             :                     {
    4068          65 :                         if (0 != syspoll[index].revents)
    4069             :                         {
    4070          49 :                             if (syspoll[index].revents & POLLIN)
    4071             :                             {
    4072          86 :                                 if (pds[index].out_flags
    4073          43 :                                 & _PR_POLL_READ_SYS_READ)
    4074             :                                 {
    4075          43 :                                     out_flags |= PR_POLL_READ;
    4076             :                                 }
    4077          86 :                                 if (pds[index].out_flags
    4078          43 :                                 & _PR_POLL_WRITE_SYS_READ)
    4079             :                                 {
    4080           0 :                                     out_flags |= PR_POLL_WRITE;
    4081             :                                 }
    4082             :                             }
    4083          49 :                             if (syspoll[index].revents & POLLOUT)
    4084             :                             {
    4085          12 :                                 if (pds[index].out_flags
    4086           6 :                                 & _PR_POLL_READ_SYS_WRITE)
    4087             :                                 {
    4088           2 :                                     out_flags |= PR_POLL_READ;
    4089             :                                 }
    4090          12 :                                 if (pds[index].out_flags
    4091           6 :                                 & _PR_POLL_WRITE_SYS_WRITE)
    4092             :                                 {
    4093           6 :                                     out_flags |= PR_POLL_WRITE;
    4094             :                                 }
    4095             :                             }
    4096          49 :                             if (syspoll[index].revents & POLLPRI)
    4097           0 :                                 out_flags |= PR_POLL_EXCEPT;
    4098          49 :                             if (syspoll[index].revents & POLLERR)
    4099           0 :                                 out_flags |= PR_POLL_ERR;
    4100          49 :                             if (syspoll[index].revents & POLLNVAL)
    4101           0 :                                 out_flags |= PR_POLL_NVAL;
    4102          49 :                             if (syspoll[index].revents & POLLHUP)
    4103           0 :                                 out_flags |= PR_POLL_HUP;
    4104             :                         }
    4105             :                     }
    4106          65 :                     pds[index].out_flags = out_flags;
    4107             :                 }
    4108             :             }
    4109             :         }
    4110             :     }
    4111          56 :     return ready;
    4112             : 
    4113             : } /* _pr_poll_with_poll */
    4114             : 
    4115             : #if defined(_PR_POLL_WITH_SELECT)
    4116             : /*
    4117             :  * OSF1 and HPUX report the POLLHUP event for a socket when the
    4118             :  * shutdown(SHUT_WR) operation is called for the remote end, even though
    4119             :  * the socket is still writeable. Use select(), instead of poll(), to
    4120             :  * workaround this problem.
    4121             :  */
    4122             : static PRInt32 _pr_poll_with_select(
    4123             :     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
    4124             : {
    4125             :     PRInt32 ready = 0;
    4126             :     /*
    4127             :      * For restarting select() if it is interrupted by a signal.
    4128             :      * We use these variables to figure out how much time has
    4129             :      * elapsed and how much of the timeout still remains.
    4130             :      */
    4131             :     PRIntervalTime start = 0, elapsed, remaining;
    4132             : 
    4133             :     if (pt_TestAbort()) return -1;
    4134             : 
    4135             :     if (0 == npds) PR_Sleep(timeout);
    4136             :     else
    4137             :     {
    4138             : #define STACK_POLL_DESC_COUNT 64
    4139             :         int stack_selectfd[STACK_POLL_DESC_COUNT];
    4140             :         int *selectfd;
    4141             :                 fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
    4142             :                 struct timeval tv, *tvp;
    4143             :         PRIntn index, msecs, maxfd = 0;
    4144             : 
    4145             :         if (npds <= STACK_POLL_DESC_COUNT)
    4146             :         {
    4147             :             selectfd = stack_selectfd;
    4148             :         }
    4149             :         else
    4150             :         {
    4151             :             PRThread *me = PR_GetCurrentThread();
    4152             :             if (npds > me->selectfd_count)
    4153             :             {
    4154             :                 PR_Free(me->selectfd_list);
    4155             :                 me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
    4156             :                 if (NULL == me->selectfd_list)
    4157             :                 {
    4158             :                     me->selectfd_count = 0;
    4159             :                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    4160             :                     return -1;
    4161             :                 }
    4162             :                 me->selectfd_count = npds;
    4163             :             }
    4164             :             selectfd = me->selectfd_list;
    4165             :         }
    4166             :                 FD_ZERO(&rd);
    4167             :                 FD_ZERO(&wr);
    4168             :                 FD_ZERO(&ex);
    4169             : 
    4170             :         for (index = 0; index < npds; ++index)
    4171             :         {
    4172             :             PRInt16 in_flags_read = 0, in_flags_write = 0;
    4173             :             PRInt16 out_flags_read = 0, out_flags_write = 0;
    4174             : 
    4175             :             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    4176             :             {
    4177             :                 if (pds[index].in_flags & PR_POLL_READ)
    4178             :                 {
    4179             :                     in_flags_read = (pds[index].fd->methods->poll)(
    4180             :                         pds[index].fd,
    4181             :                         pds[index].in_flags & ~PR_POLL_WRITE,
    4182             :                         &out_flags_read);
    4183             :                 }
    4184             :                 if (pds[index].in_flags & PR_POLL_WRITE)
    4185             :                 {
    4186             :                     in_flags_write = (pds[index].fd->methods->poll)(
    4187             :                         pds[index].fd,
    4188             :                         pds[index].in_flags & ~PR_POLL_READ,
    4189             :                         &out_flags_write);
    4190             :                 }
    4191             :                 if ((0 != (in_flags_read & out_flags_read))
    4192             :                 || (0 != (in_flags_write & out_flags_write)))
    4193             :                 {
    4194             :                     /* this one is ready right now */
    4195             :                     if (0 == ready)
    4196             :                     {
    4197             :                         /*
    4198             :                          * We will return without calling the system
    4199             :                          * poll function.  So zero the out_flags
    4200             :                          * fields of all the poll descriptors before
    4201             :                          * this one.
    4202             :                          */
    4203             :                         int i;
    4204             :                         for (i = 0; i < index; i++)
    4205             :                         {
    4206             :                             pds[i].out_flags = 0;
    4207             :                         }
    4208             :                     }
    4209             :                     ready += 1;
    4210             :                     pds[index].out_flags = out_flags_read | out_flags_write;
    4211             :                 }
    4212             :                 else
    4213             :                 {
    4214             :                     /* now locate the NSPR layer at the bottom of the stack */
    4215             :                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
    4216             :                         pds[index].fd, PR_NSPR_IO_LAYER);
    4217             :                     /* ignore a socket without PR_NSPR_IO_LAYER available */
    4218             : 
    4219             :                     pds[index].out_flags = 0;  /* pre-condition */
    4220             :                     if ((NULL != bottom)
    4221             :                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
    4222             :                     {
    4223             :                         if (0 == ready)
    4224             :                         {
    4225             :                             PRBool add_to_rd = PR_FALSE;
    4226             :                             PRBool add_to_wr = PR_FALSE;
    4227             :                             PRBool add_to_ex = PR_FALSE;
    4228             : 
    4229             :                             selectfd[index] = bottom->secret->md.osfd;
    4230             :                             if (in_flags_read & PR_POLL_READ)
    4231             :                             {
    4232             :                                 pds[index].out_flags |=
    4233             :                                     _PR_POLL_READ_SYS_READ;
    4234             :                                 add_to_rd = PR_TRUE;
    4235             :                             }
    4236             :                             if (in_flags_read & PR_POLL_WRITE)
    4237             :                             {
    4238             :                                 pds[index].out_flags |=
    4239             :                                     _PR_POLL_READ_SYS_WRITE;
    4240             :                                 add_to_wr = PR_TRUE;
    4241             :                             }
    4242             :                             if (in_flags_write & PR_POLL_READ)
    4243             :                             {
    4244             :                                 pds[index].out_flags |=
    4245             :                                     _PR_POLL_WRITE_SYS_READ;
    4246             :                                 add_to_rd = PR_TRUE;
    4247             :                             }
    4248             :                             if (in_flags_write & PR_POLL_WRITE)
    4249             :                             {
    4250             :                                 pds[index].out_flags |=
    4251             :                                     _PR_POLL_WRITE_SYS_WRITE;
    4252             :                                 add_to_wr = PR_TRUE;
    4253             :                             }
    4254             :                             if (pds[index].in_flags & PR_POLL_EXCEPT)
    4255             :                             {
    4256             :                                 add_to_ex = PR_TRUE;
    4257             :                             }
    4258             :                             if ((selectfd[index] > maxfd) &&
    4259             :                                     (add_to_rd || add_to_wr || add_to_ex))
    4260             :                             {
    4261             :                                 maxfd = selectfd[index];
    4262             :                                 /*
    4263             :                                  * If maxfd is too large to be used with
    4264             :                                  * select, fall back to calling poll.
    4265             :                                  */
    4266             :                                 if (maxfd >= FD_SETSIZE)
    4267             :                                     break;
    4268             :                             }
    4269             :                             if (add_to_rd)
    4270             :                             {
    4271             :                                 FD_SET(bottom->secret->md.osfd, &rd);
    4272             :                                 rdp = &rd;
    4273             :                             }
    4274             :                             if (add_to_wr)
    4275             :                             {
    4276             :                                 FD_SET(bottom->secret->md.osfd, &wr);
    4277             :                                 wrp = &wr;
    4278             :                             }
    4279             :                             if (add_to_ex)
    4280             :                             {
    4281             :                                 FD_SET(bottom->secret->md.osfd, &ex);
    4282             :                                 exp = &ex;
    4283             :                             }
    4284             :                         }
    4285             :                     }
    4286             :                     else
    4287             :                     {
    4288             :                         if (0 == ready)
    4289             :                         {
    4290             :                             int i;
    4291             :                             for (i = 0; i < index; i++)
    4292             :                             {
    4293             :                                 pds[i].out_flags = 0;
    4294             :                             }
    4295             :                         }
    4296             :                         ready += 1;  /* this will cause an abrupt return */
    4297             :                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
    4298             :                     }
    4299             :                 }
    4300             :             }
    4301             :             else
    4302             :             {
    4303             :                 pds[index].out_flags = 0;
    4304             :             }
    4305             :         }
    4306             :         if (0 == ready)
    4307             :         {
    4308             :                         if (maxfd >= FD_SETSIZE)
    4309             :                         {
    4310             :                                 /*
    4311             :                                  * maxfd too large to be used with select, fall back to
    4312             :                                  * calling poll
    4313             :                                  */
    4314             :                                 return(_pr_poll_with_poll(pds, npds, timeout));
    4315             :                         }
    4316             :             switch (timeout)
    4317             :             {
    4318             :             case PR_INTERVAL_NO_WAIT:
    4319             :                                 tv.tv_sec = 0;
    4320             :                                 tv.tv_usec = 0;
    4321             :                                 tvp = &tv;
    4322             :                                 break;
    4323             :             case PR_INTERVAL_NO_TIMEOUT:
    4324             :                                 tvp = NULL;
    4325             :                                 break;
    4326             :             default:
    4327             :                 msecs = PR_IntervalToMilliseconds(timeout);
    4328             :                                 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
    4329             :                                 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
    4330             :                                 tvp = &tv;
    4331             :                 start = PR_IntervalNow();
    4332             :             }
    4333             : 
    4334             : retry:
    4335             :             ready = select(maxfd + 1, rdp, wrp, exp, tvp);
    4336             :             if (-1 == ready)
    4337             :             {
    4338             :                 PRIntn oserror = errno;
    4339             : 
    4340             :                 if ((EINTR == oserror) || (EAGAIN == oserror))
    4341             :                 {
    4342             :                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
    4343             :                         goto retry;
    4344             :                     else if (timeout == PR_INTERVAL_NO_WAIT)
    4345             :                         ready = 0;  /* don't retry, just time out */
    4346             :                     else
    4347             :                     {
    4348             :                         elapsed = (PRIntervalTime) (PR_IntervalNow()
    4349             :                                 - start);
    4350             :                         if (elapsed > timeout)
    4351             :                             ready = 0;  /* timed out */
    4352             :                         else
    4353             :                         {
    4354             :                             remaining = timeout - elapsed;
    4355             :                             msecs = PR_IntervalToMilliseconds(remaining);
    4356             :                                                         tv.tv_sec = msecs/PR_MSEC_PER_SEC;
    4357             :                                                         tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
    4358             :                                                                                                         PR_USEC_PER_MSEC;
    4359             :                             goto retry;
    4360             :                         }
    4361             :                     }
    4362             :                 } else if (EBADF == oserror)
    4363             :                 {
    4364             :                                         /* find all the bad fds */
    4365             :                                         ready = 0;
    4366             :                         for (index = 0; index < npds; ++index)
    4367             :                                         {
    4368             :                         pds[index].out_flags = 0;
    4369             :                                 if ((NULL != pds[index].fd) &&
    4370             :                                                                                         (0 != pds[index].in_flags))
    4371             :                                                 {
    4372             :                                                         if (fcntl(selectfd[index], F_GETFL, 0) == -1)
    4373             :                                                         {
    4374             :                                         pds[index].out_flags = PR_POLL_NVAL;
    4375             :                                                                 ready++;
    4376             :                                                         }
    4377             :                                                 }
    4378             :                                         }
    4379             :                 } else 
    4380             :                     _PR_MD_MAP_SELECT_ERROR(oserror);
    4381             :             }
    4382             :             else if (ready > 0)
    4383             :             {
    4384             :                 for (index = 0; index < npds; ++index)
    4385             :                 {
    4386             :                     PRInt16 out_flags = 0;
    4387             :                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    4388             :                     {
    4389             :                                                 if (FD_ISSET(selectfd[index], &rd))
    4390             :                                                 {
    4391             :                                                         if (pds[index].out_flags
    4392             :                                                         & _PR_POLL_READ_SYS_READ)
    4393             :                                                         {
    4394             :                                                                 out_flags |= PR_POLL_READ;
    4395             :                                                         }
    4396             :                                                         if (pds[index].out_flags
    4397             :                                                         & _PR_POLL_WRITE_SYS_READ)
    4398             :                                                         {
    4399             :                                                                 out_flags |= PR_POLL_WRITE;
    4400             :                                                         }
    4401             :                                                 }
    4402             :                                                 if (FD_ISSET(selectfd[index], &wr))
    4403             :                                                 {
    4404             :                                                         if (pds[index].out_flags
    4405             :                                                         & _PR_POLL_READ_SYS_WRITE)
    4406             :                                                         {
    4407             :                                                                 out_flags |= PR_POLL_READ;
    4408             :                                                         }
    4409             :                                                         if (pds[index].out_flags
    4410             :                                                         & _PR_POLL_WRITE_SYS_WRITE)
    4411             :                                                         {
    4412             :                                                                 out_flags |= PR_POLL_WRITE;
    4413             :                                                         }
    4414             :                                                 }
    4415             :                                                 if (FD_ISSET(selectfd[index], &ex))
    4416             :                                                         out_flags |= PR_POLL_EXCEPT;
    4417             :                     }
    4418             :                     pds[index].out_flags = out_flags;
    4419             :                 }
    4420             :             }
    4421             :         }
    4422             :     }
    4423             :     return ready;
    4424             : 
    4425             : } /* _pr_poll_with_select */
    4426             : #endif  /* _PR_POLL_WITH_SELECT */
    4427             : 
    4428             : PR_IMPLEMENT(PRInt32) PR_Poll(
    4429             :     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
    4430             : {
    4431             : #if defined(_PR_POLL_WITH_SELECT)
    4432             :         return(_pr_poll_with_select(pds, npds, timeout));
    4433             : #else
    4434          59 :         return(_pr_poll_with_poll(pds, npds, timeout));
    4435             : #endif
    4436             : }
    4437             : 
    4438             : PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
    4439             : {
    4440             :     struct dirent *dp;
    4441             : 
    4442           0 :     if (pt_TestAbort()) return NULL;
    4443             : 
    4444             :     for (;;)
    4445             :     {
    4446           0 :         errno = 0;
    4447           0 :         dp = readdir(dir->md.d);
    4448           0 :         if (NULL == dp)
    4449             :         {
    4450           0 :             pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
    4451           0 :             return NULL;
    4452             :         }
    4453           0 :         if ((flags & PR_SKIP_DOT)
    4454           0 :             && ('.' == dp->d_name[0])
    4455           0 :             && (0 == dp->d_name[1])) continue;
    4456           0 :         if ((flags & PR_SKIP_DOT_DOT)
    4457           0 :             && ('.' == dp->d_name[0])
    4458           0 :             && ('.' == dp->d_name[1])
    4459           0 :             && (0 == dp->d_name[2])) continue;
    4460           0 :         if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
    4461           0 :             continue;
    4462           0 :         break;
    4463             :     }
    4464           0 :     dir->d.name = dp->d_name;
    4465           0 :     return &dir->d;
    4466             : }  /* PR_ReadDir */
    4467             : 
    4468             : PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
    4469             : {
    4470           0 :     PRIntn domain = PF_INET;
    4471             : 
    4472           0 :     return PR_Socket(domain, SOCK_DGRAM, 0);
    4473             : }  /* PR_NewUDPSocket */
    4474             : 
    4475             : PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
    4476             : {
    4477           0 :     PRIntn domain = PF_INET;
    4478             : 
    4479           0 :     return PR_Socket(domain, SOCK_STREAM, 0);
    4480             : }  /* PR_NewTCPSocket */
    4481             : 
    4482             : PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
    4483             : {
    4484           0 :     return PR_Socket(af, SOCK_DGRAM, 0);
    4485             : }  /* PR_NewUDPSocket */
    4486             : 
    4487             : PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
    4488             : {
    4489           3 :     return PR_Socket(af, SOCK_STREAM, 0);
    4490             : }  /* PR_NewTCPSocket */
    4491             : 
    4492             : PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
    4493             : {
    4494             : #ifdef SYMBIAN
    4495             :     /*
    4496             :      * For the platforms that don't have socketpair.
    4497             :      *
    4498             :      * Copied from prsocket.c, with the parameter f[] renamed fds[] and the
    4499             :      * _PR_CONNECT_DOES_NOT_BIND code removed.
    4500             :      */
    4501             :     PRFileDesc *listenSock;
    4502             :     PRNetAddr selfAddr, peerAddr;
    4503             :     PRUint16 port;
    4504             : 
    4505             :     fds[0] = fds[1] = NULL;
    4506             :     listenSock = PR_NewTCPSocket();
    4507             :     if (listenSock == NULL) {
    4508             :         goto failed;
    4509             :     }
    4510             :     PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
    4511             :     if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
    4512             :         goto failed;
    4513             :     }
    4514             :     if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
    4515             :         goto failed;
    4516             :     }
    4517             :     port = ntohs(selfAddr.inet.port);
    4518             :     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
    4519             :         goto failed;
    4520             :     }
    4521             :     fds[0] = PR_NewTCPSocket();
    4522             :     if (fds[0] == NULL) {
    4523             :         goto failed;
    4524             :     }
    4525             :     PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
    4526             : 
    4527             :     /*
    4528             :      * Only a thread is used to do the connect and accept.
    4529             :      * I am relying on the fact that PR_Connect returns
    4530             :      * successfully as soon as the connect request is put
    4531             :      * into the listen queue (but before PR_Accept is called).
    4532             :      * This is the behavior of the BSD socket code.  If
    4533             :      * connect does not return until accept is called, we
    4534             :      * will need to create another thread to call connect.
    4535             :      */
    4536             :     if (PR_Connect(fds[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
    4537             :             == PR_FAILURE) {
    4538             :         goto failed;
    4539             :     }
    4540             :     /*
    4541             :      * A malicious local process may connect to the listening
    4542             :      * socket, so we need to verify that the accepted connection
    4543             :      * is made from our own socket fds[0].
    4544             :      */
    4545             :     if (PR_GetSockName(fds[0], &selfAddr) == PR_FAILURE) {
    4546             :         goto failed;
    4547             :     }
    4548             :     fds[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
    4549             :     if (fds[1] == NULL) {
    4550             :         goto failed;
    4551             :     }
    4552             :     if (peerAddr.inet.port != selfAddr.inet.port) {
    4553             :         /* the connection we accepted is not from fds[0] */
    4554             :         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
    4555             :         goto failed;
    4556             :     }
    4557             :     PR_Close(listenSock);
    4558             :     return PR_SUCCESS;
    4559             : 
    4560             : failed:
    4561             :     if (listenSock) {
    4562             :         PR_Close(listenSock);
    4563             :     }
    4564             :     if (fds[0]) {
    4565             :         PR_Close(fds[0]);
    4566             :     }
    4567             :     if (fds[1]) {
    4568             :         PR_Close(fds[1]);
    4569             :     }
    4570             :     return PR_FAILURE;
    4571             : #else
    4572             :     PRInt32 osfd[2];
    4573             : 
    4574           0 :     if (pt_TestAbort()) return PR_FAILURE;
    4575             : 
    4576           0 :     if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
    4577           0 :         pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
    4578           0 :         return PR_FAILURE;
    4579             :     }
    4580             : 
    4581           0 :     fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
    4582           0 :     if (fds[0] == NULL) {
    4583           0 :         close(osfd[0]);
    4584           0 :         close(osfd[1]);
    4585           0 :         return PR_FAILURE;
    4586             :     }
    4587           0 :     fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
    4588           0 :     if (fds[1] == NULL) {
    4589           0 :         PR_Close(fds[0]);
    4590           0 :         close(osfd[1]);
    4591           0 :         return PR_FAILURE;
    4592             :     }
    4593           0 :     return PR_SUCCESS;
    4594             : #endif
    4595             : }  /* PR_NewTCPSocketPair */
    4596             : 
    4597             : PR_IMPLEMENT(PRStatus) PR_CreatePipe(
    4598             :     PRFileDesc **readPipe,
    4599             :     PRFileDesc **writePipe
    4600             : )
    4601             : {
    4602             :     int pipefd[2];
    4603             : 
    4604           3 :     if (pt_TestAbort()) return PR_FAILURE;
    4605             : 
    4606           3 :     if (pipe(pipefd) == -1)
    4607             :     {
    4608             :     /* XXX map pipe error */
    4609           0 :         PR_SetError(PR_UNKNOWN_ERROR, errno);
    4610           0 :         return PR_FAILURE;
    4611             :     }
    4612           3 :     *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
    4613           3 :     if (NULL == *readPipe)
    4614             :     {
    4615           0 :         close(pipefd[0]);
    4616           0 :         close(pipefd[1]);
    4617           0 :         return PR_FAILURE;
    4618             :     }
    4619           3 :     *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
    4620           3 :     if (NULL == *writePipe)
    4621             :     {
    4622           0 :         PR_Close(*readPipe);
    4623           0 :         close(pipefd[1]);
    4624           0 :         return PR_FAILURE;
    4625             :     }
    4626           3 :     return PR_SUCCESS;
    4627             : }
    4628             : 
    4629             : /*
    4630             : ** Set the inheritance attribute of a file descriptor.
    4631             : */
    4632             : PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
    4633             :     PRFileDesc *fd,
    4634             :     PRBool inheritable)
    4635             : {
    4636             :     /*
    4637             :      * Only a non-layered, NSPR file descriptor can be inherited
    4638             :      * by a child process.
    4639             :      */
    4640           0 :     if (fd->identity != PR_NSPR_IO_LAYER)
    4641             :     {
    4642           0 :         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    4643           0 :         return PR_FAILURE;
    4644             :     }
    4645           0 :     if (fd->secret->inheritable != inheritable)
    4646             :     {
    4647           0 :         if (fcntl(fd->secret->md.osfd, F_SETFD,
    4648             :         inheritable ? 0 : FD_CLOEXEC) == -1)
    4649             :         {
    4650           0 :             _PR_MD_MAP_DEFAULT_ERROR(errno);
    4651           0 :             return PR_FAILURE;
    4652             :         }
    4653           0 :         fd->secret->inheritable = (_PRTriStateBool) inheritable;
    4654             :     }
    4655           0 :     return PR_SUCCESS;
    4656             : }
    4657             : 
    4658             : /*****************************************************************************/
    4659             : /***************************** I/O friends methods ***************************/
    4660             : /*****************************************************************************/
    4661             : 
    4662           2 : PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
    4663             : {
    4664             :     PRFileDesc *fd;
    4665             : 
    4666           2 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    4667           2 :     fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
    4668           2 :     if (NULL == fd) close(osfd);
    4669           2 :     return fd;
    4670             : }  /* PR_ImportFile */
    4671             : 
    4672           0 : PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
    4673             : {
    4674             :     PRFileDesc *fd;
    4675             : 
    4676           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    4677           0 :     fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
    4678           0 :     if (NULL == fd) close(osfd);
    4679           0 :     return fd;
    4680             : }  /* PR_ImportPipe */
    4681             : 
    4682           0 : PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
    4683             : {
    4684             :     PRFileDesc *fd;
    4685             : 
    4686           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    4687           0 :     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
    4688           0 :     if (NULL == fd) close(osfd);
    4689             : #ifdef _PR_NEED_SECRET_AF
    4690             :     if (NULL != fd) fd->secret->af = PF_INET;
    4691             : #endif
    4692           0 :     return fd;
    4693             : }  /* PR_ImportTCPSocket */
    4694             : 
    4695           0 : PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
    4696             : {
    4697             :     PRFileDesc *fd;
    4698             : 
    4699           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    4700           0 :     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
    4701           0 :     if (NULL == fd) close(osfd);
    4702           0 :     return fd;
    4703             : }  /* PR_ImportUDPSocket */
    4704             : 
    4705           0 : PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
    4706             : {
    4707             :     PRFileDesc *fd;
    4708             : 
    4709           0 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    4710             : 
    4711           0 :     fd = _PR_Getfd();
    4712             : 
    4713           0 :     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    4714             :     else
    4715             :     {
    4716           0 :         fd->secret->md.osfd = osfd;
    4717           0 :         fd->secret->inheritable = _PR_TRI_FALSE;
    4718           0 :         fd->secret->state = _PR_FILEDESC_OPEN;
    4719           0 :         fd->methods = PR_GetSocketPollFdMethods();
    4720             :     }
    4721             : 
    4722           0 :     return fd;
    4723             : }  /* PR_CreateSocketPollFD */
    4724             : 
    4725           0 : PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
    4726             : {
    4727           0 :     if (NULL == fd)
    4728             :     {
    4729           0 :         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    4730           0 :         return PR_FAILURE;
    4731             :     }
    4732           0 :     fd->secret->state = _PR_FILEDESC_CLOSED;
    4733           0 :     _PR_Putfd(fd);
    4734           0 :     return PR_SUCCESS;
    4735             : }  /* PR_DestroySocketPollFd */
    4736             : 
    4737          80 : PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
    4738             : {
    4739          80 :     PRInt32 osfd = -1;
    4740          80 :     bottom = (NULL == bottom) ?
    4741          80 :         NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
    4742          80 :     if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    4743          80 :     else osfd = bottom->secret->md.osfd;
    4744          80 :     return osfd;
    4745             : }  /* PR_FileDesc2NativeHandle */
    4746             : 
    4747           0 : PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
    4748             :     PRInt32 handle)
    4749             : {
    4750           0 :     if (fd) fd->secret->md.osfd = handle;
    4751           0 : }  /*  PR_ChangeFileDescNativeHandle*/
    4752             : 
    4753           0 : PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
    4754             : {
    4755           0 :     PRStatus status = PR_SUCCESS;
    4756             : 
    4757           0 :     if (pt_TestAbort()) return PR_FAILURE;
    4758             : 
    4759           0 :     PR_Lock(_pr_flock_lock);
    4760           0 :     while (-1 == fd->secret->lockCount)
    4761           0 :         PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
    4762           0 :     if (0 == fd->secret->lockCount)
    4763             :     {
    4764           0 :         fd->secret->lockCount = -1;
    4765           0 :         PR_Unlock(_pr_flock_lock);
    4766           0 :         status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
    4767           0 :         PR_Lock(_pr_flock_lock);
    4768           0 :         fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
    4769           0 :         PR_NotifyAllCondVar(_pr_flock_cv);
    4770             :     }
    4771             :     else
    4772             :     {
    4773           0 :         fd->secret->lockCount += 1;
    4774             :     }
    4775           0 :     PR_Unlock(_pr_flock_lock);
    4776             :  
    4777           0 :     return status;
    4778             : }  /* PR_LockFile */
    4779             : 
    4780           0 : PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
    4781             : {
    4782           0 :     PRStatus status = PR_SUCCESS;
    4783             : 
    4784           0 :     if (pt_TestAbort()) return PR_FAILURE;
    4785             : 
    4786           0 :     PR_Lock(_pr_flock_lock);
    4787           0 :     if (0 == fd->secret->lockCount)
    4788             :     {
    4789           0 :         status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
    4790           0 :         if (PR_SUCCESS == status) fd->secret->lockCount = 1;
    4791             :     }
    4792           0 :     else fd->secret->lockCount += 1;
    4793           0 :     PR_Unlock(_pr_flock_lock);
    4794             :  
    4795           0 :     return status;
    4796             : }  /* PR_TLockFile */
    4797             : 
    4798           0 : PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
    4799             : {
    4800           0 :     PRStatus status = PR_SUCCESS;
    4801             : 
    4802           0 :     if (pt_TestAbort()) return PR_FAILURE;
    4803             : 
    4804           0 :     PR_Lock(_pr_flock_lock);
    4805           0 :     if (fd->secret->lockCount == 1)
    4806             :     {
    4807           0 :         status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
    4808           0 :         if (PR_SUCCESS == status) fd->secret->lockCount = 0;
    4809             :     }
    4810           0 :     else fd->secret->lockCount -= 1;
    4811           0 :     PR_Unlock(_pr_flock_lock);
    4812             : 
    4813           0 :     return status;
    4814             : }
    4815             : 
    4816             : /*
    4817             :  * The next two entry points should not be in the API, but they are
    4818             :  * defined here for historical (or hysterical) reasons.
    4819             :  */
    4820             : 
    4821           0 : PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
    4822             : {
    4823             : #if defined(AIX) || defined(SYMBIAN)
    4824             :     return sysconf(_SC_OPEN_MAX);
    4825             : #else
    4826             :     struct rlimit rlim;
    4827             : 
    4828           0 :     if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
    4829           0 :        return -1;
    4830             : 
    4831           0 :     return rlim.rlim_max;
    4832             : #endif
    4833             : }
    4834             : 
    4835           0 : PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
    4836             : {
    4837             : #if defined(AIX) || defined(SYMBIAN)
    4838             :     return -1;
    4839             : #else
    4840             :     struct rlimit rlim;
    4841           0 :     PRInt32 tableMax = PR_GetSysfdTableMax();
    4842             : 
    4843           0 :     if (tableMax < 0) return -1;
    4844           0 :     rlim.rlim_max = tableMax;
    4845             : 
    4846             :     /* Grow as much as we can; even if too big */
    4847           0 :     if ( rlim.rlim_max < table_size )
    4848           0 :         rlim.rlim_cur = rlim.rlim_max;
    4849             :     else
    4850           0 :         rlim.rlim_cur = table_size;
    4851             : 
    4852           0 :     if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
    4853           0 :         return -1;
    4854             : 
    4855           0 :     return rlim.rlim_cur;
    4856             : #endif
    4857             : }
    4858             : 
    4859             : /*
    4860             :  * PR_Stat is supported for backward compatibility; some existing Java
    4861             :  * code uses it.  New code should use PR_GetFileInfo.
    4862             :  */
    4863             : 
    4864             : #ifndef NO_NSPR_10_SUPPORT
    4865             : PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
    4866             : {
    4867             :     static PRBool unwarned = PR_TRUE;
    4868             :     if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
    4869             : 
    4870             :     if (pt_TestAbort()) return -1;
    4871             : 
    4872             :     if (-1 == stat(name, buf)) {
    4873             :         pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
    4874             :         return -1;
    4875             :     } else {
    4876             :         return 0;
    4877             :     }
    4878             : }
    4879             : #endif /* ! NO_NSPR_10_SUPPORT */
    4880             : 
    4881             : 
    4882           0 : PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
    4883             : {
    4884             :     static PRBool unwarned = PR_TRUE;
    4885           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
    4886           0 :     memset(set, 0, sizeof(PR_fd_set));
    4887           0 : }
    4888             : 
    4889           0 : PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
    4890             : {
    4891             :     static PRBool unwarned = PR_TRUE;
    4892           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
    4893           0 :     PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
    4894             : 
    4895           0 :     set->harray[set->hsize++] = fh;
    4896           0 : }
    4897             : 
    4898           0 : PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
    4899             : {
    4900             :     PRUint32 index, index2;
    4901             :     static PRBool unwarned = PR_TRUE;
    4902           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
    4903             : 
    4904           0 :     for (index = 0; index<set->hsize; index++)
    4905           0 :        if (set->harray[index] == fh) {
    4906           0 :            for (index2=index; index2 < (set->hsize-1); index2++) {
    4907           0 :                set->harray[index2] = set->harray[index2+1];
    4908             :            }
    4909           0 :            set->hsize--;
    4910           0 :            break;
    4911             :        }
    4912           0 : }
    4913             : 
    4914           0 : PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
    4915             : {
    4916             :     PRUint32 index;
    4917             :     static PRBool unwarned = PR_TRUE;
    4918           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
    4919           0 :     for (index = 0; index<set->hsize; index++)
    4920           0 :        if (set->harray[index] == fh) {
    4921           0 :            return 1;
    4922             :        }
    4923           0 :     return 0;
    4924             : }
    4925             : 
    4926           0 : PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
    4927             : {
    4928             :     static PRBool unwarned = PR_TRUE;
    4929           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
    4930           0 :     PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
    4931             : 
    4932           0 :     set->narray[set->nsize++] = fd;
    4933           0 : }
    4934             : 
    4935           0 : PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
    4936             : {
    4937             :     PRUint32 index, index2;
    4938             :     static PRBool unwarned = PR_TRUE;
    4939           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
    4940             : 
    4941           0 :     for (index = 0; index<set->nsize; index++)
    4942           0 :        if (set->narray[index] == fd) {
    4943           0 :            for (index2=index; index2 < (set->nsize-1); index2++) {
    4944           0 :                set->narray[index2] = set->narray[index2+1];
    4945             :            }
    4946           0 :            set->nsize--;
    4947           0 :            break;
    4948             :        }
    4949           0 : }
    4950             : 
    4951           0 : PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
    4952             : {
    4953             :     PRUint32 index;
    4954             :     static PRBool unwarned = PR_TRUE;
    4955           0 :     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
    4956           0 :     for (index = 0; index<set->nsize; index++)
    4957           0 :        if (set->narray[index] == fd) {
    4958           0 :            return 1;
    4959             :        }
    4960           0 :     return 0;
    4961             : }
    4962             : 
    4963             : #include <sys/types.h>
    4964             : #include <sys/time.h>
    4965             : #if !defined(HPUX) \
    4966             :     && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
    4967             : #include <sys/select.h>
    4968             : #endif
    4969             : 
    4970             : static PRInt32
    4971           0 : _PR_getset(PR_fd_set *pr_set, fd_set *set)
    4972             : {
    4973             :     PRUint32 index;
    4974           0 :     PRInt32 max = 0;
    4975             : 
    4976           0 :     if (!pr_set)
    4977           0 :         return 0;
    4978             :    
    4979           0 :     FD_ZERO(set);
    4980             : 
    4981             :     /* First set the pr file handle osfds */
    4982           0 :     for (index=0; index<pr_set->hsize; index++) {
    4983           0 :         FD_SET(pr_set->harray[index]->secret->md.osfd, set);
    4984           0 :         if (pr_set->harray[index]->secret->md.osfd > max)
    4985           0 :             max = pr_set->harray[index]->secret->md.osfd;
    4986             :     }
    4987             :     /* Second set the native osfds */
    4988           0 :     for (index=0; index<pr_set->nsize; index++) {
    4989           0 :         FD_SET(pr_set->narray[index], set);
    4990           0 :         if (pr_set->narray[index] > max)
    4991           0 :             max = pr_set->narray[index];
    4992             :     }
    4993           0 :     return max;
    4994             : }
    4995             : 
    4996             : static void
    4997           0 : _PR_setset(PR_fd_set *pr_set, fd_set *set)
    4998             : {
    4999             :     PRUint32 index, last_used;
    5000             : 
    5001           0 :     if (!pr_set)
    5002           0 :         return;
    5003             : 
    5004           0 :     for (last_used=0, index=0; index<pr_set->hsize; index++) {
    5005           0 :         if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
    5006           0 :             pr_set->harray[last_used++] = pr_set->harray[index];
    5007             :         }
    5008             :     }
    5009           0 :     pr_set->hsize = last_used;
    5010             : 
    5011           0 :     for (last_used=0, index=0; index<pr_set->nsize; index++) {
    5012           0 :         if ( FD_ISSET(pr_set->narray[index], set) ) {
    5013           0 :             pr_set->narray[last_used++] = pr_set->narray[index];
    5014             :         }
    5015             :     }
    5016           0 :     pr_set->nsize = last_used;
    5017             : }
    5018             : 
    5019           0 : PR_IMPLEMENT(PRInt32) PR_Select(
    5020             :     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
    5021             :     PR_fd_set *pr_ex, PRIntervalTime timeout)
    5022             : {
    5023             :     fd_set rd, wr, ex;
    5024             :     struct timeval tv, *tvp;
    5025             :     PRInt32 max, max_fd;
    5026             :     PRInt32 rv;
    5027             :     /*
    5028             :      * For restarting select() if it is interrupted by a Unix signal.
    5029             :      * We use these variables to figure out how much time has elapsed
    5030             :      * and how much of the timeout still remains.
    5031             :      */
    5032           0 :     PRIntervalTime start = 0, elapsed, remaining;
    5033             : 
    5034             :     static PRBool unwarned = PR_TRUE;
    5035           0 :     if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
    5036             : 
    5037           0 :     FD_ZERO(&rd);
    5038           0 :     FD_ZERO(&wr);
    5039           0 :     FD_ZERO(&ex);
    5040             : 
    5041           0 :     max_fd = _PR_getset(pr_rd, &rd);
    5042           0 :     max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
    5043           0 :     max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
    5044             : 
    5045           0 :     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
    5046           0 :         tvp = NULL;
    5047             :     } else {
    5048           0 :         tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
    5049           0 :         tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
    5050           0 :                 timeout - PR_SecondsToInterval(tv.tv_sec));
    5051           0 :         tvp = &tv;
    5052           0 :         start = PR_IntervalNow();
    5053             :     }
    5054             : 
    5055             : retry:
    5056           0 :     rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
    5057             :         (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
    5058             : 
    5059           0 :     if (rv == -1 && errno == EINTR) {
    5060           0 :         if (timeout == PR_INTERVAL_NO_TIMEOUT) {
    5061           0 :             goto retry;
    5062             :         } else {
    5063           0 :             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
    5064           0 :             if (elapsed > timeout) {
    5065           0 :                 rv = 0;  /* timed out */
    5066             :             } else {
    5067           0 :                 remaining = timeout - elapsed;
    5068           0 :                 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
    5069           0 :                 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
    5070           0 :                         remaining - PR_SecondsToInterval(tv.tv_sec));
    5071           0 :                 goto retry;
    5072             :             }
    5073             :         }
    5074             :     }
    5075             : 
    5076           0 :     if (rv > 0) {
    5077           0 :         _PR_setset(pr_rd, &rd);
    5078           0 :         _PR_setset(pr_wr, &wr);
    5079           0 :         _PR_setset(pr_ex, &ex);
    5080           0 :     } else if (rv == -1) {
    5081           0 :         pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
    5082             :     }
    5083           0 :     return rv;
    5084             : }
    5085             : #endif /* defined(_PR_PTHREADS) */
    5086             : 
    5087             : #ifdef MOZ_UNICODE 
    5088             : /* ================ UTF16 Interfaces ================================ */
    5089             : PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
    5090             :     const PRUnichar *name, PRIntn flags, PRIntn mode)
    5091             : {
    5092             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    5093             :     return NULL;
    5094             : }
    5095             : 
    5096             : PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
    5097             : {
    5098             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    5099             :     return PR_FAILURE;
    5100             : }
    5101             : 
    5102             : PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
    5103             : {
    5104             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    5105             :     return NULL;
    5106             : }
    5107             : 
    5108             : PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
    5109             : {
    5110             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    5111             :     return NULL;
    5112             : }
    5113             : 
    5114             : PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
    5115             : {
    5116             :     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    5117             :     return PR_FAILURE;
    5118             : }
    5119             : /* ================ UTF16 Interfaces ================================ */
    5120             : #endif /* MOZ_UNICODE */
    5121             : 
    5122             : /* ptio.c */

Generated by: LCOV version 1.13