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-06-02 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            9655 : PRBool IsValidNetAddr(const PRNetAddr *addr)
     248                 : {
     249            9655 :     if ((addr != NULL)
     250            9655 :             && (addr->raw.family != AF_UNIX)
     251            9655 :             && (addr->raw.family != PR_AF_INET6)
     252            9655 :             && (addr->raw.family != AF_INET)) {
     253               0 :         return PR_FALSE;
     254                 :     }
     255            9655 :     return PR_TRUE;
     256                 : }
     257                 : 
     258            6228 : 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            6228 :     if ((addr != NULL)
     265            6228 :             && (addr->raw.family != AF_UNIX)
     266            6228 :             && (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            6228 :     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         1766041 : static PRBool pt_TestAbort(void)
    1247                 : {
    1248         1766041 :     PRThread *me = PR_GetCurrentThread();
    1249         1766043 :     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         1766043 :     return PR_FALSE;
    1256                 : }  /* pt_TestAbort */
    1257                 : 
    1258           11765 : static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
    1259                 : {
    1260           11765 :     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           11765 :             mapper(syserrno);
    1268                 :     }
    1269           11765 : }  /* pt_MapError */
    1270                 : 
    1271          369671 : static PRStatus pt_Close(PRFileDesc *fd)
    1272                 : {
    1273          369671 :     if ((NULL == fd) || (NULL == fd->secret)
    1274          369671 :         || ((_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          369671 :     if (pt_TestAbort()) return PR_FAILURE;
    1281                 : 
    1282          369671 :     if (_PR_FILEDESC_OPEN == fd->secret->state)
    1283                 :     {
    1284          369671 :         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          369671 :         fd->secret->state = _PR_FILEDESC_CLOSED;
    1308                 :     }
    1309          369671 :     _PR_Putfd(fd);
    1310          369671 :     return PR_SUCCESS;
    1311                 : }  /* pt_Close */
    1312                 : 
    1313          403664 : static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
    1314                 : {
    1315          403664 :     PRInt32 syserrno, bytes = -1;
    1316                 : 
    1317          403664 :     if (pt_TestAbort()) return bytes;
    1318                 : 
    1319          403664 :     bytes = read(fd->secret->md.osfd, buf, amount);
    1320          403664 :     syserrno = errno;
    1321                 : 
    1322          403664 :     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          403664 :     if (bytes < 0)
    1336               0 :         pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
    1337          403664 :     return bytes;
    1338                 : }  /* pt_Read */
    1339                 : 
    1340          521452 : static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
    1341                 : {
    1342          521452 :     PRInt32 syserrno, bytes = -1;
    1343          521452 :     PRBool fNeedContinue = PR_FALSE;
    1344                 : 
    1345          521452 :     if (pt_TestAbort()) return bytes;
    1346                 : 
    1347          521452 :     bytes = write(fd->secret->md.osfd, buf, amount);
    1348          521452 :     syserrno = errno;
    1349                 : 
    1350          521452 :     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          521452 :     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          521452 :     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          521452 :     if (bytes == -1)
    1377               0 :         pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
    1378          521452 :     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               2 : static PRInt32 pt_Available_s(PRFileDesc *fd)
    1522                 : {
    1523               2 :     PRInt32 rv, bytes = -1;
    1524               2 :     if (pt_TestAbort()) return bytes;
    1525                 : 
    1526               2 :     rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
    1527                 : 
    1528               2 :     if (rv == -1)
    1529               0 :         pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
    1530               2 :     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            1839 : static PRStatus pt_Fsync(PRFileDesc *fd)
    1558                 : {
    1559            1839 :     PRIntn rv = -1;
    1560            1839 :     if (pt_TestAbort()) return PR_FAILURE;
    1561                 : 
    1562            1839 :     rv = fsync(fd->secret->md.osfd);
    1563            1839 :     if (rv < 0) {
    1564               0 :         pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
    1565               0 :         return PR_FAILURE;
    1566                 :     }
    1567            1839 :     return PR_SUCCESS;
    1568                 : }  /* pt_Fsync */
    1569                 : 
    1570            3006 : static PRStatus pt_Connect(
    1571                 :     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
    1572                 : {
    1573            3006 :     PRIntn rv = -1, syserrno;
    1574                 :     pt_SockLen addr_len;
    1575            3006 :         const PRNetAddr *addrp = addr;
    1576                 : #if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
    1577            3006 :         PRUint16 md_af = addr->raw.family;
    1578                 :     PRNetAddr addrCopy;
    1579                 : #endif
    1580                 : 
    1581            3006 :     if (pt_TestAbort()) return PR_FAILURE;
    1582                 : 
    1583            3006 :     PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    1584            3006 :     addr_len = PR_NETADDR_SIZE(addr);
    1585                 : #if defined(_PR_INET6)
    1586            3006 :         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            3006 :     rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
    1603            3006 :     syserrno = errno;
    1604            3006 :     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            3006 :     if (-1 == rv) {
    1621            3006 :         pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
    1622            3006 :         return PR_FAILURE;
    1623                 :     }
    1624               0 :     return PR_SUCCESS;
    1625                 : }  /* pt_Connect */
    1626                 : 
    1627            3006 : static PRStatus pt_ConnectContinue(
    1628                 :     PRFileDesc *fd, PRInt16 out_flags)
    1629                 : {
    1630                 :     int err;
    1631                 :     PRInt32 osfd;
    1632                 : 
    1633            3006 :     if (out_flags & PR_POLL_NVAL)
    1634                 :     {
    1635               0 :         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
    1636               0 :         return PR_FAILURE;
    1637                 :     }
    1638            3006 :     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            3006 :     osfd = fd->secret->md.osfd;
    1647                 : 
    1648            3006 :     err = _MD_unix_get_nonblocking_connect_error(osfd);
    1649            3006 :     if (err != 0)
    1650                 :     {
    1651             136 :         _PR_MD_MAP_CONNECT_ERROR(err);
    1652             136 :         return PR_FAILURE;
    1653                 :     }
    1654            2870 :     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            2870 : static PRFileDesc* pt_Accept(
    1671                 :     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
    1672                 : {
    1673            2870 :     PRFileDesc *newfd = NULL;
    1674            2870 :     PRIntn syserrno, osfd = -1;
    1675            2870 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    1676                 : #ifdef SYMBIAN
    1677                 :     PRNetAddr dummy_addr;
    1678                 : #endif
    1679                 : 
    1680            2870 :     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            2870 :     osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
    1701            2870 :     syserrno = errno;
    1702                 : 
    1703            2870 :     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            2870 :         if (addr && (AF_INET6 == addr->raw.family))
    1737               0 :         addr->raw.family = PR_AF_INET6;
    1738                 : #endif
    1739            2870 :     newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
    1740            2870 :     if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
    1741                 :     else
    1742                 :     {
    1743            2870 :         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    1744            2870 :         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            2870 :         newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
    1752                 : #endif
    1753                 :     }
    1754            2870 :     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          220365 : static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
    1840                 : {
    1841          220365 :     *out_flags = 0;
    1842          220365 :     return in_flags;
    1843                 : }  /* pt_Poll */
    1844                 : 
    1845           18618 : static PRInt32 pt_Recv(
    1846                 :     PRFileDesc *fd, void *buf, PRInt32 amount,
    1847                 :     PRIntn flags, PRIntervalTime timeout)
    1848                 : {
    1849           18618 :     PRInt32 syserrno, bytes = -1;
    1850                 :     PRIntn osflags;
    1851                 : 
    1852           18618 :     if (0 == flags)
    1853           18616 :         osflags = 0;
    1854               2 :     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               2 :         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           18618 :     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           18618 :     bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
    1880                 : #endif
    1881           18618 :     syserrno = errno;
    1882                 : 
    1883           18618 :     if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1884            6365 :         && (!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           18618 :     if (bytes < 0)
    1902            6365 :         pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
    1903           18618 :     return bytes;
    1904                 : }  /* pt_Recv */
    1905                 : 
    1906           18544 : static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
    1907                 : {
    1908           18544 :     return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
    1909                 : }  /* pt_SocketRead */
    1910                 : 
    1911            9375 : static PRInt32 pt_Send(
    1912                 :     PRFileDesc *fd, const void *buf, PRInt32 amount,
    1913                 :     PRIntn flags, PRIntervalTime timeout)
    1914                 : {
    1915            9375 :     PRInt32 syserrno, bytes = -1;
    1916            9375 :     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            9375 :     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            9375 :     bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
    1947                 : #endif
    1948            9375 :     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            9375 :     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            9375 :     if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
    1980              16 :         && (!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            9375 :     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            9375 :     if (bytes == -1)
    2005              19 :         pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
    2006            9375 :     return bytes;
    2007                 : }  /* pt_Send */
    2008                 : 
    2009            9359 : static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
    2010                 : {
    2011            9359 :     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            3350 : static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
    2791                 : {
    2792            3350 :     PRIntn rv = -1;
    2793            3350 :     pt_SockLen addr_len = sizeof(PRNetAddr);
    2794                 : 
    2795            3350 :     if (pt_TestAbort()) return PR_FAILURE;
    2796                 : 
    2797           10050 :     rv = getsockname(
    2798            6700 :         fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
    2799            3350 :     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            3350 :                 if (AF_INET6 == addr->raw.family)
    2812               0 :                         addr->raw.family = PR_AF_INET6;
    2813                 : #endif
    2814            3350 :         PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
    2815            3350 :         PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
    2816            3350 :         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            9728 : 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            9728 :     if (PR_SockOpt_Nonblocking == data->option)
    2985                 :     {
    2986            6297 :         fd->secret->nonblocking = data->value.non_blocking;
    2987            6297 :         return PR_SUCCESS;
    2988                 :     }
    2989                 : 
    2990            3431 :     rv = _PR_MapOptionName(data->option, &level, &name);
    2991            3431 :     if (PR_SUCCESS == rv)
    2992                 :     {
    2993            3431 :         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            3431 :                 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
    3010            6862 :                 rv = setsockopt(
    3011            3431 :                     fd->secret->md.osfd, level, name,
    3012                 :                     (char*)&value, sizeof(PRIntn));
    3013                 : #ifdef LINUX
    3014                 :                 /* for pt_LinuxSendFile */
    3015            3431 :                 if (name == TCP_NODELAY && rv == 0) {
    3016            3010 :                     fd->secret->md.tcp_nodelay = value;
    3017                 :                 }
    3018                 : #endif
    3019            3431 :                 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            3431 :         if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
    3081                 :     }
    3082            3431 :     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            9207 : static void pt_MakeFdNonblock(PRIntn osfd)
    3299                 : {
    3300                 :     PRIntn flags;
    3301            9207 :     flags = fcntl(osfd, F_GETFL, 0);
    3302            9207 :     flags |= _PR_FCNTL_FLAGS;
    3303            9207 :     (void)fcntl(osfd, F_SETFL, flags);
    3304            9207 : }
    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          429894 : static PRFileDesc *pt_SetMethods(
    3331                 :     PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
    3332                 : {
    3333          429894 :     PRFileDesc *fd = _PR_Getfd();
    3334                 :     
    3335          429894 :     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
    3336                 :     else
    3337                 :     {
    3338          429894 :         fd->secret->md.osfd = osfd;
    3339          429894 :         fd->secret->state = _PR_FILEDESC_OPEN;
    3340          429894 :         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          369779 :             flags = fcntl(osfd, F_GETFD, 0);
    3347          369779 :             PR_ASSERT(0 == flags);
    3348                 : #endif
    3349          369779 :             fd->secret->inheritable = _PR_TRI_TRUE;
    3350                 :         }
    3351          429894 :         switch (type)
    3352                 :         {
    3353                 :             case PR_DESC_FILE:
    3354          420687 :                 fd->methods = PR_GetFileMethods();
    3355          420687 :                 break;
    3356                 :             case PR_DESC_SOCKET_TCP:
    3357            6297 :                 fd->methods = PR_GetTCPMethods();
    3358                 : #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
    3359                 :                 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
    3360                 : #else
    3361            6297 :                 pt_MakeSocketNonblock(osfd);
    3362                 : #endif
    3363            6297 :                 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          429894 :     return fd;
    3377                 : }  /* pt_SetMethods */
    3378                 : 
    3379          420687 : PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
    3380                 : {
    3381          420687 :     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            6297 : PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
    3390                 : {
    3391            6297 :     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            3427 : PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
    3466                 : {
    3467                 :     PRIntn osfd;
    3468                 :     PRDescType ftype;
    3469            3427 :     PRFileDesc *fd = NULL;
    3470                 : #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
    3471            3427 :     PRInt32 tmp_domain = domain;
    3472                 : #endif
    3473                 : 
    3474            3427 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3475                 : 
    3476            3427 :     if (pt_TestAbort()) return NULL;
    3477                 : 
    3478            3427 :     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            3427 :         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            3427 :     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            3427 :         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            3427 :     osfd = socket(domain, type, proto);
    3524            3427 :     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            3427 :         fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
    3536            3427 :         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            3427 :         if (fd != NULL) {
    3543                 :                 /*
    3544                 :                  * For platforms with no support for IPv6 
    3545                 :                  * create layered socket for IPv4-mapped IPv6 addresses
    3546                 :                  */
    3547            3427 :                 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            3427 :     return fd;
    3556                 : }  /* PR_Socket */
    3557                 : 
    3558                 : /*****************************************************************************/
    3559                 : /****************************** I/O public methods ***************************/
    3560                 : /*****************************************************************************/
    3561                 : 
    3562          362938 : PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
    3563                 :     const char *name, PRIntn flags, PRIntn mode)
    3564                 : {
    3565          362938 :     PRFileDesc *fd = NULL;
    3566          362938 :     PRIntn syserrno, osfd = -1, osflags = 0;;
    3567                 : 
    3568          362938 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3569                 : 
    3570          362938 :     if (pt_TestAbort()) return NULL;
    3571                 : 
    3572          362938 :     if (flags & PR_RDONLY) osflags |= O_RDONLY;
    3573          362938 :     if (flags & PR_WRONLY) osflags |= O_WRONLY;
    3574          362938 :     if (flags & PR_RDWR) osflags |= O_RDWR;
    3575          362938 :     if (flags & PR_APPEND) osflags |= O_APPEND;
    3576          362938 :     if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
    3577          362938 :     if (flags & PR_EXCL) osflags |= O_EXCL;
    3578          362938 :     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          362938 :     if (flags & PR_CREATE_FILE)
    3595                 :     {
    3596            9845 :         osflags |= O_CREAT;
    3597            9845 :         if (NULL !=_pr_rename_lock)
    3598            9845 :             PR_Lock(_pr_rename_lock);
    3599                 :     }
    3600                 : 
    3601          362938 :     osfd = _md_iovector._open64(name, osflags, mode);
    3602          362938 :     syserrno = errno;
    3603                 : 
    3604          362938 :     if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
    3605            9845 :         PR_Unlock(_pr_rename_lock);
    3606                 : 
    3607          362938 :     if (osfd == -1)
    3608            2366 :         pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
    3609                 :     else
    3610                 :     {
    3611          360572 :         fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
    3612          360572 :         if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
    3613                 :     }
    3614          362938 :     return fd;
    3615                 : }  /* PR_OpenFile */
    3616                 : 
    3617          362938 : PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
    3618                 : {
    3619          362938 :     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           10585 : PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
    3670                 : {
    3671                 :     PRInt32 rv;
    3672                 : 
    3673           10585 :     if (!_pr_initialized) _PR_ImplicitInitialization();
    3674           10585 :     rv = _PR_MD_GETFILEINFO64(fn, info);
    3675           10585 :     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           63519 : static PRInt32 _pr_poll_with_poll(
    3790                 :     PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
    3791                 : {
    3792           63519 :     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           63519 :     if (pt_TestAbort()) return -1;
    3801                 : 
    3802           63519 :     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           63519 :         if (npds <= STACK_POLL_DESC_COUNT)
    3811                 :         {
    3812           63519 :             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          269018 :         for (index = 0; index < npds; ++index)
    3834                 :         {
    3835          205499 :             PRInt16 in_flags_read = 0, in_flags_write = 0;
    3836          205499 :             PRInt16 out_flags_read = 0, out_flags_write = 0;
    3837                 : 
    3838          205499 :             if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    3839                 :             {
    3840          205499 :                 if (pds[index].in_flags & PR_POLL_READ)
    3841                 :                 {
    3842          607047 :                     in_flags_read = (pds[index].fd->methods->poll)(
    3843          202349 :                         pds[index].fd,
    3844          202349 :                         pds[index].in_flags & ~PR_POLL_WRITE,
    3845                 :                         &out_flags_read);
    3846                 :                 }
    3847          205499 :                 if (pds[index].in_flags & PR_POLL_WRITE)
    3848                 :                 {
    3849           54048 :                     in_flags_write = (pds[index].fd->methods->poll)(
    3850           18016 :                         pds[index].fd,
    3851           18016 :                         pds[index].in_flags & ~PR_POLL_READ,
    3852                 :                         &out_flags_write);
    3853                 :                 }
    3854          410998 :                 if ((0 != (in_flags_read & out_flags_read))
    3855          205499 :                 || (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          205499 :                     PRFileDesc *bottom = PR_GetIdentitiesLayer(
    3879          205499 :                         pds[index].fd, PR_NSPR_IO_LAYER);
    3880          205499 :                     PR_ASSERT(NULL != bottom);  /* what to do about that? */
    3881          205499 :                     pds[index].out_flags = 0;  /* pre-condition */
    3882          205499 :                     if ((NULL != bottom)
    3883          205499 :                     && (_PR_FILEDESC_OPEN == bottom->secret->state))
    3884                 :                     {
    3885          410998 :                         if (0 == ready)
    3886                 :                         {
    3887          205499 :                             syspoll[index].fd = bottom->secret->md.osfd;
    3888          205499 :                             syspoll[index].events = 0;
    3889          205499 :                             if (in_flags_read & PR_POLL_READ)
    3890                 :                             {
    3891          202345 :                                 pds[index].out_flags |=
    3892                 :                                     _PR_POLL_READ_SYS_READ;
    3893          202345 :                                 syspoll[index].events |= POLLIN;
    3894                 :                             }
    3895          205499 :                             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          205499 :                             if (in_flags_write & PR_POLL_READ)
    3902                 :                             {
    3903              12 :                                 pds[index].out_flags |=
    3904                 :                                     _PR_POLL_WRITE_SYS_READ;
    3905              12 :                                 syspoll[index].events |= POLLIN;
    3906                 :                             }
    3907          205499 :                             if (in_flags_write & PR_POLL_WRITE)
    3908                 :                             {
    3909           18004 :                                 pds[index].out_flags |=
    3910                 :                                     _PR_POLL_WRITE_SYS_WRITE;
    3911           18004 :                                 syspoll[index].events |= POLLOUT;
    3912                 :                             }
    3913          205499 :                             if (pds[index].in_flags & PR_POLL_EXCEPT)
    3914          141827 :                                 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           63519 :         if (0 == ready)
    3941                 :         {
    3942           63519 :             switch (timeout)
    3943                 :             {
    3944           15049 :             case PR_INTERVAL_NO_WAIT: msecs = 0; break;
    3945            5375 :             case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
    3946                 :             default:
    3947           43095 :                 msecs = PR_IntervalToMilliseconds(timeout);
    3948           43095 :                 start = PR_IntervalNow();
    3949                 :             }
    3950                 : 
    3951                 : retry:
    3952           64494 :             ready = poll(syspoll, npds, msecs);
    3953           64481 :             if (-1 == ready)
    3954                 :             {
    3955             975 :                 PRIntn oserror = errno;
    3956                 : 
    3957             975 :                 if (EINTR == oserror)
    3958                 :                 {
    3959             975 :                     if (timeout == PR_INTERVAL_NO_TIMEOUT)
    3960             939 :                         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           63506 :             else if (ready > 0)
    3983                 :             {
    3984          257583 :                 for (index = 0; index < npds; ++index)
    3985                 :                 {
    3986          197495 :                     PRInt16 out_flags = 0;
    3987          197495 :                     if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
    3988                 :                     {
    3989          197495 :                         if (0 != syspoll[index].revents)
    3990                 :                         {
    3991           79656 :                             if (syspoll[index].revents & POLLIN)
    3992                 :                             {
    3993           61755 :                                 if (pds[index].out_flags
    3994                 :                                 & _PR_POLL_READ_SYS_READ)
    3995                 :                                 {
    3996           61747 :                                     out_flags |= PR_POLL_READ;
    3997                 :                                 }
    3998          123510 :                                 if (pds[index].out_flags
    3999           61755 :                                 & _PR_POLL_WRITE_SYS_READ)
    4000                 :                                 {
    4001               8 :                                     out_flags |= PR_POLL_WRITE;
    4002                 :                                 }
    4003                 :                             }
    4004           79656 :                             if (syspoll[index].revents & POLLOUT)
    4005                 :                             {
    4006           35676 :                                 if (pds[index].out_flags
    4007           17838 :                                 & _PR_POLL_READ_SYS_WRITE)
    4008                 :                                 {
    4009               4 :                                     out_flags |= PR_POLL_READ;
    4010                 :                                 }
    4011           35676 :                                 if (pds[index].out_flags
    4012           17838 :                                 & _PR_POLL_WRITE_SYS_WRITE)
    4013                 :                                 {
    4014           17838 :                                     out_flags |= PR_POLL_WRITE;
    4015                 :                                 }
    4016                 :                             }
    4017           79656 :                             if (syspoll[index].revents & POLLPRI)
    4018               0 :                                 out_flags |= PR_POLL_EXCEPT;
    4019           79656 :                             if (syspoll[index].revents & POLLERR)
    4020             140 :                                 out_flags |= PR_POLL_ERR;
    4021           79656 :                             if (syspoll[index].revents & POLLNVAL)
    4022               0 :                                 out_flags |= PR_POLL_NVAL;
    4023           79656 :                             if (syspoll[index].revents & POLLHUP)
    4024             164 :                                 out_flags |= PR_POLL_HUP;
    4025                 :                         }
    4026                 :                     }
    4027          197495 :                     pds[index].out_flags = out_flags;
    4028                 :                 }
    4029                 :             }
    4030                 :         }
    4031                 :     }
    4032           63506 :     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           63519 : 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           63519 :         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            3427 : PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
    4408                 : {
    4409            3427 :     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