Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(609)

Side by Side Diff: nspr/pr/src/pthreads/ptio.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nspr/pr/src/misc/prtrace.c ('k') | nspr/pr/src/pthreads/ptmisc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 = &wr;
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 = &wr;
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 = &wr;
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 */
OLDNEW
« no previous file with comments | « nspr/pr/src/misc/prtrace.c ('k') | nspr/pr/src/pthreads/ptmisc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698