comparison nspr/pr/src/pthreads/ptio.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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 send */
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_done;
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_done;
523
524 } else if ((rv == 0) ||
525 ((errno == EINTR) || (errno == EAGAIN))) {
526 if (rv == 0) { /* select timed out */
527 if (wait_for_remaining)
528 now += remaining;
529 else
530 now += PR_MillisecondsToInterval(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_done;
538 } else
539 remaining = op->timeout - elapsed;
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 all cases */
603 || ((events & POLLOUT) && (revents & POLLHUP)))
604 /* write op & hup */
605 {
606 op->result.code = -1;
607 if (POLLNVAL & revents) op->syserrno = EBADF;
608 else if (POLLHUP & revents) op->syserrno = EPIPE;
609 op->status = pt_continuation_done;
610 } else {
611 if (op->function(op, revents))
612 op->status = pt_continuation_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 all cases */
658 || ((events & POLLOUT) && (revents & POLLHUP)))
659 /* write op & hup */
660 {
661 op->result.code = -1;
662 if (POLLNVAL & revents) op->syserrno = EBADF;
663 else if (POLLHUP & revents) op->syserrno = EPIPE;
664 op->status = pt_continuation_done;
665 } else {
666 if (op->function(op, revents))
667 {
668 op->status = pt_continuation_done;
669 }
670 }
671 } else if ((rv == 0) ||
672 ((errno == EINTR) || (errno == EAGAIN))) {
673 if (rv == 0) /* poll timed out */
674 {
675 if (wait_for_remaining)
676 now += remaining;
677 else
678 now += PR_MillisecondsToInterval(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_done;
687 } else
688 remaining = op->timeout - elapsed;
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_struct->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 {
2858 PRIntn value;
2859 length = sizeof(PRIntn);
2860 rv = getsockopt(
2861 fd->secret->md.osfd, level, name, (char*)&value, &length);
2862 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2863 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
2864 break;
2865 }
2866 case PR_SockOpt_McastLoopback:
2867 {
2868 PRUint8 xbool;
2869 length = sizeof(xbool);
2870 rv = getsockopt(
2871 fd->secret->md.osfd, level, name,
2872 (char*)&xbool, &length);
2873 PR_ASSERT((-1 == rv) || (sizeof(xbool) == length));
2874 data->value.mcast_loopback = (0 == xbool) ? PR_FALSE : PR_TRUE;
2875 break;
2876 }
2877 case PR_SockOpt_RecvBufferSize:
2878 case PR_SockOpt_SendBufferSize:
2879 case PR_SockOpt_MaxSegment:
2880 {
2881 PRIntn value;
2882 length = sizeof(PRIntn);
2883 rv = getsockopt(
2884 fd->secret->md.osfd, level, name, (char*)&value, &length);
2885 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2886 data->value.recv_buffer_size = value;
2887 break;
2888 }
2889 case PR_SockOpt_IpTimeToLive:
2890 case PR_SockOpt_IpTypeOfService:
2891 {
2892 length = sizeof(PRUintn);
2893 rv = getsockopt(
2894 fd->secret->md.osfd, level, name,
2895 (char*)&data->value.ip_ttl, &length);
2896 PR_ASSERT((-1 == rv) || (sizeof(PRIntn) == length));
2897 break;
2898 }
2899 case PR_SockOpt_McastTimeToLive:
2900 {
2901 PRUint8 ttl;
2902 length = sizeof(ttl);
2903 rv = getsockopt(
2904 fd->secret->md.osfd, level, name,
2905 (char*)&ttl, &length);
2906 PR_ASSERT((-1 == rv) || (sizeof(ttl) == length));
2907 data->value.mcast_ttl = ttl;
2908 break;
2909 }
2910 case PR_SockOpt_AddMember:
2911 case PR_SockOpt_DropMember:
2912 {
2913 struct ip_mreq mreq;
2914 length = sizeof(mreq);
2915 rv = getsockopt(
2916 fd->secret->md.osfd, level, name, (char*)&mreq, &length);
2917 PR_ASSERT((-1 == rv) || (sizeof(mreq) == length));
2918 data->value.add_member.mcaddr.inet.ip =
2919 mreq.imr_multiaddr.s_addr;
2920 data->value.add_member.ifaddr.inet.ip =
2921 mreq.imr_interface.s_addr;
2922 break;
2923 }
2924 case PR_SockOpt_McastInterface:
2925 {
2926 length = sizeof(data->value.mcast_if.inet.ip);
2927 rv = getsockopt(
2928 fd->secret->md.osfd, level, name,
2929 (char*)&data->value.mcast_if.inet.ip, &length);
2930 PR_ASSERT((-1 == rv)
2931 || (sizeof(data->value.mcast_if.inet.ip) == length));
2932 break;
2933 }
2934 default:
2935 PR_NOT_REACHED("Unknown socket option");
2936 break;
2937 }
2938 if (-1 == rv) _PR_MD_MAP_GETSOCKOPT_ERROR(errno);
2939 }
2940 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
2941 } /* pt_GetSocketOption */
2942
2943 static PRStatus pt_SetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
2944 {
2945 PRIntn rv;
2946 PRInt32 level, name;
2947
2948 /*
2949 * PR_SockOpt_Nonblocking is a special case that does not
2950 * translate to a setsockopt call.
2951 */
2952 if (PR_SockOpt_Nonblocking == data->option)
2953 {
2954 fd->secret->nonblocking = data->value.non_blocking;
2955 return PR_SUCCESS;
2956 }
2957
2958 rv = _PR_MapOptionName(data->option, &level, &name);
2959 if (PR_SUCCESS == rv)
2960 {
2961 switch (data->option)
2962 {
2963 case PR_SockOpt_Linger:
2964 {
2965 struct linger linger;
2966 linger.l_onoff = data->value.linger.polarity;
2967 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
2968 rv = setsockopt(
2969 fd->secret->md.osfd, level, name, (char*)&linger, sizeof(linger));
2970 break;
2971 }
2972 case PR_SockOpt_Reuseaddr:
2973 case PR_SockOpt_Keepalive:
2974 case PR_SockOpt_NoDelay:
2975 case PR_SockOpt_Broadcast:
2976 {
2977 PRIntn value = (data->value.reuse_addr) ? 1 : 0;
2978 rv = setsockopt(
2979 fd->secret->md.osfd, level, name,
2980 (char*)&value, sizeof(PRIntn));
2981 #ifdef LINUX
2982 /* for pt_LinuxSendFile */
2983 if (name == TCP_NODELAY && rv == 0) {
2984 fd->secret->md.tcp_nodelay = value;
2985 }
2986 #endif
2987 break;
2988 }
2989 case PR_SockOpt_McastLoopback:
2990 {
2991 PRUint8 xbool = data->value.mcast_loopback ? 1 : 0;
2992 rv = setsockopt(
2993 fd->secret->md.osfd, level, name,
2994 (char*)&xbool, sizeof(xbool));
2995 break;
2996 }
2997 case PR_SockOpt_RecvBufferSize:
2998 case PR_SockOpt_SendBufferSize:
2999 case PR_SockOpt_MaxSegment:
3000 {
3001 PRIntn value = data->value.recv_buffer_size;
3002 rv = setsockopt(
3003 fd->secret->md.osfd, level, name,
3004 (char*)&value, sizeof(PRIntn));
3005 break;
3006 }
3007 case PR_SockOpt_IpTimeToLive:
3008 case PR_SockOpt_IpTypeOfService:
3009 {
3010 rv = setsockopt(
3011 fd->secret->md.osfd, level, name,
3012 (char*)&data->value.ip_ttl, sizeof(PRUintn));
3013 break;
3014 }
3015 case PR_SockOpt_McastTimeToLive:
3016 {
3017 PRUint8 ttl = data->value.mcast_ttl;
3018 rv = setsockopt(
3019 fd->secret->md.osfd, level, name,
3020 (char*)&ttl, sizeof(ttl));
3021 break;
3022 }
3023 case PR_SockOpt_AddMember:
3024 case PR_SockOpt_DropMember:
3025 {
3026 struct ip_mreq mreq;
3027 mreq.imr_multiaddr.s_addr =
3028 data->value.add_member.mcaddr.inet.ip;
3029 mreq.imr_interface.s_addr =
3030 data->value.add_member.ifaddr.inet.ip;
3031 rv = setsockopt(
3032 fd->secret->md.osfd, level, name,
3033 (char*)&mreq, sizeof(mreq));
3034 break;
3035 }
3036 case PR_SockOpt_McastInterface:
3037 {
3038 rv = setsockopt(
3039 fd->secret->md.osfd, level, name,
3040 (char*)&data->value.mcast_if.inet.ip,
3041 sizeof(data->value.mcast_if.inet.ip));
3042 break;
3043 }
3044 default:
3045 PR_NOT_REACHED("Unknown socket option");
3046 break;
3047 }
3048 if (-1 == rv) _PR_MD_MAP_SETSOCKOPT_ERROR(errno);
3049 }
3050 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3051 } /* pt_SetSocketOption */
3052
3053 /*****************************************************************************/
3054 /****************************** I/O method objects ***************************/
3055 /*****************************************************************************/
3056
3057 static PRIOMethods _pr_file_methods = {
3058 PR_DESC_FILE,
3059 pt_Close,
3060 pt_Read,
3061 pt_Write,
3062 pt_Available_f,
3063 pt_Available64_f,
3064 pt_Fsync,
3065 pt_Seek,
3066 pt_Seek64,
3067 pt_FileInfo,
3068 pt_FileInfo64,
3069 (PRWritevFN)_PR_InvalidInt,
3070 (PRConnectFN)_PR_InvalidStatus,
3071 (PRAcceptFN)_PR_InvalidDesc,
3072 (PRBindFN)_PR_InvalidStatus,
3073 (PRListenFN)_PR_InvalidStatus,
3074 (PRShutdownFN)_PR_InvalidStatus,
3075 (PRRecvFN)_PR_InvalidInt,
3076 (PRSendFN)_PR_InvalidInt,
3077 (PRRecvfromFN)_PR_InvalidInt,
3078 (PRSendtoFN)_PR_InvalidInt,
3079 pt_Poll,
3080 (PRAcceptreadFN)_PR_InvalidInt,
3081 (PRTransmitfileFN)_PR_InvalidInt,
3082 (PRGetsocknameFN)_PR_InvalidStatus,
3083 (PRGetpeernameFN)_PR_InvalidStatus,
3084 (PRReservedFN)_PR_InvalidInt,
3085 (PRReservedFN)_PR_InvalidInt,
3086 (PRGetsocketoptionFN)_PR_InvalidStatus,
3087 (PRSetsocketoptionFN)_PR_InvalidStatus,
3088 (PRSendfileFN)_PR_InvalidInt,
3089 (PRConnectcontinueFN)_PR_InvalidStatus,
3090 (PRReservedFN)_PR_InvalidInt,
3091 (PRReservedFN)_PR_InvalidInt,
3092 (PRReservedFN)_PR_InvalidInt,
3093 (PRReservedFN)_PR_InvalidInt
3094 };
3095
3096 static PRIOMethods _pr_pipe_methods = {
3097 PR_DESC_PIPE,
3098 pt_Close,
3099 pt_Read,
3100 pt_Write,
3101 pt_Available_s,
3102 pt_Available64_s,
3103 pt_Synch,
3104 (PRSeekFN)_PR_InvalidInt,
3105 (PRSeek64FN)_PR_InvalidInt64,
3106 (PRFileInfoFN)_PR_InvalidStatus,
3107 (PRFileInfo64FN)_PR_InvalidStatus,
3108 (PRWritevFN)_PR_InvalidInt,
3109 (PRConnectFN)_PR_InvalidStatus,
3110 (PRAcceptFN)_PR_InvalidDesc,
3111 (PRBindFN)_PR_InvalidStatus,
3112 (PRListenFN)_PR_InvalidStatus,
3113 (PRShutdownFN)_PR_InvalidStatus,
3114 (PRRecvFN)_PR_InvalidInt,
3115 (PRSendFN)_PR_InvalidInt,
3116 (PRRecvfromFN)_PR_InvalidInt,
3117 (PRSendtoFN)_PR_InvalidInt,
3118 pt_Poll,
3119 (PRAcceptreadFN)_PR_InvalidInt,
3120 (PRTransmitfileFN)_PR_InvalidInt,
3121 (PRGetsocknameFN)_PR_InvalidStatus,
3122 (PRGetpeernameFN)_PR_InvalidStatus,
3123 (PRReservedFN)_PR_InvalidInt,
3124 (PRReservedFN)_PR_InvalidInt,
3125 (PRGetsocketoptionFN)_PR_InvalidStatus,
3126 (PRSetsocketoptionFN)_PR_InvalidStatus,
3127 (PRSendfileFN)_PR_InvalidInt,
3128 (PRConnectcontinueFN)_PR_InvalidStatus,
3129 (PRReservedFN)_PR_InvalidInt,
3130 (PRReservedFN)_PR_InvalidInt,
3131 (PRReservedFN)_PR_InvalidInt,
3132 (PRReservedFN)_PR_InvalidInt
3133 };
3134
3135 static PRIOMethods _pr_tcp_methods = {
3136 PR_DESC_SOCKET_TCP,
3137 pt_Close,
3138 pt_SocketRead,
3139 pt_SocketWrite,
3140 pt_Available_s,
3141 pt_Available64_s,
3142 pt_Synch,
3143 (PRSeekFN)_PR_InvalidInt,
3144 (PRSeek64FN)_PR_InvalidInt64,
3145 (PRFileInfoFN)_PR_InvalidStatus,
3146 (PRFileInfo64FN)_PR_InvalidStatus,
3147 pt_Writev,
3148 pt_Connect,
3149 pt_Accept,
3150 pt_Bind,
3151 pt_Listen,
3152 pt_Shutdown,
3153 pt_Recv,
3154 pt_Send,
3155 (PRRecvfromFN)_PR_InvalidInt,
3156 (PRSendtoFN)_PR_InvalidInt,
3157 pt_Poll,
3158 pt_AcceptRead,
3159 pt_TransmitFile,
3160 pt_GetSockName,
3161 pt_GetPeerName,
3162 (PRReservedFN)_PR_InvalidInt,
3163 (PRReservedFN)_PR_InvalidInt,
3164 pt_GetSocketOption,
3165 pt_SetSocketOption,
3166 pt_SendFile,
3167 pt_ConnectContinue,
3168 (PRReservedFN)_PR_InvalidInt,
3169 (PRReservedFN)_PR_InvalidInt,
3170 (PRReservedFN)_PR_InvalidInt,
3171 (PRReservedFN)_PR_InvalidInt
3172 };
3173
3174 static PRIOMethods _pr_udp_methods = {
3175 PR_DESC_SOCKET_UDP,
3176 pt_Close,
3177 pt_SocketRead,
3178 pt_SocketWrite,
3179 pt_Available_s,
3180 pt_Available64_s,
3181 pt_Synch,
3182 (PRSeekFN)_PR_InvalidInt,
3183 (PRSeek64FN)_PR_InvalidInt64,
3184 (PRFileInfoFN)_PR_InvalidStatus,
3185 (PRFileInfo64FN)_PR_InvalidStatus,
3186 pt_Writev,
3187 pt_Connect,
3188 (PRAcceptFN)_PR_InvalidDesc,
3189 pt_Bind,
3190 pt_Listen,
3191 pt_Shutdown,
3192 pt_Recv,
3193 pt_Send,
3194 pt_RecvFrom,
3195 pt_SendTo,
3196 pt_Poll,
3197 (PRAcceptreadFN)_PR_InvalidInt,
3198 (PRTransmitfileFN)_PR_InvalidInt,
3199 pt_GetSockName,
3200 pt_GetPeerName,
3201 (PRReservedFN)_PR_InvalidInt,
3202 (PRReservedFN)_PR_InvalidInt,
3203 pt_GetSocketOption,
3204 pt_SetSocketOption,
3205 (PRSendfileFN)_PR_InvalidInt,
3206 (PRConnectcontinueFN)_PR_InvalidStatus,
3207 (PRReservedFN)_PR_InvalidInt,
3208 (PRReservedFN)_PR_InvalidInt,
3209 (PRReservedFN)_PR_InvalidInt,
3210 (PRReservedFN)_PR_InvalidInt
3211 };
3212
3213 static PRIOMethods _pr_socketpollfd_methods = {
3214 (PRDescType) 0,
3215 (PRCloseFN)_PR_InvalidStatus,
3216 (PRReadFN)_PR_InvalidInt,
3217 (PRWriteFN)_PR_InvalidInt,
3218 (PRAvailableFN)_PR_InvalidInt,
3219 (PRAvailable64FN)_PR_InvalidInt64,
3220 (PRFsyncFN)_PR_InvalidStatus,
3221 (PRSeekFN)_PR_InvalidInt,
3222 (PRSeek64FN)_PR_InvalidInt64,
3223 (PRFileInfoFN)_PR_InvalidStatus,
3224 (PRFileInfo64FN)_PR_InvalidStatus,
3225 (PRWritevFN)_PR_InvalidInt,
3226 (PRConnectFN)_PR_InvalidStatus,
3227 (PRAcceptFN)_PR_InvalidDesc,
3228 (PRBindFN)_PR_InvalidStatus,
3229 (PRListenFN)_PR_InvalidStatus,
3230 (PRShutdownFN)_PR_InvalidStatus,
3231 (PRRecvFN)_PR_InvalidInt,
3232 (PRSendFN)_PR_InvalidInt,
3233 (PRRecvfromFN)_PR_InvalidInt,
3234 (PRSendtoFN)_PR_InvalidInt,
3235 pt_Poll,
3236 (PRAcceptreadFN)_PR_InvalidInt,
3237 (PRTransmitfileFN)_PR_InvalidInt,
3238 (PRGetsocknameFN)_PR_InvalidStatus,
3239 (PRGetpeernameFN)_PR_InvalidStatus,
3240 (PRReservedFN)_PR_InvalidInt,
3241 (PRReservedFN)_PR_InvalidInt,
3242 (PRGetsocketoptionFN)_PR_InvalidStatus,
3243 (PRSetsocketoptionFN)_PR_InvalidStatus,
3244 (PRSendfileFN)_PR_InvalidInt,
3245 (PRConnectcontinueFN)_PR_InvalidStatus,
3246 (PRReservedFN)_PR_InvalidInt,
3247 (PRReservedFN)_PR_InvalidInt,
3248 (PRReservedFN)_PR_InvalidInt,
3249 (PRReservedFN)_PR_InvalidInt
3250 };
3251
3252 #if defined(HPUX) || defined(OSF1) || defined(SOLARIS) || defined (IRIX) \
3253 || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
3254 || defined(AIX) || defined(FREEBSD) || defined(NETBSD) \
3255 || defined(OPENBSD) || defined(BSDI) || defined(NTO) \
3256 || defined(DARWIN) || defined(UNIXWARE) || defined(RISCOS) \
3257 || defined(SYMBIAN)
3258 #define _PR_FCNTL_FLAGS O_NONBLOCK
3259 #else
3260 #error "Can't determine architecture"
3261 #endif
3262
3263 /*
3264 * Put a Unix file descriptor in non-blocking mode.
3265 */
3266 static void pt_MakeFdNonblock(PRIntn osfd)
3267 {
3268 PRIntn flags;
3269 flags = fcntl(osfd, F_GETFL, 0);
3270 flags |= _PR_FCNTL_FLAGS;
3271 (void)fcntl(osfd, F_SETFL, flags);
3272 }
3273
3274 /*
3275 * Put a Unix socket fd in non-blocking mode that can
3276 * ideally be inherited by an accepted socket.
3277 *
3278 * Why doesn't pt_MakeFdNonblock do? This is to deal with
3279 * the special case of HP-UX. HP-UX has three kinds of
3280 * non-blocking modes for sockets: the fcntl() O_NONBLOCK
3281 * and O_NDELAY flags and ioctl() FIOSNBIO request. Only
3282 * the ioctl() FIOSNBIO form of non-blocking mode is
3283 * inherited by an accepted socket.
3284 *
3285 * Other platforms just use the generic pt_MakeFdNonblock
3286 * to put a socket in non-blocking mode.
3287 */
3288 #ifdef HPUX
3289 static void pt_MakeSocketNonblock(PRIntn osfd)
3290 {
3291 PRIntn one = 1;
3292 (void)ioctl(osfd, FIOSNBIO, &one);
3293 }
3294 #else
3295 #define pt_MakeSocketNonblock pt_MakeFdNonblock
3296 #endif
3297
3298 static PRFileDesc *pt_SetMethods(
3299 PRIntn osfd, PRDescType type, PRBool isAcceptedSocket, PRBool imported)
3300 {
3301 PRFileDesc *fd = _PR_Getfd();
3302
3303 if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3304 else
3305 {
3306 fd->secret->md.osfd = osfd;
3307 fd->secret->state = _PR_FILEDESC_OPEN;
3308 if (imported) fd->secret->inheritable = _PR_TRI_UNKNOWN;
3309 else
3310 {
3311 /* By default, a Unix fd is not closed on exec. */
3312 #ifdef DEBUG
3313 PRIntn flags;
3314 flags = fcntl(osfd, F_GETFD, 0);
3315 PR_ASSERT(0 == flags);
3316 #endif
3317 fd->secret->inheritable = _PR_TRI_TRUE;
3318 }
3319 switch (type)
3320 {
3321 case PR_DESC_FILE:
3322 fd->methods = PR_GetFileMethods();
3323 break;
3324 case PR_DESC_SOCKET_TCP:
3325 fd->methods = PR_GetTCPMethods();
3326 #ifdef _PR_ACCEPT_INHERIT_NONBLOCK
3327 if (!isAcceptedSocket) pt_MakeSocketNonblock(osfd);
3328 #else
3329 pt_MakeSocketNonblock(osfd);
3330 #endif
3331 break;
3332 case PR_DESC_SOCKET_UDP:
3333 fd->methods = PR_GetUDPMethods();
3334 pt_MakeFdNonblock(osfd);
3335 break;
3336 case PR_DESC_PIPE:
3337 fd->methods = PR_GetPipeMethods();
3338 pt_MakeFdNonblock(osfd);
3339 break;
3340 default:
3341 break;
3342 }
3343 }
3344 return fd;
3345 } /* pt_SetMethods */
3346
3347 PR_IMPLEMENT(const PRIOMethods*) PR_GetFileMethods(void)
3348 {
3349 return &_pr_file_methods;
3350 } /* PR_GetFileMethods */
3351
3352 PR_IMPLEMENT(const PRIOMethods*) PR_GetPipeMethods(void)
3353 {
3354 return &_pr_pipe_methods;
3355 } /* PR_GetPipeMethods */
3356
3357 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods(void)
3358 {
3359 return &_pr_tcp_methods;
3360 } /* PR_GetTCPMethods */
3361
3362 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods(void)
3363 {
3364 return &_pr_udp_methods;
3365 } /* PR_GetUDPMethods */
3366
3367 static const PRIOMethods* PR_GetSocketPollFdMethods(void)
3368 {
3369 return &_pr_socketpollfd_methods;
3370 } /* PR_GetSocketPollFdMethods */
3371
3372 PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDesc(
3373 PRInt32 osfd, const PRIOMethods *methods)
3374 {
3375 PRFileDesc *fd = _PR_Getfd();
3376
3377 if (NULL == fd) goto failed;
3378
3379 fd->methods = methods;
3380 fd->secret->md.osfd = osfd;
3381 /* Make fd non-blocking */
3382 if (osfd > 2)
3383 {
3384 /* Don't mess around with stdin, stdout or stderr */
3385 if (&_pr_tcp_methods == methods) pt_MakeSocketNonblock(osfd);
3386 else pt_MakeFdNonblock(osfd);
3387 }
3388 fd->secret->state = _PR_FILEDESC_OPEN;
3389 fd->secret->inheritable = _PR_TRI_UNKNOWN;
3390 return fd;
3391
3392 failed:
3393 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3394 return fd;
3395 } /* PR_AllocFileDesc */
3396
3397 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
3398 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
3399 #if defined(_PR_INET6_PROBE)
3400 extern PRBool _pr_ipv6_is_present(void);
3401 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
3402 {
3403 int osfd;
3404
3405 #if defined(DARWIN)
3406 /*
3407 * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3). IPv6 on
3408 * lesser versions is not ready for general use (see bug 222031).
3409 */
3410 {
3411 struct utsname u;
3412 if (uname(&u) != 0 || atoi(u.release) < 7)
3413 return PR_FALSE;
3414 }
3415 #endif
3416
3417 /*
3418 * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
3419 * suggests that we call open("/dev/ip6", O_RDWR) to determine
3420 * whether IPv6 APIs and the IPv6 stack are on the system.
3421 * Our portable test below seems to work fine, so I am using it.
3422 */
3423 osfd = socket(AF_INET6, SOCK_STREAM, 0);
3424 if (osfd != -1) {
3425 close(osfd);
3426 return PR_TRUE;
3427 }
3428 return PR_FALSE;
3429 }
3430 #endif /* _PR_INET6_PROBE */
3431 #endif
3432
3433 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
3434 {
3435 PRIntn osfd;
3436 PRDescType ftype;
3437 PRFileDesc *fd = NULL;
3438 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
3439 PRInt32 tmp_domain = domain;
3440 #endif
3441
3442 if (!_pr_initialized) _PR_ImplicitInitialization();
3443
3444 if (pt_TestAbort()) return NULL;
3445
3446 if (PF_INET != domain
3447 && PR_AF_INET6 != domain
3448 #if defined(_PR_HAVE_SDP)
3449 && PR_AF_INET_SDP != domain
3450 #if defined(SOLARIS)
3451 && PR_AF_INET6_SDP != domain
3452 #endif /* SOLARIS */
3453 #endif /* _PR_HAVE_SDP */
3454 && PF_UNIX != domain)
3455 {
3456 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3457 return fd;
3458 }
3459 if (type == SOCK_STREAM) ftype = PR_DESC_SOCKET_TCP;
3460 else if (type == SOCK_DGRAM) ftype = PR_DESC_SOCKET_UDP;
3461 else
3462 {
3463 (void)PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
3464 return fd;
3465 }
3466 #if defined(_PR_HAVE_SDP)
3467 #if defined(LINUX)
3468 if (PR_AF_INET_SDP == domain)
3469 domain = AF_INET_SDP;
3470 #elif defined(SOLARIS)
3471 if (PR_AF_INET_SDP == domain) {
3472 domain = AF_INET;
3473 proto = PROTO_SDP;
3474 } else if(PR_AF_INET6_SDP == domain) {
3475 domain = AF_INET6;
3476 proto = PROTO_SDP;
3477 }
3478 #endif /* SOLARIS */
3479 #endif /* _PR_HAVE_SDP */
3480 #if defined(_PR_INET6_PROBE)
3481 if (PR_AF_INET6 == domain)
3482 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
3483 #elif defined(_PR_INET6)
3484 if (PR_AF_INET6 == domain)
3485 domain = AF_INET6;
3486 #else
3487 if (PR_AF_INET6 == domain)
3488 domain = AF_INET;
3489 #endif
3490
3491 osfd = socket(domain, type, proto);
3492 if (osfd == -1) pt_MapError(_PR_MD_MAP_SOCKET_ERROR, errno);
3493 else
3494 {
3495 #ifdef _PR_IPV6_V6ONLY_PROBE
3496 if ((domain == AF_INET6) && _pr_ipv6_v6only_on_by_default)
3497 {
3498 int on = 0;
3499 (void)setsockopt(osfd, IPPROTO_IPV6, IPV6_V6ONLY,
3500 &on, sizeof(on));
3501 }
3502 #endif
3503 fd = pt_SetMethods(osfd, ftype, PR_FALSE, PR_FALSE);
3504 if (fd == NULL) close(osfd);
3505 }
3506 #ifdef _PR_NEED_SECRET_AF
3507 if (fd != NULL) fd->secret->af = domain;
3508 #endif
3509 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
3510 if (fd != NULL) {
3511 /*
3512 * For platforms with no support for IPv6
3513 * create layered socket for IPv4-mapped IPv6 addresses
3514 */
3515 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
3516 if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
3517 PR_Close(fd);
3518 fd = NULL;
3519 }
3520 }
3521 }
3522 #endif
3523 return fd;
3524 } /* PR_Socket */
3525
3526 /*****************************************************************************/
3527 /****************************** I/O public methods ***************************/
3528 /*****************************************************************************/
3529
3530 PR_IMPLEMENT(PRFileDesc*) PR_OpenFile(
3531 const char *name, PRIntn flags, PRIntn mode)
3532 {
3533 PRFileDesc *fd = NULL;
3534 PRIntn syserrno, osfd = -1, osflags = 0;;
3535
3536 if (!_pr_initialized) _PR_ImplicitInitialization();
3537
3538 if (pt_TestAbort()) return NULL;
3539
3540 if (flags & PR_RDONLY) osflags |= O_RDONLY;
3541 if (flags & PR_WRONLY) osflags |= O_WRONLY;
3542 if (flags & PR_RDWR) osflags |= O_RDWR;
3543 if (flags & PR_APPEND) osflags |= O_APPEND;
3544 if (flags & PR_TRUNCATE) osflags |= O_TRUNC;
3545 if (flags & PR_EXCL) osflags |= O_EXCL;
3546 if (flags & PR_SYNC)
3547 {
3548 #if defined(O_SYNC)
3549 osflags |= O_SYNC;
3550 #elif defined(O_FSYNC)
3551 osflags |= O_FSYNC;
3552 #else
3553 #error "Neither O_SYNC nor O_FSYNC is defined on this platform"
3554 #endif
3555 }
3556
3557 /*
3558 ** We have to hold the lock across the creation in order to
3559 ** enforce the sematics of PR_Rename(). (see the latter for
3560 ** more details)
3561 */
3562 if (flags & PR_CREATE_FILE)
3563 {
3564 osflags |= O_CREAT;
3565 if (NULL !=_pr_rename_lock)
3566 PR_Lock(_pr_rename_lock);
3567 }
3568
3569 osfd = _md_iovector._open64(name, osflags, mode);
3570 syserrno = errno;
3571
3572 if ((flags & PR_CREATE_FILE) && (NULL !=_pr_rename_lock))
3573 PR_Unlock(_pr_rename_lock);
3574
3575 if (osfd == -1)
3576 pt_MapError(_PR_MD_MAP_OPEN_ERROR, syserrno);
3577 else
3578 {
3579 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_FALSE);
3580 if (fd == NULL) close(osfd); /* $$$ whoops! this is bad $$$ */
3581 }
3582 return fd;
3583 } /* PR_OpenFile */
3584
3585 PR_IMPLEMENT(PRFileDesc*) PR_Open(const char *name, PRIntn flags, PRIntn mode)
3586 {
3587 return PR_OpenFile(name, flags, mode);
3588 } /* PR_Open */
3589
3590 PR_IMPLEMENT(PRStatus) PR_Delete(const char *name)
3591 {
3592 PRIntn rv = -1;
3593
3594 if (!_pr_initialized) _PR_ImplicitInitialization();
3595
3596 if (pt_TestAbort()) return PR_FAILURE;
3597
3598 rv = unlink(name);
3599
3600 if (rv == -1) {
3601 pt_MapError(_PR_MD_MAP_UNLINK_ERROR, errno);
3602 return PR_FAILURE;
3603 } else
3604 return PR_SUCCESS;
3605 } /* PR_Delete */
3606
3607 PR_IMPLEMENT(PRStatus) PR_Access(const char *name, PRAccessHow how)
3608 {
3609 PRIntn rv;
3610
3611 if (pt_TestAbort()) return PR_FAILURE;
3612
3613 switch (how)
3614 {
3615 case PR_ACCESS_READ_OK:
3616 rv = access(name, R_OK);
3617 break;
3618 case PR_ACCESS_WRITE_OK:
3619 rv = access(name, W_OK);
3620 break;
3621 case PR_ACCESS_EXISTS:
3622 default:
3623 rv = access(name, F_OK);
3624 }
3625 if (0 == rv) return PR_SUCCESS;
3626 pt_MapError(_PR_MD_MAP_ACCESS_ERROR, errno);
3627 return PR_FAILURE;
3628
3629 } /* PR_Access */
3630
3631 PR_IMPLEMENT(PRStatus) PR_GetFileInfo(const char *fn, PRFileInfo *info)
3632 {
3633 PRInt32 rv = _PR_MD_GETFILEINFO(fn, info);
3634 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3635 } /* PR_GetFileInfo */
3636
3637 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64(const char *fn, PRFileInfo64 *info)
3638 {
3639 PRInt32 rv;
3640
3641 if (!_pr_initialized) _PR_ImplicitInitialization();
3642 rv = _PR_MD_GETFILEINFO64(fn, info);
3643 return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
3644 } /* PR_GetFileInfo64 */
3645
3646 PR_IMPLEMENT(PRStatus) PR_Rename(const char *from, const char *to)
3647 {
3648 PRIntn rv = -1;
3649
3650 if (pt_TestAbort()) return PR_FAILURE;
3651
3652 /*
3653 ** We have to acquire a lock here to stiffle anybody trying to create
3654 ** a new file at the same time. And we have to hold that lock while we
3655 ** test to see if the file exists and do the rename. The other place
3656 ** where the lock is held is in PR_Open() when possibly creating a
3657 ** new file.
3658 */
3659
3660 PR_Lock(_pr_rename_lock);
3661 rv = access(to, F_OK);
3662 if (0 == rv)
3663 {
3664 PR_SetError(PR_FILE_EXISTS_ERROR, 0);
3665 rv = -1;
3666 }
3667 else
3668 {
3669 rv = rename(from, to);
3670 if (rv == -1)
3671 pt_MapError(_PR_MD_MAP_RENAME_ERROR, errno);
3672 }
3673 PR_Unlock(_pr_rename_lock);
3674 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3675 } /* PR_Rename */
3676
3677 PR_IMPLEMENT(PRStatus) PR_CloseDir(PRDir *dir)
3678 {
3679 if (pt_TestAbort()) return PR_FAILURE;
3680
3681 if (NULL != dir->md.d)
3682 {
3683 if (closedir(dir->md.d) == -1)
3684 {
3685 _PR_MD_MAP_CLOSEDIR_ERROR(errno);
3686 return PR_FAILURE;
3687 }
3688 dir->md.d = NULL;
3689 PR_DELETE(dir);
3690 }
3691 return PR_SUCCESS;
3692 } /* PR_CloseDir */
3693
3694 PR_IMPLEMENT(PRStatus) PR_MakeDir(const char *name, PRIntn mode)
3695 {
3696 PRInt32 rv = -1;
3697
3698 if (pt_TestAbort()) return PR_FAILURE;
3699
3700 /*
3701 ** This lock is used to enforce rename semantics as described
3702 ** in PR_Rename.
3703 */
3704 if (NULL !=_pr_rename_lock)
3705 PR_Lock(_pr_rename_lock);
3706 rv = mkdir(name, mode);
3707 if (-1 == rv)
3708 pt_MapError(_PR_MD_MAP_MKDIR_ERROR, errno);
3709 if (NULL !=_pr_rename_lock)
3710 PR_Unlock(_pr_rename_lock);
3711
3712 return (-1 == rv) ? PR_FAILURE : PR_SUCCESS;
3713 } /* PR_Makedir */
3714
3715 PR_IMPLEMENT(PRStatus) PR_MkDir(const char *name, PRIntn mode)
3716 {
3717 return PR_MakeDir(name, mode);
3718 } /* PR_Mkdir */
3719
3720 PR_IMPLEMENT(PRStatus) PR_RmDir(const char *name)
3721 {
3722 PRInt32 rv;
3723
3724 if (pt_TestAbort()) return PR_FAILURE;
3725
3726 rv = rmdir(name);
3727 if (0 == rv) {
3728 return PR_SUCCESS;
3729 } else {
3730 pt_MapError(_PR_MD_MAP_RMDIR_ERROR, errno);
3731 return PR_FAILURE;
3732 }
3733 } /* PR_Rmdir */
3734
3735
3736 PR_IMPLEMENT(PRDir*) PR_OpenDir(const char *name)
3737 {
3738 DIR *osdir;
3739 PRDir *dir = NULL;
3740
3741 if (pt_TestAbort()) return dir;
3742
3743 osdir = opendir(name);
3744 if (osdir == NULL)
3745 pt_MapError(_PR_MD_MAP_OPENDIR_ERROR, errno);
3746 else
3747 {
3748 dir = PR_NEWZAP(PRDir);
3749 if (dir)
3750 dir->md.d = osdir;
3751 else
3752 (void)closedir(osdir);
3753 }
3754 return dir;
3755 } /* PR_OpenDir */
3756
3757 static PRInt32 _pr_poll_with_poll(
3758 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
3759 {
3760 PRInt32 ready = 0;
3761 /*
3762 * For restarting poll() if it is interrupted by a signal.
3763 * We use these variables to figure out how much time has
3764 * elapsed and how much of the timeout still remains.
3765 */
3766 PRIntervalTime start, elapsed, remaining;
3767
3768 if (pt_TestAbort()) return -1;
3769
3770 if (0 == npds) PR_Sleep(timeout);
3771 else
3772 {
3773 #define STACK_POLL_DESC_COUNT 64
3774 struct pollfd stack_syspoll[STACK_POLL_DESC_COUNT];
3775 struct pollfd *syspoll;
3776 PRIntn index, msecs;
3777
3778 if (npds <= STACK_POLL_DESC_COUNT)
3779 {
3780 syspoll = stack_syspoll;
3781 }
3782 else
3783 {
3784 PRThread *me = PR_GetCurrentThread();
3785 if (npds > me->syspoll_count)
3786 {
3787 PR_Free(me->syspoll_list);
3788 me->syspoll_list =
3789 (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd));
3790 if (NULL == me->syspoll_list)
3791 {
3792 me->syspoll_count = 0;
3793 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
3794 return -1;
3795 }
3796 me->syspoll_count = npds;
3797 }
3798 syspoll = me->syspoll_list;
3799 }
3800
3801 for (index = 0; index < npds; ++index)
3802 {
3803 PRInt16 in_flags_read = 0, in_flags_write = 0;
3804 PRInt16 out_flags_read = 0, out_flags_write = 0;
3805
3806 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
3807 {
3808 if (pds[index].in_flags & PR_POLL_READ)
3809 {
3810 in_flags_read = (pds[index].fd->methods->poll)(
3811 pds[index].fd,
3812 pds[index].in_flags & ~PR_POLL_WRITE,
3813 &out_flags_read);
3814 }
3815 if (pds[index].in_flags & PR_POLL_WRITE)
3816 {
3817 in_flags_write = (pds[index].fd->methods->poll)(
3818 pds[index].fd,
3819 pds[index].in_flags & ~PR_POLL_READ,
3820 &out_flags_write);
3821 }
3822 if ((0 != (in_flags_read & out_flags_read))
3823 || (0 != (in_flags_write & out_flags_write)))
3824 {
3825 /* this one is ready right now */
3826 if (0 == ready)
3827 {
3828 /*
3829 * We will return without calling the system
3830 * poll function. So zero the out_flags
3831 * fields of all the poll descriptors before
3832 * this one.
3833 */
3834 int i;
3835 for (i = 0; i < index; i++)
3836 {
3837 pds[i].out_flags = 0;
3838 }
3839 }
3840 ready += 1;
3841 pds[index].out_flags = out_flags_read | out_flags_write;
3842 }
3843 else
3844 {
3845 /* now locate the NSPR layer at the bottom of the stack */
3846 PRFileDesc *bottom = PR_GetIdentitiesLayer(
3847 pds[index].fd, PR_NSPR_IO_LAYER);
3848 PR_ASSERT(NULL != bottom); /* what to do about that? */
3849 pds[index].out_flags = 0; /* pre-condition */
3850 if ((NULL != bottom)
3851 && (_PR_FILEDESC_OPEN == bottom->secret->state))
3852 {
3853 if (0 == ready)
3854 {
3855 syspoll[index].fd = bottom->secret->md.osfd;
3856 syspoll[index].events = 0;
3857 if (in_flags_read & PR_POLL_READ)
3858 {
3859 pds[index].out_flags |=
3860 _PR_POLL_READ_SYS_READ;
3861 syspoll[index].events |= POLLIN;
3862 }
3863 if (in_flags_read & PR_POLL_WRITE)
3864 {
3865 pds[index].out_flags |=
3866 _PR_POLL_READ_SYS_WRITE;
3867 syspoll[index].events |= POLLOUT;
3868 }
3869 if (in_flags_write & PR_POLL_READ)
3870 {
3871 pds[index].out_flags |=
3872 _PR_POLL_WRITE_SYS_READ;
3873 syspoll[index].events |= POLLIN;
3874 }
3875 if (in_flags_write & PR_POLL_WRITE)
3876 {
3877 pds[index].out_flags |=
3878 _PR_POLL_WRITE_SYS_WRITE;
3879 syspoll[index].events |= POLLOUT;
3880 }
3881 if (pds[index].in_flags & PR_POLL_EXCEPT)
3882 syspoll[index].events |= POLLPRI;
3883 }
3884 }
3885 else
3886 {
3887 if (0 == ready)
3888 {
3889 int i;
3890 for (i = 0; i < index; i++)
3891 {
3892 pds[i].out_flags = 0;
3893 }
3894 }
3895 ready += 1; /* this will cause an abrupt return */
3896 pds[index].out_flags = PR_POLL_NVAL; /* bogii */
3897 }
3898 }
3899 }
3900 else
3901 {
3902 /* make poll() ignore this entry */
3903 syspoll[index].fd = -1;
3904 syspoll[index].events = 0;
3905 pds[index].out_flags = 0;
3906 }
3907 }
3908 if (0 == ready)
3909 {
3910 switch (timeout)
3911 {
3912 case PR_INTERVAL_NO_WAIT: msecs = 0; break;
3913 case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break;
3914 default:
3915 msecs = PR_IntervalToMilliseconds(timeout);
3916 start = PR_IntervalNow();
3917 }
3918
3919 retry:
3920 ready = poll(syspoll, npds, msecs);
3921 if (-1 == ready)
3922 {
3923 PRIntn oserror = errno;
3924
3925 if (EINTR == oserror)
3926 {
3927 if (timeout == PR_INTERVAL_NO_TIMEOUT)
3928 goto retry;
3929 else if (timeout == PR_INTERVAL_NO_WAIT)
3930 ready = 0; /* don't retry, just time out */
3931 else
3932 {
3933 elapsed = (PRIntervalTime) (PR_IntervalNow()
3934 - start);
3935 if (elapsed > timeout)
3936 ready = 0; /* timed out */
3937 else
3938 {
3939 remaining = timeout - elapsed;
3940 msecs = PR_IntervalToMilliseconds(remaining);
3941 goto retry;
3942 }
3943 }
3944 }
3945 else
3946 {
3947 _PR_MD_MAP_POLL_ERROR(oserror);
3948 }
3949 }
3950 else if (ready > 0)
3951 {
3952 for (index = 0; index < npds; ++index)
3953 {
3954 PRInt16 out_flags = 0;
3955 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
3956 {
3957 if (0 != syspoll[index].revents)
3958 {
3959 if (syspoll[index].revents & POLLIN)
3960 {
3961 if (pds[index].out_flags
3962 & _PR_POLL_READ_SYS_READ)
3963 {
3964 out_flags |= PR_POLL_READ;
3965 }
3966 if (pds[index].out_flags
3967 & _PR_POLL_WRITE_SYS_READ)
3968 {
3969 out_flags |= PR_POLL_WRITE;
3970 }
3971 }
3972 if (syspoll[index].revents & POLLOUT)
3973 {
3974 if (pds[index].out_flags
3975 & _PR_POLL_READ_SYS_WRITE)
3976 {
3977 out_flags |= PR_POLL_READ;
3978 }
3979 if (pds[index].out_flags
3980 & _PR_POLL_WRITE_SYS_WRITE)
3981 {
3982 out_flags |= PR_POLL_WRITE;
3983 }
3984 }
3985 if (syspoll[index].revents & POLLPRI)
3986 out_flags |= PR_POLL_EXCEPT;
3987 if (syspoll[index].revents & POLLERR)
3988 out_flags |= PR_POLL_ERR;
3989 if (syspoll[index].revents & POLLNVAL)
3990 out_flags |= PR_POLL_NVAL;
3991 if (syspoll[index].revents & POLLHUP)
3992 out_flags |= PR_POLL_HUP;
3993 }
3994 }
3995 pds[index].out_flags = out_flags;
3996 }
3997 }
3998 }
3999 }
4000 return ready;
4001
4002 } /* _pr_poll_with_poll */
4003
4004 #if defined(_PR_POLL_WITH_SELECT)
4005 /*
4006 * OSF1 and HPUX report the POLLHUP event for a socket when the
4007 * shutdown(SHUT_WR) operation is called for the remote end, even though
4008 * the socket is still writeable. Use select(), instead of poll(), to
4009 * workaround this problem.
4010 */
4011 static PRInt32 _pr_poll_with_select(
4012 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
4013 {
4014 PRInt32 ready = 0;
4015 /*
4016 * For restarting select() if it is interrupted by a signal.
4017 * We use these variables to figure out how much time has
4018 * elapsed and how much of the timeout still remains.
4019 */
4020 PRIntervalTime start, elapsed, remaining;
4021
4022 if (pt_TestAbort()) return -1;
4023
4024 if (0 == npds) PR_Sleep(timeout);
4025 else
4026 {
4027 #define STACK_POLL_DESC_COUNT 64
4028 int stack_selectfd[STACK_POLL_DESC_COUNT];
4029 int *selectfd;
4030 fd_set rd, wr, ex, *rdp = NULL, *wrp = NULL, *exp = NULL;
4031 struct timeval tv, *tvp;
4032 PRIntn index, msecs, maxfd = 0;
4033
4034 if (npds <= STACK_POLL_DESC_COUNT)
4035 {
4036 selectfd = stack_selectfd;
4037 }
4038 else
4039 {
4040 PRThread *me = PR_GetCurrentThread();
4041 if (npds > me->selectfd_count)
4042 {
4043 PR_Free(me->selectfd_list);
4044 me->selectfd_list = (int *)PR_MALLOC(npds * sizeof(int));
4045 if (NULL == me->selectfd_list)
4046 {
4047 me->selectfd_count = 0;
4048 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4049 return -1;
4050 }
4051 me->selectfd_count = npds;
4052 }
4053 selectfd = me->selectfd_list;
4054 }
4055 FD_ZERO(&rd);
4056 FD_ZERO(&wr);
4057 FD_ZERO(&ex);
4058
4059 for (index = 0; index < npds; ++index)
4060 {
4061 PRInt16 in_flags_read = 0, in_flags_write = 0;
4062 PRInt16 out_flags_read = 0, out_flags_write = 0;
4063
4064 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
4065 {
4066 if (pds[index].in_flags & PR_POLL_READ)
4067 {
4068 in_flags_read = (pds[index].fd->methods->poll)(
4069 pds[index].fd,
4070 pds[index].in_flags & ~PR_POLL_WRITE,
4071 &out_flags_read);
4072 }
4073 if (pds[index].in_flags & PR_POLL_WRITE)
4074 {
4075 in_flags_write = (pds[index].fd->methods->poll)(
4076 pds[index].fd,
4077 pds[index].in_flags & ~PR_POLL_READ,
4078 &out_flags_write);
4079 }
4080 if ((0 != (in_flags_read & out_flags_read))
4081 || (0 != (in_flags_write & out_flags_write)))
4082 {
4083 /* this one is ready right now */
4084 if (0 == ready)
4085 {
4086 /*
4087 * We will return without calling the system
4088 * poll function. So zero the out_flags
4089 * fields of all the poll descriptors before
4090 * this one.
4091 */
4092 int i;
4093 for (i = 0; i < index; i++)
4094 {
4095 pds[i].out_flags = 0;
4096 }
4097 }
4098 ready += 1;
4099 pds[index].out_flags = out_flags_read | out_flags_write;
4100 }
4101 else
4102 {
4103 /* now locate the NSPR layer at the bottom of the stack */
4104 PRFileDesc *bottom = PR_GetIdentitiesLayer(
4105 pds[index].fd, PR_NSPR_IO_LAYER);
4106 PR_ASSERT(NULL != bottom); /* what to do about that? */
4107 pds[index].out_flags = 0; /* pre-condition */
4108 if ((NULL != bottom)
4109 && (_PR_FILEDESC_OPEN == bottom->secret->state))
4110 {
4111 if (0 == ready)
4112 {
4113 PRBool add_to_rd = PR_FALSE;
4114 PRBool add_to_wr = PR_FALSE;
4115 PRBool add_to_ex = PR_FALSE;
4116
4117 selectfd[index] = bottom->secret->md.osfd;
4118 if (in_flags_read & PR_POLL_READ)
4119 {
4120 pds[index].out_flags |=
4121 _PR_POLL_READ_SYS_READ;
4122 add_to_rd = PR_TRUE;
4123 }
4124 if (in_flags_read & PR_POLL_WRITE)
4125 {
4126 pds[index].out_flags |=
4127 _PR_POLL_READ_SYS_WRITE;
4128 add_to_wr = PR_TRUE;
4129 }
4130 if (in_flags_write & PR_POLL_READ)
4131 {
4132 pds[index].out_flags |=
4133 _PR_POLL_WRITE_SYS_READ;
4134 add_to_rd = PR_TRUE;
4135 }
4136 if (in_flags_write & PR_POLL_WRITE)
4137 {
4138 pds[index].out_flags |=
4139 _PR_POLL_WRITE_SYS_WRITE;
4140 add_to_wr = PR_TRUE;
4141 }
4142 if (pds[index].in_flags & PR_POLL_EXCEPT)
4143 {
4144 add_to_ex = PR_TRUE;
4145 }
4146 if ((selectfd[index] > maxfd) &&
4147 (add_to_rd || add_to_wr || add_to_ex))
4148 {
4149 maxfd = selectfd[index];
4150 /*
4151 * If maxfd is too large to be used with
4152 * select, fall back to calling poll.
4153 */
4154 if (maxfd >= FD_SETSIZE)
4155 break;
4156 }
4157 if (add_to_rd)
4158 {
4159 FD_SET(bottom->secret->md.osfd, &rd);
4160 rdp = &rd;
4161 }
4162 if (add_to_wr)
4163 {
4164 FD_SET(bottom->secret->md.osfd, &wr);
4165 wrp = &wr;
4166 }
4167 if (add_to_ex)
4168 {
4169 FD_SET(bottom->secret->md.osfd, &ex);
4170 exp = &ex;
4171 }
4172 }
4173 }
4174 else
4175 {
4176 if (0 == ready)
4177 {
4178 int i;
4179 for (i = 0; i < index; i++)
4180 {
4181 pds[i].out_flags = 0;
4182 }
4183 }
4184 ready += 1; /* this will cause an abrupt return */
4185 pds[index].out_flags = PR_POLL_NVAL; /* bogii */
4186 }
4187 }
4188 }
4189 else
4190 {
4191 pds[index].out_flags = 0;
4192 }
4193 }
4194 if (0 == ready)
4195 {
4196 if (maxfd >= FD_SETSIZE)
4197 {
4198 /*
4199 * maxfd too large to be used with select, fall back to
4200 * calling poll
4201 */
4202 return(_pr_poll_with_poll(pds, npds, timeout));
4203 }
4204 switch (timeout)
4205 {
4206 case PR_INTERVAL_NO_WAIT:
4207 tv.tv_sec = 0;
4208 tv.tv_usec = 0;
4209 tvp = &tv;
4210 break;
4211 case PR_INTERVAL_NO_TIMEOUT:
4212 tvp = NULL;
4213 break;
4214 default:
4215 msecs = PR_IntervalToMilliseconds(timeout);
4216 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
4217 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) * PR_USEC_PER_MSEC;
4218 tvp = &tv;
4219 start = PR_IntervalNow();
4220 }
4221
4222 retry:
4223 ready = select(maxfd + 1, rdp, wrp, exp, tvp);
4224 if (-1 == ready)
4225 {
4226 PRIntn oserror = errno;
4227
4228 if ((EINTR == oserror) || (EAGAIN == oserror))
4229 {
4230 if (timeout == PR_INTERVAL_NO_TIMEOUT)
4231 goto retry;
4232 else if (timeout == PR_INTERVAL_NO_WAIT)
4233 ready = 0; /* don't retry, just time out */
4234 else
4235 {
4236 elapsed = (PRIntervalTime) (PR_IntervalNow()
4237 - start);
4238 if (elapsed > timeout)
4239 ready = 0; /* timed out */
4240 else
4241 {
4242 remaining = timeout - elapsed;
4243 msecs = PR_IntervalToMilliseconds(remaining);
4244 tv.tv_sec = msecs/PR_MSEC_PER_SEC;
4245 tv.tv_usec = (msecs % PR_MSEC_PER_SEC) *
4246 PR_USEC_PER_MSEC;
4247 goto retry;
4248 }
4249 }
4250 } else if (EBADF == oserror)
4251 {
4252 /* find all the bad fds */
4253 ready = 0;
4254 for (index = 0; index < npds; ++index)
4255 {
4256 pds[index].out_flags = 0;
4257 if ((NULL != pds[index].fd) &&
4258 (0 != pds[index].in_flags))
4259 {
4260 if (fcntl(selectfd[index], F_GETFL, 0) == -1)
4261 {
4262 pds[index].out_flags = PR_POLL_NVAL;
4263 ready++;
4264 }
4265 }
4266 }
4267 } else
4268 _PR_MD_MAP_SELECT_ERROR(oserror);
4269 }
4270 else if (ready > 0)
4271 {
4272 for (index = 0; index < npds; ++index)
4273 {
4274 PRInt16 out_flags = 0;
4275 if ((NULL != pds[index].fd) && (0 != pds[index].in_flags))
4276 {
4277 if (FD_ISSET(selectfd[index], &rd))
4278 {
4279 if (pds[index].out_flags
4280 & _PR_POLL_READ_SYS_READ)
4281 {
4282 out_flags |= PR_POLL_READ;
4283 }
4284 if (pds[index].out_flags
4285 & _PR_POLL_WRITE_SYS_READ)
4286 {
4287 out_flags |= PR_POLL_WRITE;
4288 }
4289 }
4290 if (FD_ISSET(selectfd[index], &wr))
4291 {
4292 if (pds[index].out_flags
4293 & _PR_POLL_READ_SYS_WRITE)
4294 {
4295 out_flags |= PR_POLL_READ;
4296 }
4297 if (pds[index].out_flags
4298 & _PR_POLL_WRITE_SYS_WRITE)
4299 {
4300 out_flags |= PR_POLL_WRITE;
4301 }
4302 }
4303 if (FD_ISSET(selectfd[index], &ex))
4304 out_flags |= PR_POLL_EXCEPT;
4305 }
4306 pds[index].out_flags = out_flags;
4307 }
4308 }
4309 }
4310 }
4311 return ready;
4312
4313 } /* _pr_poll_with_select */
4314 #endif /* _PR_POLL_WITH_SELECT */
4315
4316 PR_IMPLEMENT(PRInt32) PR_Poll(
4317 PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
4318 {
4319 #if defined(_PR_POLL_WITH_SELECT)
4320 return(_pr_poll_with_select(pds, npds, timeout));
4321 #else
4322 return(_pr_poll_with_poll(pds, npds, timeout));
4323 #endif
4324 }
4325
4326 PR_IMPLEMENT(PRDirEntry*) PR_ReadDir(PRDir *dir, PRDirFlags flags)
4327 {
4328 struct dirent *dp;
4329
4330 if (pt_TestAbort()) return NULL;
4331
4332 for (;;)
4333 {
4334 errno = 0;
4335 dp = readdir(dir->md.d);
4336 if (NULL == dp)
4337 {
4338 pt_MapError(_PR_MD_MAP_READDIR_ERROR, errno);
4339 return NULL;
4340 }
4341 if ((flags & PR_SKIP_DOT)
4342 && ('.' == dp->d_name[0])
4343 && (0 == dp->d_name[1])) continue;
4344 if ((flags & PR_SKIP_DOT_DOT)
4345 && ('.' == dp->d_name[0])
4346 && ('.' == dp->d_name[1])
4347 && (0 == dp->d_name[2])) continue;
4348 if ((flags & PR_SKIP_HIDDEN) && ('.' == dp->d_name[0]))
4349 continue;
4350 break;
4351 }
4352 dir->d.name = dp->d_name;
4353 return &dir->d;
4354 } /* PR_ReadDir */
4355
4356 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
4357 {
4358 PRIntn domain = PF_INET;
4359
4360 return PR_Socket(domain, SOCK_DGRAM, 0);
4361 } /* PR_NewUDPSocket */
4362
4363 PR_IMPLEMENT(PRFileDesc*) PR_NewTCPSocket(void)
4364 {
4365 PRIntn domain = PF_INET;
4366
4367 return PR_Socket(domain, SOCK_STREAM, 0);
4368 } /* PR_NewTCPSocket */
4369
4370 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
4371 {
4372 return PR_Socket(af, SOCK_DGRAM, 0);
4373 } /* PR_NewUDPSocket */
4374
4375 PR_IMPLEMENT(PRFileDesc*) PR_OpenTCPSocket(PRIntn af)
4376 {
4377 return PR_Socket(af, SOCK_STREAM, 0);
4378 } /* PR_NewTCPSocket */
4379
4380 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *fds[2])
4381 {
4382 #ifdef SYMBIAN
4383 /*
4384 * For the platforms that don't have socketpair.
4385 *
4386 * Copied from prsocket.c, with the parameter f[] renamed fds[] and the
4387 * _PR_CONNECT_DOES_NOT_BIND code removed.
4388 */
4389 PRFileDesc *listenSock;
4390 PRNetAddr selfAddr, peerAddr;
4391 PRUint16 port;
4392
4393 fds[0] = fds[1] = NULL;
4394 listenSock = PR_NewTCPSocket();
4395 if (listenSock == NULL) {
4396 goto failed;
4397 }
4398 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
4399 if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
4400 goto failed;
4401 }
4402 if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
4403 goto failed;
4404 }
4405 port = ntohs(selfAddr.inet.port);
4406 if (PR_Listen(listenSock, 5) == PR_FAILURE) {
4407 goto failed;
4408 }
4409 fds[0] = PR_NewTCPSocket();
4410 if (fds[0] == NULL) {
4411 goto failed;
4412 }
4413 PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
4414
4415 /*
4416 * Only a thread is used to do the connect and accept.
4417 * I am relying on the fact that PR_Connect returns
4418 * successfully as soon as the connect request is put
4419 * into the listen queue (but before PR_Accept is called).
4420 * This is the behavior of the BSD socket code. If
4421 * connect does not return until accept is called, we
4422 * will need to create another thread to call connect.
4423 */
4424 if (PR_Connect(fds[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
4425 == PR_FAILURE) {
4426 goto failed;
4427 }
4428 /*
4429 * A malicious local process may connect to the listening
4430 * socket, so we need to verify that the accepted connection
4431 * is made from our own socket fds[0].
4432 */
4433 if (PR_GetSockName(fds[0], &selfAddr) == PR_FAILURE) {
4434 goto failed;
4435 }
4436 fds[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
4437 if (fds[1] == NULL) {
4438 goto failed;
4439 }
4440 if (peerAddr.inet.port != selfAddr.inet.port) {
4441 /* the connection we accepted is not from fds[0] */
4442 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
4443 goto failed;
4444 }
4445 PR_Close(listenSock);
4446 return PR_SUCCESS;
4447
4448 failed:
4449 if (listenSock) {
4450 PR_Close(listenSock);
4451 }
4452 if (fds[0]) {
4453 PR_Close(fds[0]);
4454 }
4455 if (fds[1]) {
4456 PR_Close(fds[1]);
4457 }
4458 return PR_FAILURE;
4459 #else
4460 PRInt32 osfd[2];
4461
4462 if (pt_TestAbort()) return PR_FAILURE;
4463
4464 if (socketpair(AF_UNIX, SOCK_STREAM, 0, osfd) == -1) {
4465 pt_MapError(_PR_MD_MAP_SOCKETPAIR_ERROR, errno);
4466 return PR_FAILURE;
4467 }
4468
4469 fds[0] = pt_SetMethods(osfd[0], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4470 if (fds[0] == NULL) {
4471 close(osfd[0]);
4472 close(osfd[1]);
4473 return PR_FAILURE;
4474 }
4475 fds[1] = pt_SetMethods(osfd[1], PR_DESC_SOCKET_TCP, PR_FALSE, PR_FALSE);
4476 if (fds[1] == NULL) {
4477 PR_Close(fds[0]);
4478 close(osfd[1]);
4479 return PR_FAILURE;
4480 }
4481 return PR_SUCCESS;
4482 #endif
4483 } /* PR_NewTCPSocketPair */
4484
4485 PR_IMPLEMENT(PRStatus) PR_CreatePipe(
4486 PRFileDesc **readPipe,
4487 PRFileDesc **writePipe
4488 )
4489 {
4490 int pipefd[2];
4491
4492 if (pt_TestAbort()) return PR_FAILURE;
4493
4494 if (pipe(pipefd) == -1)
4495 {
4496 /* XXX map pipe error */
4497 PR_SetError(PR_UNKNOWN_ERROR, errno);
4498 return PR_FAILURE;
4499 }
4500 *readPipe = pt_SetMethods(pipefd[0], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4501 if (NULL == *readPipe)
4502 {
4503 close(pipefd[0]);
4504 close(pipefd[1]);
4505 return PR_FAILURE;
4506 }
4507 *writePipe = pt_SetMethods(pipefd[1], PR_DESC_PIPE, PR_FALSE, PR_FALSE);
4508 if (NULL == *writePipe)
4509 {
4510 PR_Close(*readPipe);
4511 close(pipefd[1]);
4512 return PR_FAILURE;
4513 }
4514 return PR_SUCCESS;
4515 }
4516
4517 /*
4518 ** Set the inheritance attribute of a file descriptor.
4519 */
4520 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
4521 PRFileDesc *fd,
4522 PRBool inheritable)
4523 {
4524 /*
4525 * Only a non-layered, NSPR file descriptor can be inherited
4526 * by a child process.
4527 */
4528 if (fd->identity != PR_NSPR_IO_LAYER)
4529 {
4530 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4531 return PR_FAILURE;
4532 }
4533 if (fd->secret->inheritable != inheritable)
4534 {
4535 if (fcntl(fd->secret->md.osfd, F_SETFD,
4536 inheritable ? 0 : FD_CLOEXEC) == -1)
4537 {
4538 _PR_MD_MAP_DEFAULT_ERROR(errno);
4539 return PR_FAILURE;
4540 }
4541 fd->secret->inheritable = (_PRTriStateBool) inheritable;
4542 }
4543 return PR_SUCCESS;
4544 }
4545
4546 /*****************************************************************************/
4547 /***************************** I/O friends methods ***************************/
4548 /*****************************************************************************/
4549
4550 PR_IMPLEMENT(PRFileDesc*) PR_ImportFile(PRInt32 osfd)
4551 {
4552 PRFileDesc *fd;
4553
4554 if (!_pr_initialized) _PR_ImplicitInitialization();
4555 fd = pt_SetMethods(osfd, PR_DESC_FILE, PR_FALSE, PR_TRUE);
4556 if (NULL == fd) close(osfd);
4557 return fd;
4558 } /* PR_ImportFile */
4559
4560 PR_IMPLEMENT(PRFileDesc*) PR_ImportPipe(PRInt32 osfd)
4561 {
4562 PRFileDesc *fd;
4563
4564 if (!_pr_initialized) _PR_ImplicitInitialization();
4565 fd = pt_SetMethods(osfd, PR_DESC_PIPE, PR_FALSE, PR_TRUE);
4566 if (NULL == fd) close(osfd);
4567 return fd;
4568 } /* PR_ImportPipe */
4569
4570 PR_IMPLEMENT(PRFileDesc*) PR_ImportTCPSocket(PRInt32 osfd)
4571 {
4572 PRFileDesc *fd;
4573
4574 if (!_pr_initialized) _PR_ImplicitInitialization();
4575 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_TCP, PR_FALSE, PR_TRUE);
4576 if (NULL == fd) close(osfd);
4577 #ifdef _PR_NEED_SECRET_AF
4578 if (NULL != fd) fd->secret->af = PF_INET;
4579 #endif
4580 return fd;
4581 } /* PR_ImportTCPSocket */
4582
4583 PR_IMPLEMENT(PRFileDesc*) PR_ImportUDPSocket(PRInt32 osfd)
4584 {
4585 PRFileDesc *fd;
4586
4587 if (!_pr_initialized) _PR_ImplicitInitialization();
4588 fd = pt_SetMethods(osfd, PR_DESC_SOCKET_UDP, PR_FALSE, PR_TRUE);
4589 if (NULL == fd) close(osfd);
4590 return fd;
4591 } /* PR_ImportUDPSocket */
4592
4593 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
4594 {
4595 PRFileDesc *fd;
4596
4597 if (!_pr_initialized) _PR_ImplicitInitialization();
4598
4599 fd = _PR_Getfd();
4600
4601 if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
4602 else
4603 {
4604 fd->secret->md.osfd = osfd;
4605 fd->secret->inheritable = _PR_TRI_FALSE;
4606 fd->secret->state = _PR_FILEDESC_OPEN;
4607 fd->methods = PR_GetSocketPollFdMethods();
4608 }
4609
4610 return fd;
4611 } /* PR_CreateSocketPollFD */
4612
4613 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
4614 {
4615 if (NULL == fd)
4616 {
4617 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
4618 return PR_FAILURE;
4619 }
4620 fd->secret->state = _PR_FILEDESC_CLOSED;
4621 _PR_Putfd(fd);
4622 return PR_SUCCESS;
4623 } /* PR_DestroySocketPollFd */
4624
4625 PR_IMPLEMENT(PRInt32) PR_FileDesc2NativeHandle(PRFileDesc *bottom)
4626 {
4627 PRInt32 osfd = -1;
4628 bottom = (NULL == bottom) ?
4629 NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
4630 if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
4631 else osfd = bottom->secret->md.osfd;
4632 return osfd;
4633 } /* PR_FileDesc2NativeHandle */
4634
4635 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
4636 PRInt32 handle)
4637 {
4638 if (fd) fd->secret->md.osfd = handle;
4639 } /* PR_ChangeFileDescNativeHandle*/
4640
4641 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
4642 {
4643 PRStatus status = PR_SUCCESS;
4644
4645 if (pt_TestAbort()) return PR_FAILURE;
4646
4647 PR_Lock(_pr_flock_lock);
4648 while (-1 == fd->secret->lockCount)
4649 PR_WaitCondVar(_pr_flock_cv, PR_INTERVAL_NO_TIMEOUT);
4650 if (0 == fd->secret->lockCount)
4651 {
4652 fd->secret->lockCount = -1;
4653 PR_Unlock(_pr_flock_lock);
4654 status = _PR_MD_LOCKFILE(fd->secret->md.osfd);
4655 PR_Lock(_pr_flock_lock);
4656 fd->secret->lockCount = (PR_SUCCESS == status) ? 1 : 0;
4657 PR_NotifyAllCondVar(_pr_flock_cv);
4658 }
4659 else
4660 {
4661 fd->secret->lockCount += 1;
4662 }
4663 PR_Unlock(_pr_flock_lock);
4664
4665 return status;
4666 } /* PR_LockFile */
4667
4668 PR_IMPLEMENT(PRStatus) PR_TLockFile(PRFileDesc *fd)
4669 {
4670 PRStatus status = PR_SUCCESS;
4671
4672 if (pt_TestAbort()) return PR_FAILURE;
4673
4674 PR_Lock(_pr_flock_lock);
4675 if (0 == fd->secret->lockCount)
4676 {
4677 status = _PR_MD_TLOCKFILE(fd->secret->md.osfd);
4678 if (PR_SUCCESS == status) fd->secret->lockCount = 1;
4679 }
4680 else fd->secret->lockCount += 1;
4681 PR_Unlock(_pr_flock_lock);
4682
4683 return status;
4684 } /* PR_TLockFile */
4685
4686 PR_IMPLEMENT(PRStatus) PR_UnlockFile(PRFileDesc *fd)
4687 {
4688 PRStatus status = PR_SUCCESS;
4689
4690 if (pt_TestAbort()) return PR_FAILURE;
4691
4692 PR_Lock(_pr_flock_lock);
4693 if (fd->secret->lockCount == 1)
4694 {
4695 status = _PR_MD_UNLOCKFILE(fd->secret->md.osfd);
4696 if (PR_SUCCESS == status) fd->secret->lockCount = 0;
4697 }
4698 else fd->secret->lockCount -= 1;
4699 PR_Unlock(_pr_flock_lock);
4700
4701 return status;
4702 }
4703
4704 /*
4705 * The next two entry points should not be in the API, but they are
4706 * defined here for historical (or hysterical) reasons.
4707 */
4708
4709 PR_IMPLEMENT(PRInt32) PR_GetSysfdTableMax(void)
4710 {
4711 #if defined(AIX) || defined(SYMBIAN)
4712 return sysconf(_SC_OPEN_MAX);
4713 #else
4714 struct rlimit rlim;
4715
4716 if ( getrlimit(RLIMIT_NOFILE, &rlim) < 0)
4717 return -1;
4718
4719 return rlim.rlim_max;
4720 #endif
4721 }
4722
4723 PR_IMPLEMENT(PRInt32) PR_SetSysfdTableSize(PRIntn table_size)
4724 {
4725 #if defined(AIX) || defined(SYMBIAN)
4726 return -1;
4727 #else
4728 struct rlimit rlim;
4729 PRInt32 tableMax = PR_GetSysfdTableMax();
4730
4731 if (tableMax < 0) return -1;
4732 rlim.rlim_max = tableMax;
4733
4734 /* Grow as much as we can; even if too big */
4735 if ( rlim.rlim_max < table_size )
4736 rlim.rlim_cur = rlim.rlim_max;
4737 else
4738 rlim.rlim_cur = table_size;
4739
4740 if ( setrlimit(RLIMIT_NOFILE, &rlim) < 0)
4741 return -1;
4742
4743 return rlim.rlim_cur;
4744 #endif
4745 }
4746
4747 /*
4748 * PR_Stat is supported for backward compatibility; some existing Java
4749 * code uses it. New code should use PR_GetFileInfo.
4750 */
4751
4752 #ifndef NO_NSPR_10_SUPPORT
4753 PR_IMPLEMENT(PRInt32) PR_Stat(const char *name, struct stat *buf)
4754 {
4755 static PRBool unwarned = PR_TRUE;
4756 if (unwarned) unwarned = _PR_Obsolete("PR_Stat", "PR_GetFileInfo");
4757
4758 if (pt_TestAbort()) return -1;
4759
4760 if (-1 == stat(name, buf)) {
4761 pt_MapError(_PR_MD_MAP_STAT_ERROR, errno);
4762 return -1;
4763 } else {
4764 return 0;
4765 }
4766 }
4767 #endif /* ! NO_NSPR_10_SUPPORT */
4768
4769
4770 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
4771 {
4772 static PRBool unwarned = PR_TRUE;
4773 if (unwarned) unwarned = _PR_Obsolete("PR_FD_ZERO (PR_Select)", "PR_Poll");
4774 memset(set, 0, sizeof(PR_fd_set));
4775 }
4776
4777 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
4778 {
4779 static PRBool unwarned = PR_TRUE;
4780 if (unwarned) unwarned = _PR_Obsolete("PR_FD_SET (PR_Select)", "PR_Poll");
4781 PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
4782
4783 set->harray[set->hsize++] = fh;
4784 }
4785
4786 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
4787 {
4788 PRUint32 index, index2;
4789 static PRBool unwarned = PR_TRUE;
4790 if (unwarned) unwarned = _PR_Obsolete("PR_FD_CLR (PR_Select)", "PR_Poll");
4791
4792 for (index = 0; index<set->hsize; index++)
4793 if (set->harray[index] == fh) {
4794 for (index2=index; index2 < (set->hsize-1); index2++) {
4795 set->harray[index2] = set->harray[index2+1];
4796 }
4797 set->hsize--;
4798 break;
4799 }
4800 }
4801
4802 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
4803 {
4804 PRUint32 index;
4805 static PRBool unwarned = PR_TRUE;
4806 if (unwarned) unwarned = _PR_Obsolete("PR_FD_ISSET (PR_Select)", "PR_Poll");
4807 for (index = 0; index<set->hsize; index++)
4808 if (set->harray[index] == fh) {
4809 return 1;
4810 }
4811 return 0;
4812 }
4813
4814 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
4815 {
4816 static PRBool unwarned = PR_TRUE;
4817 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NSET (PR_Select)", "PR_Poll");
4818 PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
4819
4820 set->narray[set->nsize++] = fd;
4821 }
4822
4823 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
4824 {
4825 PRUint32 index, index2;
4826 static PRBool unwarned = PR_TRUE;
4827 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NCLR (PR_Select)", "PR_Poll");
4828
4829 for (index = 0; index<set->nsize; index++)
4830 if (set->narray[index] == fd) {
4831 for (index2=index; index2 < (set->nsize-1); index2++) {
4832 set->narray[index2] = set->narray[index2+1];
4833 }
4834 set->nsize--;
4835 break;
4836 }
4837 }
4838
4839 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
4840 {
4841 PRUint32 index;
4842 static PRBool unwarned = PR_TRUE;
4843 if (unwarned) unwarned = _PR_Obsolete("PR_FD_NISSET (PR_Select)", "PR_Poll");
4844 for (index = 0; index<set->nsize; index++)
4845 if (set->narray[index] == fd) {
4846 return 1;
4847 }
4848 return 0;
4849 }
4850
4851 #include <sys/types.h>
4852 #include <sys/time.h>
4853 #if !defined(HPUX) \
4854 && !defined(LINUX) && !defined(__GNU__) && !defined(__GLIBC__)
4855 #include <sys/select.h>
4856 #endif
4857
4858 static PRInt32
4859 _PR_getset(PR_fd_set *pr_set, fd_set *set)
4860 {
4861 PRUint32 index;
4862 PRInt32 max = 0;
4863
4864 if (!pr_set)
4865 return 0;
4866
4867 FD_ZERO(set);
4868
4869 /* First set the pr file handle osfds */
4870 for (index=0; index<pr_set->hsize; index++) {
4871 FD_SET(pr_set->harray[index]->secret->md.osfd, set);
4872 if (pr_set->harray[index]->secret->md.osfd > max)
4873 max = pr_set->harray[index]->secret->md.osfd;
4874 }
4875 /* Second set the native osfds */
4876 for (index=0; index<pr_set->nsize; index++) {
4877 FD_SET(pr_set->narray[index], set);
4878 if (pr_set->narray[index] > max)
4879 max = pr_set->narray[index];
4880 }
4881 return max;
4882 }
4883
4884 static void
4885 _PR_setset(PR_fd_set *pr_set, fd_set *set)
4886 {
4887 PRUint32 index, last_used;
4888
4889 if (!pr_set)
4890 return;
4891
4892 for (last_used=0, index=0; index<pr_set->hsize; index++) {
4893 if ( FD_ISSET(pr_set->harray[index]->secret->md.osfd, set) ) {
4894 pr_set->harray[last_used++] = pr_set->harray[index];
4895 }
4896 }
4897 pr_set->hsize = last_used;
4898
4899 for (last_used=0, index=0; index<pr_set->nsize; index++) {
4900 if ( FD_ISSET(pr_set->narray[index], set) ) {
4901 pr_set->narray[last_used++] = pr_set->narray[index];
4902 }
4903 }
4904 pr_set->nsize = last_used;
4905 }
4906
4907 PR_IMPLEMENT(PRInt32) PR_Select(
4908 PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr,
4909 PR_fd_set *pr_ex, PRIntervalTime timeout)
4910 {
4911 fd_set rd, wr, ex;
4912 struct timeval tv, *tvp;
4913 PRInt32 max, max_fd;
4914 PRInt32 rv;
4915 /*
4916 * For restarting select() if it is interrupted by a Unix signal.
4917 * We use these variables to figure out how much time has elapsed
4918 * and how much of the timeout still remains.
4919 */
4920 PRIntervalTime start, elapsed, remaining;
4921
4922 static PRBool unwarned = PR_TRUE;
4923 if (unwarned) unwarned = _PR_Obsolete( "PR_Select", "PR_Poll");
4924
4925 FD_ZERO(&rd);
4926 FD_ZERO(&wr);
4927 FD_ZERO(&ex);
4928
4929 max_fd = _PR_getset(pr_rd, &rd);
4930 max_fd = (max = _PR_getset(pr_wr, &wr))>max_fd?max:max_fd;
4931 max_fd = (max = _PR_getset(pr_ex, &ex))>max_fd?max:max_fd;
4932
4933 if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4934 tvp = NULL;
4935 } else {
4936 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(timeout);
4937 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4938 timeout - PR_SecondsToInterval(tv.tv_sec));
4939 tvp = &tv;
4940 start = PR_IntervalNow();
4941 }
4942
4943 retry:
4944 rv = select(max_fd + 1, (_PRSelectFdSetArg_t) &rd,
4945 (_PRSelectFdSetArg_t) &wr, (_PRSelectFdSetArg_t) &ex, tvp);
4946
4947 if (rv == -1 && errno == EINTR) {
4948 if (timeout == PR_INTERVAL_NO_TIMEOUT) {
4949 goto retry;
4950 } else {
4951 elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
4952 if (elapsed > timeout) {
4953 rv = 0; /* timed out */
4954 } else {
4955 remaining = timeout - elapsed;
4956 tv.tv_sec = (PRInt32)PR_IntervalToSeconds(remaining);
4957 tv.tv_usec = (PRInt32)PR_IntervalToMicroseconds(
4958 remaining - PR_SecondsToInterval(tv.tv_sec));
4959 goto retry;
4960 }
4961 }
4962 }
4963
4964 if (rv > 0) {
4965 _PR_setset(pr_rd, &rd);
4966 _PR_setset(pr_wr, &wr);
4967 _PR_setset(pr_ex, &ex);
4968 } else if (rv == -1) {
4969 pt_MapError(_PR_MD_MAP_SELECT_ERROR, errno);
4970 }
4971 return rv;
4972 }
4973 #endif /* defined(_PR_PTHREADS) */
4974
4975 #ifdef MOZ_UNICODE
4976 /* ================ UTF16 Interfaces ================================ */
4977 PR_IMPLEMENT(PRFileDesc*) PR_OpenFileUTF16(
4978 const PRUnichar *name, PRIntn flags, PRIntn mode)
4979 {
4980 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4981 return NULL;
4982 }
4983
4984 PR_IMPLEMENT(PRStatus) PR_CloseDirUTF16(PRDir *dir)
4985 {
4986 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4987 return PR_FAILURE;
4988 }
4989
4990 PR_IMPLEMENT(PRDirUTF16*) PR_OpenDirUTF16(const PRUnichar *name)
4991 {
4992 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4993 return NULL;
4994 }
4995
4996 PR_IMPLEMENT(PRDirEntryUTF16*) PR_ReadDirUTF16(PRDirUTF16 *dir, PRDirFlags flags)
4997 {
4998 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
4999 return NULL;
5000 }
5001
5002 PR_IMPLEMENT(PRStatus) PR_GetFileInfo64UTF16(const PRUnichar *fn, PRFileInfo64 *info)
5003 {
5004 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
5005 return PR_FAILURE;
5006 }
5007 /* ================ UTF16 Interfaces ================================ */
5008 #endif /* MOZ_UNICODE */
5009
5010 /* ptio.c */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)