nsprpub/pr/src/pthreads/ptio.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/pthreads/ptio.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,5012 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +** File:   ptio.c
    1.11 +** Descritpion:  Implemenation of I/O methods for pthreads
    1.12 +*/
    1.13 +
    1.14 +#if defined(_PR_PTHREADS)
    1.15 +
    1.16 +#if defined(_PR_POLL_WITH_SELECT)
    1.17 +#if !(defined(HPUX) && defined(_USE_BIG_FDS))
    1.18 +/* set fd limit for select(), before including system header files */
    1.19 +#define FD_SETSIZE (16 * 1024)
    1.20 +#endif
    1.21 +#endif
    1.22 +
    1.23 +#include <pthread.h>
    1.24 +#include <string.h>  /* for memset() */
    1.25 +#include <sys/types.h>
    1.26 +#include <dirent.h>
    1.27 +#include <fcntl.h>
    1.28 +#include <unistd.h>
    1.29 +#include <sys/socket.h>
    1.30 +#include <sys/stat.h>
    1.31 +#include <sys/uio.h>
    1.32 +#include <sys/file.h>
    1.33 +#include <sys/ioctl.h>
    1.34 +#if defined(DARWIN)
    1.35 +#include <sys/utsname.h> /* for uname */
    1.36 +#endif
    1.37 +#if defined(SOLARIS) || defined(UNIXWARE)
    1.38 +#include <sys/filio.h>  /* to pick up FIONREAD */
    1.39 +#endif
    1.40 +#ifdef _PR_POLL_AVAILABLE
    1.41 +#include <poll.h>
    1.42 +#endif
    1.43 +#ifdef AIX
    1.44 +/* To pick up sysconf() */
    1.45 +#include <unistd.h>
    1.46 +#include <dlfcn.h>  /* for dlopen */
    1.47 +#else
    1.48 +/* To pick up getrlimit() etc. */
    1.49 +#include <sys/time.h>
    1.50 +#include <sys/resource.h>
    1.51 +#endif
    1.52 +
    1.53 +#ifdef SOLARIS
    1.54 +/*
    1.55 + * Define HAVE_SENDFILEV if the system has the sendfilev() system call.
    1.56 + * Code built this way won't run on a system without sendfilev().
    1.57 + * We can define HAVE_SENDFILEV by default when the minimum release
    1.58 + * of Solaris that NSPR supports has sendfilev().
    1.59 + */
    1.60 +#ifdef HAVE_SENDFILEV
    1.61 +
    1.62 +#include <sys/sendfile.h>
    1.63 +
    1.64 +#define SOLARIS_SENDFILEV(a, b, c, d) sendfilev((a), (b), (c), (d))
    1.65 +
    1.66 +#else
    1.67 +
    1.68 +#include <dlfcn.h>  /* for dlopen */
    1.69 +
    1.70 +/*
    1.71 + * Match the definitions in <sys/sendfile.h>.
    1.72 + */
    1.73 +typedef struct sendfilevec {
    1.74 +    int sfv_fd;       /* input fd */
    1.75 +    uint_t sfv_flag;  /* flags */
    1.76 +    off_t sfv_off;    /* offset to start reading from */
    1.77 +    size_t sfv_len;   /* amount of data */
    1.78 +} sendfilevec_t;
    1.79 +
    1.80 +#define SFV_FD_SELF (-2)
    1.81 +
    1.82 +/*
    1.83 + * extern ssize_t sendfilev(int, const struct sendfilevec *, int, size_t *);
    1.84 + */
    1.85 +static ssize_t (*pt_solaris_sendfilev_fptr)() = NULL;
    1.86 +
    1.87 +#define SOLARIS_SENDFILEV(a, b, c, d) \
    1.88 +        (*pt_solaris_sendfilev_fptr)((a), (b), (c), (d))
    1.89 +
    1.90 +#endif /* HAVE_SENDFILEV */
    1.91 +#endif /* SOLARIS */
    1.92 +
    1.93 +/*
    1.94 + * The send_file() system call is available in AIX 4.3.2 or later.
    1.95 + * If this file is compiled on an older AIX system, it attempts to
    1.96 + * look up the send_file symbol at run time to determine whether
    1.97 + * we can use the faster PR_SendFile/PR_TransmitFile implementation based on
    1.98 + * send_file().  On AIX 4.3.2 or later, we can safely skip this
    1.99 + * runtime function dispatching and just use the send_file based
   1.100 + * implementation.
   1.101 + */
   1.102 +#ifdef AIX
   1.103 +#ifdef SF_CLOSE
   1.104 +#define HAVE_SEND_FILE
   1.105 +#endif
   1.106 +
   1.107 +#ifdef HAVE_SEND_FILE
   1.108 +
   1.109 +#define AIX_SEND_FILE(a, b, c) send_file(a, b, c)
   1.110 +
   1.111 +#else /* HAVE_SEND_FILE */
   1.112 +
   1.113 +/*
   1.114 + * The following definitions match those in <sys/socket.h>
   1.115 + * on AIX 4.3.2.
   1.116 + */
   1.117 +
   1.118 +/*
   1.119 + * Structure for the send_file() system call
   1.120 + */
   1.121 +struct sf_parms {
   1.122 +    /* --------- header parms ---------- */
   1.123 +    void      *header_data;         /* Input/Output. Points to header buf */
   1.124 +    uint_t    header_length;        /* Input/Output. Length of the header */
   1.125 +    /* --------- file parms ------------ */
   1.126 +    int       file_descriptor;      /* Input. File descriptor of the file */
   1.127 +    unsigned long long file_size;   /* Output. Size of the file */
   1.128 +    unsigned long long file_offset; /* Input/Output. Starting offset */
   1.129 +    long long file_bytes;           /* Input/Output. no. of bytes to send */
   1.130 +    /* --------- trailer parms --------- */
   1.131 +    void      *trailer_data;        /* Input/Output. Points to trailer buf */
   1.132 +    uint_t    trailer_length;       /* Input/Output. Length of the trailer */
   1.133 +    /* --------- return info ----------- */
   1.134 +    unsigned long long bytes_sent;  /* Output. no. of bytes sent */
   1.135 +};
   1.136 +
   1.137 +/*
   1.138 + * Flags for the send_file() system call
   1.139 + */
   1.140 +#define SF_CLOSE        0x00000001      /* close the socket after completion */
   1.141 +#define SF_REUSE        0x00000002      /* reuse socket. not supported */
   1.142 +#define SF_DONT_CACHE   0x00000004      /* don't apply network buffer cache */
   1.143 +#define SF_SYNC_CACHE   0x00000008      /* sync/update network buffer cache */
   1.144 +
   1.145 +/*
   1.146 + * prototype: size_t send_file(int *, struct sf_parms *, uint_t);
   1.147 + */
   1.148 +static ssize_t (*pt_aix_sendfile_fptr)() = NULL;
   1.149 +
   1.150 +#define AIX_SEND_FILE(a, b, c) (*pt_aix_sendfile_fptr)(a, b, c)
   1.151 +
   1.152 +#endif /* HAVE_SEND_FILE */
   1.153 +#endif /* AIX */
   1.154 +
   1.155 +#ifdef LINUX
   1.156 +#include <sys/sendfile.h>
   1.157 +#endif
   1.158 +
   1.159 +#include "primpl.h"
   1.160 +
   1.161 +#ifdef HAVE_NETINET_TCP_H
   1.162 +#include <netinet/tcp.h>  /* TCP_NODELAY, TCP_MAXSEG */
   1.163 +#endif
   1.164 +
   1.165 +#ifdef LINUX
   1.166 +/* TCP_CORK is not defined in <netinet/tcp.h> on Red Hat Linux 6.0 */
   1.167 +#ifndef TCP_CORK
   1.168 +#define TCP_CORK 3
   1.169 +#endif
   1.170 +#endif
   1.171 +
   1.172 +#ifdef _PR_IPV6_V6ONLY_PROBE
   1.173 +static PRBool _pr_ipv6_v6only_on_by_default;
   1.174 +#endif
   1.175 +
   1.176 +#if (defined(HPUX) && !defined(HPUX10_30) && !defined(HPUX11))
   1.177 +#define _PRSelectFdSetArg_t int *
   1.178 +#elif defined(AIX4_1)
   1.179 +#define _PRSelectFdSetArg_t void *
   1.180 +#elif defined(IRIX) || (defined(AIX) && !defined(AIX4_1)) \
   1.181 +    || defined(OSF1) || defined(SOLARIS) \
   1.182 +    || defined(HPUX10_30) || defined(HPUX11) \
   1.183 +    || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
   1.184 +    || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \
   1.185 +    || defined(BSDI) || defined(NTO) || defined(DARWIN) \
   1.186 +    || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN)
   1.187 +#define _PRSelectFdSetArg_t fd_set *
   1.188 +#else
   1.189 +#error "Cannot determine architecture"
   1.190 +#endif
   1.191 +
   1.192 +#if defined(SOLARIS)            
   1.193 +#ifndef PROTO_SDP
   1.194 +/* on solaris, SDP is a new type of protocol */
   1.195 +#define PROTO_SDP   257
   1.196 +#endif 
   1.197 +#define _PR_HAVE_SDP
   1.198 +#elif defined(LINUX)
   1.199 +#ifndef AF_INET_SDP
   1.200 +/* on linux, SDP is a new type of address family */
   1.201 +#define AF_INET_SDP 27
   1.202 +#endif
   1.203 +#define _PR_HAVE_SDP
   1.204 +#endif /* LINUX */
   1.205 +
   1.206 +static PRFileDesc *pt_SetMethods(
   1.207 +    PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported);
   1.208 +
   1.209 +static PRLock *_pr_flock_lock;  /* For PR_LockFile() etc. */
   1.210 +static PRCondVar *_pr_flock_cv;  /* For PR_LockFile() etc. */
   1.211 +static PRLock *_pr_rename_lock;  /* For PR_Rename() */
   1.212 +
   1.213 +/**************************************************************************/
   1.214 +
   1.215 +/* These two functions are only used in assertions. */
   1.216 +#if defined(DEBUG)
   1.217 +
   1.218 +PRBool IsValidNetAddr(const PRNetAddr *addr)
   1.219 +{
   1.220 +    if ((addr != NULL)
   1.221 +            && (addr->raw.family != AF_UNIX)
   1.222 +            && (addr->raw.family != PR_AF_INET6)
   1.223 +            && (addr->raw.family != AF_INET)) {
   1.224 +        return PR_FALSE;
   1.225 +    }
   1.226 +    return PR_TRUE;
   1.227 +}
   1.228 +
   1.229 +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
   1.230 +{
   1.231 +    /*
   1.232 +     * The definition of the length of a Unix domain socket address
   1.233 +     * is not uniform, so we don't check it.
   1.234 +     */
   1.235 +    if ((addr != NULL)
   1.236 +            && (addr->raw.family != AF_UNIX)
   1.237 +            && (PR_NETADDR_SIZE(addr) != addr_len)) {
   1.238 +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
   1.239 +        /*
   1.240 +         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
   1.241 +         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
   1.242 +         * field and is 28 bytes.  It is possible for socket functions
   1.243 +         * to return an addr_len greater than sizeof(struct sockaddr_in6).
   1.244 +         * We need to allow that.  (Bugzilla bug #77264)
   1.245 +         */
   1.246 +        if ((PR_AF_INET6 == addr->raw.family)
   1.247 +                && (sizeof(addr->ipv6) == addr_len)) {
   1.248 +            return PR_TRUE;
   1.249 +        }
   1.250 +#endif
   1.251 +        return PR_FALSE;
   1.252 +    }
   1.253 +    return PR_TRUE;
   1.254 +}
   1.255 +
   1.256 +#endif /* DEBUG */
   1.257 +
   1.258 +/*****************************************************************************/
   1.259 +/************************* I/O Continuation machinery ************************/
   1.260 +/*****************************************************************************/
   1.261 +
   1.262 +/*
   1.263 + * The polling interval defines the maximum amount of time that a thread
   1.264 + * might hang up before an interrupt is noticed.
   1.265 + */
   1.266 +#define PT_DEFAULT_POLL_MSEC 5000
   1.267 +#if defined(_PR_POLL_WITH_SELECT)
   1.268 +#define PT_DEFAULT_SELECT_SEC (PT_DEFAULT_POLL_MSEC/PR_MSEC_PER_SEC)
   1.269 +#define PT_DEFAULT_SELECT_USEC							\
   1.270 +		((PT_DEFAULT_POLL_MSEC % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC)
   1.271 +#endif
   1.272 +
   1.273 +/*
   1.274 + * pt_SockLen is the type for the length of a socket address
   1.275 + * structure, used in the address length argument to bind,
   1.276 + * connect, accept, getsockname, getpeername, etc.  Posix.1g
   1.277 + * defines this type as socklen_t.  It is size_t or int on
   1.278 + * most current systems.
   1.279 + */
   1.280 +#if defined(HAVE_SOCKLEN_T) \
   1.281 +    || (defined(__GLIBC__) && __GLIBC__ >= 2)
   1.282 +typedef socklen_t pt_SockLen;
   1.283 +#elif (defined(AIX) && !defined(AIX4_1)) 
   1.284 +typedef PRSize pt_SockLen;
   1.285 +#else
   1.286 +typedef PRIntn pt_SockLen;
   1.287 +#endif
   1.288 +
   1.289 +typedef struct pt_Continuation pt_Continuation;
   1.290 +typedef PRBool (*ContinuationFn)(pt_Continuation *op, PRInt16 revents);
   1.291 +
   1.292 +typedef enum pr_ContuationStatus
   1.293 +{
   1.294 +    pt_continuation_pending,
   1.295 +    pt_continuation_done
   1.296 +} pr_ContuationStatus;
   1.297 +
   1.298 +struct pt_Continuation
   1.299 +{
   1.300 +    /* The building of the continuation operation */
   1.301 +    ContinuationFn function;                /* what function to continue */
   1.302 +    union { PRIntn osfd; } arg1;            /* #1 - the op's fd */
   1.303 +    union { void* buffer; } arg2;           /* #2 - primary transfer buffer */
   1.304 +    union {
   1.305 +        PRSize amount;                      /* #3 - size of 'buffer', or */
   1.306 +        pt_SockLen *addr_len;                  /*    - length of address */
   1.307 +#ifdef HPUX11
   1.308 +        /*
   1.309 +         * For sendfile()
   1.310 +         */
   1.311 +		struct file_spec {		
   1.312 +        	off_t offset;                       /* offset in file to send */
   1.313 +        	size_t nbytes;                      /* length of file data to send */
   1.314 +        	size_t st_size;                     /* file size */
   1.315 +		} file_spec;
   1.316 +#endif
   1.317 +    } arg3;
   1.318 +    union { PRIntn flags; } arg4;           /* #4 - read/write flags */
   1.319 +    union { PRNetAddr *addr; } arg5;        /* #5 - send/recv address */
   1.320 +
   1.321 +#ifdef HPUX11
   1.322 +    /*
   1.323 +     * For sendfile()
   1.324 +     */
   1.325 +    int filedesc;                           /* descriptor of file to send */
   1.326 +    int nbytes_to_send;                     /* size of header and file */
   1.327 +#endif  /* HPUX11 */
   1.328 +    
   1.329 +#ifdef SOLARIS
   1.330 +    /*
   1.331 +     * For sendfilev()
   1.332 +     */
   1.333 +    int nbytes_to_send;                     /* size of header and file */
   1.334 +#endif  /* SOLARIS */
   1.335 +
   1.336 +#ifdef LINUX
   1.337 +    /*
   1.338 +     * For sendfile()
   1.339 +     */
   1.340 +    int in_fd;                              /* descriptor of file to send */
   1.341 +    off_t offset;
   1.342 +    size_t count;
   1.343 +#endif  /* LINUX */
   1.344 + 
   1.345 +    PRIntervalTime timeout;                 /* client (relative) timeout */
   1.346 +
   1.347 +    PRInt16 event;                           /* flags for poll()'s events */
   1.348 +
   1.349 +    /*
   1.350 +    ** The representation and notification of the results of the operation.
   1.351 +    ** These function can either return an int return code or a pointer to
   1.352 +    ** some object.
   1.353 +    */
   1.354 +    union { PRSize code; void *object; } result;
   1.355 +
   1.356 +    PRIntn syserrno;                        /* in case it failed, why (errno) */
   1.357 +    pr_ContuationStatus status;             /* the status of the operation */
   1.358 +};
   1.359 +
   1.360 +#if defined(DEBUG)
   1.361 +
   1.362 +PTDebug pt_debug;  /* this is shared between several modules */
   1.363 +
   1.364 +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
   1.365 +{
   1.366 +    PTDebug stats;
   1.367 +    char buffer[100];
   1.368 +    PRExplodedTime tod;
   1.369 +    PRInt64 elapsed, aMil;
   1.370 +    stats = pt_debug;  /* a copy */
   1.371 +    PR_ExplodeTime(stats.timeStarted, PR_LocalTimeParameters, &tod);
   1.372 +    (void)PR_FormatTime(buffer, sizeof(buffer), "%T", &tod);
   1.373 +
   1.374 +    LL_SUB(elapsed, PR_Now(), stats.timeStarted);
   1.375 +    LL_I2L(aMil, 1000000);
   1.376 +    LL_DIV(elapsed, elapsed, aMil);
   1.377 +    
   1.378 +    if (NULL != msg) PR_fprintf(debug_out, "%s", msg);
   1.379 +    PR_fprintf(
   1.380 +        debug_out, "\tstarted: %s[%lld]\n", buffer, elapsed);
   1.381 +    PR_fprintf(
   1.382 +        debug_out, "\tlocks [created: %u, destroyed: %u]\n",
   1.383 +        stats.locks_created, stats.locks_destroyed);
   1.384 +    PR_fprintf(
   1.385 +        debug_out, "\tlocks [acquired: %u, released: %u]\n",
   1.386 +        stats.locks_acquired, stats.locks_released);
   1.387 +    PR_fprintf(
   1.388 +        debug_out, "\tcvars [created: %u, destroyed: %u]\n",
   1.389 +        stats.cvars_created, stats.cvars_destroyed);
   1.390 +    PR_fprintf(
   1.391 +        debug_out, "\tcvars [notified: %u, delayed_delete: %u]\n",
   1.392 +        stats.cvars_notified, stats.delayed_cv_deletes);
   1.393 +}  /* PT_FPrintStats */
   1.394 +
   1.395 +#else
   1.396 +
   1.397 +PR_IMPLEMENT(void) PT_FPrintStats(PRFileDesc *debug_out, const char *msg)
   1.398 +{
   1.399 +    /* do nothing */
   1.400 +}  /* PT_FPrintStats */
   1.401 +
   1.402 +#endif  /* DEBUG */
   1.403 +
   1.404 +#if defined(_PR_POLL_WITH_SELECT)
   1.405 +/*
   1.406 + * OSF1 and HPUX report the POLLHUP event for a socket when the
   1.407 + * shutdown(SHUT_WR) operation is called for the remote end, even though
   1.408 + * the socket is still writeable. Use select(), instead of poll(), to
   1.409 + * workaround this problem.
   1.410 + */
   1.411 +static void pt_poll_now_with_select(pt_Continuation *op)
   1.412 +{
   1.413 +    PRInt32 msecs;
   1.414 +	fd_set rd, wr, *rdp, *wrp;
   1.415 +	struct timeval tv;
   1.416 +	PRIntervalTime epoch, now, elapsed, remaining;
   1.417 +	PRBool wait_for_remaining;
   1.418 +    PRThread *self = PR_GetCurrentThread();
   1.419 +    
   1.420 +	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
   1.421 +	PR_ASSERT(op->arg1.osfd < FD_SETSIZE);
   1.422 +
   1.423 +    switch (op->timeout) {
   1.424 +        case PR_INTERVAL_NO_TIMEOUT:
   1.425 +			tv.tv_sec = PT_DEFAULT_SELECT_SEC;
   1.426 +			tv.tv_usec = PT_DEFAULT_SELECT_USEC;
   1.427 +			do
   1.428 +			{
   1.429 +				PRIntn rv;
   1.430 +
   1.431 +				if (op->event & POLLIN) {
   1.432 +					FD_ZERO(&rd);
   1.433 +					FD_SET(op->arg1.osfd, &rd);
   1.434 +					rdp = &rd;
   1.435 +				} else
   1.436 +					rdp = NULL;
   1.437 +				if (op->event & POLLOUT) {
   1.438 +					FD_ZERO(&wr);
   1.439 +					FD_SET(op->arg1.osfd, &wr);
   1.440 +					wrp = &wr;
   1.441 +				} else
   1.442 +					wrp = NULL;
   1.443 +
   1.444 +				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
   1.445 +
   1.446 +				if (_PT_THREAD_INTERRUPTED(self))
   1.447 +				{
   1.448 +					self->state &= ~PT_THREAD_ABORTED;
   1.449 +					op->result.code = -1;
   1.450 +					op->syserrno = EINTR;
   1.451 +					op->status = pt_continuation_done;
   1.452 +					return;
   1.453 +				}
   1.454 +
   1.455 +				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
   1.456 +					continue; /* go around the loop again */
   1.457 +
   1.458 +				if (rv > 0)
   1.459 +				{
   1.460 +					PRInt16 revents = 0;
   1.461 +
   1.462 +					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
   1.463 +						revents |= POLLIN;
   1.464 +					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
   1.465 +						revents |= POLLOUT;
   1.466 +						
   1.467 +					if (op->function(op, revents))
   1.468 +						op->status = pt_continuation_done;
   1.469 +				} else if (rv == -1) {
   1.470 +					op->result.code = -1;
   1.471 +					op->syserrno = errno;
   1.472 +					op->status = pt_continuation_done;
   1.473 +				}
   1.474 +				/* else, select timed out */
   1.475 +			} while (pt_continuation_done != op->status);
   1.476 +			break;
   1.477 +        default:
   1.478 +            now = epoch = PR_IntervalNow();
   1.479 +            remaining = op->timeout;
   1.480 +			do
   1.481 +			{
   1.482 +				PRIntn rv;
   1.483 +
   1.484 +				if (op->event & POLLIN) {
   1.485 +					FD_ZERO(&rd);
   1.486 +					FD_SET(op->arg1.osfd, &rd);
   1.487 +					rdp = &rd;
   1.488 +				} else
   1.489 +					rdp = NULL;
   1.490 +				if (op->event & POLLOUT) {
   1.491 +					FD_ZERO(&wr);
   1.492 +					FD_SET(op->arg1.osfd, &wr);
   1.493 +					wrp = &wr;
   1.494 +				} else
   1.495 +					wrp = NULL;
   1.496 +
   1.497 +    			wait_for_remaining = PR_TRUE;
   1.498 +    			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
   1.499 +				if (msecs > PT_DEFAULT_POLL_MSEC) {
   1.500 +					wait_for_remaining = PR_FALSE;
   1.501 +					msecs = PT_DEFAULT_POLL_MSEC;
   1.502 +				}
   1.503 +				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
   1.504 +				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
   1.505 +				rv = select(op->arg1.osfd + 1, rdp, wrp, NULL, &tv);
   1.506 +
   1.507 +				if (_PT_THREAD_INTERRUPTED(self))
   1.508 +				{
   1.509 +					self->state &= ~PT_THREAD_ABORTED;
   1.510 +					op->result.code = -1;
   1.511 +					op->syserrno = EINTR;
   1.512 +					op->status = pt_continuation_done;
   1.513 +					return;
   1.514 +				}
   1.515 +
   1.516 +				if (rv > 0) {
   1.517 +					PRInt16 revents = 0;
   1.518 +
   1.519 +					if ((op->event & POLLIN) && FD_ISSET(op->arg1.osfd, &rd))
   1.520 +						revents |= POLLIN;
   1.521 +					if ((op->event & POLLOUT) && FD_ISSET(op->arg1.osfd, &wr))
   1.522 +						revents |= POLLOUT;
   1.523 +						
   1.524 +					if (op->function(op, revents))
   1.525 +						op->status = pt_continuation_done;
   1.526 +
   1.527 +				} else if ((rv == 0) ||
   1.528 +						((errno == EINTR) || (errno == EAGAIN))) {
   1.529 +					if (rv == 0) {	/* select timed out */
   1.530 +						if (wait_for_remaining)
   1.531 +							now += remaining;
   1.532 +						else
   1.533 +							now += PR_MillisecondsToInterval(msecs);
   1.534 +					} else
   1.535 +						now = PR_IntervalNow();
   1.536 +					elapsed = (PRIntervalTime) (now - epoch);
   1.537 +					if (elapsed >= op->timeout) {
   1.538 +						op->result.code = -1;
   1.539 +						op->syserrno = ETIMEDOUT;
   1.540 +						op->status = pt_continuation_done;
   1.541 +					} else
   1.542 +						remaining = op->timeout - elapsed;
   1.543 +				} else {
   1.544 +					op->result.code = -1;
   1.545 +					op->syserrno = errno;
   1.546 +					op->status = pt_continuation_done;
   1.547 +				}
   1.548 +			} while (pt_continuation_done != op->status);
   1.549 +            break;
   1.550 +    }
   1.551 +
   1.552 +}  /* pt_poll_now_with_select */
   1.553 +
   1.554 +#endif	/* _PR_POLL_WITH_SELECT */
   1.555 +
   1.556 +static void pt_poll_now(pt_Continuation *op)
   1.557 +{
   1.558 +    PRInt32 msecs;
   1.559 +	PRIntervalTime epoch, now, elapsed, remaining;
   1.560 +	PRBool wait_for_remaining;
   1.561 +    PRThread *self = PR_GetCurrentThread();
   1.562 +    
   1.563 +	PR_ASSERT(PR_INTERVAL_NO_WAIT != op->timeout);
   1.564 +#if defined (_PR_POLL_WITH_SELECT)
   1.565 +	/*
   1.566 + 	 * If the fd is small enough call the select-based poll operation
   1.567 +	 */
   1.568 +	if (op->arg1.osfd < FD_SETSIZE) {
   1.569 +		pt_poll_now_with_select(op);
   1.570 +		return;
   1.571 +	}
   1.572 +#endif
   1.573 +
   1.574 +    switch (op->timeout) {
   1.575 +        case PR_INTERVAL_NO_TIMEOUT:
   1.576 +			msecs = PT_DEFAULT_POLL_MSEC;
   1.577 +			do
   1.578 +			{
   1.579 +				PRIntn rv;
   1.580 +				struct pollfd tmp_pfd;
   1.581 +
   1.582 +				tmp_pfd.revents = 0;
   1.583 +				tmp_pfd.fd = op->arg1.osfd;
   1.584 +				tmp_pfd.events = op->event;
   1.585 +
   1.586 +				rv = poll(&tmp_pfd, 1, msecs);
   1.587 +				
   1.588 +				if (_PT_THREAD_INTERRUPTED(self))
   1.589 +				{
   1.590 +					self->state &= ~PT_THREAD_ABORTED;
   1.591 +					op->result.code = -1;
   1.592 +					op->syserrno = EINTR;
   1.593 +					op->status = pt_continuation_done;
   1.594 +					return;
   1.595 +				}
   1.596 +
   1.597 +				if ((-1 == rv) && ((errno == EINTR) || (errno == EAGAIN)))
   1.598 +					continue; /* go around the loop again */
   1.599 +
   1.600 +				if (rv > 0)
   1.601 +				{
   1.602 +					PRInt16 events = tmp_pfd.events;
   1.603 +					PRInt16 revents = tmp_pfd.revents;
   1.604 +
   1.605 +					if ((revents & POLLNVAL)  /* busted in all cases */
   1.606 +					|| ((events & POLLOUT) && (revents & POLLHUP)))
   1.607 +						/* write op & hup */
   1.608 +					{
   1.609 +						op->result.code = -1;
   1.610 +						if (POLLNVAL & revents) op->syserrno = EBADF;
   1.611 +						else if (POLLHUP & revents) op->syserrno = EPIPE;
   1.612 +						op->status = pt_continuation_done;
   1.613 +					} else {
   1.614 +						if (op->function(op, revents))
   1.615 +							op->status = pt_continuation_done;
   1.616 +					}
   1.617 +				} else if (rv == -1) {
   1.618 +					op->result.code = -1;
   1.619 +					op->syserrno = errno;
   1.620 +					op->status = pt_continuation_done;
   1.621 +				}
   1.622 +				/* else, poll timed out */
   1.623 +			} while (pt_continuation_done != op->status);
   1.624 +			break;
   1.625 +        default:
   1.626 +            now = epoch = PR_IntervalNow();
   1.627 +            remaining = op->timeout;
   1.628 +			do
   1.629 +			{
   1.630 +				PRIntn rv;
   1.631 +				struct pollfd tmp_pfd;
   1.632 +
   1.633 +				tmp_pfd.revents = 0;
   1.634 +				tmp_pfd.fd = op->arg1.osfd;
   1.635 +				tmp_pfd.events = op->event;
   1.636 +
   1.637 +    			wait_for_remaining = PR_TRUE;
   1.638 +    			msecs = (PRInt32)PR_IntervalToMilliseconds(remaining);
   1.639 +				if (msecs > PT_DEFAULT_POLL_MSEC)
   1.640 +				{
   1.641 +					wait_for_remaining = PR_FALSE;
   1.642 +					msecs = PT_DEFAULT_POLL_MSEC;
   1.643 +				}
   1.644 +				rv = poll(&tmp_pfd, 1, msecs);
   1.645 +				
   1.646 +				if (_PT_THREAD_INTERRUPTED(self))
   1.647 +				{
   1.648 +					self->state &= ~PT_THREAD_ABORTED;
   1.649 +					op->result.code = -1;
   1.650 +					op->syserrno = EINTR;
   1.651 +					op->status = pt_continuation_done;
   1.652 +					return;
   1.653 +				}
   1.654 +
   1.655 +				if (rv > 0)
   1.656 +				{
   1.657 +					PRInt16 events = tmp_pfd.events;
   1.658 +					PRInt16 revents = tmp_pfd.revents;
   1.659 +
   1.660 +					if ((revents & POLLNVAL)  /* busted in all cases */
   1.661 +						|| ((events & POLLOUT) && (revents & POLLHUP))) 
   1.662 +											/* write op & hup */
   1.663 +					{
   1.664 +						op->result.code = -1;
   1.665 +						if (POLLNVAL & revents) op->syserrno = EBADF;
   1.666 +						else if (POLLHUP & revents) op->syserrno = EPIPE;
   1.667 +						op->status = pt_continuation_done;
   1.668 +					} else {
   1.669 +						if (op->function(op, revents))
   1.670 +						{
   1.671 +							op->status = pt_continuation_done;
   1.672 +						}
   1.673 +					}
   1.674 +				} else if ((rv == 0) ||
   1.675 +						((errno == EINTR) || (errno == EAGAIN))) {
   1.676 +					if (rv == 0)	/* poll timed out */
   1.677 +					{
   1.678 +						if (wait_for_remaining)
   1.679 +							now += remaining;
   1.680 +						else
   1.681 +							now += PR_MillisecondsToInterval(msecs);
   1.682 +					}
   1.683 +					else
   1.684 +						now = PR_IntervalNow();
   1.685 +					elapsed = (PRIntervalTime) (now - epoch);
   1.686 +					if (elapsed >= op->timeout) {
   1.687 +						op->result.code = -1;
   1.688 +						op->syserrno = ETIMEDOUT;
   1.689 +						op->status = pt_continuation_done;
   1.690 +					} else
   1.691 +						remaining = op->timeout - elapsed;
   1.692 +				} else {
   1.693 +					op->result.code = -1;
   1.694 +					op->syserrno = errno;
   1.695 +					op->status = pt_continuation_done;
   1.696 +				}
   1.697 +			} while (pt_continuation_done != op->status);
   1.698 +            break;
   1.699 +    }
   1.700 +
   1.701 +}  /* pt_poll_now */
   1.702 +
   1.703 +static PRIntn pt_Continue(pt_Continuation *op)
   1.704 +{
   1.705 +    op->status = pt_continuation_pending;  /* set default value */
   1.706 +	/*
   1.707 +	 * let each thread call poll directly
   1.708 +	 */
   1.709 +	pt_poll_now(op);
   1.710 +	PR_ASSERT(pt_continuation_done == op->status);
   1.711 +    return op->result.code;
   1.712 +}  /* pt_Continue */
   1.713 +
   1.714 +/*****************************************************************************/
   1.715 +/*********************** specific continuation functions *********************/
   1.716 +/*****************************************************************************/
   1.717 +static PRBool pt_connect_cont(pt_Continuation *op, PRInt16 revents)
   1.718 +{
   1.719 +    op->syserrno = _MD_unix_get_nonblocking_connect_error(op->arg1.osfd);
   1.720 +    if (op->syserrno != 0) {
   1.721 +        op->result.code = -1;
   1.722 +    } else {
   1.723 +        op->result.code = 0;
   1.724 +    }
   1.725 +    return PR_TRUE; /* this one is cooked */
   1.726 +}  /* pt_connect_cont */
   1.727 +
   1.728 +static PRBool pt_accept_cont(pt_Continuation *op, PRInt16 revents)
   1.729 +{
   1.730 +    op->syserrno = 0;
   1.731 +    op->result.code = accept(
   1.732 +        op->arg1.osfd, op->arg2.buffer, op->arg3.addr_len);
   1.733 +    if (-1 == op->result.code)
   1.734 +    {
   1.735 +        op->syserrno = errno;
   1.736 +        if (EWOULDBLOCK == errno || EAGAIN == errno || ECONNABORTED == errno)
   1.737 +            return PR_FALSE;  /* do nothing - this one ain't finished */
   1.738 +    }
   1.739 +    return PR_TRUE;
   1.740 +}  /* pt_accept_cont */
   1.741 +
   1.742 +static PRBool pt_read_cont(pt_Continuation *op, PRInt16 revents)
   1.743 +{
   1.744 +    /*
   1.745 +     * Any number of bytes will complete the operation. It need
   1.746 +     * not (and probably will not) satisfy the request. The only
   1.747 +     * error we continue is EWOULDBLOCK|EAGAIN.
   1.748 +     */
   1.749 +    op->result.code = read(
   1.750 +        op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   1.751 +    op->syserrno = errno;
   1.752 +    return ((-1 == op->result.code) && 
   1.753 +            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   1.754 +        PR_FALSE : PR_TRUE;
   1.755 +}  /* pt_read_cont */
   1.756 +
   1.757 +static PRBool pt_recv_cont(pt_Continuation *op, PRInt16 revents)
   1.758 +{
   1.759 +    /*
   1.760 +     * Any number of bytes will complete the operation. It need
   1.761 +     * not (and probably will not) satisfy the request. The only
   1.762 +     * error we continue is EWOULDBLOCK|EAGAIN.
   1.763 +     */
   1.764 +#if defined(SOLARIS)
   1.765 +    if (0 == op->arg4.flags)
   1.766 +        op->result.code = read(
   1.767 +            op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   1.768 +    else
   1.769 +        op->result.code = recv(
   1.770 +            op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   1.771 +#else
   1.772 +    op->result.code = recv(
   1.773 +        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   1.774 +#endif
   1.775 +    op->syserrno = errno;
   1.776 +    return ((-1 == op->result.code) && 
   1.777 +            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   1.778 +        PR_FALSE : PR_TRUE;
   1.779 +}  /* pt_recv_cont */
   1.780 +
   1.781 +static PRBool pt_send_cont(pt_Continuation *op, PRInt16 revents)
   1.782 +{
   1.783 +    PRIntn bytes;
   1.784 +#if defined(SOLARIS)
   1.785 +    PRInt32 tmp_amount = op->arg3.amount;
   1.786 +#endif
   1.787 +    /*
   1.788 +     * We want to write the entire amount out, no matter how many
   1.789 +     * tries it takes. Keep advancing the buffer and the decrementing
   1.790 +     * the amount until the amount goes away. Return the total bytes
   1.791 +     * (which should be the original amount) when finished (or an
   1.792 +     * error).
   1.793 +     */
   1.794 +#if defined(SOLARIS)
   1.795 +retry:
   1.796 +    bytes = write(op->arg1.osfd, op->arg2.buffer, tmp_amount);
   1.797 +#else
   1.798 +    bytes = send(
   1.799 +        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags);
   1.800 +#endif
   1.801 +    op->syserrno = errno;
   1.802 +
   1.803 +#if defined(SOLARIS)
   1.804 +    /*
   1.805 +     * The write system call has been reported to return the ERANGE error
   1.806 +     * on occasion. Try to write in smaller chunks to workaround this bug.
   1.807 +     */
   1.808 +    if ((bytes == -1) && (op->syserrno == ERANGE))
   1.809 +    {
   1.810 +        if (tmp_amount > 1)
   1.811 +        {
   1.812 +            tmp_amount = tmp_amount/2;  /* half the bytes */
   1.813 +            goto retry;
   1.814 +        }
   1.815 +    }
   1.816 +#endif
   1.817 +
   1.818 +    if (bytes >= 0)  /* this is progress */
   1.819 +    {
   1.820 +        char *bp = (char*)op->arg2.buffer;
   1.821 +        bp += bytes;  /* adjust the buffer pointer */
   1.822 +        op->arg2.buffer = bp;
   1.823 +        op->result.code += bytes;  /* accumulate the number sent */
   1.824 +        op->arg3.amount -= bytes;  /* and reduce the required count */
   1.825 +        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   1.826 +    }
   1.827 +    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   1.828 +    {
   1.829 +        op->result.code = -1;
   1.830 +        return PR_TRUE;
   1.831 +    }
   1.832 +    else return PR_FALSE;
   1.833 +}  /* pt_send_cont */
   1.834 +
   1.835 +static PRBool pt_write_cont(pt_Continuation *op, PRInt16 revents)
   1.836 +{
   1.837 +    PRIntn bytes;
   1.838 +    /*
   1.839 +     * We want to write the entire amount out, no matter how many
   1.840 +     * tries it takes. Keep advancing the buffer and the decrementing
   1.841 +     * the amount until the amount goes away. Return the total bytes
   1.842 +     * (which should be the original amount) when finished (or an
   1.843 +     * error).
   1.844 +     */
   1.845 +    bytes = write(op->arg1.osfd, op->arg2.buffer, op->arg3.amount);
   1.846 +    op->syserrno = errno;
   1.847 +    if (bytes >= 0)  /* this is progress */
   1.848 +    {
   1.849 +        char *bp = (char*)op->arg2.buffer;
   1.850 +        bp += bytes;  /* adjust the buffer pointer */
   1.851 +        op->arg2.buffer = bp;
   1.852 +        op->result.code += bytes;  /* accumulate the number sent */
   1.853 +        op->arg3.amount -= bytes;  /* and reduce the required count */
   1.854 +        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   1.855 +    }
   1.856 +    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   1.857 +    {
   1.858 +        op->result.code = -1;
   1.859 +        return PR_TRUE;
   1.860 +    }
   1.861 +    else return PR_FALSE;
   1.862 +}  /* pt_write_cont */
   1.863 +
   1.864 +static PRBool pt_writev_cont(pt_Continuation *op, PRInt16 revents)
   1.865 +{
   1.866 +    PRIntn bytes;
   1.867 +    struct iovec *iov = (struct iovec*)op->arg2.buffer;
   1.868 +    /*
   1.869 +     * Same rules as write, but continuing seems to be a bit more
   1.870 +     * complicated. As the number of bytes sent grows, we have to
   1.871 +     * redefine the vector we're pointing at. We might have to
   1.872 +     * modify an individual vector parms or we might have to eliminate
   1.873 +     * a pair altogether.
   1.874 +     */
   1.875 +    bytes = writev(op->arg1.osfd, iov, op->arg3.amount);
   1.876 +    op->syserrno = errno;
   1.877 +    if (bytes >= 0)  /* this is progress */
   1.878 +    {
   1.879 +        PRIntn iov_index;
   1.880 +        op->result.code += bytes;  /* accumulate the number sent */
   1.881 +        for (iov_index = 0; iov_index < op->arg3.amount; ++iov_index)
   1.882 +        {
   1.883 +            /* how much progress did we make in the i/o vector? */
   1.884 +            if (bytes < iov[iov_index].iov_len)
   1.885 +            {
   1.886 +                /* this element's not done yet */
   1.887 +                char **bp = (char**)&(iov[iov_index].iov_base);
   1.888 +                iov[iov_index].iov_len -= bytes;  /* there's that much left */
   1.889 +                *bp += bytes;  /* starting there */
   1.890 +                break;  /* go off and do that */
   1.891 +            }
   1.892 +            bytes -= iov[iov_index].iov_len;  /* that element's consumed */
   1.893 +        }
   1.894 +        op->arg2.buffer = &iov[iov_index];  /* new start of array */
   1.895 +        op->arg3.amount -= iov_index;  /* and array length */
   1.896 +        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   1.897 +    }
   1.898 +    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   1.899 +    {
   1.900 +        op->result.code = -1;
   1.901 +        return PR_TRUE;
   1.902 +    }
   1.903 +    else return PR_FALSE;
   1.904 +}  /* pt_writev_cont */
   1.905 +
   1.906 +static PRBool pt_sendto_cont(pt_Continuation *op, PRInt16 revents)
   1.907 +{
   1.908 +    PRIntn bytes = sendto(
   1.909 +        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
   1.910 +        (struct sockaddr*)op->arg5.addr, PR_NETADDR_SIZE(op->arg5.addr));
   1.911 +    op->syserrno = errno;
   1.912 +    if (bytes >= 0)  /* this is progress */
   1.913 +    {
   1.914 +        char *bp = (char*)op->arg2.buffer;
   1.915 +        bp += bytes;  /* adjust the buffer pointer */
   1.916 +        op->arg2.buffer = bp;
   1.917 +        op->result.code += bytes;  /* accumulate the number sent */
   1.918 +        op->arg3.amount -= bytes;  /* and reduce the required count */
   1.919 +        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
   1.920 +    }
   1.921 +    else if ((EWOULDBLOCK != op->syserrno) && (EAGAIN != op->syserrno))
   1.922 +    {
   1.923 +        op->result.code = -1;
   1.924 +        return PR_TRUE;
   1.925 +    }
   1.926 +    else return PR_FALSE;
   1.927 +}  /* pt_sendto_cont */
   1.928 +
   1.929 +static PRBool pt_recvfrom_cont(pt_Continuation *op, PRInt16 revents)
   1.930 +{
   1.931 +    pt_SockLen addr_len = sizeof(PRNetAddr);
   1.932 +    op->result.code = recvfrom(
   1.933 +        op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
   1.934 +        op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
   1.935 +    op->syserrno = errno;
   1.936 +    return ((-1 == op->result.code) && 
   1.937 +            (EWOULDBLOCK == op->syserrno || EAGAIN == op->syserrno)) ?
   1.938 +        PR_FALSE : PR_TRUE;
   1.939 +}  /* pt_recvfrom_cont */
   1.940 +
   1.941 +#ifdef AIX
   1.942 +static PRBool pt_aix_sendfile_cont(pt_Continuation *op, PRInt16 revents)
   1.943 +{
   1.944 +    struct sf_parms *sf_struct = (struct sf_parms *) op->arg2.buffer;
   1.945 +    ssize_t rv;
   1.946 +	unsigned long long saved_file_offset;
   1.947 +	long long saved_file_bytes;
   1.948 +
   1.949 +	saved_file_offset = sf_struct->file_offset;
   1.950 +	saved_file_bytes = sf_struct->file_bytes;
   1.951 +	sf_struct->bytes_sent = 0;
   1.952 +
   1.953 +	if ((sf_struct->file_bytes > 0) && (sf_struct->file_size > 0))
   1.954 +	PR_ASSERT((sf_struct->file_bytes + sf_struct->file_offset) <=
   1.955 +									sf_struct->file_size);
   1.956 +    rv = AIX_SEND_FILE(&op->arg1.osfd, sf_struct, op->arg4.flags);
   1.957 +    op->syserrno = errno;
   1.958 +
   1.959 +    if (rv != -1) {
   1.960 +        op->result.code += sf_struct->bytes_sent;
   1.961 +		/*
   1.962 +		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
   1.963 +		 * being updated. So, 'file_bytes' is maintained by NSPR to
   1.964 +		 * avoid conflict when this bug is fixed in AIX, in the future.
   1.965 +		 */
   1.966 +		if (saved_file_bytes != -1)
   1.967 +			saved_file_bytes -= (sf_struct->file_offset - saved_file_offset);
   1.968 +		sf_struct->file_bytes = saved_file_bytes;
   1.969 +    } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
   1.970 +        op->result.code = -1;
   1.971 +    } else {
   1.972 +        return PR_FALSE;
   1.973 +    }
   1.974 +
   1.975 +    if (rv == 1) {    /* more data to send */
   1.976 +        return PR_FALSE;
   1.977 +    }
   1.978 +
   1.979 +    return PR_TRUE;
   1.980 +}
   1.981 +#endif  /* AIX */
   1.982 +
   1.983 +#ifdef HPUX11
   1.984 +static PRBool pt_hpux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
   1.985 +{
   1.986 +    struct iovec *hdtrl = (struct iovec *) op->arg2.buffer;
   1.987 +    int count;
   1.988 +
   1.989 +    count = sendfile(op->arg1.osfd, op->filedesc, op->arg3.file_spec.offset,
   1.990 +			op->arg3.file_spec.nbytes, hdtrl, op->arg4.flags);
   1.991 +    PR_ASSERT(count <= op->nbytes_to_send);
   1.992 +    op->syserrno = errno;
   1.993 +
   1.994 +    if (count != -1) {
   1.995 +        op->result.code += count;
   1.996 +    } else if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
   1.997 +        op->result.code = -1;
   1.998 +    } else {
   1.999 +        return PR_FALSE;
  1.1000 +    }
  1.1001 +    if (count != -1 && count < op->nbytes_to_send) {
  1.1002 +        if (count < hdtrl[0].iov_len) {
  1.1003 +			/* header not sent */
  1.1004 +
  1.1005 +            hdtrl[0].iov_base = ((char *) hdtrl[0].iov_base) + count;
  1.1006 +            hdtrl[0].iov_len -= count;
  1.1007 +
  1.1008 +        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes)) {
  1.1009 +			/* header sent, file not sent */
  1.1010 +            PRUint32 file_nbytes_sent = count - hdtrl[0].iov_len;
  1.1011 +
  1.1012 +            hdtrl[0].iov_base = NULL;
  1.1013 +            hdtrl[0].iov_len = 0;
  1.1014 +
  1.1015 +            op->arg3.file_spec.offset += file_nbytes_sent;
  1.1016 +            op->arg3.file_spec.nbytes -= file_nbytes_sent;
  1.1017 +        } else if (count < (hdtrl[0].iov_len + op->arg3.file_spec.nbytes +
  1.1018 +											hdtrl[1].iov_len)) {
  1.1019 +            PRUint32 trailer_nbytes_sent = count - (hdtrl[0].iov_len +
  1.1020 +                                         op->arg3.file_spec.nbytes);
  1.1021 +
  1.1022 +			/* header sent, file sent, trailer not sent */
  1.1023 +
  1.1024 +            hdtrl[0].iov_base = NULL;
  1.1025 +            hdtrl[0].iov_len = 0;
  1.1026 +			/*
  1.1027 +			 * set file offset and len so that no more file data is
  1.1028 +			 * sent
  1.1029 +			 */
  1.1030 +            op->arg3.file_spec.offset = op->arg3.file_spec.st_size;
  1.1031 +            op->arg3.file_spec.nbytes = 0;
  1.1032 +
  1.1033 +            hdtrl[1].iov_base =((char *) hdtrl[1].iov_base)+ trailer_nbytes_sent;
  1.1034 +            hdtrl[1].iov_len -= trailer_nbytes_sent;
  1.1035 +		}
  1.1036 +        op->nbytes_to_send -= count;
  1.1037 +        return PR_FALSE;
  1.1038 +    }
  1.1039 +
  1.1040 +    return PR_TRUE;
  1.1041 +}
  1.1042 +#endif  /* HPUX11 */
  1.1043 +
  1.1044 +#ifdef SOLARIS  
  1.1045 +static PRBool pt_solaris_sendfile_cont(pt_Continuation *op, PRInt16 revents)
  1.1046 +{
  1.1047 +    struct sendfilevec *vec = (struct sendfilevec *) op->arg2.buffer;
  1.1048 +    size_t xferred;
  1.1049 +    ssize_t count;
  1.1050 +
  1.1051 +    count = SOLARIS_SENDFILEV(op->arg1.osfd, vec, op->arg3.amount, &xferred);
  1.1052 +    op->syserrno = errno;
  1.1053 +    PR_ASSERT((count == -1) || (count == xferred));
  1.1054 +
  1.1055 +    if (count == -1) {
  1.1056 +        if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN
  1.1057 +                && op->syserrno != EINTR) {
  1.1058 +            op->result.code = -1;
  1.1059 +            return PR_TRUE;
  1.1060 +        }
  1.1061 +        count = xferred;
  1.1062 +    } else if (count == 0) {
  1.1063 +        /* 
  1.1064 +         * We are now at EOF. The file was truncated. Solaris sendfile is
  1.1065 +         * supposed to return 0 and no error in this case, though some versions
  1.1066 +         * may return -1 and EINVAL .
  1.1067 +         */
  1.1068 +        op->result.code = -1;
  1.1069 +        op->syserrno = 0; /* will be treated as EOF */
  1.1070 +        return PR_TRUE;
  1.1071 +    }
  1.1072 +    PR_ASSERT(count <= op->nbytes_to_send);
  1.1073 +    
  1.1074 +    op->result.code += count;
  1.1075 +    if (count < op->nbytes_to_send) {
  1.1076 +        op->nbytes_to_send -= count;
  1.1077 +
  1.1078 +        while (count >= vec->sfv_len) {
  1.1079 +            count -= vec->sfv_len;
  1.1080 +            vec++;
  1.1081 +            op->arg3.amount--;
  1.1082 +        }
  1.1083 +        PR_ASSERT(op->arg3.amount > 0);
  1.1084 +
  1.1085 +        vec->sfv_off += count;
  1.1086 +        vec->sfv_len -= count;
  1.1087 +        PR_ASSERT(vec->sfv_len > 0);
  1.1088 +        op->arg2.buffer = vec;
  1.1089 +
  1.1090 +        return PR_FALSE;
  1.1091 +    }
  1.1092 +
  1.1093 +    return PR_TRUE;
  1.1094 +}
  1.1095 +#endif  /* SOLARIS */
  1.1096 +
  1.1097 +#ifdef LINUX 
  1.1098 +static PRBool pt_linux_sendfile_cont(pt_Continuation *op, PRInt16 revents)
  1.1099 +{
  1.1100 +    ssize_t rv;
  1.1101 +    off_t oldoffset;
  1.1102 +
  1.1103 +    oldoffset = op->offset;
  1.1104 +    rv = sendfile(op->arg1.osfd, op->in_fd, &op->offset, op->count);
  1.1105 +    op->syserrno = errno;
  1.1106 +
  1.1107 +    if (rv == -1) {
  1.1108 +        if (op->syserrno != EWOULDBLOCK && op->syserrno != EAGAIN) {
  1.1109 +            op->result.code = -1;
  1.1110 +            return PR_TRUE;
  1.1111 +        }
  1.1112 +        rv = 0;
  1.1113 +    }
  1.1114 +    PR_ASSERT(rv == op->offset - oldoffset);
  1.1115 +    op->result.code += rv;
  1.1116 +    if (rv < op->count) {
  1.1117 +        op->count -= rv;
  1.1118 +        return PR_FALSE;
  1.1119 +    }
  1.1120 +    return PR_TRUE;
  1.1121 +}
  1.1122 +#endif  /* LINUX */
  1.1123 +
  1.1124 +void _PR_InitIO(void)
  1.1125 +{
  1.1126 +#if defined(DEBUG)
  1.1127 +    memset(&pt_debug, 0, sizeof(PTDebug));
  1.1128 +    pt_debug.timeStarted = PR_Now();
  1.1129 +#endif
  1.1130 +
  1.1131 +    _pr_flock_lock = PR_NewLock();
  1.1132 +    PR_ASSERT(NULL != _pr_flock_lock);
  1.1133 +    _pr_flock_cv = PR_NewCondVar(_pr_flock_lock);
  1.1134 +    PR_ASSERT(NULL != _pr_flock_cv);
  1.1135 +    _pr_rename_lock = PR_NewLock();
  1.1136 +    PR_ASSERT(NULL != _pr_rename_lock); 
  1.1137 +
  1.1138 +    _PR_InitFdCache();  /* do that */   
  1.1139 +
  1.1140 +    _pr_stdin = pt_SetMethods(0, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1.1141 +    _pr_stdout = pt_SetMethods(1, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1.1142 +    _pr_stderr = pt_SetMethods(2, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1.1143 +    PR_ASSERT(_pr_stdin && _pr_stdout && _pr_stderr);
  1.1144 +
  1.1145 +#ifdef _PR_IPV6_V6ONLY_PROBE
  1.1146 +    /* In Mac OS X v10.3 Panther Beta the IPV6_V6ONLY socket option
  1.1147 +     * is turned on by default, contrary to what RFC 3493, Section
  1.1148 +     * 5.3 says.  So we have to turn it off.  Find out whether we
  1.1149 +     * are running on such a system.
  1.1150 +     */
  1.1151 +    {
  1.1152 +        int osfd;
  1.1153 +        osfd = socket(AF_INET6, SOCK_STREAM, 0);
  1.1154 +        if (osfd != -1) {
  1.1155 +            int on;
  1.1156 +            socklen_t optlen = sizeof(on);
  1.1157 +            if (getsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
  1.1158 +                    &on, &optlen) == 0) {
  1.1159 +                _pr_ipv6_v6only_on_by_default = on;
  1.1160 +            }
  1.1161 +            close(osfd);
  1.1162 +        }
  1.1163 +    }
  1.1164 +#endif
  1.1165 +}  /* _PR_InitIO */
  1.1166 +
  1.1167 +void _PR_CleanupIO(void)
  1.1168 +{
  1.1169 +    _PR_Putfd(_pr_stdin);
  1.1170 +    _pr_stdin = NULL;
  1.1171 +    _PR_Putfd(_pr_stdout);
  1.1172 +    _pr_stdout = NULL;
  1.1173 +    _PR_Putfd(_pr_stderr); 
  1.1174 +    _pr_stderr = NULL;
  1.1175 +
  1.1176 +    _PR_CleanupFdCache();
  1.1177 +    
  1.1178 +    if (_pr_flock_cv)
  1.1179 +    {
  1.1180 +        PR_DestroyCondVar(_pr_flock_cv);
  1.1181 +        _pr_flock_cv = NULL;
  1.1182 +    }
  1.1183 +    if (_pr_flock_lock)
  1.1184 +    {
  1.1185 +        PR_DestroyLock(_pr_flock_lock);
  1.1186 +        _pr_flock_lock = NULL;
  1.1187 +    }
  1.1188 +    if (_pr_rename_lock)
  1.1189 +    {
  1.1190 +        PR_DestroyLock(_pr_rename_lock);
  1.1191 +        _pr_rename_lock = NULL;
  1.1192 +    }
  1.1193 +}  /* _PR_CleanupIO */
  1.1194 +
  1.1195 +PR_IMPLEMENT(PRFileDesc*) PR_GetSpecialFD(PRSpecialFD osfd)
  1.1196 +{
  1.1197 +    PRFileDesc *result = NULL;
  1.1198 +    PR_ASSERT(osfd >= PR_StandardInput && osfd <= PR_StandardError);
  1.1199 +
  1.1200 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.1201 +    
  1.1202 +    switch (osfd)
  1.1203 +    {
  1.1204 +        case PR_StandardInput: result = _pr_stdin; break;
  1.1205 +        case PR_StandardOutput: result = _pr_stdout; break;
  1.1206 +        case PR_StandardError: result = _pr_stderr; break;
  1.1207 +        default:
  1.1208 +            (void)PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1209 +    }
  1.1210 +    return result;
  1.1211 +}  /* PR_GetSpecialFD */
  1.1212 +
  1.1213 +/*****************************************************************************/
  1.1214 +/***************************** I/O private methods ***************************/
  1.1215 +/*****************************************************************************/
  1.1216 +
  1.1217 +static PRBool pt_TestAbort(void)
  1.1218 +{
  1.1219 +    PRThread *me = PR_GetCurrentThread();
  1.1220 +    if(_PT_THREAD_INTERRUPTED(me))
  1.1221 +    {
  1.1222 +        PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  1.1223 +        me->state &= ~PT_THREAD_ABORTED;
  1.1224 +        return PR_TRUE;
  1.1225 +    }
  1.1226 +    return PR_FALSE;
  1.1227 +}  /* pt_TestAbort */
  1.1228 +
  1.1229 +static void pt_MapError(void (*mapper)(PRIntn), PRIntn syserrno)
  1.1230 +{
  1.1231 +    switch (syserrno)
  1.1232 +    {
  1.1233 +        case EINTR:
  1.1234 +            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); break;
  1.1235 +        case ETIMEDOUT:
  1.1236 +            PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break;
  1.1237 +        default:
  1.1238 +            mapper(syserrno);
  1.1239 +    }
  1.1240 +}  /* pt_MapError */
  1.1241 +
  1.1242 +static PRStatus pt_Close(PRFileDesc *fd)
  1.1243 +{
  1.1244 +    if ((NULL == fd) || (NULL == fd->secret)
  1.1245 +        || ((_PR_FILEDESC_OPEN != fd->secret->state)
  1.1246 +        && (_PR_FILEDESC_CLOSED != fd->secret->state)))
  1.1247 +    {
  1.1248 +        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1.1249 +        return PR_FAILURE;
  1.1250 +    }
  1.1251 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1252 +
  1.1253 +    if (_PR_FILEDESC_OPEN == fd->secret->state)
  1.1254 +    {
  1.1255 +        if (-1 == close(fd->secret->md.osfd))
  1.1256 +        {
  1.1257 +#ifdef OSF1
  1.1258 +            /*
  1.1259 +             * Bug 86941: On Tru64 UNIX V5.0A and V5.1, the close()
  1.1260 +             * system call, when called to close a TCP socket, may
  1.1261 +             * return -1 with errno set to EINVAL but the system call
  1.1262 +             * does close the socket successfully.  An application
  1.1263 +             * may safely ignore the EINVAL error.  This bug is fixed
  1.1264 +             * on Tru64 UNIX V5.1A and later.  The defect tracking
  1.1265 +             * number is QAR 81431.
  1.1266 +             */
  1.1267 +            if (PR_DESC_SOCKET_TCP != fd->methods->file_type
  1.1268 +            || EINVAL != errno)
  1.1269 +            {
  1.1270 +                pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
  1.1271 +                return PR_FAILURE;
  1.1272 +            }
  1.1273 +#else
  1.1274 +            pt_MapError(_PR_MD_MAP_CLOSE_ERROR, errno);
  1.1275 +            return PR_FAILURE;
  1.1276 +#endif
  1.1277 +        }
  1.1278 +        fd->secret->state = _PR_FILEDESC_CLOSED;
  1.1279 +    }
  1.1280 +    _PR_Putfd(fd);
  1.1281 +    return PR_SUCCESS;
  1.1282 +}  /* pt_Close */
  1.1283 +
  1.1284 +static PRInt32 pt_Read(PRFileDesc *fd, void *buf, PRInt32 amount)
  1.1285 +{
  1.1286 +    PRInt32 syserrno, bytes = -1;
  1.1287 +
  1.1288 +    if (pt_TestAbort()) return bytes;
  1.1289 +
  1.1290 +    bytes = read(fd->secret->md.osfd, buf, amount);
  1.1291 +    syserrno = errno;
  1.1292 +
  1.1293 +    if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.1294 +        && (!fd->secret->nonblocking))
  1.1295 +    {
  1.1296 +        pt_Continuation op;
  1.1297 +        op.arg1.osfd = fd->secret->md.osfd;
  1.1298 +        op.arg2.buffer = buf;
  1.1299 +        op.arg3.amount = amount;
  1.1300 +        op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1.1301 +        op.function = pt_read_cont;
  1.1302 +        op.event = POLLIN | POLLPRI;
  1.1303 +        bytes = pt_Continue(&op);
  1.1304 +        syserrno = op.syserrno;
  1.1305 +    }
  1.1306 +    if (bytes < 0)
  1.1307 +        pt_MapError(_PR_MD_MAP_READ_ERROR, syserrno);
  1.1308 +    return bytes;
  1.1309 +}  /* pt_Read */
  1.1310 +
  1.1311 +static PRInt32 pt_Write(PRFileDesc *fd, const void *buf, PRInt32 amount)
  1.1312 +{
  1.1313 +    PRInt32 syserrno, bytes = -1;
  1.1314 +    PRBool fNeedContinue = PR_FALSE;
  1.1315 +
  1.1316 +    if (pt_TestAbort()) return bytes;
  1.1317 +
  1.1318 +    bytes = write(fd->secret->md.osfd, buf, amount);
  1.1319 +    syserrno = errno;
  1.1320 +
  1.1321 +    if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1.1322 +    {
  1.1323 +        buf = (char *) buf + bytes;
  1.1324 +        amount -= bytes;
  1.1325 +        fNeedContinue = PR_TRUE;
  1.1326 +    }
  1.1327 +    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.1328 +        && (!fd->secret->nonblocking) )
  1.1329 +    {
  1.1330 +        bytes = 0;
  1.1331 +        fNeedContinue = PR_TRUE;
  1.1332 +    }
  1.1333 +
  1.1334 +    if (fNeedContinue == PR_TRUE)
  1.1335 +    {
  1.1336 +        pt_Continuation op;
  1.1337 +        op.arg1.osfd = fd->secret->md.osfd;
  1.1338 +        op.arg2.buffer = (void*)buf;
  1.1339 +        op.arg3.amount = amount;
  1.1340 +        op.timeout = PR_INTERVAL_NO_TIMEOUT;
  1.1341 +        op.result.code = bytes;  /* initialize the number sent */
  1.1342 +        op.function = pt_write_cont;
  1.1343 +        op.event = POLLOUT | POLLPRI;
  1.1344 +        bytes = pt_Continue(&op);
  1.1345 +        syserrno = op.syserrno;
  1.1346 +    }
  1.1347 +    if (bytes == -1)
  1.1348 +        pt_MapError(_PR_MD_MAP_WRITE_ERROR, syserrno);
  1.1349 +    return bytes;
  1.1350 +}  /* pt_Write */
  1.1351 +
  1.1352 +static PRInt32 pt_Writev(
  1.1353 +    PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_len, PRIntervalTime timeout)
  1.1354 +{
  1.1355 +    PRIntn iov_index;
  1.1356 +    PRBool fNeedContinue = PR_FALSE;
  1.1357 +    PRInt32 syserrno, bytes, rv = -1;
  1.1358 +    struct iovec osiov_local[PR_MAX_IOVECTOR_SIZE], *osiov;
  1.1359 +    int osiov_len;
  1.1360 +
  1.1361 +    if (pt_TestAbort()) return rv;
  1.1362 +
  1.1363 +    /* Ensured by PR_Writev */
  1.1364 +    PR_ASSERT(iov_len <= PR_MAX_IOVECTOR_SIZE);
  1.1365 +
  1.1366 +    /*
  1.1367 +     * We can't pass iov to writev because PRIOVec and struct iovec
  1.1368 +     * may not be binary compatible.  Make osiov a copy of iov and
  1.1369 +     * pass osiov to writev.  We can modify osiov if we need to
  1.1370 +     * continue the operation.
  1.1371 +     */
  1.1372 +    osiov = osiov_local;
  1.1373 +    osiov_len = iov_len;
  1.1374 +    for (iov_index = 0; iov_index < osiov_len; iov_index++)
  1.1375 +    {
  1.1376 +        osiov[iov_index].iov_base = iov[iov_index].iov_base;
  1.1377 +        osiov[iov_index].iov_len = iov[iov_index].iov_len;
  1.1378 +    }
  1.1379 +
  1.1380 +    rv = bytes = writev(fd->secret->md.osfd, osiov, osiov_len);
  1.1381 +    syserrno = errno;
  1.1382 +
  1.1383 +    if (!fd->secret->nonblocking)
  1.1384 +    {
  1.1385 +        if (bytes >= 0)
  1.1386 +        {
  1.1387 +            /*
  1.1388 +             * If we moved some bytes, how does that implicate the
  1.1389 +             * i/o vector list?  In other words, exactly where are
  1.1390 +             * we within that array?  What are the parameters for
  1.1391 +             * resumption?  Maybe we're done!
  1.1392 +             */
  1.1393 +            for ( ;osiov_len > 0; osiov++, osiov_len--)
  1.1394 +            {
  1.1395 +                if (bytes < osiov->iov_len)
  1.1396 +                {
  1.1397 +                    /* this one's not done yet */
  1.1398 +                    osiov->iov_base = (char*)osiov->iov_base + bytes;
  1.1399 +                    osiov->iov_len -= bytes;
  1.1400 +                    break;  /* go off and do that */
  1.1401 +                }
  1.1402 +                bytes -= osiov->iov_len;  /* this one's done cooked */
  1.1403 +            }
  1.1404 +            PR_ASSERT(osiov_len > 0 || bytes == 0);
  1.1405 +            if (osiov_len > 0)
  1.1406 +            {
  1.1407 +                if (PR_INTERVAL_NO_WAIT == timeout)
  1.1408 +                {
  1.1409 +                    rv = -1;
  1.1410 +                    syserrno = ETIMEDOUT;
  1.1411 +                }
  1.1412 +                else fNeedContinue = PR_TRUE;
  1.1413 +            }
  1.1414 +        }
  1.1415 +        else if (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.1416 +        {
  1.1417 +            if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.1418 +            else
  1.1419 +            {
  1.1420 +                rv = 0;
  1.1421 +                fNeedContinue = PR_TRUE;
  1.1422 +            }
  1.1423 +        }
  1.1424 +    }
  1.1425 +
  1.1426 +    if (fNeedContinue == PR_TRUE)
  1.1427 +    {
  1.1428 +        pt_Continuation op;
  1.1429 +
  1.1430 +        op.arg1.osfd = fd->secret->md.osfd;
  1.1431 +        op.arg2.buffer = (void*)osiov;
  1.1432 +        op.arg3.amount = osiov_len;
  1.1433 +        op.timeout = timeout;
  1.1434 +        op.result.code = rv;
  1.1435 +        op.function = pt_writev_cont;
  1.1436 +        op.event = POLLOUT | POLLPRI;
  1.1437 +        rv = pt_Continue(&op);
  1.1438 +        syserrno = op.syserrno;
  1.1439 +    }
  1.1440 +    if (rv == -1) pt_MapError(_PR_MD_MAP_WRITEV_ERROR, syserrno);
  1.1441 +    return rv;
  1.1442 +}  /* pt_Writev */
  1.1443 +
  1.1444 +static PRInt32 pt_Seek(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
  1.1445 +{
  1.1446 +    return _PR_MD_LSEEK(fd, offset, whence);
  1.1447 +}  /* pt_Seek */
  1.1448 +
  1.1449 +static PRInt64 pt_Seek64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
  1.1450 +{
  1.1451 +    return _PR_MD_LSEEK64(fd, offset, whence);
  1.1452 +}  /* pt_Seek64 */
  1.1453 +
  1.1454 +static PRInt32 pt_Available_f(PRFileDesc *fd)
  1.1455 +{
  1.1456 +    PRInt32 result, cur, end;
  1.1457 +
  1.1458 +    cur = _PR_MD_LSEEK(fd, 0, PR_SEEK_CUR);
  1.1459 +
  1.1460 +    if (cur >= 0)
  1.1461 +        end = _PR_MD_LSEEK(fd, 0, PR_SEEK_END);
  1.1462 +
  1.1463 +    if ((cur < 0) || (end < 0)) {
  1.1464 +        return -1;
  1.1465 +    }
  1.1466 +
  1.1467 +    result = end - cur;
  1.1468 +    _PR_MD_LSEEK(fd, cur, PR_SEEK_SET);
  1.1469 +
  1.1470 +    return result;
  1.1471 +}  /* pt_Available_f */
  1.1472 +
  1.1473 +static PRInt64 pt_Available64_f(PRFileDesc *fd)
  1.1474 +{
  1.1475 +    PRInt64 result, cur, end;
  1.1476 +    PRInt64 minus_one;
  1.1477 +
  1.1478 +    LL_I2L(minus_one, -1);
  1.1479 +    cur = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_CUR);
  1.1480 +
  1.1481 +    if (LL_GE_ZERO(cur))
  1.1482 +        end = _PR_MD_LSEEK64(fd, LL_ZERO, PR_SEEK_END);
  1.1483 +
  1.1484 +    if (!LL_GE_ZERO(cur) || !LL_GE_ZERO(end)) return minus_one;
  1.1485 +
  1.1486 +    LL_SUB(result, end, cur);
  1.1487 +    (void)_PR_MD_LSEEK64(fd, cur, PR_SEEK_SET);
  1.1488 +
  1.1489 +    return result;
  1.1490 +}  /* pt_Available64_f */
  1.1491 +
  1.1492 +static PRInt32 pt_Available_s(PRFileDesc *fd)
  1.1493 +{
  1.1494 +    PRInt32 rv, bytes = -1;
  1.1495 +    if (pt_TestAbort()) return bytes;
  1.1496 +
  1.1497 +    rv = ioctl(fd->secret->md.osfd, FIONREAD, &bytes);
  1.1498 +
  1.1499 +    if (rv == -1)
  1.1500 +        pt_MapError(_PR_MD_MAP_SOCKETAVAILABLE_ERROR, errno);
  1.1501 +    return bytes;
  1.1502 +}  /* pt_Available_s */
  1.1503 +
  1.1504 +static PRInt64 pt_Available64_s(PRFileDesc *fd)
  1.1505 +{
  1.1506 +    PRInt64 rv;
  1.1507 +    LL_I2L(rv, pt_Available_s(fd));
  1.1508 +    return rv;
  1.1509 +}  /* pt_Available64_s */
  1.1510 +
  1.1511 +static PRStatus pt_FileInfo(PRFileDesc *fd, PRFileInfo *info)
  1.1512 +{
  1.1513 +    PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, info);
  1.1514 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.1515 +}  /* pt_FileInfo */
  1.1516 +
  1.1517 +static PRStatus pt_FileInfo64(PRFileDesc *fd, PRFileInfo64 *info)
  1.1518 +{
  1.1519 +    PRInt32 rv = _PR_MD_GETOPENFILEINFO64(fd, info);
  1.1520 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.1521 +}  /* pt_FileInfo64 */
  1.1522 +
  1.1523 +static PRStatus pt_Synch(PRFileDesc *fd)
  1.1524 +{
  1.1525 +    return (NULL == fd) ? PR_FAILURE : PR_SUCCESS;
  1.1526 +} /* pt_Synch */
  1.1527 +
  1.1528 +static PRStatus pt_Fsync(PRFileDesc *fd)
  1.1529 +{
  1.1530 +    PRIntn rv = -1;
  1.1531 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1532 +
  1.1533 +    rv = fsync(fd->secret->md.osfd);
  1.1534 +    if (rv < 0) {
  1.1535 +        pt_MapError(_PR_MD_MAP_FSYNC_ERROR, errno);
  1.1536 +        return PR_FAILURE;
  1.1537 +    }
  1.1538 +    return PR_SUCCESS;
  1.1539 +}  /* pt_Fsync */
  1.1540 +
  1.1541 +static PRStatus pt_Connect(
  1.1542 +    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  1.1543 +{
  1.1544 +    PRIntn rv = -1, syserrno;
  1.1545 +    pt_SockLen addr_len;
  1.1546 +	const PRNetAddr *addrp = addr;
  1.1547 +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1.1548 +	PRUint16 md_af = addr->raw.family;
  1.1549 +    PRNetAddr addrCopy;
  1.1550 +#endif
  1.1551 +
  1.1552 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1553 +
  1.1554 +    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.1555 +    addr_len = PR_NETADDR_SIZE(addr);
  1.1556 +#if defined(_PR_INET6)
  1.1557 +	if (addr->raw.family == PR_AF_INET6) {
  1.1558 +		md_af = AF_INET6;
  1.1559 +#ifndef _PR_HAVE_SOCKADDR_LEN
  1.1560 +		addrCopy = *addr;
  1.1561 +		addrCopy.raw.family = AF_INET6;
  1.1562 +		addrp = &addrCopy;
  1.1563 +#endif
  1.1564 +	}
  1.1565 +#endif
  1.1566 +
  1.1567 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.1568 +    addrCopy = *addr;
  1.1569 +    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  1.1570 +    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  1.1571 +    addrp = &addrCopy;
  1.1572 +#endif
  1.1573 +    rv = connect(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
  1.1574 +    syserrno = errno;
  1.1575 +    if ((-1 == rv) && (EINPROGRESS == syserrno) && (!fd->secret->nonblocking))
  1.1576 +    {
  1.1577 +        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.1578 +        else
  1.1579 +        {
  1.1580 +            pt_Continuation op;
  1.1581 +            op.arg1.osfd = fd->secret->md.osfd;
  1.1582 +            op.arg2.buffer = (void*)addrp;
  1.1583 +            op.arg3.amount = addr_len;
  1.1584 +            op.timeout = timeout;
  1.1585 +            op.function = pt_connect_cont;
  1.1586 +            op.event = POLLOUT | POLLPRI;
  1.1587 +            rv = pt_Continue(&op);
  1.1588 +            syserrno = op.syserrno;
  1.1589 +        }
  1.1590 +    }
  1.1591 +    if (-1 == rv) {
  1.1592 +        pt_MapError(_PR_MD_MAP_CONNECT_ERROR, syserrno);
  1.1593 +        return PR_FAILURE;
  1.1594 +    }
  1.1595 +    return PR_SUCCESS;
  1.1596 +}  /* pt_Connect */
  1.1597 +
  1.1598 +static PRStatus pt_ConnectContinue(
  1.1599 +    PRFileDesc *fd, PRInt16 out_flags)
  1.1600 +{
  1.1601 +    int err;
  1.1602 +    PRInt32 osfd;
  1.1603 +
  1.1604 +    if (out_flags & PR_POLL_NVAL)
  1.1605 +    {
  1.1606 +        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1.1607 +        return PR_FAILURE;
  1.1608 +    }
  1.1609 +    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR
  1.1610 +        | PR_POLL_HUP)) == 0)
  1.1611 +    {
  1.1612 +        PR_ASSERT(out_flags == 0);
  1.1613 +        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
  1.1614 +        return PR_FAILURE;
  1.1615 +    }
  1.1616 +
  1.1617 +    osfd = fd->secret->md.osfd;
  1.1618 +
  1.1619 +    err = _MD_unix_get_nonblocking_connect_error(osfd);
  1.1620 +    if (err != 0)
  1.1621 +    {
  1.1622 +        _PR_MD_MAP_CONNECT_ERROR(err);
  1.1623 +        return PR_FAILURE;
  1.1624 +    }
  1.1625 +    return PR_SUCCESS;
  1.1626 +}  /* pt_ConnectContinue */
  1.1627 +
  1.1628 +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
  1.1629 +{
  1.1630 +    /* Find the NSPR layer and invoke its connectcontinue method */
  1.1631 +    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
  1.1632 +
  1.1633 +    if (NULL == bottom)
  1.1634 +    {
  1.1635 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1636 +        return PR_FAILURE;
  1.1637 +    }
  1.1638 +    return pt_ConnectContinue(bottom, pd->out_flags);
  1.1639 +}  /* PR_GetConnectStatus */
  1.1640 +
  1.1641 +static PRFileDesc* pt_Accept(
  1.1642 +    PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
  1.1643 +{
  1.1644 +    PRFileDesc *newfd = NULL;
  1.1645 +    PRIntn syserrno, osfd = -1;
  1.1646 +    pt_SockLen addr_len = sizeof(PRNetAddr);
  1.1647 +#ifdef SYMBIAN
  1.1648 +    PRNetAddr dummy_addr;
  1.1649 +#endif
  1.1650 +
  1.1651 +    if (pt_TestAbort()) return newfd;
  1.1652 +
  1.1653 +#ifdef SYMBIAN
  1.1654 +    /* On Symbian OS, accept crashes if addr is NULL. */
  1.1655 +    if (!addr)
  1.1656 +        addr = &dummy_addr;
  1.1657 +#endif
  1.1658 +
  1.1659 +#ifdef _PR_STRICT_ADDR_LEN
  1.1660 +    if (addr)
  1.1661 +    {
  1.1662 +        /*
  1.1663 +         * Set addr->raw.family just so that we can use the
  1.1664 +         * PR_NETADDR_SIZE macro.
  1.1665 +         */
  1.1666 +        addr->raw.family = fd->secret->af;
  1.1667 +        addr_len = PR_NETADDR_SIZE(addr);
  1.1668 +    }
  1.1669 +#endif
  1.1670 +
  1.1671 +    osfd = accept(fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1.1672 +    syserrno = errno;
  1.1673 +
  1.1674 +    if (osfd == -1)
  1.1675 +    {
  1.1676 +        if (fd->secret->nonblocking) goto failed;
  1.1677 +
  1.1678 +        if (EWOULDBLOCK != syserrno && EAGAIN != syserrno
  1.1679 +        && ECONNABORTED != syserrno)
  1.1680 +            goto failed;
  1.1681 +        else
  1.1682 +        {
  1.1683 +            if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.1684 +            else
  1.1685 +            {
  1.1686 +                pt_Continuation op;
  1.1687 +                op.arg1.osfd = fd->secret->md.osfd;
  1.1688 +                op.arg2.buffer = addr;
  1.1689 +                op.arg3.addr_len = &addr_len;
  1.1690 +                op.timeout = timeout;
  1.1691 +                op.function = pt_accept_cont;
  1.1692 +                op.event = POLLIN | POLLPRI;
  1.1693 +                osfd = pt_Continue(&op);
  1.1694 +                syserrno = op.syserrno;
  1.1695 +            }
  1.1696 +            if (osfd < 0) goto failed;
  1.1697 +        }
  1.1698 +    }
  1.1699 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.1700 +    /* ignore the sa_len field of struct sockaddr */
  1.1701 +    if (addr)
  1.1702 +    {
  1.1703 +        addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  1.1704 +    }
  1.1705 +#endif /* _PR_HAVE_SOCKADDR_LEN */
  1.1706 +#ifdef _PR_INET6
  1.1707 +	if (addr && (AF_INET6 == addr->raw.family))
  1.1708 +        addr->raw.family = PR_AF_INET6;
  1.1709 +#endif
  1.1710 +    newfd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_TRUE, PR_FALSE);
  1.1711 +    if (newfd == NULL) close(osfd);  /* $$$ whoops! this doesn't work $$$ */
  1.1712 +    else
  1.1713 +    {
  1.1714 +        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.1715 +        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  1.1716 +#ifdef LINUX
  1.1717 +        /*
  1.1718 +         * On Linux, experiments showed that the accepted sockets
  1.1719 +         * inherit the TCP_NODELAY socket option of the listening
  1.1720 +         * socket.
  1.1721 +         */
  1.1722 +        newfd->secret->md.tcp_nodelay = fd->secret->md.tcp_nodelay;
  1.1723 +#endif
  1.1724 +    }
  1.1725 +    return newfd;
  1.1726 +
  1.1727 +failed:
  1.1728 +    pt_MapError(_PR_MD_MAP_ACCEPT_ERROR, syserrno);
  1.1729 +    return NULL;
  1.1730 +}  /* pt_Accept */
  1.1731 +
  1.1732 +static PRStatus pt_Bind(PRFileDesc *fd, const PRNetAddr *addr)
  1.1733 +{
  1.1734 +    PRIntn rv;
  1.1735 +    pt_SockLen addr_len;
  1.1736 +	const PRNetAddr *addrp = addr;
  1.1737 +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1.1738 +	PRUint16 md_af = addr->raw.family;
  1.1739 +    PRNetAddr addrCopy;
  1.1740 +#endif
  1.1741 +
  1.1742 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1743 +
  1.1744 +    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.1745 +    if (addr->raw.family == AF_UNIX)
  1.1746 +    {
  1.1747 +        /* Disallow relative pathnames */
  1.1748 +        if (addr->local.path[0] != '/')
  1.1749 +        {
  1.1750 +            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1751 +            return PR_FAILURE;
  1.1752 +        }
  1.1753 +    }
  1.1754 +
  1.1755 +#if defined(_PR_INET6)
  1.1756 +	if (addr->raw.family == PR_AF_INET6) {
  1.1757 +		md_af = AF_INET6;
  1.1758 +#ifndef _PR_HAVE_SOCKADDR_LEN
  1.1759 +		addrCopy = *addr;
  1.1760 +		addrCopy.raw.family = AF_INET6;
  1.1761 +		addrp = &addrCopy;
  1.1762 +#endif
  1.1763 +	}
  1.1764 +#endif
  1.1765 +
  1.1766 +    addr_len = PR_NETADDR_SIZE(addr);
  1.1767 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.1768 +    addrCopy = *addr;
  1.1769 +    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  1.1770 +    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  1.1771 +    addrp = &addrCopy;
  1.1772 +#endif
  1.1773 +    rv = bind(fd->secret->md.osfd, (struct sockaddr*)addrp, addr_len);
  1.1774 +
  1.1775 +    if (rv == -1) {
  1.1776 +        pt_MapError(_PR_MD_MAP_BIND_ERROR, errno);
  1.1777 +        return PR_FAILURE;
  1.1778 +    }
  1.1779 +    return PR_SUCCESS;
  1.1780 +}  /* pt_Bind */
  1.1781 +
  1.1782 +static PRStatus pt_Listen(PRFileDesc *fd, PRIntn backlog)
  1.1783 +{
  1.1784 +    PRIntn rv;
  1.1785 +
  1.1786 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1787 +
  1.1788 +    rv = listen(fd->secret->md.osfd, backlog);
  1.1789 +    if (rv == -1) {
  1.1790 +        pt_MapError(_PR_MD_MAP_LISTEN_ERROR, errno);
  1.1791 +        return PR_FAILURE;
  1.1792 +    }
  1.1793 +    return PR_SUCCESS;
  1.1794 +}  /* pt_Listen */
  1.1795 +
  1.1796 +static PRStatus pt_Shutdown(PRFileDesc *fd, PRIntn how)
  1.1797 +{
  1.1798 +    PRIntn rv = -1;
  1.1799 +    if (pt_TestAbort()) return PR_FAILURE;
  1.1800 +
  1.1801 +    rv = shutdown(fd->secret->md.osfd, how);
  1.1802 +
  1.1803 +    if (rv == -1) {
  1.1804 +        pt_MapError(_PR_MD_MAP_SHUTDOWN_ERROR, errno);
  1.1805 +        return PR_FAILURE;
  1.1806 +    }
  1.1807 +    return PR_SUCCESS;
  1.1808 +}  /* pt_Shutdown */
  1.1809 +
  1.1810 +static PRInt16 pt_Poll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  1.1811 +{
  1.1812 +    *out_flags = 0;
  1.1813 +    return in_flags;
  1.1814 +}  /* pt_Poll */
  1.1815 +
  1.1816 +static PRInt32 pt_Recv(
  1.1817 +    PRFileDesc *fd, void *buf, PRInt32 amount,
  1.1818 +    PRIntn flags, PRIntervalTime timeout)
  1.1819 +{
  1.1820 +    PRInt32 syserrno, bytes = -1;
  1.1821 +    PRIntn osflags;
  1.1822 +
  1.1823 +    if (0 == flags)
  1.1824 +        osflags = 0;
  1.1825 +    else if (PR_MSG_PEEK == flags)
  1.1826 +    {
  1.1827 +#ifdef SYMBIAN
  1.1828 +        /* MSG_PEEK doesn't work as expected. */
  1.1829 +        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.1830 +        return bytes;
  1.1831 +#else
  1.1832 +        osflags = MSG_PEEK;
  1.1833 +#endif
  1.1834 +    }
  1.1835 +    else
  1.1836 +    {
  1.1837 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1838 +        return bytes;
  1.1839 +    }
  1.1840 +
  1.1841 +    if (pt_TestAbort()) return bytes;
  1.1842 +
  1.1843 +    /* recv() is a much slower call on pre-2.6 Solaris than read(). */
  1.1844 +#if defined(SOLARIS)
  1.1845 +    if (0 == osflags)
  1.1846 +        bytes = read(fd->secret->md.osfd, buf, amount);
  1.1847 +    else
  1.1848 +        bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
  1.1849 +#else
  1.1850 +    bytes = recv(fd->secret->md.osfd, buf, amount, osflags);
  1.1851 +#endif
  1.1852 +    syserrno = errno;
  1.1853 +
  1.1854 +    if ((bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.1855 +        && (!fd->secret->nonblocking))
  1.1856 +    {
  1.1857 +        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.1858 +        else
  1.1859 +        {
  1.1860 +            pt_Continuation op;
  1.1861 +            op.arg1.osfd = fd->secret->md.osfd;
  1.1862 +            op.arg2.buffer = buf;
  1.1863 +            op.arg3.amount = amount;
  1.1864 +            op.arg4.flags = osflags;
  1.1865 +            op.timeout = timeout;
  1.1866 +            op.function = pt_recv_cont;
  1.1867 +            op.event = POLLIN | POLLPRI;
  1.1868 +            bytes = pt_Continue(&op);
  1.1869 +            syserrno = op.syserrno;
  1.1870 +        }
  1.1871 +    }
  1.1872 +    if (bytes < 0)
  1.1873 +        pt_MapError(_PR_MD_MAP_RECV_ERROR, syserrno);
  1.1874 +    return bytes;
  1.1875 +}  /* pt_Recv */
  1.1876 +
  1.1877 +static PRInt32 pt_SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
  1.1878 +{
  1.1879 +    return pt_Recv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1.1880 +}  /* pt_SocketRead */
  1.1881 +
  1.1882 +static PRInt32 pt_Send(
  1.1883 +    PRFileDesc *fd, const void *buf, PRInt32 amount,
  1.1884 +    PRIntn flags, PRIntervalTime timeout)
  1.1885 +{
  1.1886 +    PRInt32 syserrno, bytes = -1;
  1.1887 +    PRBool fNeedContinue = PR_FALSE;
  1.1888 +#if defined(SOLARIS)
  1.1889 +	PRInt32 tmp_amount = amount;
  1.1890 +#endif
  1.1891 +
  1.1892 +    /*
  1.1893 +     * Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
  1.1894 +     * which has the following:
  1.1895 +     *     #  define send        cma_send
  1.1896 +     *     extern int  cma_send (int , void *, int, int );
  1.1897 +     * So we need to cast away the 'const' of argument #2 for send().
  1.1898 +     */
  1.1899 +#if defined (HPUX) && defined(_PR_DCETHREADS)
  1.1900 +#define PT_SENDBUF_CAST (void *)
  1.1901 +#else
  1.1902 +#define PT_SENDBUF_CAST
  1.1903 +#endif
  1.1904 +
  1.1905 +    if (pt_TestAbort()) return bytes;
  1.1906 +
  1.1907 +    /*
  1.1908 +     * On pre-2.6 Solaris, send() is much slower than write().
  1.1909 +     * On 2.6 and beyond, with in-kernel sockets, send() and
  1.1910 +     * write() are fairly equivalent in performance.
  1.1911 +     */
  1.1912 +#if defined(SOLARIS)
  1.1913 +    PR_ASSERT(0 == flags);
  1.1914 +retry:
  1.1915 +    bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
  1.1916 +#else
  1.1917 +    bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
  1.1918 +#endif
  1.1919 +    syserrno = errno;
  1.1920 +
  1.1921 +#if defined(SOLARIS)
  1.1922 +    /*
  1.1923 +     * The write system call has been reported to return the ERANGE error
  1.1924 +     * on occasion. Try to write in smaller chunks to workaround this bug.
  1.1925 +     */
  1.1926 +    if ((bytes == -1) && (syserrno == ERANGE))
  1.1927 +    {
  1.1928 +        if (tmp_amount > 1)
  1.1929 +        {
  1.1930 +            tmp_amount = tmp_amount/2;  /* half the bytes */
  1.1931 +            goto retry;
  1.1932 +        }
  1.1933 +    }
  1.1934 +#endif
  1.1935 +
  1.1936 +    if ( (bytes >= 0) && (bytes < amount) && (!fd->secret->nonblocking) )
  1.1937 +    {
  1.1938 +        if (PR_INTERVAL_NO_WAIT == timeout)
  1.1939 +        {
  1.1940 +            bytes = -1;
  1.1941 +            syserrno = ETIMEDOUT;
  1.1942 +        }
  1.1943 +        else
  1.1944 +        {
  1.1945 +            buf = (char *) buf + bytes;
  1.1946 +            amount -= bytes;
  1.1947 +            fNeedContinue = PR_TRUE;
  1.1948 +        }
  1.1949 +    }
  1.1950 +    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.1951 +        && (!fd->secret->nonblocking) )
  1.1952 +    {
  1.1953 +        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.1954 +        else
  1.1955 +        {
  1.1956 +            bytes = 0;
  1.1957 +            fNeedContinue = PR_TRUE;
  1.1958 +        }
  1.1959 +    }
  1.1960 +
  1.1961 +    if (fNeedContinue == PR_TRUE)
  1.1962 +    {
  1.1963 +        pt_Continuation op;
  1.1964 +        op.arg1.osfd = fd->secret->md.osfd;
  1.1965 +        op.arg2.buffer = (void*)buf;
  1.1966 +        op.arg3.amount = amount;
  1.1967 +        op.arg4.flags = flags;
  1.1968 +        op.timeout = timeout;
  1.1969 +        op.result.code = bytes;  /* initialize the number sent */
  1.1970 +        op.function = pt_send_cont;
  1.1971 +        op.event = POLLOUT | POLLPRI;
  1.1972 +        bytes = pt_Continue(&op);
  1.1973 +        syserrno = op.syserrno;
  1.1974 +    }
  1.1975 +    if (bytes == -1)
  1.1976 +        pt_MapError(_PR_MD_MAP_SEND_ERROR, syserrno);
  1.1977 +    return bytes;
  1.1978 +}  /* pt_Send */
  1.1979 +
  1.1980 +static PRInt32 pt_SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
  1.1981 +{
  1.1982 +    return pt_Send(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  1.1983 +}  /* pt_SocketWrite */
  1.1984 +
  1.1985 +static PRInt32 pt_SendTo(
  1.1986 +    PRFileDesc *fd, const void *buf,
  1.1987 +    PRInt32 amount, PRIntn flags, const PRNetAddr *addr,
  1.1988 +    PRIntervalTime timeout)
  1.1989 +{
  1.1990 +    PRInt32 syserrno, bytes = -1;
  1.1991 +    PRBool fNeedContinue = PR_FALSE;
  1.1992 +    pt_SockLen addr_len;
  1.1993 +	const PRNetAddr *addrp = addr;
  1.1994 +#if defined(_PR_HAVE_SOCKADDR_LEN) || defined(_PR_INET6)
  1.1995 +	PRUint16 md_af = addr->raw.family;
  1.1996 +    PRNetAddr addrCopy;
  1.1997 +#endif
  1.1998 +
  1.1999 +    if (pt_TestAbort()) return bytes;
  1.2000 +
  1.2001 +    PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.2002 +#if defined(_PR_INET6)
  1.2003 +	if (addr->raw.family == PR_AF_INET6) {
  1.2004 +		md_af = AF_INET6;
  1.2005 +#ifndef _PR_HAVE_SOCKADDR_LEN
  1.2006 +		addrCopy = *addr;
  1.2007 +		addrCopy.raw.family = AF_INET6;
  1.2008 +		addrp = &addrCopy;
  1.2009 +#endif
  1.2010 +	}
  1.2011 +#endif
  1.2012 +
  1.2013 +    addr_len = PR_NETADDR_SIZE(addr);
  1.2014 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.2015 +    addrCopy = *addr;
  1.2016 +    ((struct sockaddr*)&addrCopy)->sa_len = addr_len;
  1.2017 +    ((struct sockaddr*)&addrCopy)->sa_family = md_af;
  1.2018 +    addrp = &addrCopy;
  1.2019 +#endif
  1.2020 +    bytes = sendto(
  1.2021 +        fd->secret->md.osfd, buf, amount, flags,
  1.2022 +        (struct sockaddr*)addrp, addr_len);
  1.2023 +    syserrno = errno;
  1.2024 +    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.2025 +        && (!fd->secret->nonblocking) )
  1.2026 +    {
  1.2027 +        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.2028 +        else fNeedContinue = PR_TRUE;
  1.2029 +    }
  1.2030 +    if (fNeedContinue == PR_TRUE)
  1.2031 +    {
  1.2032 +        pt_Continuation op;
  1.2033 +        op.arg1.osfd = fd->secret->md.osfd;
  1.2034 +        op.arg2.buffer = (void*)buf;
  1.2035 +        op.arg3.amount = amount;
  1.2036 +        op.arg4.flags = flags;
  1.2037 +        op.arg5.addr = (PRNetAddr*)addrp;
  1.2038 +        op.timeout = timeout;
  1.2039 +        op.result.code = 0;  /* initialize the number sent */
  1.2040 +        op.function = pt_sendto_cont;
  1.2041 +        op.event = POLLOUT | POLLPRI;
  1.2042 +        bytes = pt_Continue(&op);
  1.2043 +        syserrno = op.syserrno;
  1.2044 +    }
  1.2045 +    if (bytes < 0)
  1.2046 +        pt_MapError(_PR_MD_MAP_SENDTO_ERROR, syserrno);
  1.2047 +    return bytes;
  1.2048 +}  /* pt_SendTo */
  1.2049 +
  1.2050 +static PRInt32 pt_RecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
  1.2051 +    PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
  1.2052 +{
  1.2053 +    PRBool fNeedContinue = PR_FALSE;
  1.2054 +    PRInt32 syserrno, bytes = -1;
  1.2055 +    pt_SockLen addr_len = sizeof(PRNetAddr);
  1.2056 +
  1.2057 +    if (pt_TestAbort()) return bytes;
  1.2058 +
  1.2059 +    bytes = recvfrom(
  1.2060 +        fd->secret->md.osfd, buf, amount, flags,
  1.2061 +        (struct sockaddr*)addr, &addr_len);
  1.2062 +    syserrno = errno;
  1.2063 +
  1.2064 +    if ( (bytes == -1) && (syserrno == EWOULDBLOCK || syserrno == EAGAIN)
  1.2065 +        && (!fd->secret->nonblocking) )
  1.2066 +    {
  1.2067 +        if (PR_INTERVAL_NO_WAIT == timeout) syserrno = ETIMEDOUT;
  1.2068 +        else fNeedContinue = PR_TRUE;
  1.2069 +    }
  1.2070 +
  1.2071 +    if (fNeedContinue == PR_TRUE)
  1.2072 +    {
  1.2073 +        pt_Continuation op;
  1.2074 +        op.arg1.osfd = fd->secret->md.osfd;
  1.2075 +        op.arg2.buffer = buf;
  1.2076 +        op.arg3.amount = amount;
  1.2077 +        op.arg4.flags = flags;
  1.2078 +        op.arg5.addr = addr;
  1.2079 +        op.timeout = timeout;
  1.2080 +        op.function = pt_recvfrom_cont;
  1.2081 +        op.event = POLLIN | POLLPRI;
  1.2082 +        bytes = pt_Continue(&op);
  1.2083 +        syserrno = op.syserrno;
  1.2084 +    }
  1.2085 +    if (bytes >= 0)
  1.2086 +    {
  1.2087 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.2088 +        /* ignore the sa_len field of struct sockaddr */
  1.2089 +        if (addr)
  1.2090 +        {
  1.2091 +            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  1.2092 +        }
  1.2093 +#endif /* _PR_HAVE_SOCKADDR_LEN */
  1.2094 +#ifdef _PR_INET6
  1.2095 +        if (addr && (AF_INET6 == addr->raw.family))
  1.2096 +            addr->raw.family = PR_AF_INET6;
  1.2097 +#endif
  1.2098 +    }
  1.2099 +    else
  1.2100 +        pt_MapError(_PR_MD_MAP_RECVFROM_ERROR, syserrno);
  1.2101 +    return bytes;
  1.2102 +}  /* pt_RecvFrom */
  1.2103 +
  1.2104 +#ifdef AIX
  1.2105 +#ifndef HAVE_SEND_FILE
  1.2106 +static pthread_once_t pt_aix_sendfile_once_block = PTHREAD_ONCE_INIT;
  1.2107 +
  1.2108 +static void pt_aix_sendfile_init_routine(void)
  1.2109 +{
  1.2110 +    void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
  1.2111 +    pt_aix_sendfile_fptr = (ssize_t (*)()) dlsym(handle, "send_file");
  1.2112 +    dlclose(handle);
  1.2113 +}
  1.2114 +
  1.2115 +/* 
  1.2116 + * pt_AIXDispatchSendFile
  1.2117 + */
  1.2118 +static PRInt32 pt_AIXDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  1.2119 +	  PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2120 +{
  1.2121 +    int rv;
  1.2122 +
  1.2123 +    rv = pthread_once(&pt_aix_sendfile_once_block,
  1.2124 +            pt_aix_sendfile_init_routine);
  1.2125 +    PR_ASSERT(0 == rv);
  1.2126 +    if (pt_aix_sendfile_fptr) {
  1.2127 +        return pt_AIXSendFile(sd, sfd, flags, timeout);
  1.2128 +    } else {
  1.2129 +        return PR_EmulateSendFile(sd, sfd, flags, timeout);
  1.2130 +    }
  1.2131 +}
  1.2132 +#endif /* !HAVE_SEND_FILE */
  1.2133 +
  1.2134 +
  1.2135 +/*
  1.2136 + * pt_AIXSendFile
  1.2137 + *
  1.2138 + *    Send file sfd->fd across socket sd. If specified, header and trailer
  1.2139 + *    buffers are sent before and after the file, respectively. 
  1.2140 + *
  1.2141 + *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1.2142 + *    
  1.2143 + *    return number of bytes sent or -1 on error
  1.2144 + *
  1.2145 + *      This implementation takes advantage of the send_file() system
  1.2146 + *      call available in AIX 4.3.2.
  1.2147 + */
  1.2148 +
  1.2149 +static PRInt32 pt_AIXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
  1.2150 +		PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2151 +{
  1.2152 +    struct sf_parms sf_struct;
  1.2153 +    uint_t send_flags;
  1.2154 +    ssize_t rv;
  1.2155 +    int syserrno;
  1.2156 +    PRInt32 count;
  1.2157 +	unsigned long long saved_file_offset;
  1.2158 +	long long saved_file_bytes;
  1.2159 +
  1.2160 +    sf_struct.header_data = (void *) sfd->header;  /* cast away the 'const' */
  1.2161 +    sf_struct.header_length = sfd->hlen;
  1.2162 +    sf_struct.file_descriptor = sfd->fd->secret->md.osfd;
  1.2163 +    sf_struct.file_size = 0;
  1.2164 +    sf_struct.file_offset = sfd->file_offset;
  1.2165 +    if (sfd->file_nbytes == 0)
  1.2166 +    	sf_struct.file_bytes = -1;
  1.2167 +	else
  1.2168 +    	sf_struct.file_bytes = sfd->file_nbytes;
  1.2169 +    sf_struct.trailer_data = (void *) sfd->trailer;
  1.2170 +    sf_struct.trailer_length = sfd->tlen;
  1.2171 +    sf_struct.bytes_sent = 0;
  1.2172 +
  1.2173 +	saved_file_offset = sf_struct.file_offset;
  1.2174 +    saved_file_bytes = sf_struct.file_bytes;
  1.2175 +
  1.2176 +    send_flags = 0;			/* flags processed at the end */
  1.2177 +
  1.2178 +    /* The first argument to send_file() is int*. */
  1.2179 +    PR_ASSERT(sizeof(int) == sizeof(sd->secret->md.osfd));
  1.2180 +    do {
  1.2181 +        rv = AIX_SEND_FILE(&sd->secret->md.osfd, &sf_struct, send_flags);
  1.2182 +    } while (rv == -1 && (syserrno = errno) == EINTR);
  1.2183 +
  1.2184 +    if (rv == -1) {
  1.2185 +        if (syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
  1.2186 +            count = 0; /* Not a real error.  Need to continue. */
  1.2187 +        } else {
  1.2188 +            count = -1;
  1.2189 +        }
  1.2190 +    } else {
  1.2191 +        count = sf_struct.bytes_sent;
  1.2192 +		/*
  1.2193 +		 * A bug in AIX 4.3.2 prevents the 'file_bytes' field from
  1.2194 +		 * being updated. So, 'file_bytes' is maintained by NSPR to
  1.2195 +		 * avoid conflict when this bug is fixed in AIX, in the future.
  1.2196 +		 */
  1.2197 +		if (saved_file_bytes != -1)
  1.2198 +			saved_file_bytes -= (sf_struct.file_offset - saved_file_offset);
  1.2199 +		sf_struct.file_bytes = saved_file_bytes;
  1.2200 +    }
  1.2201 +
  1.2202 +    if ((rv == 1) || ((rv == -1) && (count == 0))) {
  1.2203 +        pt_Continuation op;
  1.2204 +
  1.2205 +        op.arg1.osfd = sd->secret->md.osfd;
  1.2206 +        op.arg2.buffer = &sf_struct;
  1.2207 +        op.arg4.flags = send_flags;
  1.2208 +        op.result.code = count;
  1.2209 +        op.timeout = timeout;
  1.2210 +        op.function = pt_aix_sendfile_cont;
  1.2211 +        op.event = POLLOUT | POLLPRI;
  1.2212 +        count = pt_Continue(&op);
  1.2213 +        syserrno = op.syserrno;
  1.2214 +    }
  1.2215 +
  1.2216 +    if (count == -1) {
  1.2217 +        pt_MapError(_MD_aix_map_sendfile_error, syserrno);
  1.2218 +        return -1;
  1.2219 +    }
  1.2220 +    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  1.2221 +        PR_Close(sd);
  1.2222 +    }
  1.2223 +	PR_ASSERT(count == (sfd->hlen + sfd->tlen +
  1.2224 +						((sfd->file_nbytes ==  0) ?
  1.2225 +						sf_struct.file_size - sfd->file_offset :
  1.2226 +						sfd->file_nbytes)));
  1.2227 +    return count;
  1.2228 +}
  1.2229 +#endif /* AIX */
  1.2230 +
  1.2231 +#ifdef HPUX11
  1.2232 +/*
  1.2233 + * pt_HPUXSendFile
  1.2234 + *
  1.2235 + *    Send file sfd->fd across socket sd. If specified, header and trailer
  1.2236 + *    buffers are sent before and after the file, respectively.
  1.2237 + *
  1.2238 + *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1.2239 + *    
  1.2240 + *    return number of bytes sent or -1 on error
  1.2241 + *
  1.2242 + *      This implementation takes advantage of the sendfile() system
  1.2243 + *      call available in HP-UX B.11.00.
  1.2244 + */
  1.2245 +
  1.2246 +static PRInt32 pt_HPUXSendFile(PRFileDesc *sd, PRSendFileData *sfd, 
  1.2247 +		PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2248 +{
  1.2249 +    struct stat statbuf;
  1.2250 +    size_t nbytes_to_send, file_nbytes_to_send;
  1.2251 +    struct iovec hdtrl[2];  /* optional header and trailer buffers */
  1.2252 +    int send_flags;
  1.2253 +    PRInt32 count;
  1.2254 +    int syserrno;
  1.2255 +
  1.2256 +    if (sfd->file_nbytes == 0) {
  1.2257 +        /* Get file size */
  1.2258 +        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  1.2259 +            _PR_MD_MAP_FSTAT_ERROR(errno);
  1.2260 +            return -1;
  1.2261 +        } 		
  1.2262 +        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  1.2263 +    } else {
  1.2264 +        file_nbytes_to_send = sfd->file_nbytes;
  1.2265 +    }
  1.2266 +    nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
  1.2267 +
  1.2268 +    hdtrl[0].iov_base = (void *) sfd->header;  /* cast away the 'const' */
  1.2269 +    hdtrl[0].iov_len = sfd->hlen;
  1.2270 +    hdtrl[1].iov_base = (void *) sfd->trailer;
  1.2271 +    hdtrl[1].iov_len = sfd->tlen;
  1.2272 +    /*
  1.2273 +     * SF_DISCONNECT seems to close the socket even if sendfile()
  1.2274 +     * only does a partial send on a nonblocking socket.  This
  1.2275 +     * would prevent the subsequent sendfile() calls on that socket
  1.2276 +     * from working.  So we don't use the SD_DISCONNECT flag.
  1.2277 +     */
  1.2278 +    send_flags = 0;
  1.2279 +
  1.2280 +    do {
  1.2281 +        count = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
  1.2282 +                sfd->file_offset, file_nbytes_to_send, hdtrl, send_flags);
  1.2283 +    } while (count == -1 && (syserrno = errno) == EINTR);
  1.2284 +
  1.2285 +    if (count == -1 && (syserrno == EAGAIN || syserrno == EWOULDBLOCK)) {
  1.2286 +        count = 0;
  1.2287 +    }
  1.2288 +    if (count != -1 && count < nbytes_to_send) {
  1.2289 +        pt_Continuation op;
  1.2290 +
  1.2291 +        if (count < sfd->hlen) {
  1.2292 +			/* header not sent */
  1.2293 +
  1.2294 +            hdtrl[0].iov_base = ((char *) sfd->header) + count;
  1.2295 +            hdtrl[0].iov_len = sfd->hlen - count;
  1.2296 +            op.arg3.file_spec.offset = sfd->file_offset;
  1.2297 +            op.arg3.file_spec.nbytes = file_nbytes_to_send;
  1.2298 +        } else if (count < (sfd->hlen + file_nbytes_to_send)) {
  1.2299 +			/* header sent, file not sent */
  1.2300 +
  1.2301 +            hdtrl[0].iov_base = NULL;
  1.2302 +            hdtrl[0].iov_len = 0;
  1.2303 +
  1.2304 +            op.arg3.file_spec.offset = sfd->file_offset + count - sfd->hlen;
  1.2305 +            op.arg3.file_spec.nbytes = file_nbytes_to_send - (count - sfd->hlen);
  1.2306 +        } else if (count < (sfd->hlen + file_nbytes_to_send + sfd->tlen)) {
  1.2307 +			PRUint32 trailer_nbytes_sent;
  1.2308 +
  1.2309 +			/* header sent, file sent, trailer not sent */
  1.2310 +
  1.2311 +            hdtrl[0].iov_base = NULL;
  1.2312 +            hdtrl[0].iov_len = 0;
  1.2313 +			/*
  1.2314 +			 * set file offset and len so that no more file data is
  1.2315 +			 * sent
  1.2316 +			 */
  1.2317 +            op.arg3.file_spec.offset = statbuf.st_size;
  1.2318 +            op.arg3.file_spec.nbytes = 0;
  1.2319 +
  1.2320 +			trailer_nbytes_sent = count - sfd->hlen - file_nbytes_to_send;
  1.2321 +            hdtrl[1].iov_base = ((char *) sfd->trailer) + trailer_nbytes_sent;
  1.2322 +            hdtrl[1].iov_len = sfd->tlen - trailer_nbytes_sent;
  1.2323 +		}
  1.2324 +
  1.2325 +        op.arg1.osfd = sd->secret->md.osfd;
  1.2326 +        op.filedesc = sfd->fd->secret->md.osfd;
  1.2327 +        op.arg2.buffer = hdtrl;
  1.2328 +        op.arg3.file_spec.st_size = statbuf.st_size;
  1.2329 +        op.arg4.flags = send_flags;
  1.2330 +        op.nbytes_to_send = nbytes_to_send - count;
  1.2331 +        op.result.code = count;
  1.2332 +        op.timeout = timeout;
  1.2333 +        op.function = pt_hpux_sendfile_cont;
  1.2334 +        op.event = POLLOUT | POLLPRI;
  1.2335 +        count = pt_Continue(&op);
  1.2336 +        syserrno = op.syserrno;
  1.2337 +    }
  1.2338 +
  1.2339 +    if (count == -1) {
  1.2340 +        pt_MapError(_MD_hpux_map_sendfile_error, syserrno);
  1.2341 +        return -1;
  1.2342 +    }
  1.2343 +    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  1.2344 +        PR_Close(sd);
  1.2345 +    }
  1.2346 +    PR_ASSERT(count == nbytes_to_send);
  1.2347 +    return count;
  1.2348 +}
  1.2349 +
  1.2350 +#endif  /* HPUX11 */
  1.2351 +
  1.2352 +#ifdef SOLARIS 
  1.2353 +
  1.2354 +/*
  1.2355 + *    pt_SolarisSendFile
  1.2356 + *
  1.2357 + *    Send file sfd->fd across socket sd. If specified, header and trailer
  1.2358 + *    buffers are sent before and after the file, respectively.
  1.2359 + *
  1.2360 + *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1.2361 + *
  1.2362 + *    return number of bytes sent or -1 on error
  1.2363 + *
  1.2364 + *    This implementation takes advantage of the sendfilev() system
  1.2365 + *    call available in Solaris 8.
  1.2366 + */
  1.2367 +
  1.2368 +static PRInt32 pt_SolarisSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  1.2369 +                PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2370 +{
  1.2371 +    struct stat statbuf;
  1.2372 +    size_t nbytes_to_send, file_nbytes_to_send;	
  1.2373 +    struct sendfilevec sfv_struct[3];  
  1.2374 +    int sfvcnt = 0;	
  1.2375 +    size_t xferred;
  1.2376 +    PRInt32 count;
  1.2377 +    int syserrno;
  1.2378 +
  1.2379 +    if (sfd->file_nbytes == 0) {
  1.2380 +        /* Get file size */
  1.2381 +        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  1.2382 +            _PR_MD_MAP_FSTAT_ERROR(errno);
  1.2383 +            return -1;
  1.2384 +        } 		
  1.2385 +        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  1.2386 +    } else {
  1.2387 +        file_nbytes_to_send = sfd->file_nbytes;
  1.2388 +    }
  1.2389 +
  1.2390 +    nbytes_to_send = sfd->hlen + sfd->tlen + file_nbytes_to_send;
  1.2391 +
  1.2392 +    if (sfd->hlen != 0) {
  1.2393 +        sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
  1.2394 +        sfv_struct[sfvcnt].sfv_flag = 0;
  1.2395 +        sfv_struct[sfvcnt].sfv_off = (off_t) sfd->header; 
  1.2396 +        sfv_struct[sfvcnt].sfv_len = sfd->hlen;
  1.2397 +        sfvcnt++;
  1.2398 +    }
  1.2399 +
  1.2400 +    if (file_nbytes_to_send != 0) {
  1.2401 +        sfv_struct[sfvcnt].sfv_fd = sfd->fd->secret->md.osfd;
  1.2402 +        sfv_struct[sfvcnt].sfv_flag = 0;
  1.2403 +        sfv_struct[sfvcnt].sfv_off = sfd->file_offset;
  1.2404 +        sfv_struct[sfvcnt].sfv_len = file_nbytes_to_send;
  1.2405 +        sfvcnt++;
  1.2406 +    }
  1.2407 +
  1.2408 +    if (sfd->tlen != 0) {
  1.2409 +        sfv_struct[sfvcnt].sfv_fd = SFV_FD_SELF;
  1.2410 +        sfv_struct[sfvcnt].sfv_flag = 0;
  1.2411 +        sfv_struct[sfvcnt].sfv_off = (off_t) sfd->trailer; 
  1.2412 +        sfv_struct[sfvcnt].sfv_len = sfd->tlen;
  1.2413 +        sfvcnt++;
  1.2414 +    }
  1.2415 +
  1.2416 +    if (0 == sfvcnt) {
  1.2417 +        count = 0;
  1.2418 +        goto done;
  1.2419 +    }
  1.2420 +   	   
  1.2421 +    /*
  1.2422 +     * Strictly speaking, we may have sent some bytes when the
  1.2423 +     * sendfilev() is interrupted and we should retry it from an
  1.2424 +     * updated offset.  We are not doing that here.
  1.2425 +     */
  1.2426 +    count = SOLARIS_SENDFILEV(sd->secret->md.osfd, sfv_struct,
  1.2427 +            sfvcnt, &xferred);
  1.2428 +
  1.2429 +    PR_ASSERT((count == -1) || (count == xferred));
  1.2430 +
  1.2431 +    if (count == -1) {
  1.2432 +        syserrno = errno;
  1.2433 +        if (syserrno == EINTR
  1.2434 +                || syserrno == EAGAIN || syserrno == EWOULDBLOCK) {
  1.2435 +            count = xferred;
  1.2436 +        }
  1.2437 +    } else if (count == 0) {
  1.2438 +        /*
  1.2439 +         * We are now at EOF. The file was truncated. Solaris sendfile is
  1.2440 +         * supposed to return 0 and no error in this case, though some versions
  1.2441 +         * may return -1 and EINVAL .
  1.2442 +         */
  1.2443 +        count = -1;
  1.2444 +        syserrno = 0;  /* will be treated as EOF */
  1.2445 +    }
  1.2446 +
  1.2447 +    if (count != -1 && count < nbytes_to_send) {
  1.2448 +        pt_Continuation op;
  1.2449 +        struct sendfilevec *vec = sfv_struct;
  1.2450 +        PRInt32 rem = count;
  1.2451 +
  1.2452 +        while (rem >= vec->sfv_len) {
  1.2453 +            rem -= vec->sfv_len;
  1.2454 +            vec++;
  1.2455 +            sfvcnt--;
  1.2456 +        }
  1.2457 +        PR_ASSERT(sfvcnt > 0);
  1.2458 +
  1.2459 +        vec->sfv_off += rem;
  1.2460 +        vec->sfv_len -= rem;
  1.2461 +        PR_ASSERT(vec->sfv_len > 0);
  1.2462 +
  1.2463 +        op.arg1.osfd = sd->secret->md.osfd;
  1.2464 +        op.arg2.buffer = vec;
  1.2465 +        op.arg3.amount = sfvcnt;
  1.2466 +        op.arg4.flags = 0;
  1.2467 +        op.nbytes_to_send = nbytes_to_send - count;
  1.2468 +        op.result.code = count;
  1.2469 +        op.timeout = timeout;
  1.2470 +        op.function = pt_solaris_sendfile_cont;
  1.2471 +        op.event = POLLOUT | POLLPRI;
  1.2472 +        count = pt_Continue(&op);
  1.2473 +        syserrno = op.syserrno;
  1.2474 +    }
  1.2475 +
  1.2476 +done:
  1.2477 +    if (count == -1) {
  1.2478 +        pt_MapError(_MD_solaris_map_sendfile_error, syserrno);
  1.2479 +        return -1;
  1.2480 +    }
  1.2481 +    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  1.2482 +        PR_Close(sd);
  1.2483 +    }
  1.2484 +    PR_ASSERT(count == nbytes_to_send);
  1.2485 +    return count;
  1.2486 +}
  1.2487 +
  1.2488 +#ifndef HAVE_SENDFILEV
  1.2489 +static pthread_once_t pt_solaris_sendfilev_once_block = PTHREAD_ONCE_INIT;
  1.2490 +
  1.2491 +static void pt_solaris_sendfilev_init_routine(void)
  1.2492 +{
  1.2493 +    void *handle;
  1.2494 +    PRBool close_it = PR_FALSE;
  1.2495 + 
  1.2496 +    /*
  1.2497 +     * We do not want to unload libsendfile.so.  This handle is leaked
  1.2498 +     * intentionally.
  1.2499 +     */
  1.2500 +    handle = dlopen("libsendfile.so", RTLD_LAZY | RTLD_GLOBAL);
  1.2501 +    PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  1.2502 +        ("dlopen(libsendfile.so) returns %p", handle));
  1.2503 +
  1.2504 +    if (NULL == handle) {
  1.2505 +        /*
  1.2506 +         * The dlopen(0, mode) call is to allow for the possibility that
  1.2507 +         * sendfilev() may become part of a standard system library in a
  1.2508 +         * future Solaris release.
  1.2509 +         */
  1.2510 +        handle = dlopen(0, RTLD_LAZY | RTLD_GLOBAL);
  1.2511 +        PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  1.2512 +            ("dlopen(0) returns %p", handle));
  1.2513 +        close_it = PR_TRUE;
  1.2514 +    }
  1.2515 +    pt_solaris_sendfilev_fptr = (ssize_t (*)()) dlsym(handle, "sendfilev");
  1.2516 +    PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
  1.2517 +        ("dlsym(sendfilev) returns %p", pt_solaris_sendfilev_fptr));
  1.2518 +    
  1.2519 +    if (close_it) {
  1.2520 +        dlclose(handle);
  1.2521 +    }
  1.2522 +}
  1.2523 +
  1.2524 +/* 
  1.2525 + * pt_SolarisDispatchSendFile
  1.2526 + */
  1.2527 +static PRInt32 pt_SolarisDispatchSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  1.2528 +	  PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2529 +{
  1.2530 +    int rv;
  1.2531 +
  1.2532 +    rv = pthread_once(&pt_solaris_sendfilev_once_block,
  1.2533 +            pt_solaris_sendfilev_init_routine);
  1.2534 +    PR_ASSERT(0 == rv);
  1.2535 +    if (pt_solaris_sendfilev_fptr) {
  1.2536 +        return pt_SolarisSendFile(sd, sfd, flags, timeout);
  1.2537 +    } else {
  1.2538 +        return PR_EmulateSendFile(sd, sfd, flags, timeout);
  1.2539 +    }
  1.2540 +}
  1.2541 +#endif /* !HAVE_SENDFILEV */
  1.2542 +
  1.2543 +#endif  /* SOLARIS */
  1.2544 +
  1.2545 +#ifdef LINUX
  1.2546 +/*
  1.2547 + * pt_LinuxSendFile
  1.2548 + *
  1.2549 + *    Send file sfd->fd across socket sd. If specified, header and trailer
  1.2550 + *    buffers are sent before and after the file, respectively.
  1.2551 + *
  1.2552 + *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1.2553 + *    
  1.2554 + *    return number of bytes sent or -1 on error
  1.2555 + *
  1.2556 + *      This implementation takes advantage of the sendfile() system
  1.2557 + *      call available in Linux kernel 2.2 or higher.
  1.2558 + */
  1.2559 +
  1.2560 +static PRInt32 pt_LinuxSendFile(PRFileDesc *sd, PRSendFileData *sfd,
  1.2561 +                PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2562 +{
  1.2563 +    struct stat statbuf;
  1.2564 +    size_t file_nbytes_to_send;	
  1.2565 +    PRInt32 count = 0;
  1.2566 +    ssize_t rv;
  1.2567 +    int syserrno;
  1.2568 +    off_t offset;
  1.2569 +    PRBool tcp_cork_enabled = PR_FALSE;
  1.2570 +    int tcp_cork;
  1.2571 +
  1.2572 +    if (sfd->file_nbytes == 0) {
  1.2573 +        /* Get file size */
  1.2574 +        if (fstat(sfd->fd->secret->md.osfd, &statbuf) == -1) {
  1.2575 +            _PR_MD_MAP_FSTAT_ERROR(errno);
  1.2576 +            return -1;
  1.2577 +        } 		
  1.2578 +        file_nbytes_to_send = statbuf.st_size - sfd->file_offset;
  1.2579 +    } else {
  1.2580 +        file_nbytes_to_send = sfd->file_nbytes;
  1.2581 +    }
  1.2582 +
  1.2583 +    if ((sfd->hlen != 0 || sfd->tlen != 0)
  1.2584 +            && sd->secret->md.tcp_nodelay == 0) {
  1.2585 +        tcp_cork = 1;
  1.2586 +        if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
  1.2587 +                &tcp_cork, sizeof tcp_cork) == 0) {
  1.2588 +            tcp_cork_enabled = PR_TRUE;
  1.2589 +        } else {
  1.2590 +            syserrno = errno;
  1.2591 +            if (syserrno != EINVAL) {
  1.2592 +                _PR_MD_MAP_SETSOCKOPT_ERROR(syserrno);
  1.2593 +                return -1;
  1.2594 +            }
  1.2595 +            /*
  1.2596 +             * The most likely reason for the EINVAL error is that
  1.2597 +             * TCP_NODELAY is set (with a function other than
  1.2598 +             * PR_SetSocketOption).  This is not fatal, so we keep
  1.2599 +             * on going.
  1.2600 +             */
  1.2601 +            PR_LOG(_pr_io_lm, PR_LOG_WARNING,
  1.2602 +                ("pt_LinuxSendFile: "
  1.2603 +                "setsockopt(TCP_CORK) failed with EINVAL\n"));
  1.2604 +        }
  1.2605 +    }
  1.2606 +
  1.2607 +    if (sfd->hlen != 0) {
  1.2608 +        count = PR_Send(sd, sfd->header, sfd->hlen, 0, timeout);
  1.2609 +        if (count == -1) {
  1.2610 +            goto failed;
  1.2611 +        }
  1.2612 +    }
  1.2613 +
  1.2614 +    if (file_nbytes_to_send != 0) {
  1.2615 +        offset = sfd->file_offset;
  1.2616 +        do {
  1.2617 +            rv = sendfile(sd->secret->md.osfd, sfd->fd->secret->md.osfd,
  1.2618 +                &offset, file_nbytes_to_send);
  1.2619 +        } while (rv == -1 && (syserrno = errno) == EINTR);
  1.2620 +        if (rv == -1) {
  1.2621 +            if (syserrno != EAGAIN && syserrno != EWOULDBLOCK) {
  1.2622 +                _MD_linux_map_sendfile_error(syserrno);
  1.2623 +                count = -1;
  1.2624 +                goto failed;
  1.2625 +            }
  1.2626 +            rv = 0;
  1.2627 +        }
  1.2628 +        PR_ASSERT(rv == offset - sfd->file_offset);
  1.2629 +        count += rv;
  1.2630 +
  1.2631 +        if (rv < file_nbytes_to_send) {
  1.2632 +            pt_Continuation op;
  1.2633 +
  1.2634 +            op.arg1.osfd = sd->secret->md.osfd;
  1.2635 +            op.in_fd = sfd->fd->secret->md.osfd;
  1.2636 +            op.offset = offset;
  1.2637 +            op.count = file_nbytes_to_send - rv;
  1.2638 +            op.result.code = count;
  1.2639 +            op.timeout = timeout;
  1.2640 +            op.function = pt_linux_sendfile_cont;
  1.2641 +            op.event = POLLOUT | POLLPRI;
  1.2642 +            count = pt_Continue(&op);
  1.2643 +            syserrno = op.syserrno;
  1.2644 +            if (count == -1) {
  1.2645 +                pt_MapError(_MD_linux_map_sendfile_error, syserrno);
  1.2646 +                goto failed;
  1.2647 +            }
  1.2648 +        }
  1.2649 +    }
  1.2650 +
  1.2651 +    if (sfd->tlen != 0) {
  1.2652 +        rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout);
  1.2653 +        if (rv == -1) {
  1.2654 +            count = -1;
  1.2655 +            goto failed;
  1.2656 +        }
  1.2657 +        count += rv;
  1.2658 +    }
  1.2659 +
  1.2660 +failed:
  1.2661 +    if (tcp_cork_enabled) {
  1.2662 +        tcp_cork = 0;
  1.2663 +        if (setsockopt(sd->secret->md.osfd, SOL_TCP, TCP_CORK,
  1.2664 +                &tcp_cork, sizeof tcp_cork) == -1 && count != -1) {
  1.2665 +            _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
  1.2666 +            count = -1;
  1.2667 +        }
  1.2668 +    }
  1.2669 +    if (count != -1) {
  1.2670 +        if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  1.2671 +            PR_Close(sd);
  1.2672 +        }
  1.2673 +        PR_ASSERT(count == sfd->hlen + sfd->tlen + file_nbytes_to_send);
  1.2674 +    }
  1.2675 +    return count;
  1.2676 +}
  1.2677 +#endif  /* LINUX */
  1.2678 +
  1.2679 +#ifdef AIX
  1.2680 +extern	int _pr_aix_send_file_use_disabled;
  1.2681 +#endif
  1.2682 +
  1.2683 +static PRInt32 pt_SendFile(
  1.2684 +    PRFileDesc *sd, PRSendFileData *sfd,
  1.2685 +    PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2686 +{
  1.2687 +    if (pt_TestAbort()) return -1;
  1.2688 +    /* The socket must be in blocking mode. */
  1.2689 +    if (sd->secret->nonblocking)
  1.2690 +    {
  1.2691 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.2692 +        return -1;
  1.2693 +    }
  1.2694 +#ifdef HPUX11
  1.2695 +    return(pt_HPUXSendFile(sd, sfd, flags, timeout));
  1.2696 +#elif defined(AIX)
  1.2697 +#ifdef HAVE_SEND_FILE
  1.2698 +	/*
  1.2699 +	 * A bug in AIX 4.3.2 results in corruption of data transferred by
  1.2700 +	 * send_file(); AIX patch PTF U463956 contains the fix.  A user can
  1.2701 +	 * disable the use of send_file function in NSPR, when this patch is
  1.2702 +	 * not installed on the system, by setting the envionment variable
  1.2703 +	 * NSPR_AIX_SEND_FILE_USE_DISABLED to 1.
  1.2704 +	 */
  1.2705 +	if (_pr_aix_send_file_use_disabled)
  1.2706 +		return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  1.2707 +	else
  1.2708 +    	return(pt_AIXSendFile(sd, sfd, flags, timeout));
  1.2709 +#else
  1.2710 +	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  1.2711 +    /* return(pt_AIXDispatchSendFile(sd, sfd, flags, timeout));*/
  1.2712 +#endif /* HAVE_SEND_FILE */
  1.2713 +#elif defined(SOLARIS)
  1.2714 +#ifdef HAVE_SENDFILEV
  1.2715 +    	return(pt_SolarisSendFile(sd, sfd, flags, timeout));
  1.2716 +#else
  1.2717 +	return(pt_SolarisDispatchSendFile(sd, sfd, flags, timeout));
  1.2718 +#endif /* HAVE_SENDFILEV */
  1.2719 +#elif defined(LINUX)
  1.2720 +    	return(pt_LinuxSendFile(sd, sfd, flags, timeout));
  1.2721 +#else
  1.2722 +	return(PR_EmulateSendFile(sd, sfd, flags, timeout));
  1.2723 +#endif
  1.2724 +}
  1.2725 +
  1.2726 +static PRInt32 pt_TransmitFile(
  1.2727 +    PRFileDesc *sd, PRFileDesc *fd, const void *headers,
  1.2728 +    PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
  1.2729 +{
  1.2730 +	PRSendFileData sfd;
  1.2731 +
  1.2732 +	sfd.fd = fd;
  1.2733 +	sfd.file_offset = 0;
  1.2734 +	sfd.file_nbytes = 0;
  1.2735 +	sfd.header = headers;
  1.2736 +	sfd.hlen = hlen;
  1.2737 +	sfd.trailer = NULL;
  1.2738 +	sfd.tlen = 0;
  1.2739 +
  1.2740 +	return(pt_SendFile(sd, &sfd, flags, timeout));
  1.2741 +}  /* pt_TransmitFile */
  1.2742 +
  1.2743 +static PRInt32 pt_AcceptRead(
  1.2744 +    PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr,
  1.2745 +    void *buf, PRInt32 amount, PRIntervalTime timeout)
  1.2746 +{
  1.2747 +    PRInt32 rv = -1;
  1.2748 +
  1.2749 +    if (pt_TestAbort()) return rv;
  1.2750 +    /* The socket must be in blocking mode. */
  1.2751 +    if (sd->secret->nonblocking)
  1.2752 +    {
  1.2753 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.2754 +        return rv;
  1.2755 +    }
  1.2756 +
  1.2757 +    rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
  1.2758 +    return rv;
  1.2759 +}  /* pt_AcceptRead */
  1.2760 +
  1.2761 +static PRStatus pt_GetSockName(PRFileDesc *fd, PRNetAddr *addr)
  1.2762 +{
  1.2763 +    PRIntn rv = -1;
  1.2764 +    pt_SockLen addr_len = sizeof(PRNetAddr);
  1.2765 +
  1.2766 +    if (pt_TestAbort()) return PR_FAILURE;
  1.2767 +
  1.2768 +    rv = getsockname(
  1.2769 +        fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1.2770 +    if (rv == -1) {
  1.2771 +        pt_MapError(_PR_MD_MAP_GETSOCKNAME_ERROR, errno);
  1.2772 +        return PR_FAILURE;
  1.2773 +    } else {
  1.2774 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.2775 +        /* ignore the sa_len field of struct sockaddr */
  1.2776 +        if (addr)
  1.2777 +        {
  1.2778 +            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  1.2779 +        }
  1.2780 +#endif /* _PR_HAVE_SOCKADDR_LEN */
  1.2781 +#ifdef _PR_INET6
  1.2782 +		if (AF_INET6 == addr->raw.family)
  1.2783 +			addr->raw.family = PR_AF_INET6;
  1.2784 +#endif
  1.2785 +        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.2786 +        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  1.2787 +        return PR_SUCCESS;
  1.2788 +    }
  1.2789 +}  /* pt_GetSockName */
  1.2790 +
  1.2791 +static PRStatus pt_GetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  1.2792 +{
  1.2793 +    PRIntn rv = -1;
  1.2794 +    pt_SockLen addr_len = sizeof(PRNetAddr);
  1.2795 +
  1.2796 +    if (pt_TestAbort()) return PR_FAILURE;
  1.2797 +
  1.2798 +    rv = getpeername(
  1.2799 +        fd->secret->md.osfd, (struct sockaddr*)addr, &addr_len);
  1.2800 +
  1.2801 +    if (rv == -1) {
  1.2802 +        pt_MapError(_PR_MD_MAP_GETPEERNAME_ERROR, errno);
  1.2803 +        return PR_FAILURE;
  1.2804 +    } else {
  1.2805 +#ifdef _PR_HAVE_SOCKADDR_LEN
  1.2806 +        /* ignore the sa_len field of struct sockaddr */
  1.2807 +        if (addr)
  1.2808 +        {
  1.2809 +            addr->raw.family = ((struct sockaddr*)addr)->sa_family;
  1.2810 +        }
  1.2811 +#endif /* _PR_HAVE_SOCKADDR_LEN */
  1.2812 +#ifdef _PR_INET6
  1.2813 +		if (AF_INET6 == addr->raw.family)
  1.2814 +        	addr->raw.family = PR_AF_INET6;
  1.2815 +#endif
  1.2816 +        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.2817 +        PR_ASSERT(IsValidNetAddrLen(addr, addr_len) == PR_TRUE);
  1.2818 +        return PR_SUCCESS;
  1.2819 +    }
  1.2820 +}  /* pt_GetPeerName */
  1.2821 +
  1.2822 +static PRStatus pt_GetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
  1.2823 +{
  1.2824 +    PRIntn rv;
  1.2825 +    pt_SockLen length;
  1.2826 +    PRInt32 level, name;
  1.2827 +
  1.2828 +    /*
  1.2829 +     * PR_SockOpt_Nonblocking is a special case that does not
  1.2830 +     * translate to a getsockopt() call
  1.2831 +     */
  1.2832 +    if (PR_SockOpt_Nonblocking == data->option)
  1.2833 +    {
  1.2834 +        data->value.non_blocking = fd->secret->nonblocking;
  1.2835 +        return PR_SUCCESS;
  1.2836 +    }
  1.2837 +
  1.2838 +    rv = _PR_MapOptionName(data->option, &level, &name);
  1.2839 +    if (PR_SUCCESS == rv)
  1.2840 +    {
  1.2841 +        switch (data->option)
  1.2842 +        {
  1.2843 +            case PR_SockOpt_Linger:
  1.2844 +            {
  1.2845 +                struct linger linger;
  1.2846 +                length = sizeof(linger);
  1.2847 +                rv = getsockopt(
  1.2848 +                    fd->secret->md.osfd, level, name, (char *) &linger, &length);
  1.2849 +                PR_ASSERT((-1 == rv) || (sizeof(linger) == length));
  1.2850 +                data->value.linger.polarity =
  1.2851 +                    (linger.l_onoff) ? PR_TRUE : PR_FALSE;
  1.2852 +                data->value.linger.linger =
  1.2853 +                    PR_SecondsToInterval(linger.l_linger);
  1.2854 +                break;
  1.2855 +            }
  1.2856 +            case PR_SockOpt_Reuseaddr:
  1.2857 +            case PR_SockOpt_Keepalive:
  1.2858 +            case PR_SockOpt_NoDelay:
  1.2859 +            case PR_SockOpt_Broadcast:
  1.2860 +            case PR_SockOpt_Reuseport:
  1.2861 +            {
  1.2862 +                PRIntn value;
  1.2863 +                length = sizeof(PRIntn);
  1.2864 +                rv = getsockopt(
  1.2865 +                    fd->secret->md.osfd, level, name, (char*)&value, &length);
  1.2866 +                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  1.2867 +                data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
  1.2868 +                break;
  1.2869 +            }
  1.2870 +            case PR_SockOpt_McastLoopback:
  1.2871 +            {
  1.2872 +                PRUint8 xbool;
  1.2873 +                length = sizeof(xbool);
  1.2874 +                rv = getsockopt(
  1.2875 +                    fd->secret->md.osfd, level, name,
  1.2876 +                    (char*)&xbool, &length);
  1.2877 +                PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
  1.2878 +                data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
  1.2879 +                break;
  1.2880 +            }
  1.2881 +            case PR_SockOpt_RecvBufferSize:
  1.2882 +            case PR_SockOpt_SendBufferSize:
  1.2883 +            case PR_SockOpt_MaxSegment:
  1.2884 +            {
  1.2885 +                PRIntn value;
  1.2886 +                length = sizeof(PRIntn);
  1.2887 +                rv = getsockopt(
  1.2888 +                    fd->secret->md.osfd, level, name, (char*)&value, &length);
  1.2889 +                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  1.2890 +                data->value.recv_buffer_size = value;
  1.2891 +                break;
  1.2892 +            }
  1.2893 +            case PR_SockOpt_IpTimeToLive:
  1.2894 +            case PR_SockOpt_IpTypeOfService:
  1.2895 +            {
  1.2896 +                length = sizeof(PRUintn);
  1.2897 +                rv = getsockopt(
  1.2898 +                    fd->secret->md.osfd, level, name,
  1.2899 +                    (char*)&data->value.ip_ttl, &length);
  1.2900 +                PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
  1.2901 +                break;
  1.2902 +            }
  1.2903 +            case PR_SockOpt_McastTimeToLive:
  1.2904 +            {
  1.2905 +                PRUint8 ttl;
  1.2906 +                length = sizeof(ttl);
  1.2907 +                rv = getsockopt(
  1.2908 +                    fd->secret->md.osfd, level, name,
  1.2909 +                    (char*)&ttl, &length);
  1.2910 +                PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
  1.2911 +                data->value.mcast_ttl = ttl;
  1.2912 +                break;
  1.2913 +            }
  1.2914 +            case PR_SockOpt_AddMember:
  1.2915 +            case PR_SockOpt_DropMember:
  1.2916 +            {
  1.2917 +                struct ip_mreq mreq;
  1.2918 +                length = sizeof(mreq);
  1.2919 +                rv = getsockopt(
  1.2920 +                    fd->secret->md.osfd, level, name, (char*)&mreq, &length);
  1.2921 +                PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
  1.2922 +                data->value.add_member.mcaddr.inet.ip =
  1.2923 +                    mreq.imr_multiaddr.s_addr;
  1.2924 +                data->value.add_member.ifaddr.inet.ip =
  1.2925 +                    mreq.imr_interface.s_addr;
  1.2926 +                break;
  1.2927 +            }
  1.2928 +            case PR_SockOpt_McastInterface:
  1.2929 +            {
  1.2930 +                length = sizeof(data->value.mcast_if.inet.ip);
  1.2931 +                rv = getsockopt(
  1.2932 +                    fd->secret->md.osfd, level, name,
  1.2933 +                    (char*)&data->value.mcast_if.inet.ip, &length);
  1.2934 +                PR_ASSERT((-1 == rv)
  1.2935 +                    || (sizeof(data->value.mcast_if.inet.ip) == length));
  1.2936 +                break;
  1.2937 +            }
  1.2938 +            default:
  1.2939 +                PR_NOT_REACHED("Unknown socket option");
  1.2940 +                break;
  1.2941 +        }
  1.2942 +        if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
  1.2943 +    }
  1.2944 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.2945 +}  /* pt_GetSocketOption */
  1.2946 +
  1.2947 +static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
  1.2948 +{
  1.2949 +    PRIntn rv;
  1.2950 +    PRInt32 level, name;
  1.2951 +
  1.2952 +    /*
  1.2953 +     * PR_SockOpt_Nonblocking is a special case that does not
  1.2954 +     * translate to a setsockopt call.
  1.2955 +     */
  1.2956 +    if (PR_SockOpt_Nonblocking == data->option)
  1.2957 +    {
  1.2958 +        fd->secret->nonblocking = data->value.non_blocking;
  1.2959 +        return PR_SUCCESS;
  1.2960 +    }
  1.2961 +
  1.2962 +    rv = _PR_MapOptionName(data->option, &level, &name);
  1.2963 +    if (PR_SUCCESS == rv)
  1.2964 +    {
  1.2965 +        switch (data->option)
  1.2966 +        {
  1.2967 +            case PR_SockOpt_Linger:
  1.2968 +            {
  1.2969 +                struct linger linger;
  1.2970 +                linger.l_onoff = data->value.linger.polarity;
  1.2971 +                linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
  1.2972 +                rv = setsockopt(
  1.2973 +                    fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
  1.2974 +                break;
  1.2975 +            }
  1.2976 +            case PR_SockOpt_Reuseaddr:
  1.2977 +            case PR_SockOpt_Keepalive:
  1.2978 +            case PR_SockOpt_NoDelay:
  1.2979 +            case PR_SockOpt_Broadcast:
  1.2980 +            case PR_SockOpt_Reuseport:
  1.2981 +            {
  1.2982 +                PRIntn value = (data->value.reuse_addr) ? 1 : 0;
  1.2983 +                rv = setsockopt(
  1.2984 +                    fd->secret->md.osfd, level, name,
  1.2985 +                    (char*)&value, sizeof(PRIntn));
  1.2986 +#ifdef LINUX
  1.2987 +                /* for pt_LinuxSendFile */
  1.2988 +                if (name == TCP_NODELAY && rv == 0) {
  1.2989 +                    fd->secret->md.tcp_nodelay = value;
  1.2990 +                }
  1.2991 +#endif
  1.2992 +                break;
  1.2993 +            }
  1.2994 +            case PR_SockOpt_McastLoopback:
  1.2995 +            {
  1.2996 +                PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
  1.2997 +                rv = setsockopt(
  1.2998 +                    fd->secret->md.osfd, level, name,
  1.2999 +                    (char*)&xbool, sizeof(xbool));
  1.3000 +                break;
  1.3001 +            }
  1.3002 +            case PR_SockOpt_RecvBufferSize:
  1.3003 +            case PR_SockOpt_SendBufferSize:
  1.3004 +            case PR_SockOpt_MaxSegment:
  1.3005 +            {
  1.3006 +                PRIntn value = data->value.recv_buffer_size;
  1.3007 +                rv = setsockopt(
  1.3008 +                    fd->secret->md.osfd, level, name,
  1.3009 +                    (char*)&value, sizeof(PRIntn));
  1.3010 +                break;
  1.3011 +            }
  1.3012 +            case PR_SockOpt_IpTimeToLive:
  1.3013 +            case PR_SockOpt_IpTypeOfService:
  1.3014 +            {
  1.3015 +                rv = setsockopt(
  1.3016 +                    fd->secret->md.osfd, level, name,
  1.3017 +                    (char*)&data->value.ip_ttl, sizeof(PRUintn));
  1.3018 +                break;
  1.3019 +            }
  1.3020 +            case PR_SockOpt_McastTimeToLive:
  1.3021 +            {
  1.3022 +                PRUint8 ttl = data->value.mcast_ttl;
  1.3023 +                rv = setsockopt(
  1.3024 +                    fd->secret->md.osfd, level, name,
  1.3025 +                    (char*)&ttl, sizeof(ttl));
  1.3026 +                break;
  1.3027 +            }
  1.3028 +            case PR_SockOpt_AddMember:
  1.3029 +            case PR_SockOpt_DropMember:
  1.3030 +            {
  1.3031 +                struct ip_mreq mreq;
  1.3032 +                mreq.imr_multiaddr.s_addr =
  1.3033 +                    data->value.add_member.mcaddr.inet.ip;
  1.3034 +                mreq.imr_interface.s_addr =
  1.3035 +                    data->value.add_member.ifaddr.inet.ip;
  1.3036 +                rv = setsockopt(
  1.3037 +                    fd->secret->md.osfd, level, name,
  1.3038 +                    (char*)&mreq, sizeof(mreq));
  1.3039 +                break;
  1.3040 +            }
  1.3041 +            case PR_SockOpt_McastInterface:
  1.3042 +            {
  1.3043 +                rv = setsockopt(
  1.3044 +                    fd->secret->md.osfd, level, name,
  1.3045 +                    (char*)&data->value.mcast_if.inet.ip,
  1.3046 +                    sizeof(data->value.mcast_if.inet.ip));
  1.3047 +                break;
  1.3048 +            }
  1.3049 +            default:
  1.3050 +                PR_NOT_REACHED("Unknown socket option");
  1.3051 +                break;
  1.3052 +        }
  1.3053 +        if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
  1.3054 +    }
  1.3055 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.3056 +}  /* pt_SetSocketOption */
  1.3057 +
  1.3058 +/*****************************************************************************/
  1.3059 +/****************************** I/O method objects ***************************/
  1.3060 +/*****************************************************************************/
  1.3061 +
  1.3062 +static PRIOMethods _pr_file_methods = {
  1.3063 +    PR_DESC_FILE,
  1.3064 +    pt_Close,
  1.3065 +    pt_Read,
  1.3066 +    pt_Write,
  1.3067 +    pt_Available_f,
  1.3068 +    pt_Available64_f,
  1.3069 +    pt_Fsync,
  1.3070 +    pt_Seek,
  1.3071 +    pt_Seek64,
  1.3072 +    pt_FileInfo,
  1.3073 +    pt_FileInfo64,
  1.3074 +    (PRWritevFN)_PR_InvalidInt,        
  1.3075 +    (PRConnectFN)_PR_InvalidStatus,        
  1.3076 +    (PRAcceptFN)_PR_InvalidDesc,        
  1.3077 +    (PRBindFN)_PR_InvalidStatus,        
  1.3078 +    (PRListenFN)_PR_InvalidStatus,        
  1.3079 +    (PRShutdownFN)_PR_InvalidStatus,    
  1.3080 +    (PRRecvFN)_PR_InvalidInt,        
  1.3081 +    (PRSendFN)_PR_InvalidInt,        
  1.3082 +    (PRRecvfromFN)_PR_InvalidInt,    
  1.3083 +    (PRSendtoFN)_PR_InvalidInt,        
  1.3084 +    pt_Poll,
  1.3085 +    (PRAcceptreadFN)_PR_InvalidInt,   
  1.3086 +    (PRTransmitfileFN)_PR_InvalidInt, 
  1.3087 +    (PRGetsocknameFN)_PR_InvalidStatus,    
  1.3088 +    (PRGetpeernameFN)_PR_InvalidStatus,    
  1.3089 +    (PRReservedFN)_PR_InvalidInt,    
  1.3090 +    (PRReservedFN)_PR_InvalidInt,    
  1.3091 +    (PRGetsocketoptionFN)_PR_InvalidStatus,
  1.3092 +    (PRSetsocketoptionFN)_PR_InvalidStatus,
  1.3093 +    (PRSendfileFN)_PR_InvalidInt, 
  1.3094 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.3095 +    (PRReservedFN)_PR_InvalidInt, 
  1.3096 +    (PRReservedFN)_PR_InvalidInt, 
  1.3097 +    (PRReservedFN)_PR_InvalidInt, 
  1.3098 +    (PRReservedFN)_PR_InvalidInt
  1.3099 +};
  1.3100 +
  1.3101 +static PRIOMethods _pr_pipe_methods = {
  1.3102 +    PR_DESC_PIPE,
  1.3103 +    pt_Close,
  1.3104 +    pt_Read,
  1.3105 +    pt_Write,
  1.3106 +    pt_Available_s,
  1.3107 +    pt_Available64_s,
  1.3108 +    pt_Synch,
  1.3109 +    (PRSeekFN)_PR_InvalidInt,
  1.3110 +    (PRSeek64FN)_PR_InvalidInt64,
  1.3111 +    (PRFileInfoFN)_PR_InvalidStatus,
  1.3112 +    (PRFileInfo64FN)_PR_InvalidStatus,
  1.3113 +    (PRWritevFN)_PR_InvalidInt,        
  1.3114 +    (PRConnectFN)_PR_InvalidStatus,        
  1.3115 +    (PRAcceptFN)_PR_InvalidDesc,        
  1.3116 +    (PRBindFN)_PR_InvalidStatus,        
  1.3117 +    (PRListenFN)_PR_InvalidStatus,        
  1.3118 +    (PRShutdownFN)_PR_InvalidStatus,    
  1.3119 +    (PRRecvFN)_PR_InvalidInt,        
  1.3120 +    (PRSendFN)_PR_InvalidInt,        
  1.3121 +    (PRRecvfromFN)_PR_InvalidInt,    
  1.3122 +    (PRSendtoFN)_PR_InvalidInt,        
  1.3123 +    pt_Poll,
  1.3124 +    (PRAcceptreadFN)_PR_InvalidInt,   
  1.3125 +    (PRTransmitfileFN)_PR_InvalidInt, 
  1.3126 +    (PRGetsocknameFN)_PR_InvalidStatus,    
  1.3127 +    (PRGetpeernameFN)_PR_InvalidStatus,    
  1.3128 +    (PRReservedFN)_PR_InvalidInt,    
  1.3129 +    (PRReservedFN)_PR_InvalidInt,    
  1.3130 +    (PRGetsocketoptionFN)_PR_InvalidStatus,
  1.3131 +    (PRSetsocketoptionFN)_PR_InvalidStatus,
  1.3132 +    (PRSendfileFN)_PR_InvalidInt, 
  1.3133 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.3134 +    (PRReservedFN)_PR_InvalidInt, 
  1.3135 +    (PRReservedFN)_PR_InvalidInt, 
  1.3136 +    (PRReservedFN)_PR_InvalidInt, 
  1.3137 +    (PRReservedFN)_PR_InvalidInt
  1.3138 +};
  1.3139 +
  1.3140 +static PRIOMethods _pr_tcp_methods = {
  1.3141 +    PR_DESC_SOCKET_TCP,
  1.3142 +    pt_Close,
  1.3143 +    pt_SocketRead,
  1.3144 +    pt_SocketWrite,
  1.3145 +    pt_Available_s,
  1.3146 +    pt_Available64_s,
  1.3147 +    pt_Synch,
  1.3148 +    (PRSeekFN)_PR_InvalidInt,
  1.3149 +    (PRSeek64FN)_PR_InvalidInt64,
  1.3150 +    (PRFileInfoFN)_PR_InvalidStatus,
  1.3151 +    (PRFileInfo64FN)_PR_InvalidStatus,
  1.3152 +    pt_Writev,
  1.3153 +    pt_Connect,
  1.3154 +    pt_Accept,
  1.3155 +    pt_Bind,
  1.3156 +    pt_Listen,
  1.3157 +    pt_Shutdown,
  1.3158 +    pt_Recv,
  1.3159 +    pt_Send,
  1.3160 +    (PRRecvfromFN)_PR_InvalidInt,
  1.3161 +    (PRSendtoFN)_PR_InvalidInt,
  1.3162 +    pt_Poll,
  1.3163 +    pt_AcceptRead,
  1.3164 +    pt_TransmitFile,
  1.3165 +    pt_GetSockName,
  1.3166 +    pt_GetPeerName,
  1.3167 +    (PRReservedFN)_PR_InvalidInt,
  1.3168 +    (PRReservedFN)_PR_InvalidInt,
  1.3169 +    pt_GetSocketOption,
  1.3170 +    pt_SetSocketOption,
  1.3171 +    pt_SendFile, 
  1.3172 +    pt_ConnectContinue,
  1.3173 +    (PRReservedFN)_PR_InvalidInt, 
  1.3174 +    (PRReservedFN)_PR_InvalidInt, 
  1.3175 +    (PRReservedFN)_PR_InvalidInt, 
  1.3176 +    (PRReservedFN)_PR_InvalidInt
  1.3177 +};
  1.3178 +
  1.3179 +static PRIOMethods _pr_udp_methods = {
  1.3180 +    PR_DESC_SOCKET_UDP,
  1.3181 +    pt_Close,
  1.3182 +    pt_SocketRead,
  1.3183 +    pt_SocketWrite,
  1.3184 +    pt_Available_s,
  1.3185 +    pt_Available64_s,
  1.3186 +    pt_Synch,
  1.3187 +    (PRSeekFN)_PR_InvalidInt,
  1.3188 +    (PRSeek64FN)_PR_InvalidInt64,
  1.3189 +    (PRFileInfoFN)_PR_InvalidStatus,
  1.3190 +    (PRFileInfo64FN)_PR_InvalidStatus,
  1.3191 +    pt_Writev,
  1.3192 +    pt_Connect,
  1.3193 +    (PRAcceptFN)_PR_InvalidDesc,
  1.3194 +    pt_Bind,
  1.3195 +    pt_Listen,
  1.3196 +    pt_Shutdown,
  1.3197 +    pt_Recv,
  1.3198 +    pt_Send,
  1.3199 +    pt_RecvFrom,
  1.3200 +    pt_SendTo,
  1.3201 +    pt_Poll,
  1.3202 +    (PRAcceptreadFN)_PR_InvalidInt,
  1.3203 +    (PRTransmitfileFN)_PR_InvalidInt,
  1.3204 +    pt_GetSockName,
  1.3205 +    pt_GetPeerName,
  1.3206 +    (PRReservedFN)_PR_InvalidInt,
  1.3207 +    (PRReservedFN)_PR_InvalidInt,
  1.3208 +    pt_GetSocketOption,
  1.3209 +    pt_SetSocketOption,
  1.3210 +    (PRSendfileFN)_PR_InvalidInt, 
  1.3211 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.3212 +    (PRReservedFN)_PR_InvalidInt, 
  1.3213 +    (PRReservedFN)_PR_InvalidInt, 
  1.3214 +    (PRReservedFN)_PR_InvalidInt, 
  1.3215 +    (PRReservedFN)_PR_InvalidInt
  1.3216 +};
  1.3217 +
  1.3218 +static PRIOMethods _pr_socketpollfd_methods = {
  1.3219 +    (PRDescType) 0,
  1.3220 +    (PRCloseFN)_PR_InvalidStatus,
  1.3221 +    (PRReadFN)_PR_InvalidInt,
  1.3222 +    (PRWriteFN)_PR_InvalidInt,
  1.3223 +    (PRAvailableFN)_PR_InvalidInt,
  1.3224 +    (PRAvailable64FN)_PR_InvalidInt64,
  1.3225 +    (PRFsyncFN)_PR_InvalidStatus,
  1.3226 +    (PRSeekFN)_PR_InvalidInt,
  1.3227 +    (PRSeek64FN)_PR_InvalidInt64,
  1.3228 +    (PRFileInfoFN)_PR_InvalidStatus,
  1.3229 +    (PRFileInfo64FN)_PR_InvalidStatus,
  1.3230 +    (PRWritevFN)_PR_InvalidInt,        
  1.3231 +    (PRConnectFN)_PR_InvalidStatus,        
  1.3232 +    (PRAcceptFN)_PR_InvalidDesc,        
  1.3233 +    (PRBindFN)_PR_InvalidStatus,        
  1.3234 +    (PRListenFN)_PR_InvalidStatus,        
  1.3235 +    (PRShutdownFN)_PR_InvalidStatus,    
  1.3236 +    (PRRecvFN)_PR_InvalidInt,        
  1.3237 +    (PRSendFN)_PR_InvalidInt,        
  1.3238 +    (PRRecvfromFN)_PR_InvalidInt,    
  1.3239 +    (PRSendtoFN)_PR_InvalidInt,        
  1.3240 +	pt_Poll,
  1.3241 +    (PRAcceptreadFN)_PR_InvalidInt,   
  1.3242 +    (PRTransmitfileFN)_PR_InvalidInt, 
  1.3243 +    (PRGetsocknameFN)_PR_InvalidStatus,    
  1.3244 +    (PRGetpeernameFN)_PR_InvalidStatus,    
  1.3245 +    (PRReservedFN)_PR_InvalidInt,    
  1.3246 +    (PRReservedFN)_PR_InvalidInt,    
  1.3247 +    (PRGetsocketoptionFN)_PR_InvalidStatus,
  1.3248 +    (PRSetsocketoptionFN)_PR_InvalidStatus,
  1.3249 +    (PRSendfileFN)_PR_InvalidInt, 
  1.3250 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.3251 +    (PRReservedFN)_PR_InvalidInt, 
  1.3252 +    (PRReservedFN)_PR_InvalidInt, 
  1.3253 +    (PRReservedFN)_PR_InvalidInt, 
  1.3254 +    (PRReservedFN)_PR_InvalidInt
  1.3255 +};
  1.3256 +
  1.3257 +#if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
  1.3258 +    || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
  1.3259 +    || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
  1.3260 +    || defined(OPENBSD) || defined(BSDI) || defined(NTO) \
  1.3261 +    || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) \
  1.3262 +    || defined(SYMBIAN)
  1.3263 +#define _PR_FCNTL_FLAGS O_NONBLOCK
  1.3264 +#else
  1.3265 +#error "Can't determine architecture"
  1.3266 +#endif
  1.3267 +
  1.3268 +/*
  1.3269 + * Put a Unix file descriptor in non-blocking mode.
  1.3270 + */
  1.3271 +static void pt_MakeFdNonblock(PRIntn osfd)
  1.3272 +{
  1.3273 +    PRIntn flags;
  1.3274 +    flags = fcntl(osfd, F_GETFL, 0);
  1.3275 +    flags |= _PR_FCNTL_FLAGS;
  1.3276 +    (void)fcntl(osfd, F_SETFL, flags);
  1.3277 +}
  1.3278 +
  1.3279 +/*
  1.3280 + * Put a Unix socket fd in non-blocking mode that can
  1.3281 + * ideally be inherited by an accepted socket.
  1.3282 + *
  1.3283 + * Why doesn't pt_MakeFdNonblock do?  This is to deal with
  1.3284 + * the special case of HP-UX.  HP-UX has three kinds of
  1.3285 + * non-blocking modes for sockets: the fcntl() O_NONBLOCK
  1.3286 + * and O_NDELAY flags and ioctl() FIOSNBIO request.  Only
  1.3287 + * the ioctl() FIOSNBIO form of non-blocking mode is
  1.3288 + * inherited by an accepted socket.
  1.3289 + *
  1.3290 + * Other platforms just use the generic pt_MakeFdNonblock
  1.3291 + * to put a socket in non-blocking mode.
  1.3292 + */
  1.3293 +#ifdef HPUX
  1.3294 +static void pt_MakeSocketNonblock(PRIntn osfd)
  1.3295 +{
  1.3296 +    PRIntn one = 1;
  1.3297 +    (void)ioctl(osfd, FIOSNBIO, &one);
  1.3298 +}
  1.3299 +#else
  1.3300 +#define pt_MakeSocketNonblock pt_MakeFdNonblock
  1.3301 +#endif
  1.3302 +
  1.3303 +static PRFileDesc *pt_SetMethods(
  1.3304 +    PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
  1.3305 +{
  1.3306 +    PRFileDesc *fd = _PR_Getfd();
  1.3307 +    
  1.3308 +    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.3309 +    else
  1.3310 +    {
  1.3311 +        fd->secret->md.osfd = osfd;
  1.3312 +        fd->secret->state = _PR_FILEDESC_OPEN;
  1.3313 +        if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
  1.3314 +        else
  1.3315 +        {
  1.3316 +            /* By default, a Unix fd is not closed on exec. */
  1.3317 +#ifdef DEBUG
  1.3318 +            PRIntn flags;
  1.3319 +            flags = fcntl(osfd, F_GETFD, 0);
  1.3320 +            PR_ASSERT(0 == flags);
  1.3321 +#endif
  1.3322 +            fd->secret->inheritable = _PR_TRI_TRUE;
  1.3323 +        }
  1.3324 +        switch (type)
  1.3325 +        {
  1.3326 +            case PR_DESC_FILE:
  1.3327 +                fd->methods = PR_GetFileMethods();
  1.3328 +                break;
  1.3329 +            case PR_DESC_SOCKET_TCP:
  1.3330 +                fd->methods = PR_GetTCPMethods();
  1.3331 +#ifdef _PR_ACCEPT_INHERIT_NONBLOCK
  1.3332 +                if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
  1.3333 +#else
  1.3334 +                pt_MakeSocketNonblock(osfd);
  1.3335 +#endif
  1.3336 +                break;
  1.3337 +            case PR_DESC_SOCKET_UDP:
  1.3338 +                fd->methods = PR_GetUDPMethods();
  1.3339 +                pt_MakeFdNonblock(osfd);
  1.3340 +                break;
  1.3341 +            case PR_DESC_PIPE:
  1.3342 +                fd->methods = PR_GetPipeMethods();
  1.3343 +                pt_MakeFdNonblock(osfd);
  1.3344 +                break;
  1.3345 +            default:
  1.3346 +                break;
  1.3347 +        }
  1.3348 +    }
  1.3349 +    return fd;
  1.3350 +}  /* pt_SetMethods */
  1.3351 +
  1.3352 +PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
  1.3353 +{
  1.3354 +    return &_pr_file_methods;
  1.3355 +}  /* PR_GetFileMethods */
  1.3356 +
  1.3357 +PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
  1.3358 +{
  1.3359 +    return &_pr_pipe_methods;
  1.3360 +}  /* PR_GetPipeMethods */
  1.3361 +
  1.3362 +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
  1.3363 +{
  1.3364 +    return &_pr_tcp_methods;
  1.3365 +}  /* PR_GetTCPMethods */
  1.3366 +
  1.3367 +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
  1.3368 +{
  1.3369 +    return &_pr_udp_methods;
  1.3370 +}  /* PR_GetUDPMethods */
  1.3371 +
  1.3372 +static const PRIOMethods* PR_GetSocketPollFdMethods(void)
  1.3373 +{
  1.3374 +    return &_pr_socketpollfd_methods;
  1.3375 +}  /* PR_GetSocketPollFdMethods */
  1.3376 +
  1.3377 +PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
  1.3378 +    PRInt32 osfd, const PRIOMethods *methods)
  1.3379 +{
  1.3380 +    PRFileDesc *fd = _PR_Getfd();
  1.3381 +
  1.3382 +    if (NULL == fd) goto failed;
  1.3383 +
  1.3384 +    fd->methods = methods;
  1.3385 +    fd->secret->md.osfd = osfd;
  1.3386 +    /* Make fd non-blocking */
  1.3387 +    if (osfd > 2)
  1.3388 +    {
  1.3389 +        /* Don't mess around with stdin, stdout or stderr */
  1.3390 +        if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
  1.3391 +        else pt_MakeFdNonblock(osfd);
  1.3392 +    }
  1.3393 +    fd->secret->state = _PR_FILEDESC_OPEN;
  1.3394 +    fd->secret->inheritable = _PR_TRI_UNKNOWN;
  1.3395 +    return fd;
  1.3396 +    
  1.3397 +failed:
  1.3398 +    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.3399 +    return fd;
  1.3400 +}  /* PR_AllocFileDesc */
  1.3401 +
  1.3402 +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
  1.3403 +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
  1.3404 +#if defined(_PR_INET6_PROBE)
  1.3405 +extern PRBool _pr_ipv6_is_present(void);
  1.3406 +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
  1.3407 +{
  1.3408 +    int osfd;
  1.3409 +
  1.3410 +#if defined(DARWIN)
  1.3411 +    /*
  1.3412 +     * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
  1.3413 +     * lesser versions is not ready for general use (see bug 222031).
  1.3414 +     */
  1.3415 +    {
  1.3416 +        struct utsname u;
  1.3417 +        if (uname(&u) != 0 || atoi(u.release) < 7)
  1.3418 +            return PR_FALSE;
  1.3419 +    }
  1.3420 +#endif
  1.3421 +
  1.3422 +    /*
  1.3423 +     * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
  1.3424 +     * suggests that we call open("/dev/ip6", O_RDWR) to determine
  1.3425 +     * whether IPv6 APIs and the IPv6 stack are on the system.
  1.3426 +     * Our portable test below seems to work fine, so I am using it.
  1.3427 +     */
  1.3428 +    osfd = socket(AF_INET6, SOCK_STREAM, 0);
  1.3429 +    if (osfd != -1) {
  1.3430 +        close(osfd);
  1.3431 +        return PR_TRUE;
  1.3432 +    }
  1.3433 +    return PR_FALSE;
  1.3434 +}
  1.3435 +#endif	/* _PR_INET6_PROBE */
  1.3436 +#endif
  1.3437 +
  1.3438 +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
  1.3439 +{
  1.3440 +    PRIntn osfd;
  1.3441 +    PRDescType ftype;
  1.3442 +    PRFileDesc *fd = NULL;
  1.3443 +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
  1.3444 +    PRInt32 tmp_domain = domain;
  1.3445 +#endif
  1.3446 +
  1.3447 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.3448 +
  1.3449 +    if (pt_TestAbort()) return NULL;
  1.3450 +
  1.3451 +    if (PF_INET != domain
  1.3452 +        && PR_AF_INET6 != domain
  1.3453 +#if defined(_PR_HAVE_SDP)
  1.3454 +        && PR_AF_INET_SDP != domain
  1.3455 +#if defined(SOLARIS)
  1.3456 +        && PR_AF_INET6_SDP != domain
  1.3457 +#endif /* SOLARIS */
  1.3458 +#endif /* _PR_HAVE_SDP */
  1.3459 +        && PF_UNIX != domain)
  1.3460 +    {
  1.3461 +        PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  1.3462 +        return fd;
  1.3463 +    }
  1.3464 +	if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
  1.3465 +	else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
  1.3466 +	else
  1.3467 +	{
  1.3468 +		(void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  1.3469 +		return fd;
  1.3470 +	}
  1.3471 +#if defined(_PR_HAVE_SDP)
  1.3472 +#if defined(LINUX)
  1.3473 +    if (PR_AF_INET_SDP == domain)
  1.3474 +        domain = AF_INET_SDP;
  1.3475 +#elif defined(SOLARIS)
  1.3476 +    if (PR_AF_INET_SDP == domain) {
  1.3477 +        domain = AF_INET;
  1.3478 +        proto = PROTO_SDP;
  1.3479 +    } else if(PR_AF_INET6_SDP == domain) {
  1.3480 +        domain = AF_INET6;
  1.3481 +        proto = PROTO_SDP;
  1.3482 +    }
  1.3483 +#endif /* SOLARIS */
  1.3484 +#endif /* _PR_HAVE_SDP */
  1.3485 +#if defined(_PR_INET6_PROBE)
  1.3486 +	if (PR_AF_INET6 == domain)
  1.3487 +		domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
  1.3488 +#elif defined(_PR_INET6) 
  1.3489 +	if (PR_AF_INET6 == domain)
  1.3490 +		domain = AF_INET6;
  1.3491 +#else
  1.3492 +	if (PR_AF_INET6 == domain)
  1.3493 +		domain = AF_INET;
  1.3494 +#endif
  1.3495 +
  1.3496 +    osfd = socket(domain, type, proto);
  1.3497 +    if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
  1.3498 +    else
  1.3499 +    {
  1.3500 +#ifdef _PR_IPV6_V6ONLY_PROBE
  1.3501 +        if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
  1.3502 +        {
  1.3503 +            int on = 0;
  1.3504 +            (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
  1.3505 +                    &on, sizeof(on));
  1.3506 +        }
  1.3507 +#endif
  1.3508 +        fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
  1.3509 +        if (fd == NULL) close(osfd);
  1.3510 +    }
  1.3511 +#ifdef _PR_NEED_SECRET_AF
  1.3512 +    if (fd != NULL) fd->secret->af = domain;
  1.3513 +#endif
  1.3514 +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
  1.3515 +	if (fd != NULL) {
  1.3516 +		/*
  1.3517 +		 * For platforms with no support for IPv6 
  1.3518 +		 * create layered socket for IPv4-mapped IPv6 addresses
  1.3519 +		 */
  1.3520 +		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
  1.3521 +			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
  1.3522 +				PR_Close(fd);
  1.3523 +				fd = NULL;
  1.3524 +			}
  1.3525 +		}
  1.3526 +	}
  1.3527 +#endif
  1.3528 +    return fd;
  1.3529 +}  /* PR_Socket */
  1.3530 +
  1.3531 +/*****************************************************************************/
  1.3532 +/****************************** I/O public methods ***************************/
  1.3533 +/*****************************************************************************/
  1.3534 +
  1.3535 +PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
  1.3536 +    const char *name, PRIntn flags, PRIntn mode)
  1.3537 +{
  1.3538 +    PRFileDesc *fd = NULL;
  1.3539 +    PRIntn syserrno, osfd = -1, osflags = 0;;
  1.3540 +
  1.3541 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.3542 +
  1.3543 +    if (pt_TestAbort()) return NULL;
  1.3544 +
  1.3545 +    if (flags & PR_RDONLY) osflags |= O_RDONLY;
  1.3546 +    if (flags & PR_WRONLY) osflags |= O_WRONLY;
  1.3547 +    if (flags & PR_RDWR) osflags |= O_RDWR;
  1.3548 +    if (flags & PR_APPEND) osflags |= O_APPEND;
  1.3549 +    if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
  1.3550 +    if (flags & PR_EXCL) osflags |= O_EXCL;
  1.3551 +    if (flags & PR_SYNC)
  1.3552 +    {
  1.3553 +#if defined(O_SYNC)
  1.3554 +        osflags |= O_SYNC;
  1.3555 +#elif defined(O_FSYNC)
  1.3556 +        osflags |= O_FSYNC;
  1.3557 +#else
  1.3558 +#error "Neither O_SYNC nor O_FSYNC is defined on this platform"
  1.3559 +#endif
  1.3560 +    }
  1.3561 +
  1.3562 +    /*
  1.3563 +    ** We have to hold the lock across the creation in order to
  1.3564 +    ** enforce the sematics of PR_Rename(). (see the latter for
  1.3565 +    ** more details)
  1.3566 +    */
  1.3567 +    if (flags & PR_CREATE_FILE)
  1.3568 +    {
  1.3569 +        osflags |= O_CREAT;
  1.3570 +        if (NULL !=_pr_rename_lock)
  1.3571 +            PR_Lock(_pr_rename_lock);
  1.3572 +    }
  1.3573 +
  1.3574 +    osfd = _md_iovector._open64(name, osflags, mode);
  1.3575 +    syserrno = errno;
  1.3576 +
  1.3577 +    if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
  1.3578 +        PR_Unlock(_pr_rename_lock);
  1.3579 +
  1.3580 +    if (osfd == -1)
  1.3581 +        pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
  1.3582 +    else
  1.3583 +    {
  1.3584 +        fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
  1.3585 +        if (fd == NULL) close(osfd);  /* $$$ whoops! this is bad $$$ */
  1.3586 +    }
  1.3587 +    return fd;
  1.3588 +}  /* PR_OpenFile */
  1.3589 +
  1.3590 +PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
  1.3591 +{
  1.3592 +    return PR_OpenFile(name, flags, mode);
  1.3593 +}  /* PR_Open */
  1.3594 +
  1.3595 +PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
  1.3596 +{
  1.3597 +    PRIntn rv = -1;
  1.3598 +
  1.3599 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.3600 +
  1.3601 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3602 +
  1.3603 +    rv = unlink(name);
  1.3604 +
  1.3605 +    if (rv == -1) {
  1.3606 +        pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
  1.3607 +        return PR_FAILURE;
  1.3608 +    } else
  1.3609 +        return PR_SUCCESS;
  1.3610 +}  /* PR_Delete */
  1.3611 +
  1.3612 +PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
  1.3613 +{
  1.3614 +    PRIntn rv;
  1.3615 +
  1.3616 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3617 +
  1.3618 +    switch (how)
  1.3619 +    {
  1.3620 +    case PR_ACCESS_READ_OK:
  1.3621 +        rv =  access(name, R_OK);
  1.3622 +        break;
  1.3623 +    case PR_ACCESS_WRITE_OK:
  1.3624 +        rv = access(name, W_OK);
  1.3625 +        break;
  1.3626 +    case PR_ACCESS_EXISTS:
  1.3627 +    default:
  1.3628 +        rv = access(name, F_OK);
  1.3629 +    }
  1.3630 +    if (0 == rv) return PR_SUCCESS;
  1.3631 +    pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
  1.3632 +    return PR_FAILURE;
  1.3633 +    
  1.3634 +}  /* PR_Access */
  1.3635 +
  1.3636 +PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
  1.3637 +{
  1.3638 +    PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
  1.3639 +    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  1.3640 +}  /* PR_GetFileInfo */
  1.3641 +
  1.3642 +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
  1.3643 +{
  1.3644 +    PRInt32 rv;
  1.3645 +
  1.3646 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.3647 +    rv = _PR_MD_GETFILEINFO64(fn, info);
  1.3648 +    return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  1.3649 +}  /* PR_GetFileInfo64 */
  1.3650 +
  1.3651 +PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
  1.3652 +{
  1.3653 +    PRIntn rv = -1;
  1.3654 +
  1.3655 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3656 +
  1.3657 +    /*
  1.3658 +    ** We have to acquire a lock here to stiffle anybody trying to create
  1.3659 +    ** a new file at the same time. And we have to hold that lock while we
  1.3660 +    ** test to see if the file exists and do the rename. The other place
  1.3661 +    ** where the lock is held is in PR_Open() when possibly creating a 
  1.3662 +    ** new file.
  1.3663 +    */
  1.3664 +
  1.3665 +    PR_Lock(_pr_rename_lock);
  1.3666 +    rv = access(to, F_OK);
  1.3667 +    if (0 == rv)
  1.3668 +    {
  1.3669 +        PR_SetError(PR_FILE_EXISTS_ERROR, 0);
  1.3670 +        rv = -1;
  1.3671 +    }
  1.3672 +    else
  1.3673 +    {
  1.3674 +        rv = rename(from, to);
  1.3675 +        if (rv == -1)
  1.3676 +            pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
  1.3677 +    }
  1.3678 +    PR_Unlock(_pr_rename_lock);
  1.3679 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.3680 +}  /* PR_Rename */
  1.3681 +
  1.3682 +PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
  1.3683 +{
  1.3684 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3685 +
  1.3686 +    if (NULL != dir->md.d)
  1.3687 +    {
  1.3688 +        if (closedir(dir->md.d) == -1)
  1.3689 +        {
  1.3690 +            _PR_MD_MAP_CLOSEDIR_ERROR(errno);
  1.3691 +            return PR_FAILURE;
  1.3692 +        }
  1.3693 +        dir->md.d = NULL;
  1.3694 +        PR_DELETE(dir);
  1.3695 +    }
  1.3696 +    return PR_SUCCESS;
  1.3697 +}  /* PR_CloseDir */
  1.3698 +
  1.3699 +PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
  1.3700 +{
  1.3701 +    PRInt32 rv = -1;
  1.3702 +
  1.3703 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3704 +
  1.3705 +    /*
  1.3706 +    ** This lock is used to enforce rename semantics as described
  1.3707 +    ** in PR_Rename.
  1.3708 +    */
  1.3709 +    if (NULL !=_pr_rename_lock)
  1.3710 +        PR_Lock(_pr_rename_lock);
  1.3711 +    rv = mkdir(name, mode);
  1.3712 +    if (-1 == rv)
  1.3713 +        pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
  1.3714 +    if (NULL !=_pr_rename_lock)
  1.3715 +        PR_Unlock(_pr_rename_lock);
  1.3716 +
  1.3717 +    return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
  1.3718 +}  /* PR_Makedir */
  1.3719 +
  1.3720 +PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
  1.3721 +{
  1.3722 +    return PR_MakeDir(name, mode);
  1.3723 +}  /* PR_Mkdir */
  1.3724 +
  1.3725 +PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
  1.3726 +{
  1.3727 +    PRInt32 rv;
  1.3728 +
  1.3729 +    if (pt_TestAbort()) return PR_FAILURE;
  1.3730 +
  1.3731 +    rv = rmdir(name);
  1.3732 +    if (0 == rv) {
  1.3733 +    return PR_SUCCESS;
  1.3734 +    } else {
  1.3735 +    pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
  1.3736 +    return PR_FAILURE;
  1.3737 +    }
  1.3738 +}  /* PR_Rmdir */
  1.3739 +
  1.3740 +
  1.3741 +PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
  1.3742 +{
  1.3743 +    DIR *osdir;
  1.3744 +    PRDir *dir = NULL;
  1.3745 +
  1.3746 +    if (pt_TestAbort()) return dir;
  1.3747 +
  1.3748 +    osdir = opendir(name);
  1.3749 +    if (osdir == NULL)
  1.3750 +        pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
  1.3751 +    else
  1.3752 +    {
  1.3753 +        dir = PR_NEWZAP(PRDir);
  1.3754 +        if (dir)
  1.3755 +            dir->md.d = osdir;
  1.3756 +        else
  1.3757 +            (void)closedir(osdir);
  1.3758 +    }
  1.3759 +    return dir;
  1.3760 +}  /* PR_OpenDir */
  1.3761 +
  1.3762 +static PRInt32 _pr_poll_with_poll(
  1.3763 +    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  1.3764 +{
  1.3765 +    PRInt32 ready = 0;
  1.3766 +    /*
  1.3767 +     * For restarting poll() if it is interrupted by a signal.
  1.3768 +     * We use these variables to figure out how much time has
  1.3769 +     * elapsed and how much of the timeout still remains.
  1.3770 +     */
  1.3771 +    PRIntervalTime start, elapsed, remaining;
  1.3772 +
  1.3773 +    if (pt_TestAbort()) return -1;
  1.3774 +
  1.3775 +    if (0 == npds) PR_Sleep(timeout);
  1.3776 +    else
  1.3777 +    {
  1.3778 +#define STACK_POLL_DESC_COUNT 64
  1.3779 +        struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
  1.3780 +        struct pollfd *syspoll;
  1.3781 +        PRIntn index, msecs;
  1.3782 +
  1.3783 +        if (npds <= STACK_POLL_DESC_COUNT)
  1.3784 +        {
  1.3785 +            syspoll = stack_syspoll;
  1.3786 +        }
  1.3787 +        else
  1.3788 +        {
  1.3789 +            PRThread *me = PR_GetCurrentThread();
  1.3790 +            if (npds > me->syspoll_count)
  1.3791 +            {
  1.3792 +                PR_Free(me->syspoll_list);
  1.3793 +                me->syspoll_list =
  1.3794 +                    (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
  1.3795 +                if (NULL == me->syspoll_list)
  1.3796 +                {
  1.3797 +                    me->syspoll_count = 0;
  1.3798 +                    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.3799 +                    return -1;
  1.3800 +                }
  1.3801 +                me->syspoll_count = npds;
  1.3802 +            }
  1.3803 +            syspoll = me->syspoll_list;
  1.3804 +        }
  1.3805 +
  1.3806 +        for (index = 0; index < npds; ++index)
  1.3807 +        {
  1.3808 +            PRInt16 in_flags_read = 0, in_flags_write = 0;
  1.3809 +            PRInt16 out_flags_read = 0, out_flags_write = 0;
  1.3810 +
  1.3811 +            if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  1.3812 +            {
  1.3813 +                if (pds[index].in_flags & PR_POLL_READ)
  1.3814 +                {
  1.3815 +                    in_flags_read = (pds[index].fd->methods->poll)(
  1.3816 +                        pds[index].fd,
  1.3817 +                        pds[index].in_flags & ~PR_POLL_WRITE,
  1.3818 +                        &out_flags_read);
  1.3819 +                }
  1.3820 +                if (pds[index].in_flags & PR_POLL_WRITE)
  1.3821 +                {
  1.3822 +                    in_flags_write = (pds[index].fd->methods->poll)(
  1.3823 +                        pds[index].fd,
  1.3824 +                        pds[index].in_flags & ~PR_POLL_READ,
  1.3825 +                        &out_flags_write);
  1.3826 +                }
  1.3827 +                if ((0 != (in_flags_read & out_flags_read))
  1.3828 +                || (0 != (in_flags_write & out_flags_write)))
  1.3829 +                {
  1.3830 +                    /* this one is ready right now */
  1.3831 +                    if (0 == ready)
  1.3832 +                    {
  1.3833 +                        /*
  1.3834 +                         * We will return without calling the system
  1.3835 +                         * poll function.  So zero the out_flags
  1.3836 +                         * fields of all the poll descriptors before
  1.3837 +                         * this one.
  1.3838 +                         */
  1.3839 +                        int i;
  1.3840 +                        for (i = 0; i < index; i++)
  1.3841 +                        {
  1.3842 +                            pds[i].out_flags = 0;
  1.3843 +                        }
  1.3844 +                    }
  1.3845 +                    ready += 1;
  1.3846 +                    pds[index].out_flags = out_flags_read | out_flags_write;
  1.3847 +                }
  1.3848 +                else
  1.3849 +                {
  1.3850 +                    /* now locate the NSPR layer at the bottom of the stack */
  1.3851 +                    PRFileDesc *bottom = PR_GetIdentitiesLayer(
  1.3852 +                        pds[index].fd, PR_NSPR_IO_LAYER);
  1.3853 +                    PR_ASSERT(NULL != bottom);  /* what to do about that? */
  1.3854 +                    pds[index].out_flags = 0;  /* pre-condition */
  1.3855 +                    if ((NULL != bottom)
  1.3856 +                    && (_PR_FILEDESC_OPEN == bottom->secret->state))
  1.3857 +                    {
  1.3858 +                        if (0 == ready)
  1.3859 +                        {
  1.3860 +                            syspoll[index].fd = bottom->secret->md.osfd;
  1.3861 +                            syspoll[index].events = 0;
  1.3862 +                            if (in_flags_read & PR_POLL_READ)
  1.3863 +                            {
  1.3864 +                                pds[index].out_flags |=
  1.3865 +                                    _PR_POLL_READ_SYS_READ;
  1.3866 +                                syspoll[index].events |= POLLIN;
  1.3867 +                            }
  1.3868 +                            if (in_flags_read & PR_POLL_WRITE)
  1.3869 +                            {
  1.3870 +                                pds[index].out_flags |=
  1.3871 +                                    _PR_POLL_READ_SYS_WRITE;
  1.3872 +                                syspoll[index].events |= POLLOUT;
  1.3873 +                            }
  1.3874 +                            if (in_flags_write & PR_POLL_READ)
  1.3875 +                            {
  1.3876 +                                pds[index].out_flags |=
  1.3877 +                                    _PR_POLL_WRITE_SYS_READ;
  1.3878 +                                syspoll[index].events |= POLLIN;
  1.3879 +                            }
  1.3880 +                            if (in_flags_write & PR_POLL_WRITE)
  1.3881 +                            {
  1.3882 +                                pds[index].out_flags |=
  1.3883 +                                    _PR_POLL_WRITE_SYS_WRITE;
  1.3884 +                                syspoll[index].events |= POLLOUT;
  1.3885 +                            }
  1.3886 +                            if (pds[index].in_flags & PR_POLL_EXCEPT)
  1.3887 +                                syspoll[index].events |= POLLPRI;
  1.3888 +                        }
  1.3889 +                    }
  1.3890 +                    else
  1.3891 +                    {
  1.3892 +                        if (0 == ready)
  1.3893 +                        {
  1.3894 +                            int i;
  1.3895 +                            for (i = 0; i < index; i++)
  1.3896 +                            {
  1.3897 +                                pds[i].out_flags = 0;
  1.3898 +                            }
  1.3899 +                        }
  1.3900 +                        ready += 1;  /* this will cause an abrupt return */
  1.3901 +                        pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
  1.3902 +                    }
  1.3903 +                }
  1.3904 +            }
  1.3905 +            else
  1.3906 +            {
  1.3907 +                /* make poll() ignore this entry */
  1.3908 +                syspoll[index].fd = -1;
  1.3909 +                syspoll[index].events = 0;
  1.3910 +                pds[index].out_flags = 0;
  1.3911 +            }
  1.3912 +        }
  1.3913 +        if (0 == ready)
  1.3914 +        {
  1.3915 +            switch (timeout)
  1.3916 +            {
  1.3917 +            case PR_INTERVAL_NO_WAIT: msecs = 0; break;
  1.3918 +            case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
  1.3919 +            default:
  1.3920 +                msecs = PR_IntervalToMilliseconds(timeout);
  1.3921 +                start = PR_IntervalNow();
  1.3922 +            }
  1.3923 +
  1.3924 +retry:
  1.3925 +            ready = poll(syspoll, npds, msecs);
  1.3926 +            if (-1 == ready)
  1.3927 +            {
  1.3928 +                PRIntn oserror = errno;
  1.3929 +
  1.3930 +                if (EINTR == oserror)
  1.3931 +                {
  1.3932 +                    if (timeout == PR_INTERVAL_NO_TIMEOUT)
  1.3933 +                        goto retry;
  1.3934 +                    else if (timeout == PR_INTERVAL_NO_WAIT)
  1.3935 +                        ready = 0;  /* don't retry, just time out */
  1.3936 +                    else
  1.3937 +                    {
  1.3938 +                        elapsed = (PRIntervalTime) (PR_IntervalNow()
  1.3939 +                                - start);
  1.3940 +                        if (elapsed > timeout)
  1.3941 +                            ready = 0;  /* timed out */
  1.3942 +                        else
  1.3943 +                        {
  1.3944 +                            remaining = timeout - elapsed;
  1.3945 +                            msecs = PR_IntervalToMilliseconds(remaining);
  1.3946 +                            goto retry;
  1.3947 +                        }
  1.3948 +                    }
  1.3949 +                }
  1.3950 +                else
  1.3951 +                {
  1.3952 +                    _PR_MD_MAP_POLL_ERROR(oserror);
  1.3953 +                }
  1.3954 +            }
  1.3955 +            else if (ready > 0)
  1.3956 +            {
  1.3957 +                for (index = 0; index < npds; ++index)
  1.3958 +                {
  1.3959 +                    PRInt16 out_flags = 0;
  1.3960 +                    if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  1.3961 +                    {
  1.3962 +                        if (0 != syspoll[index].revents)
  1.3963 +                        {
  1.3964 +                            if (syspoll[index].revents & POLLIN)
  1.3965 +                            {
  1.3966 +                                if (pds[index].out_flags
  1.3967 +                                & _PR_POLL_READ_SYS_READ)
  1.3968 +                                {
  1.3969 +                                    out_flags |= PR_POLL_READ;
  1.3970 +                                }
  1.3971 +                                if (pds[index].out_flags
  1.3972 +                                & _PR_POLL_WRITE_SYS_READ)
  1.3973 +                                {
  1.3974 +                                    out_flags |= PR_POLL_WRITE;
  1.3975 +                                }
  1.3976 +                            }
  1.3977 +                            if (syspoll[index].revents & POLLOUT)
  1.3978 +                            {
  1.3979 +                                if (pds[index].out_flags
  1.3980 +                                & _PR_POLL_READ_SYS_WRITE)
  1.3981 +                                {
  1.3982 +                                    out_flags |= PR_POLL_READ;
  1.3983 +                                }
  1.3984 +                                if (pds[index].out_flags
  1.3985 +                                & _PR_POLL_WRITE_SYS_WRITE)
  1.3986 +                                {
  1.3987 +                                    out_flags |= PR_POLL_WRITE;
  1.3988 +                                }
  1.3989 +                            }
  1.3990 +                            if (syspoll[index].revents & POLLPRI)
  1.3991 +                                out_flags |= PR_POLL_EXCEPT;
  1.3992 +                            if (syspoll[index].revents & POLLERR)
  1.3993 +                                out_flags |= PR_POLL_ERR;
  1.3994 +                            if (syspoll[index].revents & POLLNVAL)
  1.3995 +                                out_flags |= PR_POLL_NVAL;
  1.3996 +                            if (syspoll[index].revents & POLLHUP)
  1.3997 +                                out_flags |= PR_POLL_HUP;
  1.3998 +                        }
  1.3999 +                    }
  1.4000 +                    pds[index].out_flags = out_flags;
  1.4001 +                }
  1.4002 +            }
  1.4003 +        }
  1.4004 +    }
  1.4005 +    return ready;
  1.4006 +
  1.4007 +} /* _pr_poll_with_poll */
  1.4008 +
  1.4009 +#if defined(_PR_POLL_WITH_SELECT)
  1.4010 +/*
  1.4011 + * OSF1 and HPUX report the POLLHUP event for a socket when the
  1.4012 + * shutdown(SHUT_WR) operation is called for the remote end, even though
  1.4013 + * the socket is still writeable. Use select(), instead of poll(), to
  1.4014 + * workaround this problem.
  1.4015 + */
  1.4016 +static PRInt32 _pr_poll_with_select(
  1.4017 +    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  1.4018 +{
  1.4019 +    PRInt32 ready = 0;
  1.4020 +    /*
  1.4021 +     * For restarting select() if it is interrupted by a signal.
  1.4022 +     * We use these variables to figure out how much time has
  1.4023 +     * elapsed and how much of the timeout still remains.
  1.4024 +     */
  1.4025 +    PRIntervalTime start, elapsed, remaining;
  1.4026 +
  1.4027 +    if (pt_TestAbort()) return -1;
  1.4028 +
  1.4029 +    if (0 == npds) PR_Sleep(timeout);
  1.4030 +    else
  1.4031 +    {
  1.4032 +#define STACK_POLL_DESC_COUNT 64
  1.4033 +        int stack_selectfd[STACK_POLL_DESC_COUNT];
  1.4034 +        int *selectfd;
  1.4035 +		fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
  1.4036 +		struct timeval tv, *tvp;
  1.4037 +        PRIntn index, msecs, maxfd = 0;
  1.4038 +
  1.4039 +        if (npds <= STACK_POLL_DESC_COUNT)
  1.4040 +        {
  1.4041 +            selectfd = stack_selectfd;
  1.4042 +        }
  1.4043 +        else
  1.4044 +        {
  1.4045 +            PRThread *me = PR_GetCurrentThread();
  1.4046 +            if (npds > me->selectfd_count)
  1.4047 +            {
  1.4048 +                PR_Free(me->selectfd_list);
  1.4049 +                me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
  1.4050 +                if (NULL == me->selectfd_list)
  1.4051 +                {
  1.4052 +                    me->selectfd_count = 0;
  1.4053 +                    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.4054 +                    return -1;
  1.4055 +                }
  1.4056 +                me->selectfd_count = npds;
  1.4057 +            }
  1.4058 +            selectfd = me->selectfd_list;
  1.4059 +        }
  1.4060 +		FD_ZERO(&rd);
  1.4061 +		FD_ZERO(&wr);
  1.4062 +		FD_ZERO(&ex);
  1.4063 +
  1.4064 +        for (index = 0; index < npds; ++index)
  1.4065 +        {
  1.4066 +            PRInt16 in_flags_read = 0, in_flags_write = 0;
  1.4067 +            PRInt16 out_flags_read = 0, out_flags_write = 0;
  1.4068 +
  1.4069 +            if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  1.4070 +            {
  1.4071 +                if (pds[index].in_flags & PR_POLL_READ)
  1.4072 +                {
  1.4073 +                    in_flags_read = (pds[index].fd->methods->poll)(
  1.4074 +                        pds[index].fd,
  1.4075 +                        pds[index].in_flags & ~PR_POLL_WRITE,
  1.4076 +                        &out_flags_read);
  1.4077 +                }
  1.4078 +                if (pds[index].in_flags & PR_POLL_WRITE)
  1.4079 +                {
  1.4080 +                    in_flags_write = (pds[index].fd->methods->poll)(
  1.4081 +                        pds[index].fd,
  1.4082 +                        pds[index].in_flags & ~PR_POLL_READ,
  1.4083 +                        &out_flags_write);
  1.4084 +                }
  1.4085 +                if ((0 != (in_flags_read & out_flags_read))
  1.4086 +                || (0 != (in_flags_write & out_flags_write)))
  1.4087 +                {
  1.4088 +                    /* this one is ready right now */
  1.4089 +                    if (0 == ready)
  1.4090 +                    {
  1.4091 +                        /*
  1.4092 +                         * We will return without calling the system
  1.4093 +                         * poll function.  So zero the out_flags
  1.4094 +                         * fields of all the poll descriptors before
  1.4095 +                         * this one.
  1.4096 +                         */
  1.4097 +                        int i;
  1.4098 +                        for (i = 0; i < index; i++)
  1.4099 +                        {
  1.4100 +                            pds[i].out_flags = 0;
  1.4101 +                        }
  1.4102 +                    }
  1.4103 +                    ready += 1;
  1.4104 +                    pds[index].out_flags = out_flags_read | out_flags_write;
  1.4105 +                }
  1.4106 +                else
  1.4107 +                {
  1.4108 +                    /* now locate the NSPR layer at the bottom of the stack */
  1.4109 +                    PRFileDesc *bottom = PR_GetIdentitiesLayer(
  1.4110 +                        pds[index].fd, PR_NSPR_IO_LAYER);
  1.4111 +                    PR_ASSERT(NULL != bottom);  /* what to do about that? */
  1.4112 +                    pds[index].out_flags = 0;  /* pre-condition */
  1.4113 +                    if ((NULL != bottom)
  1.4114 +                    && (_PR_FILEDESC_OPEN == bottom->secret->state))
  1.4115 +                    {
  1.4116 +                        if (0 == ready)
  1.4117 +                        {
  1.4118 +                            PRBool add_to_rd = PR_FALSE;
  1.4119 +                            PRBool add_to_wr = PR_FALSE;
  1.4120 +                            PRBool add_to_ex = PR_FALSE;
  1.4121 +
  1.4122 +                            selectfd[index] = bottom->secret->md.osfd;
  1.4123 +                            if (in_flags_read & PR_POLL_READ)
  1.4124 +                            {
  1.4125 +                                pds[index].out_flags |=
  1.4126 +                                    _PR_POLL_READ_SYS_READ;
  1.4127 +                                add_to_rd = PR_TRUE;
  1.4128 +                            }
  1.4129 +                            if (in_flags_read & PR_POLL_WRITE)
  1.4130 +                            {
  1.4131 +                                pds[index].out_flags |=
  1.4132 +                                    _PR_POLL_READ_SYS_WRITE;
  1.4133 +                                add_to_wr = PR_TRUE;
  1.4134 +                            }
  1.4135 +                            if (in_flags_write & PR_POLL_READ)
  1.4136 +                            {
  1.4137 +                                pds[index].out_flags |=
  1.4138 +                                    _PR_POLL_WRITE_SYS_READ;
  1.4139 +                                add_to_rd = PR_TRUE;
  1.4140 +                            }
  1.4141 +                            if (in_flags_write & PR_POLL_WRITE)
  1.4142 +                            {
  1.4143 +                                pds[index].out_flags |=
  1.4144 +                                    _PR_POLL_WRITE_SYS_WRITE;
  1.4145 +                                add_to_wr = PR_TRUE;
  1.4146 +                            }
  1.4147 +                            if (pds[index].in_flags & PR_POLL_EXCEPT)
  1.4148 +                            {
  1.4149 +                                add_to_ex = PR_TRUE;
  1.4150 +                            }
  1.4151 +                            if ((selectfd[index] > maxfd) &&
  1.4152 +                                    (add_to_rd || add_to_wr || add_to_ex))
  1.4153 +                            {
  1.4154 +                                maxfd = selectfd[index];
  1.4155 +                                /*
  1.4156 +                                 * If maxfd is too large to be used with
  1.4157 +                                 * select, fall back to calling poll.
  1.4158 +                                 */
  1.4159 +                                if (maxfd >= FD_SETSIZE)
  1.4160 +                                    break;
  1.4161 +                            }
  1.4162 +                            if (add_to_rd)
  1.4163 +                            {
  1.4164 +                                FD_SET(bottom->secret->md.osfd, &rd);
  1.4165 +                                rdp = &rd;
  1.4166 +                            }
  1.4167 +                            if (add_to_wr)
  1.4168 +                            {
  1.4169 +                                FD_SET(bottom->secret->md.osfd, &wr);
  1.4170 +                                wrp = &wr;
  1.4171 +                            }
  1.4172 +                            if (add_to_ex)
  1.4173 +                            {
  1.4174 +                                FD_SET(bottom->secret->md.osfd, &ex);
  1.4175 +                                exp = &ex;
  1.4176 +                            }
  1.4177 +                        }
  1.4178 +                    }
  1.4179 +                    else
  1.4180 +                    {
  1.4181 +                        if (0 == ready)
  1.4182 +                        {
  1.4183 +                            int i;
  1.4184 +                            for (i = 0; i < index; i++)
  1.4185 +                            {
  1.4186 +                                pds[i].out_flags = 0;
  1.4187 +                            }
  1.4188 +                        }
  1.4189 +                        ready += 1;  /* this will cause an abrupt return */
  1.4190 +                        pds[index].out_flags = PR_POLL_NVAL;  /* bogii */
  1.4191 +                    }
  1.4192 +                }
  1.4193 +            }
  1.4194 +            else
  1.4195 +            {
  1.4196 +                pds[index].out_flags = 0;
  1.4197 +            }
  1.4198 +        }
  1.4199 +        if (0 == ready)
  1.4200 +        {
  1.4201 +			if (maxfd >= FD_SETSIZE)
  1.4202 +			{
  1.4203 +				/*
  1.4204 +				 * maxfd too large to be used with select, fall back to
  1.4205 +				 * calling poll
  1.4206 +				 */
  1.4207 +				return(_pr_poll_with_poll(pds, npds, timeout));
  1.4208 +			}
  1.4209 +            switch (timeout)
  1.4210 +            {
  1.4211 +            case PR_INTERVAL_NO_WAIT:
  1.4212 +				tv.tv_sec = 0;
  1.4213 +				tv.tv_usec = 0;
  1.4214 +				tvp = &tv;
  1.4215 +				break;
  1.4216 +            case PR_INTERVAL_NO_TIMEOUT:
  1.4217 +				tvp = NULL;
  1.4218 +				break;
  1.4219 +            default:
  1.4220 +                msecs = PR_IntervalToMilliseconds(timeout);
  1.4221 +				tv.tv_sec = msecs/PR_MSEC_PER_SEC;
  1.4222 +				tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
  1.4223 +				tvp = &tv;
  1.4224 +                start = PR_IntervalNow();
  1.4225 +            }
  1.4226 +
  1.4227 +retry:
  1.4228 +            ready = select(maxfd + 1, rdp, wrp, exp, tvp);
  1.4229 +            if (-1 == ready)
  1.4230 +            {
  1.4231 +                PRIntn oserror = errno;
  1.4232 +
  1.4233 +                if ((EINTR == oserror) || (EAGAIN == oserror))
  1.4234 +                {
  1.4235 +                    if (timeout == PR_INTERVAL_NO_TIMEOUT)
  1.4236 +                        goto retry;
  1.4237 +                    else if (timeout == PR_INTERVAL_NO_WAIT)
  1.4238 +                        ready = 0;  /* don't retry, just time out */
  1.4239 +                    else
  1.4240 +                    {
  1.4241 +                        elapsed = (PRIntervalTime) (PR_IntervalNow()
  1.4242 +                                - start);
  1.4243 +                        if (elapsed > timeout)
  1.4244 +                            ready = 0;  /* timed out */
  1.4245 +                        else
  1.4246 +                        {
  1.4247 +                            remaining = timeout - elapsed;
  1.4248 +                            msecs = PR_IntervalToMilliseconds(remaining);
  1.4249 +							tv.tv_sec = msecs/PR_MSEC_PER_SEC;
  1.4250 +							tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
  1.4251 +													PR_USEC_PER_MSEC;
  1.4252 +                            goto retry;
  1.4253 +                        }
  1.4254 +                    }
  1.4255 +                } else if (EBADF == oserror)
  1.4256 +                {
  1.4257 +					/* find all the bad fds */
  1.4258 +					ready = 0;
  1.4259 +                	for (index = 0; index < npds; ++index)
  1.4260 +					{
  1.4261 +                    	pds[index].out_flags = 0;
  1.4262 +            			if ((NULL != pds[index].fd) &&
  1.4263 +											(0 != pds[index].in_flags))
  1.4264 +						{
  1.4265 +							if (fcntl(selectfd[index], F_GETFL, 0) == -1)
  1.4266 +							{
  1.4267 +                    			pds[index].out_flags = PR_POLL_NVAL;
  1.4268 +								ready++;
  1.4269 +							}
  1.4270 +						}
  1.4271 +					}
  1.4272 +                } else 
  1.4273 +                    _PR_MD_MAP_SELECT_ERROR(oserror);
  1.4274 +            }
  1.4275 +            else if (ready > 0)
  1.4276 +            {
  1.4277 +                for (index = 0; index < npds; ++index)
  1.4278 +                {
  1.4279 +                    PRInt16 out_flags = 0;
  1.4280 +                    if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
  1.4281 +                    {
  1.4282 +						if (FD_ISSET(selectfd[index], &rd))
  1.4283 +						{
  1.4284 +							if (pds[index].out_flags
  1.4285 +							& _PR_POLL_READ_SYS_READ)
  1.4286 +							{
  1.4287 +								out_flags |= PR_POLL_READ;
  1.4288 +							}
  1.4289 +							if (pds[index].out_flags
  1.4290 +							& _PR_POLL_WRITE_SYS_READ)
  1.4291 +							{
  1.4292 +								out_flags |= PR_POLL_WRITE;
  1.4293 +							}
  1.4294 +						}
  1.4295 +						if (FD_ISSET(selectfd[index], &wr))
  1.4296 +						{
  1.4297 +							if (pds[index].out_flags
  1.4298 +							& _PR_POLL_READ_SYS_WRITE)
  1.4299 +							{
  1.4300 +								out_flags |= PR_POLL_READ;
  1.4301 +							}
  1.4302 +							if (pds[index].out_flags
  1.4303 +							& _PR_POLL_WRITE_SYS_WRITE)
  1.4304 +							{
  1.4305 +								out_flags |= PR_POLL_WRITE;
  1.4306 +							}
  1.4307 +						}
  1.4308 +						if (FD_ISSET(selectfd[index], &ex))
  1.4309 +							out_flags |= PR_POLL_EXCEPT;
  1.4310 +                    }
  1.4311 +                    pds[index].out_flags = out_flags;
  1.4312 +                }
  1.4313 +            }
  1.4314 +        }
  1.4315 +    }
  1.4316 +    return ready;
  1.4317 +
  1.4318 +} /* _pr_poll_with_select */
  1.4319 +#endif	/* _PR_POLL_WITH_SELECT */
  1.4320 +
  1.4321 +PR_IMPLEMENT(PRInt32) PR_Poll(
  1.4322 +    PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
  1.4323 +{
  1.4324 +#if defined(_PR_POLL_WITH_SELECT)
  1.4325 +	return(_pr_poll_with_select(pds, npds, timeout));
  1.4326 +#else
  1.4327 +	return(_pr_poll_with_poll(pds, npds, timeout));
  1.4328 +#endif
  1.4329 +}
  1.4330 +
  1.4331 +PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
  1.4332 +{
  1.4333 +    struct dirent *dp;
  1.4334 +
  1.4335 +    if (pt_TestAbort()) return NULL;
  1.4336 +
  1.4337 +    for (;;)
  1.4338 +    {
  1.4339 +        errno = 0;
  1.4340 +        dp = readdir(dir->md.d);
  1.4341 +        if (NULL == dp)
  1.4342 +        {
  1.4343 +            pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
  1.4344 +            return NULL;
  1.4345 +        }
  1.4346 +        if ((flags & PR_SKIP_DOT)
  1.4347 +            && ('.' == dp->d_name[0])
  1.4348 +            && (0 == dp->d_name[1])) continue;
  1.4349 +        if ((flags & PR_SKIP_DOT_DOT)
  1.4350 +            && ('.' == dp->d_name[0])
  1.4351 +            && ('.' == dp->d_name[1])
  1.4352 +            && (0 == dp->d_name[2])) continue;
  1.4353 +        if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
  1.4354 +            continue;
  1.4355 +        break;
  1.4356 +    }
  1.4357 +    dir->d.name = dp->d_name;
  1.4358 +    return &dir->d;
  1.4359 +}  /* PR_ReadDir */
  1.4360 +
  1.4361 +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
  1.4362 +{
  1.4363 +    PRIntn domain = PF_INET;
  1.4364 +
  1.4365 +    return PR_Socket(domain, SOCK_DGRAM, 0);
  1.4366 +}  /* PR_NewUDPSocket */
  1.4367 +
  1.4368 +PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
  1.4369 +{
  1.4370 +    PRIntn domain = PF_INET;
  1.4371 +
  1.4372 +    return PR_Socket(domain, SOCK_STREAM, 0);
  1.4373 +}  /* PR_NewTCPSocket */
  1.4374 +
  1.4375 +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
  1.4376 +{
  1.4377 +    return PR_Socket(af, SOCK_DGRAM, 0);
  1.4378 +}  /* PR_NewUDPSocket */
  1.4379 +
  1.4380 +PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
  1.4381 +{
  1.4382 +    return PR_Socket(af, SOCK_STREAM, 0);
  1.4383 +}  /* PR_NewTCPSocket */
  1.4384 +
  1.4385 +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
  1.4386 +{
  1.4387 +#ifdef SYMBIAN
  1.4388 +    /*
  1.4389 +     * For the platforms that don't have socketpair.
  1.4390 +     *
  1.4391 +     * Copied from prsocket.c, with the parameter f[] renamed fds[] and the
  1.4392 +     * _PR_CONNECT_DOES_NOT_BIND code removed.
  1.4393 +     */
  1.4394 +    PRFileDesc *listenSock;
  1.4395 +    PRNetAddr selfAddr, peerAddr;
  1.4396 +    PRUint16 port;
  1.4397 +
  1.4398 +    fds[0] = fds[1] = NULL;
  1.4399 +    listenSock = PR_NewTCPSocket();
  1.4400 +    if (listenSock == NULL) {
  1.4401 +        goto failed;
  1.4402 +    }
  1.4403 +    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
  1.4404 +    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
  1.4405 +        goto failed;
  1.4406 +    }
  1.4407 +    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
  1.4408 +        goto failed;
  1.4409 +    }
  1.4410 +    port = ntohs(selfAddr.inet.port);
  1.4411 +    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
  1.4412 +        goto failed;
  1.4413 +    }
  1.4414 +    fds[0] = PR_NewTCPSocket();
  1.4415 +    if (fds[0] == NULL) {
  1.4416 +        goto failed;
  1.4417 +    }
  1.4418 +    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
  1.4419 +
  1.4420 +    /*
  1.4421 +     * Only a thread is used to do the connect and accept.
  1.4422 +     * I am relying on the fact that PR_Connect returns
  1.4423 +     * successfully as soon as the connect request is put
  1.4424 +     * into the listen queue (but before PR_Accept is called).
  1.4425 +     * This is the behavior of the BSD socket code.  If
  1.4426 +     * connect does not return until accept is called, we
  1.4427 +     * will need to create another thread to call connect.
  1.4428 +     */
  1.4429 +    if (PR_Connect(fds[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
  1.4430 +            == PR_FAILURE) {
  1.4431 +        goto failed;
  1.4432 +    }
  1.4433 +    /*
  1.4434 +     * A malicious local process may connect to the listening
  1.4435 +     * socket, so we need to verify that the accepted connection
  1.4436 +     * is made from our own socket fds[0].
  1.4437 +     */
  1.4438 +    if (PR_GetSockName(fds[0], &selfAddr) == PR_FAILURE) {
  1.4439 +        goto failed;
  1.4440 +    }
  1.4441 +    fds[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
  1.4442 +    if (fds[1] == NULL) {
  1.4443 +        goto failed;
  1.4444 +    }
  1.4445 +    if (peerAddr.inet.port != selfAddr.inet.port) {
  1.4446 +        /* the connection we accepted is not from fds[0] */
  1.4447 +        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1.4448 +        goto failed;
  1.4449 +    }
  1.4450 +    PR_Close(listenSock);
  1.4451 +    return PR_SUCCESS;
  1.4452 +
  1.4453 +failed:
  1.4454 +    if (listenSock) {
  1.4455 +        PR_Close(listenSock);
  1.4456 +    }
  1.4457 +    if (fds[0]) {
  1.4458 +        PR_Close(fds[0]);
  1.4459 +    }
  1.4460 +    if (fds[1]) {
  1.4461 +        PR_Close(fds[1]);
  1.4462 +    }
  1.4463 +    return PR_FAILURE;
  1.4464 +#else
  1.4465 +    PRInt32 osfd[2];
  1.4466 +
  1.4467 +    if (pt_TestAbort()) return PR_FAILURE;
  1.4468 +
  1.4469 +    if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
  1.4470 +        pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
  1.4471 +        return PR_FAILURE;
  1.4472 +    }
  1.4473 +
  1.4474 +    fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
  1.4475 +    if (fds[0] == NULL) {
  1.4476 +        close(osfd[0]);
  1.4477 +        close(osfd[1]);
  1.4478 +        return PR_FAILURE;
  1.4479 +    }
  1.4480 +    fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
  1.4481 +    if (fds[1] == NULL) {
  1.4482 +        PR_Close(fds[0]);
  1.4483 +        close(osfd[1]);
  1.4484 +        return PR_FAILURE;
  1.4485 +    }
  1.4486 +    return PR_SUCCESS;
  1.4487 +#endif
  1.4488 +}  /* PR_NewTCPSocketPair */
  1.4489 +
  1.4490 +PR_IMPLEMENT(PRStatus) PR_CreatePipe(
  1.4491 +    PRFileDesc **readPipe,
  1.4492 +    PRFileDesc **writePipe
  1.4493 +)
  1.4494 +{
  1.4495 +    int pipefd[2];
  1.4496 +
  1.4497 +    if (pt_TestAbort()) return PR_FAILURE;
  1.4498 +
  1.4499 +    if (pipe(pipefd) == -1)
  1.4500 +    {
  1.4501 +    /* XXX map pipe error */
  1.4502 +        PR_SetError(PR_UNKNOWN_ERROR, errno);
  1.4503 +        return PR_FAILURE;
  1.4504 +    }
  1.4505 +    *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
  1.4506 +    if (NULL == *readPipe)
  1.4507 +    {
  1.4508 +        close(pipefd[0]);
  1.4509 +        close(pipefd[1]);
  1.4510 +        return PR_FAILURE;
  1.4511 +    }
  1.4512 +    *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
  1.4513 +    if (NULL == *writePipe)
  1.4514 +    {
  1.4515 +        PR_Close(*readPipe);
  1.4516 +        close(pipefd[1]);
  1.4517 +        return PR_FAILURE;
  1.4518 +    }
  1.4519 +    return PR_SUCCESS;
  1.4520 +}
  1.4521 +
  1.4522 +/*
  1.4523 +** Set the inheritance attribute of a file descriptor.
  1.4524 +*/
  1.4525 +PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
  1.4526 +    PRFileDesc *fd,
  1.4527 +    PRBool inheritable)
  1.4528 +{
  1.4529 +    /*
  1.4530 +     * Only a non-layered, NSPR file descriptor can be inherited
  1.4531 +     * by a child process.
  1.4532 +     */
  1.4533 +    if (fd->identity != PR_NSPR_IO_LAYER)
  1.4534 +    {
  1.4535 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.4536 +        return PR_FAILURE;
  1.4537 +    }
  1.4538 +    if (fd->secret->inheritable != inheritable)
  1.4539 +    {
  1.4540 +        if (fcntl(fd->secret->md.osfd, F_SETFD,
  1.4541 +        inheritable ? 0 : FD_CLOEXEC) == -1)
  1.4542 +        {
  1.4543 +            _PR_MD_MAP_DEFAULT_ERROR(errno);
  1.4544 +            return PR_FAILURE;
  1.4545 +        }
  1.4546 +        fd->secret->inheritable = (_PRTriStateBool) inheritable;
  1.4547 +    }
  1.4548 +    return PR_SUCCESS;
  1.4549 +}
  1.4550 +
  1.4551 +/*****************************************************************************/
  1.4552 +/***************************** I/O friends methods ***************************/
  1.4553 +/*****************************************************************************/
  1.4554 +
  1.4555 +PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
  1.4556 +{
  1.4557 +    PRFileDesc *fd;
  1.4558 +
  1.4559 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.4560 +    fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
  1.4561 +    if (NULL == fd) close(osfd);
  1.4562 +    return fd;
  1.4563 +}  /* PR_ImportFile */
  1.4564 +
  1.4565 +PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
  1.4566 +{
  1.4567 +    PRFileDesc *fd;
  1.4568 +
  1.4569 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.4570 +    fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
  1.4571 +    if (NULL == fd) close(osfd);
  1.4572 +    return fd;
  1.4573 +}  /* PR_ImportPipe */
  1.4574 +
  1.4575 +PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
  1.4576 +{
  1.4577 +    PRFileDesc *fd;
  1.4578 +
  1.4579 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.4580 +    fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
  1.4581 +    if (NULL == fd) close(osfd);
  1.4582 +#ifdef _PR_NEED_SECRET_AF
  1.4583 +    if (NULL != fd) fd->secret->af = PF_INET;
  1.4584 +#endif
  1.4585 +    return fd;
  1.4586 +}  /* PR_ImportTCPSocket */
  1.4587 +
  1.4588 +PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
  1.4589 +{
  1.4590 +    PRFileDesc *fd;
  1.4591 +
  1.4592 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.4593 +    fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
  1.4594 +    if (NULL == fd) close(osfd);
  1.4595 +    return fd;
  1.4596 +}  /* PR_ImportUDPSocket */
  1.4597 +
  1.4598 +PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
  1.4599 +{
  1.4600 +    PRFileDesc *fd;
  1.4601 +
  1.4602 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.4603 +
  1.4604 +    fd = _PR_Getfd();
  1.4605 +
  1.4606 +    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.4607 +    else
  1.4608 +    {
  1.4609 +        fd->secret->md.osfd = osfd;
  1.4610 +        fd->secret->inheritable = _PR_TRI_FALSE;
  1.4611 +    	fd->secret->state = _PR_FILEDESC_OPEN;
  1.4612 +        fd->methods = PR_GetSocketPollFdMethods();
  1.4613 +    }
  1.4614 +
  1.4615 +    return fd;
  1.4616 +}  /* PR_CreateSocketPollFD */
  1.4617 +
  1.4618 +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
  1.4619 +{
  1.4620 +    if (NULL == fd)
  1.4621 +    {
  1.4622 +        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1.4623 +        return PR_FAILURE;
  1.4624 +    }
  1.4625 +    fd->secret->state = _PR_FILEDESC_CLOSED;
  1.4626 +    _PR_Putfd(fd);
  1.4627 +    return PR_SUCCESS;
  1.4628 +}  /* PR_DestroySocketPollFd */
  1.4629 +
  1.4630 +PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
  1.4631 +{
  1.4632 +    PRInt32 osfd = -1;
  1.4633 +    bottom = (NULL == bottom) ?
  1.4634 +        NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
  1.4635 +    if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.4636 +    else osfd = bottom->secret->md.osfd;
  1.4637 +    return osfd;
  1.4638 +}  /* PR_FileDesc2NativeHandle */
  1.4639 +
  1.4640 +PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
  1.4641 +    PRInt32 handle)
  1.4642 +{
  1.4643 +    if (fd) fd->secret->md.osfd = handle;
  1.4644 +}  /*  PR_ChangeFileDescNativeHandle*/
  1.4645 +
  1.4646 +PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
  1.4647 +{
  1.4648 +    PRStatus status = PR_SUCCESS;
  1.4649 +
  1.4650 +    if (pt_TestAbort()) return PR_FAILURE;
  1.4651 +
  1.4652 +    PR_Lock(_pr_flock_lock);
  1.4653 +    while (-1 == fd->secret->lockCount)
  1.4654 +        PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
  1.4655 +    if (0 == fd->secret->lockCount)
  1.4656 +    {
  1.4657 +        fd->secret->lockCount = -1;
  1.4658 +        PR_Unlock(_pr_flock_lock);
  1.4659 +        status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
  1.4660 +        PR_Lock(_pr_flock_lock);
  1.4661 +        fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
  1.4662 +        PR_NotifyAllCondVar(_pr_flock_cv);
  1.4663 +    }
  1.4664 +    else
  1.4665 +    {
  1.4666 +        fd->secret->lockCount += 1;
  1.4667 +    }
  1.4668 +    PR_Unlock(_pr_flock_lock);
  1.4669 + 
  1.4670 +    return status;
  1.4671 +}  /* PR_LockFile */
  1.4672 +
  1.4673 +PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
  1.4674 +{
  1.4675 +    PRStatus status = PR_SUCCESS;
  1.4676 +
  1.4677 +    if (pt_TestAbort()) return PR_FAILURE;
  1.4678 +
  1.4679 +    PR_Lock(_pr_flock_lock);
  1.4680 +    if (0 == fd->secret->lockCount)
  1.4681 +    {
  1.4682 +        status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
  1.4683 +        if (PR_SUCCESS == status) fd->secret->lockCount = 1;
  1.4684 +    }
  1.4685 +    else fd->secret->lockCount += 1;
  1.4686 +    PR_Unlock(_pr_flock_lock);
  1.4687 + 
  1.4688 +    return status;
  1.4689 +}  /* PR_TLockFile */
  1.4690 +
  1.4691 +PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
  1.4692 +{
  1.4693 +    PRStatus status = PR_SUCCESS;
  1.4694 +
  1.4695 +    if (pt_TestAbort()) return PR_FAILURE;
  1.4696 +
  1.4697 +    PR_Lock(_pr_flock_lock);
  1.4698 +    if (fd->secret->lockCount == 1)
  1.4699 +    {
  1.4700 +        status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
  1.4701 +        if (PR_SUCCESS == status) fd->secret->lockCount = 0;
  1.4702 +    }
  1.4703 +    else fd->secret->lockCount -= 1;
  1.4704 +    PR_Unlock(_pr_flock_lock);
  1.4705 +
  1.4706 +    return status;
  1.4707 +}
  1.4708 +
  1.4709 +/*
  1.4710 + * The next two entry points should not be in the API, but they are
  1.4711 + * defined here for historical (or hysterical) reasons.
  1.4712 + */
  1.4713 +
  1.4714 +PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
  1.4715 +{
  1.4716 +#if defined(AIX) || defined(SYMBIAN)
  1.4717 +    return sysconf(_SC_OPEN_MAX);
  1.4718 +#else
  1.4719 +    struct rlimit rlim;
  1.4720 +
  1.4721 +    if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  1.4722 +       return -1;
  1.4723 +
  1.4724 +    return rlim.rlim_max;
  1.4725 +#endif
  1.4726 +}
  1.4727 +
  1.4728 +PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
  1.4729 +{
  1.4730 +#if defined(AIX) || defined(SYMBIAN)
  1.4731 +    return -1;
  1.4732 +#else
  1.4733 +    struct rlimit rlim;
  1.4734 +    PRInt32 tableMax = PR_GetSysfdTableMax();
  1.4735 +
  1.4736 +    if (tableMax < 0) return -1;
  1.4737 +    rlim.rlim_max = tableMax;
  1.4738 +
  1.4739 +    /* Grow as much as we can; even if too big */
  1.4740 +    if ( rlim.rlim_max < table_size )
  1.4741 +        rlim.rlim_cur = rlim.rlim_max;
  1.4742 +    else
  1.4743 +        rlim.rlim_cur = table_size;
  1.4744 +
  1.4745 +    if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0) 
  1.4746 +        return -1;
  1.4747 +
  1.4748 +    return rlim.rlim_cur;
  1.4749 +#endif
  1.4750 +}
  1.4751 +
  1.4752 +/*
  1.4753 + * PR_Stat is supported for backward compatibility; some existing Java
  1.4754 + * code uses it.  New code should use PR_GetFileInfo.
  1.4755 + */
  1.4756 +
  1.4757 +#ifndef NO_NSPR_10_SUPPORT
  1.4758 +PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
  1.4759 +{
  1.4760 +    static PRBool unwarned = PR_TRUE;
  1.4761 +    if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
  1.4762 +
  1.4763 +    if (pt_TestAbort()) return -1;
  1.4764 +
  1.4765 +    if (-1 == stat(name, buf)) {
  1.4766 +        pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
  1.4767 +        return -1;
  1.4768 +    } else {
  1.4769 +        return 0;
  1.4770 +    }
  1.4771 +}
  1.4772 +#endif /* ! NO_NSPR_10_SUPPORT */
  1.4773 +
  1.4774 +
  1.4775 +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
  1.4776 +{
  1.4777 +    static PRBool unwarned = PR_TRUE;
  1.4778 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
  1.4779 +    memset(set, 0, sizeof(PR_fd_set));
  1.4780 +}
  1.4781 +
  1.4782 +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
  1.4783 +{
  1.4784 +    static PRBool unwarned = PR_TRUE;
  1.4785 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
  1.4786 +    PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
  1.4787 +
  1.4788 +    set->harray[set->hsize++] = fh;
  1.4789 +}
  1.4790 +
  1.4791 +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
  1.4792 +{
  1.4793 +    PRUint32 index, index2;
  1.4794 +    static PRBool unwarned = PR_TRUE;
  1.4795 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
  1.4796 +
  1.4797 +    for (index = 0; index<set->hsize; index++)
  1.4798 +       if (set->harray[index] == fh) {
  1.4799 +           for (index2=index; index2 < (set->hsize-1); index2++) {
  1.4800 +               set->harray[index2] = set->harray[index2+1];
  1.4801 +           }
  1.4802 +           set->hsize--;
  1.4803 +           break;
  1.4804 +       }
  1.4805 +}
  1.4806 +
  1.4807 +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
  1.4808 +{
  1.4809 +    PRUint32 index;
  1.4810 +    static PRBool unwarned = PR_TRUE;
  1.4811 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
  1.4812 +    for (index = 0; index<set->hsize; index++)
  1.4813 +       if (set->harray[index] == fh) {
  1.4814 +           return 1;
  1.4815 +       }
  1.4816 +    return 0;
  1.4817 +}
  1.4818 +
  1.4819 +PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
  1.4820 +{
  1.4821 +    static PRBool unwarned = PR_TRUE;
  1.4822 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
  1.4823 +    PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
  1.4824 +
  1.4825 +    set->narray[set->nsize++] = fd;
  1.4826 +}
  1.4827 +
  1.4828 +PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
  1.4829 +{
  1.4830 +    PRUint32 index, index2;
  1.4831 +    static PRBool unwarned = PR_TRUE;
  1.4832 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
  1.4833 +
  1.4834 +    for (index = 0; index<set->nsize; index++)
  1.4835 +       if (set->narray[index] == fd) {
  1.4836 +           for (index2=index; index2 < (set->nsize-1); index2++) {
  1.4837 +               set->narray[index2] = set->narray[index2+1];
  1.4838 +           }
  1.4839 +           set->nsize--;
  1.4840 +           break;
  1.4841 +       }
  1.4842 +}
  1.4843 +
  1.4844 +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
  1.4845 +{
  1.4846 +    PRUint32 index;
  1.4847 +    static PRBool unwarned = PR_TRUE;
  1.4848 +    if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
  1.4849 +    for (index = 0; index<set->nsize; index++)
  1.4850 +       if (set->narray[index] == fd) {
  1.4851 +           return 1;
  1.4852 +       }
  1.4853 +    return 0;
  1.4854 +}
  1.4855 +
  1.4856 +#include <sys/types.h>
  1.4857 +#include <sys/time.h>
  1.4858 +#if !defined(HPUX) \
  1.4859 +    && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
  1.4860 +#include <sys/select.h>
  1.4861 +#endif
  1.4862 +
  1.4863 +static PRInt32
  1.4864 +_PR_getset(PR_fd_set *pr_set, fd_set *set)
  1.4865 +{
  1.4866 +    PRUint32 index;
  1.4867 +    PRInt32 max = 0;
  1.4868 +
  1.4869 +    if (!pr_set)
  1.4870 +        return 0;
  1.4871 +   
  1.4872 +    FD_ZERO(set);
  1.4873 +
  1.4874 +    /* First set the pr file handle osfds */
  1.4875 +    for (index=0; index<pr_set->hsize; index++) {
  1.4876 +        FD_SET(pr_set->harray[index]->secret->md.osfd, set);
  1.4877 +        if (pr_set->harray[index]->secret->md.osfd > max)
  1.4878 +            max = pr_set->harray[index]->secret->md.osfd;
  1.4879 +    }
  1.4880 +    /* Second set the native osfds */
  1.4881 +    for (index=0; index<pr_set->nsize; index++) {
  1.4882 +        FD_SET(pr_set->narray[index], set);
  1.4883 +        if (pr_set->narray[index] > max)
  1.4884 +            max = pr_set->narray[index];
  1.4885 +    }
  1.4886 +    return max;
  1.4887 +}
  1.4888 +
  1.4889 +static void
  1.4890 +_PR_setset(PR_fd_set *pr_set, fd_set *set)
  1.4891 +{
  1.4892 +    PRUint32 index, last_used;
  1.4893 +
  1.4894 +    if (!pr_set)
  1.4895 +        return;
  1.4896 +
  1.4897 +    for (last_used=0, index=0; index<pr_set->hsize; index++) {
  1.4898 +        if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
  1.4899 +            pr_set->harray[last_used++] = pr_set->harray[index];
  1.4900 +        }
  1.4901 +    }
  1.4902 +    pr_set->hsize = last_used;
  1.4903 +
  1.4904 +    for (last_used=0, index=0; index<pr_set->nsize; index++) {
  1.4905 +        if ( FD_ISSET(pr_set->narray[index], set) ) {
  1.4906 +            pr_set->narray[last_used++] = pr_set->narray[index];
  1.4907 +        }
  1.4908 +    }
  1.4909 +    pr_set->nsize = last_used;
  1.4910 +}
  1.4911 +
  1.4912 +PR_IMPLEMENT(PRInt32) PR_Select(
  1.4913 +    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
  1.4914 +    PR_fd_set *pr_ex, PRIntervalTime timeout)
  1.4915 +{
  1.4916 +    fd_set rd, wr, ex;
  1.4917 +    struct timeval tv, *tvp;
  1.4918 +    PRInt32 max, max_fd;
  1.4919 +    PRInt32 rv;
  1.4920 +    /*
  1.4921 +     * For restarting select() if it is interrupted by a Unix signal.
  1.4922 +     * We use these variables to figure out how much time has elapsed
  1.4923 +     * and how much of the timeout still remains.
  1.4924 +     */
  1.4925 +    PRIntervalTime start, elapsed, remaining;
  1.4926 +
  1.4927 +    static PRBool unwarned = PR_TRUE;
  1.4928 +    if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
  1.4929 +
  1.4930 +    FD_ZERO(&rd);
  1.4931 +    FD_ZERO(&wr);
  1.4932 +    FD_ZERO(&ex);
  1.4933 +
  1.4934 +    max_fd = _PR_getset(pr_rd, &rd);
  1.4935 +    max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
  1.4936 +    max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
  1.4937 +
  1.4938 +    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  1.4939 +        tvp = NULL;
  1.4940 +    } else {
  1.4941 +        tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
  1.4942 +        tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  1.4943 +                timeout - PR_SecondsToInterval(tv.tv_sec));
  1.4944 +        tvp = &tv;
  1.4945 +        start = PR_IntervalNow();
  1.4946 +    }
  1.4947 +
  1.4948 +retry:
  1.4949 +    rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
  1.4950 +        (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
  1.4951 +
  1.4952 +    if (rv == -1 && errno == EINTR) {
  1.4953 +        if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  1.4954 +            goto retry;
  1.4955 +        } else {
  1.4956 +            elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
  1.4957 +            if (elapsed > timeout) {
  1.4958 +                rv = 0;  /* timed out */
  1.4959 +            } else {
  1.4960 +                remaining = timeout - elapsed;
  1.4961 +                tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
  1.4962 +                tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
  1.4963 +                        remaining - PR_SecondsToInterval(tv.tv_sec));
  1.4964 +                goto retry;
  1.4965 +            }
  1.4966 +        }
  1.4967 +    }
  1.4968 +
  1.4969 +    if (rv > 0) {
  1.4970 +        _PR_setset(pr_rd, &rd);
  1.4971 +        _PR_setset(pr_wr, &wr);
  1.4972 +        _PR_setset(pr_ex, &ex);
  1.4973 +    } else if (rv == -1) {
  1.4974 +        pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
  1.4975 +    }
  1.4976 +    return rv;
  1.4977 +}
  1.4978 +#endif /* defined(_PR_PTHREADS) */
  1.4979 +
  1.4980 +#ifdef MOZ_UNICODE 
  1.4981 +/* ================ UTF16 Interfaces ================================ */
  1.4982 +PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
  1.4983 +    const PRUnichar *name, PRIntn flags, PRIntn mode)
  1.4984 +{
  1.4985 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.4986 +    return NULL;
  1.4987 +}
  1.4988 +
  1.4989 +PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
  1.4990 +{
  1.4991 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.4992 +    return PR_FAILURE;
  1.4993 +}
  1.4994 +
  1.4995 +PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
  1.4996 +{
  1.4997 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.4998 +    return NULL;
  1.4999 +}
  1.5000 +
  1.5001 +PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
  1.5002 +{
  1.5003 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.5004 +    return NULL;
  1.5005 +}
  1.5006 +
  1.5007 +PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
  1.5008 +{
  1.5009 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1.5010 +    return PR_FAILURE;
  1.5011 +}
  1.5012 +/* ================ UTF16 Interfaces ================================ */
  1.5013 +#endif /* MOZ_UNICODE */
  1.5014 +
  1.5015 +/* ptio.c */

mercurial