Back to index

lightning-sunbird  0.9+nobinonly
ptio.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** File:   ptio.c
00040 ** Descritpion:  Implemenation of I/O methods for pthreads
00041 */
00042 
00043 #if defined(_PR_PTHREADS)
00044 
00045 #if defined(_PR_POLL_WITH_SELECT)
00046 #if !(defined(HPUX) && defined(_USE_BIG_FDS))
00047 /* set fd limit for select(), before including system header files */
00048 #define FD_SETSIZE (16 * 1024)
00049 #endif
00050 #endif
00051 
00052 #include <pthread.h>
00053 #include <string.h>  /* for memset() */
00054 #include <sys/types.h>
00055 #include <dirent.h>
00056 #include <fcntl.h>
00057 #include <unistd.h>
00058 #include <sys/socket.h>
00059 #include <sys/stat.h>
00060 #include <sys/uio.h>
00061 #include <sys/file.h>
00062 #include <sys/ioctl.h>
00063 #if defined(DARWIN)
00064 #include <sys/utsname.h> /* for uname */
00065 #endif
00066 #if defined(SOLARIS) || defined(UNIXWARE)
00067 #include <sys/filio.h>  /* to pick up FIONREAD */
00068 #endif
00069 #ifdef _PR_POLL_AVAILABLE
00070 #include <poll.h>
00071 #endif
00072 #ifdef AIX
00073 /* To pick up sysconf() */
00074 #include <unistd.h>
00075 #include <dlfcn.h>  /* for dlopen */
00076 #else
00077 /* To pick up getrlimit() etc. */
00078 #include <sys/time.h>
00079 #include <sys/resource.h>
00080 #endif
00081 
00082 #ifdef SOLARIS
00083 /*
00084  * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
00085  * Code built this way won't run on a system without sendfilev().
00086  * We can define HAVE_SENDFILEV by default when the minimum release
00087  * of Solaris that NSPR supports has sendfilev().
00088  */
00089 #ifdef HAVE_SENDFILEV
00090 
00091 #include <sys/sendfile.h>
00092 
00093 #define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
00094 
00095 #else
00096 
00097 #include <dlfcn.h>  /* for dlopen */
00098 
00099 /*
00100  * Match the definitions in <sys/sendfile.h>.
00101  */
00102 typedef struct sendfilevec {
00103     int sfv_fd;       /* input fd */
00104     uint_t sfv_flag;  /* flags */
00105     off_t sfv_off;    /* offset to start reading from */
00106     size_t sfv_len;   /* amount of data */
00107 } sendfilevec_t;
00108 
00109 #define SFV_FD_SELF (-2)
00110 
00111 /*
00112  * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
00113  */
00114 static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
00115 
00116 #define SOLARIS_SENDFILEV(a, b, c, d) \
00117         (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
00118 
00119 #endif /* HAVE_SENDFILEV */
00120 #endif /* SOLARIS */
00121 
00122 /*
00123  * The send_file() system call is available in AIX 4.3.2 or later.
00124  * If this file is compiled on an older AIX system, it attempts to
00125  * look up the send_file symbol at run time to determine whether
00126  * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
00127  * send_file().  On AIX 4.3.2 or later, we can safely skip this
00128  * runtime function dispatching and just use the send_file based
00129  * implementation.
00130  */
00131 #ifdef AIX
00132 #ifdef SF_CLOSE
00133 #define HAVE_SEND_FILE
00134 #endif
00135 
00136 #ifdef HAVE_SEND_FILE
00137 
00138 #define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
00139 
00140 #else /* HAVE_SEND_FILE */
00141 
00142 /*
00143  * The following definitions match those in <sys/socket.h>
00144  * on AIX 4.3.2.
00145  */
00146 
00147 /*
00148  * Structure for the send_file() system call
00149  */
00150 struct sf_parms {
00151     /* --------- header parms ---------- */
00152     void      *header_data;         /* Input/Output. Points to header buf */
00153     uint_t    header_length;        /* Input/Output. Length of the header */
00154     /* --------- file parms ------------ */
00155     int       file_descriptor;      /* Input. File descriptor of the file */
00156     unsigned long long file_size;   /* Output. Size of the file */
00157     unsigned long long file_offset; /* Input/Output. Starting offset */
00158     long long file_bytes;           /* Input/Output. no. of bytes to send */
00159     /* --------- trailer parms --------- */
00160     void      *trailer_data;        /* Input/Output. Points to trailer buf */
00161     uint_t    trailer_length;       /* Input/Output. Length of the trailer */
00162     /* --------- return info ----------- */
00163     unsigned long long bytes_sent;  /* Output. no. of bytes sent */
00164 };
00165 
00166 /*
00167  * Flags for the send_file() system call
00168  */
00169 #define SF_CLOSE        0x00000001      /* close the socket after completion */
00170 #define SF_REUSE        0x00000002      /* reuse socket. not supported */
00171 #define SF_DONT_CACHE   0x00000004      /* don't apply network buffer cache */
00172 #define SF_SYNC_CACHE   0x00000008      /* sync/update network buffer cache */
00173 
00174 /*
00175  * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
00176  */
00177 static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
00178 
00179 #define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
00180 
00181 #endif /* HAVE_SEND_FILE */
00182 #endif /* AIX */
00183 
00184 #ifdef LINUX
00185 #include <sys/sendfile.h>
00186 #endif
00187 
00188 #include "primpl.h"
00189 
00190 #include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
00191 #ifdef LINUX
00192 /* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
00193 #ifndef TCP_CORK
00194 #define TCP_CORK 3
00195 #endif
00196 #endif
00197 
00198 #ifdef _PR_IPV6_V6ONLY_PROBE
00199 static PRBool _pr_ipv6_v6only_on_by_default;
00200 #endif
00201 
00202 #if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
00203 #define _PRSelectFdSetArg_t int *
00204 #elif defined(AIX4_1)
00205 #define _PRSelectFdSetArg_t void *
00206 #elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
00207     || defined(OSF1) || defined(SOLARIS) \
00208     || defined(HPUX10_30) || defined(HPUX11) || defined(LINUX) \
00209     || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
00210     || defined(BSDI) || defined(VMS) || defined(NTO) || defined(DARWIN) \
00211     || defined(UNIXWARE) || defined(RISCOS)
00212 #define _PRSelectFdSetArg_t fd_set *
00213 #else
00214 #error "Cannot determine architecture"
00215 #endif
00216 
00217 static PRFileDesc *pt_SetMethods(
00218     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
00219 
00220 static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
00221 static PRCondVar *_pr_flock_cv;  /* For PR_LockFile() etc. */
00222 static PRLock *_pr_rename_lock;  /* For PR_Rename() */
00223 
00224 /**************************************************************************/
00225 
00226 /* These two functions are only used in assertions. */
00227 #if defined(DEBUG)
00228 
00229 PRBool IsValidNetAddr(const PRNetAddr *addr)
00230 {
00231     if ((addr != NULL)
00232             && (addr->raw.family != AF_UNIX)
00233             && (addr->raw.family != PR_AF_INET6)
00234             && (addr->raw.family != AF_INET)) {
00235         return PR_FALSE;
00236     }
00237     return PR_TRUE;
00238 }
00239 
00240 static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
00241 {
00242     /*
00243      * The definition of the length of a Unix domain socket address
00244      * is not uniform, so we don't check it.
00245      */
00246     if ((addr != NULL)
00247             && (addr->raw.family != AF_UNIX)
00248             && (PR_NETADDR_SIZE(addr) != addr_len)) {
00249 #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
00250         /*
00251          * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
00252          * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
00253          * field and is 28 bytes.  It is possible for socket functions
00254          * to return an addr_len greater than sizeof(struct sockaddr_in6).
00255          * We need to allow that.  (Bugzilla bug #77264)
00256          */
00257         if ((PR_AF_INET6 == addr->raw.family)
00258                 && (sizeof(addr->ipv6) == addr_len)) {
00259             return PR_TRUE;
00260         }
00261 #endif
00262         return PR_FALSE;
00263     }
00264     return PR_TRUE;
00265 }
00266 
00267 #endif /* DEBUG */
00268 
00269 /*****************************************************************************/
00270 /************************* I/O Continuation machinery ************************/
00271 /*****************************************************************************/
00272 
00273 /*
00274  * The polling interval defines the maximum amount of time that a thread
00275  * might hang up before an interrupt is noticed.
00276  */
00277 #define PT_DEFAULT_POLL_MSEC 5000
00278 #if defined(_PR_POLL_WITH_SELECT)
00279 #define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
00280 #define PT_DEFAULT_SELECT_USEC                                               \
00281               ((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
00282 #endif
00283 
00284 /*
00285  * pt_SockLen is the type for the length of a socket address
00286  * structure, used in the address length argument to bind,
00287  * connect, accept, getsockname, getpeername, etc.  Posix.1g
00288  * defines this type as socklen_t.  It is size_t or int on
00289  * most current systems.
00290  */
00291 #if defined(HAVE_SOCKLEN_T) \
00292     || (defined(LINUX) && defined(__GLIBC__) && __GLIBC__ >= 2)
00293 typedef socklen_t pt_SockLen;
00294 #elif (defined(AIX) && !defined(AIX4_1)) \
00295     || defined(VMS)
00296 typedef PRSize pt_SockLen;
00297 #else
00298 typedef PRIntn pt_SockLen;
00299 #endif
00300 
00301 typedef struct pt_Continuation pt_Continuation;
00302 typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
00303 
00304 typedef enum pr_ContuationStatus
00305 {
00306     pt_continuation_pending,
00307     pt_continuation_done
00308 } pr_ContuationStatus;
00309 
00310 struct pt_Continuation
00311 {
00312     /* The building of the continuation operation */
00313     ContinuationFn function;                /* what function to continue */
00314     union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
00315     union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
00316     union {
00317         PRSize amount;                      /* #3 - size of 'buffer', or */
00318         pt_SockLen *addr_len;                  /*    - length of address */
00319 #ifdef HPUX11
00320         /*
00321          * For sendfile()
00322          */
00323               struct file_spec {          
00324               off_t offset;                       /* offset in file to send */
00325               size_t nbytes;                      /* length of file data to send */
00326               size_t st_size;                     /* file size */
00327               } file_spec;
00328 #endif
00329     } arg3;
00330     union { PRIntn flags; } arg4;           /* #4 - read/write flags */
00331     union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
00332 
00333 #ifdef HPUX11
00334     /*
00335      * For sendfile()
00336      */
00337     int filedesc;                           /* descriptor of file to send */
00338     int nbytes_to_send;                     /* size of header and file */
00339 #endif  /* HPUX11 */
00340     
00341 #ifdef SOLARIS
00342     /*
00343      * For sendfilev()
00344      */
00345     int nbytes_to_send;                     /* size of header and file */
00346 #endif  /* SOLARIS */
00347 
00348 #ifdef LINUX
00349     /*
00350      * For sendfile()
00351      */
00352     int in_fd;                              /* descriptor of file to send */
00353     off_t offset;
00354     size_t count;
00355 #endif  /* LINUX */
00356  
00357     PRIntervalTime timeout;                 /* client (relative) timeout */
00358 
00359     PRInt16 event;                           /* flags for poll()'s events */
00360 
00361     /*
00362     ** The representation and notification of the results of the operation.
00363     ** These function can either return an int return code or a pointer to
00364     ** some object.
00365     */
00366     union { PRSize code; void *object; } result;
00367 
00368     PRIntn syserrno;                        /* in case it failed, why (errno) */
00369     pr_ContuationStatus status;             /* the status of the operation */
00370 };
00371 
00372 #if defined(DEBUG)
00373 
00374 PTDebug pt_debug;  /* this is shared between several modules */
00375 
00376 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
00377 {
00378     PTDebug stats;
00379     char buffer[100];
00380     PRExplodedTime tod;
00381     PRInt64 elapsed, aMil;
00382     stats = pt_debug;  /* a copy */
00383     PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
00384     (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
00385 
00386     LL_SUB(elapsed, PR_Now(), stats.timeStarted);
00387     LL_I2L(aMil, 1000000);
00388     LL_DIV(elapsed, elapsed, aMil);
00389     
00390     if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
00391     PR_fprintf(
00392         debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
00393     PR_fprintf(
00394         debug_out, "\tlocks [created: %u, destroyed: %u]\n",
00395         stats.locks_created, stats.locks_destroyed);
00396     PR_fprintf(
00397         debug_out, "\tlocks [acquired: %u, released: %u]\n",
00398         stats.locks_acquired, stats.locks_released);
00399     PR_fprintf(
00400         debug_out, "\tcvars [created: %u, destroyed: %u]\n",
00401         stats.cvars_created, stats.cvars_destroyed);
00402     PR_fprintf(
00403         debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
00404         stats.cvars_notified, stats.delayed_cv_deletes);
00405 }  /* PT_FPrintStats */
00406 
00407 #else
00408 
00409 PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
00410 {
00411     /* do nothing */
00412 }  /* PT_FPrintStats */
00413 
00414 #endif  /* DEBUG */
00415 
00416 #if defined(_PR_POLL_WITH_SELECT)
00417 /*
00418  * OSF1 and HPUX report the POLLHUP event for a socket when the
00419  * shutdown(SHUT_WR) operation is called for the remote end, even though
00420  * the socket is still writeable. Use select(), instead of poll(), to
00421  * workaround this problem.
00422  */
00423 static void pt_poll_now_with_select(pt_Continuation *op)
00424 {
00425     PRInt32 msecs;
00426        fd_set rd, wr, *rdp, *wrp;
00427        struct timeval tv;
00428        PRIntervalTime epoch, now, elapsed, remaining;
00429        PRBool wait_for_remaining;
00430     PRThread *self = PR_GetCurrentThread();
00431     
00432        PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
00433        PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
00434 
00435     switch (op->timeout) {
00436         case PR_INTERVAL_NO_TIMEOUT:
00437                      tv.tv_sec = PT_DEFAULT_SELECT_SEC;
00438                      tv.tv_usec = PT_DEFAULT_SELECT_USEC;
00439                      do
00440                      {
00441                             PRIntn rv;
00442 
00443                             if (op->event & POLLIN) {
00444                                    FD_ZERO(&rd);
00445                                    FD_SET(op->arg1.osfd, &rd);
00446                                    rdp = &rd;
00447                             } else
00448                                    rdp = NULL;
00449                             if (op->event & POLLOUT) {
00450                                    FD_ZERO(&wr);
00451                                    FD_SET(op->arg1.osfd, &wr);
00452                                    wrp = &wr;
00453                             } else
00454                                    wrp = NULL;
00455 
00456                             rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
00457 
00458                             if (self->state & PT_THREAD_ABORTED)
00459                             {
00460                                    self->state &= ~PT_THREAD_ABORTED;
00461                                    op->result.code = -1;
00462                                    op->syserrno = EINTR;
00463                                    op->status = pt_continuation_done;
00464                                    return;
00465                             }
00466 
00467                             if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
00468                                    continue; /* go around the loop again */
00469 
00470                             if (rv > 0)
00471                             {
00472                                    PRInt16 revents = 0;
00473 
00474                                    if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
00475                                           revents |= POLLIN;
00476                                    if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
00477                                           revents |= POLLOUT;
00478                                           
00479                                    if (op->function(op, revents))
00480                                           op->status = pt_continuation_done;
00481                             } else if (rv == -1) {
00482                                    op->result.code = -1;
00483                                    op->syserrno = errno;
00484                                    op->status = pt_continuation_done;
00485                             }
00486                             /* else, select timed out */
00487                      } while (pt_continuation_done != op->status);
00488                      break;
00489         default:
00490             now = epoch = PR_IntervalNow();
00491             remaining = op->timeout;
00492                      do
00493                      {
00494                             PRIntn rv;
00495 
00496                             if (op->event & POLLIN) {
00497                                    FD_ZERO(&rd);
00498                                    FD_SET(op->arg1.osfd, &rd);
00499                                    rdp = &rd;
00500                             } else
00501                                    rdp = NULL;
00502                             if (op->event & POLLOUT) {
00503                                    FD_ZERO(&wr);
00504                                    FD_SET(op->arg1.osfd, &wr);
00505                                    wrp = &wr;
00506                             } else
00507                                    wrp = NULL;
00508 
00509                      wait_for_remaining = PR_TRUE;
00510                      msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
00511                             if (msecs > PT_DEFAULT_POLL_MSEC) {
00512                                    wait_for_remaining = PR_FALSE;
00513                                    msecs = PT_DEFAULT_POLL_MSEC;
00514                             }
00515                             tv.tv_sec = msecs/PR_MSEC_PER_SEC;
00516                             tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
00517                             rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
00518 
00519                             if (self->state & PT_THREAD_ABORTED)
00520                             {
00521                                    self->state &= ~PT_THREAD_ABORTED;
00522                                    op->result.code = -1;
00523                                    op->syserrno = EINTR;
00524                                    op->status = pt_continuation_done;
00525                                    return;
00526                             }
00527 
00528                             if (rv > 0) {
00529                                    PRInt16 revents = 0;
00530 
00531                                    if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
00532                                           revents |= POLLIN;
00533                                    if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
00534                                           revents |= POLLOUT;
00535                                           
00536                                    if (op->function(op, revents))
00537                                           op->status = pt_continuation_done;
00538 
00539                             } else if ((rv == 0) ||
00540                                           ((errno == EINTR) || (errno == EAGAIN))) {
00541                                    if (rv == 0) {       /* select timed out */
00542                                           if (wait_for_remaining)
00543                                                  now += remaining;
00544                                           else
00545                                                  now += PR_MillisecondsToInterval(msecs);
00546                                    } else
00547                                           now = PR_IntervalNow();
00548                                    elapsed = (PRIntervalTime) (now - epoch);
00549                                    if (elapsed >= op->timeout) {
00550                                           op->result.code = -1;
00551                                           op->syserrno = ETIMEDOUT;
00552                                           op->status = pt_continuation_done;
00553                                    } else
00554                                           remaining = op->timeout - elapsed;
00555                             } else {
00556                                    op->result.code = -1;
00557                                    op->syserrno = errno;
00558                                    op->status = pt_continuation_done;
00559                             }
00560                      } while (pt_continuation_done != op->status);
00561             break;
00562     }
00563 
00564 }  /* pt_poll_now_with_select */
00565 
00566 #endif /* _PR_POLL_WITH_SELECT */
00567 
00568 static void pt_poll_now(pt_Continuation *op)
00569 {
00570     PRInt32 msecs;
00571        PRIntervalTime epoch, now, elapsed, remaining;
00572        PRBool wait_for_remaining;
00573     PRThread *self = PR_GetCurrentThread();
00574     
00575        PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
00576 #if defined (_PR_POLL_WITH_SELECT)
00577        /*
00578         * If the fd is small enough call the select-based poll operation
00579         */
00580        if (op->arg1.osfd < FD_SETSIZE) {
00581               pt_poll_now_with_select(op);
00582               return;
00583        }
00584 #endif
00585 
00586     switch (op->timeout) {
00587         case PR_INTERVAL_NO_TIMEOUT:
00588                      msecs = PT_DEFAULT_POLL_MSEC;
00589                      do
00590                      {
00591                             PRIntn rv;
00592                             struct pollfd tmp_pfd;
00593 
00594                             tmp_pfd.revents = 0;
00595                             tmp_pfd.fd = op->arg1.osfd;
00596                             tmp_pfd.events = op->event;
00597 
00598                             rv = poll(&tmp_pfd, 1, msecs);
00599                             
00600                             if (self->state & PT_THREAD_ABORTED)
00601                             {
00602                                    self->state &= ~PT_THREAD_ABORTED;
00603                                    op->result.code = -1;
00604                                    op->syserrno = EINTR;
00605                                    op->status = pt_continuation_done;
00606                                    return;
00607                             }
00608 
00609                             if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
00610                                    continue; /* go around the loop again */
00611 
00612                             if (rv > 0)
00613                             {
00614                                    PRInt16 events = tmp_pfd.events;
00615                                    PRInt16 revents = tmp_pfd.revents;
00616 
00617                                    if ((revents & POLLNVAL)  /* busted in all cases */
00618                                    || ((events & POLLOUT) && (revents & POLLHUP)))
00619                                           /* write op & hup */
00620                                    {
00621                                           op->result.code = -1;
00622                                           if (POLLNVAL & revents) op->syserrno = EBADF;
00623                                           else if (POLLHUP & revents) op->syserrno = EPIPE;
00624                                           op->status = pt_continuation_done;
00625                                    } else {
00626                                           if (op->function(op, revents))
00627                                                  op->status = pt_continuation_done;
00628                                    }
00629                             } else if (rv == -1) {
00630                                    op->result.code = -1;
00631                                    op->syserrno = errno;
00632                                    op->status = pt_continuation_done;
00633                             }
00634                             /* else, poll timed out */
00635                      } while (pt_continuation_done != op->status);
00636                      break;
00637         default:
00638             now = epoch = PR_IntervalNow();
00639             remaining = op->timeout;
00640                      do
00641                      {
00642                             PRIntn rv;
00643                             struct pollfd tmp_pfd;
00644 
00645                             tmp_pfd.revents = 0;
00646                             tmp_pfd.fd = op->arg1.osfd;
00647                             tmp_pfd.events = op->event;
00648 
00649                      wait_for_remaining = PR_TRUE;
00650                      msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
00651                             if (msecs > PT_DEFAULT_POLL_MSEC)
00652                             {
00653                                    wait_for_remaining = PR_FALSE;
00654                                    msecs = PT_DEFAULT_POLL_MSEC;
00655                             }
00656                             rv = poll(&tmp_pfd, 1, msecs);
00657                             
00658                             if (self->state & PT_THREAD_ABORTED)
00659                             {
00660                                    self->state &= ~PT_THREAD_ABORTED;
00661                                    op->result.code = -1;
00662                                    op->syserrno = EINTR;
00663                                    op->status = pt_continuation_done;
00664                                    return;
00665                             }
00666 
00667                             if (rv > 0)
00668                             {
00669                                    PRInt16 events = tmp_pfd.events;
00670                                    PRInt16 revents = tmp_pfd.revents;
00671 
00672                                    if ((revents & POLLNVAL)  /* busted in all cases */
00673                                           || ((events & POLLOUT) && (revents & POLLHUP))) 
00674                                                                              /* write op & hup */
00675                                    {
00676                                           op->result.code = -1;
00677                                           if (POLLNVAL & revents) op->syserrno = EBADF;
00678                                           else if (POLLHUP & revents) op->syserrno = EPIPE;
00679                                           op->status = pt_continuation_done;
00680                                    } else {
00681                                           if (op->function(op, revents))
00682                                           {
00683                                                  op->status = pt_continuation_done;
00684                                           }
00685                                    }
00686                             } else if ((rv == 0) ||
00687                                           ((errno == EINTR) || (errno == EAGAIN))) {
00688                                    if (rv == 0)  /* poll timed out */
00689                                    {
00690                                           if (wait_for_remaining)
00691                                                  now += remaining;
00692                                           else
00693                                                  now += PR_MillisecondsToInterval(msecs);
00694                                    }
00695                                    else
00696                                           now = PR_IntervalNow();
00697                                    elapsed = (PRIntervalTime) (now - epoch);
00698                                    if (elapsed >= op->timeout) {
00699                                           op->result.code = -1;
00700                                           op->syserrno = ETIMEDOUT;
00701                                           op->status = pt_continuation_done;
00702                                    } else
00703                                           remaining = op->timeout - elapsed;
00704                             } else {
00705                                    op->result.code = -1;
00706                                    op->syserrno = errno;
00707                                    op->status = pt_continuation_done;
00708                             }
00709                      } while (pt_continuation_done != op->status);
00710             break;
00711     }
00712 
00713 }  /* pt_poll_now */
00714 
00715 static PRIntn pt_Continue(pt_Continuation *op)
00716 {
00717     op->status = pt_continuation_pending;  /* set default value */
00718        /*
00719         * let each thread call poll directly
00720         */
00721        pt_poll_now(op);
00722        PR_ASSERT(pt_continuation_done == op->status);
00723     return op->result.code;
00724 }  /* pt_Continue */
00725 
00726 /*****************************************************************************/
00727 /*********************** specific continuation functions *********************/
00728 /*****************************************************************************/
00729 static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
00730 {
00731     op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
00732     if (op->syserrno != 0) {
00733         op->result.code = -1;
00734     } else {
00735         op->result.code = 0;
00736     }
00737     return PR_TRUE; /* this one is cooked */
00738 }  /* pt_connect_cont */
00739 
00740 static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
00741 {
00742     op->syserrno = 0;
00743     op->result.code = accept(
00744         op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
00745     if (-1 == op->result.code)
00746     {
00747         op->syserrno = errno;
00748         if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
00749             return PR_FALSE;  /* do nothing - this one ain't finished */
00750     }
00751     return PR_TRUE;
00752 }  /* pt_accept_cont */
00753 
00754 static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
00755 {
00756     /*
00757      * Any number of bytes will complete the operation. It need
00758      * not (and probably will not) satisfy the request. The only
00759      * error we continue is EWOULDBLOCK|EAGAIN.
00760      */
00761     op->result.code = read(
00762         op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
00763     op->syserrno = errno;
00764     return ((-1 == op->result.code) && 
00765             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
00766         PR_FALSE : PR_TRUE;
00767 }  /* pt_read_cont */
00768 
00769 static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
00770 {
00771     /*
00772      * Any number of bytes will complete the operation. It need
00773      * not (and probably will not) satisfy the request. The only
00774      * error we continue is EWOULDBLOCK|EAGAIN.
00775      */
00776 #if defined(SOLARIS)
00777     if (0 == op->arg4.flags)
00778         op->result.code = read(
00779             op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
00780     else
00781         op->result.code = recv(
00782             op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
00783 #else
00784     op->result.code = recv(
00785         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
00786 #endif
00787     op->syserrno = errno;
00788     return ((-1 == op->result.code) && 
00789             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
00790         PR_FALSE : PR_TRUE;
00791 }  /* pt_recv_cont */
00792 
00793 static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
00794 {
00795     PRIntn bytes;
00796 #if defined(SOLARIS)
00797     PRInt32 tmp_amount = op->arg3.amount;
00798 #endif
00799     /*
00800      * We want to write the entire amount out, no matter how many
00801      * tries it takes. Keep advancing the buffer and the decrementing
00802      * the amount until the amount goes away. Return the total bytes
00803      * (which should be the original amount) when finished (or an
00804      * error).
00805      */
00806 #if defined(SOLARIS)
00807 retry:
00808     bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
00809 #else
00810     bytes = send(
00811         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
00812 #endif
00813     op->syserrno = errno;
00814 
00815 #if defined(SOLARIS)
00816     /*
00817      * The write system call has been reported to return the ERANGE error
00818      * on occasion. Try to write in smaller chunks to workaround this bug.
00819      */
00820     if ((bytes == -1) && (op->syserrno == ERANGE))
00821     {
00822         if (tmp_amount > 1)
00823         {
00824             tmp_amount = tmp_amount/2;  /* half the bytes */
00825             goto retry;
00826         }
00827     }
00828 #endif
00829 
00830     if (bytes >= 0)  /* this is progress */
00831     {
00832         char *bp = (char*)op->arg2.buffer;
00833         bp += bytes;  /* adjust the buffer pointer */
00834         op->arg2.buffer = bp;
00835         op->result.code += bytes;  /* accumulate the number sent */
00836         op->arg3.amount -= bytes;  /* and reduce the required count */
00837         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
00838     }
00839     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
00840     {
00841         op->result.code = -1;
00842         return PR_TRUE;
00843     }
00844     else return PR_FALSE;
00845 }  /* pt_send_cont */
00846 
00847 static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
00848 {
00849     PRIntn bytes;
00850     /*
00851      * We want to write the entire amount out, no matter how many
00852      * tries it takes. Keep advancing the buffer and the decrementing
00853      * the amount until the amount goes away. Return the total bytes
00854      * (which should be the original amount) when finished (or an
00855      * error).
00856      */
00857     bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
00858     op->syserrno = errno;
00859     if (bytes >= 0)  /* this is progress */
00860     {
00861         char *bp = (char*)op->arg2.buffer;
00862         bp += bytes;  /* adjust the buffer pointer */
00863         op->arg2.buffer = bp;
00864         op->result.code += bytes;  /* accumulate the number sent */
00865         op->arg3.amount -= bytes;  /* and reduce the required count */
00866         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
00867     }
00868     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
00869     {
00870         op->result.code = -1;
00871         return PR_TRUE;
00872     }
00873     else return PR_FALSE;
00874 }  /* pt_write_cont */
00875 
00876 static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
00877 {
00878     PRIntn bytes;
00879     struct iovec *iov = (struct iovec*)op->arg2.buffer;
00880     /*
00881      * Same rules as write, but continuing seems to be a bit more
00882      * complicated. As the number of bytes sent grows, we have to
00883      * redefine the vector we're pointing at. We might have to
00884      * modify an individual vector parms or we might have to eliminate
00885      * a pair altogether.
00886      */
00887     bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
00888     op->syserrno = errno;
00889     if (bytes >= 0)  /* this is progress */
00890     {
00891         PRIntn iov_index;
00892         op->result.code += bytes;  /* accumulate the number sent */
00893         for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
00894         {
00895             /* how much progress did we make in the i/o vector? */
00896             if (bytes < iov[iov_index].iov_len)
00897             {
00898                 /* this element's not done yet */
00899                 char **bp = (char**)&(iov[iov_index].iov_base);
00900                 iov[iov_index].iov_len -= bytes;  /* there's that much left */
00901                 *bp += bytes;  /* starting there */
00902                 break;  /* go off and do that */
00903             }
00904             bytes -= iov[iov_index].iov_len;  /* that element's consumed */
00905         }
00906         op->arg2.buffer = &iov[iov_index];  /* new start of array */
00907         op->arg3.amount -= iov_index;  /* and array length */
00908         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
00909     }
00910     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
00911     {
00912         op->result.code = -1;
00913         return PR_TRUE;
00914     }
00915     else return PR_FALSE;
00916 }  /* pt_writev_cont */
00917 
00918 static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
00919 {
00920     PRIntn bytes = sendto(
00921         op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
00922         (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
00923     op->syserrno = errno;
00924     if (bytes >= 0)  /* this is progress */
00925     {
00926         char *bp = (char*)op->arg2.buffer;
00927         bp += bytes;  /* adjust the buffer pointer */
00928         op->arg2.buffer = bp;
00929         op->result.code += bytes;  /* accumulate the number sent */
00930         op->arg3.amount -= bytes;  /* and reduce the required count */
00931         return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
00932     }
00933     else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
00934     {
00935         op->result.code = -1;
00936         return PR_TRUE;
00937     }
00938     else return PR_FALSE;
00939 }  /* pt_sendto_cont */
00940 
00941 static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
00942 {
00943     pt_SockLen addr_len = sizeof(PRNetAddr);
00944     op->result.code = recvfrom(
00945         op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
00946         op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
00947     op->syserrno = errno;
00948     return ((-1 == op->result.code) && 
00949             (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
00950         PR_FALSE : PR_TRUE;
00951 }  /* pt_recvfrom_cont */
00952 
00953 #ifdef AIX
00954 static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
00955 {
00956     struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
00957     ssize_t rv;
00958        unsigned long long saved_file_offset;
00959        long long saved_file_bytes;
00960 
00961        saved_file_offset = sf_struct->file_offset;
00962        saved_file_bytes = sf_struct->file_bytes;
00963        sf_struct->bytes_sent = 0;
00964 
00965        if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
00966        PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
00967                                                                sf_struct->file_size);
00968     rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
00969     op->syserrno = errno;
00970 
00971     if (rv != -1) {
00972         op->result.code += sf_struct->bytes_sent;
00973               /*
00974                * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
00975                * being updated. So, 'file_bytes' is maintained by NSPR to
00976                * avoid conflict when this bug is fixed in AIX, in the future.
00977                */
00978               if (saved_file_bytes != -1)
00979                      saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
00980               sf_struct->file_bytes = saved_file_bytes;
00981     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
00982         op->result.code = -1;
00983     } else {
00984         return PR_FALSE;
00985     }
00986 
00987     if (rv == 1) {    /* more data to send */
00988         return PR_FALSE;
00989     }
00990 
00991     return PR_TRUE;
00992 }
00993 #endif  /* AIX */
00994 
00995 #ifdef HPUX11
00996 static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
00997 {
00998     struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
00999     int count;
01000 
01001     count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
01002                      op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
01003     PR_ASSERT(count <= op->nbytes_to_send);
01004     op->syserrno = errno;
01005 
01006     if (count != -1) {
01007         op->result.code += count;
01008     } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
01009         op->result.code = -1;
01010     } else {
01011         return PR_FALSE;
01012     }
01013     if (count != -1 && count < op->nbytes_to_send) {
01014         if (count < hdtrl[0].iov_len) {
01015                      /* header not sent */
01016 
01017             hdtrl[0].iov_base = ((char *) hdtrl[0].iov_len) + count;
01018             hdtrl[0].iov_len -= count;
01019 
01020         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
01021                      /* header sent, file not sent */
01022             PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
01023 
01024             hdtrl[0].iov_base = NULL;
01025             hdtrl[0].iov_len = 0;
01026 
01027             op->arg3.file_spec.offset += file_nbytes_sent;
01028             op->arg3.file_spec.nbytes -= file_nbytes_sent;
01029         } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
01030                                                                              hdtrl[1].iov_len)) {
01031             PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
01032                                          op->arg3.file_spec.nbytes);
01033 
01034                      /* header sent, file sent, trailer not sent */
01035 
01036             hdtrl[0].iov_base = NULL;
01037             hdtrl[0].iov_len = 0;
01038                      /*
01039                       * set file offset and len so that no more file data is
01040                       * sent
01041                       */
01042             op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
01043             op->arg3.file_spec.nbytes = 0;
01044 
01045             hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
01046             hdtrl[1].iov_len -= trailer_nbytes_sent;
01047               }
01048         op->nbytes_to_send -= count;
01049         return PR_FALSE;
01050     }
01051 
01052     return PR_TRUE;
01053 }
01054 #endif  /* HPUX11 */
01055 
01056 #ifdef SOLARIS  
01057 static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
01058 {
01059     struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
01060     size_t xferred;
01061     ssize_t count;
01062 
01063     count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
01064     op->syserrno = errno;
01065     PR_ASSERT((count == -1) || (count == xferred));
01066 
01067     if (count == -1) {
01068         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
01069                 && op->syserrno != EINTR) {
01070             op->result.code = -1;
01071             return PR_TRUE;
01072         }
01073         count = xferred;
01074     } else if (count == 0) {
01075         /* 
01076          * We are now at EOF. The file was truncated. Solaris sendfile is
01077          * supposed to return 0 and no error in this case, though some versions
01078          * may return -1 and EINVAL .
01079          */
01080         op->result.code = -1;
01081         op->syserrno = 0; /* will be treated as EOF */
01082         return PR_TRUE;
01083     }
01084     PR_ASSERT(count <= op->nbytes_to_send);
01085     
01086     op->result.code += count;
01087     if (count < op->nbytes_to_send) {
01088         op->nbytes_to_send -= count;
01089 
01090         while (count >= vec->sfv_len) {
01091             count -= vec->sfv_len;
01092             vec++;
01093             op->arg3.amount--;
01094         }
01095         PR_ASSERT(op->arg3.amount > 0);
01096 
01097         vec->sfv_off += count;
01098         vec->sfv_len -= count;
01099         PR_ASSERT(vec->sfv_len > 0);
01100         op->arg2.buffer = vec;
01101 
01102         return PR_FALSE;
01103     }
01104 
01105     return PR_TRUE;
01106 }
01107 #endif  /* SOLARIS */
01108 
01109 #ifdef LINUX 
01110 static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
01111 {
01112     ssize_t rv;
01113     off_t oldoffset;
01114 
01115     oldoffset = op->offset;
01116     rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
01117     op->syserrno = errno;
01118 
01119     if (rv == -1) {
01120         if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
01121             op->result.code = -1;
01122             return PR_TRUE;
01123         }
01124         rv = 0;
01125     }
01126     PR_ASSERT(rv == op->offset - oldoffset);
01127     op->result.code += rv;
01128     if (rv < op->count) {
01129         op->count -= rv;
01130         return PR_FALSE;
01131     }
01132     return PR_TRUE;
01133 }
01134 #endif  /* LINUX */
01135 
01136 void _PR_InitIO(void)
01137 {
01138 #if defined(DEBUG)
01139     memset(&pt_debug, 0, sizeof(PTDebug));
01140     pt_debug.timeStarted = PR_Now();
01141 #endif
01142 
01143     _pr_flock_lock = PR_NewLock();
01144     PR_ASSERT(NULL != _pr_flock_lock);
01145     _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
01146     PR_ASSERT(NULL != _pr_flock_cv);
01147     _pr_rename_lock = PR_NewLock();
01148     PR_ASSERT(NULL != _pr_rename_lock); 
01149 
01150     _PR_InitFdCache();  /* do that */   
01151 
01152     _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
01153     _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
01154     _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
01155     PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
01156 
01157 #ifdef _PR_IPV6_V6ONLY_PROBE
01158     /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
01159      * is turned on by default, contrary to what RFC 3493, Section
01160      * 5.3 says.  So we have to turn it off.  Find out whether we
01161      * are running on such a system.
01162      */
01163     {
01164         int osfd;
01165         osfd = socket(AF_INET6, SOCK_STREAM, 0);
01166         if (osfd != -1) {
01167             int on;
01168             int optlen = sizeof(on);
01169             if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
01170                     &on, &optlen) == 0) {
01171                 _pr_ipv6_v6only_on_by_default = on;
01172             }
01173             close(osfd);
01174         }
01175     }
01176 #endif
01177 }  /* _PR_InitIO */
01178 
01179 void _PR_CleanupIO(void)
01180 {
01181     _PR_Putfd(_pr_stdin);
01182     _pr_stdin = NULL;
01183     _PR_Putfd(_pr_stdout);
01184     _pr_stdout = NULL;
01185     _PR_Putfd(_pr_stderr); 
01186     _pr_stderr = NULL;
01187 
01188     _PR_CleanupFdCache();
01189     
01190     if (_pr_flock_cv)
01191     {
01192         PR_DestroyCondVar(_pr_flock_cv);
01193         _pr_flock_cv = NULL;
01194     }
01195     if (_pr_flock_lock)
01196     {
01197         PR_DestroyLock(_pr_flock_lock);
01198         _pr_flock_lock = NULL;
01199     }
01200     if (_pr_rename_lock)
01201     {
01202         PR_DestroyLock(_pr_rename_lock);
01203         _pr_rename_lock = NULL;
01204     }
01205 }  /* _PR_CleanupIO */
01206 
01207 PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
01208 {
01209     PRFileDesc *result = NULL;
01210     PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
01211 
01212     if (!_pr_initialized) _PR_ImplicitInitialization();
01213     
01214     switch (osfd)
01215     {
01216         case PR_StandardInput: result = _pr_stdin; break;
01217         case PR_StandardOutput: result = _pr_stdout; break;
01218         case PR_StandardError: result = _pr_stderr; break;
01219         default:
01220             (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01221     }
01222     return result;
01223 }  /* PR_GetSpecialFD */
01224 
01225 /*****************************************************************************/
01226 /***************************** I/O private methods ***************************/
01227 /*****************************************************************************/
01228 
01229 static PRBool pt_TestAbort(void)
01230 {
01231     PRThread *me = PR_CurrentThread();
01232     if(_PT_THREAD_INTERRUPTED(me))
01233     {
01234         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
01235         me->state &= ~PT_THREAD_ABORTED;
01236         return PR_TRUE;
01237     }
01238     return PR_FALSE;
01239 }  /* pt_TestAbort */
01240 
01241 static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
01242 {
01243     switch (syserrno)
01244     {
01245         case EINTR:
01246             PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
01247         case ETIMEDOUT:
01248             PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
01249         default:
01250             mapper(syserrno);
01251     }
01252 }  /* pt_MapError */
01253 
01254 static PRStatus pt_Close(PRFileDesc *fd)
01255 {
01256     if ((NULL == fd) || (NULL == fd->secret)
01257         || ((_PR_FILEDESC_OPEN != fd->secret->state)
01258         && (_PR_FILEDESC_CLOSED != fd->secret->state)))
01259     {
01260         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
01261         return PR_FAILURE;
01262     }
01263     if (pt_TestAbort()) return PR_FAILURE;
01264 
01265     if (_PR_FILEDESC_OPEN == fd->secret->state)
01266     {
01267         if (-1 == close(fd->secret->md.osfd))
01268         {
01269 #ifdef OSF1
01270             /*
01271              * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
01272              * system call, when called to close a TCP socket, may
01273              * return -1 with errno set to EINVAL but the system call
01274              * does close the socket successfully.  An application
01275              * may safely ignore the EINVAL error.  This bug is fixed
01276              * on Tru64 UNIX V5.1A and later.  The defect tracking
01277              * number is QAR 81431.
01278              */
01279             if (PR_DESC_SOCKET_TCP != fd->methods->file_type
01280             || EINVAL != errno)
01281             {
01282                 pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
01283                 return PR_FAILURE;
01284             }
01285 #else
01286             pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
01287             return PR_FAILURE;
01288 #endif
01289         }
01290         fd->secret->state = _PR_FILEDESC_CLOSED;
01291     }
01292     _PR_Putfd(fd);
01293     return PR_SUCCESS;
01294 }  /* pt_Close */
01295 
01296 static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
01297 {
01298     PRInt32 syserrno, bytes = -1;
01299 
01300     if (pt_TestAbort()) return bytes;
01301 
01302     bytes = read(fd->secret->md.osfd, buf, amount);
01303     syserrno = errno;
01304 
01305     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
01306         && (!fd->secret->nonblocking))
01307     {
01308         pt_Continuation op;
01309         op.arg1.osfd = fd->secret->md.osfd;
01310         op.arg2.buffer = buf;
01311         op.arg3.amount = amount;
01312         op.timeout = PR_INTERVAL_NO_TIMEOUT;
01313         op.function = pt_read_cont;
01314         op.event = POLLIN | POLLPRI;
01315         bytes = pt_Continue(&op);
01316         syserrno = op.syserrno;
01317     }
01318     if (bytes < 0)
01319         pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
01320     return bytes;
01321 }  /* pt_Read */
01322 
01323 static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
01324 {
01325     PRInt32 syserrno, bytes = -1;
01326     PRBool fNeedContinue = PR_FALSE;
01327 
01328     if (pt_TestAbort()) return bytes;
01329 
01330     bytes = write(fd->secret->md.osfd, buf, amount);
01331     syserrno = errno;
01332 
01333     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
01334     {
01335         buf = (char *) buf + bytes;
01336         amount -= bytes;
01337         fNeedContinue = PR_TRUE;
01338     }
01339     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
01340         && (!fd->secret->nonblocking) )
01341     {
01342         bytes = 0;
01343         fNeedContinue = PR_TRUE;
01344     }
01345 
01346     if (fNeedContinue == PR_TRUE)
01347     {
01348         pt_Continuation op;
01349         op.arg1.osfd = fd->secret->md.osfd;
01350         op.arg2.buffer = (void*)buf;
01351         op.arg3.amount = amount;
01352         op.timeout = PR_INTERVAL_NO_TIMEOUT;
01353         op.result.code = bytes;  /* initialize the number sent */
01354         op.function = pt_write_cont;
01355         op.event = POLLOUT | POLLPRI;
01356         bytes = pt_Continue(&op);
01357         syserrno = op.syserrno;
01358     }
01359     if (bytes == -1)
01360         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
01361     return bytes;
01362 }  /* pt_Write */
01363 
01364 static PRInt32 pt_Writev(
01365     PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
01366 {
01367     PRIntn iov_index;
01368     PRBool fNeedContinue = PR_FALSE;
01369     PRInt32 syserrno, bytes, rv = -1;
01370     struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
01371     int osiov_len;
01372 
01373     if (pt_TestAbort()) return rv;
01374 
01375     /* Ensured by PR_Writev */
01376     PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
01377 
01378     /*
01379      * We can't pass iov to writev because PRIOVec and struct iovec
01380      * may not be binary compatible.  Make osiov a copy of iov and
01381      * pass osiov to writev.  We can modify osiov if we need to
01382      * continue the operation.
01383      */
01384     osiov = osiov_local;
01385     osiov_len = iov_len;
01386     for (iov_index = 0; iov_index < osiov_len; iov_index++)
01387     {
01388         osiov[iov_index].iov_base = iov[iov_index].iov_base;
01389         osiov[iov_index].iov_len = iov[iov_index].iov_len;
01390     }
01391 
01392     rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
01393     syserrno = errno;
01394 
01395     if (!fd->secret->nonblocking)
01396     {
01397         if (bytes >= 0)
01398         {
01399             /*
01400              * If we moved some bytes, how does that implicate the
01401              * i/o vector list?  In other words, exactly where are
01402              * we within that array?  What are the parameters for
01403              * resumption?  Maybe we're done!
01404              */
01405             for ( ;osiov_len > 0; osiov++, osiov_len--)
01406             {
01407                 if (bytes < osiov->iov_len)
01408                 {
01409                     /* this one's not done yet */
01410                     osiov->iov_base = (char*)osiov->iov_base + bytes;
01411                     osiov->iov_len -= bytes;
01412                     break;  /* go off and do that */
01413                 }
01414                 bytes -= osiov->iov_len;  /* this one's done cooked */
01415             }
01416             PR_ASSERT(osiov_len > 0 || bytes == 0);
01417             if (osiov_len > 0)
01418             {
01419                 if (PR_INTERVAL_NO_WAIT == timeout)
01420                 {
01421                     rv = -1;
01422                     syserrno = ETIMEDOUT;
01423                 }
01424                 else fNeedContinue = PR_TRUE;
01425             }
01426         }
01427         else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
01428         {
01429             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
01430             else
01431             {
01432                 rv = 0;
01433                 fNeedContinue = PR_TRUE;
01434             }
01435         }
01436     }
01437 
01438     if (fNeedContinue == PR_TRUE)
01439     {
01440         pt_Continuation op;
01441 
01442         op.arg1.osfd = fd->secret->md.osfd;
01443         op.arg2.buffer = (void*)osiov;
01444         op.arg3.amount = osiov_len;
01445         op.timeout = timeout;
01446         op.result.code = rv;
01447         op.function = pt_writev_cont;
01448         op.event = POLLOUT | POLLPRI;
01449         rv = pt_Continue(&op);
01450         syserrno = op.syserrno;
01451     }
01452     if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
01453     return rv;
01454 }  /* pt_Writev */
01455 
01456 static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
01457 {
01458     return _PR_MD_LSEEK(fd, offset, whence);
01459 }  /* pt_Seek */
01460 
01461 static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
01462 {
01463     return _PR_MD_LSEEK64(fd, offset, whence);
01464 }  /* pt_Seek64 */
01465 
01466 static PRInt32 pt_Available_f(PRFileDesc *fd)
01467 {
01468     PRInt32 result, cur, end;
01469 
01470     cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
01471 
01472     if (cur >= 0)
01473         end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
01474 
01475     if ((cur < 0) || (end < 0)) {
01476         return -1;
01477     }
01478 
01479     result = end - cur;
01480     _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
01481 
01482     return result;
01483 }  /* pt_Available_f */
01484 
01485 static PRInt64 pt_Available64_f(PRFileDesc *fd)
01486 {
01487     PRInt64 result, cur, end;
01488     PRInt64 minus_one;
01489 
01490     LL_I2L(minus_one, -1);
01491     cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
01492 
01493     if (LL_GE_ZERO(cur))
01494         end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
01495 
01496     if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
01497 
01498     LL_SUB(result, end, cur);
01499     (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
01500 
01501     return result;
01502 }  /* pt_Available64_f */
01503 
01504 static PRInt32 pt_Available_s(PRFileDesc *fd)
01505 {
01506     PRInt32 rv, bytes = -1;
01507     if (pt_TestAbort()) return bytes;
01508 
01509     rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
01510 
01511     if (rv == -1)
01512         pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
01513     return bytes;
01514 }  /* pt_Available_s */
01515 
01516 static PRInt64 pt_Available64_s(PRFileDesc *fd)
01517 {
01518     PRInt64 rv;
01519     LL_I2L(rv, pt_Available_s(fd));
01520     return rv;
01521 }  /* pt_Available64_s */
01522 
01523 static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
01524 {
01525     PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
01526     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
01527 }  /* pt_FileInfo */
01528 
01529 static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
01530 {
01531     PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
01532     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
01533 }  /* pt_FileInfo64 */
01534 
01535 static PRStatus pt_Synch(PRFileDesc *fd)
01536 {
01537     return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
01538 } /* pt_Synch */
01539 
01540 static PRStatus pt_Fsync(PRFileDesc *fd)
01541 {
01542     PRIntn rv = -1;
01543     if (pt_TestAbort()) return PR_FAILURE;
01544 
01545     rv = fsync(fd->secret->md.osfd);
01546     if (rv < 0) {
01547         pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
01548         return PR_FAILURE;
01549     }
01550     return PR_SUCCESS;
01551 }  /* pt_Fsync */
01552 
01553 static PRStatus pt_Connect(
01554     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
01555 {
01556     PRIntn rv = -1, syserrno;
01557     pt_SockLen addr_len;
01558        const PRNetAddr *addrp = addr;
01559 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
01560        PRUint16 md_af = addr->raw.family;
01561     PRNetAddr addrCopy;
01562 #endif
01563 
01564     if (pt_TestAbort()) return PR_FAILURE;
01565 
01566     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01567     addr_len = PR_NETADDR_SIZE(addr);
01568 #if defined(_PR_INET6)
01569        if (addr->raw.family == PR_AF_INET6) {
01570               md_af = AF_INET6;
01571 #ifndef _PR_HAVE_SOCKADDR_LEN
01572               addrCopy = *addr;
01573               addrCopy.raw.family = AF_INET6;
01574               addrp = &addrCopy;
01575 #endif
01576        }
01577 #endif
01578 
01579 #ifdef _PR_HAVE_SOCKADDR_LEN
01580     addrCopy = *addr;
01581     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
01582     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
01583     addrp = &addrCopy;
01584 #endif
01585     rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
01586     syserrno = errno;
01587     if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
01588     {
01589         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
01590         else
01591         {
01592             pt_Continuation op;
01593             op.arg1.osfd = fd->secret->md.osfd;
01594             op.arg2.buffer = (void*)addrp;
01595             op.arg3.amount = addr_len;
01596             op.timeout = timeout;
01597             op.function = pt_connect_cont;
01598             op.event = POLLOUT | POLLPRI;
01599             rv = pt_Continue(&op);
01600             syserrno = op.syserrno;
01601         }
01602     }
01603     if (-1 == rv) {
01604         pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
01605         return PR_FAILURE;
01606     }
01607     return PR_SUCCESS;
01608 }  /* pt_Connect */
01609 
01610 static PRStatus pt_ConnectContinue(
01611     PRFileDesc *fd, PRInt16 out_flags)
01612 {
01613     int err;
01614     PRInt32 osfd;
01615 
01616     if (out_flags & PR_POLL_NVAL)
01617     {
01618         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
01619         return PR_FAILURE;
01620     }
01621     if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0)
01622     {
01623         PR_ASSERT(out_flags == 0);
01624         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
01625         return PR_FAILURE;
01626     }
01627 
01628     osfd = fd->secret->md.osfd;
01629 
01630     err = _MD_unix_get_nonblocking_connect_error(osfd);
01631     if (err != 0)
01632     {
01633         _PR_MD_MAP_CONNECT_ERROR(err);
01634         return PR_FAILURE;
01635     }
01636     return PR_SUCCESS;
01637 }  /* pt_ConnectContinue */
01638 
01639 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
01640 {
01641     /* Find the NSPR layer and invoke its connectcontinue method */
01642     PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
01643 
01644     if (NULL == bottom)
01645     {
01646         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01647         return PR_FAILURE;
01648     }
01649     return pt_ConnectContinue(bottom, pd->out_flags);
01650 }  /* PR_GetConnectStatus */
01651 
01652 static PRFileDesc* pt_Accept(
01653     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
01654 {
01655     PRFileDesc *newfd = NULL;
01656     PRIntn syserrno, osfd = -1;
01657     pt_SockLen addr_len = sizeof(PRNetAddr);
01658 
01659     if (pt_TestAbort()) return newfd;
01660 
01661 #ifdef _PR_STRICT_ADDR_LEN
01662     if (addr)
01663     {
01664         /*
01665          * Set addr->raw.family just so that we can use the
01666          * PR_NETADDR_SIZE macro.
01667          */
01668         addr->raw.family = fd->secret->af;
01669         addr_len = PR_NETADDR_SIZE(addr);
01670     }
01671 #endif
01672 
01673     osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
01674     syserrno = errno;
01675 
01676     if (osfd == -1)
01677     {
01678         if (fd->secret->nonblocking) goto failed;
01679 
01680         if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
01681         && ECONNABORTED != syserrno)
01682             goto failed;
01683         else
01684         {
01685             if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
01686             else
01687             {
01688                 pt_Continuation op;
01689                 op.arg1.osfd = fd->secret->md.osfd;
01690                 op.arg2.buffer = addr;
01691                 op.arg3.addr_len = &addr_len;
01692                 op.timeout = timeout;
01693                 op.function = pt_accept_cont;
01694                 op.event = POLLIN | POLLPRI;
01695                 osfd = pt_Continue(&op);
01696                 syserrno = op.syserrno;
01697             }
01698             if (osfd < 0) goto failed;
01699         }
01700     }
01701 #ifdef _PR_HAVE_SOCKADDR_LEN
01702     /* ignore the sa_len field of struct sockaddr */
01703     if (addr)
01704     {
01705         addr->raw.family = ((struct sockaddr*)addr)->sa_family;
01706     }
01707 #endif /* _PR_HAVE_SOCKADDR_LEN */
01708 #ifdef _PR_INET6
01709        if (addr && (AF_INET6 == addr->raw.family))
01710         addr->raw.family = PR_AF_INET6;
01711 #endif
01712     newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
01713     if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
01714     else
01715     {
01716         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01717         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
01718 #ifdef LINUX
01719         /*
01720          * On Linux, experiments showed that the accepted sockets
01721          * inherit the TCP_NODELAY socket option of the listening
01722          * socket.
01723          */
01724         newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
01725 #endif
01726     }
01727     return newfd;
01728 
01729 failed:
01730     pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
01731     return NULL;
01732 }  /* pt_Accept */
01733 
01734 static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
01735 {
01736     PRIntn rv;
01737     pt_SockLen addr_len;
01738        const PRNetAddr *addrp = addr;
01739 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
01740        PRUint16 md_af = addr->raw.family;
01741     PRNetAddr addrCopy;
01742 #endif
01743 
01744     if (pt_TestAbort()) return PR_FAILURE;
01745 
01746     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01747     if (addr->raw.family == AF_UNIX)
01748     {
01749         /* Disallow relative pathnames */
01750         if (addr->local.path[0] != '/')
01751         {
01752             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01753             return PR_FAILURE;
01754         }
01755     }
01756 
01757 #if defined(_PR_INET6)
01758        if (addr->raw.family == PR_AF_INET6) {
01759               md_af = AF_INET6;
01760 #ifndef _PR_HAVE_SOCKADDR_LEN
01761               addrCopy = *addr;
01762               addrCopy.raw.family = AF_INET6;
01763               addrp = &addrCopy;
01764 #endif
01765        }
01766 #endif
01767 
01768     addr_len = PR_NETADDR_SIZE(addr);
01769 #ifdef _PR_HAVE_SOCKADDR_LEN
01770     addrCopy = *addr;
01771     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
01772     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
01773     addrp = &addrCopy;
01774 #endif
01775     rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
01776 
01777     if (rv == -1) {
01778         pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
01779         return PR_FAILURE;
01780     }
01781     return PR_SUCCESS;
01782 }  /* pt_Bind */
01783 
01784 static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
01785 {
01786     PRIntn rv;
01787 
01788     if (pt_TestAbort()) return PR_FAILURE;
01789 
01790     rv = listen(fd->secret->md.osfd, backlog);
01791     if (rv == -1) {
01792         pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
01793         return PR_FAILURE;
01794     }
01795     return PR_SUCCESS;
01796 }  /* pt_Listen */
01797 
01798 static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
01799 {
01800     PRIntn rv = -1;
01801     if (pt_TestAbort()) return PR_FAILURE;
01802 
01803     rv = shutdown(fd->secret->md.osfd, how);
01804 
01805     if (rv == -1) {
01806         pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
01807         return PR_FAILURE;
01808     }
01809     return PR_SUCCESS;
01810 }  /* pt_Shutdown */
01811 
01812 static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
01813 {
01814     *out_flags = 0;
01815     return in_flags;
01816 }  /* pt_Poll */
01817 
01818 static PRInt32 pt_Recv(
01819     PRFileDesc *fd, void *buf, PRInt32 amount,
01820     PRIntn flags, PRIntervalTime timeout)
01821 {
01822     PRInt32 syserrno, bytes = -1;
01823     PRIntn osflags;
01824 
01825     if (0 == flags)
01826         osflags = 0;
01827     else if (PR_MSG_PEEK == flags)
01828         osflags = MSG_PEEK;
01829     else
01830     {
01831         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01832         return bytes;
01833     }
01834 
01835     if (pt_TestAbort()) return bytes;
01836 
01837     /* recv() is a much slower call on pre-2.6 Solaris than read(). */
01838 #if defined(SOLARIS)
01839     if (0 == osflags)
01840         bytes = read(fd->secret->md.osfd, buf, amount);
01841     else
01842         bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
01843 #else
01844     bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
01845 #endif
01846     syserrno = errno;
01847 
01848     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
01849         && (!fd->secret->nonblocking))
01850     {
01851         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
01852         else
01853         {
01854             pt_Continuation op;
01855             op.arg1.osfd = fd->secret->md.osfd;
01856             op.arg2.buffer = buf;
01857             op.arg3.amount = amount;
01858             op.arg4.flags = osflags;
01859             op.timeout = timeout;
01860             op.function = pt_recv_cont;
01861             op.event = POLLIN | POLLPRI;
01862             bytes = pt_Continue(&op);
01863             syserrno = op.syserrno;
01864         }
01865     }
01866     if (bytes < 0)
01867         pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
01868     return bytes;
01869 }  /* pt_Recv */
01870 
01871 static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
01872 {
01873     return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
01874 }  /* pt_SocketRead */
01875 
01876 static PRInt32 pt_Send(
01877     PRFileDesc *fd, const void *buf, PRInt32 amount,
01878     PRIntn flags, PRIntervalTime timeout)
01879 {
01880     PRInt32 syserrno, bytes = -1;
01881     PRBool fNeedContinue = PR_FALSE;
01882 #if defined(SOLARIS)
01883        PRInt32 tmp_amount = amount;
01884 #endif
01885 
01886     /*
01887      * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
01888      * which has the following:
01889      *     #  define send        cma_send
01890      *     extern int  cma_send (int , void *, int, int );
01891      * So we need to cast away the 'const' of argument #2 for send().
01892      */
01893 #if defined (HPUX) && defined(_PR_DCETHREADS)
01894 #define PT_SENDBUF_CAST (void *)
01895 #else
01896 #define PT_SENDBUF_CAST
01897 #endif
01898 
01899     if (pt_TestAbort()) return bytes;
01900 
01901     /*
01902      * On pre-2.6 Solaris, send() is much slower than write().
01903      * On 2.6 and beyond, with in-kernel sockets, send() and
01904      * write() are fairly equivalent in performance.
01905      */
01906 #if defined(SOLARIS)
01907     PR_ASSERT(0 == flags);
01908 retry:
01909     bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
01910 #else
01911     bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
01912 #endif
01913     syserrno = errno;
01914 
01915 #if defined(SOLARIS)
01916     /*
01917      * The write system call has been reported to return the ERANGE error
01918      * on occasion. Try to write in smaller chunks to workaround this bug.
01919      */
01920     if ((bytes == -1) && (syserrno == ERANGE))
01921     {
01922         if (tmp_amount > 1)
01923         {
01924             tmp_amount = tmp_amount/2;  /* half the bytes */
01925             goto retry;
01926         }
01927     }
01928 #endif
01929 
01930     if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
01931     {
01932         if (PR_INTERVAL_NO_WAIT == timeout)
01933         {
01934             bytes = -1;
01935             syserrno = ETIMEDOUT;
01936         }
01937         else
01938         {
01939             buf = (char *) buf + bytes;
01940             amount -= bytes;
01941             fNeedContinue = PR_TRUE;
01942         }
01943     }
01944     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
01945         && (!fd->secret->nonblocking) )
01946     {
01947         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
01948         else
01949         {
01950             bytes = 0;
01951             fNeedContinue = PR_TRUE;
01952         }
01953     }
01954 
01955     if (fNeedContinue == PR_TRUE)
01956     {
01957         pt_Continuation op;
01958         op.arg1.osfd = fd->secret->md.osfd;
01959         op.arg2.buffer = (void*)buf;
01960         op.arg3.amount = amount;
01961         op.arg4.flags = flags;
01962         op.timeout = timeout;
01963         op.result.code = bytes;  /* initialize the number sent */
01964         op.function = pt_send_cont;
01965         op.event = POLLOUT | POLLPRI;
01966         bytes = pt_Continue(&op);
01967         syserrno = op.syserrno;
01968     }
01969     if (bytes == -1)
01970         pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
01971     return bytes;
01972 }  /* pt_Send */
01973 
01974 static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
01975 {
01976     return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
01977 }  /* pt_SocketWrite */
01978 
01979 static PRInt32 pt_SendTo(
01980     PRFileDesc *fd, const void *buf,
01981     PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
01982     PRIntervalTime timeout)
01983 {
01984     PRInt32 syserrno, bytes = -1;
01985     PRBool fNeedContinue = PR_FALSE;
01986     pt_SockLen addr_len;
01987        const PRNetAddr *addrp = addr;
01988 #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
01989        PRUint16 md_af = addr->raw.family;
01990     PRNetAddr addrCopy;
01991 #endif
01992 
01993     if (pt_TestAbort()) return bytes;
01994 
01995     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01996 #if defined(_PR_INET6)
01997        if (addr->raw.family == PR_AF_INET6) {
01998               md_af = AF_INET6;
01999 #ifndef _PR_HAVE_SOCKADDR_LEN
02000               addrCopy = *addr;
02001               addrCopy.raw.family = AF_INET6;
02002               addrp = &addrCopy;
02003 #endif
02004        }
02005 #endif
02006 
02007     addr_len = PR_NETADDR_SIZE(addr);
02008 #ifdef _PR_HAVE_SOCKADDR_LEN
02009     addrCopy = *addr;
02010     ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
02011     ((struct sockaddr*)&addrCopy)->sa_family = md_af;
02012     addrp = &addrCopy;
02013 #endif
02014     bytes = sendto(
02015         fd->secret->md.osfd, buf, amount, flags,
02016         (struct sockaddr*)addrp, addr_len);
02017     syserrno = errno;
02018     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
02019         && (!fd->secret->nonblocking) )
02020     {
02021         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
02022         else fNeedContinue = PR_TRUE;
02023     }
02024     if (fNeedContinue == PR_TRUE)
02025     {
02026         pt_Continuation op;
02027         op.arg1.osfd = fd->secret->md.osfd;
02028         op.arg2.buffer = (void*)buf;
02029         op.arg3.amount = amount;
02030         op.arg4.flags = flags;
02031         op.arg5.addr = (PRNetAddr*)addrp;
02032         op.timeout = timeout;
02033         op.result.code = 0;  /* initialize the number sent */
02034         op.function = pt_sendto_cont;
02035         op.event = POLLOUT | POLLPRI;
02036         bytes = pt_Continue(&op);
02037         syserrno = op.syserrno;
02038     }
02039     if (bytes < 0)
02040         pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
02041     return bytes;
02042 }  /* pt_SendTo */
02043 
02044 static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
02045     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
02046 {
02047     PRBool fNeedContinue = PR_FALSE;
02048     PRInt32 syserrno, bytes = -1;
02049     pt_SockLen addr_len = sizeof(PRNetAddr);
02050 
02051     if (pt_TestAbort()) return bytes;
02052 
02053     bytes = recvfrom(
02054         fd->secret->md.osfd, buf, amount, flags,
02055         (struct sockaddr*)addr, &addr_len);
02056     syserrno = errno;
02057 
02058     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
02059         && (!fd->secret->nonblocking) )
02060     {
02061         if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
02062         else fNeedContinue = PR_TRUE;
02063     }
02064 
02065     if (fNeedContinue == PR_TRUE)
02066     {
02067         pt_Continuation op;
02068         op.arg1.osfd = fd->secret->md.osfd;
02069         op.arg2.buffer = buf;
02070         op.arg3.amount = amount;
02071         op.arg4.flags = flags;
02072         op.arg5.addr = addr;
02073         op.timeout = timeout;
02074         op.function = pt_recvfrom_cont;
02075         op.event = POLLIN | POLLPRI;
02076         bytes = pt_Continue(&op);
02077         syserrno = op.syserrno;
02078     }
02079 #ifdef _PR_HAVE_SOCKADDR_LEN
02080     if (bytes >= 0)
02081     {
02082         /* ignore the sa_len field of struct sockaddr */
02083         if (addr)
02084         {
02085             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
02086         }
02087     }
02088 #endif /* _PR_HAVE_SOCKADDR_LEN */
02089 #ifdef _PR_INET6
02090        if (addr && (AF_INET6 == addr->raw.family))
02091         addr->raw.family = PR_AF_INET6;
02092 #endif
02093     if (bytes < 0)
02094         pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
02095     return bytes;
02096 }  /* pt_RecvFrom */
02097 
02098 #ifdef AIX
02099 #ifndef HAVE_SEND_FILE
02100 static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
02101 
02102 static void pt_aix_sendfile_init_routine(void)
02103 {
02104     void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
02105     pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
02106     dlclose(handle);
02107 }
02108 
02109 /* 
02110  * pt_AIXDispatchSendFile
02111  */
02112 static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
02113          PRTransmitFileFlags flags, PRIntervalTime timeout)
02114 {
02115     int rv;
02116 
02117     rv = pthread_once(&pt_aix_sendfile_once_block,
02118             pt_aix_sendfile_init_routine);
02119     PR_ASSERT(0 == rv);
02120     if (pt_aix_sendfile_fptr) {
02121         return pt_AIXSendFile(sd, sfd, flags, timeout);
02122     } else {
02123         return PR_EmulateSendFile(sd, sfd, flags, timeout);
02124     }
02125 }
02126 #endif /* !HAVE_SEND_FILE */
02127 
02128 
02129 /*
02130  * pt_AIXSendFile
02131  *
02132  *    Send file sfd->fd across socket sd. If specified, header and trailer
02133  *    buffers are sent before and after the file, respectively. 
02134  *
02135  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
02136  *    
02137  *    return number of bytes sent or -1 on error
02138  *
02139  *      This implementation takes advantage of the send_file() system
02140  *      call available in AIX 4.3.2.
02141  */
02142 
02143 static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
02144               PRTransmitFileFlags flags, PRIntervalTime timeout)
02145 {
02146     struct sf_parms sf_struct;
02147     uint_t send_flags;
02148     ssize_t rv;
02149     int syserrno;
02150     PRInt32 count;
02151        unsigned long long saved_file_offset;
02152        long long saved_file_bytes;
02153 
02154     sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
02155     sf_struct.header_length = sfd->hlen;
02156     sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
02157     sf_struct.file_size = 0;
02158     sf_struct.file_offset = sfd->file_offset;
02159     if (sfd->file_nbytes == 0)
02160        sf_struct.file_bytes = -1;
02161        else
02162        sf_struct.file_bytes = sfd->file_nbytes;
02163     sf_struct.trailer_data = (void *) sfd->trailer;
02164     sf_struct.trailer_length = sfd->tlen;
02165     sf_struct.bytes_sent = 0;
02166 
02167        saved_file_offset = sf_struct.file_offset;
02168     saved_file_bytes = sf_struct.file_bytes;
02169 
02170     send_flags = 0;                /* flags processed at the end */
02171 
02172     /* The first argument to send_file() is int*. */
02173     PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
02174     do {
02175         rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
02176     } while (rv == -1 && (syserrno = errno) == EINTR);
02177 
02178     if (rv == -1) {
02179         if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
02180             count = 0; /* Not a real error.  Need to continue. */
02181         } else {
02182             count = -1;
02183         }
02184     } else {
02185         count = sf_struct.bytes_sent;
02186               /*
02187                * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
02188                * being updated. So, 'file_bytes' is maintained by NSPR to
02189                * avoid conflict when this bug is fixed in AIX, in the future.
02190                */
02191               if (saved_file_bytes != -1)
02192                      saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
02193               sf_struct.file_bytes = saved_file_bytes;
02194     }
02195 
02196     if ((rv == 1) || ((rv == -1) && (count == 0))) {
02197         pt_Continuation op;
02198 
02199         op.arg1.osfd = sd->secret->md.osfd;
02200         op.arg2.buffer = &sf_struct;
02201         op.arg4.flags = send_flags;
02202         op.result.code = count;
02203         op.timeout = timeout;
02204         op.function = pt_aix_sendfile_cont;
02205         op.event = POLLOUT | POLLPRI;
02206         count = pt_Continue(&op);
02207         syserrno = op.syserrno;
02208     }
02209 
02210     if (count == -1) {
02211         pt_MapError(_MD_aix_map_sendfile_error, syserrno);
02212         return -1;
02213     }
02214     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
02215         PR_Close(sd);
02216     }
02217        PR_ASSERT(count == (sfd->hlen + sfd->tlen +
02218                                           ((sfd->file_nbytes ==  0) ?
02219                                           sf_struct.file_size - sfd->file_offset :
02220                                           sfd->file_nbytes)));
02221     return count;
02222 }
02223 #endif /* AIX */
02224 
02225 #ifdef HPUX11
02226 /*
02227  * pt_HPUXSendFile
02228  *
02229  *    Send file sfd->fd across socket sd. If specified, header and trailer
02230  *    buffers are sent before and after the file, respectively.
02231  *
02232  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
02233  *    
02234  *    return number of bytes sent or -1 on error
02235  *
02236  *      This implementation takes advantage of the sendfile() system
02237  *      call available in HP-UX B.11.00.
02238  */
02239 
02240 static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
02241               PRTransmitFileFlags flags, PRIntervalTime timeout)
02242 {
02243     struct stat statbuf;
02244     size_t nbytes_to_send, file_nbytes_to_send;
02245     struct iovec hdtrl[2];  /* optional header and trailer buffers */
02246     int send_flags;
02247     PRInt32 count;
02248     int syserrno;
02249 
02250     if (sfd->file_nbytes == 0) {
02251         /* Get file size */
02252         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
02253             _PR_MD_MAP_FSTAT_ERROR(errno);
02254             return -1;
02255         }            
02256         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
02257     } else {
02258         file_nbytes_to_send = sfd->file_nbytes;
02259     }
02260     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
02261 
02262     hdtrl[0].iov_base = (void *) sfd->header;  /* cast away the 'const' */
02263     hdtrl[0].iov_len = sfd->hlen;
02264     hdtrl[1].iov_base = (void *) sfd->trailer;
02265     hdtrl[1].iov_len = sfd->tlen;
02266     /*
02267      * SF_DISCONNECT seems to close the socket even if sendfile()
02268      * only does a partial send on a nonblocking socket.  This
02269      * would prevent the subsequent sendfile() calls on that socket
02270      * from working.  So we don't use the SD_DISCONNECT flag.
02271      */
02272     send_flags = 0;
02273 
02274     do {
02275         count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
02276                 sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
02277     } while (count == -1 && (syserrno = errno) == EINTR);
02278 
02279     if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
02280         count = 0;
02281     }
02282     if (count != -1 && count < nbytes_to_send) {
02283         pt_Continuation op;
02284 
02285         if (count < sfd->hlen) {
02286                      /* header not sent */
02287 
02288             hdtrl[0].iov_base = ((char *) sfd->header) + count;
02289             hdtrl[0].iov_len = sfd->hlen - count;
02290             op.arg3.file_spec.offset = sfd->file_offset;
02291             op.arg3.file_spec.nbytes = file_nbytes_to_send;
02292         } else if (count < (sfd->hlen + file_nbytes_to_send)) {
02293                      /* header sent, file not sent */
02294 
02295             hdtrl[0].iov_base = NULL;
02296             hdtrl[0].iov_len = 0;
02297 
02298             op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
02299             op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
02300         } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
02301                      PRUint32 trailer_nbytes_sent;
02302 
02303                      /* header sent, file sent, trailer not sent */
02304 
02305             hdtrl[0].iov_base = NULL;
02306             hdtrl[0].iov_len = 0;
02307                      /*
02308                       * set file offset and len so that no more file data is
02309                       * sent
02310                       */
02311             op.arg3.file_spec.offset = statbuf.st_size;
02312             op.arg3.file_spec.nbytes = 0;
02313 
02314                      trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
02315             hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
02316             hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
02317               }
02318 
02319         op.arg1.osfd = sd->secret->md.osfd;
02320         op.filedesc = sfd->fd->secret->md.osfd;
02321         op.arg2.buffer = hdtrl;
02322         op.arg3.file_spec.st_size = statbuf.st_size;
02323         op.arg4.flags = send_flags;
02324         op.nbytes_to_send = nbytes_to_send - count;
02325         op.result.code = count;
02326         op.timeout = timeout;
02327         op.function = pt_hpux_sendfile_cont;
02328         op.event = POLLOUT | POLLPRI;
02329         count = pt_Continue(&op);
02330         syserrno = op.syserrno;
02331     }
02332 
02333     if (count == -1) {
02334         pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
02335         return -1;
02336     }
02337     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
02338         PR_Close(sd);
02339     }
02340     PR_ASSERT(count == nbytes_to_send);
02341     return count;
02342 }
02343 
02344 #endif  /* HPUX11 */
02345 
02346 #ifdef SOLARIS 
02347 
02348 /*
02349  *    pt_SolarisSendFile
02350  *
02351  *    Send file sfd->fd across socket sd. If specified, header and trailer
02352  *    buffers are sent before and after the file, respectively.
02353  *
02354  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
02355  *
02356  *    return number of bytes sent or -1 on error
02357  *
02358  *    This implementation takes advantage of the sendfilev() system
02359  *    call available in Solaris 8.
02360  */
02361 
02362 static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
02363                 PRTransmitFileFlags flags, PRIntervalTime timeout)
02364 {
02365     struct stat statbuf;
02366     size_t nbytes_to_send, file_nbytes_to_send;  
02367     struct sendfilevec sfv_struct[3];  
02368     int sfvcnt = 0;  
02369     size_t xferred;
02370     PRInt32 count;
02371     int syserrno;
02372 
02373     if (sfd->file_nbytes == 0) {
02374         /* Get file size */
02375         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
02376             _PR_MD_MAP_FSTAT_ERROR(errno);
02377             return -1;
02378         }            
02379         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
02380     } else {
02381         file_nbytes_to_send = sfd->file_nbytes;
02382     }
02383 
02384     nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
02385 
02386     if (sfd->hlen != 0) {
02387         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
02388         sfv_struct[sfvcnt].sfv_flag = 0;
02389         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; 
02390         sfv_struct[sfvcnt].sfv_len = sfd->hlen;
02391         sfvcnt++;
02392     }
02393 
02394     if (file_nbytes_to_send != 0) {
02395         sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
02396         sfv_struct[sfvcnt].sfv_flag = 0;
02397         sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
02398         sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
02399         sfvcnt++;
02400     }
02401 
02402     if (sfd->tlen != 0) {
02403         sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
02404         sfv_struct[sfvcnt].sfv_flag = 0;
02405         sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; 
02406         sfv_struct[sfvcnt].sfv_len = sfd->tlen;
02407         sfvcnt++;
02408     }
02409 
02410     if (0 == sfvcnt) {
02411         count = 0;
02412         goto done;
02413     }
02414           
02415     /*
02416      * Strictly speaking, we may have sent some bytes when the
02417      * sendfilev() is interrupted and we should retry it from an
02418      * updated offset.  We are not doing that here.
02419      */
02420     count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
02421             sfvcnt, &xferred);
02422 
02423     PR_ASSERT((count == -1) || (count == xferred));
02424 
02425     if (count == -1) {
02426         syserrno = errno;
02427         if (syserrno == EINTR
02428                 || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
02429             count = xferred;
02430         }
02431     } else if (count == 0) {
02432         /*
02433          * We are now at EOF. The file was truncated. Solaris sendfile is
02434          * supposed to return 0 and no error in this case, though some versions
02435          * may return -1 and EINVAL .
02436          */
02437         count = -1;
02438         syserrno = 0;  /* will be treated as EOF */
02439     }
02440 
02441     if (count != -1 && count < nbytes_to_send) {
02442         pt_Continuation op;
02443         struct sendfilevec *vec = sfv_struct;
02444         PRInt32 rem = count;
02445 
02446         while (rem >= vec->sfv_len) {
02447             rem -= vec->sfv_len;
02448             vec++;
02449             sfvcnt--;
02450         }
02451         PR_ASSERT(sfvcnt > 0);
02452 
02453         vec->sfv_off += rem;
02454         vec->sfv_len -= rem;
02455         PR_ASSERT(vec->sfv_len > 0);
02456 
02457         op.arg1.osfd = sd->secret->md.osfd;
02458         op.arg2.buffer = vec;
02459         op.arg3.amount = sfvcnt;
02460         op.arg4.flags = 0;
02461         op.nbytes_to_send = nbytes_to_send - count;
02462         op.result.code = count;
02463         op.timeout = timeout;
02464         op.function = pt_solaris_sendfile_cont;
02465         op.event = POLLOUT | POLLPRI;
02466         count = pt_Continue(&op);
02467         syserrno = op.syserrno;
02468     }
02469 
02470 done:
02471     if (count == -1) {
02472         pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
02473         return -1;
02474     }
02475     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
02476         PR_Close(sd);
02477     }
02478     PR_ASSERT(count == nbytes_to_send);
02479     return count;
02480 }
02481 
02482 #ifndef HAVE_SENDFILEV
02483 static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
02484 
02485 static void pt_solaris_sendfilev_init_routine(void)
02486 {
02487     void *handle;
02488     PRBool close_it = PR_FALSE;
02489  
02490     /*
02491      * We do not want to unload libsendfile.so.  This handle is leaked
02492      * intentionally.
02493      */
02494     handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
02495     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
02496         ("dlopen(libsendfile.so) returns %p", handle));
02497 
02498     if (NULL == handle) {
02499         /*
02500          * The dlopen(0, mode) call is to allow for the possibility that
02501          * sendfilev() may become part of a standard system library in a
02502          * future Solaris release.
02503          */
02504         handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
02505         PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
02506             ("dlopen(0) returns %p", handle));
02507         close_it = PR_TRUE;
02508     }
02509     pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
02510     PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
02511         ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
02512     
02513     if (close_it) {
02514         dlclose(handle);
02515     }
02516 }
02517 
02518 /* 
02519  * pt_SolarisDispatchSendFile
02520  */
02521 static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
02522          PRTransmitFileFlags flags, PRIntervalTime timeout)
02523 {
02524     int rv;
02525 
02526     rv = pthread_once(&pt_solaris_sendfilev_once_block,
02527             pt_solaris_sendfilev_init_routine);
02528     PR_ASSERT(0 == rv);
02529     if (pt_solaris_sendfilev_fptr) {
02530         return pt_SolarisSendFile(sd, sfd, flags, timeout);
02531     } else {
02532         return PR_EmulateSendFile(sd, sfd, flags, timeout);
02533     }
02534 }
02535 #endif /* !HAVE_SENDFILEV */
02536 
02537 #endif  /* SOLARIS */
02538 
02539 #ifdef LINUX
02540 /*
02541  * pt_LinuxSendFile
02542  *
02543  *    Send file sfd->fd across socket sd. If specified, header and trailer
02544  *    buffers are sent before and after the file, respectively.
02545  *
02546  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
02547  *    
02548  *    return number of bytes sent or -1 on error
02549  *
02550  *      This implementation takes advantage of the sendfile() system
02551  *      call available in Linux kernel 2.2 or higher.
02552  */
02553 
02554 static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
02555                 PRTransmitFileFlags flags, PRIntervalTime timeout)
02556 {
02557     struct stat statbuf;
02558     size_t file_nbytes_to_send;    
02559     PRInt32 count = 0;
02560     ssize_t rv;
02561     int syserrno;
02562     off_t offset;
02563     PRBool tcp_cork_enabled = PR_FALSE;
02564     int tcp_cork;
02565 
02566     if (sfd->file_nbytes == 0) {
02567         /* Get file size */
02568         if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
02569             _PR_MD_MAP_FSTAT_ERROR(errno);
02570             return -1;
02571         }            
02572         file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
02573     } else {
02574         file_nbytes_to_send = sfd->file_nbytes;
02575     }
02576 
02577     if ((sfd->hlen != 0 || sfd->tlen != 0)
02578             && sd->secret->md.tcp_nodelay == 0) {
02579         tcp_cork = 1;
02580         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
02581                 &tcp_cork, sizeof tcp_cork) == 0) {
02582             tcp_cork_enabled = PR_TRUE;
02583         } else {
02584             syserrno = errno;
02585             if (syserrno != EINVAL) {
02586                 _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
02587                 return -1;
02588             }
02589             /*
02590              * The most likely reason for the EINVAL error is that
02591              * TCP_NODELAY is set (with a function other than
02592              * PR_SetSocketOption).  This is not fatal, so we keep
02593              * on going.
02594              */
02595             PR_LOG(_pr_io_lm, PR_LOG_WARNING,
02596                 ("pt_LinuxSendFile: "
02597                 "setsockopt(TCP_CORK) failed with EINVAL\n"));
02598         }
02599     }
02600 
02601     if (sfd->hlen != 0) {
02602         count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
02603         if (count == -1) {
02604             goto failed;
02605         }
02606     }
02607 
02608     if (file_nbytes_to_send != 0) {
02609         offset = sfd->file_offset;
02610         do {
02611             rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
02612                 &offset, file_nbytes_to_send);
02613         } while (rv == -1 && (syserrno = errno) == EINTR);
02614         if (rv == -1) {
02615             if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
02616                 _MD_linux_map_sendfile_error(syserrno);
02617                 count = -1;
02618                 goto failed;
02619             }
02620             rv = 0;
02621         }
02622         PR_ASSERT(rv == offset - sfd->file_offset);
02623         count += rv;
02624 
02625         if (rv < file_nbytes_to_send) {
02626             pt_Continuation op;
02627 
02628             op.arg1.osfd = sd->secret->md.osfd;
02629             op.in_fd = sfd->fd->secret->md.osfd;
02630             op.offset = offset;
02631             op.count = file_nbytes_to_send - rv;
02632             op.result.code = count;
02633             op.timeout = timeout;
02634             op.function = pt_linux_sendfile_cont;
02635             op.event = POLLOUT | POLLPRI;
02636             count = pt_Continue(&op);
02637             syserrno = op.syserrno;
02638             if (count == -1) {
02639                 pt_MapError(_MD_linux_map_sendfile_error, syserrno);
02640                 goto failed;
02641             }
02642         }
02643     }
02644 
02645     if (sfd->tlen != 0) {
02646         rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
02647         if (rv == -1) {
02648             count = -1;
02649             goto failed;
02650         }
02651         count += rv;
02652     }
02653 
02654 failed:
02655     if (tcp_cork_enabled) {
02656         tcp_cork = 0;
02657         if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
02658                 &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
02659             _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
02660             count = -1;
02661         }
02662     }
02663     if (count != -1) {
02664         if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
02665             PR_Close(sd);
02666         }
02667         PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
02668     }
02669     return count;
02670 }
02671 #endif  /* LINUX */
02672 
02673 #ifdef AIX
02674 extern int _pr_aix_send_file_use_disabled;
02675 #endif
02676 
02677 static PRInt32 pt_SendFile(
02678     PRFileDesc *sd, PRSendFileData *sfd,
02679     PRTransmitFileFlags flags, PRIntervalTime timeout)
02680 {
02681     if (pt_TestAbort()) return -1;
02682     /* The socket must be in blocking mode. */
02683     if (sd->secret->nonblocking)
02684     {
02685         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02686         return -1;
02687     }
02688 #ifdef HPUX11
02689     return(pt_HPUXSendFile(sd, sfd, flags, timeout));
02690 #elif defined(AIX)
02691 #ifdef HAVE_SEND_FILE
02692        /*
02693         * A bug in AIX 4.3.2 results in corruption of data transferred by
02694         * send_file(); AIX patch PTF U463956 contains the fix.  A user can
02695         * disable the use of send_file function in NSPR, when this patch is
02696         * not installed on the system, by setting the envionment variable
02697         * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
02698         */
02699        if (_pr_aix_send_file_use_disabled)
02700               return(PR_EmulateSendFile(sd, sfd, flags, timeout));
02701        else
02702        return(pt_AIXSendFile(sd, sfd, flags, timeout));
02703 #else
02704        return(PR_EmulateSendFile(sd, sfd, flags, timeout));
02705     /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
02706 #endif /* HAVE_SEND_FILE */
02707 #elif defined(SOLARIS)
02708 #ifdef HAVE_SENDFILEV
02709        return(pt_SolarisSendFile(sd, sfd, flags, timeout));
02710 #else
02711        return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
02712 #endif /* HAVE_SENDFILEV */
02713 #elif defined(LINUX)
02714        return(pt_LinuxSendFile(sd, sfd, flags, timeout));
02715 #else
02716        return(PR_EmulateSendFile(sd, sfd, flags, timeout));
02717 #endif
02718 }
02719 
02720 static PRInt32 pt_TransmitFile(
02721     PRFileDesc *sd, PRFileDesc *fd, const void *headers,
02722     PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
02723 {
02724        PRSendFileData sfd;
02725 
02726        sfd.fd = fd;
02727        sfd.file_offset = 0;
02728        sfd.file_nbytes = 0;
02729        sfd.header = headers;
02730        sfd.hlen = hlen;
02731        sfd.trailer = NULL;
02732        sfd.tlen = 0;
02733 
02734        return(pt_SendFile(sd, &sfd, flags, timeout));
02735 }  /* pt_TransmitFile */
02736 
02737 static PRInt32 pt_AcceptRead(
02738     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
02739     void *buf, PRInt32 amount, PRIntervalTime timeout)
02740 {
02741     PRInt32 rv = -1;
02742 
02743     if (pt_TestAbort()) return rv;
02744     /* The socket must be in blocking mode. */
02745     if (sd->secret->nonblocking)
02746     {
02747         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
02748         return rv;
02749     }
02750 
02751     rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
02752     return rv;
02753 }  /* pt_AcceptRead */
02754 
02755 static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
02756 {
02757     PRIntn rv = -1;
02758     pt_SockLen addr_len = sizeof(PRNetAddr);
02759 
02760     if (pt_TestAbort()) return PR_FAILURE;
02761 
02762     rv = getsockname(
02763         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
02764     if (rv == -1) {
02765         pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
02766         return PR_FAILURE;
02767     } else {
02768 #ifdef _PR_HAVE_SOCKADDR_LEN
02769         /* ignore the sa_len field of struct sockaddr */
02770         if (addr)
02771         {
02772             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
02773         }
02774 #endif /* _PR_HAVE_SOCKADDR_LEN */
02775 #ifdef _PR_INET6
02776               if (AF_INET6 == addr->raw.family)
02777                      addr->raw.family = PR_AF_INET6;
02778 #endif
02779         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
02780         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
02781         return PR_SUCCESS;
02782     }
02783 }  /* pt_GetSockName */
02784 
02785 static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
02786 {
02787     PRIntn rv = -1;
02788     pt_SockLen addr_len = sizeof(PRNetAddr);
02789 
02790     if (pt_TestAbort()) return PR_FAILURE;
02791 
02792     rv = getpeername(
02793         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
02794 
02795     if (rv == -1) {
02796         pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
02797         return PR_FAILURE;
02798     } else {
02799 #ifdef _PR_HAVE_SOCKADDR_LEN
02800         /* ignore the sa_len field of struct sockaddr */
02801         if (addr)
02802         {
02803             addr->raw.family = ((struct sockaddr*)addr)->sa_family;
02804         }
02805 #endif /* _PR_HAVE_SOCKADDR_LEN */
02806 #ifdef _PR_INET6
02807               if (AF_INET6 == addr->raw.family)
02808               addr->raw.family = PR_AF_INET6;
02809 #endif
02810         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
02811         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
02812         return PR_SUCCESS;
02813     }
02814 }  /* pt_GetPeerName */
02815 
02816 static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
02817 {
02818     PRIntn rv;
02819     pt_SockLen length;
02820     PRInt32 level, name;
02821 
02822     /*
02823      * PR_SockOpt_Nonblocking is a special case that does not
02824      * translate to a getsockopt() call
02825      */
02826     if (PR_SockOpt_Nonblocking == data->option)
02827     {
02828         data->value.non_blocking = fd->secret->nonblocking;
02829         return PR_SUCCESS;
02830     }
02831 
02832     rv = _PR_MapOptionName(data->option, &level, &name);
02833     if (PR_SUCCESS == rv)
02834     {
02835         switch (data->option)
02836         {
02837             case PR_SockOpt_Linger:
02838             {
02839                 struct linger linger;
02840                 length = sizeof(linger);
02841                 rv = getsockopt(
02842                     fd->secret->md.osfd, level, name, (char *) &linger, &length);
02843                 PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
02844                 data->value.linger.polarity =
02845                     (linger.l_onoff) ? PR_TRUE : PR_FALSE;
02846                 data->value.linger.linger =
02847                     PR_SecondsToInterval(linger.l_linger);
02848                 break;
02849             }
02850             case PR_SockOpt_Reuseaddr:
02851             case PR_SockOpt_Keepalive:
02852             case PR_SockOpt_NoDelay:
02853             case PR_SockOpt_Broadcast:
02854             {
02855                 PRIntn value;
02856                 length = sizeof(PRIntn);
02857                 rv = getsockopt(
02858                     fd->secret->md.osfd, level, name, (char*)&value, &length);
02859                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
02860                 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
02861                 break;
02862             }
02863             case PR_SockOpt_McastLoopback:
02864             {
02865                 PRUint8 xbool;
02866                 length = sizeof(xbool);
02867                 rv = getsockopt(
02868                     fd->secret->md.osfd, level, name,
02869                     (char*)&xbool, &length);
02870                 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
02871                 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
02872                 break;
02873             }
02874             case PR_SockOpt_RecvBufferSize:
02875             case PR_SockOpt_SendBufferSize:
02876             case PR_SockOpt_MaxSegment:
02877             {
02878                 PRIntn value;
02879                 length = sizeof(PRIntn);
02880                 rv = getsockopt(
02881                     fd->secret->md.osfd, level, name, (char*)&value, &length);
02882                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
02883                 data->value.recv_buffer_size = value;
02884                 break;
02885             }
02886             case PR_SockOpt_IpTimeToLive:
02887             case PR_SockOpt_IpTypeOfService:
02888             {
02889                 length = sizeof(PRUintn);
02890                 rv = getsockopt(
02891                     fd->secret->md.osfd, level, name,
02892                     (char*)&data->value.ip_ttl, &length);
02893                 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
02894                 break;
02895             }
02896             case PR_SockOpt_McastTimeToLive:
02897             {
02898                 PRUint8 ttl;
02899                 length = sizeof(ttl);
02900                 rv = getsockopt(
02901                     fd->secret->md.osfd, level, name,
02902                     (char*)&ttl, &length);
02903                 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
02904                 data->value.mcast_ttl = ttl;
02905                 break;
02906             }
02907             case PR_SockOpt_AddMember:
02908             case PR_SockOpt_DropMember:
02909             {
02910                 struct ip_mreq mreq;
02911                 length = sizeof(mreq);
02912                 rv = getsockopt(
02913                     fd->secret->md.osfd, level, name, (char*)&mreq, &length);
02914                 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
02915                 data->value.add_member.mcaddr.inet.ip =
02916                     mreq.imr_multiaddr.s_addr;
02917                 data->value.add_member.ifaddr.inet.ip =
02918                     mreq.imr_interface.s_addr;
02919                 break;
02920             }
02921             case PR_SockOpt_McastInterface:
02922             {
02923                 length = sizeof(data->value.mcast_if.inet.ip);
02924                 rv = getsockopt(
02925                     fd->secret->md.osfd, level, name,
02926                     (char*)&data->value.mcast_if.inet.ip, &length);
02927                 PR_ASSERT((-1 == rv)
02928                     || (sizeof(data->value.mcast_if.inet.ip) == length));
02929                 break;
02930             }
02931             default:
02932                 PR_NOT_REACHED("Unknown socket option");
02933                 break;
02934         }
02935         if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
02936     }
02937     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
02938 }  /* pt_GetSocketOption */
02939 
02940 static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
02941 {
02942     PRIntn rv;
02943     PRInt32 level, name;
02944 
02945     /*
02946      * PR_SockOpt_Nonblocking is a special case that does not
02947      * translate to a setsockopt call.
02948      */
02949     if (PR_SockOpt_Nonblocking == data->option)
02950     {
02951         fd->secret->nonblocking = data->value.non_blocking;
02952         return PR_SUCCESS;
02953     }
02954 
02955     rv = _PR_MapOptionName(data->option, &level, &name);
02956     if (PR_SUCCESS == rv)
02957     {
02958         switch (data->option)
02959         {
02960             case PR_SockOpt_Linger:
02961             {
02962                 struct linger linger;
02963                 linger.l_onoff = data->value.linger.polarity;
02964                 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
02965                 rv = setsockopt(
02966                     fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
02967                 break;
02968             }
02969             case PR_SockOpt_Reuseaddr:
02970             case PR_SockOpt_Keepalive:
02971             case PR_SockOpt_NoDelay:
02972             case PR_SockOpt_Broadcast:
02973             {
02974                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
02975                 rv = setsockopt(
02976                     fd->secret->md.osfd, level, name,
02977                     (char*)&value, sizeof(PRIntn));
02978 #ifdef LINUX
02979                 /* for pt_LinuxSendFile */
02980                 if (name == TCP_NODELAY && rv == 0) {
02981                     fd->secret->md.tcp_nodelay = value;
02982                 }
02983 #endif
02984                 break;
02985             }
02986             case PR_SockOpt_McastLoopback:
02987             {
02988                 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
02989                 rv = setsockopt(
02990                     fd->secret->md.osfd, level, name,
02991                     (char*)&xbool, sizeof(xbool));
02992                 break;
02993             }
02994             case PR_SockOpt_RecvBufferSize:
02995             case PR_SockOpt_SendBufferSize:
02996             case PR_SockOpt_MaxSegment:
02997             {
02998                 PRIntn value = data->value.recv_buffer_size;
02999                 rv = setsockopt(
03000                     fd->secret->md.osfd, level, name,
03001                     (char*)&value, sizeof(PRIntn));
03002                 break;
03003             }
03004             case PR_SockOpt_IpTimeToLive:
03005             case PR_SockOpt_IpTypeOfService:
03006             {
03007                 rv = setsockopt(
03008                     fd->secret->md.osfd, level, name,
03009                     (char*)&data->value.ip_ttl, sizeof(PRUintn));
03010                 break;
03011             }
03012             case PR_SockOpt_McastTimeToLive:
03013             {
03014                 PRUint8 ttl = data->value.mcast_ttl;
03015                 rv = setsockopt(
03016                     fd->secret->md.osfd, level, name,
03017                     (char*)&ttl, sizeof(ttl));
03018                 break;
03019             }
03020             case PR_SockOpt_AddMember:
03021             case PR_SockOpt_DropMember:
03022             {
03023                 struct ip_mreq mreq;
03024                 mreq.imr_multiaddr.s_addr =
03025                     data->value.add_member.mcaddr.inet.ip;
03026                 mreq.imr_interface.s_addr =
03027                     data->value.add_member.ifaddr.inet.ip;
03028                 rv = setsockopt(
03029                     fd->secret->md.osfd, level, name,
03030                     (char*)&mreq, sizeof(mreq));
03031                 break;
03032             }
03033             case PR_SockOpt_McastInterface:
03034             {
03035                 rv = setsockopt(
03036                     fd->secret->md.osfd, level, name,
03037                     (char*)&data->value.mcast_if.inet.ip,
03038                     sizeof(data->value.mcast_if.inet.ip));
03039                 break;
03040             }
03041             default:
03042                 PR_NOT_REACHED("Unknown socket option");
03043                 break;
03044         }
03045         if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
03046     }
03047     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
03048 }  /* pt_SetSocketOption */
03049 
03050 /*****************************************************************************/
03051 /****************************** I/O method objects ***************************/
03052 /*****************************************************************************/
03053 
03054 static PRIOMethods _pr_file_methods = {
03055     PR_DESC_FILE,
03056     pt_Close,
03057     pt_Read,
03058     pt_Write,
03059     pt_Available_f,
03060     pt_Available64_f,
03061     pt_Fsync,
03062     pt_Seek,
03063     pt_Seek64,
03064     pt_FileInfo,
03065     pt_FileInfo64,
03066     (PRWritevFN)_PR_InvalidInt,        
03067     (PRConnectFN)_PR_InvalidStatus,        
03068     (PRAcceptFN)_PR_InvalidDesc,        
03069     (PRBindFN)_PR_InvalidStatus,        
03070     (PRListenFN)_PR_InvalidStatus,        
03071     (PRShutdownFN)_PR_InvalidStatus,    
03072     (PRRecvFN)_PR_InvalidInt,        
03073     (PRSendFN)_PR_InvalidInt,        
03074     (PRRecvfromFN)_PR_InvalidInt,    
03075     (PRSendtoFN)_PR_InvalidInt,        
03076     pt_Poll,
03077     (PRAcceptreadFN)_PR_InvalidInt,   
03078     (PRTransmitfileFN)_PR_InvalidInt, 
03079     (PRGetsocknameFN)_PR_InvalidStatus,    
03080     (PRGetpeernameFN)_PR_InvalidStatus,    
03081     (PRReservedFN)_PR_InvalidInt,    
03082     (PRReservedFN)_PR_InvalidInt,    
03083     (PRGetsocketoptionFN)_PR_InvalidStatus,
03084     (PRSetsocketoptionFN)_PR_InvalidStatus,
03085     (PRSendfileFN)_PR_InvalidInt, 
03086     (PRConnectcontinueFN)_PR_InvalidStatus, 
03087     (PRReservedFN)_PR_InvalidInt, 
03088     (PRReservedFN)_PR_InvalidInt, 
03089     (PRReservedFN)_PR_InvalidInt, 
03090     (PRReservedFN)_PR_InvalidInt
03091 };
03092 
03093 static PRIOMethods _pr_pipe_methods = {
03094     PR_DESC_PIPE,
03095     pt_Close,
03096     pt_Read,
03097     pt_Write,
03098     pt_Available_s,
03099     pt_Available64_s,
03100     pt_Synch,
03101     (PRSeekFN)_PR_InvalidInt,
03102     (PRSeek64FN)_PR_InvalidInt64,
03103     (PRFileInfoFN)_PR_InvalidStatus,
03104     (PRFileInfo64FN)_PR_InvalidStatus,
03105     (PRWritevFN)_PR_InvalidInt,        
03106     (PRConnectFN)_PR_InvalidStatus,        
03107     (PRAcceptFN)_PR_InvalidDesc,        
03108     (PRBindFN)_PR_InvalidStatus,        
03109     (PRListenFN)_PR_InvalidStatus,        
03110     (PRShutdownFN)_PR_InvalidStatus,    
03111     (PRRecvFN)_PR_InvalidInt,        
03112     (PRSendFN)_PR_InvalidInt,        
03113     (PRRecvfromFN)_PR_InvalidInt,    
03114     (PRSendtoFN)_PR_InvalidInt,        
03115     pt_Poll,
03116     (PRAcceptreadFN)_PR_InvalidInt,   
03117     (PRTransmitfileFN)_PR_InvalidInt, 
03118     (PRGetsocknameFN)_PR_InvalidStatus,    
03119     (PRGetpeernameFN)_PR_InvalidStatus,    
03120     (PRReservedFN)_PR_InvalidInt,    
03121     (PRReservedFN)_PR_InvalidInt,    
03122     (PRGetsocketoptionFN)_PR_InvalidStatus,
03123     (PRSetsocketoptionFN)_PR_InvalidStatus,
03124     (PRSendfileFN)_PR_InvalidInt, 
03125     (PRConnectcontinueFN)_PR_InvalidStatus, 
03126     (PRReservedFN)_PR_InvalidInt, 
03127     (PRReservedFN)_PR_InvalidInt, 
03128     (PRReservedFN)_PR_InvalidInt, 
03129     (PRReservedFN)_PR_InvalidInt
03130 };
03131 
03132 static PRIOMethods _pr_tcp_methods = {
03133     PR_DESC_SOCKET_TCP,
03134     pt_Close,
03135     pt_SocketRead,
03136     pt_SocketWrite,
03137     pt_Available_s,
03138     pt_Available64_s,
03139     pt_Synch,
03140     (PRSeekFN)_PR_InvalidInt,
03141     (PRSeek64FN)_PR_InvalidInt64,
03142     (PRFileInfoFN)_PR_InvalidStatus,
03143     (PRFileInfo64FN)_PR_InvalidStatus,
03144     pt_Writev,
03145     pt_Connect,
03146     pt_Accept,
03147     pt_Bind,
03148     pt_Listen,
03149     pt_Shutdown,
03150     pt_Recv,
03151     pt_Send,
03152     (PRRecvfromFN)_PR_InvalidInt,
03153     (PRSendtoFN)_PR_InvalidInt,
03154     pt_Poll,
03155     pt_AcceptRead,
03156     pt_TransmitFile,
03157     pt_GetSockName,
03158     pt_GetPeerName,
03159     (PRReservedFN)_PR_InvalidInt,
03160     (PRReservedFN)_PR_InvalidInt,
03161     pt_GetSocketOption,
03162     pt_SetSocketOption,
03163     pt_SendFile, 
03164     pt_ConnectContinue,
03165     (PRReservedFN)_PR_InvalidInt, 
03166     (PRReservedFN)_PR_InvalidInt, 
03167     (PRReservedFN)_PR_InvalidInt, 
03168     (PRReservedFN)_PR_InvalidInt
03169 };
03170 
03171 static PRIOMethods _pr_udp_methods = {
03172     PR_DESC_SOCKET_UDP,
03173     pt_Close,
03174     pt_SocketRead,
03175     pt_SocketWrite,
03176     pt_Available_s,
03177     pt_Available64_s,
03178     pt_Synch,
03179     (PRSeekFN)_PR_InvalidInt,
03180     (PRSeek64FN)_PR_InvalidInt64,
03181     (PRFileInfoFN)_PR_InvalidStatus,
03182     (PRFileInfo64FN)_PR_InvalidStatus,
03183     pt_Writev,
03184     pt_Connect,
03185     (PRAcceptFN)_PR_InvalidDesc,
03186     pt_Bind,
03187     pt_Listen,
03188     pt_Shutdown,
03189     pt_Recv,
03190     pt_Send,
03191     pt_RecvFrom,
03192     pt_SendTo,
03193     pt_Poll,
03194     (PRAcceptreadFN)_PR_InvalidInt,
03195     (PRTransmitfileFN)_PR_InvalidInt,
03196     pt_GetSockName,
03197     pt_GetPeerName,
03198     (PRReservedFN)_PR_InvalidInt,
03199     (PRReservedFN)_PR_InvalidInt,
03200     pt_GetSocketOption,
03201     pt_SetSocketOption,
03202     (PRSendfileFN)_PR_InvalidInt, 
03203     (PRConnectcontinueFN)_PR_InvalidStatus, 
03204     (PRReservedFN)_PR_InvalidInt, 
03205     (PRReservedFN)_PR_InvalidInt, 
03206     (PRReservedFN)_PR_InvalidInt, 
03207     (PRReservedFN)_PR_InvalidInt
03208 };
03209 
03210 static PRIOMethods _pr_socketpollfd_methods = {
03211     (PRDescType) 0,
03212     (PRCloseFN)_PR_InvalidStatus,
03213     (PRReadFN)_PR_InvalidInt,
03214     (PRWriteFN)_PR_InvalidInt,
03215     (PRAvailableFN)_PR_InvalidInt,
03216     (PRAvailable64FN)_PR_InvalidInt64,
03217     (PRFsyncFN)_PR_InvalidStatus,
03218     (PRSeekFN)_PR_InvalidInt,
03219     (PRSeek64FN)_PR_InvalidInt64,
03220     (PRFileInfoFN)_PR_InvalidStatus,
03221     (PRFileInfo64FN)_PR_InvalidStatus,
03222     (PRWritevFN)_PR_InvalidInt,        
03223     (PRConnectFN)_PR_InvalidStatus,        
03224     (PRAcceptFN)_PR_InvalidDesc,        
03225     (PRBindFN)_PR_InvalidStatus,        
03226     (PRListenFN)_PR_InvalidStatus,        
03227     (PRShutdownFN)_PR_InvalidStatus,    
03228     (PRRecvFN)_PR_InvalidInt,        
03229     (PRSendFN)_PR_InvalidInt,        
03230     (PRRecvfromFN)_PR_InvalidInt,    
03231     (PRSendtoFN)_PR_InvalidInt,        
03232        pt_Poll,
03233     (PRAcceptreadFN)_PR_InvalidInt,   
03234     (PRTransmitfileFN)_PR_InvalidInt, 
03235     (PRGetsocknameFN)_PR_InvalidStatus,    
03236     (PRGetpeernameFN)_PR_InvalidStatus,    
03237     (PRReservedFN)_PR_InvalidInt,    
03238     (PRReservedFN)_PR_InvalidInt,    
03239     (PRGetsocketoptionFN)_PR_InvalidStatus,
03240     (PRSetsocketoptionFN)_PR_InvalidStatus,
03241     (PRSendfileFN)_PR_InvalidInt, 
03242     (PRConnectcontinueFN)_PR_InvalidStatus, 
03243     (PRReservedFN)_PR_InvalidInt, 
03244     (PRReservedFN)_PR_InvalidInt, 
03245     (PRReservedFN)_PR_InvalidInt, 
03246     (PRReservedFN)_PR_InvalidInt
03247 };
03248 
03249 #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
03250     || defined(AIX) || defined(LINUX) || defined(FREEBSD) || defined(NETBSD) \
03251     || defined(OPENBSD) || defined(BSDI) || defined(VMS) || defined(NTO) \
03252     || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS)
03253 #define _PR_FCNTL_FLAGS O_NONBLOCK
03254 #else
03255 #error "Can't determine architecture"
03256 #endif
03257 
03258 /*
03259  * Put a Unix file descriptor in non-blocking mode.
03260  */
03261 static void pt_MakeFdNonblock(PRIntn osfd)
03262 {
03263     PRIntn flags;
03264     flags = fcntl(osfd, F_GETFL, 0);
03265     flags |= _PR_FCNTL_FLAGS;
03266     (void)fcntl(osfd, F_SETFL, flags);
03267 }
03268 
03269 /*
03270  * Put a Unix socket fd in non-blocking mode that can
03271  * ideally be inherited by an accepted socket.
03272  *
03273  * Why doesn't pt_MakeFdNonblock do?  This is to deal with
03274  * the special case of HP-UX.  HP-UX has three kinds of
03275  * non-blocking modes for sockets: the fcntl() O_NONBLOCK
03276  * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
03277  * the ioctl() FIOSNBIO form of non-blocking mode is
03278  * inherited by an accepted socket.
03279  *
03280  * Other platforms just use the generic pt_MakeFdNonblock
03281  * to put a socket in non-blocking mode.
03282  */
03283 #ifdef HPUX
03284 static void pt_MakeSocketNonblock(PRIntn osfd)
03285 {
03286     PRIntn one = 1;
03287     (void)ioctl(osfd, FIOSNBIO, &one);
03288 }
03289 #else
03290 #define pt_MakeSocketNonblock pt_MakeFdNonblock
03291 #endif
03292 
03293 static PRFileDesc *pt_SetMethods(
03294     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
03295 {
03296     PRFileDesc *fd = _PR_Getfd();
03297     
03298     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
03299     else
03300     {
03301         fd->secret->md.osfd = osfd;
03302         fd->secret->state = _PR_FILEDESC_OPEN;
03303         if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
03304         else
03305         {
03306             /* By default, a Unix fd is not closed on exec. */
03307 #ifdef DEBUG
03308             PRIntn flags;
03309             flags = fcntl(osfd, F_GETFD, 0);
03310             PR_ASSERT(0 == flags);
03311 #endif
03312             fd->secret->inheritable = _PR_TRI_TRUE;
03313         }
03314         switch (type)
03315         {
03316             case PR_DESC_FILE:
03317                 fd->methods = PR_GetFileMethods();
03318                 break;
03319             case PR_DESC_SOCKET_TCP:
03320                 fd->methods = PR_GetTCPMethods();
03321 #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
03322                 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
03323 #else
03324                 pt_MakeSocketNonblock(osfd);
03325 #endif
03326                 break;
03327             case PR_DESC_SOCKET_UDP:
03328                 fd->methods = PR_GetUDPMethods();
03329                 pt_MakeFdNonblock(osfd);
03330                 break;
03331             case PR_DESC_PIPE:
03332                 fd->methods = PR_GetPipeMethods();
03333                 pt_MakeFdNonblock(osfd);
03334                 break;
03335             default:
03336                 break;
03337         }
03338     }
03339     return fd;
03340 }  /* pt_SetMethods */
03341 
03342 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
03343 {
03344     return &_pr_file_methods;
03345 }  /* PR_GetFileMethods */
03346 
03347 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
03348 {
03349     return &_pr_pipe_methods;
03350 }  /* PR_GetPipeMethods */
03351 
03352 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
03353 {
03354     return &_pr_tcp_methods;
03355 }  /* PR_GetTCPMethods */
03356 
03357 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
03358 {
03359     return &_pr_udp_methods;
03360 }  /* PR_GetUDPMethods */
03361 
03362 static const PRIOMethods* PR_GetSocketPollFdMethods(void)
03363 {
03364     return &_pr_socketpollfd_methods;
03365 }  /* PR_GetSocketPollFdMethods */
03366 
03367 PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
03368     PRInt32 osfd, const PRIOMethods *methods)
03369 {
03370     PRFileDesc *fd = _PR_Getfd();
03371 
03372     if (NULL == fd) goto failed;
03373 
03374     fd->methods = methods;
03375     fd->secret->md.osfd = osfd;
03376     /* Make fd non-blocking */
03377     if (osfd > 2)
03378     {
03379         /* Don't mess around with stdin, stdout or stderr */
03380         if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
03381         else pt_MakeFdNonblock(osfd);
03382     }
03383     fd->secret->state = _PR_FILEDESC_OPEN;
03384     fd->secret->inheritable = _PR_TRI_UNKNOWN;
03385     return fd;
03386     
03387 failed:
03388     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
03389     return fd;
03390 }  /* PR_AllocFileDesc */
03391 
03392 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
03393 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
03394 #if defined(_PR_INET6_PROBE)
03395 PR_EXTERN(PRBool) _pr_ipv6_is_present;
03396 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
03397 {
03398 PRInt32 osfd;
03399 
03400 #if defined(DARWIN)
03401     /*
03402      * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
03403      * lesser versions is not ready for general use (see bug 222031).
03404      */
03405     {
03406         struct utsname u;
03407         if (uname(&u) != 0 || atoi(u.release) < 7)
03408             return PR_FALSE;
03409     }
03410 #endif
03411 
03412     /*
03413      * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
03414      * suggests that we call open("/dev/ip6", O_RDWR) to determine
03415      * whether IPv6 APIs and the IPv6 stack are on the system.
03416      * Our portable test below seems to work fine, so I am using it.
03417      */
03418     osfd = socket(AF_INET6, SOCK_STREAM, 0);
03419     if (osfd != -1) {
03420         close(osfd);
03421         return PR_TRUE;
03422     }
03423     return PR_FALSE;
03424 }
03425 #endif /* _PR_INET6_PROBE */
03426 #endif
03427 
03428 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
03429 {
03430     PRIntn osfd;
03431     PRDescType ftype;
03432     PRFileDesc *fd = NULL;
03433        PRInt32 tmp_domain = domain;
03434 
03435     if (!_pr_initialized) _PR_ImplicitInitialization();
03436 
03437     if (pt_TestAbort()) return NULL;
03438 
03439     if (PF_INET != domain
03440         && PR_AF_INET6 != domain
03441         && PF_UNIX != domain)
03442     {
03443         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
03444         return fd;
03445     }
03446        if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
03447        else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
03448        else
03449        {
03450               (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
03451               return fd;
03452        }
03453 #if defined(_PR_INET6_PROBE)
03454        if (PR_AF_INET6 == domain) {
03455               if (_pr_ipv6_is_present == PR_FALSE) 
03456                      domain = AF_INET;
03457               else
03458                      domain = AF_INET6;
03459        }
03460 #elif defined(_PR_INET6) 
03461        if (PR_AF_INET6 == domain)
03462               domain = AF_INET6;
03463 #else
03464        if (PR_AF_INET6 == domain)
03465               domain = AF_INET;
03466 #endif
03467 
03468     osfd = socket(domain, type, proto);
03469     if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
03470     else
03471     {
03472 #ifdef _PR_IPV6_V6ONLY_PROBE
03473         if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
03474         {
03475             int on = 0;
03476             (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
03477                     &on, sizeof(on));
03478         }
03479 #endif
03480         fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
03481         if (fd == NULL) close(osfd);
03482     }
03483 #ifdef _PR_NEED_SECRET_AF
03484     if (fd != NULL) fd->secret->af = domain;
03485 #endif
03486 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
03487        if (fd != NULL) {
03488               /*
03489                * For platforms with no support for IPv6 
03490                * create layered socket for IPv4-mapped IPv6 addresses
03491                */
03492               if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
03493                      if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
03494                             PR_Close(fd);
03495                             fd = NULL;
03496                      }
03497               }
03498        }
03499 #endif
03500     return fd;
03501 }  /* PR_Socket */
03502 
03503 /*****************************************************************************/
03504 /****************************** I/O public methods ***************************/
03505 /*****************************************************************************/
03506 
03507 PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
03508     const char *name, PRIntn flags, PRIntn mode)
03509 {
03510     PRFileDesc *fd = NULL;
03511     PRIntn syserrno, osfd = -1, osflags = 0;;
03512 
03513     if (!_pr_initialized) _PR_ImplicitInitialization();
03514 
03515     if (pt_TestAbort()) return NULL;
03516 
03517     if (flags & PR_RDONLY) osflags |= O_RDONLY;
03518     if (flags & PR_WRONLY) osflags |= O_WRONLY;
03519     if (flags & PR_RDWR) osflags |= O_RDWR;
03520     if (flags & PR_APPEND) osflags |= O_APPEND;
03521     if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
03522     if (flags & PR_EXCL) osflags |= O_EXCL;
03523     if (flags & PR_SYNC)
03524     {
03525 #if defined(O_SYNC)
03526         osflags |= O_SYNC;
03527 #elif defined(O_FSYNC)
03528         osflags |= O_FSYNC;
03529 #else
03530 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
03531 #endif
03532     }
03533 
03534     /*
03535     ** We have to hold the lock across the creation in order to
03536     ** enforce the sematics of PR_Rename(). (see the latter for
03537     ** more details)
03538     */
03539     if (flags & PR_CREATE_FILE)
03540     {
03541         osflags |= O_CREAT;
03542         if (NULL !=_pr_rename_lock)
03543             PR_Lock(_pr_rename_lock);
03544     }
03545 
03546     osfd = _md_iovector._open64(name, osflags, mode);
03547     syserrno = errno;
03548 
03549     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
03550         PR_Unlock(_pr_rename_lock);
03551 
03552     if (osfd == -1)
03553         pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
03554     else
03555     {
03556         fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
03557         if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
03558     }
03559     return fd;
03560 }  /* PR_OpenFile */
03561 
03562 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
03563 {
03564     return PR_OpenFile(name, flags, mode);
03565 }  /* PR_Open */
03566 
03567 PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
03568 {
03569     PRIntn rv = -1;
03570 
03571     if (!_pr_initialized) _PR_ImplicitInitialization();
03572 
03573     if (pt_TestAbort()) return PR_FAILURE;
03574 
03575     rv = unlink(name);
03576 
03577     if (rv == -1) {
03578         pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
03579         return PR_FAILURE;
03580     } else
03581         return PR_SUCCESS;
03582 }  /* PR_Delete */
03583 
03584 PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
03585 {
03586     PRIntn rv;
03587 
03588     if (pt_TestAbort()) return PR_FAILURE;
03589 
03590     switch (how)
03591     {
03592     case PR_ACCESS_READ_OK:
03593         rv =  access(name, R_OK);
03594         break;
03595     case PR_ACCESS_WRITE_OK:
03596         rv = access(name, W_OK);
03597         break;
03598     case PR_ACCESS_EXISTS:
03599     default:
03600         rv = access(name, F_OK);
03601     }
03602     if (0 == rv) return PR_SUCCESS;
03603     pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
03604     return PR_FAILURE;
03605     
03606 }  /* PR_Access */
03607 
03608 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
03609 {
03610     PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
03611     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
03612 }  /* PR_GetFileInfo */
03613 
03614 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
03615 {
03616     PRInt32 rv;
03617 
03618     if (!_pr_initialized) _PR_ImplicitInitialization();
03619     rv = _PR_MD_GETFILEINFO64(fn, info);
03620     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
03621 }  /* PR_GetFileInfo64 */
03622 
03623 PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
03624 {
03625     PRIntn rv = -1;
03626 
03627     if (pt_TestAbort()) return PR_FAILURE;
03628 
03629     /*
03630     ** We have to acquire a lock here to stiffle anybody trying to create
03631     ** a new file at the same time. And we have to hold that lock while we
03632     ** test to see if the file exists and do the rename. The other place
03633     ** where the lock is held is in PR_Open() when possibly creating a 
03634     ** new file.
03635     */
03636 
03637     PR_Lock(_pr_rename_lock);
03638     rv = access(to, F_OK);
03639     if (0 == rv)
03640     {
03641         PR_SetError(PR_FILE_EXISTS_ERROR, 0);
03642         rv = -1;
03643     }
03644     else
03645     {
03646         rv = rename(from, to);
03647         if (rv == -1)
03648             pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
03649     }
03650     PR_Unlock(_pr_rename_lock);
03651     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
03652 }  /* PR_Rename */
03653 
03654 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
03655 {
03656     if (pt_TestAbort()) return PR_FAILURE;
03657 
03658     if (NULL != dir->md.d)
03659     {
03660         if (closedir(dir->md.d) == -1)
03661         {
03662             _PR_MD_MAP_CLOSEDIR_ERROR(errno);
03663             return PR_FAILURE;
03664         }
03665         dir->md.d = NULL;
03666         PR_DELETE(dir);
03667     }
03668     return PR_SUCCESS;
03669 }  /* PR_CloseDir */
03670 
03671 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
03672 {
03673     PRInt32 rv = -1;
03674 
03675     if (pt_TestAbort()) return PR_FAILURE;
03676 
03677     /*
03678     ** This lock is used to enforce rename semantics as described
03679     ** in PR_Rename.
03680     */
03681     if (NULL !=_pr_rename_lock)
03682         PR_Lock(_pr_rename_lock);
03683     rv = mkdir(name, mode);
03684     if (-1 == rv)
03685         pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
03686     if (NULL !=_pr_rename_lock)
03687         PR_Unlock(_pr_rename_lock);
03688 
03689     return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
03690 }  /* PR_Makedir */
03691 
03692 PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
03693 {
03694     return PR_MakeDir(name, mode);
03695 }  /* PR_Mkdir */
03696 
03697 PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
03698 {
03699     PRInt32 rv;
03700 
03701     if (pt_TestAbort()) return PR_FAILURE;
03702 
03703     rv = rmdir(name);
03704     if (0 == rv) {
03705     return PR_SUCCESS;
03706     } else {
03707     pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
03708     return PR_FAILURE;
03709     }
03710 }  /* PR_Rmdir */
03711 
03712 
03713 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
03714 {
03715     DIR *osdir;
03716     PRDir *dir = NULL;
03717 
03718     if (pt_TestAbort()) return dir;
03719 
03720     osdir = opendir(name);
03721     if (osdir == NULL)
03722         pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
03723     else
03724     {
03725         dir = PR_NEWZAP(PRDir);
03726         dir->md.d = osdir;
03727     }
03728     return dir;
03729 }  /* PR_OpenDir */
03730 
03731 static PRInt32 _pr_poll_with_poll(
03732     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
03733 {
03734     PRInt32 ready = 0;
03735     /*
03736      * For restarting poll() if it is interrupted by a signal.
03737      * We use these variables to figure out how much time has
03738      * elapsed and how much of the timeout still remains.
03739      */
03740     PRIntervalTime start, elapsed, remaining;
03741 
03742     if (pt_TestAbort()) return -1;
03743 
03744     if (0 == npds) PR_Sleep(timeout);
03745     else
03746     {
03747 #define STACK_POLL_DESC_COUNT 64
03748         struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
03749         struct pollfd *syspoll;
03750         PRIntn index, msecs;
03751 
03752         if (npds <= STACK_POLL_DESC_COUNT)
03753         {
03754             syspoll = stack_syspoll;
03755         }
03756         else
03757         {
03758             PRThread *me = PR_GetCurrentThread();
03759             if (npds > me->syspoll_count)
03760             {
03761                 PR_Free(me->syspoll_list);
03762                 me->syspoll_list =
03763                     (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
03764                 if (NULL == me->syspoll_list)
03765                 {
03766                     me->syspoll_count = 0;
03767                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
03768                     return -1;
03769                 }
03770                 me->syspoll_count = npds;
03771             }
03772             syspoll = me->syspoll_list;
03773         }
03774 
03775         for (index = 0; index < npds; ++index)
03776         {
03777             PRInt16 in_flags_read = 0, in_flags_write = 0;
03778             PRInt16 out_flags_read = 0, out_flags_write = 0;
03779 
03780             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
03781             {
03782                 if (pds[index].in_flags & PR_POLL_READ)
03783                 {
03784                     in_flags_read = (pds[index].fd->methods->poll)(
03785                         pds[index].fd,
03786                         pds[index].in_flags & ~PR_POLL_WRITE,
03787                         &out_flags_read);
03788                 }
03789                 if (pds[index].in_flags & PR_POLL_WRITE)
03790                 {
03791                     in_flags_write = (pds[index].fd->methods->poll)(
03792                         pds[index].fd,
03793                         pds[index].in_flags & ~PR_POLL_READ,
03794                         &out_flags_write);
03795                 }
03796                 if ((0 != (in_flags_read & out_flags_read))
03797                 || (0 != (in_flags_write & out_flags_write)))
03798                 {
03799                     /* this one is ready right now */
03800                     if (0 == ready)
03801                     {
03802                         /*
03803                          * We will return without calling the system
03804                          * poll function.  So zero the out_flags
03805                          * fields of all the poll descriptors before
03806                          * this one.
03807                          */
03808                         int i;
03809                         for (i = 0; i < index; i++)
03810                         {
03811                             pds[i].out_flags = 0;
03812                         }
03813                     }
03814                     ready += 1;
03815                     pds[index].out_flags = out_flags_read | out_flags_write;
03816                 }
03817                 else
03818                 {
03819                     /* now locate the NSPR layer at the bottom of the stack */
03820                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
03821                         pds[index].fd, PR_NSPR_IO_LAYER);
03822                     PR_ASSERT(NULL != bottom);  /* what to do about that? */
03823                     pds[index].out_flags = 0;  /* pre-condition */
03824                     if ((NULL != bottom)
03825                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
03826                     {
03827                         if (0 == ready)
03828                         {
03829                             syspoll[index].fd = bottom->secret->md.osfd;
03830                             syspoll[index].events = 0;
03831                             if (in_flags_read & PR_POLL_READ)
03832                             {
03833                                 pds[index].out_flags |=
03834                                     _PR_POLL_READ_SYS_READ;
03835                                 syspoll[index].events |= POLLIN;
03836                             }
03837                             if (in_flags_read & PR_POLL_WRITE)
03838                             {
03839                                 pds[index].out_flags |=
03840                                     _PR_POLL_READ_SYS_WRITE;
03841                                 syspoll[index].events |= POLLOUT;
03842                             }
03843                             if (in_flags_write & PR_POLL_READ)
03844                             {
03845                                 pds[index].out_flags |=
03846                                     _PR_POLL_WRITE_SYS_READ;
03847                                 syspoll[index].events |= POLLIN;
03848                             }
03849                             if (in_flags_write & PR_POLL_WRITE)
03850                             {
03851                                 pds[index].out_flags |=
03852                                     _PR_POLL_WRITE_SYS_WRITE;
03853                                 syspoll[index].events |= POLLOUT;
03854                             }
03855                             if (pds[index].in_flags & PR_POLL_EXCEPT)
03856                                 syspoll[index].events |= POLLPRI;
03857                         }
03858                     }
03859                     else
03860                     {
03861                         if (0 == ready)
03862                         {
03863                             int i;
03864                             for (i = 0; i < index; i++)
03865                             {
03866                                 pds[i].out_flags = 0;
03867                             }
03868                         }
03869                         ready += 1;  /* this will cause an abrupt return */
03870                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
03871                     }
03872                 }
03873             }
03874             else
03875             {
03876                 /* make poll() ignore this entry */
03877                 syspoll[index].fd = -1;
03878                 syspoll[index].events = 0;
03879                 pds[index].out_flags = 0;
03880             }
03881         }
03882         if (0 == ready)
03883         {
03884             switch (timeout)
03885             {
03886             case PR_INTERVAL_NO_WAIT: msecs = 0; break;
03887             case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
03888             default:
03889                 msecs = PR_IntervalToMilliseconds(timeout);
03890                 start = PR_IntervalNow();
03891             }
03892 
03893 retry:
03894             ready = poll(syspoll, npds, msecs);
03895             if (-1 == ready)
03896             {
03897                 PRIntn oserror = errno;
03898 
03899                 if (EINTR == oserror)
03900                 {
03901                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
03902                         goto retry;
03903                     else if (timeout == PR_INTERVAL_NO_WAIT)
03904                         ready = 0;  /* don't retry, just time out */
03905                     else
03906                     {
03907                         elapsed = (PRIntervalTime) (PR_IntervalNow()
03908                                 - start);
03909                         if (elapsed > timeout)
03910                             ready = 0;  /* timed out */
03911                         else
03912                         {
03913                             remaining = timeout - elapsed;
03914                             msecs = PR_IntervalToMilliseconds(remaining);
03915                             goto retry;
03916                         }
03917                     }
03918                 }
03919                 else
03920                 {
03921                     _PR_MD_MAP_POLL_ERROR(oserror);
03922                 }
03923             }
03924             else if (ready > 0)
03925             {
03926                 for (index = 0; index < npds; ++index)
03927                 {
03928                     PRInt16 out_flags = 0;
03929                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
03930                     {
03931                         if (0 != syspoll[index].revents)
03932                         {
03933                             if (syspoll[index].revents & POLLIN)
03934                             {
03935                                 if (pds[index].out_flags
03936                                 & _PR_POLL_READ_SYS_READ)
03937                                 {
03938                                     out_flags |= PR_POLL_READ;
03939                                 }
03940                                 if (pds[index].out_flags
03941                                 & _PR_POLL_WRITE_SYS_READ)
03942                                 {
03943                                     out_flags |= PR_POLL_WRITE;
03944                                 }
03945                             }
03946                             if (syspoll[index].revents & POLLOUT)
03947                             {
03948                                 if (pds[index].out_flags
03949                                 & _PR_POLL_READ_SYS_WRITE)
03950                                 {
03951                                     out_flags |= PR_POLL_READ;
03952                                 }
03953                                 if (pds[index].out_flags
03954                                 & _PR_POLL_WRITE_SYS_WRITE)
03955                                 {
03956                                     out_flags |= PR_POLL_WRITE;
03957                                 }
03958                             }
03959                             if (syspoll[index].revents & POLLPRI)
03960                                 out_flags |= PR_POLL_EXCEPT;
03961                             if (syspoll[index].revents & POLLERR)
03962                                 out_flags |= PR_POLL_ERR;
03963                             if (syspoll[index].revents & POLLNVAL)
03964                                 out_flags |= PR_POLL_NVAL;
03965                             if (syspoll[index].revents & POLLHUP)
03966                                 out_flags |= PR_POLL_HUP;
03967                         }
03968                     }
03969                     pds[index].out_flags = out_flags;
03970                 }
03971             }
03972         }
03973     }
03974     return ready;
03975 
03976 } /* _pr_poll_with_poll */
03977 
03978 #if defined(_PR_POLL_WITH_SELECT)
03979 /*
03980  * OSF1 and HPUX report the POLLHUP event for a socket when the
03981  * shutdown(SHUT_WR) operation is called for the remote end, even though
03982  * the socket is still writeable. Use select(), instead of poll(), to
03983  * workaround this problem.
03984  */
03985 static PRInt32 _pr_poll_with_select(
03986     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
03987 {
03988     PRInt32 ready = 0;
03989     /*
03990      * For restarting select() if it is interrupted by a signal.
03991      * We use these variables to figure out how much time has
03992      * elapsed and how much of the timeout still remains.
03993      */
03994     PRIntervalTime start, elapsed, remaining;
03995 
03996     if (pt_TestAbort()) return -1;
03997 
03998     if (0 == npds) PR_Sleep(timeout);
03999     else
04000     {
04001 #define STACK_POLL_DESC_COUNT 64
04002         int stack_selectfd[STACK_POLL_DESC_COUNT];
04003         int *selectfd;
04004               fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
04005               struct timeval tv, *tvp;
04006         PRIntn index, msecs, maxfd = 0;
04007 
04008         if (npds <= STACK_POLL_DESC_COUNT)
04009         {
04010             selectfd = stack_selectfd;
04011         }
04012         else
04013         {
04014             PRThread *me = PR_GetCurrentThread();
04015             if (npds > me->selectfd_count)
04016             {
04017                 PR_Free(me->selectfd_list);
04018                 me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
04019                 if (NULL == me->selectfd_list)
04020                 {
04021                     me->selectfd_count = 0;
04022                     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
04023                     return -1;
04024                 }
04025                 me->selectfd_count = npds;
04026             }
04027             selectfd = me->selectfd_list;
04028         }
04029               FD_ZERO(&rd);
04030               FD_ZERO(&wr);
04031               FD_ZERO(&ex);
04032 
04033         for (index = 0; index < npds; ++index)
04034         {
04035             PRInt16 in_flags_read = 0, in_flags_write = 0;
04036             PRInt16 out_flags_read = 0, out_flags_write = 0;
04037 
04038             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
04039             {
04040                 if (pds[index].in_flags & PR_POLL_READ)
04041                 {
04042                     in_flags_read = (pds[index].fd->methods->poll)(
04043                         pds[index].fd,
04044                         pds[index].in_flags & ~PR_POLL_WRITE,
04045                         &out_flags_read);
04046                 }
04047                 if (pds[index].in_flags & PR_POLL_WRITE)
04048                 {
04049                     in_flags_write = (pds[index].fd->methods->poll)(
04050                         pds[index].fd,
04051                         pds[index].in_flags & ~PR_POLL_READ,
04052                         &out_flags_write);
04053                 }
04054                 if ((0 != (in_flags_read & out_flags_read))
04055                 || (0 != (in_flags_write & out_flags_write)))
04056                 {
04057                     /* this one is ready right now */
04058                     if (0 == ready)
04059                     {
04060                         /*
04061                          * We will return without calling the system
04062                          * poll function.  So zero the out_flags
04063                          * fields of all the poll descriptors before
04064                          * this one.
04065                          */
04066                         int i;
04067                         for (i = 0; i < index; i++)
04068                         {
04069                             pds[i].out_flags = 0;
04070                         }
04071                     }
04072                     ready += 1;
04073                     pds[index].out_flags = out_flags_read | out_flags_write;
04074                 }
04075                 else
04076                 {
04077                     /* now locate the NSPR layer at the bottom of the stack */
04078                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
04079                         pds[index].fd, PR_NSPR_IO_LAYER);
04080                     PR_ASSERT(NULL != bottom);  /* what to do about that? */
04081                     pds[index].out_flags = 0;  /* pre-condition */
04082                     if ((NULL != bottom)
04083                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
04084                     {
04085                         if (0 == ready)
04086                         {
04087                             PRBool add_to_rd = PR_FALSE;
04088                             PRBool add_to_wr = PR_FALSE;
04089                             PRBool add_to_ex = PR_FALSE;
04090 
04091                             selectfd[index] = bottom->secret->md.osfd;
04092                             if (in_flags_read & PR_POLL_READ)
04093                             {
04094                                 pds[index].out_flags |=
04095                                     _PR_POLL_READ_SYS_READ;
04096                                 add_to_rd = PR_TRUE;
04097                             }
04098                             if (in_flags_read & PR_POLL_WRITE)
04099                             {
04100                                 pds[index].out_flags |=
04101                                     _PR_POLL_READ_SYS_WRITE;
04102                                 add_to_wr = PR_TRUE;
04103                             }
04104                             if (in_flags_write & PR_POLL_READ)
04105                             {
04106                                 pds[index].out_flags |=
04107                                     _PR_POLL_WRITE_SYS_READ;
04108                                 add_to_rd = PR_TRUE;
04109                             }
04110                             if (in_flags_write & PR_POLL_WRITE)
04111                             {
04112                                 pds[index].out_flags |=
04113                                     _PR_POLL_WRITE_SYS_WRITE;
04114                                 add_to_wr = PR_TRUE;
04115                             }
04116                             if (pds[index].in_flags & PR_POLL_EXCEPT)
04117                             {
04118                                 add_to_ex = PR_TRUE;
04119                             }
04120                             if ((selectfd[index] > maxfd) &&
04121                                     (add_to_rd || add_to_wr || add_to_ex))
04122                             {
04123                                 maxfd = selectfd[index];
04124                                 /*
04125                                  * If maxfd is too large to be used with
04126                                  * select, fall back to calling poll.
04127                                  */
04128                                 if (maxfd >= FD_SETSIZE)
04129                                     break;
04130                             }
04131                             if (add_to_rd)
04132                             {
04133                                 FD_SET(bottom->secret->md.osfd, &rd);
04134                                 rdp = &rd;
04135                             }
04136                             if (add_to_wr)
04137                             {
04138                                 FD_SET(bottom->secret->md.osfd, &wr);
04139                                 wrp = &wr;
04140                             }
04141                             if (add_to_ex)
04142                             {
04143                                 FD_SET(bottom->secret->md.osfd, &ex);
04144                                 exp = &ex;
04145                             }
04146                         }
04147                     }
04148                     else
04149                     {
04150                         if (0 == ready)
04151                         {
04152                             int i;
04153                             for (i = 0; i < index; i++)
04154                             {
04155                                 pds[i].out_flags = 0;
04156                             }
04157                         }
04158                         ready += 1;  /* this will cause an abrupt return */
04159                         pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
04160                     }
04161                 }
04162             }
04163             else
04164             {
04165                 pds[index].out_flags = 0;
04166             }
04167         }
04168         if (0 == ready)
04169         {
04170                      if (maxfd >= FD_SETSIZE)
04171                      {
04172                             /*
04173                              * maxfd too large to be used with select, fall back to
04174                              * calling poll
04175                              */
04176                             return(_pr_poll_with_poll(pds, npds, timeout));
04177                      }
04178             switch (timeout)
04179             {
04180             case PR_INTERVAL_NO_WAIT:
04181                             tv.tv_sec = 0;
04182                             tv.tv_usec = 0;
04183                             tvp = &tv;
04184                             break;
04185             case PR_INTERVAL_NO_TIMEOUT:
04186                             tvp = NULL;
04187                             break;
04188             default:
04189                 msecs = PR_IntervalToMilliseconds(timeout);
04190                             tv.tv_sec = msecs/PR_MSEC_PER_SEC;
04191                             tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
04192                             tvp = &tv;
04193                 start = PR_IntervalNow();
04194             }
04195 
04196 retry:
04197             ready = select(maxfd + 1, rdp, wrp, exp, tvp);
04198             if (-1 == ready)
04199             {
04200                 PRIntn oserror = errno;
04201 
04202                 if ((EINTR == oserror) || (EAGAIN == oserror))
04203                 {
04204                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
04205                         goto retry;
04206                     else if (timeout == PR_INTERVAL_NO_WAIT)
04207                         ready = 0;  /* don't retry, just time out */
04208                     else
04209                     {
04210                         elapsed = (PRIntervalTime) (PR_IntervalNow()
04211                                 - start);
04212                         if (elapsed > timeout)
04213                             ready = 0;  /* timed out */
04214                         else
04215                         {
04216                             remaining = timeout - elapsed;
04217                             msecs = PR_IntervalToMilliseconds(remaining);
04218                                                  tv.tv_sec = msecs/PR_MSEC_PER_SEC;
04219                                                  tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
04220                                                                                            PR_USEC_PER_MSEC;
04221                             goto retry;
04222                         }
04223                     }
04224                 } else if (EBADF == oserror)
04225                 {
04226                                    /* find all the bad fds */
04227                                    ready = 0;
04228                      for (index = 0; index < npds; ++index)
04229                                    {
04230                      pds[index].out_flags = 0;
04231                             if ((NULL != pds[index].fd) &&
04232                                                                              (0 != pds[index].in_flags))
04233                                           {
04234                                                  if (fcntl(selectfd[index], F_GETFL, 0) == -1)
04235                                                  {
04236                                    pds[index].out_flags = PR_POLL_NVAL;
04237                                                         ready++;
04238                                                  }
04239                                           }
04240                                    }
04241                 } else 
04242                     _PR_MD_MAP_SELECT_ERROR(oserror);
04243             }
04244             else if (ready > 0)
04245             {
04246                 for (index = 0; index < npds; ++index)
04247                 {
04248                     PRInt16 out_flags = 0;
04249                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
04250                     {
04251                                           if (FD_ISSET(selectfd[index], &rd))
04252                                           {
04253                                                  if (pds[index].out_flags
04254                                                  & _PR_POLL_READ_SYS_READ)
04255                                                  {
04256                                                         out_flags |= PR_POLL_READ;
04257                                                  }
04258                                                  if (pds[index].out_flags
04259                                                  & _PR_POLL_WRITE_SYS_READ)
04260                                                  {
04261                                                         out_flags |= PR_POLL_WRITE;
04262                                                  }
04263                                           }
04264                                           if (FD_ISSET(selectfd[index], &wr))
04265                                           {
04266                                                  if (pds[index].out_flags
04267                                                  & _PR_POLL_READ_SYS_WRITE)
04268                                                  {
04269                                                         out_flags |= PR_POLL_READ;
04270                                                  }
04271                                                  if (pds[index].out_flags
04272                                                  & _PR_POLL_WRITE_SYS_WRITE)
04273                                                  {
04274                                                         out_flags |= PR_POLL_WRITE;
04275                                                  }
04276                                           }
04277                                           if (FD_ISSET(selectfd[index], &ex))
04278                                                  out_flags |= PR_POLL_EXCEPT;
04279                     }
04280                     pds[index].out_flags = out_flags;
04281                 }
04282             }
04283         }
04284     }
04285     return ready;
04286 
04287 } /* _pr_poll_with_select */
04288 #endif /* _PR_POLL_WITH_SELECT */
04289 
04290 PR_IMPLEMENT(PRInt32) PR_Poll(
04291     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
04292 {
04293 #if defined(_PR_POLL_WITH_SELECT)
04294        return(_pr_poll_with_select(pds, npds, timeout));
04295 #else
04296        return(_pr_poll_with_poll(pds, npds, timeout));
04297 #endif
04298 }
04299 
04300 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
04301 {
04302     struct dirent *dp;
04303 
04304     if (pt_TestAbort()) return NULL;
04305 
04306     for (;;)
04307     {
04308         errno = 0;
04309         dp = readdir(dir->md.d);
04310         if (NULL == dp)
04311         {
04312             pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
04313             return NULL;
04314         }
04315         if ((flags & PR_SKIP_DOT)
04316             && ('.' == dp->d_name[0])
04317             && (0 == dp->d_name[1])) continue;
04318         if ((flags & PR_SKIP_DOT_DOT)
04319             && ('.' == dp->d_name[0])
04320             && ('.' == dp->d_name[1])
04321             && (0 == dp->d_name[2])) continue;
04322         if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
04323             continue;
04324         break;
04325     }
04326     dir->d.name = dp->d_name;
04327     return &dir->d;
04328 }  /* PR_ReadDir */
04329 
04330 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
04331 {
04332     PRIntn domain = PF_INET;
04333 
04334     return PR_Socket(domain, SOCK_DGRAM, 0);
04335 }  /* PR_NewUDPSocket */
04336 
04337 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
04338 {
04339     PRIntn domain = PF_INET;
04340 
04341     return PR_Socket(domain, SOCK_STREAM, 0);
04342 }  /* PR_NewTCPSocket */
04343 
04344 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
04345 {
04346     return PR_Socket(af, SOCK_DGRAM, 0);
04347 }  /* PR_NewUDPSocket */
04348 
04349 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
04350 {
04351     return PR_Socket(af, SOCK_STREAM, 0);
04352 }  /* PR_NewTCPSocket */
04353 
04354 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
04355 {
04356     PRInt32 osfd[2];
04357 
04358     if (pt_TestAbort()) return PR_FAILURE;
04359 
04360     if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
04361         pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
04362         return PR_FAILURE;
04363     }
04364 
04365     fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
04366     if (fds[0] == NULL) {
04367         close(osfd[0]);
04368         close(osfd[1]);
04369         return PR_FAILURE;
04370     }
04371     fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
04372     if (fds[1] == NULL) {
04373         PR_Close(fds[0]);
04374         close(osfd[1]);
04375         return PR_FAILURE;
04376     }
04377     return PR_SUCCESS;
04378 }  /* PR_NewTCPSocketPair */
04379 
04380 PR_IMPLEMENT(PRStatus) PR_CreatePipe(
04381     PRFileDesc **readPipe,
04382     PRFileDesc **writePipe
04383 )
04384 {
04385     int pipefd[2];
04386 
04387     if (pt_TestAbort()) return PR_FAILURE;
04388 
04389     if (pipe(pipefd) == -1)
04390     {
04391     /* XXX map pipe error */
04392         PR_SetError(PR_UNKNOWN_ERROR, errno);
04393         return PR_FAILURE;
04394     }
04395     *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
04396     if (NULL == *readPipe)
04397     {
04398         close(pipefd[0]);
04399         close(pipefd[1]);
04400         return PR_FAILURE;
04401     }
04402     *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
04403     if (NULL == *writePipe)
04404     {
04405         PR_Close(*readPipe);
04406         close(pipefd[1]);
04407         return PR_FAILURE;
04408     }
04409     return PR_SUCCESS;
04410 }
04411 
04412 /*
04413 ** Set the inheritance attribute of a file descriptor.
04414 */
04415 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
04416     PRFileDesc *fd,
04417     PRBool inheritable)
04418 {
04419     /*
04420      * Only a non-layered, NSPR file descriptor can be inherited
04421      * by a child process.
04422      */
04423     if (fd->identity != PR_NSPR_IO_LAYER)
04424     {
04425         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
04426         return PR_FAILURE;
04427     }
04428     if (fd->secret->inheritable != inheritable)
04429     {
04430         if (fcntl(fd->secret->md.osfd, F_SETFD,
04431         inheritable ? 0 : FD_CLOEXEC) == -1)
04432         {
04433             return PR_FAILURE;
04434         }
04435         fd->secret->inheritable = (_PRTriStateBool) inheritable;
04436     }
04437     return PR_SUCCESS;
04438 }
04439 
04440 /*****************************************************************************/
04441 /***************************** I/O friends methods ***************************/
04442 /*****************************************************************************/
04443 
04444 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
04445 {
04446     PRFileDesc *fd;
04447 
04448     if (!_pr_initialized) _PR_ImplicitInitialization();
04449     fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
04450     if (NULL == fd) close(osfd);
04451     return fd;
04452 }  /* PR_ImportFile */
04453 
04454 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
04455 {
04456     PRFileDesc *fd;
04457 
04458     if (!_pr_initialized) _PR_ImplicitInitialization();
04459     fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
04460     if (NULL == fd) close(osfd);
04461     return fd;
04462 }  /* PR_ImportPipe */
04463 
04464 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
04465 {
04466     PRFileDesc *fd;
04467 
04468     if (!_pr_initialized) _PR_ImplicitInitialization();
04469     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
04470     if (NULL == fd) close(osfd);
04471 #ifdef _PR_NEED_SECRET_AF
04472     if (NULL != fd) fd->secret->af = PF_INET;
04473 #endif
04474     return fd;
04475 }  /* PR_ImportTCPSocket */
04476 
04477 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
04478 {
04479     PRFileDesc *fd;
04480 
04481     if (!_pr_initialized) _PR_ImplicitInitialization();
04482     fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
04483     if (NULL != fd) close(osfd);
04484     return fd;
04485 }  /* PR_ImportUDPSocket */
04486 
04487 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
04488 {
04489     PRFileDesc *fd;
04490 
04491     if (!_pr_initialized) _PR_ImplicitInitialization();
04492 
04493     fd = _PR_Getfd();
04494 
04495     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
04496     else
04497     {
04498         fd->secret->md.osfd = osfd;
04499         fd->secret->inheritable = _PR_TRI_FALSE;
04500        fd->secret->state = _PR_FILEDESC_OPEN;
04501         fd->methods = PR_GetSocketPollFdMethods();
04502     }
04503 
04504     return fd;
04505 }  /* PR_CreateSocketPollFD */
04506 
04507 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
04508 {
04509     if (NULL == fd)
04510     {
04511         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
04512         return PR_FAILURE;
04513     }
04514     fd->secret->state = _PR_FILEDESC_CLOSED;
04515     _PR_Putfd(fd);
04516     return PR_SUCCESS;
04517 }  /* PR_DestroySocketPollFd */
04518 
04519 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
04520 {
04521     PRInt32 osfd = -1;
04522     bottom = (NULL == bottom) ?
04523         NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
04524     if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
04525     else osfd = bottom->secret->md.osfd;
04526     return osfd;
04527 }  /* PR_FileDesc2NativeHandle */
04528 
04529 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
04530     PRInt32 handle)
04531 {
04532     if (fd) fd->secret->md.osfd = handle;
04533 }  /*  PR_ChangeFileDescNativeHandle*/
04534 
04535 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
04536 {
04537     PRStatus status = PR_SUCCESS;
04538 
04539     if (pt_TestAbort()) return PR_FAILURE;
04540 
04541     PR_Lock(_pr_flock_lock);
04542     while (-1 == fd->secret->lockCount)
04543         PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
04544     if (0 == fd->secret->lockCount)
04545     {
04546         fd->secret->lockCount = -1;
04547         PR_Unlock(_pr_flock_lock);
04548         status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
04549         PR_Lock(_pr_flock_lock);
04550         fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
04551         PR_NotifyAllCondVar(_pr_flock_cv);
04552     }
04553     else
04554     {
04555         fd->secret->lockCount += 1;
04556     }
04557     PR_Unlock(_pr_flock_lock);
04558  
04559     return status;
04560 }  /* PR_LockFile */
04561 
04562 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
04563 {
04564     PRStatus status = PR_SUCCESS;
04565 
04566     if (pt_TestAbort()) return PR_FAILURE;
04567 
04568     PR_Lock(_pr_flock_lock);
04569     if (0 == fd->secret->lockCount)
04570     {
04571         status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
04572         if (PR_SUCCESS == status) fd->secret->lockCount = 1;
04573     }
04574     else fd->secret->lockCount += 1;
04575     PR_Unlock(_pr_flock_lock);
04576  
04577     return status;
04578 }  /* PR_TLockFile */
04579 
04580 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
04581 {
04582     PRStatus status = PR_SUCCESS;
04583 
04584     if (pt_TestAbort()) return PR_FAILURE;
04585 
04586     PR_Lock(_pr_flock_lock);
04587     if (fd->secret->lockCount == 1)
04588     {
04589         status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
04590         if (PR_SUCCESS == status) fd->secret->lockCount = 0;
04591     }
04592     else fd->secret->lockCount -= 1;
04593     PR_Unlock(_pr_flock_lock);
04594 
04595     return status;
04596 }
04597 
04598 /*
04599  * The next two entry points should not be in the API, but they are
04600  * defined here for historical (or hysterical) reasons.
04601  */
04602 
04603 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
04604 {
04605 #if defined(XP_UNIX) && !defined(AIX) && !defined(VMS)
04606     struct rlimit rlim;
04607 
04608     if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
04609        return -1;
04610 
04611     return rlim.rlim_max;
04612 #elif defined(AIX) || defined(VMS)
04613     return sysconf(_SC_OPEN_MAX);
04614 #endif
04615 }
04616 
04617 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
04618 {
04619 #if defined(XP_UNIX) && !defined(AIX) && !defined(VMS)
04620     struct rlimit rlim;
04621     PRInt32 tableMax = PR_GetSysfdTableMax();
04622 
04623     if (tableMax < 0) return -1;
04624     rlim.rlim_max = tableMax;
04625 
04626     /* Grow as much as we can; even if too big */
04627     if ( rlim.rlim_max < table_size )
04628         rlim.rlim_cur = rlim.rlim_max;
04629     else
04630         rlim.rlim_cur = table_size;
04631 
04632     if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
04633         return -1;
04634 
04635     return rlim.rlim_cur;
04636 #elif defined(AIX) || defined(VMS)
04637     return -1;
04638 #endif
04639 }
04640 
04641 /*
04642  * PR_Stat is supported for backward compatibility; some existing Java
04643  * code uses it.  New code should use PR_GetFileInfo.
04644  */
04645 
04646 #ifndef NO_NSPR_10_SUPPORT
04647 PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
04648 {
04649     static PRBool unwarned = PR_TRUE;
04650     if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
04651 
04652     if (pt_TestAbort()) return -1;
04653 
04654     if (-1 == stat(name, buf)) {
04655         pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
04656         return -1;
04657     } else {
04658         return 0;
04659     }
04660 }
04661 #endif /* ! NO_NSPR_10_SUPPORT */
04662 
04663 
04664 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
04665 {
04666     static PRBool unwarned = PR_TRUE;
04667     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
04668     memset(set, 0, sizeof(PR_fd_set));
04669 }
04670 
04671 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
04672 {
04673     static PRBool unwarned = PR_TRUE;
04674     if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
04675     PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
04676 
04677     set->harray[set->hsize++] = fh;
04678 }
04679 
04680 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
04681 {
04682     PRUint32 index, index2;
04683     static PRBool unwarned = PR_TRUE;
04684     if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
04685 
04686     for (index = 0; index<set->hsize; index++)
04687        if (set->harray[index] == fh) {
04688            for (index2=index; index2 < (set->hsize-1); index2++) {
04689                set->harray[index2] = set->harray[index2+1];
04690            }
04691            set->hsize--;
04692            break;
04693        }
04694 }
04695 
04696 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
04697 {
04698     PRUint32 index;
04699     static PRBool unwarned = PR_TRUE;
04700     if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
04701     for (index = 0; index<set->hsize; index++)
04702        if (set->harray[index] == fh) {
04703            return 1;
04704        }
04705     return 0;
04706 }
04707 
04708 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
04709 {
04710     static PRBool unwarned = PR_TRUE;
04711     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
04712     PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
04713 
04714     set->narray[set->nsize++] = fd;
04715 }
04716 
04717 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
04718 {
04719     PRUint32 index, index2;
04720     static PRBool unwarned = PR_TRUE;
04721     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
04722 
04723     for (index = 0; index<set->nsize; index++)
04724        if (set->narray[index] == fd) {
04725            for (index2=index; index2 < (set->nsize-1); index2++) {
04726                set->narray[index2] = set->narray[index2+1];
04727            }
04728            set->nsize--;
04729            break;
04730        }
04731 }
04732 
04733 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
04734 {
04735     PRUint32 index;
04736     static PRBool unwarned = PR_TRUE;
04737     if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
04738     for (index = 0; index<set->nsize; index++)
04739        if (set->narray[index] == fd) {
04740            return 1;
04741        }
04742     return 0;
04743 }
04744 
04745 #include <sys/types.h>
04746 #include <sys/time.h>
04747 #if !defined(SUNOS4) && !defined(HPUX) && !defined(LINUX)
04748 #include <sys/select.h>
04749 #endif
04750 
04751 static PRInt32
04752 _PR_getset(PR_fd_set *pr_set, fd_set *set)
04753 {
04754     PRUint32 index;
04755     PRInt32 max = 0;
04756 
04757     if (!pr_set)
04758         return 0;
04759    
04760     FD_ZERO(set);
04761 
04762     /* First set the pr file handle osfds */
04763     for (index=0; index<pr_set->hsize; index++) {
04764         FD_SET(pr_set->harray[index]->secret->md.osfd, set);
04765         if (pr_set->harray[index]->secret->md.osfd > max)
04766             max = pr_set->harray[index]->secret->md.osfd;
04767     }
04768     /* Second set the native osfds */
04769     for (index=0; index<pr_set->nsize; index++) {
04770         FD_SET(pr_set->narray[index], set);
04771         if (pr_set->narray[index] > max)
04772             max = pr_set->narray[index];
04773     }
04774     return max;
04775 }
04776 
04777 static void
04778 _PR_setset(PR_fd_set *pr_set, fd_set *set)
04779 {
04780     PRUint32 index, last_used;
04781 
04782     if (!pr_set)
04783         return;
04784 
04785     for (last_used=0, index=0; index<pr_set->hsize; index++) {
04786         if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
04787             pr_set->harray[last_used++] = pr_set->harray[index];
04788         }
04789     }
04790     pr_set->hsize = last_used;
04791 
04792     for (last_used=0, index=0; index<pr_set->nsize; index++) {
04793         if ( FD_ISSET(pr_set->narray[index], set) ) {
04794             pr_set->narray[last_used++] = pr_set->narray[index];
04795         }
04796     }
04797     pr_set->nsize = last_used;
04798 }
04799 
04800 PR_IMPLEMENT(PRInt32) PR_Select(
04801     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
04802     PR_fd_set *pr_ex, PRIntervalTime timeout)
04803 {
04804     fd_set rd, wr, ex;
04805     struct timeval tv, *tvp;
04806     PRInt32 max, max_fd;
04807     PRInt32 rv;
04808     /*
04809      * For restarting select() if it is interrupted by a Unix signal.
04810      * We use these variables to figure out how much time has elapsed
04811      * and how much of the timeout still remains.
04812      */
04813     PRIntervalTime start, elapsed, remaining;
04814 
04815     static PRBool unwarned = PR_TRUE;
04816     if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
04817 
04818     FD_ZERO(&rd);
04819     FD_ZERO(&wr);
04820     FD_ZERO(&ex);
04821 
04822     max_fd = _PR_getset(pr_rd, &rd);
04823     max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
04824     max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
04825 
04826     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
04827         tvp = NULL;
04828     } else {
04829         tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
04830         tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
04831                 timeout - PR_SecondsToInterval(tv.tv_sec));
04832         tvp = &tv;
04833         start = PR_IntervalNow();
04834     }
04835 
04836 retry:
04837     rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
04838         (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
04839 
04840     if (rv == -1 && errno == EINTR) {
04841         if (timeout == PR_INTERVAL_NO_TIMEOUT) {
04842             goto retry;
04843         } else {
04844             elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
04845             if (elapsed > timeout) {
04846                 rv = 0;  /* timed out */
04847             } else {
04848                 remaining = timeout - elapsed;
04849                 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
04850                 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
04851                         remaining - PR_SecondsToInterval(tv.tv_sec));
04852                 goto retry;
04853             }
04854         }
04855     }
04856 
04857     if (rv > 0) {
04858         _PR_setset(pr_rd, &rd);
04859         _PR_setset(pr_wr, &wr);
04860         _PR_setset(pr_ex, &ex);
04861     } else if (rv == -1) {
04862         pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
04863     }
04864     return rv;
04865 }
04866 #endif /* defined(_PR_PTHREADS) */
04867 
04868 #ifdef MOZ_UNICODE 
04869 /* ================ UTF16 Interfaces ================================ */
04870 PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
04871     const PRUnichar *name, PRIntn flags, PRIntn mode)
04872 {
04873     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
04874     return NULL;
04875 }
04876 
04877 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
04878 {
04879     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
04880     return PR_FAILURE;
04881 }
04882 
04883 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
04884 {
04885     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
04886     return NULL;
04887 }
04888 
04889 PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
04890 {
04891     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
04892     return NULL;
04893 }
04894 
04895 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
04896 {
04897     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
04898     return PR_FAILURE;
04899 }
04900 /* ================ UTF16 Interfaces ================================ */
04901 #endif /* MOZ_UNICODE */
04902 
04903 /* ptio.c */