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; }