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