Back to index

lightning-sunbird  0.9+nobinonly
bnet.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 #include <signal.h>
00041 #include <unistd.h>
00042 #include <memory.h>
00043 #include <fcntl.h>
00044 #include <sys/types.h>
00045 #include <sys/socket.h>
00046 #include <sys/time.h>
00047 #include <sys/ioctl.h>
00048 
00049 /*
00050  * Make sure _PRSockLen_t is 32-bit, because we will cast a PRUint32* or
00051  * PRInt32* pointer to a _PRSockLen_t* pointer.
00052  */
00053 #define _PRSockLen_t int
00054 
00055 
00056 /*
00057 ** Global lock variable used to bracket calls into rusty libraries that
00058 ** aren't thread safe (like libc, libX, etc).
00059 */
00060 static PRLock *_pr_rename_lock = NULL;
00061 static PRMonitor *_pr_Xfe_mon = NULL;
00062 
00063 #define READ_FD     1
00064 #define WRITE_FD    2
00065 
00066 /*
00067 ** This is a support routine to handle "deferred" i/o on sockets. 
00068 ** It uses "select", so it is subject to all of the BeOS limitations
00069 ** (only READ notification, only sockets)
00070 */
00071 
00072 /*
00073  * socket_io_wait --
00074  *
00075  * wait for socket i/o, periodically checking for interrupt
00076  *
00077  */
00078 
00079 static PRInt32 socket_io_wait(PRInt32 osfd, PRInt32 fd_type,
00080                               PRIntervalTime timeout)
00081 {
00082     PRInt32 rv = -1;
00083     struct timeval tv;
00084     PRThread *me = _PR_MD_CURRENT_THREAD();
00085     PRIntervalTime epoch, now, elapsed, remaining;
00086     PRBool wait_for_remaining;
00087     PRInt32 syserror;
00088     fd_set rd_wr;
00089 
00090     switch (timeout) {
00091     case PR_INTERVAL_NO_WAIT:
00092         PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00093         break;
00094     case PR_INTERVAL_NO_TIMEOUT:
00095         /*
00096          * This is a special case of the 'default' case below.
00097          * Please see the comments there.
00098          */
00099         tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00100         tv.tv_usec = 0;
00101         FD_ZERO(&rd_wr);
00102         do {
00103             FD_SET(osfd, &rd_wr);
00104             if (fd_type == READ_FD)
00105                 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00106             else
00107                 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00108             if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00109 #ifdef BONE_VERSION
00110                 _PR_MD_MAP_SELECT_ERROR(syserror);
00111 #else
00112                 if (syserror == EBADF) {
00113                     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
00114                 } else {
00115                     PR_SetError(PR_UNKNOWN_ERROR, syserror);
00116                 }
00117 #endif
00118                 break;
00119             }
00120             if (_PR_PENDING_INTERRUPT(me)) {
00121                 me->flags &= ~_PR_INTERRUPT;
00122                 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00123                 rv = -1;
00124                 break;
00125             }
00126         } while (rv == 0 || (rv == -1 && syserror == EINTR));
00127         break;
00128     default:
00129         now = epoch = PR_IntervalNow();
00130         remaining = timeout;
00131         FD_ZERO(&rd_wr);
00132         do {
00133             /*
00134              * We block in _MD_SELECT for at most
00135              * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
00136              * so that there is an upper limit on the delay
00137              * before the interrupt bit is checked.
00138              */
00139             wait_for_remaining = PR_TRUE;
00140             tv.tv_sec = PR_IntervalToSeconds(remaining);
00141             if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
00142                 wait_for_remaining = PR_FALSE;
00143                 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
00144                 tv.tv_usec = 0;
00145             } else {
00146                 tv.tv_usec = PR_IntervalToMicroseconds(
00147                                  remaining -
00148                                  PR_SecondsToInterval(tv.tv_sec));
00149             }
00150             FD_SET(osfd, &rd_wr);
00151             if (fd_type == READ_FD)
00152                 rv = _MD_SELECT(osfd + 1, &rd_wr, NULL, NULL, &tv);
00153             else
00154                 rv = _MD_SELECT(osfd + 1, NULL, &rd_wr, NULL, &tv);
00155             /*
00156              * we don't consider EINTR a real error
00157              */
00158             if (rv == -1 && (syserror = _MD_ERRNO()) != EINTR) {
00159 #ifdef BONE_VERSION
00160                 _PR_MD_MAP_SELECT_ERROR(syserror);
00161 #else
00162                 if (syserror == EBADF) {
00163                     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, EBADF);
00164                 } else {
00165                     PR_SetError(PR_UNKNOWN_ERROR, syserror);
00166                 }
00167 #endif
00168                 break;
00169             }
00170             if (_PR_PENDING_INTERRUPT(me)) {
00171                 me->flags &= ~_PR_INTERRUPT;
00172                 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00173                 rv = -1;
00174                 break;
00175             }
00176             /*
00177              * We loop again if _MD_SELECT timed out or got interrupted
00178              * by a signal, and the timeout deadline has not passed yet.
00179              */
00180             if (rv == 0 || (rv == -1 && syserror == EINTR)) {
00181                 /*
00182                  * If _MD_SELECT timed out, we know how much time
00183                  * we spent in blocking, so we can avoid a
00184                  * PR_IntervalNow() call.
00185                  */
00186                 if (rv == 0) {
00187                     if (wait_for_remaining) {
00188                         now += remaining;
00189                     } else {
00190                         now += PR_SecondsToInterval(tv.tv_sec)
00191                                + PR_MicrosecondsToInterval(tv.tv_usec);
00192                     }
00193                 } else {
00194                     now = PR_IntervalNow();
00195                 }
00196                 elapsed = (PRIntervalTime) (now - epoch);
00197                 if (elapsed >= timeout) {
00198                     PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
00199                     rv = -1;
00200                     break;
00201                 } else {
00202                     remaining = timeout - elapsed;
00203                 }
00204             }
00205         } while (rv == 0 || (rv == -1 && syserror == EINTR));
00206         break;
00207     }
00208     return(rv);
00209 }
00210 
00211 PRInt32
00212 _MD_recv (PRFileDesc *fd, void *buf, PRInt32 amount, PRInt32 flags,
00213           PRIntervalTime timeout)
00214 {
00215     PRInt32 osfd = fd->secret->md.osfd;
00216     PRInt32 rv, err;
00217     PRThread *me = _PR_MD_CURRENT_THREAD();
00218 
00219 #ifndef BONE_VERSION
00220     if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_READ) {
00221         _PR_MD_MAP_RECV_ERROR(EPIPE);
00222         return -1;
00223     }
00224 #endif
00225 
00226 #ifdef BONE_VERSION
00227     /*
00228     ** Gah, stupid hack.  If reading a zero amount, instantly return success.
00229     ** BONE beta 6 returns EINVAL for reads of zero bytes, which parts of
00230     ** mozilla use to check for socket availability.
00231     */
00232 
00233     if( 0 == amount ) return(0);
00234 #endif
00235 
00236     while ((rv = recv(osfd, buf, amount, flags)) == -1) {
00237         err = _MD_ERRNO();
00238 
00239         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00240             if (fd->secret->nonblocking) {
00241                 break;
00242             }
00243             /* If socket was supposed to be blocking,
00244             wait a while for the condition to be
00245             satisfied. */
00246             if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00247                 goto done;
00248         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00249             continue;
00250 
00251         } else
00252             break;
00253     }
00254 
00255     if (rv < 0) {
00256         _PR_MD_MAP_RECV_ERROR(err);
00257     }
00258 
00259 done:
00260     return(rv);
00261 }
00262 
00263 PRInt32
00264 _MD_recvfrom (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
00265               PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
00266 {
00267     PRInt32 osfd = fd->secret->md.osfd;
00268     PRInt32 rv, err;
00269     PRThread *me = _PR_MD_CURRENT_THREAD();
00270 
00271     while ((*addrlen = PR_NETADDR_SIZE(addr)),
00272             ((rv = recvfrom(osfd, buf, amount, flags,
00273                             (struct sockaddr *) addr,
00274                             (_PRSockLen_t *)addrlen)) == -1)) {
00275         err = _MD_ERRNO();
00276 
00277         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00278             if (fd->secret->nonblocking) {
00279                 break;
00280             }
00281             if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00282                 goto done;
00283 
00284         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
00285             continue;
00286         } else {
00287             break;
00288         }
00289     }
00290 
00291     if (rv < 0) {
00292         _PR_MD_MAP_RECVFROM_ERROR(err);
00293     }
00294 
00295 done:
00296 #ifdef _PR_HAVE_SOCKADDR_LEN
00297     if (rv != -1) {
00298         /* ignore the sa_len field of struct sockaddr */
00299         if (addr) {
00300             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
00301         }
00302     }
00303 #endif /* _PR_HAVE_SOCKADDR_LEN */
00304     return(rv);
00305 }
00306 
00307 PRInt32
00308 _MD_send (PRFileDesc *fd, const void *buf, PRInt32 amount, PRInt32 flags,
00309           PRIntervalTime timeout)
00310 {
00311     PRInt32 osfd = fd->secret->md.osfd;
00312     PRInt32 rv, err;
00313     PRThread *me = _PR_MD_CURRENT_THREAD();
00314 
00315 #ifndef BONE_VERSION
00316     if (fd->secret->md.sock_state & BE_SOCK_SHUTDOWN_WRITE)
00317     {
00318         _PR_MD_MAP_SEND_ERROR(EPIPE);
00319         return -1;
00320     }
00321 #endif
00322 
00323     while ((rv = send(osfd, buf, amount, flags)) == -1) {
00324         err = _MD_ERRNO();
00325 
00326         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00327             if (fd->secret->nonblocking) {
00328                 break;
00329             }
00330 
00331 #ifndef BONE_VERSION
00332             if( _PR_PENDING_INTERRUPT(me)) {
00333 
00334                 me->flags &= ~_PR_INTERRUPT;
00335                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00336                 return -1;
00337             }
00338 
00339             /* in UNIX implementations, you could do a socket_io_wait here.
00340              * but since BeOS doesn't yet support WRITE notification in select,
00341              * you're spanked.
00342              */
00343             snooze( 10000L );
00344             continue;
00345 #else /* BONE_VERSION */
00346             if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
00347                 goto done;
00348 #endif
00349 
00350         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
00351             continue;
00352 
00353         } else {
00354             break;
00355         }
00356     }
00357 
00358 #ifdef BONE_VERSION
00359     /*
00360      * optimization; if bytes sent is less than "amount" call
00361      * select before returning. This is because it is likely that
00362      * the next writev() call will return EWOULDBLOCK.
00363      */
00364     if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
00365         && (timeout != PR_INTERVAL_NO_WAIT)) {
00366         if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
00367             rv = -1;
00368             goto done;
00369         }
00370     }
00371 #endif /* BONE_VERSION */
00372     
00373     if (rv < 0) {
00374         _PR_MD_MAP_SEND_ERROR(err);
00375     }
00376 
00377 #ifdef BONE_VERSION
00378 done:
00379 #endif
00380     return(rv);
00381 }
00382 
00383 PRInt32
00384 _MD_sendto (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
00385             const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
00386 {
00387     PRInt32 osfd = fd->secret->md.osfd;
00388     PRInt32 rv, err;
00389     PRThread *me = _PR_MD_CURRENT_THREAD();
00390 #ifdef _PR_HAVE_SOCKADDR_LEN
00391     PRNetAddr addrCopy;
00392 
00393     addrCopy = *addr;
00394     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
00395     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
00396 
00397     while ((rv = sendto(osfd, buf, amount, flags,
00398                         (struct sockaddr *) &addrCopy, addrlen)) == -1) {
00399 #else
00400     while ((rv = sendto(osfd, buf, amount, flags,
00401                         (struct sockaddr *) addr, addrlen)) == -1) {
00402 #endif
00403         err = _MD_ERRNO();
00404 
00405         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00406             if (fd->secret->nonblocking) {
00407                 break;
00408             }
00409 
00410 #ifdef BONE_VERSION
00411             if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))< 0)
00412                 goto done;
00413 #endif
00414         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
00415             continue;
00416 
00417         } else {
00418             break;
00419         }
00420     }
00421 
00422     if (rv < 0) {
00423         _PR_MD_MAP_SENDTO_ERROR(err);
00424     }
00425 
00426 #ifdef BONE_VERSION
00427 done:
00428 #endif
00429     return(rv);
00430 }
00431 
00432 #ifdef BONE_VERSION
00433 
00434 PRInt32 _MD_writev(
00435     PRFileDesc *fd, const PRIOVec *iov,
00436     PRInt32 iov_size, PRIntervalTime timeout)
00437 {
00438     PRInt32 rv, err;
00439     PRThread *me = _PR_MD_CURRENT_THREAD();
00440     PRInt32 index, amount = 0;
00441     PRInt32 osfd = fd->secret->md.osfd;
00442 
00443     /*
00444      * Calculate the total number of bytes to be sent; needed for
00445      * optimization later.
00446      * We could avoid this if this number was passed in; but it is
00447      * probably not a big deal because iov_size is usually small (less than
00448      * 3)
00449      */
00450     if (!fd->secret->nonblocking) {
00451         for (index=0; index<iov_size; index++) {
00452             amount += iov[index].iov_len;
00453         }
00454     }
00455 
00456     while ((rv = writev(osfd, (const struct iovec*)iov, iov_size)) == -1) {
00457         err = _MD_ERRNO();
00458         if ((err == EAGAIN) || (err == EWOULDBLOCK))    {
00459             if (fd->secret->nonblocking) {
00460                 break;
00461             }
00462             if ((rv = socket_io_wait(osfd, WRITE_FD, timeout))<0)
00463                 goto done;
00464 
00465         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))){
00466             continue;
00467         } else {
00468             break;
00469         }
00470     }
00471 
00472     /*
00473      * optimization; if bytes sent is less than "amount" call
00474      * select before returning. This is because it is likely that
00475      * the next writev() call will return EWOULDBLOCK.
00476      */
00477     if ((!fd->secret->nonblocking) && (rv > 0) && (rv < amount)
00478         && (timeout != PR_INTERVAL_NO_WAIT)) {
00479         if (socket_io_wait(osfd, WRITE_FD, timeout) < 0) {
00480             rv = -1;
00481             goto done;
00482         }
00483     }
00484 
00485 
00486     if (rv < 0) {
00487         _PR_MD_MAP_WRITEV_ERROR(err);
00488     }
00489 done:
00490     return(rv);
00491 }
00492 
00493 #endif /* BONE_VERSION */
00494 
00495 PRInt32
00496 _MD_accept (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen,
00497             PRIntervalTime timeout)
00498 {
00499     PRInt32 osfd = fd->secret->md.osfd;
00500     PRInt32 rv, err;
00501     PRThread *me = _PR_MD_CURRENT_THREAD();
00502 
00503     while ((rv = accept(osfd, (struct sockaddr *) addr,
00504                         (_PRSockLen_t *)addrlen)) == -1) {
00505         err = _MD_ERRNO();
00506 
00507         if ((err == EAGAIN) || (err == EWOULDBLOCK)) {
00508             if (fd->secret->nonblocking) {
00509                 break;
00510             }
00511             /* If it's SUPPOSED to be a blocking thread, wait
00512              * a while to see if the triggering condition gets
00513              * satisfied.
00514              */
00515             /* Assume that we're always using a native thread */
00516             if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
00517                 goto done;
00518         } else if ((err == EINTR) && (!_PR_PENDING_INTERRUPT(me))) {
00519             continue;
00520         } else {
00521             break;
00522         }
00523     }
00524     if (rv < 0) {
00525         _PR_MD_MAP_ACCEPT_ERROR(err);
00526     } else if (addr != NULL) {
00527         /* bug 134099 */
00528         err = getpeername(rv, (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
00529     }
00530 done:
00531 #ifdef _PR_HAVE_SOCKADDR_LEN
00532     if (rv != -1) {
00533         /* Mask off the first byte of struct sockaddr (the length field) */
00534         if (addr) {
00535             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
00536         }
00537     }
00538 #endif /* _PR_HAVE_SOCKADDR_LEN */
00539     return(rv);
00540 }
00541 
00542 PRInt32
00543 _MD_connect (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
00544              PRIntervalTime timeout)
00545 {
00546     PRInt32 rv, err;
00547     PRThread *me = _PR_MD_CURRENT_THREAD();
00548     PRInt32 osfd = fd->secret->md.osfd;
00549 
00550 #ifndef BONE_VERSION
00551     fd->secret->md.connectValueValid = PR_FALSE;
00552 #endif
00553 #ifdef _PR_HAVE_SOCKADDR_LEN
00554     PRNetAddr addrCopy;
00555 
00556     addrCopy = *addr;
00557     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
00558     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
00559 #endif
00560 
00561     /* (Copied from unix.c)
00562      * We initiate the connection setup by making a nonblocking connect()
00563      * call.  If the connect() call fails, there are two cases we handle
00564      * specially:
00565      * 1. The connect() call was interrupted by a signal.  In this case
00566      *    we simply retry connect().
00567      * 2. The NSPR socket is nonblocking and connect() fails with
00568      *    EINPROGRESS.  We first wait until the socket becomes writable.
00569      *    Then we try to find out whether the connection setup succeeded
00570      *    or failed.
00571      */
00572 
00573 retry:
00574 #ifdef _PR_HAVE_SOCKADDR_LEN
00575     if ((rv = connect(osfd, (struct sockaddr *)&addrCopy, addrlen)) == -1) {
00576 #else
00577     if ((rv = connect(osfd, (struct sockaddr *)addr, addrlen)) == -1) {
00578 #endif
00579         err = _MD_ERRNO();
00580 #ifndef BONE_VERSION
00581         fd->secret->md.connectReturnValue = rv;
00582         fd->secret->md.connectReturnError = err;
00583         fd->secret->md.connectValueValid = PR_TRUE;
00584 #endif
00585         if( err == EINTR ) {
00586 
00587             if( _PR_PENDING_INTERRUPT(me)) {
00588 
00589                 me->flags &= ~_PR_INTERRUPT;
00590                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00591                 return -1;
00592             }
00593 #ifndef BONE_VERSION
00594             snooze( 100000L );
00595 #endif
00596             goto retry;
00597         }
00598 
00599 #ifndef BONE_VERSION
00600         if(!fd->secret->nonblocking && ((err == EINPROGRESS) || (err==EAGAIN) || (err==EALREADY))) {
00601 
00602             /*
00603             ** There's no timeout on this connect, but that's not
00604             ** a big deal, since the connect times out anyways
00605             ** after 30 seconds.   Just sleep for 1/10th of a second
00606             ** and retry until we go through or die.
00607             */
00608 
00609             if( _PR_PENDING_INTERRUPT(me)) {
00610                 me->flags &= ~_PR_INTERRUPT;
00611                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00612                 return -1;
00613             }
00614 
00615             goto retry;
00616         }
00617 
00618         if( fd->secret->nonblocking && ((err == EAGAIN) || (err == EINPROGRESS))) {
00619             PR_Lock(_connectLock);
00620             if (connectCount < sizeof(connectList)/sizeof(connectList[0])) {
00621                 connectList[connectCount].osfd = osfd;
00622                 memcpy(&connectList[connectCount].addr, addr, addrlen);
00623                 connectList[connectCount].addrlen = addrlen;
00624                 connectList[connectCount].timeout = timeout;
00625                 connectCount++;
00626                 PR_Unlock(_connectLock);
00627                 _PR_MD_MAP_CONNECT_ERROR(err);
00628             } else {
00629                 PR_Unlock(_connectLock);
00630                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00631             }
00632             return rv;
00633         }
00634 #else /* BONE_VERSION */
00635         if(!fd->secret->nonblocking && (err == EINTR)) {
00636 
00637             rv = socket_io_wait(osfd, WRITE_FD, timeout);
00638             if (rv == -1) {
00639                 return -1;
00640             }
00641 
00642             PR_ASSERT(rv == 1);
00643             if (_PR_PENDING_INTERRUPT(me)) {
00644                 me->flags &= ~_PR_INTERRUPT;
00645                 PR_SetError( PR_PENDING_INTERRUPT_ERROR, 0);
00646                 return -1;
00647             }
00648             err = _MD_beos_get_nonblocking_connect_error(osfd);
00649             if (err != 0) {
00650                 _PR_MD_MAP_CONNECT_ERROR(err);
00651                 return -1;
00652             }
00653             return 0;
00654         }
00655 #endif
00656 
00657         _PR_MD_MAP_CONNECT_ERROR(err);
00658     }
00659 
00660     return rv;
00661 }
00662 
00663 PRInt32
00664 _MD_bind (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
00665 {
00666     PRInt32 rv, err;
00667 #ifdef _PR_HAVE_SOCKADDR_LEN
00668     PRNetAddr addrCopy;
00669 
00670     addrCopy = *addr;
00671     ((struct sockaddr *) &addrCopy)->sa_len = addrlen;
00672     ((struct sockaddr *) &addrCopy)->sa_family = addr->raw.family;
00673     rv = bind(fd->secret->md.osfd, (struct sockaddr *) &addrCopy, (int )addrlen);
00674 #else
00675     rv = bind(fd->secret->md.osfd, (struct sockaddr *) addr, (int )addrlen);
00676 #endif
00677     if (rv < 0) {
00678         err = _MD_ERRNO();
00679         _PR_MD_MAP_BIND_ERROR(err);
00680     }
00681 
00682     return(rv);
00683 }
00684 
00685 PRInt32
00686 _MD_listen (PRFileDesc *fd, PRIntn backlog)
00687 {
00688     PRInt32 rv, err;
00689 
00690 #ifndef BONE_VERSION
00691     /* Bug workaround!  Setting listen to 0 on Be accepts no connections.
00692     ** On most UN*Xes this sets the default.
00693     */
00694 
00695     if( backlog == 0 ) backlog = 5;
00696 #endif
00697 
00698     rv = listen(fd->secret->md.osfd, backlog);
00699     if (rv < 0) {
00700         err = _MD_ERRNO();
00701         _PR_MD_MAP_LISTEN_ERROR(err);
00702     }
00703 
00704     return(rv);
00705 }
00706 
00707 PRInt32
00708 _MD_shutdown (PRFileDesc *fd, PRIntn how)
00709 {
00710     PRInt32 rv, err;
00711 
00712 #ifndef BONE_VERSION
00713     if (how == PR_SHUTDOWN_SEND)
00714         fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_WRITE;
00715     else if (how == PR_SHUTDOWN_RCV)
00716         fd->secret->md.sock_state = BE_SOCK_SHUTDOWN_READ;
00717     else if (how == PR_SHUTDOWN_BOTH) {
00718         fd->secret->md.sock_state = (BE_SOCK_SHUTDOWN_WRITE | BE_SOCK_SHUTDOWN_READ);
00719     }
00720 
00721     return 0;
00722 #else /* BONE_VERSION */
00723     rv = shutdown(fd->secret->md.osfd, how);
00724     if (rv < 0) {
00725         err = _MD_ERRNO();
00726         _PR_MD_MAP_SHUTDOWN_ERROR(err);
00727     }
00728     return(rv);
00729 #endif
00730 }
00731 
00732 PRInt32
00733 _MD_socketpair (int af, int type, int flags, PRInt32 *osfd)
00734 {
00735     return PR_NOT_IMPLEMENTED_ERROR;
00736 }
00737 
00738 PRInt32
00739 _MD_close_socket (PRInt32 osfd)
00740 {
00741 #ifdef BONE_VERSION
00742     close( osfd );
00743 #else
00744     closesocket( osfd );
00745 #endif
00746 }
00747 
00748 PRStatus
00749 _MD_getsockname (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
00750 {
00751     PRInt32 rv, err;
00752 
00753     rv = getsockname(fd->secret->md.osfd,
00754                      (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
00755 #ifdef _PR_HAVE_SOCKADDR_LEN
00756     if (rv == 0) {
00757         /* ignore the sa_len field of struct sockaddr */
00758         if (addr) {
00759             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
00760         }
00761     }
00762 #endif /* _PR_HAVE_SOCKADDR_LEN */
00763     if (rv < 0) {
00764         err = _MD_ERRNO();
00765         _PR_MD_MAP_GETSOCKNAME_ERROR(err);
00766     }
00767 
00768     return rv==0?PR_SUCCESS:PR_FAILURE;
00769 }
00770 
00771 PRStatus
00772 _MD_getpeername (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *addrlen)
00773 {
00774     PRInt32 rv, err;
00775 
00776     rv = getpeername(fd->secret->md.osfd,
00777                      (struct sockaddr *) addr, (_PRSockLen_t *)addrlen);
00778 
00779 #ifdef _PR_HAVE_SOCKADDR_LEN
00780     if (rv == 0) {
00781         /* ignore the sa_len field of struct sockaddr */
00782         if (addr) {
00783             addr->raw.family = ((struct sockaddr *) addr)->sa_family;
00784         }
00785     }
00786 #endif /* _PR_HAVE_SOCKADDR_LEN */
00787 
00788     if (rv < 0) {
00789         err = _MD_ERRNO();
00790         _PR_MD_MAP_GETPEERNAME_ERROR(err);
00791     }
00792     return rv==0?PR_SUCCESS:PR_FAILURE;
00793 }
00794 
00795 PRStatus
00796 _MD_getsockopt (PRFileDesc *fd, PRInt32 level,
00797                 PRInt32 optname, char* optval, PRInt32* optlen)
00798 {
00799     PRInt32 rv, err;
00800 
00801     rv = getsockopt(fd->secret->md.osfd, level, optname,
00802                     optval, (_PRSockLen_t *)optlen);
00803     if (rv < 0) {
00804         err = _MD_ERRNO();
00805         _PR_MD_MAP_GETSOCKOPT_ERROR(err);
00806     }
00807 
00808     return rv==0?PR_SUCCESS:PR_FAILURE;
00809 }
00810 
00811 PRStatus
00812 _MD_setsockopt (PRFileDesc *fd, PRInt32 level,
00813                 PRInt32 optname, const char* optval, PRInt32 optlen)
00814 {
00815     PRInt32 rv, err;
00816 
00817     rv = setsockopt(fd->secret->md.osfd, level, optname, optval, optlen);
00818     if (rv < 0) {
00819         err = _MD_ERRNO();
00820         _PR_MD_MAP_SETSOCKOPT_ERROR(err);
00821     }
00822     return rv==0?PR_SUCCESS:PR_FAILURE;
00823 }
00824 
00825 PRInt32
00826 _MD_accept_read (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr,
00827                  void *buf, PRInt32 amount, PRIntervalTime timeout)
00828 {
00829     return PR_NOT_IMPLEMENTED_ERROR;
00830 }
00831 
00832 #ifndef BONE_VERSION
00833 PRInt32
00834 _MD_socket (int af, int type, int flags)
00835 {
00836     PRInt32 osfd, err;
00837 
00838     osfd = socket( af, type, 0 );
00839 
00840     if( -1 == osfd ) {
00841 
00842         err = _MD_ERRNO();
00843         _PR_MD_MAP_SOCKET_ERROR( err );
00844     }
00845 
00846     return( osfd );
00847 }
00848 #else
00849 PRInt32
00850 _MD_socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
00851 {
00852     PRInt32 osfd, err;
00853 
00854     osfd = socket(domain, type, proto);
00855 
00856     if (osfd == -1) {
00857         err = _MD_ERRNO();
00858         _PR_MD_MAP_SOCKET_ERROR(err);
00859     }
00860 
00861     return(osfd);
00862 }
00863 #endif
00864 
00865 PRInt32
00866 _MD_socketavailable (PRFileDesc *fd)
00867 {
00868 #ifdef BONE_VERSION
00869     PRInt32 result;
00870 
00871     if (ioctl(fd->secret->md.osfd, FIONREAD, &result) < 0) {
00872         _PR_MD_MAP_SOCKETAVAILABLE_ERROR(_MD_ERRNO());
00873         return -1;
00874     }
00875     return result;
00876 #else
00877     return PR_NOT_IMPLEMENTED_ERROR;
00878 #endif
00879 }
00880 
00881 PRInt32
00882 _MD_get_socket_error (void)
00883 {
00884     return PR_NOT_IMPLEMENTED_ERROR;
00885 }
00886 
00887 PRStatus
00888 _MD_gethostname (char *name, PRUint32 namelen)
00889 {
00890     PRInt32 rv, err;
00891 
00892     rv = gethostname(name, namelen);
00893     if (rv == 0)
00894     {
00895         err = _MD_ERRNO();
00896         _PR_MD_MAP_GETHOSTNAME_ERROR(err);
00897         return PR_FAILURE;
00898     }
00899     return PR_SUCCESS;
00900 }
00901 
00902 #ifndef BONE_VERSION
00903 PRInt32
00904 _MD_beos_get_nonblocking_connect_error(PRFileDesc *fd)
00905 {
00906     int rv;
00907     int flags = 0;
00908 
00909     rv = recv(fd->secret->md.osfd, NULL, 0, flags);
00910     PR_ASSERT(-1 == rv || 0 == rv);
00911     if (-1 == rv && errno != EAGAIN && errno != EWOULDBLOCK) {
00912         return errno;
00913     }
00914     return 0;  /* no error */
00915 }
00916 #else
00917 PRInt32
00918 _MD_beos_get_nonblocking_connect_error(int osfd)
00919 {
00920     return PR_NOT_IMPLEMENTED_ERROR;
00921     //    int err;
00922     //    _PRSockLen_t optlen = sizeof(err);
00923     //    if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &optlen) == -1) {
00924     //        return errno;
00925     //    } else {
00926     //        return err;
00927     //    }
00928 }
00929 #endif /* BONE_VERSION */