Back to index

lightning-sunbird  0.9+nobinonly
prsocket.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 <string.h>
00041 
00042 /************************************************************************/
00043 
00044 /* These two functions are only used in assertions. */
00045 #if defined(DEBUG)
00046 
00047 PRBool IsValidNetAddr(const PRNetAddr *addr)
00048 {
00049     if ((addr != NULL)
00050 #if defined(XP_UNIX) || defined(XP_OS2_EMX)
00051            && (addr->raw.family != PR_AF_LOCAL)
00052 #endif
00053            && (addr->raw.family != PR_AF_INET6)
00054            && (addr->raw.family != PR_AF_INET)) {
00055         return PR_FALSE;
00056     }
00057     return PR_TRUE;
00058 }
00059 
00060 static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
00061 {
00062     /*
00063      * The definition of the length of a Unix domain socket address
00064      * is not uniform, so we don't check it.
00065      */
00066     if ((addr != NULL)
00067 #if defined(XP_UNIX) || defined(XP_OS2_EMX)
00068             && (addr->raw.family != AF_UNIX)
00069 #endif
00070             && (PR_NETADDR_SIZE(addr) != addr_len)) {
00071 #if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
00072         /*
00073          * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
00074          * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
00075          * field and is 28 bytes.  It is possible for socket functions
00076          * to return an addr_len greater than sizeof(struct sockaddr_in6).
00077          * We need to allow that.  (Bugzilla bug #77264)
00078          */
00079         if ((PR_AF_INET6 == addr->raw.family)
00080                 && (sizeof(addr->ipv6) == addr_len)) {
00081             return PR_TRUE;
00082         }
00083 #endif
00084         /*
00085          * The accept(), getsockname(), etc. calls on some platforms
00086          * do not set the actual socket address length on return.
00087          * In this case, we verifiy addr_len is still the value we
00088          * passed in (i.e., sizeof(PRNetAddr)).
00089          */
00090 #if defined(QNX)
00091         if (sizeof(PRNetAddr) == addr_len) {
00092             return PR_TRUE;
00093         }
00094 #endif
00095         return PR_FALSE;
00096     }
00097     return PR_TRUE;
00098 }
00099 
00100 #endif /* DEBUG */
00101 
00102 static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
00103 PRInt32 iov_size, PRIntervalTime timeout)
00104 {
00105        PRThread *me = _PR_MD_CURRENT_THREAD();
00106        int w = 0;
00107        const PRIOVec *tmp_iov;
00108 #define LOCAL_MAXIOV    8
00109        PRIOVec local_iov[LOCAL_MAXIOV];
00110        PRIOVec *iov_copy = NULL;
00111        int tmp_out;
00112        int index, iov_cnt;
00113        int count=0, sz = 0;    /* 'count' is the return value. */
00114 
00115        if (_PR_PENDING_INTERRUPT(me)) {
00116               me->flags &= ~_PR_INTERRUPT;
00117               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00118               return -1;
00119        }
00120        if (_PR_IO_PENDING(me)) {
00121               PR_SetError(PR_IO_PENDING_ERROR, 0);
00122               return -1;
00123        }
00124 
00125     /*
00126      * Assume the first writev will succeed.  Copy iov's only on
00127      * failure.
00128      */
00129     tmp_iov = iov;
00130     for (index = 0; index < iov_size; index++)
00131         sz += iov[index].iov_len;
00132 
00133        iov_cnt = iov_size;
00134 
00135        while (sz > 0) {
00136 
00137               w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
00138               if (w < 0) {
00139                      count = -1;
00140                      break;
00141               }
00142               count += w;
00143               if (fd->secret->nonblocking) {
00144                      break;
00145               }
00146               sz -= w;
00147 
00148               if (sz > 0) {
00149                      /* find the next unwritten vector */
00150                      for ( index = 0, tmp_out = count;
00151                             tmp_out >= iov[index].iov_len;
00152                             tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
00153 
00154                      if (tmp_iov == iov) {
00155                             /*
00156                              * The first writev failed so we
00157                              * must copy iov's around.
00158                              * Avoid calloc/free if there
00159                              * are few enough iov's.
00160                              */
00161                             if (iov_size - index <= LOCAL_MAXIOV)
00162                                    iov_copy = local_iov;
00163                             else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
00164                                    sizeof *iov_copy)) == NULL) {
00165                                    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00166                                    return -1;
00167                             }
00168                             tmp_iov = iov_copy;
00169                      }
00170 
00171                      PR_ASSERT(tmp_iov == iov_copy);
00172 
00173                      /* fill in the first partial read */
00174                      iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
00175                      iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
00176                      index++;
00177 
00178                      /* copy the remaining vectors */
00179                      for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
00180                             iov_copy[iov_cnt].iov_base = iov[index].iov_base;
00181                             iov_copy[iov_cnt].iov_len = iov[index].iov_len;
00182                      }
00183               }
00184        }
00185 
00186        if (iov_copy != local_iov)
00187               PR_DELETE(iov_copy);
00188        return count;
00189 }
00190 
00191 /************************************************************************/
00192 
00193 PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
00194 {
00195 PRFileDesc *fd;
00196 
00197        if (!_pr_initialized) _PR_ImplicitInitialization();
00198        fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
00199        if (fd != NULL) {
00200               _PR_MD_MAKE_NONBLOCK(fd);
00201               _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
00202 #ifdef _PR_NEED_SECRET_AF
00203               /* this means we can only import IPv4 sockets here.
00204                * but this is what the function in ptio.c does.
00205                * We need a way to import IPv6 sockets, too.
00206                */
00207               fd->secret->af = AF_INET;
00208 #endif
00209        } else
00210               _PR_MD_CLOSE_SOCKET(osfd);
00211        return(fd);
00212 }
00213 
00214 PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
00215 {
00216 PRFileDesc *fd;
00217 
00218        if (!_pr_initialized) _PR_ImplicitInitialization();
00219        fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
00220        if (fd != NULL) {
00221               _PR_MD_MAKE_NONBLOCK(fd);
00222               _PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
00223        } else
00224               _PR_MD_CLOSE_SOCKET(osfd);
00225        return(fd);
00226 }
00227 
00228 
00229 static const PRIOMethods* PR_GetSocketPollFdMethods(void);
00230 
00231 PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PRInt32 osfd)
00232 {
00233     PRFileDesc *fd;
00234 
00235     if (!_pr_initialized) _PR_ImplicitInitialization();
00236 
00237     fd = _PR_Getfd();
00238 
00239     if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00240     else
00241     {
00242         fd->secret->md.osfd = osfd;
00243         fd->secret->inheritable = _PR_TRI_FALSE;
00244        fd->secret->state = _PR_FILEDESC_OPEN;
00245         fd->methods = PR_GetSocketPollFdMethods();
00246     }
00247 
00248     return fd;
00249 }  /* PR_CreateSocketPollFD */
00250 
00251 PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
00252 {
00253     if (NULL == fd)
00254     {
00255         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
00256         return PR_FAILURE;
00257     }
00258     fd->secret->state = _PR_FILEDESC_CLOSED;
00259     _PR_Putfd(fd);
00260     return PR_SUCCESS;
00261 }  /* PR_DestroySocketPollFd */
00262 
00263 static PRStatus PR_CALLBACK SocketConnect(
00264     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
00265 {
00266        PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
00267     const PRNetAddr *addrp = addr;
00268 #if defined(_PR_INET6)
00269        PRNetAddr addrCopy;
00270 #endif
00271        PRThread *me = _PR_MD_CURRENT_THREAD();
00272 
00273        if (_PR_PENDING_INTERRUPT(me)) {
00274               me->flags &= ~_PR_INTERRUPT;
00275               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00276               return PR_FAILURE;
00277        }
00278 #if defined(_PR_INET6)
00279        if (addr->raw.family == PR_AF_INET6) {
00280               addrCopy = *addr;
00281               addrCopy.raw.family = AF_INET6;
00282               addrp = &addrCopy;
00283        }
00284 #endif
00285 
00286        rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
00287        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
00288        if (rv == 0)
00289               return PR_SUCCESS;
00290        else
00291               return PR_FAILURE;
00292 }
00293 
00294 static PRStatus PR_CALLBACK SocketConnectContinue(
00295     PRFileDesc *fd, PRInt16 out_flags)
00296 {
00297     PRInt32 osfd;
00298     int err;
00299 
00300     if (out_flags & PR_POLL_NVAL) {
00301         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
00302         return PR_FAILURE;
00303     }
00304     if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
00305         PR_ASSERT(out_flags == 0);
00306         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
00307         return PR_FAILURE;
00308     }
00309 
00310     osfd = fd->secret->md.osfd;
00311 
00312 #if defined(XP_UNIX)
00313 
00314     err = _MD_unix_get_nonblocking_connect_error(osfd);
00315     if (err != 0) {
00316         _PR_MD_MAP_CONNECT_ERROR(err);
00317         return PR_FAILURE;
00318     }
00319     return PR_SUCCESS;
00320 
00321 #elif defined(WIN32) || defined(WIN16)
00322 
00323 #if defined(WIN32)
00324     /*
00325      * The sleep circumvents a bug in Win32 WinSock.
00326      * See Microsoft Knowledge Base article ID: Q165989.
00327      */
00328     Sleep(0);
00329 #endif /* WIN32 */
00330 
00331     if (out_flags & PR_POLL_EXCEPT) {
00332         int len = sizeof(err);
00333         if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
00334                 == SOCKET_ERROR) {
00335             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
00336             return PR_FAILURE;
00337         }
00338         if (err != 0) {
00339             _PR_MD_MAP_CONNECT_ERROR(err);
00340         } else {
00341             PR_SetError(PR_UNKNOWN_ERROR, 0);
00342         }
00343         return PR_FAILURE;
00344     }
00345 
00346     PR_ASSERT(out_flags & PR_POLL_WRITE);
00347     return PR_SUCCESS;
00348 
00349 #elif defined(XP_OS2)
00350 
00351     err = _MD_os2_get_nonblocking_connect_error(osfd);
00352     if (err != 0) {
00353         _PR_MD_MAP_CONNECT_ERROR(err);
00354         return PR_FAILURE;
00355     }
00356     return PR_SUCCESS;
00357 
00358 #elif defined(XP_MAC)
00359 
00360     err = _MD_mac_get_nonblocking_connect_error(fd);
00361     if (err == -1)
00362         return PR_FAILURE;
00363        else     
00364               return PR_SUCCESS;
00365 
00366 #elif defined(XP_BEOS)
00367 
00368 #ifdef BONE_VERSION  /* bug 122364 */
00369     /* temporary workaround until getsockopt(SO_ERROR) works in BONE */
00370     if (out_flags & PR_POLL_EXCEPT) {
00371         PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
00372         return PR_FAILURE;
00373     }
00374     PR_ASSERT(out_flags & PR_POLL_WRITE);
00375     return PR_SUCCESS;
00376 #else
00377     err = _MD_beos_get_nonblocking_connect_error(fd);
00378     if( err != 0 ) {
00379         _PR_MD_MAP_CONNECT_ERROR(err);
00380         return PR_FAILURE;
00381     }
00382     else
00383         return PR_SUCCESS;
00384 #endif /* BONE_VERSION */
00385 
00386 #else
00387     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00388     return PR_FAILURE;
00389 #endif
00390 }
00391 
00392 PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
00393 {
00394     /* Find the NSPR layer and invoke its connectcontinue method */
00395     PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
00396 
00397     if (NULL == bottom) {
00398         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00399         return PR_FAILURE;
00400     }
00401     return SocketConnectContinue(bottom, pd->out_flags);
00402 }
00403 
00404 static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
00405 PRIntervalTime timeout)
00406 {
00407        PRInt32 osfd;
00408        PRFileDesc *fd2;
00409        PRUint32 al;
00410        PRThread *me = _PR_MD_CURRENT_THREAD();
00411 #ifdef WINNT
00412        PRNetAddr addrCopy;
00413 #endif
00414 
00415        if (_PR_PENDING_INTERRUPT(me)) {
00416               me->flags &= ~_PR_INTERRUPT;
00417               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00418               return 0;
00419        }
00420        if (_PR_IO_PENDING(me)) {
00421               PR_SetError(PR_IO_PENDING_ERROR, 0);
00422               return 0;
00423        }
00424 
00425 #ifdef WINNT
00426        if (addr == NULL) {
00427               addr = &addrCopy;
00428        }
00429 #endif
00430        al = sizeof(PRNetAddr);
00431        osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
00432        if (osfd == -1)
00433               return 0;
00434 
00435        fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
00436        if (!fd2) {
00437               _PR_MD_CLOSE_SOCKET(osfd);
00438               return NULL;
00439        }
00440 
00441        fd2->secret->nonblocking = fd->secret->nonblocking;
00442        fd2->secret->inheritable = fd->secret->inheritable;
00443 #ifdef WINNT
00444        if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
00445               /*
00446                * The new socket has been associated with an I/O
00447                * completion port.  There is no going back.
00448                */
00449               fd2->secret->md.io_model_committed = PR_TRUE;
00450        }
00451        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
00452        fd2->secret->md.accepted_socket = PR_TRUE;
00453        memcpy(&fd2->secret->md.peer_addr, addr, al);
00454 #endif
00455 
00456        /*
00457         * On some platforms, the new socket created by accept()
00458         * inherits the nonblocking (or overlapped io) attribute
00459         * of the listening socket.  As an optimization, these
00460         * platforms can skip the following _PR_MD_MAKE_NONBLOCK
00461         * call.
00462         * 
00463         * On Mac, we MUST make this call, because _PR_MD_MAKE_NONBLOCK
00464         * (which maps to _MD_makenonblock, see macsockotpt.c)
00465         * installs the async notifier routine needed to make blocking
00466         * I/O work properly.
00467         */
00468 #if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
00469        _PR_MD_MAKE_NONBLOCK(fd2);
00470 #endif
00471 
00472 #ifdef _PR_INET6
00473        if (addr && (AF_INET6 == addr->raw.family))
00474         addr->raw.family = PR_AF_INET6;
00475 #endif
00476        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
00477        PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
00478 
00479        return fd2;
00480 }
00481 
00482 #ifdef WINNT
00483 PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
00484 PRIntervalTime timeout)
00485 {
00486        PRInt32 osfd;
00487        PRFileDesc *fd2;
00488        PRIntn al;
00489        PRThread *me = _PR_MD_CURRENT_THREAD();
00490        PRNetAddr addrCopy;
00491 
00492        if (_PR_PENDING_INTERRUPT(me)) {
00493               me->flags &= ~_PR_INTERRUPT;
00494               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00495               return 0;
00496        }
00497        if (_PR_IO_PENDING(me)) {
00498               PR_SetError(PR_IO_PENDING_ERROR, 0);
00499               return 0;
00500        }
00501 
00502               if (addr == NULL) {
00503                      addr = &addrCopy;
00504               }
00505               al = PR_NETADDR_SIZE(addr);
00506               osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
00507               if (osfd == -1) {
00508                      return 0;
00509               }
00510 
00511        fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
00512        if (!fd2) {
00513               _PR_MD_CLOSE_SOCKET(osfd);
00514        } else {
00515               fd2->secret->nonblocking = fd->secret->nonblocking;
00516               fd2->secret->md.io_model_committed = PR_TRUE;
00517                PR_ASSERT(al == PR_NETADDR_SIZE(addr));
00518               fd2->secret->md.accepted_socket = PR_TRUE;
00519               memcpy(&fd2->secret->md.peer_addr, addr, al);
00520 #ifdef _PR_INET6
00521               if (AF_INET6 == addr->raw.family)
00522               addr->raw.family = PR_AF_INET6;
00523 #endif
00524 #ifdef _PR_NEED_SECRET_AF
00525               fd2->secret->af = fd->secret->af;
00526 #endif
00527        }
00528        return fd2;
00529 }
00530 #endif /* WINNT */
00531 
00532 
00533 static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
00534 {
00535        PRInt32 result;
00536     const PRNetAddr *addrp = addr;
00537 #if defined(_PR_INET6)
00538        PRNetAddr addrCopy;
00539 #endif
00540 
00541        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
00542 
00543 #ifdef XP_UNIX
00544        if (addr->raw.family == AF_UNIX) {
00545               /* Disallow relative pathnames */
00546               if (addr->local.path[0] != '/') {
00547                      PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00548                      return PR_FAILURE;
00549               }
00550        }
00551 #endif /* XP_UNIX */
00552 
00553 #if defined(_PR_INET6)
00554        if (addr->raw.family == PR_AF_INET6) {
00555               addrCopy = *addr;
00556               addrCopy.raw.family = AF_INET6;
00557               addrp = &addrCopy;
00558        }
00559 #endif
00560        result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
00561        if (result < 0) {
00562               return PR_FAILURE;
00563        }
00564        return PR_SUCCESS;
00565 }
00566 
00567 static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
00568 {
00569        PRInt32 result;
00570 
00571        result = _PR_MD_LISTEN(fd, backlog);
00572        if (result < 0) {
00573               return PR_FAILURE;
00574        }
00575        return PR_SUCCESS;
00576 }
00577 
00578 static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
00579 {
00580        PRInt32 result;
00581 
00582        result = _PR_MD_SHUTDOWN(fd, how);
00583        if (result < 0) {
00584               return PR_FAILURE;
00585        }
00586        return PR_SUCCESS;
00587 }
00588 
00589 static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
00590 PRIntervalTime timeout)
00591 {
00592        PRInt32 rv;
00593        PRThread *me = _PR_MD_CURRENT_THREAD();
00594 
00595        if ((flags != 0) && (flags != PR_MSG_PEEK)) {
00596               PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00597               return -1;
00598        }
00599        if (_PR_PENDING_INTERRUPT(me)) {
00600               me->flags &= ~_PR_INTERRUPT;
00601               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00602               return -1;
00603        }
00604        if (_PR_IO_PENDING(me)) {
00605               PR_SetError(PR_IO_PENDING_ERROR, 0);
00606               return -1;
00607        }
00608 
00609        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d flags=%d",
00610                                                         fd, fd->secret->md.osfd, buf, amount, flags));
00611 
00612 #ifdef _PR_HAVE_PEEK_BUFFER
00613        if (fd->secret->peekBytes != 0) {
00614               rv = (amount < fd->secret->peekBytes) ?
00615                      amount : fd->secret->peekBytes;
00616               memcpy(buf, fd->secret->peekBuffer, rv);
00617               if (flags == 0) {
00618                      /* consume the bytes in the peek buffer */
00619                      fd->secret->peekBytes -= rv;
00620                      if (fd->secret->peekBytes != 0) {
00621                             memmove(fd->secret->peekBuffer,
00622                                    fd->secret->peekBuffer + rv,
00623                                    fd->secret->peekBytes);
00624                      }
00625               }
00626               return rv;
00627        }
00628 
00629        /* allocate peek buffer, if necessary */
00630        if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
00631               PR_ASSERT(0 == fd->secret->peekBytes);
00632               /* impose a max size on the peek buffer */
00633               if (amount > _PR_PEEK_BUFFER_MAX) {
00634                      amount = _PR_PEEK_BUFFER_MAX;
00635               }
00636               if (fd->secret->peekBufSize < amount) {
00637                      if (fd->secret->peekBuffer) {
00638                             PR_Free(fd->secret->peekBuffer);
00639                      }
00640                      fd->secret->peekBufSize = amount;
00641                      fd->secret->peekBuffer = PR_Malloc(amount);
00642                      if (NULL == fd->secret->peekBuffer) {
00643                             fd->secret->peekBufSize = 0;
00644                             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00645                             return -1;
00646                      }
00647               }
00648        }
00649 #endif
00650 
00651        rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
00652        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
00653               rv, PR_GetError(), PR_GetOSError()));
00654 
00655 #ifdef _PR_HAVE_PEEK_BUFFER
00656        if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
00657               if (rv > 0) {
00658                      memcpy(fd->secret->peekBuffer, buf, rv);
00659                      fd->secret->peekBytes = rv;
00660               }
00661        }
00662 #endif
00663 
00664        return rv;
00665 }
00666 
00667 static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
00668 {
00669        return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
00670 }
00671 
00672 static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
00673 PRIntn flags, PRIntervalTime timeout)
00674 {
00675        PRInt32 temp, count;
00676        PRThread *me = _PR_MD_CURRENT_THREAD();
00677 
00678        if (_PR_PENDING_INTERRUPT(me)) {
00679               me->flags &= ~_PR_INTERRUPT;
00680               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00681               return -1;
00682        }
00683        if (_PR_IO_PENDING(me)) {
00684               PR_SetError(PR_IO_PENDING_ERROR, 0);
00685               return -1;
00686        }
00687 
00688        count = 0;
00689        while (amount > 0) {
00690               PR_LOG(_pr_io_lm, PR_LOG_MAX,
00691                   ("send: fd=%p osfd=%d buf=%p amount=%d",
00692                   fd, fd->secret->md.osfd, buf, amount));
00693               temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
00694               if (temp < 0) {
00695                                    count = -1;
00696                                    break;
00697                             }
00698 
00699               count += temp;
00700               if (fd->secret->nonblocking) {
00701                      break;
00702               }
00703               buf = (const void*) ((const char*)buf + temp);
00704 
00705               amount -= temp;
00706        }
00707        PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
00708        return count;
00709 }
00710 
00711 static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
00712 {
00713        return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
00714 }
00715 
00716 static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
00717 {
00718        if (!fd || !fd->secret
00719                      || (fd->secret->state != _PR_FILEDESC_OPEN
00720                      && fd->secret->state != _PR_FILEDESC_CLOSED)) {
00721               PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
00722               return PR_FAILURE;
00723        }
00724 
00725        if (fd->secret->state == _PR_FILEDESC_OPEN) {
00726               if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
00727                      return PR_FAILURE;
00728               }
00729               fd->secret->state = _PR_FILEDESC_CLOSED;
00730        }
00731 
00732 #ifdef _PR_HAVE_PEEK_BUFFER
00733        if (fd->secret->peekBuffer) {
00734               PR_ASSERT(fd->secret->peekBufSize > 0);
00735               PR_DELETE(fd->secret->peekBuffer);
00736               fd->secret->peekBufSize = 0;
00737               fd->secret->peekBytes = 0;
00738        }
00739 #endif
00740 
00741        PR_FreeFileDesc(fd);
00742        return PR_SUCCESS;
00743 }
00744 
00745 static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
00746 {
00747        PRInt32 rv;
00748 #ifdef _PR_HAVE_PEEK_BUFFER
00749        if (fd->secret->peekBytes != 0) {
00750               return fd->secret->peekBytes;
00751        }
00752 #endif
00753        rv =  _PR_MD_SOCKETAVAILABLE(fd);
00754        return rv;           
00755 }
00756 
00757 static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
00758 {
00759     PRInt64 rv;
00760 #ifdef _PR_HAVE_PEEK_BUFFER
00761     if (fd->secret->peekBytes != 0) {
00762         LL_I2L(rv, fd->secret->peekBytes);
00763         return rv;
00764     }
00765 #endif
00766     LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
00767        return rv;           
00768 }
00769 
00770 static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
00771 {
00772 #if defined(XP_MAC)
00773 #pragma unused (fd)
00774 #endif
00775 
00776        return PR_SUCCESS;
00777 }
00778 
00779 static PRInt32 PR_CALLBACK SocketSendTo(
00780     PRFileDesc *fd, const void *buf, PRInt32 amount,
00781     PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
00782 {
00783        PRInt32 temp, count;
00784     const PRNetAddr *addrp = addr;
00785 #if defined(_PR_INET6)
00786        PRNetAddr addrCopy;
00787 #endif
00788        PRThread *me = _PR_MD_CURRENT_THREAD();
00789 
00790        if (_PR_PENDING_INTERRUPT(me)) {
00791               me->flags &= ~_PR_INTERRUPT;
00792               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00793               return -1;
00794        }
00795        if (_PR_IO_PENDING(me)) {
00796               PR_SetError(PR_IO_PENDING_ERROR, 0);
00797               return -1;
00798        }
00799 
00800        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
00801 #if defined(_PR_INET6)
00802        if (addr->raw.family == PR_AF_INET6) {
00803               addrCopy = *addr;
00804               addrCopy.raw.family = AF_INET6;
00805               addrp = &addrCopy;
00806        }
00807 #endif
00808 
00809        count = 0;
00810        while (amount > 0) {
00811               temp = _PR_MD_SENDTO(fd, buf, amount, flags,
00812                   addrp, PR_NETADDR_SIZE(addr), timeout);
00813               if (temp < 0) {
00814                                    count = -1;
00815                                    break;
00816                             }
00817               count += temp;
00818               if (fd->secret->nonblocking) {
00819                      break;
00820               }
00821               buf = (const void*) ((const char*)buf + temp);
00822               amount -= temp;
00823        }
00824        return count;
00825 }
00826 
00827 static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
00828 PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
00829 {
00830        PRInt32 rv;
00831        PRUint32 al;
00832        PRThread *me = _PR_MD_CURRENT_THREAD();
00833 
00834        if (_PR_PENDING_INTERRUPT(me)) {
00835               me->flags &= ~_PR_INTERRUPT;
00836               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00837               return -1;
00838        }
00839        if (_PR_IO_PENDING(me)) {
00840               PR_SetError(PR_IO_PENDING_ERROR, 0);
00841               return -1;
00842        }
00843 
00844        al = sizeof(PRNetAddr);
00845        rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
00846 #ifdef _PR_INET6
00847        if (addr && (AF_INET6 == addr->raw.family))
00848         addr->raw.family = PR_AF_INET6;
00849 #endif
00850        return rv;
00851 }
00852 
00853 static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
00854 PRNetAddr **raddr, void *buf, PRInt32 amount,
00855 PRIntervalTime timeout)
00856 {
00857        PRInt32 rv;
00858        PRThread *me = _PR_MD_CURRENT_THREAD();
00859 
00860        if (_PR_PENDING_INTERRUPT(me)) {
00861               me->flags &= ~_PR_INTERRUPT;
00862               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00863               return -1;
00864        }
00865        if (_PR_IO_PENDING(me)) {
00866               PR_SetError(PR_IO_PENDING_ERROR, 0);
00867               return -1;
00868        }
00869        /* The socket must be in blocking mode. */
00870        if (sd->secret->nonblocking) {
00871               PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00872               return -1;
00873        }
00874        *nd = NULL;
00875 
00876 #if defined(WINNT)
00877        {
00878        PRInt32 newSock;
00879        PRNetAddr *raddrCopy;
00880 
00881        if (raddr == NULL) {
00882               raddr = &raddrCopy;
00883        }
00884        rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
00885        if (rv < 0) {
00886               rv = -1;
00887        } else {
00888               /* Successfully accepted and read; create the new PRFileDesc */
00889               *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
00890               if (*nd == 0) {
00891                      _PR_MD_CLOSE_SOCKET(newSock);
00892                      /* PR_AllocFileDesc() has invoked PR_SetError(). */
00893                      rv = -1;
00894               } else {
00895                      (*nd)->secret->md.io_model_committed = PR_TRUE;
00896                      (*nd)->secret->md.accepted_socket = PR_TRUE;
00897                      memcpy(&(*nd)->secret->md.peer_addr, *raddr,
00898                             PR_NETADDR_SIZE(*raddr));
00899 #ifdef _PR_INET6
00900                      if (AF_INET6 == *raddr->raw.family)
00901                      *raddr->raw.family = PR_AF_INET6;
00902 #endif
00903               }
00904        }
00905        }
00906 #else
00907        rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
00908 #endif
00909        return rv;
00910 }
00911 
00912 #ifdef WINNT
00913 PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
00914 PRNetAddr **raddr, void *buf, PRInt32 amount,
00915 PRIntervalTime timeout)
00916 {
00917        PRInt32 rv;
00918        PRInt32 newSock;
00919        PRThread *me = _PR_MD_CURRENT_THREAD();
00920        PRNetAddr *raddrCopy;
00921 
00922        if (_PR_PENDING_INTERRUPT(me)) {
00923               me->flags &= ~_PR_INTERRUPT;
00924               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00925               return -1;
00926        }
00927        if (_PR_IO_PENDING(me)) {
00928               PR_SetError(PR_IO_PENDING_ERROR, 0);
00929               return -1;
00930        }
00931        *nd = NULL;
00932 
00933        if (raddr == NULL) {
00934               raddr = &raddrCopy;
00935        }
00936        rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
00937            timeout, PR_TRUE, NULL, NULL);
00938        if (rv < 0) {
00939               rv = -1;
00940        } else {
00941               /* Successfully accepted and read; create the new PRFileDesc */
00942               *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
00943               if (*nd == 0) {
00944                      _PR_MD_CLOSE_SOCKET(newSock);
00945                      /* PR_AllocFileDesc() has invoked PR_SetError(). */
00946                      rv = -1;
00947               } else {
00948                      (*nd)->secret->md.io_model_committed = PR_TRUE;
00949                      (*nd)->secret->md.accepted_socket = PR_TRUE;
00950                      memcpy(&(*nd)->secret->md.peer_addr, *raddr,
00951                             PR_NETADDR_SIZE(*raddr));
00952 #ifdef _PR_INET6
00953                      if (AF_INET6 == *raddr->raw.family)
00954                      *raddr->raw.family = PR_AF_INET6;
00955 #endif
00956 #ifdef _PR_NEED_SECRET_AF
00957                      (*nd)->secret->af = sd->secret->af;
00958 #endif
00959               }
00960        }
00961        return rv;
00962 }
00963 
00964 PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
00965 PRFileDesc *sd, PRFileDesc **nd, 
00966 PRNetAddr **raddr, void *buf, PRInt32 amount,
00967 PRIntervalTime timeout,
00968 _PR_AcceptTimeoutCallback callback,
00969 void *callbackArg)
00970 {
00971        PRInt32 rv;
00972        PRInt32 newSock;
00973        PRThread *me = _PR_MD_CURRENT_THREAD();
00974        PRNetAddr *raddrCopy;
00975 
00976        if (_PR_PENDING_INTERRUPT(me)) {
00977               me->flags &= ~_PR_INTERRUPT;
00978               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00979               return -1;
00980        }
00981        if (_PR_IO_PENDING(me)) {
00982               PR_SetError(PR_IO_PENDING_ERROR, 0);
00983               return -1;
00984        }
00985        *nd = NULL;
00986 
00987        if (raddr == NULL) {
00988               raddr = &raddrCopy;
00989        }
00990        rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
00991            timeout, PR_TRUE, callback, callbackArg);
00992        if (rv < 0) {
00993               rv = -1;
00994        } else {
00995               /* Successfully accepted and read; create the new PRFileDesc */
00996               *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
00997               if (*nd == 0) {
00998                      _PR_MD_CLOSE_SOCKET(newSock);
00999                      /* PR_AllocFileDesc() has invoked PR_SetError(). */
01000                      rv = -1;
01001               } else {
01002                      (*nd)->secret->md.io_model_committed = PR_TRUE;
01003                      (*nd)->secret->md.accepted_socket = PR_TRUE;
01004                      memcpy(&(*nd)->secret->md.peer_addr, *raddr,
01005                             PR_NETADDR_SIZE(*raddr));
01006 #ifdef _PR_INET6
01007                      if (AF_INET6 == *raddr->raw.family)
01008                      *raddr->raw.family = PR_AF_INET6;
01009 #endif
01010 #ifdef _PR_NEED_SECRET_AF
01011                      (*nd)->secret->af = sd->secret->af;
01012 #endif
01013               }
01014        }
01015        return rv;
01016 }
01017 #endif /* WINNT */
01018 
01019 #ifdef WINNT
01020 PR_IMPLEMENT(void)
01021 PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
01022 {
01023        _PR_MD_UPDATE_ACCEPT_CONTEXT(
01024               socket->secret->md.osfd, acceptSocket->secret->md.osfd);
01025 }
01026 #endif /* WINNT */
01027 
01028 static PRInt32 PR_CALLBACK SocketSendFile(
01029     PRFileDesc *sd, PRSendFileData *sfd,
01030     PRTransmitFileFlags flags, PRIntervalTime timeout)
01031 {
01032        PRInt32 rv;
01033        PRThread *me = _PR_MD_CURRENT_THREAD();
01034 
01035        if (_PR_PENDING_INTERRUPT(me)) {
01036               me->flags &= ~_PR_INTERRUPT;
01037               PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
01038               return -1;
01039        }
01040        if (_PR_IO_PENDING(me)) {
01041               PR_SetError(PR_IO_PENDING_ERROR, 0);
01042               return -1;
01043        }
01044        /* The socket must be in blocking mode. */
01045        if (sd->secret->nonblocking) {
01046               PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01047               return -1;
01048        }
01049 #if defined(WINNT)
01050        rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
01051        if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
01052               /*
01053                * This should be kept the same as SocketClose, except
01054                * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
01055                * not be called because the socket will be recycled.
01056                */
01057               PR_FreeFileDesc(sd);
01058        }
01059 #else
01060        rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
01061 #endif /* WINNT */
01062 
01063        return rv;
01064 }
01065 
01066 static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
01067 const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
01068 PRIntervalTime timeout)
01069 {
01070        PRSendFileData sfd;
01071 
01072        sfd.fd = fd;
01073        sfd.file_offset = 0;
01074        sfd.file_nbytes = 0;
01075        sfd.header = headers;
01076        sfd.hlen = hlen;
01077        sfd.trailer = NULL;
01078        sfd.tlen = 0;
01079 
01080        return(SocketSendFile(sd, &sfd, flags, timeout));
01081 }
01082 
01083 static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
01084 {
01085        PRInt32 result;
01086        PRUint32 addrlen;
01087 
01088        addrlen = sizeof(PRNetAddr);
01089        result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
01090        if (result < 0) {
01091               return PR_FAILURE;
01092        }
01093 #ifdef _PR_INET6
01094        if (AF_INET6 == addr->raw.family)
01095         addr->raw.family = PR_AF_INET6;
01096 #endif
01097        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01098        PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
01099        return PR_SUCCESS;
01100 }
01101 
01102 static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
01103 {
01104        PRInt32 result;
01105        PRUint32 addrlen;
01106 
01107        addrlen = sizeof(PRNetAddr);
01108        result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
01109        if (result < 0) {
01110               return PR_FAILURE;
01111        }
01112 #ifdef _PR_INET6
01113        if (AF_INET6 == addr->raw.family)
01114         addr->raw.family = PR_AF_INET6;
01115 #endif
01116        PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
01117        PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
01118        return PR_SUCCESS;
01119 }
01120 
01121 static PRInt16 PR_CALLBACK SocketPoll(
01122     PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
01123 {
01124 #ifdef XP_MAC
01125 #pragma unused( fd, in_flags )
01126 #endif
01127     *out_flags = 0;
01128     return in_flags;
01129 }  /* SocketPoll */
01130 
01131 static PRIOMethods tcpMethods = {
01132        PR_DESC_SOCKET_TCP,
01133        SocketClose,
01134        SocketRead,
01135        SocketWrite,
01136        SocketAvailable,
01137        SocketAvailable64,
01138        SocketSync,
01139        (PRSeekFN)_PR_InvalidInt,
01140        (PRSeek64FN)_PR_InvalidInt64,
01141        (PRFileInfoFN)_PR_InvalidStatus,
01142        (PRFileInfo64FN)_PR_InvalidStatus,
01143        SocketWritev,
01144        SocketConnect,
01145        SocketAccept,
01146        SocketBind,
01147        SocketListen,
01148        SocketShutdown,
01149        SocketRecv,
01150        SocketSend,
01151        (PRRecvfromFN)_PR_InvalidInt,
01152        (PRSendtoFN)_PR_InvalidInt,
01153        SocketPoll,
01154        SocketAcceptRead,
01155        SocketTransmitFile,
01156        SocketGetName,
01157        SocketGetPeerName,
01158        (PRReservedFN)_PR_InvalidInt,
01159        (PRReservedFN)_PR_InvalidInt,
01160        _PR_SocketGetSocketOption,
01161        _PR_SocketSetSocketOption,
01162     SocketSendFile, 
01163     SocketConnectContinue,
01164     (PRReservedFN)_PR_InvalidInt, 
01165     (PRReservedFN)_PR_InvalidInt, 
01166     (PRReservedFN)_PR_InvalidInt, 
01167     (PRReservedFN)_PR_InvalidInt
01168 };
01169 
01170 static PRIOMethods udpMethods = {
01171        PR_DESC_SOCKET_UDP,
01172        SocketClose,
01173        SocketRead,
01174        SocketWrite,
01175        SocketAvailable,
01176        SocketAvailable64,
01177        SocketSync,
01178        (PRSeekFN)_PR_InvalidInt,
01179        (PRSeek64FN)_PR_InvalidInt64,
01180        (PRFileInfoFN)_PR_InvalidStatus,
01181        (PRFileInfo64FN)_PR_InvalidStatus,
01182        SocketWritev,
01183        SocketConnect,
01184        (PRAcceptFN)_PR_InvalidDesc,
01185        SocketBind,
01186        SocketListen,
01187        SocketShutdown,
01188        SocketRecv,
01189        SocketSend,
01190        SocketRecvFrom,
01191        SocketSendTo,
01192        SocketPoll,
01193        (PRAcceptreadFN)_PR_InvalidInt,
01194        (PRTransmitfileFN)_PR_InvalidInt,
01195        SocketGetName,
01196        SocketGetPeerName,
01197        (PRReservedFN)_PR_InvalidInt,
01198        (PRReservedFN)_PR_InvalidInt,
01199        _PR_SocketGetSocketOption,
01200        _PR_SocketSetSocketOption,
01201     (PRSendfileFN)_PR_InvalidInt, 
01202     (PRConnectcontinueFN)_PR_InvalidStatus, 
01203     (PRReservedFN)_PR_InvalidInt, 
01204     (PRReservedFN)_PR_InvalidInt, 
01205     (PRReservedFN)_PR_InvalidInt, 
01206     (PRReservedFN)_PR_InvalidInt
01207 };
01208 
01209 
01210 static PRIOMethods socketpollfdMethods = {
01211     (PRDescType) 0,
01212     (PRCloseFN)_PR_InvalidStatus,
01213     (PRReadFN)_PR_InvalidInt,
01214     (PRWriteFN)_PR_InvalidInt,
01215     (PRAvailableFN)_PR_InvalidInt,
01216     (PRAvailable64FN)_PR_InvalidInt64,
01217     (PRFsyncFN)_PR_InvalidStatus,
01218     (PRSeekFN)_PR_InvalidInt,
01219     (PRSeek64FN)_PR_InvalidInt64,
01220     (PRFileInfoFN)_PR_InvalidStatus,
01221     (PRFileInfo64FN)_PR_InvalidStatus,
01222     (PRWritevFN)_PR_InvalidInt,        
01223     (PRConnectFN)_PR_InvalidStatus,        
01224     (PRAcceptFN)_PR_InvalidDesc,        
01225     (PRBindFN)_PR_InvalidStatus,        
01226     (PRListenFN)_PR_InvalidStatus,        
01227     (PRShutdownFN)_PR_InvalidStatus,    
01228     (PRRecvFN)_PR_InvalidInt,        
01229     (PRSendFN)_PR_InvalidInt,        
01230     (PRRecvfromFN)_PR_InvalidInt,    
01231     (PRSendtoFN)_PR_InvalidInt,        
01232        SocketPoll,
01233     (PRAcceptreadFN)_PR_InvalidInt,   
01234     (PRTransmitfileFN)_PR_InvalidInt, 
01235     (PRGetsocknameFN)_PR_InvalidStatus,    
01236     (PRGetpeernameFN)_PR_InvalidStatus,    
01237     (PRReservedFN)_PR_InvalidInt,    
01238     (PRReservedFN)_PR_InvalidInt,    
01239     (PRGetsocketoptionFN)_PR_InvalidStatus,
01240     (PRSetsocketoptionFN)_PR_InvalidStatus,
01241     (PRSendfileFN)_PR_InvalidInt, 
01242     (PRConnectcontinueFN)_PR_InvalidStatus, 
01243     (PRReservedFN)_PR_InvalidInt, 
01244     (PRReservedFN)_PR_InvalidInt, 
01245     (PRReservedFN)_PR_InvalidInt, 
01246     (PRReservedFN)_PR_InvalidInt
01247 };
01248 
01249 PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
01250 {
01251        return &tcpMethods;
01252 }
01253 
01254 PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
01255 {
01256        return &udpMethods;
01257 }
01258 
01259 static const PRIOMethods* PR_GetSocketPollFdMethods()
01260 {
01261     return &socketpollfdMethods;
01262 }  /* PR_GetSocketPollFdMethods */
01263 
01264 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
01265 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
01266 
01267 #if defined(_PR_INET6_PROBE)
01268 
01269 PR_EXTERN(PRBool) _pr_ipv6_is_present;
01270 
01271 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
01272 {
01273 PRInt32 osfd;
01274 
01275        osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
01276        if (osfd != -1) {
01277               _PR_MD_CLOSE_SOCKET(osfd);
01278               return PR_TRUE;
01279        }
01280        return PR_FALSE;
01281 }
01282 #endif /* _PR_INET6_PROBE */
01283 
01284 #endif
01285 
01286 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
01287 {
01288        PRInt32 osfd;
01289        PRFileDesc *fd;
01290        PRInt32 tmp_domain = domain;
01291 
01292        if (!_pr_initialized) _PR_ImplicitInitialization();
01293        if (PR_AF_INET != domain
01294                      && PR_AF_INET6 != domain
01295 #if defined(XP_UNIX) || defined(XP_OS2_EMX)
01296                      && PR_AF_LOCAL != domain
01297 #endif
01298                      ) {
01299               PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
01300               return NULL;
01301        }
01302 
01303 #if defined(_PR_INET6_PROBE)
01304        if (PR_AF_INET6 == domain) {
01305               if (_pr_ipv6_is_present == PR_FALSE) 
01306                      domain = AF_INET;
01307               else
01308                      domain = AF_INET6;
01309        }
01310 #elif defined(_PR_INET6)
01311        if (PR_AF_INET6 == domain)
01312               domain = AF_INET6;
01313 #else
01314        if (PR_AF_INET6 == domain)
01315               domain = AF_INET;
01316 #endif /* _PR_INET6 */
01317        osfd = _PR_MD_SOCKET(domain, type, proto);
01318        if (osfd == -1) {
01319               return 0;
01320        }
01321        if (type == SOCK_STREAM)
01322               fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
01323        else
01324               fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
01325        /*
01326         * Make the sockets non-blocking
01327         */
01328        if (fd != NULL) {
01329               _PR_MD_MAKE_NONBLOCK(fd);
01330               _PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
01331 #ifdef _PR_NEED_SECRET_AF
01332               fd->secret->af = domain;
01333 #endif
01334 #if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
01335               /*
01336                * For platforms with no support for IPv6 
01337                * create layered socket for IPv4-mapped IPv6 addresses
01338                */
01339               if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
01340                      if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
01341                             PR_Close(fd);
01342                             fd = NULL;
01343                      }
01344               }
01345 #endif
01346        } else
01347               _PR_MD_CLOSE_SOCKET(osfd);
01348 
01349        return fd;
01350 }
01351 
01352 PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
01353 {
01354        PRInt32 domain = AF_INET;
01355 
01356        return PR_Socket(domain, SOCK_STREAM, 0);
01357 }
01358 
01359 PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
01360 {
01361        PRInt32 domain = AF_INET;
01362 
01363        return PR_Socket(domain, SOCK_DGRAM, 0);
01364 }
01365 
01366 PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
01367 {
01368        return PR_Socket(af, SOCK_STREAM, 0);
01369 }
01370 
01371 PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
01372 {
01373        return PR_Socket(af, SOCK_DGRAM, 0);
01374 }
01375 
01376 PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
01377 {
01378 #ifdef XP_UNIX
01379        PRInt32 rv, osfd[2];
01380 
01381        if (!_pr_initialized) _PR_ImplicitInitialization();
01382 
01383        rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
01384        if (rv == -1) {
01385               return PR_FAILURE;
01386        }
01387 
01388        f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
01389        if (!f[0]) {
01390               _PR_MD_CLOSE_SOCKET(osfd[0]);
01391               _PR_MD_CLOSE_SOCKET(osfd[1]);
01392               /* PR_AllocFileDesc() has invoked PR_SetError(). */
01393               return PR_FAILURE;
01394        }
01395        f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
01396        if (!f[1]) {
01397               PR_Close(f[0]);
01398               _PR_MD_CLOSE_SOCKET(osfd[1]);
01399               /* PR_AllocFileDesc() has invoked PR_SetError(). */
01400               return PR_FAILURE;
01401        }
01402        _PR_MD_MAKE_NONBLOCK(f[0]);
01403        _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
01404        _PR_MD_MAKE_NONBLOCK(f[1]);
01405        _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
01406        return PR_SUCCESS;
01407 #elif defined(WINNT)
01408     /*
01409      * A socket pair is often used for interprocess communication,
01410      * so we need to make sure neither socket is associated with
01411      * the I/O completion port; otherwise it can't be used by a
01412      * child process.
01413      *
01414      * The default implementation below cannot be used for NT
01415      * because PR_Accept would have associated the I/O completion
01416      * port with the listening and accepted sockets.
01417      */
01418     SOCKET listenSock;
01419     SOCKET osfd[2];
01420     struct sockaddr_in selfAddr, peerAddr;
01421     int addrLen;
01422 
01423     if (!_pr_initialized) _PR_ImplicitInitialization();
01424 
01425     osfd[0] = osfd[1] = INVALID_SOCKET;
01426     listenSock = socket(AF_INET, SOCK_STREAM, 0);
01427     if (listenSock == INVALID_SOCKET) {
01428         goto failed;
01429     }
01430     selfAddr.sin_family = AF_INET;
01431     selfAddr.sin_port = 0;
01432     selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
01433     addrLen = sizeof(selfAddr);
01434     if (bind(listenSock, (struct sockaddr *) &selfAddr,
01435             addrLen) == SOCKET_ERROR) {
01436         goto failed;
01437     }
01438     if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
01439             &addrLen) == SOCKET_ERROR) {
01440         goto failed;
01441     }
01442     if (listen(listenSock, 5) == SOCKET_ERROR) {
01443         goto failed;
01444     }
01445     osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
01446     if (osfd[0] == INVALID_SOCKET) {
01447         goto failed;
01448     }
01449     selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
01450 
01451     /*
01452      * Only a thread is used to do the connect and accept.
01453      * I am relying on the fact that connect returns
01454      * successfully as soon as the connect request is put
01455      * into the listen queue (but before accept is called).
01456      * This is the behavior of the BSD socket code.  If
01457      * connect does not return until accept is called, we
01458      * will need to create another thread to call connect.
01459      */
01460     if (connect(osfd[0], (struct sockaddr *) &selfAddr,
01461             addrLen) == SOCKET_ERROR) {
01462         goto failed;
01463     }
01464     /*
01465      * A malicious local process may connect to the listening
01466      * socket, so we need to verify that the accepted connection
01467      * is made from our own socket osfd[0].
01468      */
01469     if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
01470             &addrLen) == SOCKET_ERROR) {
01471         goto failed;
01472     }
01473     osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
01474     if (osfd[1] == INVALID_SOCKET) {
01475         goto failed;
01476     }
01477     if (peerAddr.sin_port != selfAddr.sin_port) {
01478         /* the connection we accepted is not from osfd[0] */
01479         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01480         goto failed;
01481     }
01482     closesocket(listenSock);
01483 
01484     f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
01485     if (!f[0]) {
01486         closesocket(osfd[0]);
01487         closesocket(osfd[1]);
01488         /* PR_AllocFileDesc() has invoked PR_SetError(). */
01489         return PR_FAILURE;
01490     }
01491     f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
01492     if (!f[1]) {
01493         PR_Close(f[0]);
01494         closesocket(osfd[1]);
01495         /* PR_AllocFileDesc() has invoked PR_SetError(). */
01496         return PR_FAILURE;
01497     }
01498     _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
01499     _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
01500     return PR_SUCCESS;
01501 
01502 failed:
01503     if (listenSock != INVALID_SOCKET) {
01504         closesocket(listenSock);
01505     }
01506     if (osfd[0] != INVALID_SOCKET) {
01507         closesocket(osfd[0]);
01508     }
01509     if (osfd[1] != INVALID_SOCKET) {
01510         closesocket(osfd[1]);
01511     }
01512     return PR_FAILURE;
01513 #else /* not Unix or NT */
01514     /*
01515      * default implementation
01516      */
01517     PRFileDesc *listenSock;
01518     PRNetAddr selfAddr, peerAddr;
01519     PRUint16 port;
01520 
01521     f[0] = f[1] = NULL;
01522     listenSock = PR_NewTCPSocket();
01523     if (listenSock == NULL) {
01524         goto failed;
01525     }
01526     PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
01527     if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
01528         goto failed;
01529     }
01530     if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
01531         goto failed;
01532     }
01533     port = ntohs(selfAddr.inet.port);
01534     if (PR_Listen(listenSock, 5) == PR_FAILURE) {
01535         goto failed;
01536     }
01537     f[0] = PR_NewTCPSocket();
01538     if (f[0] == NULL) {
01539         goto failed;
01540     }
01541 #ifdef _PR_CONNECT_DOES_NOT_BIND
01542     /*
01543      * If connect does not implicitly bind the socket (e.g., on
01544      * BeOS), we have to bind the socket so that we can get its
01545      * port with getsockname later.
01546      */
01547     PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
01548     if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
01549         goto failed;
01550     }
01551 #endif
01552     PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
01553 
01554     /*
01555      * Only a thread is used to do the connect and accept.
01556      * I am relying on the fact that PR_Connect returns
01557      * successfully as soon as the connect request is put
01558      * into the listen queue (but before PR_Accept is called).
01559      * This is the behavior of the BSD socket code.  If
01560      * connect does not return until accept is called, we
01561      * will need to create another thread to call connect.
01562      */
01563     if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
01564             == PR_FAILURE) {
01565         goto failed;
01566     }
01567     /*
01568      * A malicious local process may connect to the listening
01569      * socket, so we need to verify that the accepted connection
01570      * is made from our own socket f[0].
01571      */
01572     if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
01573         goto failed;
01574     }
01575     f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
01576     if (f[1] == NULL) {
01577         goto failed;
01578     }
01579     if (peerAddr.inet.port != selfAddr.inet.port) {
01580         /* the connection we accepted is not from f[0] */
01581         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01582         goto failed;
01583     }
01584     PR_Close(listenSock);
01585     return PR_SUCCESS;
01586 
01587 failed:
01588     if (listenSock) {
01589         PR_Close(listenSock);
01590     }
01591     if (f[0]) {
01592         PR_Close(f[0]);
01593     }
01594     if (f[1]) {
01595         PR_Close(f[1]);
01596     }
01597     return PR_FAILURE;
01598 #endif
01599 }
01600 
01601 PR_IMPLEMENT(PRInt32)
01602 PR_FileDesc2NativeHandle(PRFileDesc *fd)
01603 {
01604     if (fd) {
01605         fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
01606     }
01607     if (!fd) {
01608         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01609         return -1;
01610     }
01611     return fd->secret->md.osfd;
01612 }
01613 
01614 PR_IMPLEMENT(void)
01615 PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
01616 {
01617        if (fd)
01618               fd->secret->md.osfd = handle;
01619 }
01620 
01621 /*
01622 ** Select compatibility
01623 **
01624 */
01625 
01626 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
01627 {
01628        memset(set, 0, sizeof(PR_fd_set));
01629 }
01630 
01631 PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
01632 {
01633        PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
01634 
01635        set->harray[set->hsize++] = fh;
01636 }
01637 
01638 PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
01639 {
01640        PRUint32 index, index2;
01641 
01642        for (index = 0; index<set->hsize; index++)
01643               if (set->harray[index] == fh) {
01644                      for (index2=index; index2 < (set->hsize-1); index2++) {
01645                             set->harray[index2] = set->harray[index2+1];
01646                      }
01647                      set->hsize--;
01648                      break;
01649               }
01650 }
01651 
01652 PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
01653 {
01654        PRUint32 index;
01655        for (index = 0; index<set->hsize; index++)
01656               if (set->harray[index] == fh) {
01657                      return 1;
01658               }
01659        return 0;
01660 }
01661 
01662 PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
01663 {
01664        PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
01665 
01666        set->narray[set->nsize++] = fd;
01667 }
01668 
01669 PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
01670 {
01671        PRUint32 index, index2;
01672 
01673        for (index = 0; index<set->nsize; index++)
01674               if (set->narray[index] == fd) {
01675                      for (index2=index; index2 < (set->nsize-1); index2++) {
01676                             set->narray[index2] = set->narray[index2+1];
01677                      }
01678                      set->nsize--;
01679                      break;
01680               }
01681 }
01682 
01683 PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
01684 {
01685        PRUint32 index;
01686        for (index = 0; index<set->nsize; index++)
01687               if (set->narray[index] == fd) {
01688                      return 1;
01689               }
01690        return 0;
01691 }
01692 
01693 
01694 #if !defined(NEED_SELECT)
01695 #if !defined(XP_MAC)
01696 #include "obsolete/probslet.h"
01697 #else
01698 #include "probslet.h"
01699 #endif
01700 
01701 #define PD_INCR 20
01702 
01703 static PRPollDesc *_pr_setfd(
01704     PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
01705 {
01706     PRUintn fsidx, pdidx;
01707     PRPollDesc *poll = polldesc;
01708 
01709     if (NULL == set) return poll;
01710 
01711        /* First set the pr file handle osfds */
01712        for (fsidx = 0; fsidx < set->hsize; fsidx++)
01713        {
01714            for (pdidx = 0; 1; pdidx++)
01715         {
01716             if ((PRFileDesc*)-1 == poll[pdidx].fd)
01717             {
01718                 /* our vector is full - extend and condition it */
01719                 poll = (PRPollDesc*)PR_Realloc(
01720                     poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
01721                 if (NULL == poll) goto out_of_memory;
01722                 memset(
01723                     poll + pdidx * sizeof(PRPollDesc),
01724                     0, PD_INCR * sizeof(PRPollDesc));
01725                 poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
01726             }
01727             if ((NULL == poll[pdidx].fd)
01728             || (poll[pdidx].fd == set->harray[fsidx]))
01729             {
01730                 /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
01731                 /* either empty or prevously defined */
01732                 poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
01733                 poll[pdidx].in_flags |= flags;  /* possibly redundant */
01734                 break;
01735             }
01736         }
01737        }
01738 
01739 #if 0
01740        /* Second set the native osfds */
01741        for (fsidx = 0; fsidx < set->nsize; fsidx++)
01742        {
01743            for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
01744         {
01745             if ((PRFileDesc*)-1 == poll[pdidx].fd)
01746             {
01747                 /* our vector is full - extend and condition it */
01748                 poll = PR_Realloc(
01749                     poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
01750                 if (NULL == poll) goto out_of_memory;
01751                 memset(
01752                     poll + pdidx * sizeof(PRPollDesc),
01753                     0, PD_INCR * sizeof(PRPollDesc));
01754                 poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
01755             }
01756             if ((NULL == poll[pdidx].fd)
01757             || (poll[pdidx].fd == set->narray[fsidx]))
01758             {
01759                 /* either empty or prevously defined */
01760                 poll[pdidx].fd = set->narray[fsidx];
01761                 PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
01762                 poll[pdidx].in_flags |= flags;
01763                 break;
01764             }
01765         }
01766        }
01767 #endif /* 0 */
01768 
01769        return poll;
01770 
01771 out_of_memory:
01772     if (NULL != polldesc) PR_DELETE(polldesc);
01773     return NULL;
01774 }  /* _pr_setfd */
01775 
01776 #endif /* !defined(NEED_SELECT) */
01777 
01778 PR_IMPLEMENT(PRInt32) PR_Select(
01779     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
01780     PR_fd_set *pr_ex, PRIntervalTime timeout)
01781 {
01782 
01783 #if !defined(NEED_SELECT)
01784     PRInt32 npds = 0; 
01785     /*
01786     ** Find out how many fds are represented in the three lists.
01787     ** Then allocate a polling descriptor for the logical union
01788     ** (there can't be any overlapping) and call PR_Poll().
01789     */
01790 
01791     PRPollDesc *copy, *poll;
01792 
01793     static PRBool warning = PR_TRUE;
01794     if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
01795 
01796     /* try to get an initial guesss at how much space we need */
01797     npds = 0;
01798     if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
01799         npds = pr_rd->hsize + pr_rd->nsize;
01800     if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
01801         npds = pr_wr->hsize + pr_wr->nsize;
01802     if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
01803         npds = pr_ex->hsize + pr_ex->nsize;
01804 
01805     if (0 == npds)
01806     {
01807         PR_Sleep(timeout);
01808         return 0;
01809     }
01810 
01811     copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
01812     if (NULL == poll) goto out_of_memory;
01813     poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
01814 
01815     poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
01816     if (NULL == poll) goto out_of_memory;
01817     poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
01818     if (NULL == poll) goto out_of_memory;
01819     poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
01820     if (NULL == poll) goto out_of_memory;
01821     unused = 0;
01822     while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
01823     {
01824         ++unused;
01825     }
01826 
01827     PR_ASSERT(unused > 0);
01828     npds = PR_Poll(poll, unused, timeout);
01829 
01830     if (npds > 0)
01831     {
01832         /* Copy the results back into the fd sets */
01833         if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
01834         if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
01835         if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
01836         for (copy = &poll[unused - 1]; copy >= poll; --copy)
01837         {
01838             if (copy->out_flags & PR_POLL_NVAL)
01839             {
01840                 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
01841                 npds = -1;
01842                 break;
01843             }
01844             if (copy->out_flags & PR_POLL_READ)
01845                 if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
01846             if (copy->out_flags & PR_POLL_WRITE)
01847                 if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
01848             if (copy->out_flags & PR_POLL_EXCEPT)
01849                 if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
01850         }
01851     }
01852     PR_DELETE(poll);
01853 
01854     return npds;
01855 out_of_memory:
01856     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01857     return -1;    
01858 
01859 #endif /* !defined(NEED_SELECT) */
01860     
01861 }