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