|
| 1 | +#include "netinterfaces.h" |
| 2 | +#include "loguru/loguru.hpp" |
| 3 | + |
| 4 | +using lslboost::asio::ip::address_v4; |
| 5 | + |
| 6 | +lslboost::asio::ip::address_v6 sinaddr_to_asio(sockaddr_in6 *addr) { |
| 7 | + lslboost::asio::ip::address_v6::bytes_type buf; |
| 8 | + memcpy(buf.data(), addr->sin6_addr.s6_addr, sizeof(addr->sin6_addr)); |
| 9 | + return lslboost::asio::ip::make_address_v6(buf, addr->sin6_scope_id); |
| 10 | +} |
| 11 | + |
| 12 | +#if defined(_WIN32) |
| 13 | +#undef UNICODE |
| 14 | +#include <winsock2.h> |
| 15 | +// Headers that need to be included after winsock2.h: |
| 16 | +#include <iphlpapi.h> |
| 17 | +#include <ws2ipdef.h> |
| 18 | + |
| 19 | +typedef IP_ADAPTER_UNICAST_ADDRESS_LH Addr; |
| 20 | +typedef IP_ADAPTER_ADDRESSES *AddrList; |
| 21 | + |
| 22 | +std::vector<lsl::netif> lsl::get_local_interfaces() { |
| 23 | + // It's a windows machine, we assume it has 512KB free memory |
| 24 | + DWORD outBufLen = 1 << 19; |
| 25 | + AddrList ifaddrs = (AddrList) new char[outBufLen]; |
| 26 | + |
| 27 | + std::vector<lsl::netif> ret; |
| 28 | + |
| 29 | + ULONG res = GetAdaptersAddresses(AF_UNSPEC, |
| 30 | + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, ifaddrs, |
| 31 | + &outBufLen); |
| 32 | + |
| 33 | + if (res == NO_ERROR) { |
| 34 | + for (AddrList addr = ifaddrs; addr != 0; addr = addr->Next) { |
| 35 | + // Interface isn't up or doesn't support multicast? Skip it. |
| 36 | + LOG_F(INFO, "netif '%s' (status: %d, multicast: %d", addr->AdapterName, |
| 37 | + addr->OperStatus, !addr->NoMulticast); |
| 38 | + if (addr->OperStatus != IfOperStatusUp) continue; |
| 39 | + if (addr->NoMulticast) continue; |
| 40 | + |
| 41 | + lsl::netif if_; |
| 42 | + if_.name = addr->AdapterName; |
| 43 | + if_.ifindex = addr->IfIndex; |
| 44 | + |
| 45 | + // Find the first IPv4 address |
| 46 | + if (addr->Ipv4Enabled) { |
| 47 | + for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) { |
| 48 | + if (uaddr->Address.lpSockaddr->sa_family != AF_INET) continue; |
| 49 | + |
| 50 | + if_.addr = lslboost::asio::ip::make_address_v4( |
| 51 | + ntohl(reinterpret_cast<sockaddr_in *>(uaddr->Address.lpSockaddr) |
| 52 | + ->sin_addr.s_addr)); |
| 53 | + ret.emplace_back(std::move(if_)); |
| 54 | + break; |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + if (addr->Ipv6Enabled) { |
| 59 | + LOG_F(INFO, "\tIPv6 ifindex %d", if_.ifindex); |
| 60 | + for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) { |
| 61 | + if (uaddr->Address.lpSockaddr->sa_family != AF_INET6) continue; |
| 62 | + |
| 63 | + if_.addr = sinaddr_to_asio( |
| 64 | + reinterpret_cast<sockaddr_in6 *>(uaddr->Address.lpSockaddr)); |
| 65 | + ret.emplace_back(std::move(if_)); |
| 66 | + break; |
| 67 | + } |
| 68 | + } |
| 69 | + } |
| 70 | + } else { |
| 71 | + LOG_F(ERROR, "Couldn't enumerate network interfaces: %d", res); |
| 72 | + } |
| 73 | + delete[]((char *)ifaddrs); |
| 74 | + return ret; |
| 75 | +} |
| 76 | +#elif defined(__APPLE__) || defined(__linux__) |
| 77 | +#include <arpa/inet.h> |
| 78 | +#include <ifaddrs.h> |
| 79 | +#include <map> |
| 80 | +#include <net/if.h> |
| 81 | +#include <sys/types.h> |
| 82 | + |
| 83 | +std::vector<lsl::netif> lsl::get_local_interfaces() { |
| 84 | + std::vector<lsl::netif> res; |
| 85 | + ifaddrs *ifs; |
| 86 | + if (getifaddrs(&ifs)) { |
| 87 | + LOG_F(ERROR, "Couldn't enumerate network interfaces: %d", errno); |
| 88 | + return res; |
| 89 | + } |
| 90 | + for (auto addr = ifs; addr != nullptr; addr = addr->ifa_next) { |
| 91 | + // No address? Skip. |
| 92 | + if (addr->ifa_addr == nullptr) continue; |
| 93 | + LOG_F(INFO, "netif '%s' (status: %d, multicast: %d, broadcast: %d)", addr->ifa_name, |
| 94 | + addr->ifa_flags & IFF_MULTICAST, addr->ifa_flags & IFF_UP, |
| 95 | + addr->ifa_flags & IFF_BROADCAST); |
| 96 | + // Interface doesn't support multicast? Skip. |
| 97 | + if (!(addr->ifa_flags & IFF_MULTICAST)) continue; |
| 98 | + // Interface isn't active? Skip. |
| 99 | + if (!(addr->ifa_flags & IFF_UP)) continue; |
| 100 | + |
| 101 | + lsl::netif if_; |
| 102 | + |
| 103 | + if (addr->ifa_addr->sa_family == AF_INET) { |
| 104 | + if_.addr = lslboost::asio::ip::make_address_v4( |
| 105 | + ntohl(reinterpret_cast<sockaddr_in *>(addr->ifa_addr)->sin_addr.s_addr)); |
| 106 | + LOG_F(INFO, "\tIPv4 addr: %x", if_.addr.to_v4().to_uint()); |
| 107 | + } else if (addr->ifa_addr->sa_family == AF_INET6) { |
| 108 | + if_.addr = sinaddr_to_asio(reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr)); |
| 109 | + LOG_F(INFO, "\tIPv6 addr: %s", if_.addr.to_string().c_str()); |
| 110 | + } else |
| 111 | + continue; |
| 112 | + |
| 113 | + if_.ifindex = if_nametoindex(addr->ifa_name); |
| 114 | + res.emplace_back(std::move(if_)); |
| 115 | + } |
| 116 | + freeifaddrs(ifs); |
| 117 | + return res; |
| 118 | +} |
| 119 | +#else |
| 120 | + |
| 121 | +std::vector<lsl::netif> get_interface_addresses() { |
| 122 | + LOG_F(WARN, "No implementation to enumerate network interfaces found."); |
| 123 | + return std::vector<lsl::netif>(); |
| 124 | +} |
| 125 | +#endif |
0 commit comments