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