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