| 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 (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_TRU
E) { | |
| 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 a
mount, | |
| 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 amo
unt, | |
| 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 } | |
| OLD | NEW |