home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / io / prsocket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  37.5 KB  |  1,520 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20.  
  21. #ifdef XP_UNIX
  22. #include <fcntl.h>
  23. #endif
  24. #include <string.h>
  25.  
  26. #if defined(SVR4) || defined(SUNOS4)
  27. /* To pick up FIONREAD */
  28. #include <sys/filio.h>
  29. #endif
  30.  
  31. /************************************************************************/
  32.  
  33. static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, PRIOVec *iov, PRInt32 iov_size,
  34. PRIntervalTime timeout)
  35. {
  36.     PRThread *me = _PR_MD_CURRENT_THREAD();
  37.     int w = 0;
  38.     PRIOVec *tmp_iov = NULL;
  39.     int tmp_out;
  40.     int index, iov_cnt;
  41.     int count=0, sz = 0;    /* 'count' is the return value. */
  42. #if defined(XP_UNIX)
  43.     struct timeval tv, *tvp;
  44.     fd_set wd;
  45.  
  46.     FD_ZERO(&wd);
  47.     if (timeout == PR_INTERVAL_NO_TIMEOUT)
  48.         tvp = NULL;
  49.     else if (timeout != PR_INTERVAL_NO_WAIT) {
  50.         tv.tv_sec = PR_IntervalToSeconds(timeout);
  51.         tv.tv_usec = PR_IntervalToMicroseconds(
  52.             timeout - PR_SecondsToInterval(tv.tv_sec));
  53.         tvp = &tv;
  54.     }
  55. #endif
  56.  
  57.     if (_PR_PENDING_INTERRUPT(me)) {
  58.         me->flags &= ~_PR_INTERRUPT;
  59.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  60.         return -1;
  61.     }
  62.     if (_PR_IO_PENDING(me)) {
  63.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  64.         return -1;
  65.     }
  66.  
  67.     tmp_iov = (PRIOVec *)PR_CALLOC(iov_size * sizeof(PRIOVec));
  68.     if (!tmp_iov) {
  69.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  70.         return -1;
  71.     }
  72.  
  73.     for (index=0; index<iov_size; index++) {
  74.         sz += iov[index].iov_len;
  75.         tmp_iov[index].iov_base = iov[index].iov_base;
  76.         tmp_iov[index].iov_len = iov[index].iov_len;
  77.     }
  78.     iov_cnt = iov_size;
  79.  
  80.     while (sz > 0) {
  81.  
  82.         w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
  83.         if (w < 0) {
  84.                     count = -1;
  85.                     break;
  86.         }
  87.         count += w;
  88.         if (fd->secret->nonblocking) {
  89.             break;
  90.         }
  91.         sz -= w;
  92.  
  93.         if (sz > 0) {
  94.             /* find the next unwritten vector */
  95.             for ( index = 0, tmp_out = count;
  96.                 tmp_out >= iov[index].iov_len;
  97.                 tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
  98.  
  99.  
  100.             /* fill in the first partial read */
  101.             tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
  102.             tmp_iov[0].iov_len = iov[index].iov_len - tmp_out;
  103.             index++;
  104.  
  105.             /* copy the remaining vectors */
  106.             for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
  107.                 tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
  108.                 tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
  109.             }
  110.         }
  111.     }
  112.  
  113.     if (tmp_iov)
  114.         PR_DELETE(tmp_iov);
  115.     return count;
  116. }
  117.  
  118. /************************************************************************/
  119.  
  120. PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PRInt32 osfd)
  121. {
  122. PRFileDesc *fd;
  123.  
  124.     fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
  125.     if (fd != NULL)
  126.         _PR_MD_MAKE_NONBLOCK(fd);
  127.     else
  128.         _PR_MD_CLOSE_SOCKET(osfd);
  129.     return(fd);
  130. }
  131.  
  132. PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PRInt32 osfd)
  133. {
  134. PRFileDesc *fd;
  135.  
  136.     fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
  137.     if (fd != NULL)
  138.         _PR_MD_MAKE_NONBLOCK(fd);
  139.     else
  140.         _PR_MD_CLOSE_SOCKET(osfd);
  141.     return(fd);
  142. }
  143.  
  144. static PRStatus PR_CALLBACK SocketConnect(
  145.     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  146. {
  147.     PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
  148.     PRThread *me = _PR_MD_CURRENT_THREAD();
  149.  
  150.     if (_PR_PENDING_INTERRUPT(me)) {
  151.         me->flags &= ~_PR_INTERRUPT;
  152.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  153.         return PR_FAILURE;
  154.     }
  155.  
  156.     rv = _PR_MD_CONNECT(fd, addr, PR_NETADDR_SIZE(addr), timeout);
  157.     PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
  158.     if (rv == 0)
  159.         return PR_SUCCESS;
  160.     else
  161.         return PR_FAILURE;
  162. }
  163.  
  164. PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
  165. {
  166.     PRInt32 osfd;
  167.     PRFileDesc *bottom = pd->fd;
  168.     int err, len;
  169.  
  170.     if (pd->out_flags & PR_POLL_NVAL) {
  171.         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  172.         return PR_FAILURE;
  173.     }
  174.     if ((pd->out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
  175.         PR_ASSERT(pd->out_flags == 0);
  176.         PR_SetError(PR_IN_PROGRESS_ERROR, 0);
  177.         return PR_FAILURE;
  178.     }
  179.  
  180.     while (bottom->lower != NULL) {
  181.         bottom = bottom->lower;
  182.     }
  183.     osfd = bottom->secret->md.osfd;
  184.  
  185. #if defined(XP_UNIX)
  186.  
  187.     err = _MD_unix_get_nonblocking_connect_error(osfd);
  188.     if (err != 0) {
  189.         _PR_MD_MAP_CONNECT_ERROR(err);
  190.         return PR_FAILURE;
  191.     }
  192.     return PR_SUCCESS;
  193.  
  194. #elif defined(WIN32) || defined(WIN16)
  195.  
  196.     if (pd->out_flags & PR_POLL_EXCEPT) {
  197. #if defined(WIN32)
  198. /* Note: There is a bug in Win32 WinSock. The sleep circumvents the
  199. ** bug. See wtc. /s lth.
  200. */
  201.         Sleep(0);
  202. #endif /* WIN32 */
  203.         len = sizeof(err);
  204.         if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
  205.                 == SOCKET_ERROR) {
  206.             _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
  207.             return PR_FAILURE;
  208.         }
  209.         if (err != 0) {
  210.             _PR_MD_MAP_CONNECT_ERROR(err);
  211.         } else {
  212.             PR_SetError(PR_UNKNOWN_ERROR, 0);
  213.         }
  214.         return PR_FAILURE;
  215.     }
  216.  
  217.     PR_ASSERT(pd->out_flags & PR_POLL_WRITE);
  218.     return PR_SUCCESS;
  219.  
  220. #elif defined(XP_OS2)
  221.  
  222.     if (pd->out_flags & PR_POLL_EXCEPT) {
  223.         len = sizeof(err);
  224.         if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len)
  225.                 < 0) {
  226.             _PR_MD_MAP_GETSOCKOPT_ERROR(sock_errno());
  227.             return PR_FAILURE;
  228.         }
  229.         if (err != 0) {
  230.             _PR_MD_MAP_CONNECT_ERROR(err);
  231.         } else {
  232.             PR_SetError(PR_UNKNOWN_ERROR, 0);
  233.         }
  234.         return PR_FAILURE;
  235.     }
  236.  
  237.     PR_ASSERT(pd->out_flags & PR_POLL_WRITE);
  238.     return PR_SUCCESS;
  239.  
  240. #elif defined(XP_MAC)
  241.  
  242.     err = _MD_mac_get_nonblocking_connect_error(osfd);
  243.     if (err == -1)
  244.         return PR_FAILURE;
  245.     else     
  246.         return PR_SUCCESS;
  247.  
  248. #else
  249.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  250.     return PR_FAILURE;
  251. #endif
  252. }
  253.  
  254. static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
  255. PRIntervalTime timeout)
  256. {
  257.     PRInt32 osfd;
  258.     PRFileDesc *fd2;
  259.     PRUint32 al;
  260.     PRThread *me = _PR_MD_CURRENT_THREAD();
  261. #ifdef WINNT
  262.     PRNetAddr addrCopy;
  263. #endif
  264.  
  265.     if (_PR_PENDING_INTERRUPT(me)) {
  266.         me->flags &= ~_PR_INTERRUPT;
  267.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  268.         return 0;
  269.     }
  270.     if (_PR_IO_PENDING(me)) {
  271.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  272.         return 0;
  273.     }
  274.  
  275. #ifdef WINNT
  276.     if (addr == NULL) {
  277.         addr = &addrCopy;
  278.     }
  279. #endif
  280.     al = sizeof(PRNetAddr);
  281.     osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
  282.     if (osfd == -1)
  283.         return 0;
  284.  
  285.     fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
  286.     if (!fd2) {
  287.         _PR_MD_CLOSE_SOCKET(osfd);
  288.         return NULL;
  289.     }
  290.  
  291.     fd2->secret->nonblocking = fd->secret->nonblocking;
  292. #ifdef WINNT
  293.     fd2->secret->md.io_model_committed = PR_TRUE;
  294.     PR_ASSERT(al == PR_NETADDR_SIZE(addr));
  295.     fd2->secret->md.accepted_socket = PR_TRUE;
  296.     memcpy(&fd2->secret->md.peer_addr, addr, al);
  297. #endif
  298.  
  299.     /*
  300.      * On some platforms, the new socket created by accept()
  301.      * inherits the nonblocking (or overlapped io) attribute
  302.      * of the listening socket.  As an optimization, these
  303.      * platforms can skip the following _PR_MD_MAKE_NONBLOCK
  304.      * call.
  305.      */
  306. #if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
  307.     _PR_MD_MAKE_NONBLOCK(fd2);
  308. #endif
  309.  
  310.     PR_ASSERT((NULL == addr) || (PR_NETADDR_SIZE(addr) == al));
  311. #if defined(_PR_INET6)
  312.     PR_ASSERT((NULL == addr) || (addr->raw.family == AF_INET)
  313.         || (addr->raw.family == AF_INET6));
  314. #else
  315.     PR_ASSERT((NULL == addr) || (addr->raw.family == AF_INET));
  316. #endif
  317.  
  318.     return fd2;
  319. }
  320.  
  321. #ifdef WINNT
  322. PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
  323. PRIntervalTime timeout)
  324. {
  325.     PRInt32 osfd;
  326.     PRFileDesc *fd2;
  327.     PRIntn al;
  328.     PRThread *me = _PR_MD_CURRENT_THREAD();
  329.     PRNetAddr addrCopy;
  330.  
  331.     if (_PR_PENDING_INTERRUPT(me)) {
  332.         me->flags &= ~_PR_INTERRUPT;
  333.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  334.         return 0;
  335.     }
  336.     if (_PR_IO_PENDING(me)) {
  337.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  338.         return 0;
  339.     }
  340.  
  341.         if (addr == NULL) {
  342.             addr = &addrCopy;
  343.         }
  344.         al = PR_NETADDR_SIZE(addr);
  345.         osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
  346.         if (osfd == -1) {
  347.             return 0;
  348.         }
  349.  
  350.     fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
  351.     if (!fd2) {
  352.         _PR_MD_CLOSE_SOCKET(osfd);
  353.     } else {
  354.         fd2->secret->nonblocking = fd->secret->nonblocking;
  355.         fd2->secret->md.io_model_committed = PR_TRUE;
  356.             PR_ASSERT(al == PR_NETADDR_SIZE(addr));
  357.             fd2->secret->md.accepted_socket = PR_TRUE;
  358.             memcpy(&fd2->secret->md.peer_addr, addr, al);
  359.     }
  360.     return fd2;
  361. }
  362. #endif /* WINNT */
  363.  
  364.  
  365. static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
  366. {
  367.     PRInt32 result;
  368.     int one = 1;
  369.  
  370. #if defined(_PR_INET6)
  371.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  372. #else
  373.     PR_ASSERT(addr->raw.family == AF_INET);
  374. #endif
  375.  
  376. #ifdef HAVE_SOCKET_REUSEADDR
  377.     if ( setsockopt (fd->secret->md.osfd, (int)SOL_SOCKET, SO_REUSEADDR, 
  378.         (const void *)&one, sizeof(one) ) < 0) {
  379.         return PR_FAILURE;
  380.     }
  381. #endif
  382.  
  383.     result = _PR_MD_BIND(fd, addr, PR_NETADDR_SIZE(addr));
  384.     if (result < 0) {
  385.         return PR_FAILURE;
  386.     }
  387.     return PR_SUCCESS;
  388. }
  389.  
  390. static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
  391. {
  392.     PRInt32 result;
  393.  
  394.     result = _PR_MD_LISTEN(fd, backlog);
  395.     if (result < 0) {
  396.         return PR_FAILURE;
  397.     }
  398.     return PR_SUCCESS;
  399. }
  400.  
  401. static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
  402. {
  403.     PRInt32 result;
  404.  
  405.     result = _PR_MD_SHUTDOWN(fd, how);
  406.     if (result < 0) {
  407.         return PR_FAILURE;
  408.     }
  409.     return PR_SUCCESS;
  410. }
  411.  
  412. static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
  413. PRIntervalTime timeout)
  414. {
  415.     PRInt32 rv;
  416.     PRThread *me = _PR_MD_CURRENT_THREAD();
  417.  
  418.     if (_PR_PENDING_INTERRUPT(me)) {
  419.         me->flags &= ~_PR_INTERRUPT;
  420.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  421.         return -1;
  422.     }
  423.     if (_PR_IO_PENDING(me)) {
  424.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  425.         return -1;
  426.     }
  427.  
  428.     PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv: fd=%p osfd=%d buf=%p amount=%d",
  429.                                     fd, fd->secret->md.osfd, buf, amount));
  430.     rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
  431.     PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
  432.         rv, PR_GetError(), PR_GetOSError()));
  433.     return rv;
  434. }
  435.  
  436. static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
  437. {
  438.     return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  439. }
  440.  
  441. static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
  442. PRIntn flags, PRIntervalTime timeout)
  443. {
  444.     PRInt32 temp, count;
  445.     PRThread *me = _PR_MD_CURRENT_THREAD();
  446.  
  447.     if (_PR_PENDING_INTERRUPT(me)) {
  448.         me->flags &= ~_PR_INTERRUPT;
  449.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  450.         return -1;
  451.     }
  452.     if (_PR_IO_PENDING(me)) {
  453.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  454.         return -1;
  455.     }
  456.  
  457.     count = 0;
  458.     while (amount > 0) {
  459.         PR_LOG(_pr_io_lm, PR_LOG_MAX,
  460.             ("send: fd=%p osfd=%d buf=%p amount=%d",
  461.             fd, fd->secret->md.osfd, buf, amount));
  462.         temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
  463.         if (temp < 0) {
  464.                     count = -1;
  465.                     break;
  466.                 }
  467.  
  468.         count += temp;
  469.         if (fd->secret->nonblocking) {
  470.             break;
  471.         }
  472.         buf = (const void*) ((const char*)buf + temp);
  473.  
  474.         amount -= temp;
  475.     }
  476.     PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
  477.     return count;
  478. }
  479.  
  480. static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
  481. {
  482.     return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
  483. }
  484.  
  485. static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
  486. {
  487.     PRInt32 rv;
  488.  
  489.     if (!fd || fd->secret->state != _PR_FILEDESC_OPEN) {
  490.         PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  491.         return PR_FAILURE;
  492.     }
  493.  
  494.     fd->secret->state = _PR_FILEDESC_CLOSED;
  495.  
  496.     rv =  _PR_MD_CLOSE_SOCKET(fd->secret->md.osfd);
  497.     PR_FreeFileDesc(fd);
  498.     if (rv < 0) {
  499.         return PR_FAILURE;
  500.     }
  501.     return PR_SUCCESS;
  502. }
  503.  
  504. static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
  505. {
  506.     PRInt32 rv;
  507.     rv =  _PR_MD_SOCKETAVAILABLE(fd);
  508.     return rv;        
  509. }
  510.  
  511. static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
  512. {
  513.     PRInt64 rv;
  514.     LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
  515.     return rv;        
  516. }
  517.  
  518. static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
  519. {
  520. #if defined(XP_MAC)
  521. #pragma unused (fd)
  522. #endif
  523.  
  524.     return PR_SUCCESS;
  525. }
  526.  
  527. static PRInt32 PR_CALLBACK SocketSendTo(
  528.     PRFileDesc *fd, const void *buf, PRInt32 amount,
  529.     PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
  530. {
  531.     PRInt32 temp, count;
  532.     PRThread *me = _PR_MD_CURRENT_THREAD();
  533.  
  534.     if (_PR_PENDING_INTERRUPT(me)) {
  535.         me->flags &= ~_PR_INTERRUPT;
  536.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  537.         return -1;
  538.     }
  539.     if (_PR_IO_PENDING(me)) {
  540.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  541.         return -1;
  542.     }
  543.  
  544. #if defined(_PR_INET6)
  545.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  546. #else
  547.     PR_ASSERT(addr->raw.family == AF_INET);
  548. #endif
  549.  
  550.     count = 0;
  551.     while (amount > 0) {
  552.         temp = _PR_MD_SENDTO(fd, buf, amount, flags,
  553.             addr, PR_NETADDR_SIZE(addr), timeout);
  554.         if (temp < 0) {
  555.                     count = -1;
  556.                     break;
  557.                 }
  558.         count += temp;
  559.         if (fd->secret->nonblocking) {
  560.             break;
  561.         }
  562.         buf = (const void*) ((const char*)buf + temp);
  563.         amount -= temp;
  564.     }
  565.     return count;
  566. }
  567.  
  568. static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
  569. PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
  570. {
  571.     PRInt32 rv;
  572.     PRUint32 al;
  573.     PRThread *me = _PR_MD_CURRENT_THREAD();
  574.  
  575.     if (_PR_PENDING_INTERRUPT(me)) {
  576.         me->flags &= ~_PR_INTERRUPT;
  577.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  578.         return -1;
  579.     }
  580.     if (_PR_IO_PENDING(me)) {
  581.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  582.         return -1;
  583.     }
  584.  
  585.     al = sizeof(PRNetAddr);
  586.     rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
  587.     return rv;
  588. }
  589.  
  590. static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
  591. PRNetAddr **raddr, void *buf, PRInt32 amount,
  592. PRIntervalTime timeout)
  593. {
  594.     PRInt32 rv;
  595.     PRThread *me = _PR_MD_CURRENT_THREAD();
  596.  
  597.     if (_PR_PENDING_INTERRUPT(me)) {
  598.         me->flags &= ~_PR_INTERRUPT;
  599.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  600.         return -1;
  601.     }
  602.     if (_PR_IO_PENDING(me)) {
  603.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  604.         return -1;
  605.     }
  606.     *nd = NULL;
  607.  
  608. #if defined(WINNT)
  609.     {
  610.     PRInt32 newSock;
  611.     PRNetAddr *raddrCopy;
  612.  
  613.     if (raddr == NULL) {
  614.         raddr = &raddrCopy;
  615.     }
  616.     rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
  617.     if (rv < 0) {
  618.         rv = -1;
  619.     } else {
  620.         /* Successfully accepted and read; create the new PRFileDesc */
  621.         *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
  622.         if (*nd == 0) {
  623.             _PR_MD_CLOSE_SOCKET(newSock);
  624.             /* PR_AllocFileDesc() has invoked PR_SetError(). */
  625.             rv = -1;
  626.         } else {
  627.             (*nd)->secret->md.io_model_committed = PR_TRUE;
  628.             (*nd)->secret->md.accepted_socket = PR_TRUE;
  629.             memcpy(&(*nd)->secret->md.peer_addr, *raddr,
  630.                 PR_NETADDR_SIZE(*raddr));
  631.         }
  632.     }
  633.     }
  634. #else
  635.     rv = _PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
  636. #endif
  637.     return rv;
  638. }
  639.  
  640. #ifdef WINNT
  641. PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
  642. PRNetAddr **raddr, void *buf, PRInt32 amount,
  643. PRIntervalTime timeout)
  644. {
  645.     PRInt32 rv;
  646.     PRInt32 newSock;
  647.     PRThread *me = _PR_MD_CURRENT_THREAD();
  648.     PRNetAddr *raddrCopy;
  649.  
  650.     if (_PR_PENDING_INTERRUPT(me)) {
  651.         me->flags &= ~_PR_INTERRUPT;
  652.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  653.         return -1;
  654.     }
  655.     if (_PR_IO_PENDING(me)) {
  656.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  657.         return -1;
  658.     }
  659.     *nd = NULL;
  660.  
  661.     if (raddr == NULL) {
  662.         raddr = &raddrCopy;
  663.     }
  664.     rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
  665.         timeout, PR_TRUE, NULL, NULL);
  666.     if (rv < 0) {
  667.         rv = -1;
  668.     } else {
  669.         /* Successfully accepted and read; create the new PRFileDesc */
  670.         *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
  671.         if (*nd == 0) {
  672.             _PR_MD_CLOSE_SOCKET(newSock);
  673.             /* PR_AllocFileDesc() has invoked PR_SetError(). */
  674.             rv = -1;
  675.         } else {
  676.             (*nd)->secret->md.io_model_committed = PR_TRUE;
  677.             (*nd)->secret->md.accepted_socket = PR_TRUE;
  678.             memcpy(&(*nd)->secret->md.peer_addr, *raddr,
  679.                 PR_NETADDR_SIZE(*raddr));
  680.         }
  681.     }
  682.     return rv;
  683. }
  684.  
  685. PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
  686. PRFileDesc *sd, PRFileDesc **nd, 
  687. PRNetAddr **raddr, void *buf, PRInt32 amount,
  688. PRIntervalTime timeout,
  689. _PR_AcceptTimeoutCallback callback,
  690. void *callbackArg)
  691. {
  692.     PRInt32 rv;
  693.     PRInt32 newSock;
  694.     PRThread *me = _PR_MD_CURRENT_THREAD();
  695.     PRNetAddr *raddrCopy;
  696.  
  697.     if (_PR_PENDING_INTERRUPT(me)) {
  698.         me->flags &= ~_PR_INTERRUPT;
  699.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  700.         return -1;
  701.     }
  702.     if (_PR_IO_PENDING(me)) {
  703.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  704.         return -1;
  705.     }
  706.     *nd = NULL;
  707.  
  708.     if (raddr == NULL) {
  709.         raddr = &raddrCopy;
  710.     }
  711.     rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
  712.         timeout, PR_TRUE, callback, callbackArg);
  713.     if (rv < 0) {
  714.         rv = -1;
  715.     } else {
  716.         /* Successfully accepted and read; create the new PRFileDesc */
  717.         *nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
  718.         if (*nd == 0) {
  719.             _PR_MD_CLOSE_SOCKET(newSock);
  720.             /* PR_AllocFileDesc() has invoked PR_SetError(). */
  721.             rv = -1;
  722.         } else {
  723.             (*nd)->secret->md.io_model_committed = PR_TRUE;
  724.             (*nd)->secret->md.accepted_socket = PR_TRUE;
  725.             memcpy(&(*nd)->secret->md.peer_addr, *raddr,
  726.                 PR_NETADDR_SIZE(*raddr));
  727.         }
  728.     }
  729.     return rv;
  730. }
  731. #endif /* WINNT */
  732.  
  733. #ifdef WINNT
  734. PR_IMPLEMENT(void)
  735. PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
  736. {
  737.     _PR_MD_UPDATE_ACCEPT_CONTEXT(
  738.         socket->secret->md.osfd, acceptSocket->secret->md.osfd);
  739. }
  740. #endif /* WINNT */
  741.  
  742. static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
  743. const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
  744. PRIntervalTime timeout)
  745. {
  746.     PRInt32 rv;
  747.     PRThread *me = _PR_MD_CURRENT_THREAD();
  748.  
  749.     if (_PR_PENDING_INTERRUPT(me)) {
  750.         me->flags &= ~_PR_INTERRUPT;
  751.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  752.         return -1;
  753.     }
  754.     if (_PR_IO_PENDING(me)) {
  755.         PR_SetError(PR_IO_PENDING_ERROR, 0);
  756.         return -1;
  757.     }
  758. #if defined(WINNT)
  759.     rv = _PR_MD_TRANSMITFILE(
  760.         sd, fd,
  761.         headers, hlen, flags, timeout);
  762.     if (rv < 0) {
  763.         rv = -1;
  764.     }
  765.     if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
  766.         /*
  767.          * This should be kept the same as SocketClose, except
  768.          * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
  769.          * not be called because the socket will be recycled.
  770.          */
  771.         sd->secret->state = _PR_FILEDESC_CLOSED;
  772.         PR_FreeFileDesc(sd);
  773.     }
  774. #else
  775. #if defined(XP_UNIX)
  776.     /*
  777.      * On HPUX11, we could call _PR_HPUXTransmitFile(), but that
  778.      * would require that we not override the malloc() functions.
  779.      */
  780.     rv = _PR_UnixTransmitFile(sd, fd, headers, hlen, flags, timeout);
  781. #else    /* XP_UNIX */
  782.     rv = _PR_EmulateTransmitFile(sd, fd, headers, hlen, flags,
  783.         timeout);
  784. #endif    /* XP_UNIX */
  785. #endif    /* WINNT */
  786.  
  787.     return rv;
  788. }
  789.  
  790. static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
  791. {
  792.     PRInt32 result;
  793.     PRUint32 addrlen;
  794.  
  795.     addrlen = sizeof(PRNetAddr);
  796.     result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
  797.     if (result < 0) {
  798.         return PR_FAILURE;
  799.     }
  800.     PR_ASSERT(addrlen == PR_NETADDR_SIZE(addr));
  801. #if defined(_PR_INET6)
  802.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  803. #else
  804.     PR_ASSERT(addr->raw.family == AF_INET);
  805. #endif
  806.     return PR_SUCCESS;
  807. }
  808.  
  809. static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  810. {
  811.     PRInt32 result;
  812.     PRUint32 addrlen;
  813.  
  814.     addrlen = sizeof(PRNetAddr);
  815.     result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
  816.     if (result < 0) {
  817.         return PR_FAILURE;
  818.     }
  819.     PR_ASSERT(addrlen == PR_NETADDR_SIZE(addr));
  820. #if defined(_PR_INET6)
  821.     PR_ASSERT(addr->raw.family == AF_INET || addr->raw.family == AF_INET6);
  822. #else
  823.     PR_ASSERT(addr->raw.family == AF_INET);
  824. #endif
  825.     return PR_SUCCESS;
  826. }
  827.  
  828. static PRStatus PR_CALLBACK SocketGetSockOpt(
  829.     PRFileDesc *fd, PRSockOption optname, void* optval, PRInt32* optlen)
  830. {
  831.     PRInt32 level, name;
  832.     PRStatus rv;
  833.  
  834.     /*
  835.      * PR_SockOpt_Nonblocking is a special case that does not
  836.      * translate to a getsockopt() call
  837.      */
  838.     if (PR_SockOpt_Nonblocking == optname)
  839.     {
  840.         PR_ASSERT(sizeof(PRIntn) <= *optlen);
  841.         *((PRIntn *) optval) = (PRIntn) fd->secret->nonblocking;
  842.         *optlen = sizeof(PRIntn);
  843.         return PR_SUCCESS;
  844.     }
  845.  
  846.     rv = _PR_MapOptionName(optname, &level, &name);
  847.     if (PR_SUCCESS == rv)
  848.     {
  849.         if (PR_SockOpt_Linger == optname)
  850.         {
  851.             struct linger linger;
  852.             PRInt32 len = sizeof(linger);
  853.             rv = _PR_MD_GETSOCKOPT(
  854.                 fd, level, name, (char *) &linger, &len);
  855.             if (PR_SUCCESS == rv)
  856.             {
  857.                 ((PRLinger*)(optval))->polarity = linger.l_onoff
  858.                     ? PR_TRUE : PR_FALSE;
  859.                 ((PRLinger*)(optval))->linger = PR_SecondsToInterval(
  860.                     linger.l_linger);
  861.                 *optlen = sizeof(PRLinger);
  862.             }
  863.         }
  864.         else
  865.         {
  866.             rv = _PR_MD_GETSOCKOPT(
  867.                 fd, level, name, optval, optlen);
  868.         }
  869.     }
  870.     return rv;
  871. }
  872.  
  873. static PRStatus PR_CALLBACK SocketSetSockOpt(
  874.     PRFileDesc *fd, PRSockOption optname, const void* optval, PRInt32 optlen)
  875. {
  876.     PRInt32 level, name;
  877.     PRStatus rv;
  878.  
  879.     /*
  880.      * PR_SockOpt_Nonblocking is a special case that does not
  881.      * translate to a setsockopt call.
  882.      */
  883.     if (PR_SockOpt_Nonblocking == optname)
  884.     {
  885.         PRBool fNonblocking = *((PRIntn *) optval) ? PR_TRUE : PR_FALSE;
  886.         PR_ASSERT(sizeof(PRIntn) == optlen);
  887. #ifdef WINNT
  888.         PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
  889.             || (fd->secret->nonblocking == fNonblocking));
  890.         if (fd->secret->md.io_model_committed
  891.             && (fd->secret->nonblocking != fNonblocking))
  892.         {
  893.             /*
  894.              * On NT, once we have associated a socket with the io
  895.              * completion port, we can't disassociate it.  So we
  896.              * can't change the nonblocking option of the socket
  897.              * afterwards.
  898.              */
  899.             PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  900.             return PR_FAILURE;
  901.         }
  902. #endif
  903.         fd->secret->nonblocking = fNonblocking;
  904.         return PR_SUCCESS;
  905.     }
  906.  
  907.     rv = _PR_MapOptionName(optname, &level, &name);
  908.     if (PR_SUCCESS == rv)
  909.     {
  910.         if (PR_SockOpt_Linger == optname)
  911.         {
  912.             struct linger linger;
  913.             linger.l_onoff = ((PRLinger*)(optval))->polarity ? 1 : 0;
  914.             linger.l_linger = PR_IntervalToSeconds(
  915.                 ((PRLinger*)(optval))->linger);
  916.             rv = _PR_MD_SETSOCKOPT(
  917.                 fd, level, name, (char *) &linger, sizeof(linger));
  918.         }
  919.         else
  920.         {
  921.             rv = _PR_MD_SETSOCKOPT(
  922.                 fd, level, name, optval, optlen);
  923.         }
  924.     }
  925.     return rv;
  926. }
  927.  
  928. static PRIOMethods tcpMethods = {
  929.     PR_DESC_SOCKET_TCP,
  930.     SocketClose,
  931.     SocketRead,
  932.     SocketWrite,
  933.     SocketAvailable,
  934.     SocketAvailable64,
  935.     SocketSync,
  936.     (PRSeekFN)_PR_InvalidInt,
  937.     (PRSeek64FN)_PR_InvalidInt64,
  938.     (PRFileInfoFN)_PR_InvalidStatus,
  939.     (PRFileInfo64FN)_PR_InvalidStatus,
  940.     SocketWritev,
  941.     SocketConnect,
  942.     SocketAccept,
  943.     SocketBind,
  944.     SocketListen,
  945.     SocketShutdown,
  946.     SocketRecv,
  947.     SocketSend,
  948.     (PRRecvfromFN)_PR_InvalidInt,
  949.     (PRSendtoFN)_PR_InvalidInt,
  950.     (PRPollFN)0,
  951.     SocketAcceptRead,
  952.     SocketTransmitFile,
  953.     SocketGetName,
  954.     SocketGetPeerName,
  955.     SocketGetSockOpt,
  956.     SocketSetSockOpt,
  957.     _PR_SocketGetSocketOption,
  958.     _PR_SocketSetSocketOption
  959. };
  960.  
  961. static PRIOMethods udpMethods = {
  962.     PR_DESC_SOCKET_UDP,
  963.     SocketClose,
  964.     SocketRead,
  965.     SocketWrite,
  966.     SocketAvailable,
  967.     SocketAvailable64,
  968.     SocketSync,
  969.     (PRSeekFN)_PR_InvalidInt,
  970.     (PRSeek64FN)_PR_InvalidInt64,
  971.     (PRFileInfoFN)_PR_InvalidStatus,
  972.     (PRFileInfo64FN)_PR_InvalidStatus,
  973.     SocketWritev,
  974.     SocketConnect,
  975.     (PRAcceptFN)_PR_InvalidDesc,
  976.     SocketBind,
  977.     SocketListen,
  978.     SocketShutdown,
  979.     SocketRecv,
  980.     SocketSend,
  981.     SocketRecvFrom,
  982.     SocketSendTo,
  983.     (PRPollFN)0,
  984.     (PRAcceptreadFN)_PR_InvalidInt,
  985.     (PRTransmitfileFN)_PR_InvalidInt,
  986.     SocketGetName,
  987.     SocketGetPeerName,
  988.     SocketGetSockOpt,
  989.     SocketSetSockOpt,
  990.     _PR_SocketGetSocketOption,
  991.     _PR_SocketSetSocketOption
  992. };
  993.  
  994. PR_IMPLEMENT(PRIOMethods*) PR_GetTCPMethods()
  995. {
  996.     return &tcpMethods;
  997. }
  998.  
  999. PR_IMPLEMENT(PRIOMethods*) PR_GetUDPMethods()
  1000. {
  1001.     return &udpMethods;
  1002. }
  1003.  
  1004. PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
  1005. {
  1006.     PRInt32 osfd;
  1007.     int one = 1;
  1008.     PRFileDesc *fd;
  1009.  
  1010.     if (!_pr_initialized) _PR_ImplicitInitialization();
  1011.     if (AF_INET != domain
  1012. #if defined(_PR_INET6)
  1013.             && AF_INET6 != domain
  1014. #endif
  1015.             ) {
  1016.         PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  1017.         return NULL;
  1018.     }
  1019.     osfd = _PR_MD_SOCKET(domain, type, proto);
  1020.     if (osfd == -1) {
  1021.         return 0;
  1022.     }
  1023. #ifdef HAVE_SOCKET_KEEPALIVE
  1024.     /* "Keep-alive" packets are specific to TCP. */
  1025.     if (domain == AF_INET && type == SOCK_STREAM) {
  1026.         if (setsockopt(osfd, (int)SOL_SOCKET, SO_KEEPALIVE,
  1027.             (const void *) &one, sizeof(one) ) < 0) {
  1028.             _PR_MD_CLOSE_SOCKET(osfd);
  1029.             return 0;
  1030.         }
  1031.     }
  1032. #endif
  1033.     if (type == SOCK_STREAM)
  1034.         fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
  1035.     else
  1036.         fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
  1037.     /*
  1038.      * Make the sockets non-blocking
  1039.      */
  1040.     if (fd != NULL)
  1041.         _PR_MD_MAKE_NONBLOCK(fd);
  1042.     else
  1043.         _PR_MD_CLOSE_SOCKET(osfd);
  1044.     return fd;
  1045. }
  1046.  
  1047. PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
  1048. {
  1049.     PRInt32 domain = AF_INET;
  1050.  
  1051. #if defined(_PR_INET6)
  1052.     if (_pr_ipv6_enabled) {
  1053.         domain = AF_INET6;
  1054.     }
  1055. #endif
  1056.     return PR_Socket(domain, SOCK_STREAM, 0);
  1057. }
  1058.  
  1059. PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
  1060. {
  1061.     PRInt32 domain = AF_INET;
  1062.  
  1063. #if defined(_PR_INET6)
  1064.     if (_pr_ipv6_enabled) {
  1065.         domain = AF_INET6;
  1066.     }
  1067. #endif
  1068.     return PR_Socket(domain, SOCK_DGRAM, 0);
  1069. }
  1070.  
  1071. PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
  1072. {
  1073. #ifdef XP_UNIX
  1074.     PRInt32 rv, osfd[2];
  1075.  
  1076.     rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
  1077.     if (rv == -1) {
  1078.         return PR_FAILURE;
  1079.     }
  1080.  
  1081.     f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
  1082.     if (!f[0]) {
  1083.         _PR_MD_CLOSE_SOCKET(osfd[0]);
  1084.         _PR_MD_CLOSE_SOCKET(osfd[1]);
  1085.         /* PR_AllocFileDesc() has invoked PR_SetError(). */
  1086.         return PR_FAILURE;
  1087.     }
  1088.     f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
  1089.     if (!f[1]) {
  1090.         PR_Close(f[0]);
  1091.         _PR_MD_CLOSE_SOCKET(osfd[1]);
  1092.         /* PR_AllocFileDesc() has invoked PR_SetError(). */
  1093.         return PR_FAILURE;
  1094.     }
  1095.     _PR_MD_MAKE_NONBLOCK(f[0]);
  1096.     _PR_MD_MAKE_NONBLOCK(f[1]);
  1097.     return PR_SUCCESS;
  1098. #endif
  1099.  
  1100.     /* XXX: this needs to be implemented for MAC and NT */
  1101. #ifdef XP_MAC
  1102. #pragma unused (f)
  1103.  
  1104.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
  1105.     return PR_FAILURE;
  1106. #endif
  1107.  
  1108. #ifdef XP_PC
  1109.     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
  1110.     return PR_FAILURE;
  1111. #endif
  1112. }
  1113.  
  1114. PR_IMPLEMENT(PRInt32)
  1115. PR_FileDesc2NativeHandle(PRFileDesc *fd)
  1116. {
  1117.     if (fd) {
  1118.         /*
  1119.          * The fd may be layered.  Chase the links to the
  1120.          * bottom layer to get the osfd.
  1121.          */
  1122.         PRFileDesc *bottom = fd;
  1123.         while (bottom->lower != NULL) {
  1124.             bottom = bottom->lower;
  1125.         }
  1126.         return bottom->secret->md.osfd;
  1127.     } else {
  1128.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1129.         return -1;
  1130.     }
  1131. }
  1132.  
  1133. PR_IMPLEMENT(void)
  1134. PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PRInt32 handle)
  1135. {
  1136.     if (fd)
  1137.         fd->secret->md.osfd = handle;
  1138. }
  1139.  
  1140. /*
  1141.  * _PR_EmulateTransmitFile
  1142.  *
  1143.  *    Send file fd across socket sd. If headers is non-NULL, 'hlen'
  1144.  *    bytes of headers is sent before sending the file.
  1145.  *
  1146.  *    PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file
  1147.  *    
  1148.  *    return number of bytes sent or -1 on error
  1149.  *
  1150.  */
  1151.  
  1152. PRInt32 _PR_EmulateTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
  1153. const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
  1154. PRIntervalTime timeout)
  1155. {
  1156.     PRInt32 rv, count = 0;
  1157.     PRInt32 rlen;
  1158.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1159.     char *buf = NULL;
  1160. #define _TRANSMITFILE_BUFSIZE    (16 * 1024)
  1161.  
  1162.     if (_PR_PENDING_INTERRUPT(me)) {
  1163.         me->flags &= ~_PR_INTERRUPT;
  1164.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  1165.         return -1;
  1166.     }
  1167.  
  1168.     buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE);
  1169.     if (buf == NULL) {
  1170.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1171.         return -1;
  1172.     }
  1173.  
  1174.     /*
  1175.      * send headers, first
  1176.      */
  1177.     while (hlen) {
  1178.         rv =  PR_Send(sd, headers, hlen, 0, timeout);
  1179.         if (rv < 0) {
  1180.             /* PR_Send() has invoked PR_SetError(). */
  1181.             rv = -1;
  1182.             goto done;
  1183.         } else {
  1184.             count += rv;
  1185.             headers = (const void*) ((const char*)headers + rv);
  1186.             hlen -= rv;
  1187.         }
  1188.     }
  1189.     /*
  1190.      * send file, next
  1191.      */
  1192.     while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) {
  1193.         while (rlen) {
  1194.             char *bufptr = buf;
  1195.  
  1196.             rv =  PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT);
  1197.             if (rv < 0) {
  1198.                 /* PR_Send() has invoked PR_SetError(). */
  1199.                 rv = -1;
  1200.                 goto done;
  1201.             } else {
  1202.                 count += rv;
  1203.                 bufptr = ((char*)bufptr + rv);
  1204.                 rlen -= rv;
  1205.             }
  1206.         }
  1207.     }
  1208.     if (rlen == 0) {
  1209.         /*
  1210.          * end-of-file
  1211.          */
  1212.         if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
  1213.             PR_Close(sd);
  1214.         rv = count;
  1215.     } else {
  1216.         PR_ASSERT(rlen < 0);
  1217.         /* PR_Read() has invoked PR_SetError(). */
  1218.         rv = -1;
  1219.     }
  1220.  
  1221. done:
  1222.     if (buf)
  1223.         PR_DELETE(buf);
  1224.     return rv;
  1225. }
  1226.  
  1227. /*
  1228.  * _PR_EmulateAcceptRead
  1229.  *
  1230.  *    Accept an incoming connection on sd, set *nd to point to the
  1231.  *    newly accepted socket, read 'amount' bytes from the accepted
  1232.  *    socket.
  1233.  *
  1234.  *    buf is a buffer of length = (amount + sizeof(PRNetAddr))
  1235.  *    *raddr points to the PRNetAddr of the accepted connection upon
  1236.  *    return
  1237.  *
  1238.  *    return number of bytes read or -1 on error
  1239.  *
  1240.  */
  1241. PRInt32 _PR_EmulateAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
  1242. PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout)
  1243. {
  1244.     PRInt32 rv;
  1245.     PRFileDesc *newsockfd;
  1246.     PRNetAddr remote;
  1247.     PRIntervalTime start, elapsed;
  1248.  
  1249.     if (PR_INTERVAL_NO_TIMEOUT != timeout) {
  1250.         start = PR_IntervalNow();
  1251.     }
  1252.     if ((newsockfd = PR_Accept(sd, &remote, timeout)) == NULL) {
  1253.         return -1;
  1254.     }
  1255.  
  1256.     if (PR_INTERVAL_NO_TIMEOUT != timeout) {
  1257.         elapsed = (PRIntervalTime) (PR_IntervalNow() - start);
  1258.         if (elapsed > timeout) {
  1259.             PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
  1260.             goto failed;
  1261.         } else {
  1262.             timeout = timeout - elapsed;
  1263.         }
  1264.     }
  1265.  
  1266.     rv = PR_Recv(newsockfd, buf, amount, 0, timeout);
  1267.     if (rv >= 0) {
  1268.         *nd = newsockfd;
  1269.         *raddr = (PRNetAddr *)((char *) buf + amount);
  1270.         memcpy(*raddr, &remote, PR_NETADDR_SIZE(&remote));
  1271.         return rv;
  1272.     }
  1273.  
  1274. failed:
  1275.     PR_Close(newsockfd);
  1276.     return -1;
  1277. }
  1278.  
  1279. /*
  1280. ** Select compatibility
  1281. **
  1282. */
  1283.  
  1284. PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
  1285. {
  1286.     memset(set, 0, sizeof(PR_fd_set));
  1287. }
  1288.  
  1289. PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
  1290. {
  1291.     PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
  1292.  
  1293.     set->harray[set->hsize++] = fh;
  1294. }
  1295.  
  1296. PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
  1297. {
  1298.     PRUint32 index, index2;
  1299.  
  1300.     for (index = 0; index<set->hsize; index++)
  1301.         if (set->harray[index] == fh) {
  1302.             for (index2=index; index2 < (set->hsize-1); index2++) {
  1303.                 set->harray[index2] = set->harray[index2+1];
  1304.             }
  1305.             set->hsize--;
  1306.             break;
  1307.         }
  1308. }
  1309.  
  1310. PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
  1311. {
  1312.     PRUint32 index;
  1313.     for (index = 0; index<set->hsize; index++)
  1314.         if (set->harray[index] == fh) {
  1315.             return 1;
  1316.         }
  1317.     return 0;
  1318. }
  1319.  
  1320. PR_IMPLEMENT(void) PR_FD_NSET(PRInt32 fd, PR_fd_set *set)
  1321. {
  1322.     PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
  1323.  
  1324.     set->narray[set->nsize++] = fd;
  1325. }
  1326.  
  1327. PR_IMPLEMENT(void) PR_FD_NCLR(PRInt32 fd, PR_fd_set *set)
  1328. {
  1329.     PRUint32 index, index2;
  1330.  
  1331.     for (index = 0; index<set->nsize; index++)
  1332.         if (set->narray[index] == fd) {
  1333.             for (index2=index; index2 < (set->nsize-1); index2++) {
  1334.                 set->narray[index2] = set->narray[index2+1];
  1335.             }
  1336.             set->nsize--;
  1337.             break;
  1338.         }
  1339. }
  1340.  
  1341. PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PRInt32 fd, PR_fd_set *set)
  1342. {
  1343.     PRUint32 index;
  1344.     for (index = 0; index<set->nsize; index++)
  1345.         if (set->narray[index] == fd) {
  1346.             return 1;
  1347.         }
  1348.     return 0;
  1349. }
  1350.  
  1351.  
  1352. #if !defined(NEED_SELECT)
  1353. #if !defined(XP_MAC)
  1354. #include "obsolete/probslet.h"
  1355. #else
  1356. #include "probslet.h"
  1357. #endif
  1358.  
  1359. #define PD_INCR 20
  1360.  
  1361. static PRPollDesc *_pr_setfd(
  1362.     PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
  1363. {
  1364.     PRUintn fsidx, pdidx;
  1365.     PRPollDesc *poll = polldesc;
  1366.  
  1367.     if (NULL == set) return poll;
  1368.  
  1369.     /* First set the pr file handle osfds */
  1370.     for (fsidx = 0; fsidx < set->hsize; fsidx++)
  1371.     {
  1372.         for (pdidx = 0; 1; pdidx++)
  1373.         {
  1374.             if ((PRFileDesc*)-1 == poll[pdidx].fd)
  1375.             {
  1376.                 /* our vector is full - extend and condition it */
  1377.                 poll = PR_Realloc(
  1378.                     poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
  1379.                 if (NULL == poll) goto out_of_memory;
  1380.                 memset(
  1381.                     poll + pdidx * sizeof(PRPollDesc),
  1382.                     0, PD_INCR * sizeof(PRPollDesc));
  1383.                 poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
  1384.             }
  1385.             if ((NULL == poll[pdidx].fd)
  1386.             || (poll[pdidx].fd == set->harray[fsidx]))
  1387.             {
  1388.                 /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
  1389.                 /* either empty or prevously defined */
  1390.                 poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
  1391.                 poll[pdidx].in_flags |= flags;  /* possibly redundant */
  1392.                 break;
  1393.             }
  1394.         }
  1395.     }
  1396.  
  1397. #if 0
  1398.     /* Second set the native osfds */
  1399.     for (fsidx = 0; fsidx < set->nsize; fsidx++)
  1400.     {
  1401.         for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
  1402.         {
  1403.             if ((PRFileDesc*)-1 == poll[pdidx].fd)
  1404.             {
  1405.                 /* our vector is full - extend and condition it */
  1406.                 poll = PR_Realloc(
  1407.                     poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
  1408.                 if (NULL == poll) goto out_of_memory;
  1409.                 memset(
  1410.                     poll + pdidx * sizeof(PRPollDesc),
  1411.                     0, PD_INCR * sizeof(PRPollDesc));
  1412.                 poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
  1413.             }
  1414.             if ((NULL == poll[pdidx].fd)
  1415.             || (poll[pdidx].fd == set->narray[fsidx]))
  1416.             {
  1417.                 /* either empty or prevously defined */
  1418.                 poll[pdidx].fd = set->narray[fsidx];
  1419.                 PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
  1420.                 poll[pdidx].in_flags |= flags;
  1421.                 break;
  1422.             }
  1423.         }
  1424.     }
  1425. #endif /* 0 */
  1426.  
  1427.     return poll;
  1428.  
  1429. out_of_memory:
  1430.     if (NULL != polldesc) PR_DELETE(polldesc);
  1431.     return NULL;
  1432. }  /* _pr_setfd */
  1433.  
  1434. #endif /* !defined(NEED_SELECT) */
  1435.  
  1436. PR_IMPLEMENT(PRInt32) PR_Select(
  1437.     PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
  1438.     PR_fd_set *pr_ex, PRIntervalTime timeout)
  1439. {
  1440.  
  1441. #if !defined(NEED_SELECT)
  1442.     PRInt32 npds = 0; 
  1443.     /*
  1444.     ** Find out how many fds are represented in the three lists.
  1445.     ** Then allocate a polling descriptor for the logical union
  1446.     ** (there can't be any overlapping) and call PR_Poll().
  1447.     */
  1448.  
  1449.     PRPollDesc *copy, *poll;
  1450.  
  1451.     static PRBool warning = PR_TRUE;
  1452.     if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
  1453.  
  1454.     /* try to get an initial guesss at how much space we need */
  1455.     npds = 0;
  1456.     if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
  1457.         npds = pr_rd->hsize + pr_rd->nsize;
  1458.     if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
  1459.         npds = pr_wr->hsize + pr_wr->nsize;
  1460.     if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
  1461.         npds = pr_ex->hsize + pr_ex->nsize;
  1462.  
  1463.     if (0 == npds)
  1464.     {
  1465.         PR_Sleep(timeout);
  1466.         return 0;
  1467.     }
  1468.  
  1469.     copy = poll = PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
  1470.     if (NULL == poll) goto out_of_memory;
  1471.     poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
  1472.  
  1473.     poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
  1474.     if (NULL == poll) goto out_of_memory;
  1475.     poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
  1476.     if (NULL == poll) goto out_of_memory;
  1477.     poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
  1478.     if (NULL == poll) goto out_of_memory;
  1479.     unused = 0;
  1480.     while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
  1481.     {
  1482.         ++unused;
  1483.     }
  1484.  
  1485.     PR_ASSERT(unused > 0);
  1486.     npds = PR_Poll(poll, unused, timeout);
  1487.  
  1488.     if (npds > 0)
  1489.     {
  1490.         /* Copy the results back into the fd sets */
  1491.         if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
  1492.         if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
  1493.         if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
  1494.         for (copy = &poll[unused - 1]; copy >= poll; --copy)
  1495.         {
  1496.             if (copy->out_flags & PR_POLL_NVAL)
  1497.             {
  1498.                 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1499.                 npds = -1;
  1500.                 break;
  1501.             }
  1502.             if (copy->out_flags & PR_POLL_READ)
  1503.                 if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
  1504.             if (copy->out_flags & PR_POLL_WRITE)
  1505.                 if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
  1506.             if (copy->out_flags & PR_POLL_EXCEPT)
  1507.                 if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
  1508.         }
  1509.     }
  1510.     PR_DELETE(poll);
  1511.  
  1512.     return npds;
  1513. out_of_memory:
  1514.     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1515.     return -1;    
  1516.  
  1517. #endif /* !defined(NEED_SELECT) */
  1518.     
  1519. }
  1520.