LCOV - app.info - nsprpub/pr/src/pthreads/ptio.c

LCOV - code coverage report
| Current view: | directory - nsprpub/pr/src/pthreads - ptio.c (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1496 | 464 | 31.0 %
| Date: | 2012-07-07 | Functions: | 112 | 50 | 44.6 %

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

Generated by: LCOV version 1.7