nsprpub/pr/src/md/beos/bnet.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; c-basic-offset: 4 -*- */
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 <signal.h>
michael@0 9 #include <unistd.h>
michael@0 10 #include <memory.h>
michael@0 11 #include <fcntl.h>
michael@0 12 #include <sys/types.h>
michael@0 13 #include <sys/socket.h>
michael@0 14 #include <sys/time.h>
michael@0 15 #include <sys/ioctl.h>
michael@0 16
michael@0 17 /*
michael@0 18 * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
michael@0 19 * PRInt32* pointer to a _PRSockLen_t* pointer.
michael@0 20 */
michael@0 21 #define _PRSockLen_t int
michael@0 22
michael@0 23
michael@0 24 /*
michael@0 25 ** Global lock variable used to bracket calls into rusty libraries that
michael@0 26 ** aren't thread safe (like libc, libX, etc).
michael@0 27 */
michael@0 28 static PRLock *_pr_rename_lock = NULL;
michael@0 29 static PRMonitor *_pr_Xfe_mon = NULL;
michael@0 30
michael@0 31 #define READ_FD 1
michael@0 32 #define WRITE_FD 2
michael@0 33
michael@0 34 /*
michael@0 35 ** This is a support routine to handle "deferred" i/o on sockets.
michael@0 36 ** It uses "select", so it is subject to all of the BeOS limitations
michael@0 37 ** (only READ notification, only sockets)
michael@0 38 */
michael@0 39
michael@0 40 /*
michael@0 41 * socket_io_wait --
michael@0 42 *
michael@0 43 * wait for socket i/o, periodically checking for interrupt
michael@0 44 *
michael@0 45 */
michael@0 46
michael@0 47 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
michael@0 48 PRIntervalTime timeout)
michael@0 49 {
michael@0 50 PRInt32 rv = -1;
michael@0 51 struct timeval tv;
michael@0 52 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 53 PRIntervalTime epoch, now, elapsed, remaining;
michael@0 54 PRBool wait_for_remaining;
michael@0 55 PRInt32 syserror;
michael@0 56 fd_set rd_wr;
michael@0 57
michael@0 58 switch (timeout) {
michael@0 59 case PR_INTERVAL_NO_WAIT:
michael@0 60 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
michael@0 61 break;
michael@0 62 case PR_INTERVAL_NO_TIMEOUT:
michael@0 63 /*
michael@0 64 * This is a special case of the 'default' case below.
michael@0 65 * Please see the comments there.
michael@0 66 */
michael@0 67 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
michael@0 68 tv.tv_usec = 0;
michael@0 69 FD_ZERO(&rd_wr);
michael@0 70 do {
michael@0 71 FD_SET(osfd, &rd_wr);
michael@0 72 if (fd_type == READ_FD)
michael@0 73 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
michael@0 74 else
michael@0 75 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
michael@0 76 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
michael@0 77 #ifdef BONE_VERSION
michael@0 78 _PR_MD_MAP_SELECT_ERROR(syserror);
michael@0 79 #else
michael@0 80 if (syserror == EBADF) {
michael@0 81 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
michael@0 82 } else {
michael@0 83 PR_SetError(PR_UNKNOWN_ERROR, syserror);
michael@0 84 }
michael@0 85 #endif
michael@0 86 break;
michael@0 87 }
michael@0 88 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 89 me->flags &= ~_PR_INTERRUPT;
michael@0 90 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 91 rv = -1;
michael@0 92 break;
michael@0 93 }
michael@0 94 } while (rv == 0 || (rv == -1 && syserror == EINTR));
michael@0 95 break;
michael@0 96 default:
michael@0 97 now = epoch = PR_IntervalNow();
michael@0 98 remaining = timeout;
michael@0 99 FD_ZERO(&rd_wr);
michael@0 100 do {
michael@0 101 /*
michael@0 102 * We block in _MD_SELECT for at most
michael@0 103 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
michael@0 104 * so that there is an upper limit on the delay
michael@0 105 * before the interrupt bit is checked.
michael@0 106 */
michael@0 107 wait_for_remaining = PR_TRUE;
michael@0 108 tv.tv_sec = PR_IntervalToSeconds(remaining);
michael@0 109 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
michael@0 110 wait_for_remaining = PR_FALSE;
michael@0 111 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
michael@0 112 tv.tv_usec = 0;
michael@0 113 } else {
michael@0 114 tv.tv_usec = PR_IntervalToMicroseconds(
michael@0 115 remaining -
michael@0 116 PR_SecondsToInterval(tv.tv_sec));
michael@0 117 }
michael@0 118 FD_SET(osfd, &rd_wr);
michael@0 119 if (fd_type == READ_FD)
michael@0 120 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
michael@0 121 else
michael@0 122 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
michael@0 123 /*
michael@0 124 * we don't consider EINTR a real error
michael@0 125 */
michael@0 126 if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
michael@0 127 #ifdef BONE_VERSION
michael@0 128 _PR_MD_MAP_SELECT_ERROR(syserror);
michael@0 129 #else
michael@0 130 if (syserror == EBADF) {
michael@0 131 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
michael@0 132 } else {
michael@0 133 PR_SetError(PR_UNKNOWN_ERROR, syserror);
michael@0 134 }
michael@0 135 #endif
michael@0 136 break;
michael@0 137 }
michael@0 138 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 139 me->flags &= ~_PR_INTERRUPT;
michael@0 140 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 141 rv = -1;
michael@0 142 break;
michael@0 143 }
michael@0 144 /*
michael@0 145 * We loop again if _MD_SELECT timed out or got interrupted
michael@0 146 * by a signal, and the timeout deadline has not passed yet.
michael@0 147 */
michael@0 148 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
michael@0 149 /*
michael@0 150 * If _MD_SELECT timed out, we know how much time
michael@0 151 * we spent in blocking, so we can avoid a
michael@0 152 * PR_IntervalNow() call.
michael@0 153 */
michael@0 154 if (rv == 0) {
michael@0 155 if (wait_for_remaining) {
michael@0 156 now += remaining;
michael@0 157 } else {
michael@0 158 now += PR_SecondsToInterval(tv.tv_sec)
michael@0 159 + PR_MicrosecondsToInterval(tv.tv_usec);
michael@0 160 }
michael@0 161 } else {
michael@0 162 now = PR_IntervalNow();
michael@0 163 }
michael@0 164 elapsed = (PRIntervalTime) (now - epoch);
michael@0 165 if (elapsed >= timeout) {
michael@0 166 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
michael@0 167 rv = -1;
michael@0 168 break;
michael@0 169 } else {
michael@0 170 remaining = timeout - elapsed;
michael@0 171 }
michael@0 172 }
michael@0 173 } while (rv == 0 || (rv == -1 && syserror == EINTR));
michael@0 174 break;
michael@0 175 }
michael@0 176 return(rv);
michael@0 177 }
michael@0 178
michael@0 179 PRInt32
michael@0 180 _MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags,
michael@0 181 PRIntervalTime timeout)
michael@0 182 {
michael@0 183 PRInt32 osfd = fd->secret->md.osfd;
michael@0 184 PRInt32 rv, err;
michael@0 185 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 186
michael@0 187 #ifndef BONE_VERSION
michael@0 188 if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) {
michael@0 189 _PR_MD_MAP_RECV_ERROR(EPIPE);
michael@0 190 return -1;
michael@0 191 }
michael@0 192 #endif
michael@0 193
michael@0 194 #ifdef BONE_VERSION
michael@0 195 /*
michael@0 196 ** Gah, stupid hack. If reading a zero amount, instantly return success.
michael@0 197 ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of
michael@0 198 ** mozilla use to check for socket availability.
michael@0 199 */
michael@0 200
michael@0 201 if( 0 == amount ) return(0);
michael@0 202 #endif
michael@0 203
michael@0 204 while ((rv = recv(osfd, buf, amount, flags)) == -1) {
michael@0 205 err = _MD_ERRNO();
michael@0 206
michael@0 207 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 208 if (fd->secret->nonblocking) {
michael@0 209 break;
michael@0 210 }
michael@0 211 /* If socket was supposed to be blocking,
michael@0 212 wait a while for the condition to be
michael@0 213 satisfied. */
michael@0 214 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 215 goto done;
michael@0 216 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 217 continue;
michael@0 218
michael@0 219 } else
michael@0 220 break;
michael@0 221 }
michael@0 222
michael@0 223 if (rv < 0) {
michael@0 224 _PR_MD_MAP_RECV_ERROR(err);
michael@0 225 }
michael@0 226
michael@0 227 done:
michael@0 228 return(rv);
michael@0 229 }
michael@0 230
michael@0 231 PRInt32
michael@0 232 _MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
michael@0 233 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
michael@0 234 {
michael@0 235 PRInt32 osfd = fd->secret->md.osfd;
michael@0 236 PRInt32 rv, err;
michael@0 237 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 238
michael@0 239 while ((*addrlen = PR_NETADDR_SIZE(addr)),
michael@0 240 ((rv = recvfrom(osfd, buf, amount, flags,
michael@0 241 (struct sockaddr *) addr,
michael@0 242 (_PRSockLen_t *)addrlen)) == -1)) {
michael@0 243 err = _MD_ERRNO();
michael@0 244
michael@0 245 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 246 if (fd->secret->nonblocking) {
michael@0 247 break;
michael@0 248 }
michael@0 249 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 250 goto done;
michael@0 251
michael@0 252 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
michael@0 253 continue;
michael@0 254 } else {
michael@0 255 break;
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 if (rv < 0) {
michael@0 260 _PR_MD_MAP_RECVFROM_ERROR(err);
michael@0 261 }
michael@0 262
michael@0 263 done:
michael@0 264 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 265 if (rv != -1) {
michael@0 266 /* ignore the sa_len field of struct sockaddr */
michael@0 267 if (addr) {
michael@0 268 addr->raw.family = ((struct sockaddr *) addr)->sa_family;
michael@0 269 }
michael@0 270 }
michael@0 271 #endif /* _PR_HAVE_SOCKADDR_LEN */
michael@0 272 return(rv);
michael@0 273 }
michael@0 274
michael@0 275 PRInt32
michael@0 276 _MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags,
michael@0 277 PRIntervalTime timeout)
michael@0 278 {
michael@0 279 PRInt32 osfd = fd->secret->md.osfd;
michael@0 280 PRInt32 rv, err;
michael@0 281 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 282
michael@0 283 #ifndef BONE_VERSION
michael@0 284 if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE)
michael@0 285 {
michael@0 286 _PR_MD_MAP_SEND_ERROR(EPIPE);
michael@0 287 return -1;
michael@0 288 }
michael@0 289 #endif
michael@0 290
michael@0 291 while ((rv = send(osfd, buf, amount, flags)) == -1) {
michael@0 292 err = _MD_ERRNO();
michael@0 293
michael@0 294 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 295 if (fd->secret->nonblocking) {
michael@0 296 break;
michael@0 297 }
michael@0 298
michael@0 299 #ifndef BONE_VERSION
michael@0 300 if( _PR_PENDING_INTERRUPT(me)) {
michael@0 301
michael@0 302 me->flags &= ~_PR_INTERRUPT;
michael@0 303 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 304 return -1;
michael@0 305 }
michael@0 306
michael@0 307 /* in UNIX implementations, you could do a socket_io_wait here.
michael@0 308 * but since BeOS doesn't yet support WRITE notification in select,
michael@0 309 * you're spanked.
michael@0 310 */
michael@0 311 snooze( 10000L );
michael@0 312 continue;
michael@0 313 #else /* BONE_VERSION */
michael@0 314 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
michael@0 315 goto done;
michael@0 316 #endif
michael@0 317
michael@0 318 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
michael@0 319 continue;
michael@0 320
michael@0 321 } else {
michael@0 322 break;
michael@0 323 }
michael@0 324 }
michael@0 325
michael@0 326 #ifdef BONE_VERSION
michael@0 327 /*
michael@0 328 * optimization; if bytes sent is less than "amount" call
michael@0 329 * select before returning. This is because it is likely that
michael@0 330 * the next writev() call will return EWOULDBLOCK.
michael@0 331 */
michael@0 332 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
michael@0 333 && (timeout != PR_INTERVAL_NO_WAIT)) {
michael@0 334 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
michael@0 335 rv = -1;
michael@0 336 goto done;
michael@0 337 }
michael@0 338 }
michael@0 339 #endif /* BONE_VERSION */
michael@0 340
michael@0 341 if (rv < 0) {
michael@0 342 _PR_MD_MAP_SEND_ERROR(err);
michael@0 343 }
michael@0 344
michael@0 345 #ifdef BONE_VERSION
michael@0 346 done:
michael@0 347 #endif
michael@0 348 return(rv);
michael@0 349 }
michael@0 350
michael@0 351 PRInt32
michael@0 352 _MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
michael@0 353 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
michael@0 354 {
michael@0 355 PRInt32 osfd = fd->secret->md.osfd;
michael@0 356 PRInt32 rv, err;
michael@0 357 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 358 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 359 PRNetAddr addrCopy;
michael@0 360
michael@0 361 addrCopy = *addr;
michael@0 362 ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
michael@0 363 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
michael@0 364
michael@0 365 while ((rv = sendto(osfd, buf, amount, flags,
michael@0 366 (struct sockaddr *) &addrCopy, addrlen)) == -1) {
michael@0 367 #else
michael@0 368 while ((rv = sendto(osfd, buf, amount, flags,
michael@0 369 (struct sockaddr *) addr, addrlen)) == -1) {
michael@0 370 #endif
michael@0 371 err = _MD_ERRNO();
michael@0 372
michael@0 373 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 374 if (fd->secret->nonblocking) {
michael@0 375 break;
michael@0 376 }
michael@0 377
michael@0 378 #ifdef BONE_VERSION
michael@0 379 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
michael@0 380 goto done;
michael@0 381 #endif
michael@0 382 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
michael@0 383 continue;
michael@0 384
michael@0 385 } else {
michael@0 386 break;
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 if (rv < 0) {
michael@0 391 _PR_MD_MAP_SENDTO_ERROR(err);
michael@0 392 }
michael@0 393
michael@0 394 #ifdef BONE_VERSION
michael@0 395 done:
michael@0 396 #endif
michael@0 397 return(rv);
michael@0 398 }
michael@0 399
michael@0 400 #ifdef BONE_VERSION
michael@0 401
michael@0 402 PRInt32 _MD_writev(
michael@0 403 PRFileDesc *fd, const PRIOVec *iov,
michael@0 404 PRInt32 iov_size, PRIntervalTime timeout)
michael@0 405 {
michael@0 406 PRInt32 rv, err;
michael@0 407 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 408 PRInt32 index, amount = 0;
michael@0 409 PRInt32 osfd = fd->secret->md.osfd;
michael@0 410 struct iovec osiov[PR_MAX_IOVECTOR_SIZE];
michael@0 411
michael@0 412 /* Ensured by PR_Writev */
michael@0 413 PR_ASSERT(iov_size <= PR_MAX_IOVECTOR_SIZE);
michael@0 414
michael@0 415 /*
michael@0 416 * We can't pass iov to writev because PRIOVec and struct iovec
michael@0 417 * may not be binary compatible. Make osiov a copy of iov and
michael@0 418 * pass osiov to writev.
michael@0 419 */
michael@0 420 for (index = 0; index < iov_size; index++) {
michael@0 421 osiov[index].iov_base = iov[index].iov_base;
michael@0 422 osiov[index].iov_len = iov[index].iov_len;
michael@0 423 }
michael@0 424
michael@0 425 /*
michael@0 426 * Calculate the total number of bytes to be sent; needed for
michael@0 427 * optimization later.
michael@0 428 * We could avoid this if this number was passed in; but it is
michael@0 429 * probably not a big deal because iov_size is usually small (less than
michael@0 430 * 3)
michael@0 431 */
michael@0 432 if (!fd->secret->nonblocking) {
michael@0 433 for (index=0; index<iov_size; index++) {
michael@0 434 amount += iov[index].iov_len;
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 while ((rv = writev(osfd, osiov, iov_size)) == -1) {
michael@0 439 err = _MD_ERRNO();
michael@0 440 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 441 if (fd->secret->nonblocking) {
michael@0 442 break;
michael@0 443 }
michael@0 444 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
michael@0 445 goto done;
michael@0 446
michael@0 447 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 448 continue;
michael@0 449 } else {
michael@0 450 break;
michael@0 451 }
michael@0 452 }
michael@0 453
michael@0 454 /*
michael@0 455 * optimization; if bytes sent is less than "amount" call
michael@0 456 * select before returning. This is because it is likely that
michael@0 457 * the next writev() call will return EWOULDBLOCK.
michael@0 458 */
michael@0 459 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
michael@0 460 && (timeout != PR_INTERVAL_NO_WAIT)) {
michael@0 461 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
michael@0 462 rv = -1;
michael@0 463 goto done;
michael@0 464 }
michael@0 465 }
michael@0 466
michael@0 467
michael@0 468 if (rv < 0) {
michael@0 469 _PR_MD_MAP_WRITEV_ERROR(err);
michael@0 470 }
michael@0 471 done:
michael@0 472 return(rv);
michael@0 473 }
michael@0 474
michael@0 475 #endif /* BONE_VERSION */
michael@0 476
michael@0 477 PRInt32
michael@0 478 _MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
michael@0 479 PRIntervalTime timeout)
michael@0 480 {
michael@0 481 PRInt32 osfd = fd->secret->md.osfd;
michael@0 482 PRInt32 rv, err;
michael@0 483 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 484
michael@0 485 while ((rv = accept(osfd, (struct sockaddr *) addr,
michael@0 486 (_PRSockLen_t *)addrlen)) == -1) {
michael@0 487 err = _MD_ERRNO();
michael@0 488
michael@0 489 if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
michael@0 490 if (fd->secret->nonblocking) {
michael@0 491 break;
michael@0 492 }
michael@0 493 /* If it's SUPPOSED to be a blocking thread, wait
michael@0 494 * a while to see if the triggering condition gets
michael@0 495 * satisfied.
michael@0 496 */
michael@0 497 /* Assume that we're always using a native thread */
michael@0 498 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 499 goto done;
michael@0 500 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
michael@0 501 continue;
michael@0 502 } else {
michael@0 503 break;
michael@0 504 }
michael@0 505 }
michael@0 506 if (rv < 0) {
michael@0 507 _PR_MD_MAP_ACCEPT_ERROR(err);
michael@0 508 } else if (addr != NULL) {
michael@0 509 /* bug 134099 */
michael@0 510 err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
michael@0 511 }
michael@0 512 done:
michael@0 513 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 514 if (rv != -1) {
michael@0 515 /* Mask off the first byte of struct sockaddr (the length field) */
michael@0 516 if (addr) {
michael@0 517 addr->raw.family = ((struct sockaddr *) addr)->sa_family;
michael@0 518 }
michael@0 519 }
michael@0 520 #endif /* _PR_HAVE_SOCKADDR_LEN */
michael@0 521 return(rv);
michael@0 522 }
michael@0 523
michael@0 524 PRInt32
michael@0 525 _MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
michael@0 526 PRIntervalTime timeout)
michael@0 527 {
michael@0 528 PRInt32 rv, err;
michael@0 529 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 530 PRInt32 osfd = fd->secret->md.osfd;
michael@0 531
michael@0 532 #ifndef BONE_VERSION
michael@0 533 fd->secret->md.connectValueValid = PR_FALSE;
michael@0 534 #endif
michael@0 535 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 536 PRNetAddr addrCopy;
michael@0 537
michael@0 538 addrCopy = *addr;
michael@0 539 ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
michael@0 540 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
michael@0 541 #endif
michael@0 542
michael@0 543 /* (Copied from unix.c)
michael@0 544 * We initiate the connection setup by making a nonblocking connect()
michael@0 545 * call. If the connect() call fails, there are two cases we handle
michael@0 546 * specially:
michael@0 547 * 1. The connect() call was interrupted by a signal. In this case
michael@0 548 * we simply retry connect().
michael@0 549 * 2. The NSPR socket is nonblocking and connect() fails with
michael@0 550 * EINPROGRESS. We first wait until the socket becomes writable.
michael@0 551 * Then we try to find out whether the connection setup succeeded
michael@0 552 * or failed.
michael@0 553 */
michael@0 554
michael@0 555 retry:
michael@0 556 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 557 if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) {
michael@0 558 #else
michael@0 559 if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
michael@0 560 #endif
michael@0 561 err = _MD_ERRNO();
michael@0 562 #ifndef BONE_VERSION
michael@0 563 fd->secret->md.connectReturnValue = rv;
michael@0 564 fd->secret->md.connectReturnError = err;
michael@0 565 fd->secret->md.connectValueValid = PR_TRUE;
michael@0 566 #endif
michael@0 567 if( err == EINTR ) {
michael@0 568
michael@0 569 if( _PR_PENDING_INTERRUPT(me)) {
michael@0 570
michael@0 571 me->flags &= ~_PR_INTERRUPT;
michael@0 572 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 573 return -1;
michael@0 574 }
michael@0 575 #ifndef BONE_VERSION
michael@0 576 snooze( 100000L );
michael@0 577 #endif
michael@0 578 goto retry;
michael@0 579 }
michael@0 580
michael@0 581 #ifndef BONE_VERSION
michael@0 582 if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) {
michael@0 583
michael@0 584 /*
michael@0 585 ** There's no timeout on this connect, but that's not
michael@0 586 ** a big deal, since the connect times out anyways
michael@0 587 ** after 30 seconds. Just sleep for 1/10th of a second
michael@0 588 ** and retry until we go through or die.
michael@0 589 */
michael@0 590
michael@0 591 if( _PR_PENDING_INTERRUPT(me)) {
michael@0 592 me->flags &= ~_PR_INTERRUPT;
michael@0 593 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 594 return -1;
michael@0 595 }
michael@0 596
michael@0 597 goto retry;
michael@0 598 }
michael@0 599
michael@0 600 if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) {
michael@0 601 PR_Lock(_connectLock);
michael@0 602 if (connectCount < sizeof(connectList)/sizeof(connectList[0])) {
michael@0 603 connectList[connectCount].osfd = osfd;
michael@0 604 memcpy(&connectList[connectCount].addr, addr, addrlen);
michael@0 605 connectList[connectCount].addrlen = addrlen;
michael@0 606 connectList[connectCount].timeout = timeout;
michael@0 607 connectCount++;
michael@0 608 PR_Unlock(_connectLock);
michael@0 609 _PR_MD_MAP_CONNECT_ERROR(err);
michael@0 610 } else {
michael@0 611 PR_Unlock(_connectLock);
michael@0 612 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
michael@0 613 }
michael@0 614 return rv;
michael@0 615 }
michael@0 616 #else /* BONE_VERSION */
michael@0 617 if(!fd->secret->nonblocking && (err == EINTR)) {
michael@0 618
michael@0 619 rv = socket_io_wait(osfd, WRITE_FD, timeout);
michael@0 620 if (rv == -1) {
michael@0 621 return -1;
michael@0 622 }
michael@0 623
michael@0 624 PR_ASSERT(rv == 1);
michael@0 625 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 626 me->flags &= ~_PR_INTERRUPT;
michael@0 627 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 628 return -1;
michael@0 629 }
michael@0 630 err = _MD_beos_get_nonblocking_connect_error(osfd);
michael@0 631 if (err != 0) {
michael@0 632 _PR_MD_MAP_CONNECT_ERROR(err);
michael@0 633 return -1;
michael@0 634 }
michael@0 635 return 0;
michael@0 636 }
michael@0 637 #endif
michael@0 638
michael@0 639 _PR_MD_MAP_CONNECT_ERROR(err);
michael@0 640 }
michael@0 641
michael@0 642 return rv;
michael@0 643 }
michael@0 644
michael@0 645 PRInt32
michael@0 646 _MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
michael@0 647 {
michael@0 648 PRInt32 rv, err;
michael@0 649 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 650 PRNetAddr addrCopy;
michael@0 651
michael@0 652 addrCopy = *addr;
michael@0 653 ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
michael@0 654 ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
michael@0 655 rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen);
michael@0 656 #else
michael@0 657 rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
michael@0 658 #endif
michael@0 659 if (rv < 0) {
michael@0 660 err = _MD_ERRNO();
michael@0 661 _PR_MD_MAP_BIND_ERROR(err);
michael@0 662 }
michael@0 663
michael@0 664 return(rv);
michael@0 665 }
michael@0 666
michael@0 667 PRInt32
michael@0 668 _MD_listen (PRFileDesc *fd, PRIntn backlog)
michael@0 669 {
michael@0 670 PRInt32 rv, err;
michael@0 671
michael@0 672 #ifndef BONE_VERSION
michael@0 673 /* Bug workaround! Setting listen to 0 on Be accepts no connections.
michael@0 674 ** On most UN*Xes this sets the default.
michael@0 675 */
michael@0 676
michael@0 677 if( backlog == 0 ) backlog = 5;
michael@0 678 #endif
michael@0 679
michael@0 680 rv = listen(fd->secret->md.osfd, backlog);
michael@0 681 if (rv < 0) {
michael@0 682 err = _MD_ERRNO();
michael@0 683 _PR_MD_MAP_LISTEN_ERROR(err);
michael@0 684 }
michael@0 685
michael@0 686 return(rv);
michael@0 687 }
michael@0 688
michael@0 689 PRInt32
michael@0 690 _MD_shutdown (PRFileDesc *fd, PRIntn how)
michael@0 691 {
michael@0 692 PRInt32 rv, err;
michael@0 693
michael@0 694 #ifndef BONE_VERSION
michael@0 695 if (how == PR_SHUTDOWN_SEND)
michael@0 696 fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE;
michael@0 697 else if (how == PR_SHUTDOWN_RCV)
michael@0 698 fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ;
michael@0 699 else if (how == PR_SHUTDOWN_BOTH) {
michael@0 700 fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ);
michael@0 701 }
michael@0 702
michael@0 703 return 0;
michael@0 704 #else /* BONE_VERSION */
michael@0 705 rv = shutdown(fd->secret->md.osfd, how);
michael@0 706 if (rv < 0) {
michael@0 707 err = _MD_ERRNO();
michael@0 708 _PR_MD_MAP_SHUTDOWN_ERROR(err);
michael@0 709 }
michael@0 710 return(rv);
michael@0 711 #endif
michael@0 712 }
michael@0 713
michael@0 714 PRInt32
michael@0 715 _MD_socketpair (int af, int type, int flags, PRInt32 *osfd)
michael@0 716 {
michael@0 717 return PR_NOT_IMPLEMENTED_ERROR;
michael@0 718 }
michael@0 719
michael@0 720 PRInt32
michael@0 721 _MD_close_socket (PRInt32 osfd)
michael@0 722 {
michael@0 723 #ifdef BONE_VERSION
michael@0 724 close( osfd );
michael@0 725 #else
michael@0 726 closesocket( osfd );
michael@0 727 #endif
michael@0 728 }
michael@0 729
michael@0 730 PRStatus
michael@0 731 _MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
michael@0 732 {
michael@0 733 PRInt32 rv, err;
michael@0 734
michael@0 735 rv = getsockname(fd->secret->md.osfd,
michael@0 736 (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
michael@0 737 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 738 if (rv == 0) {
michael@0 739 /* ignore the sa_len field of struct sockaddr */
michael@0 740 if (addr) {
michael@0 741 addr->raw.family = ((struct sockaddr *) addr)->sa_family;
michael@0 742 }
michael@0 743 }
michael@0 744 #endif /* _PR_HAVE_SOCKADDR_LEN */
michael@0 745 if (rv < 0) {
michael@0 746 err = _MD_ERRNO();
michael@0 747 _PR_MD_MAP_GETSOCKNAME_ERROR(err);
michael@0 748 }
michael@0 749
michael@0 750 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 751 }
michael@0 752
michael@0 753 PRStatus
michael@0 754 _MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
michael@0 755 {
michael@0 756 PRInt32 rv, err;
michael@0 757
michael@0 758 rv = getpeername(fd->secret->md.osfd,
michael@0 759 (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
michael@0 760
michael@0 761 #ifdef _PR_HAVE_SOCKADDR_LEN
michael@0 762 if (rv == 0) {
michael@0 763 /* ignore the sa_len field of struct sockaddr */
michael@0 764 if (addr) {
michael@0 765 addr->raw.family = ((struct sockaddr *) addr)->sa_family;
michael@0 766 }
michael@0 767 }
michael@0 768 #endif /* _PR_HAVE_SOCKADDR_LEN */
michael@0 769
michael@0 770 if (rv < 0) {
michael@0 771 err = _MD_ERRNO();
michael@0 772 _PR_MD_MAP_GETPEERNAME_ERROR(err);
michael@0 773 }
michael@0 774 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 775 }
michael@0 776
michael@0 777 PRStatus
michael@0 778 _MD_getsockopt (PRFileDesc *fd, PRInt32 level,
michael@0 779 PRInt32 optname, char* optval, PRInt32* optlen)
michael@0 780 {
michael@0 781 PRInt32 rv, err;
michael@0 782
michael@0 783 rv = getsockopt(fd->secret->md.osfd, level, optname,
michael@0 784 optval, (_PRSockLen_t *)optlen);
michael@0 785 if (rv < 0) {
michael@0 786 err = _MD_ERRNO();
michael@0 787 _PR_MD_MAP_GETSOCKOPT_ERROR(err);
michael@0 788 }
michael@0 789
michael@0 790 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 791 }
michael@0 792
michael@0 793 PRStatus
michael@0 794 _MD_setsockopt (PRFileDesc *fd, PRInt32 level,
michael@0 795 PRInt32 optname, const char* optval, PRInt32 optlen)
michael@0 796 {
michael@0 797 PRInt32 rv, err;
michael@0 798
michael@0 799 rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
michael@0 800 if (rv < 0) {
michael@0 801 err = _MD_ERRNO();
michael@0 802 _PR_MD_MAP_SETSOCKOPT_ERROR(err);
michael@0 803 }
michael@0 804 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 805 }
michael@0 806
michael@0 807 PRInt32
michael@0 808 _MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
michael@0 809 void *buf, PRInt32 amount, PRIntervalTime timeout)
michael@0 810 {
michael@0 811 return PR_NOT_IMPLEMENTED_ERROR;
michael@0 812 }
michael@0 813
michael@0 814 #ifndef BONE_VERSION
michael@0 815 PRInt32
michael@0 816 _MD_socket (int af, int type, int flags)
michael@0 817 {
michael@0 818 PRInt32 osfd, err;
michael@0 819
michael@0 820 osfd = socket( af, type, 0 );
michael@0 821
michael@0 822 if( -1 == osfd ) {
michael@0 823
michael@0 824 err = _MD_ERRNO();
michael@0 825 _PR_MD_MAP_SOCKET_ERROR( err );
michael@0 826 }
michael@0 827
michael@0 828 return( osfd );
michael@0 829 }
michael@0 830 #else
michael@0 831 PRInt32
michael@0 832 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
michael@0 833 {
michael@0 834 PRInt32 osfd, err;
michael@0 835
michael@0 836 osfd = socket(domain, type, proto);
michael@0 837
michael@0 838 if (osfd == -1) {
michael@0 839 err = _MD_ERRNO();
michael@0 840 _PR_MD_MAP_SOCKET_ERROR(err);
michael@0 841 }
michael@0 842
michael@0 843 return(osfd);
michael@0 844 }
michael@0 845 #endif
michael@0 846
michael@0 847 PRInt32
michael@0 848 _MD_socketavailable (PRFileDesc *fd)
michael@0 849 {
michael@0 850 #ifdef BONE_VERSION
michael@0 851 PRInt32 result;
michael@0 852
michael@0 853 if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
michael@0 854 _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
michael@0 855 return -1;
michael@0 856 }
michael@0 857 return result;
michael@0 858 #else
michael@0 859 return PR_NOT_IMPLEMENTED_ERROR;
michael@0 860 #endif
michael@0 861 }
michael@0 862
michael@0 863 PRInt32
michael@0 864 _MD_get_socket_error (void)
michael@0 865 {
michael@0 866 return PR_NOT_IMPLEMENTED_ERROR;
michael@0 867 }
michael@0 868
michael@0 869 PRStatus
michael@0 870 _MD_gethostname (char *name, PRUint32 namelen)
michael@0 871 {
michael@0 872 PRInt32 rv, err;
michael@0 873
michael@0 874 rv = gethostname(name, namelen);
michael@0 875 if (rv == 0)
michael@0 876 {
michael@0 877 err = _MD_ERRNO();
michael@0 878 _PR_MD_MAP_GETHOSTNAME_ERROR(err);
michael@0 879 return PR_FAILURE;
michael@0 880 }
michael@0 881 return PR_SUCCESS;
michael@0 882 }
michael@0 883
michael@0 884 #ifndef BONE_VERSION
michael@0 885 PRInt32
michael@0 886 _MD_beos_get_nonblocking_connect_error(PRFileDesc *fd)
michael@0 887 {
michael@0 888 int rv;
michael@0 889 int flags = 0;
michael@0 890
michael@0 891 rv = recv(fd->secret->md.osfd, NULL, 0, flags);
michael@0 892 PR_ASSERT(-1 == rv || 0 == rv);
michael@0 893 if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
michael@0 894 return errno;
michael@0 895 }
michael@0 896 return 0; /* no error */
michael@0 897 }
michael@0 898 #else
michael@0 899 PRInt32
michael@0 900 _MD_beos_get_nonblocking_connect_error(int osfd)
michael@0 901 {
michael@0 902 return PR_NOT_IMPLEMENTED_ERROR;
michael@0 903 // int err;
michael@0 904 // _PRSockLen_t optlen = sizeof(err);
michael@0 905 // if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) {
michael@0 906 // return errno;
michael@0 907 // } else {
michael@0 908 // return err;
michael@0 909 // }
michael@0 910 }
michael@0 911 #endif /* BONE_VERSION */

mercurial