示例#1
0
int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
{
    int rc = VINF_SUCCESS;
    size_t cbNeeded;
    char *pBuf, *pNext;
    int aiMib[6];
    unsigned short u16DefaultIface = 0; /* initialized to shut up gcc */

    /* Get the index of the interface associated with default route. */
    rc = getDefaultIfaceIndex(&u16DefaultIface);
    if (RT_FAILURE(rc))
        return rc;

    aiMib[0] = CTL_NET;
    aiMib[1] = PF_ROUTE;
    aiMib[2] = 0;
    aiMib[3] = 0;       /* address family */
    aiMib[4] = NET_RT_IFLIST;
    aiMib[5] = 0;

    if (sysctl(aiMib, 6, NULL, &cbNeeded, NULL, 0) < 0)
    {
        Log(("NetIfList: Failed to get estimate for list size (errno=%d).\n", errno));
        return RTErrConvertFromErrno(errno);
    }
    if ((pBuf = (char*)RTMemAlloc(cbNeeded)) == NULL)
        return VERR_NO_MEMORY;
    if (sysctl(aiMib, 6, pBuf, &cbNeeded, NULL, 0) < 0)
    {
        RTMemFree(pBuf);
        Log(("NetIfList: Failed to retrieve interface table (errno=%d).\n", errno));
        return RTErrConvertFromErrno(errno);
    }

    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock < 0)
    {
        RTMemFree(pBuf);
        Log(("NetIfList: socket() -> %d\n", errno));
        return RTErrConvertFromErrno(errno);
    }

    PDARWINETHERNIC pNIC;
    PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();

    char *pEnd = pBuf + cbNeeded;
    for (pNext = pBuf; pNext < pEnd;)
    {
        struct if_msghdr *pIfMsg = (struct if_msghdr *)pNext;

        if (pIfMsg->ifm_type != RTM_IFINFO)
        {
            Log(("NetIfList: Got message %u while expecting %u.\n",
                 pIfMsg->ifm_type, RTM_IFINFO));
            rc = VERR_INTERNAL_ERROR;
            break;
        }
        struct sockaddr_dl *pSdl = (struct sockaddr_dl *)(pIfMsg + 1);

        size_t cbNameLen = pSdl->sdl_nlen + 1;
        Assert(pSdl->sdl_nlen < sizeof(pNIC->szBSDName));
        for (pNIC = pEtherNICs; pNIC; pNIC = pNIC->pNext)
            if (   !strncmp(pSdl->sdl_data, pNIC->szBSDName, pSdl->sdl_nlen)
                && pNIC->szBSDName[pSdl->sdl_nlen] == '\0')
            {
                cbNameLen = strlen(pNIC->szName) + 1;
                break;
            }
        PNETIFINFO pNew = (PNETIFINFO)RTMemAllocZ(RT_OFFSETOF(NETIFINFO, szName[cbNameLen]));
        if (!pNew)
        {
            rc = VERR_NO_MEMORY;
            break;
        }
        memcpy(pNew->MACAddress.au8, LLADDR(pSdl), sizeof(pNew->MACAddress.au8));
        pNew->enmMediumType = NETIF_T_ETHERNET;
        Assert(sizeof(pNew->szShortName) > pSdl->sdl_nlen);
        memcpy(pNew->szShortName, pSdl->sdl_data, RT_MIN(pSdl->sdl_nlen, sizeof(pNew->szShortName) - 1));

        /*
         * If we found the adapter in the list returned by
         * DarwinGetEthernetControllers() copy the name and UUID from there.
         */
        if (pNIC)
        {
            memcpy(pNew->szName, pNIC->szName, cbNameLen);
            pNew->Uuid = pNIC->Uuid;
        }
        else
        {
            memcpy(pNew->szName, pSdl->sdl_data, pSdl->sdl_nlen);
            /* Generate UUID from name and MAC address. */
            RTUUID uuid;
            RTUuidClear(&uuid);
            memcpy(&uuid, pNew->szShortName, RT_MIN(cbNameLen, sizeof(uuid)));
            uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
            uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
            memcpy(uuid.Gen.au8Node, pNew->MACAddress.au8, sizeof(uuid.Gen.au8Node));
            pNew->Uuid = uuid;
        }

        pNext += pIfMsg->ifm_msglen;
        while (pNext < pEnd)
        {
            struct ifa_msghdr *pIfAddrMsg = (struct ifa_msghdr *)pNext;

            if (pIfAddrMsg->ifam_type != RTM_NEWADDR)
                break;
            extractAddressesToNetInfo(pIfAddrMsg->ifam_addrs,
                                      (char *)(pIfAddrMsg + 1),
                                      pIfAddrMsg->ifam_msglen + (char *)pIfAddrMsg,
                                      pNew);
            pNext += pIfAddrMsg->ifam_msglen;
        }

        if (pSdl->sdl_type == IFT_ETHER)
        {
            struct ifreq IfReq;
            RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), pNew->szShortName);
            if (ioctl(sock, SIOCGIFFLAGS, &IfReq) < 0)
            {
                Log(("NetIfList: ioctl(SIOCGIFFLAGS) -> %d\n", errno));
                pNew->enmStatus = NETIF_S_UNKNOWN;
            }
            else
                pNew->enmStatus = (IfReq.ifr_flags & IFF_UP) ? NETIF_S_UP : NETIF_S_DOWN;

            HostNetworkInterfaceType_T enmType;
            if (strncmp(pNew->szName, RT_STR_TUPLE("vboxnet")))
                enmType = HostNetworkInterfaceType_Bridged;
            else
                enmType = HostNetworkInterfaceType_HostOnly;

            ComObjPtr<HostNetworkInterface> IfObj;
            IfObj.createObject();
            if (SUCCEEDED(IfObj->init(Bstr(pNew->szName), enmType, pNew)))
            {
                /* Make sure the default interface gets to the beginning. */
                if (pIfMsg->ifm_index == u16DefaultIface)
                    list.push_front(IfObj);
                else
                    list.push_back(IfObj);
            }
        }
        RTMemFree(pNew);
    }
    for (pNIC = pEtherNICs; pNIC;)
    {
        void *pvFree = pNIC;
        pNIC = pNIC->pNext;
        RTMemFree(pvFree);
    }
    close(sock);
    RTMemFree(pBuf);
    return rc;
}
int SoapyRPCSocket::multicastJoin(const std::string &group, const bool loop, const int ttl, int iface)
{
    /*
     * Multicast join docs:
     * http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html
     * http://www.tenouk.com/Module41c.html
     */

    //lookup group url
    SoapyURL urlObj(group);
    SockAddrData addr;
    const auto errorMsg = urlObj.toSockAddr(addr);
    if (not errorMsg.empty())
    {
        this->reportError("getaddrinfo("+group+")", errorMsg);
        return -1;
    }

    //create socket if null
    if (this->null()) _sock = ::socket(addr.addr()->sa_family, SOCK_DGRAM, 0);
    if (this->null()) return -1;
    int ret = 0;

    int loopInt = loop?1:0;

    switch(addr.addr()->sa_family)
    {
    case AF_INET: {

        //setup IP_MULTICAST_LOOP
        ret = ::setsockopt(_sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char *)&loopInt, sizeof(loopInt));
        if (ret != 0)
        {
            this->reportError("setsockopt(IP_MULTICAST_LOOP)");
            return -1;
        }

        //setup IP_MULTICAST_TTL
        ret = ::setsockopt(_sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&ttl, sizeof(ttl));
        if (ret != 0)
        {
            this->reportError("setsockopt(IP_MULTICAST_TTL)");
            return -1;
        }

        //setup IP_ADD_MEMBERSHIP
        auto *addr_in = (const struct sockaddr_in *)addr.addr();
        struct ip_mreq mreq;
        mreq.imr_multiaddr = addr_in->sin_addr;
        mreq.imr_interface.s_addr = INADDR_ANY;
        ret = ::setsockopt(_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq));
        if (ret != 0)
        {
            this->reportError("setsockopt(IP_ADD_MEMBERSHIP)");
            return -1;
        }
        break;
    }
    case AF_INET6: {

        //setup IPV6_MULTICAST_LOOP
        ret = ::setsockopt(_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char *)&loopInt, sizeof(loopInt));
        if (ret != 0)
        {
            this->reportError("setsockopt(IPV6_MULTICAST_LOOP)");
            return -1;
        }

        //setup IPV6_MULTICAST_HOPS
        ret = ::setsockopt(_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&ttl, sizeof(ttl));
        if (ret != 0)
        {
            this->reportError("setsockopt(IPV6_MULTICAST_HOPS)");
            return -1;
        }

        //setup IPV6_MULTICAST_IF
        if (iface == 0) iface = getDefaultIfaceIndex();
        if (iface != 0)
        {
            ret = ::setsockopt(_sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const char *)&iface, sizeof(iface));
            if (ret != 0)
            {
                this->reportError("setsockopt(IPV6_MULTICAST_IF)");
                return -1;
            }
        }

        //setup IPV6_ADD_MEMBERSHIP
        auto *addr_in6 = (const struct sockaddr_in6 *)addr.addr();
        struct ipv6_mreq mreq6;
        mreq6.ipv6mr_multiaddr = addr_in6->sin6_addr;
        mreq6.ipv6mr_interface = iface;
        ret = ::setsockopt(_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq6, sizeof(mreq6));
        if (ret != 0)
        {
            this->reportError("setsockopt(IPV6_ADD_MEMBERSHIP)");
            return -1;
        }
        break;
    }
    default:
        break;
    }

    return 0;
}