VirtualBox

Changeset 52154 in vbox


Ignore:
Timestamp:
Jul 23, 2014 6:14:33 PM (11 years ago)
Author:
vboxsync
Message:

NAT: Rework sorecvfrom().

On Windows provide iovec definition that is congruent to WSABUF (and
assert at compile time that it is). Get rid of FIONREAD hack, instead
use recvmsg()/WSARecvFrom to read the datagram into the first mbuf and
a spillover buffer large enough to accomodate anything. Small
datagrams will fit and will need to copying, for large datagrams
m_append() spilover buffer contents.

Fix mbuf length calculations - old code would cause memory corruption
for certain datagram sizes that it considered small enough when they
weren't.

Untanlge the code a bit and make sure we do SOCKET_UNLOCK() on error
legs too (though it happens to be a nop, so we were lucky).

Location:
trunk/src/VBox/Devices/Network/slirp
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/slirp/socket.c

    r51137 r52154  
    3535#include <iphlpapi.h>
    3636#include <icmpapi.h>
     37#endif
     38
     39#if defined(DECLARE_IOVEC) && defined(RT_OS_WINDOWS)
     40AssertCompileMembersSameSizeAndOffset(struct iovec, iov_base, WSABUF, buf);
     41AssertCompileMembersSameSizeAndOffset(struct iovec, iov_len,  WSABUF, len);
    3742#endif
    3843
     
    805810sorecvfrom(PNATState pData, struct socket *so)
    806811{
    807     ssize_t ret = 0;
    808     struct sockaddr_in addr;
    809     socklen_t addrlen = sizeof(struct sockaddr_in);
    810 
    811812    LogFlowFunc(("sorecvfrom: so = %lx\n", (long)so));
    812813
     
    823824    else
    824825    {
     826        static uint8_t au8Buf[64 * 1024];
     827
    825828        /* A "normal" UDP packet */
     829        struct sockaddr_in addr;
     830        socklen_t addrlen = sizeof(struct sockaddr_in);
     831        struct iovec iov[2];
     832        ssize_t nread;
    826833        struct mbuf *m;
    827         ssize_t len;
    828         u_long n = 0;
    829         int rc = 0;
    830         static int signalled = 0;
    831         char *pchBuffer = NULL;
    832         bool fWithTemporalBuffer = false;
    833834
    834835        QSOCKET_LOCK(udb);
     
    836837        QSOCKET_UNLOCK(udb);
    837838
    838         /*How many data has been received ?*/
    839         /*
    840         * 1. calculate how much we can read
    841         * 2. read as much as possible
    842         * 3. attach buffer to allocated header mbuf
    843         */
    844         rc = ioctlsocket(so->s, FIONREAD, &n);
    845         if (rc == -1)
    846         {
    847             if (  soIgnorableErrorCode(errno)
    848                || errno == ENOTCONN)
    849                 return;
    850             else if (signalled == 0)
    851             {
    852                 LogRel(("NAT: can't fetch amount of bytes on socket %R[natsock], so message will be truncated.\n", so));
    853                 signalled = 1;
    854             }
    855             return;
    856         }
    857 
    858         len = sizeof(struct udpiphdr);
    859839        m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, slirp_size(pData));
    860840        if (m == NULL)
     841        {
     842            SOCKET_UNLOCK(so);
    861843            return;
    862 
    863         len += n;
     844        }
     845
    864846        m->m_data += ETH_HLEN;
    865847        m->m_pkthdr.header = mtod(m, void *);
     848
    866849        m->m_data += sizeof(struct udpiphdr);
    867850
    868         pchBuffer = mtod(m, char *);
    869         fWithTemporalBuffer = false;
    870         /*
    871          * Even if amounts of bytes on socket is greater than MTU value
    872          * Slirp will able fragment it, but we won't create temporal location
    873          * here.
    874          */
    875         if (n > (slirp_size(pData) - sizeof(struct udpiphdr)))
    876         {
    877             pchBuffer = RTMemAlloc((n) * sizeof(char));
    878             if (!pchBuffer)
     851        /* small packets will fit without copying */
     852        iov[0].iov_base = mtod(m, char *);
     853        iov[0].iov_len = M_TRAILINGSPACE(m);
     854
     855        /* large packets will spill into a temp buffer */
     856        iov[1].iov_base = au8Buf;
     857        iov[1].iov_len = sizeof(au8Buf);
     858
     859#if !defined(RT_OS_WINDOWS)
     860        {
     861            struct msghdr mh;
     862            memset(&mh, 0, sizeof(mh));
     863
     864            mh.msg_iov = iov;
     865            mh.msg_iovlen = 2;
     866            mh.msg_name = &addr;
     867            mh.msg_namelen = addrlen;
     868
     869            nread = recvmsg(so->s, &mh, 0);
     870        }
     871#else  /* RT_OS_WINDOWS */
     872        {
     873            DWORD nbytes; /* NB: can't use nread b/c of different size */
     874            DWORD flags;
     875            int status;
     876
     877            flags = 0;
     878            status = WSARecvFrom(so->s, iov, 2, &nbytes, &flags,
     879                                 (struct sockaddr *)&addr, &addrlen,
     880                                 NULL, NULL);
     881            nread = (status != SOCKET_ERROR) ? nbytes : -1;
     882        }
     883#endif
     884        if (nread >= 0)
     885        {
     886            if (nread <= iov[0].iov_len)
     887                m->m_len = nread;
     888            else
    879889            {
    880                 m_freem(pData, m);
    881                 return;
     890                m->m_len = iov[0].iov_len;
     891                m_append(pData, m, nread - iov[0].iov_len, iov[1].iov_base);
    882892            }
    883             fWithTemporalBuffer = true;
    884         }
    885         ret = recvfrom(so->s, pchBuffer, n, 0,
    886                        (struct sockaddr *)&addr, &addrlen);
    887         if (fWithTemporalBuffer)
    888         {
    889             if (ret > 0)
    890             {
    891                 m_copyback(pData, m, 0, ret, pchBuffer);
    892                 /*
    893                  * If we've met comporison below our size prediction was failed
    894                  * it's not fatal just we've allocated for nothing. (@todo add counter here
    895                  * to calculate how rare we here)
    896                  */
    897                 if(ret < slirp_size(pData) && !m->m_next)
    898                     Log(("NAT:udp: Expected size(%d) lesser than real(%d) and less minimal mbuf size(%d)\n",
    899                          n, ret, slirp_size(pData)));
    900             }
    901             /* we're freeing buffer anyway */
    902             RTMemFree(pchBuffer);
    903         }
    904         else
    905             m->m_len = ret;
    906 
    907         if (ret < 0)
    908         {
    909             u_char code = ICMP_UNREACH_PORT;
    910 
    911             if (errno == EHOSTUNREACH)
    912                 code = ICMP_UNREACH_HOST;
    913             else if (errno == ENETUNREACH)
    914                 code = ICMP_UNREACH_NET;
    915 
    916             m_freem(pData, m);
    917             if (   soIgnorableErrorCode(errno)
    918                 || errno == ENOTCONN)
    919             {
    920                 return;
    921             }
    922 
    923             Log2((" rx error, tx icmp ICMP_UNREACH:%i\n", code));
    924             icmp_error(pData, so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
    925             so->so_m = NULL;
    926         }
    927         else
    928         {
    929             Assert((m_length(m,NULL) == ret));
     893            Assert((m_length(m, NULL) == nread));
     894
    930895            /*
    931896             * Hack: domain name lookup will be used the most for UDP,
     
    939904                    so->so_expire = curtime + SO_EXPIRE;
    940905            }
     906
    941907            /*
    942908             *  last argument should be changed if Slirp will inject IP attributes
     
    947913                dnsproxy_answer(pData, so, m);
    948914
    949 #if 0
    950             if (m->m_len == len)
    951             {
    952                 m_inc(m, MINCSIZE);
    953                 m->m_len = 0;
    954             }
    955 #endif
    956 
    957915            /* packets definetly will be fragmented, could confuse receiver peer. */
    958             if (m_length(m, NULL) > if_mtu)
     916            if (nread > if_mtu)
    959917                m->m_flags |= M_SKIP_FIREWALL;
     918
    960919            /*
    961920             * If this packet was destined for CTL_ADDR,
     
    963922             */
    964923            udp_output(pData, so, m, &addr);
    965             SOCKET_UNLOCK(so);
    966         } /* rx error */
    967     } /* if ping packet */
     924        }
     925        else
     926        {
     927            m_freem(pData, m);
     928            so->so_m = NULL;
     929
     930            if (!soIgnorableErrorCode(errno))
     931            {
     932                u_char code;
     933                if (errno == EHOSTUNREACH)
     934                    code = ICMP_UNREACH_HOST;
     935                else if (errno == ENETUNREACH)
     936                    code = ICMP_UNREACH_NET;
     937                else
     938                    code = ICMP_UNREACH_PORT;
     939
     940                Log2((" rx error, tx icmp ICMP_UNREACH:%i\n", code));
     941                icmp_error(pData, so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
     942            }
     943        }
     944
     945        SOCKET_UNLOCK(so);
     946    }
    968947}
    969948
  • trunk/src/VBox/Devices/Network/slirp/socket.h

    r44528 r52154  
    158158
    159159#if defined(DECLARE_IOVEC) && !defined(HAVE_READV)
     160# if !defined(RT_OS_WINDOWS)
    160161struct iovec
    161162{
     
    163164    size_t iov_len;
    164165};
     166# else
     167/* make it congruent with WSABUF */
     168struct iovec
     169{
     170    ULONG iov_len;
     171    char *iov_base;
     172};
     173# endif
    165174#endif
    166175
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