115 lines
4.6 KiB
C++
115 lines
4.6 KiB
C++
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "platform/impl/network_interface.h"
|
|
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
|
|
#include "util/osp_logging.h"
|
|
|
|
namespace openscreen {
|
|
|
|
std::vector<InterfaceInfo> GetAllInterfaces() {
|
|
constexpr size_t INITIAL_BUFFER_SIZE = 15000;
|
|
ULONG outbuflen = INITIAL_BUFFER_SIZE;
|
|
std::vector<unsigned char> charbuf(INITIAL_BUFFER_SIZE);
|
|
DWORD ret = NO_ERROR;
|
|
constexpr int MAX_RETRIES = 5;
|
|
|
|
for (int i = 0; i < MAX_RETRIES; ++i) {
|
|
// TODO: This does not include the loopback interface. Decide if we need it.
|
|
ret = GetAdaptersAddresses(AF_UNSPEC /* get both v4/v6 addrs */,
|
|
GAA_FLAG_INCLUDE_PREFIX,
|
|
NULL,
|
|
reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data()),
|
|
&outbuflen);
|
|
if (ret == ERROR_BUFFER_OVERFLOW) {
|
|
charbuf.resize(outbuflen);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (ret != NO_ERROR) {
|
|
OSP_DVLOG << "GetAdapterAddresses failed err=" << ret;
|
|
return std::vector<InterfaceInfo>();
|
|
}
|
|
|
|
std::vector<InterfaceInfo> infos;
|
|
auto pcurraddrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data());
|
|
while (pcurraddrs != nullptr) {
|
|
// TODO: return the interfaces
|
|
OSP_DVLOG << "\tIfIndex=" << pcurraddrs->IfIndex;
|
|
OSP_DVLOG << "\tAdapter name=" << pcurraddrs->AdapterName;
|
|
|
|
// Ignore interfaces that are down
|
|
if (pcurraddrs->OperStatus == IfOperStatusDown) {
|
|
pcurraddrs = pcurraddrs->Next;
|
|
continue;
|
|
}
|
|
|
|
infos.emplace_back();
|
|
InterfaceInfo& info = infos.back();
|
|
|
|
info.index = pcurraddrs->IfIndex;
|
|
std::memcpy(info.hardware_address.data(), pcurraddrs->PhysicalAddress,
|
|
std::min((unsigned long)sizeof(info.hardware_address),
|
|
pcurraddrs->PhysicalAddressLength));
|
|
info.name = pcurraddrs->AdapterName;
|
|
|
|
// Determine the interface type
|
|
switch (pcurraddrs->IfType) {
|
|
case IF_TYPE_ETHERNET_CSMACD:
|
|
info.type = InterfaceInfo::Type::kEthernet;
|
|
break;
|
|
case IF_TYPE_IEEE80211:
|
|
info.type = InterfaceInfo::Type::kWifi;
|
|
break;
|
|
case IF_TYPE_SOFTWARE_LOOPBACK:
|
|
info.type = InterfaceInfo::Type::kLoopback;
|
|
break;
|
|
default:
|
|
info.type = InterfaceInfo::Type::kOther;
|
|
break;
|
|
}
|
|
|
|
auto punicast = pcurraddrs->FirstUnicastAddress;
|
|
if (punicast != nullptr) {
|
|
for (int i = 0; punicast != nullptr; ++i) {
|
|
if (punicast->Address.lpSockaddr->sa_family == AF_INET) {
|
|
sockaddr_in* sa_in = (sockaddr_in*)punicast->Address.lpSockaddr;
|
|
char buff[100];
|
|
DWORD bufflen = 100;
|
|
OSP_DVLOG << "\tIPV4:" << inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen);
|
|
OSP_DVLOG << "\t prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
|
|
IPAddress ip(IPAddress::Version::kV4,
|
|
reinterpret_cast<uint8_t*>(&(sa_in->sin_addr.s_addr)));
|
|
info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
|
|
} else if (punicast->Address.lpSockaddr->sa_family == AF_INET6) {
|
|
sockaddr_in6* sa_in6 = (sockaddr_in6*)punicast->Address.lpSockaddr;
|
|
char buff[100];
|
|
DWORD bufflen = 100;
|
|
OSP_DVLOG << "\tIPV6:" << inet_ntop(AF_INET6, &(sa_in6->sin6_addr), buff, bufflen);
|
|
OSP_DVLOG << "\t prefixsize=" << (unsigned int)punicast->OnLinkPrefixLength;
|
|
IPAddress ip(IPAddress::Version::kV6,
|
|
reinterpret_cast<uint8_t*>(&(sa_in6->sin6_addr.s6_addr)));
|
|
info.addresses.emplace_back(ip, punicast->OnLinkPrefixLength);
|
|
} else {
|
|
OSP_DVLOG << "\tUNSPEC";
|
|
}
|
|
punicast = punicast->Next;
|
|
}
|
|
}
|
|
OSP_DVLOG << "\tIfType=" << pcurraddrs->IfType;
|
|
OSP_DVLOG << "\tDescription=" << pcurraddrs->Description;
|
|
OSP_DVLOG << "\tFreindlyName=" << pcurraddrs->FriendlyName;
|
|
pcurraddrs = pcurraddrs->Next;
|
|
}
|
|
return infos;
|
|
}
|
|
|
|
} // namespace openscreen
|