nsprpub/pr/src/md/os2/os2sock.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++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* OS/2 Sockets module
michael@0 8 *
michael@0 9 */
michael@0 10
michael@0 11 /*Note from DSR111297 - it should be noted that there are two flavors of select() on OS/2 */
michael@0 12 /*There is standard BSD (which is kind of slow) and a new flavor of select() that takes */
michael@0 13 /*an integer list of sockets, the number of read sockets, write sockets, except sockets, and */
michael@0 14 /*a millisecond count for timeout. In the interest of performance I have choosen the OS/2 */
michael@0 15 /*specific version of select(). See OS/2 TCP/IP Programmer's Toolkit for more info. */
michael@0 16
michael@0 17 #include "primpl.h"
michael@0 18
michael@0 19 #include <sys/time.h> /* For timeval. */
michael@0 20
michael@0 21 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
michael@0 22 #define READ_FD 1
michael@0 23 #define WRITE_FD 2
michael@0 24
michael@0 25 /* --- SOCKET IO --------------------------------------------------------- */
michael@0 26
michael@0 27
michael@0 28 PRInt32
michael@0 29 _PR_MD_SOCKET(int domain, int type, int flags)
michael@0 30 {
michael@0 31 PRInt32 osfd, err;
michael@0 32
michael@0 33 osfd = socket(domain, type, flags);
michael@0 34
michael@0 35 if (osfd == -1)
michael@0 36 {
michael@0 37 err = sock_errno();
michael@0 38 _PR_MD_MAP_SOCKET_ERROR(err);
michael@0 39 }
michael@0 40
michael@0 41 return(osfd);
michael@0 42 }
michael@0 43
michael@0 44 /*
michael@0 45 ** _MD_CloseSocket() -- Close a socket
michael@0 46 **
michael@0 47 */
michael@0 48 PRInt32
michael@0 49 _MD_CloseSocket(PRInt32 osfd)
michael@0 50 {
michael@0 51 PRInt32 rv, err;
michael@0 52
michael@0 53 rv = soclose(osfd);
michael@0 54 if (rv == -1) {
michael@0 55 err = sock_errno();
michael@0 56 _PR_MD_MAP_CLOSE_ERROR(err);
michael@0 57 }
michael@0 58 return rv;
michael@0 59 }
michael@0 60
michael@0 61 PRInt32
michael@0 62 _MD_SocketAvailable(PRFileDesc *fd)
michael@0 63 {
michael@0 64 PRInt32 result;
michael@0 65
michael@0 66 if (so_ioctl(fd->secret->md.osfd, FIONREAD, (char *) &result, sizeof(result)) < 0) {
michael@0 67 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, sock_errno());
michael@0 68 return -1;
michael@0 69 }
michael@0 70 return result;
michael@0 71 }
michael@0 72
michael@0 73 static PRInt32
michael@0 74 socket_io_wait( PRInt32 osfd, PRInt32 fd_type, PRIntervalTime timeout )
michael@0 75 {
michael@0 76 PRInt32 rv = -1;
michael@0 77 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 78 PRIntervalTime epoch, now, elapsed, remaining;
michael@0 79 PRBool wait_for_remaining;
michael@0 80 PRInt32 syserror;
michael@0 81 #ifdef BSD_SELECT
michael@0 82 struct timeval tv;
michael@0 83 fd_set rd_wr;
michael@0 84 #else
michael@0 85 int socks[1];
michael@0 86 long lTimeout;
michael@0 87 #endif
michael@0 88
michael@0 89 switch (timeout) {
michael@0 90 case PR_INTERVAL_NO_WAIT:
michael@0 91 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
michael@0 92 break;
michael@0 93 case PR_INTERVAL_NO_TIMEOUT:
michael@0 94 /*
michael@0 95 * This is a special case of the 'default' case below.
michael@0 96 * Please see the comments there.
michael@0 97 */
michael@0 98 #ifdef BSD_SELECT
michael@0 99 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
michael@0 100 tv.tv_usec = 0;
michael@0 101 FD_ZERO(&rd_wr);
michael@0 102 do {
michael@0 103 FD_SET(osfd, &rd_wr);
michael@0 104 if (fd_type == READ_FD)
michael@0 105 rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv);
michael@0 106 else
michael@0 107 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
michael@0 108 #else
michael@0 109 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
michael@0 110 do {
michael@0 111 socks[0] = osfd;
michael@0 112 if (fd_type == READ_FD)
michael@0 113 rv = os2_select(socks, 1, 0, 0, lTimeout);
michael@0 114 else
michael@0 115 rv = os2_select(socks, 0, 1, 0, lTimeout);
michael@0 116 #endif
michael@0 117 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
michael@0 118 _PR_MD_MAP_SELECT_ERROR(syserror);
michael@0 119 break;
michael@0 120 }
michael@0 121 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 122 me->flags &= ~_PR_INTERRUPT;
michael@0 123 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 124 rv = -1;
michael@0 125 break;
michael@0 126 }
michael@0 127 } while (rv == 0 || (rv == -1 && syserror == EINTR));
michael@0 128 break;
michael@0 129 default:
michael@0 130 now = epoch = PR_IntervalNow();
michael@0 131 remaining = timeout;
michael@0 132 #ifdef BSD_SELECT
michael@0 133 FD_ZERO(&rd_wr);
michael@0 134 #endif
michael@0 135 do {
michael@0 136 /*
michael@0 137 * We block in select for at most
michael@0 138 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
michael@0 139 * so that there is an upper limit on the delay
michael@0 140 * before the interrupt bit is checked.
michael@0 141 */
michael@0 142 #ifdef BSD_SELECT
michael@0 143 wait_for_remaining = PR_TRUE;
michael@0 144 tv.tv_sec = PR_IntervalToSeconds(remaining);
michael@0 145 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
michael@0 146 wait_for_remaining = PR_FALSE;
michael@0 147 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
michael@0 148 tv.tv_usec = 0;
michael@0 149 } else {
michael@0 150 tv.tv_usec = PR_IntervalToMicroseconds(
michael@0 151 remaining -
michael@0 152 PR_SecondsToInterval(tv.tv_sec));
michael@0 153 }
michael@0 154 FD_SET(osfd, &rd_wr);
michael@0 155 if (fd_type == READ_FD)
michael@0 156 rv = bsdselect(osfd + 1, &rd_wr, NULL, NULL, &tv);
michael@0 157 else
michael@0 158 rv = bsdselect(osfd + 1, NULL, &rd_wr, NULL, &tv);
michael@0 159 #else
michael@0 160 wait_for_remaining = PR_TRUE;
michael@0 161 lTimeout = PR_IntervalToMilliseconds(remaining);
michael@0 162 if (lTimeout > _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000) {
michael@0 163 wait_for_remaining = PR_FALSE;
michael@0 164 lTimeout = _PR_INTERRUPT_CHECK_INTERVAL_SECS * 1000;
michael@0 165 }
michael@0 166 socks[0] = osfd;
michael@0 167 if (fd_type == READ_FD)
michael@0 168 rv = os2_select(socks, 1, 0, 0, lTimeout);
michael@0 169 else
michael@0 170 rv = os2_select(socks, 0, 1, 0, lTimeout);
michael@0 171 #endif
michael@0 172 /*
michael@0 173 * we don't consider EINTR a real error
michael@0 174 */
michael@0 175 if (rv == -1 && (syserror = sock_errno()) != EINTR) {
michael@0 176 _PR_MD_MAP_SELECT_ERROR(syserror);
michael@0 177 break;
michael@0 178 }
michael@0 179 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 180 me->flags &= ~_PR_INTERRUPT;
michael@0 181 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 182 rv = -1;
michael@0 183 break;
michael@0 184 }
michael@0 185 /*
michael@0 186 * We loop again if select timed out or got interrupted
michael@0 187 * by a signal, and the timeout deadline has not passed yet.
michael@0 188 */
michael@0 189 if (rv == 0 || (rv == -1 && syserror == EINTR)) {
michael@0 190 /*
michael@0 191 * If select timed out, we know how much time
michael@0 192 * we spent in blocking, so we can avoid a
michael@0 193 * PR_IntervalNow() call.
michael@0 194 */
michael@0 195 if (rv == 0) {
michael@0 196 if (wait_for_remaining) {
michael@0 197 now += remaining;
michael@0 198 } else {
michael@0 199 #ifdef BSD_SELECT
michael@0 200 now += PR_SecondsToInterval(tv.tv_sec)
michael@0 201 + PR_MicrosecondsToInterval(tv.tv_usec);
michael@0 202 #else
michael@0 203 now += PR_MillisecondsToInterval(lTimeout);
michael@0 204 #endif
michael@0 205 }
michael@0 206 } else {
michael@0 207 now = PR_IntervalNow();
michael@0 208 }
michael@0 209 elapsed = (PRIntervalTime) (now - epoch);
michael@0 210 if (elapsed >= timeout) {
michael@0 211 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
michael@0 212 rv = -1;
michael@0 213 break;
michael@0 214 } else {
michael@0 215 remaining = timeout - elapsed;
michael@0 216 }
michael@0 217 }
michael@0 218 } while (rv == 0 || (rv == -1 && syserror == EINTR));
michael@0 219 break;
michael@0 220 }
michael@0 221 return(rv);
michael@0 222 }
michael@0 223
michael@0 224 PRInt32
michael@0 225 _MD_Accept(PRFileDesc *fd, PRNetAddr *addr,
michael@0 226 PRUint32 *addrlen, PRIntervalTime timeout)
michael@0 227 {
michael@0 228 PRInt32 osfd = fd->secret->md.osfd;
michael@0 229 PRInt32 rv, err;
michael@0 230 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 231
michael@0 232 while ((rv = accept(osfd, (struct sockaddr*) addr, (int*)addrlen)) == -1)
michael@0 233 {
michael@0 234 err = sock_errno();
michael@0 235 if ((err == EWOULDBLOCK) || (err == ECONNABORTED))
michael@0 236 {
michael@0 237 if (fd->secret->nonblocking) {
michael@0 238 break;
michael@0 239 }
michael@0 240 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 241 goto done;
michael@0 242 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 243 continue;
michael@0 244 } else {
michael@0 245 break;
michael@0 246 }
michael@0 247 }
michael@0 248 if (rv < 0) {
michael@0 249 _PR_MD_MAP_ACCEPT_ERROR(err);
michael@0 250 }
michael@0 251 done:
michael@0 252 return(rv);
michael@0 253 }
michael@0 254
michael@0 255 PRInt32
michael@0 256 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
michael@0 257 PRIntervalTime timeout)
michael@0 258 {
michael@0 259 PRInt32 rv, err;
michael@0 260 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 261 PRInt32 osfd = fd->secret->md.osfd;
michael@0 262 PRNetAddr addrCopy = *addr; /* Work around a bug in OS/2 where connect
michael@0 263 * modifies the sockaddr structure.
michael@0 264 * See Bugzilla bug 100776. */
michael@0 265
michael@0 266 /*
michael@0 267 * We initiate the connection setup by making a nonblocking connect()
michael@0 268 * call. If the connect() call fails, there are two cases we handle
michael@0 269 * specially:
michael@0 270 * 1. The connect() call was interrupted by a signal. In this case
michael@0 271 * we simply retry connect().
michael@0 272 * 2. The NSPR socket is nonblocking and connect() fails with
michael@0 273 * EINPROGRESS. We first wait until the socket becomes writable.
michael@0 274 * Then we try to find out whether the connection setup succeeded
michael@0 275 * or failed.
michael@0 276 */
michael@0 277
michael@0 278 retry:
michael@0 279 if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1)
michael@0 280 {
michael@0 281 err = sock_errno();
michael@0 282
michael@0 283 if (err == EINTR) {
michael@0 284 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 285 me->flags &= ~_PR_INTERRUPT;
michael@0 286 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 287 return -1;
michael@0 288 }
michael@0 289 goto retry;
michael@0 290 }
michael@0 291
michael@0 292 if (!fd->secret->nonblocking && (err == EINPROGRESS))
michael@0 293 {
michael@0 294 /*
michael@0 295 * socket_io_wait() may return -1 or 1.
michael@0 296 */
michael@0 297
michael@0 298 rv = socket_io_wait(osfd, WRITE_FD, timeout);
michael@0 299 if (rv == -1) {
michael@0 300 return -1;
michael@0 301 }
michael@0 302
michael@0 303 PR_ASSERT(rv == 1);
michael@0 304 if (_PR_PENDING_INTERRUPT(me)) {
michael@0 305 me->flags &= ~_PR_INTERRUPT;
michael@0 306 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 307 return -1;
michael@0 308 }
michael@0 309 err = _MD_os2_get_nonblocking_connect_error(osfd);
michael@0 310 if (err != 0) {
michael@0 311 _PR_MD_MAP_CONNECT_ERROR(err);
michael@0 312 return -1;
michael@0 313 }
michael@0 314 return 0;
michael@0 315 }
michael@0 316
michael@0 317 _PR_MD_MAP_CONNECT_ERROR(err);
michael@0 318 }
michael@0 319
michael@0 320 return rv;
michael@0 321 } /* _MD_connect */
michael@0 322
michael@0 323 PRInt32
michael@0 324 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
michael@0 325 {
michael@0 326 PRInt32 rv, err;
michael@0 327 rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
michael@0 328 if (rv < 0) {
michael@0 329 err = sock_errno();
michael@0 330 _PR_MD_MAP_BIND_ERROR(err);
michael@0 331 }
michael@0 332 return(rv);
michael@0 333 }
michael@0 334
michael@0 335
michael@0 336 PRInt32
michael@0 337 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
michael@0 338 {
michael@0 339 PRInt32 rv, err;
michael@0 340 rv = listen(fd->secret->md.osfd, backlog);
michael@0 341 if (rv < 0) {
michael@0 342 err = sock_errno();
michael@0 343 _PR_MD_MAP_DEFAULT_ERROR(err);
michael@0 344 }
michael@0 345 return(rv);
michael@0 346 }
michael@0 347
michael@0 348
michael@0 349 PRInt32
michael@0 350 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
michael@0 351 PRIntervalTime timeout)
michael@0 352 {
michael@0 353 PRInt32 osfd = fd->secret->md.osfd;
michael@0 354 PRInt32 rv, err;
michael@0 355 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 356
michael@0 357 while ((rv = recv(osfd,buf,amount,flags)) == -1)
michael@0 358 {
michael@0 359 err = sock_errno();
michael@0 360 if ((err == EWOULDBLOCK)) {
michael@0 361 if (fd->secret->nonblocking) {
michael@0 362 break;
michael@0 363 }
michael@0 364 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 365 goto done;
michael@0 366 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 367 continue;
michael@0 368 } else {
michael@0 369 break;
michael@0 370 }
michael@0 371 }
michael@0 372 if (rv < 0) {
michael@0 373 _PR_MD_MAP_RECV_ERROR(err);
michael@0 374 }
michael@0 375 done:
michael@0 376 return(rv);
michael@0 377 }
michael@0 378
michael@0 379 PRInt32
michael@0 380 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
michael@0 381 PRIntervalTime timeout)
michael@0 382 {
michael@0 383 PRInt32 osfd = fd->secret->md.osfd;
michael@0 384 PRInt32 rv, err;
michael@0 385 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 386
michael@0 387 while ((rv = send(osfd,buf,amount,flags)) == -1)
michael@0 388 {
michael@0 389 err = sock_errno();
michael@0 390 if ((err == EWOULDBLOCK)) {
michael@0 391 if (fd->secret->nonblocking) {
michael@0 392 break;
michael@0 393 }
michael@0 394 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
michael@0 395 goto done;
michael@0 396 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 397 continue;
michael@0 398 } else {
michael@0 399 break;
michael@0 400 }
michael@0 401 }
michael@0 402
michael@0 403 /*
michael@0 404 * optimization; if bytes sent is less than "amount" call
michael@0 405 * select before returning. This is because it is likely that
michael@0 406 * the next send() call will return EWOULDBLOCK.
michael@0 407 */
michael@0 408 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
michael@0 409 && (timeout != PR_INTERVAL_NO_WAIT))
michael@0 410 {
michael@0 411 if (socket_io_wait(osfd, WRITE_FD, timeout)< 0) {
michael@0 412 rv = -1;
michael@0 413 goto done;
michael@0 414 }
michael@0 415 }
michael@0 416 if (rv < 0) {
michael@0 417 _PR_MD_MAP_SEND_ERROR(err);
michael@0 418 }
michael@0 419 done:
michael@0 420 return(rv);
michael@0 421 }
michael@0 422
michael@0 423 PRInt32
michael@0 424 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
michael@0 425 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
michael@0 426 {
michael@0 427 PRInt32 osfd = fd->secret->md.osfd;
michael@0 428 PRInt32 rv, err;
michael@0 429 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 430 while ((rv = sendto(osfd, buf, amount, flags,
michael@0 431 (struct sockaddr *) addr, addrlen)) == -1)
michael@0 432 {
michael@0 433 err = sock_errno();
michael@0 434 if ((err == EWOULDBLOCK))
michael@0 435 {
michael@0 436 if (fd->secret->nonblocking) {
michael@0 437 break;
michael@0 438 }
michael@0 439 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout)) < 0)
michael@0 440 goto done;
michael@0 441 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 442 continue;
michael@0 443 } else {
michael@0 444 break;
michael@0 445 }
michael@0 446 }
michael@0 447 if (rv < 0) {
michael@0 448 _PR_MD_MAP_SENDTO_ERROR(err);
michael@0 449 }
michael@0 450 done:
michael@0 451 return(rv);
michael@0 452 }
michael@0 453
michael@0 454 PRInt32
michael@0 455 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
michael@0 456 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
michael@0 457 {
michael@0 458 PRInt32 osfd = fd->secret->md.osfd;
michael@0 459 PRInt32 rv, err;
michael@0 460 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 461
michael@0 462 while( (*addrlen = PR_NETADDR_SIZE(addr)),
michael@0 463 ((rv = recvfrom(osfd, buf, amount, flags,
michael@0 464 (struct sockaddr *) addr, (int *)addrlen)) == -1))
michael@0 465 {
michael@0 466 err = sock_errno();
michael@0 467 if ((err == EWOULDBLOCK)) {
michael@0 468 if (fd->secret->nonblocking) {
michael@0 469 break;
michael@0 470 }
michael@0 471 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
michael@0 472 goto done;
michael@0 473 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 474 continue;
michael@0 475 } else {
michael@0 476 break;
michael@0 477 }
michael@0 478 }
michael@0 479 if (rv < 0) {
michael@0 480 _PR_MD_MAP_RECVFROM_ERROR(err);
michael@0 481 }
michael@0 482 done:
michael@0 483 return(rv);
michael@0 484 }
michael@0 485
michael@0 486 PRInt32
michael@0 487 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size,
michael@0 488 PRIntervalTime timeout)
michael@0 489 {
michael@0 490 PRInt32 rv, err;
michael@0 491 PRThread *me = _PR_MD_CURRENT_THREAD();
michael@0 492 PRInt32 index, amount = 0;
michael@0 493 PRInt32 osfd = fd->secret->md.osfd;
michael@0 494 struct iovec osiov[PR_MAX_IOVECTOR_SIZE];
michael@0 495
michael@0 496 /* Ensured by PR_Writev */
michael@0 497 PR_ASSERT(iov_size <= PR_MAX_IOVECTOR_SIZE);
michael@0 498
michael@0 499 /*
michael@0 500 * We can't pass iov to so_writev because PRIOVec and struct iovec
michael@0 501 * may not be binary compatible. Make osiov a copy of iov and
michael@0 502 * pass osiov to so_writev .
michael@0 503 */
michael@0 504 for (index = 0; index < iov_size; index++) {
michael@0 505 osiov[index].iov_base = iov[index].iov_base;
michael@0 506 osiov[index].iov_len = iov[index].iov_len;
michael@0 507 }
michael@0 508
michael@0 509 /*
michael@0 510 * Calculate the total number of bytes to be sent; needed for
michael@0 511 * optimization later.
michael@0 512 * We could avoid this if this number was passed in; but it is
michael@0 513 * probably not a big deal because iov_size is usually small (less than
michael@0 514 * 3)
michael@0 515 */
michael@0 516 if (!fd->secret->nonblocking) {
michael@0 517 for (index=0; index<iov_size; index++) {
michael@0 518 amount += iov[index].iov_len;
michael@0 519 }
michael@0 520 }
michael@0 521
michael@0 522 while ((rv = so_writev(osfd, osiov, iov_size)) == -1) {
michael@0 523 err = sock_errno();
michael@0 524 if ((err == EWOULDBLOCK)) {
michael@0 525 if (fd->secret->nonblocking) {
michael@0 526 break;
michael@0 527 }
michael@0 528 if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
michael@0 529 goto done;
michael@0 530 } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
michael@0 531 continue;
michael@0 532 } else {
michael@0 533 break;
michael@0 534 }
michael@0 535 }
michael@0 536
michael@0 537 /*
michael@0 538 * optimization; if bytes sent is less than "amount" call
michael@0 539 * select before returning. This is because it is likely that
michael@0 540 * the next writev() call will return EWOULDBLOCK.
michael@0 541 */
michael@0 542 if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
michael@0 543 && (timeout != PR_INTERVAL_NO_WAIT)) {
michael@0 544 if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
michael@0 545 rv = -1;
michael@0 546 goto done;
michael@0 547 }
michael@0 548 }
michael@0 549 if (rv < 0) {
michael@0 550 _PR_MD_MAP_WRITEV_ERROR(err);
michael@0 551 }
michael@0 552 done:
michael@0 553 return(rv);
michael@0 554 }
michael@0 555
michael@0 556 PRInt32
michael@0 557 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
michael@0 558 {
michael@0 559 PRInt32 rv;
michael@0 560
michael@0 561 rv = shutdown(fd->secret->md.osfd, how);
michael@0 562 if (rv < 0)
michael@0 563 _PR_MD_MAP_SHUTDOWN_ERROR(sock_errno());
michael@0 564 return rv;
michael@0 565 }
michael@0 566
michael@0 567 PRInt32
michael@0 568 _PR_MD_SOCKETPAIR(int af, int type, int flags, PRInt32 *osfd)
michael@0 569 {
michael@0 570 PRInt32 rv, err;
michael@0 571
michael@0 572 rv = socketpair(af, type, flags, osfd);
michael@0 573 if (rv < 0) {
michael@0 574 err = _MD_ERRNO();
michael@0 575 _PR_MD_MAP_SOCKETPAIR_ERROR(err);
michael@0 576 }
michael@0 577 return rv;
michael@0 578 }
michael@0 579
michael@0 580 PRStatus
michael@0 581 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
michael@0 582 {
michael@0 583 PRInt32 rv, err;
michael@0 584
michael@0 585 rv = getsockname(fd->secret->md.osfd,
michael@0 586 (struct sockaddr *) addr, (int *)addrlen);
michael@0 587 if (rv < 0) {
michael@0 588 err = sock_errno();
michael@0 589 _PR_MD_MAP_GETSOCKNAME_ERROR(err);
michael@0 590 }
michael@0 591 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 592 }
michael@0 593
michael@0 594 PRStatus
michael@0 595 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
michael@0 596 {
michael@0 597 PRInt32 rv, err;
michael@0 598
michael@0 599 rv = getpeername(fd->secret->md.osfd,
michael@0 600 (struct sockaddr *) addr, (int *)addrlen);
michael@0 601 if (rv < 0) {
michael@0 602 err = sock_errno();
michael@0 603 _PR_MD_MAP_GETPEERNAME_ERROR(err);
michael@0 604 }
michael@0 605 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 606 }
michael@0 607
michael@0 608 PRStatus
michael@0 609 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
michael@0 610 char* optval, PRInt32* optlen)
michael@0 611 {
michael@0 612 PRInt32 rv, err;
michael@0 613
michael@0 614 rv = getsockopt(fd->secret->md.osfd, level, optname, optval, (int *)optlen);
michael@0 615 if (rv < 0) {
michael@0 616 err = sock_errno();
michael@0 617 _PR_MD_MAP_GETSOCKOPT_ERROR(err);
michael@0 618 }
michael@0 619 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 620 }
michael@0 621
michael@0 622 PRStatus
michael@0 623 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname,
michael@0 624 const char* optval, PRInt32 optlen)
michael@0 625 {
michael@0 626 PRInt32 rv, err;
michael@0 627
michael@0 628 rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
michael@0 629 if (rv < 0) {
michael@0 630 err = sock_errno();
michael@0 631 _PR_MD_MAP_SETSOCKOPT_ERROR(err);
michael@0 632 }
michael@0 633 return rv==0?PR_SUCCESS:PR_FAILURE;
michael@0 634 }
michael@0 635
michael@0 636 void
michael@0 637 _MD_MakeNonblock(PRFileDesc *fd)
michael@0 638 {
michael@0 639 PRInt32 osfd = fd->secret->md.osfd;
michael@0 640 PRInt32 err;
michael@0 641 PRUint32 one = 1;
michael@0 642
michael@0 643 if (osfd <= 2) {
michael@0 644 /* Don't mess around with stdin, stdout or stderr */
michael@0 645 return;
michael@0 646 }
michael@0 647
michael@0 648 err = so_ioctl( osfd, FIONBIO, (char *) &one, sizeof(one));
michael@0 649 if ( err != 0 )
michael@0 650 {
michael@0 651 err = sock_errno();
michael@0 652 _PR_MD_MAP_SOCKET_ERROR(err);
michael@0 653 }
michael@0 654 }

mercurial