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