VirtualBox

Changeset 51674 in vbox


Ignore:
Timestamp:
Jun 19, 2014 9:01:20 PM (10 years ago)
Author:
vboxsync
Message:

NAT/Net: OS X reports POLLHUP when inbound closes, not when both sides
are closed. Co-opt existing !HAVE_TCP_POLLHUP code written for NetBSD
(where POLLHUP is never reported) to handle the case then inbound
closes first.

Makes inbound half-close work on OS X. Otherwise almost the same
object code is generated, modulo trivial changes (exactly the same
without them).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/NAT/pxtcp.c

    r51608 r51674  
    4343#include "lwip/icmp6.h"
    4444
    45 /* NetBSD doesn't report POLLHUP for TCP sockets */
    46 #ifdef __NetBSD__
    47 # define HAVE_TCP_POLLHUP 0
     45/*
     46 * Different OSes have different quirks in reporting POLLHUP for TCP
     47 * sockets.
     48 *
     49 * Using shutdown(2) "how" values here would be more readable, but
     50 * since SHUT_RD is 0, we can't use 0 for "none", unfortunately.
     51 */
     52#if defined(RT_OS_NETBSD)
     53# define HAVE_TCP_POLLHUP 0                     /* not reported */
     54#elif defined(RT_OS_DARWIN)
     55# define HAVE_TCP_POLLHUP POLLIN                /* reported when remote closes */
    4856#else
    49 # define HAVE_TCP_POLLHUP 1
     57# define HAVE_TCP_POLLHUP (POLLIN|POLLOUT)      /* reported when both directions are closed */
    5058#endif
    5159
     
    172180     * inbuf::buf.  We defer delete until all data are acked to
    173181     * pxtcp_pcb_sent().
    174      *
    175      * It's also implied by inbound_pull.  It probably means that
    176      * "deferred" is not a very fortunate name.
    177182     */
    178183    int deferred_delete;
     
    213218static int pxtcp_pmgr_chan_pollout(struct pollmgr_handler *, SOCKET, int);
    214219static int pxtcp_pmgr_chan_pollin(struct pollmgr_handler *, SOCKET, int);
    215 #if !HAVE_TCP_POLLHUP
     220#if !(HAVE_TCP_POLLHUP & POLLOUT)
    216221static int pxtcp_pmgr_chan_del(struct pollmgr_handler *, SOCKET, int);
    217222#endif
     
    273278static struct pollmgr_handler pxtcp_pmgr_chan_pollout_hdl;
    274279static struct pollmgr_handler pxtcp_pmgr_chan_pollin_hdl;
    275 #if !HAVE_TCP_POLLHUP
     280#if !(HAVE_TCP_POLLHUP & POLLOUT)
    276281static struct pollmgr_handler pxtcp_pmgr_chan_del_hdl;
    277282#endif
     
    299304    CHANNEL(POLLMGR_CHAN_PXTCP_POLLIN,  pxtcp_pmgr_chan_pollin);
    300305    CHANNEL(POLLMGR_CHAN_PXTCP_POLLOUT, pxtcp_pmgr_chan_pollout);
    301 #if !HAVE_TCP_POLLHUP
     306#if !(HAVE_TCP_POLLHUP & POLLOUT)
    302307    CHANNEL(POLLMGR_CHAN_PXTCP_DEL,     pxtcp_pmgr_chan_del);
    303308#endif
     
    487492
    488493
    489 #if !HAVE_TCP_POLLHUP
     494#if !(HAVE_TCP_POLLHUP & POLLOUT)
    490495/**
    491496 * POLLMGR_CHAN_PXTCP_DEL handler.
     
    518523    return POLLIN;
    519524}
    520 #endif  /* !HAVE_TCP_POLLHUP  */
     525#endif  /* !(HAVE_TCP_POLLHUP & POLLOUT)  */
    521526
    522527
     
    13731378
    13741379
    1375     /*
    1376      * NB: set the flag first, since shutdown() will trigger POLLHUP
    1377      * if inbound is already closed, and poll manager asserts
    1378      * outbound_close_done (may be it should not?).
    1379      */
     1380    /* set the flag first, since shutdown() may trigger POLLHUP */
    13801381    pxtcp->outbound_close_done = 1;
    13811382    shutdown(pxtcp->sock, SHUT_WR); /* half-close the socket */
    13821383
    1383 #if !HAVE_TCP_POLLHUP
    1384     /*
    1385      * On NetBSD POLLHUP is not reported for TCP sockets, so we need
    1386      * to nudge poll manager manually.
     1384#if !(HAVE_TCP_POLLHUP & POLLOUT)
     1385    /*
     1386     * We need to nudge poll manager manually, since OS will not
     1387     * report POLLHUP.
    13871388     */
    13881389    if (pxtcp->inbound_close) {
     
    16821683#else
    16831684    if (revents & POLLHUP) {
     1685#if HAVE_TCP_POLLHUP == POLLIN
    16841686        /*
    1685          * Linux and Darwin seems to report POLLHUP when both
    1686          * directions are shut down.  And they do report POLLHUP even
    1687          * when there's unread data (which they aslo report as POLLIN
    1688          * along with that POLLHUP).
    1689          *
    1690          * FreeBSD (from source inspection) seems to follow Linux,
    1691          * reporting POLLHUP when both directions are shut down, but
    1692          * POLLHUP is always accompanied with POLLIN.
    1693          *
    1694          * NetBSD never reports POLLHUP for sockets.
    1695          *
    1696          * ---
    1697          *
    1698          * If external half-closes first, we don't get POLLHUP, we
    1699          * recv 0 bytes from the socket as EOF indicator, stop polling
    1700          * for POLLIN and poll with events == 0 (with occasional
    1701          * one-shot POLLOUT).  When guest eventually closes, we get
    1702          * POLLHUP.
    1703          *
    1704          * If guest half-closes first things are more tricky.  As soon
    1705          * as host sees the FIN from external it will spam POLLHUP,
    1706          * even when there's unread data.  The problem is that we
    1707          * might have stopped polling for POLLIN because the ring
    1708          * buffer is full or we were polling POLLIN but can't read all
    1709          * of the data becuase buffer doesn't have enough space.
    1710          * Either way, there's unread data but we can't keep polling
    1711          * the socket.
     1687         * Remote closed inbound.
    17121688         */
    1713         DPRINTF(("sock %d: HUP\n", fd));
    1714         LWIP_ASSERT1(pxtcp->outbound_close_done);
    1715 
    1716         if (pxtcp->inbound_close) {
    1717             /* there's no unread data, we are done */
    1718             return pxtcp_schedule_delete(pxtcp);
    1719         }
    1720         else {
    1721             /* DPRINTF */ {
    1722 #ifndef RT_OS_WINDOWS
    1723                 int unread;
    1724 #else
    1725                 u_long unread;
     1689        if (!pxtcp->outbound_close_done) {
     1690            /*
     1691             * We might still need to poll for POLLOUT, but we can not
     1692             * poll for POLLIN anymore (even if not all data are read)
     1693             * because we will be spammed by POLLHUP.
     1694             */
     1695            pxtcp->events &= ~POLLIN;
     1696            if (!pxtcp->inbound_close) {
     1697                /* the rest of the input has to be pulled */
     1698                proxy_lwip_post(&pxtcp->msg_inpull);
     1699            }
     1700        }
     1701        else
    17261702#endif
    1727                 status = ioctlsocket(fd, FIONREAD, &unread);
    1728                 if (status == SOCKET_ERROR) {
    1729                     DPRINTF2(("sock %d: FIONREAD: %R[sockerr]\n",
    1730                               fd, SOCKERRNO()));
    1731                 }
    1732                 else {
    1733                     DPRINTF2(("sock %d: %d UNREAD bytes\n", fd, unread));
    1734                 }
     1703        /*
     1704         * Both directions are closed.
     1705         */
     1706        {
     1707            DPRINTF(("sock %d: HUP\n", fd));
     1708            LWIP_ASSERT1(pxtcp->outbound_close_done);
     1709
     1710            if (pxtcp->inbound_close) {
     1711                /* there's no unread data, we are done */
     1712                return pxtcp_schedule_delete(pxtcp);
    17351713            }
    1736 
    1737             /*
    1738              * We cannot just set a flag here and let pxtcp_pcb_sent()
    1739              * notice and start pulling, because if we are preempted
    1740              * before setting the flag and all data in inbuf is ACKed
    1741              * there will be no more calls to pxtcp_pcb_sent() to
    1742              * notice the flag.
    1743              *
    1744              * We cannot set a flag and then send a message to make
    1745              * sure it noticed, because if it has and it has read all
    1746              * data while the message is in transit it will delete
    1747              * pxtcp.
    1748              *
    1749              * In a sense this message is like msg_delete (except we
    1750              * ask to pull some data first).
    1751              */
    1752             proxy_lwip_post(&pxtcp->msg_inpull);
    1753             pxtcp->pmhdl.slot = -1;
    1754             return -1;
    1755         }
    1756         /* NOTREACHED */
    1757     } /* POLLHUP */
     1714            else {
     1715                /* pull the rest of the input first (deferred_delete) */
     1716                pxtcp->pmhdl.slot = -1;
     1717                proxy_lwip_post(&pxtcp->msg_inpull);
     1718                return -1;
     1719            }
     1720            /* NOTREACHED */
     1721        }
     1722
     1723    }
    17581724#endif  /* HAVE_TCP_POLLHUP */
    17591725
     
    22272193    if (/* __predict_false */ len == 0) {
    22282194        /* we are notified to start pulling */
    2229         LWIP_ASSERT1(pxtcp->outbound_close_done);
    22302195        LWIP_ASSERT1(!pxtcp->inbound_close);
    22312196        LWIP_ASSERT1(pxtcp->inbound_pull);
     
    23432308    }
    23442309
    2345     DPRINTF(("%s: pxtcp %p: pcb %p\n",
    2346              __func__, (void *)pxtcp, (void *)pxtcp->pcb));
    23472310    pxtcp->inbound_pull = 1;
    2348     pxtcp->deferred_delete = 1;
     2311    if (pxtcp->outbound_close_done) {
     2312        DPRINTF(("%s: pxtcp %p: pcb %p (deferred delete)\n",
     2313                 __func__, (void *)pxtcp, (void *)pxtcp->pcb));
     2314        pxtcp->deferred_delete = 1;
     2315    }
     2316    else {
     2317        DPRINTF(("%s: pxtcp %p: pcb %p\n",
     2318                 __func__, (void *)pxtcp, (void *)pxtcp->pcb));
     2319    }
     2320
    23492321    pxtcp_pcb_sent(pxtcp, pxtcp->pcb, 0);
    23502322}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette