| // 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); |
| PIP_ADAPTER_ADDRESSES paddrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(charbuf.data()); |
| 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, |
| paddrs, |
| &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 = paddrs; |
| 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 |