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