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