OLD | NEW |
| (Empty) |
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
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 #include "primpl.h" | |
7 | |
8 #include <string.h> | |
9 | |
10 /************************************************************************/ | |
11 | |
12 /* These two functions are only used in assertions. */ | |
13 #if defined(DEBUG) | |
14 | |
15 PRBool IsValidNetAddr(const PRNetAddr *addr) | |
16 { | |
17 if ((addr != NULL) | |
18 #if defined(XP_UNIX) || defined(XP_OS2) | |
19 && (addr->raw.family != PR_AF_LOCAL) | |
20 #endif | |
21 && (addr->raw.family != PR_AF_INET6) | |
22 && (addr->raw.family != PR_AF_INET)) { | |
23 return PR_FALSE; | |
24 } | |
25 return PR_TRUE; | |
26 } | |
27 | |
28 static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len) | |
29 { | |
30 /* | |
31 * The definition of the length of a Unix domain socket address | |
32 * is not uniform, so we don't check it. | |
33 */ | |
34 if ((addr != NULL) | |
35 #if defined(XP_UNIX) || defined(XP_OS2) | |
36 && (addr->raw.family != AF_UNIX) | |
37 #endif | |
38 && (PR_NETADDR_SIZE(addr) != addr_len)) { | |
39 #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 | |
40 /* | |
41 * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 | |
42 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id | |
43 * field and is 28 bytes. It is possible for socket functions | |
44 * to return an addr_len greater than sizeof(struct sockaddr_in6). | |
45 * We need to allow that. (Bugzilla bug #77264) | |
46 */ | |
47 if ((PR_AF_INET6 == addr->raw.family) | |
48 && (sizeof(addr->ipv6) == addr_len)) { | |
49 return PR_TRUE; | |
50 } | |
51 #endif | |
52 /* | |
53 * The accept(), getsockname(), etc. calls on some platforms | |
54 * do not set the actual socket address length on return. | |
55 * In this case, we verifiy addr_len is still the value we | |
56 * passed in (i.e., sizeof(PRNetAddr)). | |
57 */ | |
58 #if defined(QNX) | |
59 if (sizeof(PRNetAddr) == addr_len) { | |
60 return PR_TRUE; | |
61 } | |
62 #endif | |
63 return PR_FALSE; | |
64 } | |
65 return PR_TRUE; | |
66 } | |
67 | |
68 #endif /* DEBUG */ | |
69 | |
70 static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov, | |
71 PRInt32 iov_size, PRIntervalTime timeout) | |
72 { | |
73 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
74 int w = 0; | |
75 const PRIOVec *tmp_iov; | |
76 #define LOCAL_MAXIOV 8 | |
77 PRIOVec local_iov[LOCAL_MAXIOV]; | |
78 PRIOVec *iov_copy = NULL; | |
79 int tmp_out; | |
80 int index, iov_cnt; | |
81 int count=0, sz = 0; /* 'count' is the return value. */ | |
82 | |
83 if (_PR_PENDING_INTERRUPT(me)) { | |
84 me->flags &= ~_PR_INTERRUPT; | |
85 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
86 return -1; | |
87 } | |
88 if (_PR_IO_PENDING(me)) { | |
89 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
90 return -1; | |
91 } | |
92 | |
93 /* | |
94 * Assume the first writev will succeed. Copy iov's only on | |
95 * failure. | |
96 */ | |
97 tmp_iov = iov; | |
98 for (index = 0; index < iov_size; index++) | |
99 sz += iov[index].iov_len; | |
100 | |
101 iov_cnt = iov_size; | |
102 | |
103 while (sz > 0) { | |
104 | |
105 w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); | |
106 if (w < 0) { | |
107 count = -1; | |
108 break; | |
109 } | |
110 count += w; | |
111 if (fd->secret->nonblocking) { | |
112 break; | |
113 } | |
114 sz -= w; | |
115 | |
116 if (sz > 0) { | |
117 /* find the next unwritten vector */ | |
118 for ( index = 0, tmp_out = count; | |
119 tmp_out >= iov[index].iov_len; | |
120 tmp_out -= iov[index].iov_len, index++){;} /* no
thing to execute */ | |
121 | |
122 if (tmp_iov == iov) { | |
123 /* | |
124 * The first writev failed so we | |
125 * must copy iov's around. | |
126 * Avoid calloc/free if there | |
127 * are few enough iov's. | |
128 */ | |
129 if (iov_size - index <= LOCAL_MAXIOV) | |
130 iov_copy = local_iov; | |
131 else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_
size - index) * | |
132 sizeof *iov_copy)) == NULL) { | |
133 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
134 return -1; | |
135 } | |
136 tmp_iov = iov_copy; | |
137 } | |
138 | |
139 PR_ASSERT(tmp_iov == iov_copy); | |
140 | |
141 /* fill in the first partial read */ | |
142 iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[t
mp_out]); | |
143 iov_copy[0].iov_len = iov[index].iov_len - tmp_out; | |
144 index++; | |
145 | |
146 /* copy the remaining vectors */ | |
147 for (iov_cnt=1; index<iov_size; iov_cnt++, index++) { | |
148 iov_copy[iov_cnt].iov_base = iov[index].iov_base
; | |
149 iov_copy[iov_cnt].iov_len = iov[index].iov_len; | |
150 } | |
151 } | |
152 } | |
153 | |
154 if (iov_copy != local_iov) | |
155 PR_DELETE(iov_copy); | |
156 return count; | |
157 } | |
158 | |
159 /************************************************************************/ | |
160 | |
161 PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PROsfd osfd) | |
162 { | |
163 PRFileDesc *fd; | |
164 | |
165 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
166 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); | |
167 if (fd != NULL) { | |
168 _PR_MD_MAKE_NONBLOCK(fd); | |
169 _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); | |
170 #ifdef _PR_NEED_SECRET_AF | |
171 /* this means we can only import IPv4 sockets here. | |
172 * but this is what the function in ptio.c does. | |
173 * We need a way to import IPv6 sockets, too. | |
174 */ | |
175 fd->secret->af = AF_INET; | |
176 #endif | |
177 } else | |
178 _PR_MD_CLOSE_SOCKET(osfd); | |
179 return(fd); | |
180 } | |
181 | |
182 PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd) | |
183 { | |
184 PRFileDesc *fd; | |
185 | |
186 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
187 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); | |
188 if (fd != NULL) { | |
189 _PR_MD_MAKE_NONBLOCK(fd); | |
190 _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); | |
191 } else | |
192 _PR_MD_CLOSE_SOCKET(osfd); | |
193 return(fd); | |
194 } | |
195 | |
196 | |
197 static const PRIOMethods* PR_GetSocketPollFdMethods(void); | |
198 | |
199 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd) | |
200 { | |
201 PRFileDesc *fd; | |
202 | |
203 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
204 | |
205 fd = _PR_Getfd(); | |
206 | |
207 if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
208 else | |
209 { | |
210 fd->secret->md.osfd = osfd; | |
211 fd->secret->inheritable = _PR_TRI_FALSE; | |
212 fd->secret->state = _PR_FILEDESC_OPEN; | |
213 fd->methods = PR_GetSocketPollFdMethods(); | |
214 } | |
215 | |
216 return fd; | |
217 } /* PR_CreateSocketPollFD */ | |
218 | |
219 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd) | |
220 { | |
221 if (NULL == fd) | |
222 { | |
223 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); | |
224 return PR_FAILURE; | |
225 } | |
226 fd->secret->state = _PR_FILEDESC_CLOSED; | |
227 _PR_Putfd(fd); | |
228 return PR_SUCCESS; | |
229 } /* PR_DestroySocketPollFd */ | |
230 | |
231 static PRStatus PR_CALLBACK SocketConnect( | |
232 PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout) | |
233 { | |
234 PRInt32 rv; /* Return value of _PR_MD_CONNECT */ | |
235 const PRNetAddr *addrp = addr; | |
236 #if defined(_PR_INET6) | |
237 PRNetAddr addrCopy; | |
238 #endif | |
239 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
240 | |
241 if (_PR_PENDING_INTERRUPT(me)) { | |
242 me->flags &= ~_PR_INTERRUPT; | |
243 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
244 return PR_FAILURE; | |
245 } | |
246 #if defined(_PR_INET6) | |
247 if (addr->raw.family == PR_AF_INET6) { | |
248 addrCopy = *addr; | |
249 addrCopy.raw.family = AF_INET6; | |
250 addrp = &addrCopy; | |
251 } | |
252 #endif | |
253 | |
254 rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout); | |
255 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv)); | |
256 if (rv == 0) | |
257 return PR_SUCCESS; | |
258 else | |
259 return PR_FAILURE; | |
260 } | |
261 | |
262 static PRStatus PR_CALLBACK SocketConnectContinue( | |
263 PRFileDesc *fd, PRInt16 out_flags) | |
264 { | |
265 PROsfd osfd; | |
266 int err; | |
267 | |
268 if (out_flags & PR_POLL_NVAL) { | |
269 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); | |
270 return PR_FAILURE; | |
271 } | |
272 if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) { | |
273 PR_ASSERT(out_flags == 0); | |
274 PR_SetError(PR_IN_PROGRESS_ERROR, 0); | |
275 return PR_FAILURE; | |
276 } | |
277 | |
278 osfd = fd->secret->md.osfd; | |
279 | |
280 #if defined(XP_UNIX) | |
281 | |
282 err = _MD_unix_get_nonblocking_connect_error(osfd); | |
283 if (err != 0) { | |
284 _PR_MD_MAP_CONNECT_ERROR(err); | |
285 return PR_FAILURE; | |
286 } | |
287 return PR_SUCCESS; | |
288 | |
289 #elif defined(WIN32) || defined(WIN16) | |
290 | |
291 #if defined(WIN32) | |
292 /* | |
293 * The sleep circumvents a bug in Win32 WinSock. | |
294 * See Microsoft Knowledge Base article ID: Q165989. | |
295 */ | |
296 Sleep(0); | |
297 #endif /* WIN32 */ | |
298 | |
299 if (out_flags & PR_POLL_EXCEPT) { | |
300 int len = sizeof(err); | |
301 if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len) | |
302 == SOCKET_ERROR) { | |
303 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); | |
304 return PR_FAILURE; | |
305 } | |
306 if (err != 0) { | |
307 _PR_MD_MAP_CONNECT_ERROR(err); | |
308 } else { | |
309 PR_SetError(PR_UNKNOWN_ERROR, 0); | |
310 } | |
311 return PR_FAILURE; | |
312 } | |
313 | |
314 PR_ASSERT(out_flags & PR_POLL_WRITE); | |
315 return PR_SUCCESS; | |
316 | |
317 #elif defined(XP_OS2) | |
318 | |
319 err = _MD_os2_get_nonblocking_connect_error(osfd); | |
320 if (err != 0) { | |
321 _PR_MD_MAP_CONNECT_ERROR(err); | |
322 return PR_FAILURE; | |
323 } | |
324 return PR_SUCCESS; | |
325 | |
326 #elif defined(XP_BEOS) | |
327 | |
328 #ifdef BONE_VERSION /* bug 122364 */ | |
329 /* temporary workaround until getsockopt(SO_ERROR) works in BONE */ | |
330 if (out_flags & PR_POLL_EXCEPT) { | |
331 PR_SetError(PR_CONNECT_REFUSED_ERROR, 0); | |
332 return PR_FAILURE; | |
333 } | |
334 PR_ASSERT(out_flags & PR_POLL_WRITE); | |
335 return PR_SUCCESS; | |
336 #else | |
337 err = _MD_beos_get_nonblocking_connect_error(fd); | |
338 if( err != 0 ) { | |
339 _PR_MD_MAP_CONNECT_ERROR(err); | |
340 return PR_FAILURE; | |
341 } | |
342 else | |
343 return PR_SUCCESS; | |
344 #endif /* BONE_VERSION */ | |
345 | |
346 #else | |
347 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
348 return PR_FAILURE; | |
349 #endif | |
350 } | |
351 | |
352 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd) | |
353 { | |
354 /* Find the NSPR layer and invoke its connectcontinue method */ | |
355 PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); | |
356 | |
357 if (NULL == bottom) { | |
358 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
359 return PR_FAILURE; | |
360 } | |
361 return SocketConnectContinue(bottom, pd->out_flags); | |
362 } | |
363 | |
364 static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr, | |
365 PRIntervalTime timeout) | |
366 { | |
367 PROsfd osfd; | |
368 PRFileDesc *fd2; | |
369 PRUint32 al; | |
370 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
371 #ifdef WINNT | |
372 PRNetAddr addrCopy; | |
373 #endif | |
374 | |
375 if (_PR_PENDING_INTERRUPT(me)) { | |
376 me->flags &= ~_PR_INTERRUPT; | |
377 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
378 return 0; | |
379 } | |
380 if (_PR_IO_PENDING(me)) { | |
381 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
382 return 0; | |
383 } | |
384 | |
385 #ifdef WINNT | |
386 if (addr == NULL) { | |
387 addr = &addrCopy; | |
388 } | |
389 #endif | |
390 al = sizeof(PRNetAddr); | |
391 osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout); | |
392 if (osfd == -1) | |
393 return 0; | |
394 | |
395 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); | |
396 if (!fd2) { | |
397 _PR_MD_CLOSE_SOCKET(osfd); | |
398 return NULL; | |
399 } | |
400 | |
401 fd2->secret->nonblocking = fd->secret->nonblocking; | |
402 fd2->secret->inheritable = fd->secret->inheritable; | |
403 #ifdef WINNT | |
404 if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRU
E) { | |
405 /* | |
406 * The new socket has been associated with an I/O | |
407 * completion port. There is no going back. | |
408 */ | |
409 fd2->secret->md.io_model_committed = PR_TRUE; | |
410 } | |
411 PR_ASSERT(al == PR_NETADDR_SIZE(addr)); | |
412 fd2->secret->md.accepted_socket = PR_TRUE; | |
413 memcpy(&fd2->secret->md.peer_addr, addr, al); | |
414 #endif | |
415 | |
416 /* | |
417 * On some platforms, the new socket created by accept() | |
418 * inherits the nonblocking (or overlapped io) attribute | |
419 * of the listening socket. As an optimization, these | |
420 * platforms can skip the following _PR_MD_MAKE_NONBLOCK | |
421 * call. | |
422 */ | |
423 #if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT) | |
424 _PR_MD_MAKE_NONBLOCK(fd2); | |
425 #endif | |
426 | |
427 #ifdef _PR_INET6 | |
428 if (addr && (AF_INET6 == addr->raw.family)) | |
429 addr->raw.family = PR_AF_INET6; | |
430 #endif | |
431 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); | |
432 PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE); | |
433 | |
434 return fd2; | |
435 } | |
436 | |
437 #ifdef WINNT | |
438 PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr, | |
439 PRIntervalTime timeout) | |
440 { | |
441 PROsfd osfd; | |
442 PRFileDesc *fd2; | |
443 PRIntn al; | |
444 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
445 PRNetAddr addrCopy; | |
446 | |
447 if (_PR_PENDING_INTERRUPT(me)) { | |
448 me->flags &= ~_PR_INTERRUPT; | |
449 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
450 return 0; | |
451 } | |
452 if (_PR_IO_PENDING(me)) { | |
453 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
454 return 0; | |
455 } | |
456 | |
457 if (addr == NULL) { | |
458 addr = &addrCopy; | |
459 } | |
460 al = PR_NETADDR_SIZE(addr); | |
461 osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL,
NULL); | |
462 if (osfd == -1) { | |
463 return 0; | |
464 } | |
465 | |
466 fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); | |
467 if (!fd2) { | |
468 _PR_MD_CLOSE_SOCKET(osfd); | |
469 } else { | |
470 fd2->secret->nonblocking = fd->secret->nonblocking; | |
471 fd2->secret->md.io_model_committed = PR_TRUE; | |
472 PR_ASSERT(al == PR_NETADDR_SIZE(addr)); | |
473 fd2->secret->md.accepted_socket = PR_TRUE; | |
474 memcpy(&fd2->secret->md.peer_addr, addr, al); | |
475 #ifdef _PR_INET6 | |
476 if (AF_INET6 == addr->raw.family) | |
477 addr->raw.family = PR_AF_INET6; | |
478 #endif | |
479 #ifdef _PR_NEED_SECRET_AF | |
480 fd2->secret->af = fd->secret->af; | |
481 #endif | |
482 } | |
483 return fd2; | |
484 } | |
485 #endif /* WINNT */ | |
486 | |
487 | |
488 static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr) | |
489 { | |
490 PRInt32 result; | |
491 const PRNetAddr *addrp = addr; | |
492 #if defined(_PR_INET6) | |
493 PRNetAddr addrCopy; | |
494 #endif | |
495 | |
496 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); | |
497 | |
498 #ifdef XP_UNIX | |
499 if (addr->raw.family == AF_UNIX) { | |
500 /* Disallow relative pathnames */ | |
501 if (addr->local.path[0] != '/') { | |
502 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
503 return PR_FAILURE; | |
504 } | |
505 } | |
506 #endif /* XP_UNIX */ | |
507 | |
508 #if defined(_PR_INET6) | |
509 if (addr->raw.family == PR_AF_INET6) { | |
510 addrCopy = *addr; | |
511 addrCopy.raw.family = AF_INET6; | |
512 addrp = &addrCopy; | |
513 } | |
514 #endif | |
515 result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr)); | |
516 if (result < 0) { | |
517 return PR_FAILURE; | |
518 } | |
519 return PR_SUCCESS; | |
520 } | |
521 | |
522 static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog) | |
523 { | |
524 PRInt32 result; | |
525 | |
526 result = _PR_MD_LISTEN(fd, backlog); | |
527 if (result < 0) { | |
528 return PR_FAILURE; | |
529 } | |
530 return PR_SUCCESS; | |
531 } | |
532 | |
533 static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how) | |
534 { | |
535 PRInt32 result; | |
536 | |
537 result = _PR_MD_SHUTDOWN(fd, how); | |
538 if (result < 0) { | |
539 return PR_FAILURE; | |
540 } | |
541 return PR_SUCCESS; | |
542 } | |
543 | |
544 static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
PRIntn flags, | |
545 PRIntervalTime timeout) | |
546 { | |
547 PRInt32 rv; | |
548 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
549 | |
550 if ((flags != 0) && (flags != PR_MSG_PEEK)) { | |
551 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
552 return -1; | |
553 } | |
554 if (_PR_PENDING_INTERRUPT(me)) { | |
555 me->flags &= ~_PR_INTERRUPT; | |
556 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
557 return -1; | |
558 } | |
559 if (_PR_IO_PENDING(me)) { | |
560 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
561 return -1; | |
562 } | |
563 | |
564 PR_LOG(_pr_io_lm, PR_LOG_MAX, | |
565 ("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d", | |
566 fd, fd->secret->md.osfd, buf, amount, flags)); | |
567 | |
568 #ifdef _PR_HAVE_PEEK_BUFFER | |
569 if (fd->secret->peekBytes != 0) { | |
570 rv = (amount < fd->secret->peekBytes) ? | |
571 amount : fd->secret->peekBytes; | |
572 memcpy(buf, fd->secret->peekBuffer, rv); | |
573 if (flags == 0) { | |
574 /* consume the bytes in the peek buffer */ | |
575 fd->secret->peekBytes -= rv; | |
576 if (fd->secret->peekBytes != 0) { | |
577 memmove(fd->secret->peekBuffer, | |
578 fd->secret->peekBuffer + rv, | |
579 fd->secret->peekBytes); | |
580 } | |
581 } | |
582 return rv; | |
583 } | |
584 | |
585 /* allocate peek buffer, if necessary */ | |
586 if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { | |
587 PR_ASSERT(0 == fd->secret->peekBytes); | |
588 /* impose a max size on the peek buffer */ | |
589 if (amount > _PR_PEEK_BUFFER_MAX) { | |
590 amount = _PR_PEEK_BUFFER_MAX; | |
591 } | |
592 if (fd->secret->peekBufSize < amount) { | |
593 if (fd->secret->peekBuffer) { | |
594 PR_Free(fd->secret->peekBuffer); | |
595 } | |
596 fd->secret->peekBufSize = amount; | |
597 fd->secret->peekBuffer = PR_Malloc(amount); | |
598 if (NULL == fd->secret->peekBuffer) { | |
599 fd->secret->peekBufSize = 0; | |
600 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
601 return -1; | |
602 } | |
603 } | |
604 } | |
605 #endif | |
606 | |
607 rv = _PR_MD_RECV(fd, buf, amount, flags, timeout); | |
608 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d", | |
609 rv, PR_GetError(), PR_GetOSError())); | |
610 | |
611 #ifdef _PR_HAVE_PEEK_BUFFER | |
612 if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) { | |
613 if (rv > 0) { | |
614 memcpy(fd->secret->peekBuffer, buf, rv); | |
615 fd->secret->peekBytes = rv; | |
616 } | |
617 } | |
618 #endif | |
619 | |
620 return rv; | |
621 } | |
622 | |
623 static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount) | |
624 { | |
625 return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); | |
626 } | |
627 | |
628 static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 a
mount, | |
629 PRIntn flags, PRIntervalTime timeout) | |
630 { | |
631 PRInt32 temp, count; | |
632 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
633 | |
634 if (_PR_PENDING_INTERRUPT(me)) { | |
635 me->flags &= ~_PR_INTERRUPT; | |
636 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
637 return -1; | |
638 } | |
639 if (_PR_IO_PENDING(me)) { | |
640 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
641 return -1; | |
642 } | |
643 | |
644 count = 0; | |
645 while (amount > 0) { | |
646 PR_LOG(_pr_io_lm, PR_LOG_MAX, | |
647 ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d", | |
648 fd, fd->secret->md.osfd, buf, amount)); | |
649 temp = _PR_MD_SEND(fd, buf, amount, flags, timeout); | |
650 if (temp < 0) { | |
651 count = -1; | |
652 break; | |
653 } | |
654 | |
655 count += temp; | |
656 if (fd->secret->nonblocking) { | |
657 break; | |
658 } | |
659 buf = (const void*) ((const char*)buf + temp); | |
660 | |
661 amount -= temp; | |
662 } | |
663 PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count)); | |
664 return count; | |
665 } | |
666 | |
667 static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32
amount) | |
668 { | |
669 return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT); | |
670 } | |
671 | |
672 static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd) | |
673 { | |
674 if (!fd || !fd->secret | |
675 || (fd->secret->state != _PR_FILEDESC_OPEN | |
676 && fd->secret->state != _PR_FILEDESC_CLOSED)) { | |
677 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); | |
678 return PR_FAILURE; | |
679 } | |
680 | |
681 if (fd->secret->state == _PR_FILEDESC_OPEN) { | |
682 if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) { | |
683 return PR_FAILURE; | |
684 } | |
685 fd->secret->state = _PR_FILEDESC_CLOSED; | |
686 } | |
687 | |
688 #ifdef _PR_HAVE_PEEK_BUFFER | |
689 if (fd->secret->peekBuffer) { | |
690 PR_ASSERT(fd->secret->peekBufSize > 0); | |
691 PR_DELETE(fd->secret->peekBuffer); | |
692 fd->secret->peekBufSize = 0; | |
693 fd->secret->peekBytes = 0; | |
694 } | |
695 #endif | |
696 | |
697 PR_FreeFileDesc(fd); | |
698 return PR_SUCCESS; | |
699 } | |
700 | |
701 static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd) | |
702 { | |
703 PRInt32 rv; | |
704 #ifdef _PR_HAVE_PEEK_BUFFER | |
705 if (fd->secret->peekBytes != 0) { | |
706 return fd->secret->peekBytes; | |
707 } | |
708 #endif | |
709 rv = _PR_MD_SOCKETAVAILABLE(fd); | |
710 return rv; | |
711 } | |
712 | |
713 static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd) | |
714 { | |
715 PRInt64 rv; | |
716 #ifdef _PR_HAVE_PEEK_BUFFER | |
717 if (fd->secret->peekBytes != 0) { | |
718 LL_I2L(rv, fd->secret->peekBytes); | |
719 return rv; | |
720 } | |
721 #endif | |
722 LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd)); | |
723 return rv; | |
724 } | |
725 | |
726 static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd) | |
727 { | |
728 return PR_SUCCESS; | |
729 } | |
730 | |
731 static PRInt32 PR_CALLBACK SocketSendTo( | |
732 PRFileDesc *fd, const void *buf, PRInt32 amount, | |
733 PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout) | |
734 { | |
735 PRInt32 temp, count; | |
736 const PRNetAddr *addrp = addr; | |
737 #if defined(_PR_INET6) | |
738 PRNetAddr addrCopy; | |
739 #endif | |
740 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
741 | |
742 if (_PR_PENDING_INTERRUPT(me)) { | |
743 me->flags &= ~_PR_INTERRUPT; | |
744 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
745 return -1; | |
746 } | |
747 if (_PR_IO_PENDING(me)) { | |
748 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
749 return -1; | |
750 } | |
751 | |
752 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); | |
753 #if defined(_PR_INET6) | |
754 if (addr->raw.family == PR_AF_INET6) { | |
755 addrCopy = *addr; | |
756 addrCopy.raw.family = AF_INET6; | |
757 addrp = &addrCopy; | |
758 } | |
759 #endif | |
760 | |
761 count = 0; | |
762 while (amount > 0) { | |
763 temp = _PR_MD_SENDTO(fd, buf, amount, flags, | |
764 addrp, PR_NETADDR_SIZE(addr), timeout); | |
765 if (temp < 0) { | |
766 count = -1; | |
767 break; | |
768 } | |
769 count += temp; | |
770 if (fd->secret->nonblocking) { | |
771 break; | |
772 } | |
773 buf = (const void*) ((const char*)buf + temp); | |
774 amount -= temp; | |
775 } | |
776 return count; | |
777 } | |
778 | |
779 static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amo
unt, | |
780 PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout) | |
781 { | |
782 PRInt32 rv; | |
783 PRUint32 al; | |
784 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
785 | |
786 if (_PR_PENDING_INTERRUPT(me)) { | |
787 me->flags &= ~_PR_INTERRUPT; | |
788 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
789 return -1; | |
790 } | |
791 if (_PR_IO_PENDING(me)) { | |
792 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
793 return -1; | |
794 } | |
795 | |
796 al = sizeof(PRNetAddr); | |
797 rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout); | |
798 #ifdef _PR_INET6 | |
799 if (addr && (AF_INET6 == addr->raw.family)) | |
800 addr->raw.family = PR_AF_INET6; | |
801 #endif | |
802 return rv; | |
803 } | |
804 | |
805 static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, | |
806 PRNetAddr **raddr, void *buf, PRInt32 amount, | |
807 PRIntervalTime timeout) | |
808 { | |
809 PRInt32 rv; | |
810 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
811 | |
812 if (_PR_PENDING_INTERRUPT(me)) { | |
813 me->flags &= ~_PR_INTERRUPT; | |
814 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
815 return -1; | |
816 } | |
817 if (_PR_IO_PENDING(me)) { | |
818 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
819 return -1; | |
820 } | |
821 /* The socket must be in blocking mode. */ | |
822 if (sd->secret->nonblocking) { | |
823 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
824 return -1; | |
825 } | |
826 *nd = NULL; | |
827 | |
828 #if defined(WINNT) | |
829 { | |
830 PROsfd newSock; | |
831 PRNetAddr *raddrCopy; | |
832 | |
833 if (raddr == NULL) { | |
834 raddr = &raddrCopy; | |
835 } | |
836 rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout); | |
837 if (rv < 0) { | |
838 rv = -1; | |
839 } else { | |
840 /* Successfully accepted and read; create the new PRFileDesc */ | |
841 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); | |
842 if (*nd == 0) { | |
843 _PR_MD_CLOSE_SOCKET(newSock); | |
844 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
845 rv = -1; | |
846 } else { | |
847 (*nd)->secret->md.io_model_committed = PR_TRUE; | |
848 (*nd)->secret->md.accepted_socket = PR_TRUE; | |
849 memcpy(&(*nd)->secret->md.peer_addr, *raddr, | |
850 PR_NETADDR_SIZE(*raddr)); | |
851 #ifdef _PR_INET6 | |
852 if (AF_INET6 == *raddr->raw.family) | |
853 *raddr->raw.family = PR_AF_INET6; | |
854 #endif | |
855 } | |
856 } | |
857 } | |
858 #else | |
859 rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); | |
860 #endif | |
861 return rv; | |
862 } | |
863 | |
864 #ifdef WINNT | |
865 PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, | |
866 PRNetAddr **raddr, void *buf, PRInt32 amount, | |
867 PRIntervalTime timeout) | |
868 { | |
869 PRInt32 rv; | |
870 PROsfd newSock; | |
871 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
872 PRNetAddr *raddrCopy; | |
873 | |
874 if (_PR_PENDING_INTERRUPT(me)) { | |
875 me->flags &= ~_PR_INTERRUPT; | |
876 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
877 return -1; | |
878 } | |
879 if (_PR_IO_PENDING(me)) { | |
880 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
881 return -1; | |
882 } | |
883 *nd = NULL; | |
884 | |
885 if (raddr == NULL) { | |
886 raddr = &raddrCopy; | |
887 } | |
888 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, | |
889 timeout, PR_TRUE, NULL, NULL); | |
890 if (rv < 0) { | |
891 rv = -1; | |
892 } else { | |
893 /* Successfully accepted and read; create the new PRFileDesc */ | |
894 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); | |
895 if (*nd == 0) { | |
896 _PR_MD_CLOSE_SOCKET(newSock); | |
897 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
898 rv = -1; | |
899 } else { | |
900 (*nd)->secret->md.io_model_committed = PR_TRUE; | |
901 (*nd)->secret->md.accepted_socket = PR_TRUE; | |
902 memcpy(&(*nd)->secret->md.peer_addr, *raddr, | |
903 PR_NETADDR_SIZE(*raddr)); | |
904 #ifdef _PR_INET6 | |
905 if (AF_INET6 == *raddr->raw.family) | |
906 *raddr->raw.family = PR_AF_INET6; | |
907 #endif | |
908 #ifdef _PR_NEED_SECRET_AF | |
909 (*nd)->secret->af = sd->secret->af; | |
910 #endif | |
911 } | |
912 } | |
913 return rv; | |
914 } | |
915 | |
916 PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback( | |
917 PRFileDesc *sd, PRFileDesc **nd, | |
918 PRNetAddr **raddr, void *buf, PRInt32 amount, | |
919 PRIntervalTime timeout, | |
920 _PR_AcceptTimeoutCallback callback, | |
921 void *callbackArg) | |
922 { | |
923 PRInt32 rv; | |
924 PROsfd newSock; | |
925 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
926 PRNetAddr *raddrCopy; | |
927 | |
928 if (_PR_PENDING_INTERRUPT(me)) { | |
929 me->flags &= ~_PR_INTERRUPT; | |
930 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
931 return -1; | |
932 } | |
933 if (_PR_IO_PENDING(me)) { | |
934 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
935 return -1; | |
936 } | |
937 *nd = NULL; | |
938 | |
939 if (raddr == NULL) { | |
940 raddr = &raddrCopy; | |
941 } | |
942 rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, | |
943 timeout, PR_TRUE, callback, callbackArg); | |
944 if (rv < 0) { | |
945 rv = -1; | |
946 } else { | |
947 /* Successfully accepted and read; create the new PRFileDesc */ | |
948 *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods()); | |
949 if (*nd == 0) { | |
950 _PR_MD_CLOSE_SOCKET(newSock); | |
951 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
952 rv = -1; | |
953 } else { | |
954 (*nd)->secret->md.io_model_committed = PR_TRUE; | |
955 (*nd)->secret->md.accepted_socket = PR_TRUE; | |
956 memcpy(&(*nd)->secret->md.peer_addr, *raddr, | |
957 PR_NETADDR_SIZE(*raddr)); | |
958 #ifdef _PR_INET6 | |
959 if (AF_INET6 == *raddr->raw.family) | |
960 *raddr->raw.family = PR_AF_INET6; | |
961 #endif | |
962 #ifdef _PR_NEED_SECRET_AF | |
963 (*nd)->secret->af = sd->secret->af; | |
964 #endif | |
965 } | |
966 } | |
967 return rv; | |
968 } | |
969 #endif /* WINNT */ | |
970 | |
971 #ifdef WINNT | |
972 PR_IMPLEMENT(void) | |
973 PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket) | |
974 { | |
975 _PR_MD_UPDATE_ACCEPT_CONTEXT( | |
976 socket->secret->md.osfd, acceptSocket->secret->md.osfd); | |
977 } | |
978 #endif /* WINNT */ | |
979 | |
980 static PRInt32 PR_CALLBACK SocketSendFile( | |
981 PRFileDesc *sd, PRSendFileData *sfd, | |
982 PRTransmitFileFlags flags, PRIntervalTime timeout) | |
983 { | |
984 PRInt32 rv; | |
985 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
986 | |
987 if (_PR_PENDING_INTERRUPT(me)) { | |
988 me->flags &= ~_PR_INTERRUPT; | |
989 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
990 return -1; | |
991 } | |
992 if (_PR_IO_PENDING(me)) { | |
993 PR_SetError(PR_IO_PENDING_ERROR, 0); | |
994 return -1; | |
995 } | |
996 /* The socket must be in blocking mode. */ | |
997 if (sd->secret->nonblocking) { | |
998 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
999 return -1; | |
1000 } | |
1001 #if defined(WINNT) | |
1002 rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout); | |
1003 if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { | |
1004 /* | |
1005 * This should be kept the same as SocketClose, except | |
1006 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should | |
1007 * not be called because the socket will be recycled. | |
1008 */ | |
1009 PR_FreeFileDesc(sd); | |
1010 } | |
1011 #else | |
1012 rv = PR_EmulateSendFile(sd, sfd, flags, timeout); | |
1013 #endif /* WINNT */ | |
1014 | |
1015 return rv; | |
1016 } | |
1017 | |
1018 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, | |
1019 const void *headers, PRInt32 hlen, PRTransmitFileFlags flags, | |
1020 PRIntervalTime timeout) | |
1021 { | |
1022 PRSendFileData sfd; | |
1023 | |
1024 sfd.fd = fd; | |
1025 sfd.file_offset = 0; | |
1026 sfd.file_nbytes = 0; | |
1027 sfd.header = headers; | |
1028 sfd.hlen = hlen; | |
1029 sfd.trailer = NULL; | |
1030 sfd.tlen = 0; | |
1031 | |
1032 return(SocketSendFile(sd, &sfd, flags, timeout)); | |
1033 } | |
1034 | |
1035 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr) | |
1036 { | |
1037 PRInt32 result; | |
1038 PRUint32 addrlen; | |
1039 | |
1040 addrlen = sizeof(PRNetAddr); | |
1041 result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen); | |
1042 if (result < 0) { | |
1043 return PR_FAILURE; | |
1044 } | |
1045 #ifdef _PR_INET6 | |
1046 if (AF_INET6 == addr->raw.family) | |
1047 addr->raw.family = PR_AF_INET6; | |
1048 #endif | |
1049 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); | |
1050 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); | |
1051 return PR_SUCCESS; | |
1052 } | |
1053 | |
1054 static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr) | |
1055 { | |
1056 PRInt32 result; | |
1057 PRUint32 addrlen; | |
1058 | |
1059 addrlen = sizeof(PRNetAddr); | |
1060 result = _PR_MD_GETPEERNAME(fd, addr, &addrlen); | |
1061 if (result < 0) { | |
1062 return PR_FAILURE; | |
1063 } | |
1064 #ifdef _PR_INET6 | |
1065 if (AF_INET6 == addr->raw.family) | |
1066 addr->raw.family = PR_AF_INET6; | |
1067 #endif | |
1068 PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE); | |
1069 PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE); | |
1070 return PR_SUCCESS; | |
1071 } | |
1072 | |
1073 static PRInt16 PR_CALLBACK SocketPoll( | |
1074 PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) | |
1075 { | |
1076 *out_flags = 0; | |
1077 return in_flags; | |
1078 } /* SocketPoll */ | |
1079 | |
1080 static PRIOMethods tcpMethods = { | |
1081 PR_DESC_SOCKET_TCP, | |
1082 SocketClose, | |
1083 SocketRead, | |
1084 SocketWrite, | |
1085 SocketAvailable, | |
1086 SocketAvailable64, | |
1087 SocketSync, | |
1088 (PRSeekFN)_PR_InvalidInt, | |
1089 (PRSeek64FN)_PR_InvalidInt64, | |
1090 (PRFileInfoFN)_PR_InvalidStatus, | |
1091 (PRFileInfo64FN)_PR_InvalidStatus, | |
1092 SocketWritev, | |
1093 SocketConnect, | |
1094 SocketAccept, | |
1095 SocketBind, | |
1096 SocketListen, | |
1097 SocketShutdown, | |
1098 SocketRecv, | |
1099 SocketSend, | |
1100 (PRRecvfromFN)_PR_InvalidInt, | |
1101 (PRSendtoFN)_PR_InvalidInt, | |
1102 SocketPoll, | |
1103 SocketAcceptRead, | |
1104 SocketTransmitFile, | |
1105 SocketGetName, | |
1106 SocketGetPeerName, | |
1107 (PRReservedFN)_PR_InvalidInt, | |
1108 (PRReservedFN)_PR_InvalidInt, | |
1109 _PR_SocketGetSocketOption, | |
1110 _PR_SocketSetSocketOption, | |
1111 SocketSendFile, | |
1112 SocketConnectContinue, | |
1113 (PRReservedFN)_PR_InvalidInt, | |
1114 (PRReservedFN)_PR_InvalidInt, | |
1115 (PRReservedFN)_PR_InvalidInt, | |
1116 (PRReservedFN)_PR_InvalidInt | |
1117 }; | |
1118 | |
1119 static PRIOMethods udpMethods = { | |
1120 PR_DESC_SOCKET_UDP, | |
1121 SocketClose, | |
1122 SocketRead, | |
1123 SocketWrite, | |
1124 SocketAvailable, | |
1125 SocketAvailable64, | |
1126 SocketSync, | |
1127 (PRSeekFN)_PR_InvalidInt, | |
1128 (PRSeek64FN)_PR_InvalidInt64, | |
1129 (PRFileInfoFN)_PR_InvalidStatus, | |
1130 (PRFileInfo64FN)_PR_InvalidStatus, | |
1131 SocketWritev, | |
1132 SocketConnect, | |
1133 (PRAcceptFN)_PR_InvalidDesc, | |
1134 SocketBind, | |
1135 SocketListen, | |
1136 SocketShutdown, | |
1137 SocketRecv, | |
1138 SocketSend, | |
1139 SocketRecvFrom, | |
1140 SocketSendTo, | |
1141 SocketPoll, | |
1142 (PRAcceptreadFN)_PR_InvalidInt, | |
1143 (PRTransmitfileFN)_PR_InvalidInt, | |
1144 SocketGetName, | |
1145 SocketGetPeerName, | |
1146 (PRReservedFN)_PR_InvalidInt, | |
1147 (PRReservedFN)_PR_InvalidInt, | |
1148 _PR_SocketGetSocketOption, | |
1149 _PR_SocketSetSocketOption, | |
1150 (PRSendfileFN)_PR_InvalidInt, | |
1151 (PRConnectcontinueFN)_PR_InvalidStatus, | |
1152 (PRReservedFN)_PR_InvalidInt, | |
1153 (PRReservedFN)_PR_InvalidInt, | |
1154 (PRReservedFN)_PR_InvalidInt, | |
1155 (PRReservedFN)_PR_InvalidInt | |
1156 }; | |
1157 | |
1158 | |
1159 static PRIOMethods socketpollfdMethods = { | |
1160 (PRDescType) 0, | |
1161 (PRCloseFN)_PR_InvalidStatus, | |
1162 (PRReadFN)_PR_InvalidInt, | |
1163 (PRWriteFN)_PR_InvalidInt, | |
1164 (PRAvailableFN)_PR_InvalidInt, | |
1165 (PRAvailable64FN)_PR_InvalidInt64, | |
1166 (PRFsyncFN)_PR_InvalidStatus, | |
1167 (PRSeekFN)_PR_InvalidInt, | |
1168 (PRSeek64FN)_PR_InvalidInt64, | |
1169 (PRFileInfoFN)_PR_InvalidStatus, | |
1170 (PRFileInfo64FN)_PR_InvalidStatus, | |
1171 (PRWritevFN)_PR_InvalidInt, | |
1172 (PRConnectFN)_PR_InvalidStatus, | |
1173 (PRAcceptFN)_PR_InvalidDesc, | |
1174 (PRBindFN)_PR_InvalidStatus, | |
1175 (PRListenFN)_PR_InvalidStatus, | |
1176 (PRShutdownFN)_PR_InvalidStatus, | |
1177 (PRRecvFN)_PR_InvalidInt, | |
1178 (PRSendFN)_PR_InvalidInt, | |
1179 (PRRecvfromFN)_PR_InvalidInt, | |
1180 (PRSendtoFN)_PR_InvalidInt, | |
1181 SocketPoll, | |
1182 (PRAcceptreadFN)_PR_InvalidInt, | |
1183 (PRTransmitfileFN)_PR_InvalidInt, | |
1184 (PRGetsocknameFN)_PR_InvalidStatus, | |
1185 (PRGetpeernameFN)_PR_InvalidStatus, | |
1186 (PRReservedFN)_PR_InvalidInt, | |
1187 (PRReservedFN)_PR_InvalidInt, | |
1188 (PRGetsocketoptionFN)_PR_InvalidStatus, | |
1189 (PRSetsocketoptionFN)_PR_InvalidStatus, | |
1190 (PRSendfileFN)_PR_InvalidInt, | |
1191 (PRConnectcontinueFN)_PR_InvalidStatus, | |
1192 (PRReservedFN)_PR_InvalidInt, | |
1193 (PRReservedFN)_PR_InvalidInt, | |
1194 (PRReservedFN)_PR_InvalidInt, | |
1195 (PRReservedFN)_PR_InvalidInt | |
1196 }; | |
1197 | |
1198 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods() | |
1199 { | |
1200 return &tcpMethods; | |
1201 } | |
1202 | |
1203 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods() | |
1204 { | |
1205 return &udpMethods; | |
1206 } | |
1207 | |
1208 static const PRIOMethods* PR_GetSocketPollFdMethods() | |
1209 { | |
1210 return &socketpollfdMethods; | |
1211 } /* PR_GetSocketPollFdMethods */ | |
1212 | |
1213 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE) | |
1214 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd); | |
1215 | |
1216 #if defined(_PR_INET6_PROBE) | |
1217 | |
1218 extern PRBool _pr_ipv6_is_present(void); | |
1219 | |
1220 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket() | |
1221 { | |
1222 PROsfd osfd; | |
1223 | |
1224 osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0); | |
1225 if (osfd != -1) { | |
1226 _PR_MD_CLOSE_SOCKET(osfd); | |
1227 return PR_TRUE; | |
1228 } | |
1229 return PR_FALSE; | |
1230 } | |
1231 #endif /* _PR_INET6_PROBE */ | |
1232 | |
1233 #endif | |
1234 | |
1235 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto) | |
1236 { | |
1237 PROsfd osfd; | |
1238 PRFileDesc *fd; | |
1239 PRInt32 tmp_domain = domain; | |
1240 | |
1241 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1242 if (PR_AF_INET != domain | |
1243 && PR_AF_INET6 != domain | |
1244 #if defined(XP_UNIX) || defined(XP_OS2) | |
1245 && PR_AF_LOCAL != domain | |
1246 #endif | |
1247 ) { | |
1248 PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0); | |
1249 return NULL; | |
1250 } | |
1251 | |
1252 #if defined(_PR_INET6_PROBE) | |
1253 if (PR_AF_INET6 == domain) | |
1254 domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET; | |
1255 #elif defined(_PR_INET6) | |
1256 if (PR_AF_INET6 == domain) | |
1257 domain = AF_INET6; | |
1258 #else | |
1259 if (PR_AF_INET6 == domain) | |
1260 domain = AF_INET; | |
1261 #endif /* _PR_INET6 */ | |
1262 osfd = _PR_MD_SOCKET(domain, type, proto); | |
1263 if (osfd == -1) { | |
1264 return 0; | |
1265 } | |
1266 if (type == SOCK_STREAM) | |
1267 fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); | |
1268 else | |
1269 fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods()); | |
1270 /* | |
1271 * Make the sockets non-blocking | |
1272 */ | |
1273 if (fd != NULL) { | |
1274 _PR_MD_MAKE_NONBLOCK(fd); | |
1275 _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE); | |
1276 #ifdef _PR_NEED_SECRET_AF | |
1277 fd->secret->af = domain; | |
1278 #endif | |
1279 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6) | |
1280 /* | |
1281 * For platforms with no support for IPv6 | |
1282 * create layered socket for IPv4-mapped IPv6 addresses | |
1283 */ | |
1284 if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) { | |
1285 if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) { | |
1286 PR_Close(fd); | |
1287 fd = NULL; | |
1288 } | |
1289 } | |
1290 #endif | |
1291 } else | |
1292 _PR_MD_CLOSE_SOCKET(osfd); | |
1293 | |
1294 return fd; | |
1295 } | |
1296 | |
1297 PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void) | |
1298 { | |
1299 PRInt32 domain = AF_INET; | |
1300 | |
1301 return PR_Socket(domain, SOCK_STREAM, 0); | |
1302 } | |
1303 | |
1304 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void) | |
1305 { | |
1306 PRInt32 domain = AF_INET; | |
1307 | |
1308 return PR_Socket(domain, SOCK_DGRAM, 0); | |
1309 } | |
1310 | |
1311 PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af) | |
1312 { | |
1313 return PR_Socket(af, SOCK_STREAM, 0); | |
1314 } | |
1315 | |
1316 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af) | |
1317 { | |
1318 return PR_Socket(af, SOCK_DGRAM, 0); | |
1319 } | |
1320 | |
1321 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[]) | |
1322 { | |
1323 #ifdef XP_UNIX | |
1324 PRInt32 rv, osfd[2]; | |
1325 | |
1326 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1327 | |
1328 rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd); | |
1329 if (rv == -1) { | |
1330 return PR_FAILURE; | |
1331 } | |
1332 | |
1333 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); | |
1334 if (!f[0]) { | |
1335 _PR_MD_CLOSE_SOCKET(osfd[0]); | |
1336 _PR_MD_CLOSE_SOCKET(osfd[1]); | |
1337 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
1338 return PR_FAILURE; | |
1339 } | |
1340 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); | |
1341 if (!f[1]) { | |
1342 PR_Close(f[0]); | |
1343 _PR_MD_CLOSE_SOCKET(osfd[1]); | |
1344 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
1345 return PR_FAILURE; | |
1346 } | |
1347 _PR_MD_MAKE_NONBLOCK(f[0]); | |
1348 _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); | |
1349 _PR_MD_MAKE_NONBLOCK(f[1]); | |
1350 _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); | |
1351 return PR_SUCCESS; | |
1352 #elif defined(WINNT) | |
1353 /* | |
1354 * A socket pair is often used for interprocess communication, | |
1355 * so we need to make sure neither socket is associated with | |
1356 * the I/O completion port; otherwise it can't be used by a | |
1357 * child process. | |
1358 * | |
1359 * The default implementation below cannot be used for NT | |
1360 * because PR_Accept would have associated the I/O completion | |
1361 * port with the listening and accepted sockets. | |
1362 */ | |
1363 SOCKET listenSock; | |
1364 SOCKET osfd[2]; | |
1365 struct sockaddr_in selfAddr, peerAddr; | |
1366 int addrLen; | |
1367 | |
1368 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1369 | |
1370 osfd[0] = osfd[1] = INVALID_SOCKET; | |
1371 listenSock = socket(AF_INET, SOCK_STREAM, 0); | |
1372 if (listenSock == INVALID_SOCKET) { | |
1373 goto failed; | |
1374 } | |
1375 selfAddr.sin_family = AF_INET; | |
1376 selfAddr.sin_port = 0; | |
1377 selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */ | |
1378 addrLen = sizeof(selfAddr); | |
1379 if (bind(listenSock, (struct sockaddr *) &selfAddr, | |
1380 addrLen) == SOCKET_ERROR) { | |
1381 goto failed; | |
1382 } | |
1383 if (getsockname(listenSock, (struct sockaddr *) &selfAddr, | |
1384 &addrLen) == SOCKET_ERROR) { | |
1385 goto failed; | |
1386 } | |
1387 if (listen(listenSock, 5) == SOCKET_ERROR) { | |
1388 goto failed; | |
1389 } | |
1390 osfd[0] = socket(AF_INET, SOCK_STREAM, 0); | |
1391 if (osfd[0] == INVALID_SOCKET) { | |
1392 goto failed; | |
1393 } | |
1394 selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
1395 | |
1396 /* | |
1397 * Only a thread is used to do the connect and accept. | |
1398 * I am relying on the fact that connect returns | |
1399 * successfully as soon as the connect request is put | |
1400 * into the listen queue (but before accept is called). | |
1401 * This is the behavior of the BSD socket code. If | |
1402 * connect does not return until accept is called, we | |
1403 * will need to create another thread to call connect. | |
1404 */ | |
1405 if (connect(osfd[0], (struct sockaddr *) &selfAddr, | |
1406 addrLen) == SOCKET_ERROR) { | |
1407 goto failed; | |
1408 } | |
1409 /* | |
1410 * A malicious local process may connect to the listening | |
1411 * socket, so we need to verify that the accepted connection | |
1412 * is made from our own socket osfd[0]. | |
1413 */ | |
1414 if (getsockname(osfd[0], (struct sockaddr *) &selfAddr, | |
1415 &addrLen) == SOCKET_ERROR) { | |
1416 goto failed; | |
1417 } | |
1418 osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen); | |
1419 if (osfd[1] == INVALID_SOCKET) { | |
1420 goto failed; | |
1421 } | |
1422 if (peerAddr.sin_port != selfAddr.sin_port) { | |
1423 /* the connection we accepted is not from osfd[0] */ | |
1424 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); | |
1425 goto failed; | |
1426 } | |
1427 closesocket(listenSock); | |
1428 | |
1429 f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); | |
1430 if (!f[0]) { | |
1431 closesocket(osfd[0]); | |
1432 closesocket(osfd[1]); | |
1433 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
1434 return PR_FAILURE; | |
1435 } | |
1436 f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); | |
1437 if (!f[1]) { | |
1438 PR_Close(f[0]); | |
1439 closesocket(osfd[1]); | |
1440 /* PR_AllocFileDesc() has invoked PR_SetError(). */ | |
1441 return PR_FAILURE; | |
1442 } | |
1443 _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE); | |
1444 _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); | |
1445 return PR_SUCCESS; | |
1446 | |
1447 failed: | |
1448 if (listenSock != INVALID_SOCKET) { | |
1449 closesocket(listenSock); | |
1450 } | |
1451 if (osfd[0] != INVALID_SOCKET) { | |
1452 closesocket(osfd[0]); | |
1453 } | |
1454 if (osfd[1] != INVALID_SOCKET) { | |
1455 closesocket(osfd[1]); | |
1456 } | |
1457 return PR_FAILURE; | |
1458 #else /* not Unix or NT */ | |
1459 /* | |
1460 * default implementation | |
1461 */ | |
1462 PRFileDesc *listenSock; | |
1463 PRNetAddr selfAddr, peerAddr; | |
1464 PRUint16 port; | |
1465 | |
1466 f[0] = f[1] = NULL; | |
1467 listenSock = PR_NewTCPSocket(); | |
1468 if (listenSock == NULL) { | |
1469 goto failed; | |
1470 } | |
1471 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ | |
1472 if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { | |
1473 goto failed; | |
1474 } | |
1475 if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { | |
1476 goto failed; | |
1477 } | |
1478 port = ntohs(selfAddr.inet.port); | |
1479 if (PR_Listen(listenSock, 5) == PR_FAILURE) { | |
1480 goto failed; | |
1481 } | |
1482 f[0] = PR_NewTCPSocket(); | |
1483 if (f[0] == NULL) { | |
1484 goto failed; | |
1485 } | |
1486 #ifdef _PR_CONNECT_DOES_NOT_BIND | |
1487 /* | |
1488 * If connect does not implicitly bind the socket (e.g., on | |
1489 * BeOS), we have to bind the socket so that we can get its | |
1490 * port with getsockname later. | |
1491 */ | |
1492 PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); | |
1493 if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { | |
1494 goto failed; | |
1495 } | |
1496 #endif | |
1497 PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr); | |
1498 | |
1499 /* | |
1500 * Only a thread is used to do the connect and accept. | |
1501 * I am relying on the fact that PR_Connect returns | |
1502 * successfully as soon as the connect request is put | |
1503 * into the listen queue (but before PR_Accept is called). | |
1504 * This is the behavior of the BSD socket code. If | |
1505 * connect does not return until accept is called, we | |
1506 * will need to create another thread to call connect. | |
1507 */ | |
1508 if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) | |
1509 == PR_FAILURE) { | |
1510 goto failed; | |
1511 } | |
1512 /* | |
1513 * A malicious local process may connect to the listening | |
1514 * socket, so we need to verify that the accepted connection | |
1515 * is made from our own socket f[0]. | |
1516 */ | |
1517 if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { | |
1518 goto failed; | |
1519 } | |
1520 f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); | |
1521 if (f[1] == NULL) { | |
1522 goto failed; | |
1523 } | |
1524 if (peerAddr.inet.port != selfAddr.inet.port) { | |
1525 /* the connection we accepted is not from f[0] */ | |
1526 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); | |
1527 goto failed; | |
1528 } | |
1529 PR_Close(listenSock); | |
1530 return PR_SUCCESS; | |
1531 | |
1532 failed: | |
1533 if (listenSock) { | |
1534 PR_Close(listenSock); | |
1535 } | |
1536 if (f[0]) { | |
1537 PR_Close(f[0]); | |
1538 } | |
1539 if (f[1]) { | |
1540 PR_Close(f[1]); | |
1541 } | |
1542 return PR_FAILURE; | |
1543 #endif | |
1544 } | |
1545 | |
1546 PR_IMPLEMENT(PROsfd) | |
1547 PR_FileDesc2NativeHandle(PRFileDesc *fd) | |
1548 { | |
1549 if (fd) { | |
1550 fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER); | |
1551 } | |
1552 if (!fd) { | |
1553 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
1554 return -1; | |
1555 } | |
1556 return fd->secret->md.osfd; | |
1557 } | |
1558 | |
1559 PR_IMPLEMENT(void) | |
1560 PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PROsfd handle) | |
1561 { | |
1562 if (fd) | |
1563 fd->secret->md.osfd = handle; | |
1564 } | |
1565 | |
1566 /* | |
1567 ** Select compatibility | |
1568 ** | |
1569 */ | |
1570 | |
1571 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set) | |
1572 { | |
1573 memset(set, 0, sizeof(PR_fd_set)); | |
1574 } | |
1575 | |
1576 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set) | |
1577 { | |
1578 PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC ); | |
1579 | |
1580 set->harray[set->hsize++] = fh; | |
1581 } | |
1582 | |
1583 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set) | |
1584 { | |
1585 PRUint32 index, index2; | |
1586 | |
1587 for (index = 0; index<set->hsize; index++) | |
1588 if (set->harray[index] == fh) { | |
1589 for (index2=index; index2 < (set->hsize-1); index2++) { | |
1590 set->harray[index2] = set->harray[index2+1]; | |
1591 } | |
1592 set->hsize--; | |
1593 break; | |
1594 } | |
1595 } | |
1596 | |
1597 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set) | |
1598 { | |
1599 PRUint32 index; | |
1600 for (index = 0; index<set->hsize; index++) | |
1601 if (set->harray[index] == fh) { | |
1602 return 1; | |
1603 } | |
1604 return 0; | |
1605 } | |
1606 | |
1607 PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set *set) | |
1608 { | |
1609 PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC ); | |
1610 | |
1611 set->narray[set->nsize++] = fd; | |
1612 } | |
1613 | |
1614 PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set *set) | |
1615 { | |
1616 PRUint32 index, index2; | |
1617 | |
1618 for (index = 0; index<set->nsize; index++) | |
1619 if (set->narray[index] == fd) { | |
1620 for (index2=index; index2 < (set->nsize-1); index2++) { | |
1621 set->narray[index2] = set->narray[index2+1]; | |
1622 } | |
1623 set->nsize--; | |
1624 break; | |
1625 } | |
1626 } | |
1627 | |
1628 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set *set) | |
1629 { | |
1630 PRUint32 index; | |
1631 for (index = 0; index<set->nsize; index++) | |
1632 if (set->narray[index] == fd) { | |
1633 return 1; | |
1634 } | |
1635 return 0; | |
1636 } | |
1637 | |
1638 | |
1639 #if !defined(NEED_SELECT) | |
1640 #include "obsolete/probslet.h" | |
1641 | |
1642 #define PD_INCR 20 | |
1643 | |
1644 static PRPollDesc *_pr_setfd( | |
1645 PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc) | |
1646 { | |
1647 PRUintn fsidx, pdidx; | |
1648 PRPollDesc *poll = polldesc; | |
1649 | |
1650 if (NULL == set) return poll; | |
1651 | |
1652 /* First set the pr file handle osfds */ | |
1653 for (fsidx = 0; fsidx < set->hsize; fsidx++) | |
1654 { | |
1655 for (pdidx = 0; 1; pdidx++) | |
1656 { | |
1657 if ((PRFileDesc*)-1 == poll[pdidx].fd) | |
1658 { | |
1659 /* our vector is full - extend and condition it */ | |
1660 poll = (PRPollDesc*)PR_Realloc( | |
1661 poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc)); | |
1662 if (NULL == poll) goto out_of_memory; | |
1663 memset( | |
1664 poll + pdidx * sizeof(PRPollDesc), | |
1665 0, PD_INCR * sizeof(PRPollDesc)); | |
1666 poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1; | |
1667 } | |
1668 if ((NULL == poll[pdidx].fd) | |
1669 || (poll[pdidx].fd == set->harray[fsidx])) | |
1670 { | |
1671 /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */ | |
1672 /* either empty or prevously defined */ | |
1673 poll[pdidx].fd = set->harray[fsidx]; /* possibly redundant */ | |
1674 poll[pdidx].in_flags |= flags; /* possibly redundant */ | |
1675 break; | |
1676 } | |
1677 } | |
1678 } | |
1679 | |
1680 #if 0 | |
1681 /* Second set the native osfds */ | |
1682 for (fsidx = 0; fsidx < set->nsize; fsidx++) | |
1683 { | |
1684 for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++) | |
1685 { | |
1686 if ((PRFileDesc*)-1 == poll[pdidx].fd) | |
1687 { | |
1688 /* our vector is full - extend and condition it */ | |
1689 poll = PR_Realloc( | |
1690 poll, (pdidx + PD_INCR) * sizeof(PRPollDesc)); | |
1691 if (NULL == poll) goto out_of_memory; | |
1692 memset( | |
1693 poll + pdidx * sizeof(PRPollDesc), | |
1694 0, PD_INCR * sizeof(PRPollDesc)); | |
1695 poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1; | |
1696 } | |
1697 if ((NULL == poll[pdidx].fd) | |
1698 || (poll[pdidx].fd == set->narray[fsidx])) | |
1699 { | |
1700 /* either empty or prevously defined */ | |
1701 poll[pdidx].fd = set->narray[fsidx]; | |
1702 PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); | |
1703 poll[pdidx].in_flags |= flags; | |
1704 break; | |
1705 } | |
1706 } | |
1707 } | |
1708 #endif /* 0 */ | |
1709 | |
1710 return poll; | |
1711 | |
1712 out_of_memory: | |
1713 if (NULL != polldesc) PR_DELETE(polldesc); | |
1714 return NULL; | |
1715 } /* _pr_setfd */ | |
1716 | |
1717 #endif /* !defined(NEED_SELECT) */ | |
1718 | |
1719 PR_IMPLEMENT(PRInt32) PR_Select( | |
1720 PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, | |
1721 PR_fd_set *pr_ex, PRIntervalTime timeout) | |
1722 { | |
1723 | |
1724 #if !defined(NEED_SELECT) | |
1725 PRInt32 npds = 0; | |
1726 /* | |
1727 ** Find out how many fds are represented in the three lists. | |
1728 ** Then allocate a polling descriptor for the logical union | |
1729 ** (there can't be any overlapping) and call PR_Poll(). | |
1730 */ | |
1731 | |
1732 PRPollDesc *copy, *poll; | |
1733 | |
1734 static PRBool warning = PR_TRUE; | |
1735 if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()"); | |
1736 | |
1737 /* try to get an initial guesss at how much space we need */ | |
1738 npds = 0; | |
1739 if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0)) | |
1740 npds = pr_rd->hsize + pr_rd->nsize; | |
1741 if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0)) | |
1742 npds = pr_wr->hsize + pr_wr->nsize; | |
1743 if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0)) | |
1744 npds = pr_ex->hsize + pr_ex->nsize; | |
1745 | |
1746 if (0 == npds) | |
1747 { | |
1748 PR_Sleep(timeout); | |
1749 return 0; | |
1750 } | |
1751 | |
1752 copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc)); | |
1753 if (NULL == poll) goto out_of_memory; | |
1754 poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1; | |
1755 | |
1756 poll = _pr_setfd(pr_rd, PR_POLL_READ, poll); | |
1757 if (NULL == poll) goto out_of_memory; | |
1758 poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll); | |
1759 if (NULL == poll) goto out_of_memory; | |
1760 poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll); | |
1761 if (NULL == poll) goto out_of_memory; | |
1762 unused = 0; | |
1763 while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd) | |
1764 { | |
1765 ++unused; | |
1766 } | |
1767 | |
1768 PR_ASSERT(unused > 0); | |
1769 npds = PR_Poll(poll, unused, timeout); | |
1770 | |
1771 if (npds > 0) | |
1772 { | |
1773 /* Copy the results back into the fd sets */ | |
1774 if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0; | |
1775 if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0; | |
1776 if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0; | |
1777 for (copy = &poll[unused - 1]; copy >= poll; --copy) | |
1778 { | |
1779 if (copy->out_flags & PR_POLL_NVAL) | |
1780 { | |
1781 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0); | |
1782 npds = -1; | |
1783 break; | |
1784 } | |
1785 if (copy->out_flags & PR_POLL_READ) | |
1786 if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd; | |
1787 if (copy->out_flags & PR_POLL_WRITE) | |
1788 if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd; | |
1789 if (copy->out_flags & PR_POLL_EXCEPT) | |
1790 if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd; | |
1791 } | |
1792 } | |
1793 PR_DELETE(poll); | |
1794 | |
1795 return npds; | |
1796 out_of_memory: | |
1797 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
1798 return -1; | |
1799 | |
1800 #endif /* !defined(NEED_SELECT) */ | |
1801 | |
1802 } | |
OLD | NEW |