nsprpub/pr/src/pthreads/ptio.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial