nsprpub/pr/src/io/prsocket.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial