4#include "Stroika/Foundation/StroikaPreComp.h"
12#if qStroika_Platform_POSIX
16#include <net/if_arp.h>
18#include <netinet/in.h>
20#include <sys/socket.h>
22#if qStroika_Platform_Linux
23#include <linux/ethtool.h>
24#include <linux/sockios.h>
25#include <linux/wireless.h>
26#elif qStroika_Platform_MacOS
29#include <sys/sysctl.h>
31#elif qStroika_Platform_Windows
46#include "Stroika/Foundation/Containers/Collection.h"
47#include "Stroika/Foundation/Containers/KeyedCollection.h"
48#include "Stroika/Foundation/Containers/Mapping.h"
51#include "Stroika/Foundation/Execution/Exceptions.h"
53#if qStroika_Platform_Windows
54#include "Stroika/Foundation/../Foundation/Execution/Platform/Windows/Exception.h"
60#include "Stroika/Foundation/IO/Network/ConnectionlessSocket.h"
71using namespace Stroika::Foundation::Memory;
72using namespace Stroika::Foundation::IO;
82#pragma comment(lib, "Iphlpapi.lib")
88 auto PrintMacAddr_ (
const uint8_t* macaddrBytes, [[maybe_unused]]
const uint8_t* macaddrBytesEnd) ->
String
90 Require (macaddrBytesEnd - macaddrBytes == 6);
92 (void)snprintf (buf,
sizeof (buf),
"%02x:%02x:%02x:%02x:%02x:%02x", macaddrBytes[0], macaddrBytes[1], macaddrBytes[2],
93 macaddrBytes[3], macaddrBytes[4], macaddrBytes[5]);
94 Assert (::strlen (buf) < std::size (buf));
108 sb <<
"SSID: "sv << fSSID;
109 sb <<
", state: "sv << fState;
110 sb <<
", connectionMode: "sv << fConnectionMode;
111 sb <<
", profileName: "sv << fProfileName;
112 sb <<
", BSSType: "sv << fBSSType;
113 sb <<
", MACAddress: "sv << fMACAddress;
114 sb <<
", physicalConnectionType: "sv << fPhysicalConnectionType;
116 sb <<
", securityEnabled: "sv << fSecurityEnabled;
117 sb <<
", 8021XEnabled: "sv << f8021XEnabled;
118 sb <<
", authAlgorithm: "sv << fAuthAlgorithm;
119 sb <<
", cipher: "sv << fCipher;
129String Interface::Bindings::ToString ()
const
133 sb <<
"boundAddressRanges: "sv << fAddressRanges;
134 sb <<
", boundAddresses: "sv << fAddresses;
148#if qStroika_Platform_POSIX
149 sb <<
", interfaceName: "sv << GetInterfaceName ();
159 sb <<
", type: "sv << *fType;
162 sb <<
", index: "sv << *
fIndex;
174 sb <<
", wirelessInfo: "sv << fWirelessInfo;
181 sb <<
", status: "sv << *
fStatus;
192#if qStroika_Platform_POSIX
196 optional<InternetAddress> GetInternetAddress_ (
const sockaddr* sa)
198 if (sa !=
nullptr and sa->sa_family == AF_INET) {
200 ::memcpy (&a, sa,
sizeof (a));
203 if (sa !=
nullptr and sa->sa_family == AF_INET6) {
205 ::memcpy (&a, sa,
sizeof (a));
213 optional<unsigned int> GetPrefixLength_ (
const sockaddr* netmask,
int family)
215 if (netmask ==
nullptr) {
218 sockaddr_storage ss{};
219#if qStroika_Platform_MacOS
220 ::memcpy (&ss, netmask, min<size_t> (netmask->sa_len, sizeof (ss)));
222 ::memcpy (&ss, netmask, family == AF_INET ?
sizeof (sockaddr_in) : sizeof (sockaddr_in6));
224 ss.ss_family =
static_cast<sa_family_t
> (family);
225 optional<InternetAddress> mask = GetInternetAddress_ (
reinterpret_cast<const sockaddr*
> (&ss));
229 unsigned int prefixLen{};
230 for (
bool b : mask->As<vector<bool>> ()) {
239#if qStroika_Platform_MacOS
242 optional<String> GetHardwareAddress_ (
const sockaddr* sa)
244 if (sa ==
nullptr or sa->sa_family != AF_LINK) {
247 alignas (sockaddr_dl) uint8_t buf[
sizeof (sockaddr_storage)]{};
248 ::memcpy (buf, sa, min<size_t> (sa->sa_len, sizeof (buf)));
249 const sockaddr_dl* sdl =
reinterpret_cast<const sockaddr_dl*
> (buf);
250 if (sdl->sdl_alen != 6 or offsetof (sockaddr_dl, sdl_data) + sdl->sdl_nlen + 6 >
sizeof (buf)) {
253 const uint8_t* mac =
reinterpret_cast<const uint8_t*
> (LLADDR (sdl));
254 return PrintMacAddr_ (mac, mac + 6);
259#if qStroika_Platform_Linux or qStroika_Platform_MacOS
265#if qStroika_Platform_Linux
267 static const filesystem::path kFileName_{
"/proc/net/route"};
276 for (
const Sequence<String>& line : reader.ReadMatrix (FileInputStream::New (kFileName_, IO::FileSystem::FileInputStream::eNotSeekable))) {
277 if (line.size () >= 3 and line[1] ==
"00000000"sv and not result.
ContainsKey (line[0])) {
279 swscanf (line[2].As<wstring> ().c_str (), L
"%02x%02x%02x%02x", &tmp[3], &tmp[2], &tmp[1], &tmp[0]);
280 result.
Add (line[0],
InternetAddress{
static_cast<byte> (tmp[0]),
static_cast<byte> (tmp[1]),
static_cast<byte> (tmp[2]),
281 static_cast<byte> (tmp[3])});
284#elif qStroika_Platform_MacOS
288 int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
291 for (
int tries = 0;; ++tries) {
293 buf.resize (len + len / 8 + 1024);
295 if (::sysctl (mib,
static_cast<u_int
> (std::size (mib)), buf.data (), &len,
nullptr, 0) == 0) {
298 if (errno != ENOMEM or tries == 3) {
304 for (
size_t offset = 0; offset +
sizeof (rt_msghdr) <= len;) {
306 ::memcpy (&rtm, buf.data () + offset, sizeof (rtm));
307 if (rtm.rtm_msglen == 0) {
310 size_t end = min<size_t> (offset + rtm.rtm_msglen, len);
311 optional<in_addr> dst;
312 optional<in_addr> gateway;
313 optional<in_addr> mask;
314 for (
size_t i = 0, a = offset +
sizeof (rtm); i < RTAX_MAX and a < end; ++i) {
315 if (not(rtm.rtm_addrs & (1 << i))) {
318 uint8_t saLen =
static_cast<uint8_t
> (buf[a]);
319 if (i == RTAX_DST or i == RTAX_GATEWAY or i == RTAX_NETMASK) {
322 ::memcpy (&sin, buf.data () + a, min (min<size_t> (saLen,
sizeof (sin)), end - a));
323 if (i == RTAX_NETMASK) {
326 else if (sin.sin_family == AF_INET) {
327 (i == RTAX_DST ? dst : gateway) = sin.sin_addr;
330 a += saLen > 0 ? (1 + ((saLen - 1) | (
sizeof (uint32_t) - 1))) : sizeof (uint32_t);
333 char name[IF_NAMESIZE]{};
334 if (dst and dst->s_addr == INADDR_ANY and not(rtm.rtm_flags & RTF_HOST) and (not mask or mask->s_addr == 0) and gateway and
335 ::if_indextoname (rtm.rtm_index, name) !=
nullptr) {
341 offset += rtm.rtm_msglen;
352 Interface GetInterfaces_POSIX_mkInterface_ (
int sd,
const char* name,
unsigned int flags,
358 if (
unsigned int index = ::if_nametoindex (name); index != 0) {
359 newInterface.
fIndex = index;
361#if qStroika_Platform_Linux
362 auto getWirelessFlag = [] (
int sd,
const char* name) ->
bool {
363#if defined(SIOCGIWNAME)
365 CString::Copy (pwrq.ifr_name, std::size (pwrq.ifr_name), name);
366 int r = ::ioctl (sd, SIOCGIWNAME, (
char*)&pwrq);
373 if (flags & IFF_LOOPBACK) {
374 newInterface.fType = Interface::Type::eLoopback;
376#if qStroika_Platform_Linux
377 else if (getWirelessFlag (sd, name)) {
378 newInterface.fType = Interface::Type::eWIFI;
383 newInterface.fType = Interface::Type::eWiredEthernet;
386#if qStroika_Platform_Linux
389 CString::Copy (tmp.ifr_name, std::size (tmp.ifr_name), name);
390 if (::ioctl (sd, SIOCGIFHWADDR, &tmp) == 0 and tmp.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
391 newInterface.
fHardwareAddress = PrintMacAddr_ (
reinterpret_cast<const uint8_t*
> (tmp.ifr_hwaddr.sa_data),
392 reinterpret_cast<const uint8_t*
> (tmp.ifr_hwaddr.sa_data) + 6);
397#if qStroika_Platform_Linux or qStroika_Platform_MacOS
403#if qStroika_Platform_Linux
404 auto getSpeed = [] (
int sd,
const char* name) -> optional<uint64_t> {
406 CString::Copy (ifreq.ifr_name, std::size (ifreq.ifr_name), name);
408 ifreq.ifr_data =
reinterpret_cast<caddr_t
> (&edata);
409 edata.cmd = ETHTOOL_GSET;
410 int r = ioctl (sd, SIOCETHTOOL, &ifreq);
412#if USE_NOISY_TRACE_IN_THIS_MODULE_
413 DbgTrace (
"No speed for interface {}, errno={}"_f, name, errno);
417 constexpr uint64_t kMegabit_ = 1000 * 1000;
418 switch (ethtool_cmd_speed (&edata)) {
420 return 10 * kMegabit_;
422 return 100 * kMegabit_;
424 return 1000 * kMegabit_;
426 return 2500 * kMegabit_;
428 return 10000 * kMegabit_;
439 if (flags & IFF_RUNNING) {
446#if qStroika_Platform_Linux
447 auto checkCarrierKnownSet = [] (
const char* id) ->
bool {
448#if !USE_NOISY_TRACE_IN_THIS_MODULE_
452 auto fs = FileInputStream::New (filesystem::path{
"/sys/class/net"} / id, IO::FileSystem::FileInputStream::eNotSeekable);
454 if (b.size () >= 1 and b[0] ==
static_cast<byte> (
'1')) {
462 if (checkCarrierKnownSet (name)) {
469#if USE_NOISY_TRACE_IN_THIS_MODULE_
470 DbgTrace (
"GetInterfaces_POSIX_mkInterface_ returns {}"_f, newInterface);
477 ifaddrs* ifa =
nullptr;
478 if (::getifaddrs (&ifa) != 0) {
481 [[maybe_unused]]
auto&& cleanupIfa =
Execution::Finally ([ifa] ()
noexcept { ::freeifaddrs (ifa); });
483 int sd = ::socket (PF_INET, SOCK_STREAM, 0);
485 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([sd] ()
noexcept { ::close (sd); });
496#if qStroika_Platform_Linux or qStroika_Platform_MacOS
497 GetDefaultGateways_ ();
502 for (
const ifaddrs* p = ifa; p !=
nullptr; p = p->ifa_next) {
503#if USE_NOISY_TRACE_IN_THIS_MODULE_
504 DbgTrace (
"interface: ifa_name={}; ifa_addr.sa_family = {}"_f, p->ifa_name, p->ifa_addr ==
nullptr ? -1 : p->ifa_addr->sa_family);
508 string deviceName{p->ifa_name};
509#if qStroika_Platform_Linux
510 if (
size_t colon = deviceName.find (
':'); colon != string::npos) {
511 deviceName.
erase (colon);
515 optional<Interface> prev = results.
Lookup (interfaceName);
516 Interface newInterface = prev ? *prev : GetInterfaces_POSIX_mkInterface_ (sd, deviceName.c_str (), p->ifa_flags, defaultGateways);
517 if (optional<InternetAddress> ia = GetInternetAddress_ (p->ifa_addr)) {
518 newInterface.
fBindings.fAddressRanges.Add (
CIDR{*ia, GetPrefixLength_ (p->ifa_netmask, p->ifa_addr->sa_family)});
519 newInterface.
fBindings.fAddresses.Add (*ia);
521#if qStroika_Platform_MacOS
523 if (optional<String> mac = GetHardwareAddress_ (p->ifa_addr)) {
527 results.
Add (newInterface);
534#if qStroika_Platform_Windows
547 : fDLL{::LoadLibrary (_T (
"wlanapi.dll"))}
549 Execution::ThrowIfNull (fDLL);
550 fWlanOpenHandle = (DWORD (WINAPI*) (_In_ DWORD dwClientVersion, _Reserved_ PVOID pReserved, _Out_ PDWORD pdwNegotiatedVersion,
551 _Out_ PHANDLE phClientHandle)) (::GetProcAddress (fDLL,
"WlanOpenHandle"));
553 (DWORD (WINAPI*) (_In_ HANDLE hClientHandle, _Reserved_ PVOID pReserved)) (::GetProcAddress (fDLL,
"WlanCloseHandle"));
554 fWlanFreeMemory = (DWORD (WINAPI*) (_In_ PVOID pMemory)) (::GetProcAddress (fDLL,
"WlanFreeMemory"));
555 fWlanEnumInterfaces =
556 (DWORD (WINAPI*) (_In_ HANDLE hClientHandle, _Reserved_ PVOID pReserved,
557 _Outptr_ PWLAN_INTERFACE_INFO_LIST * ppInterfaceList)) (::GetProcAddress (fDLL,
"WlanEnumInterfaces"));
558 fWlanQueryInterface =
559 (DWORD (WINAPI*) (_In_ HANDLE hClientHandle, _In_ CONST ::GUID * pInterfaceGuid, _In_ WLAN_INTF_OPCODE OpCode,
560 _Reserved_ PVOID pReserved, _Out_ PDWORD pdwDataSize, _Outptr_result_bytebuffer_ (*pdwDataSize) PVOID * ppData,
561 _Out_opt_ PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType)) (::GetProcAddress (fDLL,
"WlanQueryInterface"));
563 WLANAPI_ (
const WLANAPI_&) =
delete;
566 if (fDLL !=
nullptr) {
567 Verify (::FreeLibrary (fDLL));
571 DWORD (WINAPI* fWlanOpenHandle)
572 (_In_ DWORD dwClientVersion, _Reserved_ PVOID pReserved, _Out_ PDWORD pdwNegotiatedVersion, _Out_ PHANDLE phClientHandle) =
nullptr;
573 DWORD (WINAPI* fWlanCloseHandle)
574 (_In_ HANDLE hClientHandle, _Reserved_ PVOID pReserved) =
nullptr;
575 DWORD (WINAPI* fWlanFreeMemory)
576 (_In_ PVOID pMemory) =
nullptr;
577 DWORD (WINAPI* fWlanEnumInterfaces)
578 (_In_ HANDLE hClientHandle, _Reserved_ PVOID pReserved, _Outptr_ PWLAN_INTERFACE_INFO_LIST* ppInterfaceList) =
nullptr;
579 DWORD (WINAPI* fWlanQueryInterface)
580 (_In_ HANDLE hClientHandle, _In_ CONST ::GUID* pInterfaceGuid, _In_ WLAN_INTF_OPCODE OpCode, _Reserved_ PVOID pReserved, _Out_ PDWORD pdwDataSize,
581 _Outptr_result_bytebuffer_ (*pdwDataSize) PVOID* ppData, _Out_opt_ PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType) =
nullptr;
585 optional<uint64_t> fTransmitSpeedBaud;
586 optional<uint64_t> fReceiveLinkSpeedBaud;
593 static unique_ptr<WLANAPI_> sWlanAPI_;
594 static once_flag sOnceFlag_;
595 call_once (sOnceFlag_, [&] () { IgnoreExceptionsForCall (sWlanAPI_ = make_unique<WLANAPI_> ()) });
598 HANDLE hClient =
nullptr;
600 DWORD dwCurVersion = 0;
604 if (hClient !=
nullptr) {
605 sWlanAPI_->fWlanCloseHandle (hClient,
nullptr);
609 PWLAN_INTERFACE_INFO_LIST pIfList =
nullptr;
612 if (pIfList !=
nullptr) {
613 sWlanAPI_->fWlanFreeMemory (pIfList);
626 PWLAN_CONNECTION_ATTRIBUTES pConnectInfo{};
628 if (pConnectInfo !=
nullptr) {
629 sWlanAPI_->fWlanFreeMemory (pConnectInfo);
633 for (DWORD i = 0; i < pIfList->dwNumberOfItems; ++i) {
634 PWLAN_INTERFACE_INFO pIfInfo = (WLAN_INTERFACE_INFO*)&pIfList->InterfaceInfo[i];
635 WirelessInfoPlus_ wInfo;
640 case wlan_interface_state_not_ready:
641 return WirelessInfo::State::eNotReady;
642 case wlan_interface_state_connected:
643 return WirelessInfo::State::eConnected;
644 case wlan_interface_state_ad_hoc_network_formed:
645 return WirelessInfo::State::eAdHocNetworkFormed;
646 case wlan_interface_state_disconnecting:
647 return WirelessInfo::State::eDisconnecting;
648 case wlan_interface_state_disconnected:
649 return WirelessInfo::State::eDisconnected;
650 case wlan_interface_state_associating:
651 return WirelessInfo::State::eAssociating;
652 case wlan_interface_state_discovering:
653 return WirelessInfo::State::eDiscovering;
654 case wlan_interface_state_authenticating:
655 return WirelessInfo::State::eAuthenticating;
657 DbgTrace (
"Unknown state {}"_f,
static_cast<int> (s));
658 return WirelessInfo::State::eUnknown;
662 wInfo.fState = mapState (pIfInfo->isState);
666 if (pIfInfo->isState == wlan_interface_state_connected) {
668 DWORD connectInfoSize =
sizeof (WLAN_CONNECTION_ATTRIBUTES);
669 WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
671 sWlanAPI_->fWlanQueryInterface (hClient, &pIfInfo->InterfaceGuid, wlan_intf_opcode_current_connection,
nullptr,
672 &connectInfoSize, (PVOID*)&pConnectInfo, &opCode));
675 if (pConnectInfo->isState != pIfInfo->isState) {
676 DbgTrace (
"Not sure how these can differ (except for race condition) - but if they do, maybe worth looking into"_f);
681 case wlan_connection_mode_profile:
682 return WirelessInfo::ConnectionMode::eProfile;
683 case wlan_connection_mode_temporary_profile:
684 return WirelessInfo::ConnectionMode::eTemporaryProfile;
685 case wlan_connection_mode_discovery_secure:
686 return WirelessInfo::ConnectionMode::eDiscoverSecrure;
687 case wlan_connection_mode_discovery_unsecure:
688 return WirelessInfo::ConnectionMode::eDiscoverInsecure;
689 case wlan_connection_mode_auto:
690 return WirelessInfo::ConnectionMode::eAuto;
691 case wlan_connection_mode_invalid:
692 return WirelessInfo::ConnectionMode::eInvalid;
694 DbgTrace (
"Unknown connection mode {}"_f,
static_cast<int> (s));
695 return WirelessInfo::ConnectionMode::eUnknown;
698 wInfo.fConnectionMode = mapConnectionMode (pConnectInfo->wlanConnectionMode);
699 wInfo.fProfileName = pConnectInfo->strProfileName;
702 if (pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength != 0) {
704 span{
reinterpret_cast<const char*
> (pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID),
705 pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength});
710 case dot11_BSS_type_infrastructure:
711 return WirelessInfo::BSSType::eInfrastructure;
712 case dot11_BSS_type_independent:
713 return WirelessInfo::BSSType::eIndependent;
714 case dot11_BSS_type_any:
715 return WirelessInfo::BSSType::eAny;
717 DbgTrace (
"Unknown BSS mode {}"_f,
static_cast<int> (s));
718 return WirelessInfo::BSSType::eUnknown;
721 wInfo.fBSSType = mapBSSType (pConnectInfo->wlanAssociationAttributes.dot11BssType);
723 wInfo.fMACAddress = PrintMacAddr_ (std::begin (pConnectInfo->wlanAssociationAttributes.dot11Bssid),
724 std::end (pConnectInfo->wlanAssociationAttributes.dot11Bssid));
728 case dot11_phy_type_unknown:
729 return WirelessInfo::PhysicalConnectionType::eUnknown;
730 case dot11_phy_type_fhss:
731 return WirelessInfo::PhysicalConnectionType::eFHSS;
732 case dot11_phy_type_dsss:
733 return WirelessInfo::PhysicalConnectionType::eDSSS;
734 case dot11_phy_type_irbaseband:
735 return WirelessInfo::PhysicalConnectionType::eIRBaseBand;
736 case dot11_phy_type_ofdm:
737 return WirelessInfo::PhysicalConnectionType::e80211a;
738 case dot11_phy_type_hrdsss:
739 return WirelessInfo::PhysicalConnectionType::e80211b;
740 case dot11_phy_type_erp:
741 return WirelessInfo::PhysicalConnectionType::e80211g;
742 case dot11_phy_type_ht:
743 return WirelessInfo::PhysicalConnectionType::e80211n;
744 case dot11_phy_type_vht:
745 return WirelessInfo::PhysicalConnectionType::e80211ac;
746 case dot11_phy_type_dmg:
747 return WirelessInfo::PhysicalConnectionType::e80211ad;
748 case dot11_phy_type_he:
749 return WirelessInfo::PhysicalConnectionType::e80211ax;
751 DbgTrace (
"Unknown DOT11_PHY_TYPE {}"_f,
static_cast<int> (s));
752 return WirelessInfo::PhysicalConnectionType::eUnknown;
755 wInfo.fPhysicalConnectionType = mapPhysicalConnectionType (pConnectInfo->wlanAssociationAttributes.dot11PhyType);
757 wInfo.fSignalQuality = pConnectInfo->wlanAssociationAttributes.wlanSignalQuality;
760 const ULONG kMagicFactor_{1000};
761 wInfo.fTransmitSpeedBaud = pConnectInfo->wlanAssociationAttributes.ulTxRate * kMagicFactor_;
762 wInfo.fReceiveLinkSpeedBaud = pConnectInfo->wlanAssociationAttributes.ulRxRate * kMagicFactor_;
765 wInfo.fSecurityEnabled = pConnectInfo->wlanSecurityAttributes.bSecurityEnabled;
766 wInfo.f8021XEnabled = pConnectInfo->wlanSecurityAttributes.bOneXEnabled;
769 case DOT11_AUTH_ALGO_80211_OPEN:
770 return WirelessInfo::AuthAlgorithm::eOpen;
771 case DOT11_AUTH_ALGO_80211_SHARED_KEY:
772 return WirelessInfo::AuthAlgorithm::ePresharedKey;
773 case DOT11_AUTH_ALGO_WPA:
774 return WirelessInfo::AuthAlgorithm::eWPA;
775 case DOT11_AUTH_ALGO_WPA_PSK:
776 return WirelessInfo::AuthAlgorithm::eWPA_PSK;
777 case DOT11_AUTH_ALGO_WPA_NONE:
778 return WirelessInfo::AuthAlgorithm::eWPA_NONE;
779 case DOT11_AUTH_ALGO_RSNA:
780 return WirelessInfo::AuthAlgorithm::eRSNA;
781 case DOT11_AUTH_ALGO_RSNA_PSK:
782 return WirelessInfo::AuthAlgorithm::eRSNA_PSK;
784 DbgTrace (
"Unknown AuthAlgorithm {}"_f,
static_cast<int> (s));
785 return WirelessInfo::AuthAlgorithm::eUnknown;
788 wInfo.fAuthAlgorithm = mapAuthAlgorithm (pConnectInfo->wlanSecurityAttributes.dot11AuthAlgorithm);
790 auto mapCipher = [] (DOT11_CIPHER_ALGORITHM s) ->
String {
792 case DOT11_CIPHER_ALGO_NONE:
794 case DOT11_CIPHER_ALGO_WEP40:
796 case DOT11_CIPHER_ALGO_TKIP:
798 case DOT11_CIPHER_ALGO_CCMP:
800 case DOT11_CIPHER_ALGO_WEP104:
802 case DOT11_CIPHER_ALGO_WEP:
805 return "{}"_f(
static_cast<int> (s));
808 wInfo.fCipher = mapCipher (pConnectInfo->wlanSecurityAttributes.dot11CipherAlgorithm);
809 results.
Add (interfaceGUID, wInfo);
821 wirelessInfo2Merge = GetInterfaces_Windows_WirelessInfo_ ();
823 catch (
const std::system_error& e) {
824 if (Execution::Platform::Windows::IsWin32Error (e.code (), ERROR_SERVICE_NOT_ACTIVE)) {
833 ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS;
834 ULONG family = AF_UNSPEC;
837 ULONG ulOutBufLen =
static_cast<ULONG
> (buf.
GetSize ());
838 PIP_ADAPTER_ADDRESSES pAddresses =
reinterpret_cast<PIP_ADAPTER_ADDRESSES
> (buf.begin ());
844 DWORD dwRetVal = ::GetAdaptersAddresses (family, flags,
nullptr, pAddresses, &ulOutBufLen);
845 if (dwRetVal == NO_ERROR) {
846 for (PIP_ADAPTER_ADDRESSES currAddresses = pAddresses; currAddresses !=
nullptr; currAddresses = currAddresses->Next) {
854 if (memcmp (&currAddresses->NetworkGuid, &kZeroGUID_, sizeof (kZeroGUID_)) != 0) {
857 switch (currAddresses->IfType) {
858 case IF_TYPE_SOFTWARE_LOOPBACK:
859 newInterface.fType = Interface::Type::eLoopback;
861 case IF_TYPE_PROP_VIRTUAL:
864 case IF_TYPE_IEEE80211:
865 newInterface.fType = Interface::Type::eWIFI;
867 case IF_TYPE_ETHERNET_CSMACD:
868 if (newInterface.
fDescription->Contains (
"VirtualBox Host-Only Ethernet Adapter"sv) or
869 newInterface.
fDescription->Contains (
"Hyper-V Virtual Ethernet Adapter"sv)) {
874 newInterface.fType = Interface::Type::eWiredEthernet;
878 DbgTrace (
"Treating unknown currAddresses->IfType = {} type as eOther"_f, currAddresses->IfType);
879 newInterface.fType = Interface::Type::eOther;
882 if (currAddresses->TunnelType != TUNNEL_TYPE_NONE) {
883 if (newInterface.fType) {
884 DbgTrace (
"overwriting type {} with tunneltype"_f, newInterface.fType);
886 newInterface.fType = Interface::Type::eTunnel;
888 switch (currAddresses->OperStatus) {
890 newInterface.
fStatus = Memory::NullCoalesce (newInterface.
fStatus) +
893 case IfOperStatusDown:
894 newInterface.
fStatus = Memory::NullCoalesce (newInterface.
fStatus);
896 case IfOperStatusDormant:
897 case IfOperStatusLowerLayerDown:
903 DbgTrace (
"ignoring unrecognized status: {}"_f,
static_cast<int> (currAddresses->OperStatus));
906 for (PIP_ADAPTER_UNICAST_ADDRESS pu = currAddresses->FirstUnicastAddress; pu !=
nullptr; pu = pu->Next) {
908 if (sa.IsInternetAddress ()) {
909 newInterface.
fBindings.fAddressRanges.Add (
910 pu->OnLinkPrefixLength == 255 ? sa.GetInternetAddress () :
CIDR{sa.GetInternetAddress (), pu->OnLinkPrefixLength});
911 newInterface.
fBindings.fAddresses.Add (sa.GetInternetAddress ());
914 for (PIP_ADAPTER_ANYCAST_ADDRESS pa = currAddresses->FirstAnycastAddress; pa !=
nullptr; pa = pa->Next) {
916 if (sa.IsInternetAddress ()) {
917 newInterface.
fBindings.fAddressRanges.Add (sa.GetInternetAddress ());
918 newInterface.
fBindings.fAddresses.Add (sa.GetInternetAddress ());
922 for (PIP_ADAPTER_GATEWAY_ADDRESS_LH pa = currAddresses->FirstGatewayAddress; pa !=
nullptr; pa = pa->Next) {
924 if (sa.IsInternetAddress ()) {
926 if (not gws.Contains (sa.GetInternetAddress ())) {
927 gws += sa.GetInternetAddress ();
932 for (PIP_ADAPTER_DNS_SERVER_ADDRESS_XP pa = currAddresses->FirstDnsServerAddress; pa !=
nullptr; pa = pa->Next) {
934 if (sa.IsInternetAddress ()) {
936 if (not ds.Contains (sa.GetInternetAddress ())) {
937 ds += sa.GetInternetAddress ();
942 if (currAddresses->IfIndex != 0) {
943 newInterface.
fIndex = currAddresses->IfIndex;
945 else if (currAddresses->Ipv6IfIndex != 0) {
946 newInterface.
fIndex = currAddresses->Ipv6IfIndex;
948 if (currAddresses->PhysicalAddressLength == 6) {
949 newInterface.
fHardwareAddress = PrintMacAddr_ (currAddresses->PhysicalAddress, currAddresses->PhysicalAddress + 6);
952#if (NTDDI_VERSION >= NTDDI_WIN6)
957 if (newInterface.fType == Interface::Type::eWIFI) {
959 newInterface.fWirelessInfo = *owinfo;
974#if USE_NOISY_TRACE_IN_THIS_MODULE_
975 DbgTrace (
"newInterface={}"_f, newInterface);
977 results.
Add (newInterface);
980 else if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
984 else if (dwRetVal == ERROR_NO_DATA) {
985 DbgTrace (
"There are no network adapters enabled on the local system"_f);
988 Execution::ThrowSystemErrNo (dwRetVal);
991#if USE_NOISY_TRACE_IN_THIS_MODULE_
992 DbgTrace (
"returning {}"_f, results.MappedValues ());
1006#if USE_NOISY_TRACE_IN_THIS_MODULE_
1009#if qStroika_Platform_POSIX
1011#elif qStroika_Platform_Windows
1016#if USE_NOISY_TRACE_IN_THIS_MODULE_
1017 DbgTrace (
"returning {}"_f, results);
1025 return GetAll ().
Lookup (interfaceID);
1030#if USE_NOISY_TRACE_IN_THIS_MODULE_
1035 if (i.fBindings.fAddressRanges.Any ([&ia] (
CIDR c) { return c.GetRange ().Contains (ia); })) {
1036#if USE_NOISY_TRACE_IN_THIS_MODULE_
1037 DbgTrace (
"found interface {}"_f, i.fInterfaceID);
1042#if USE_NOISY_TRACE_IN_THIS_MODULE_
1043 DbgTrace (
"no interface contains {}"_f, ia);
1060 constexpr PortType kAnyPort_ = 9;
1063 withPort.sin6_scope_id = peer.
As<sockaddr_in6> ().sin6_scope_id;
1072 sockaddr_storage ss = usePeer.
As<sockaddr_storage> ();
1076 if (optional<SocketAddress> local = s.
GetLocalAddress (); local and local->IsInternetAddress ()) {
1077 return local->GetInternetAddress ();
1081 DbgTrace (
"GetLocalAddressToReach ({}) failed: {}"_f, peer, current_exception ());
#define AssertNotImplemented()
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
#define Stroika_ATTRIBUTE_INDETERMINATE
Stroika_ATTRIBUTE_INDETERMINATE is used where you would use a C++ attribute for a variable that is in...
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromSDKString(const SDKChar *from)
static String FromNarrowSDKString(const char *from)
a cross between Mapping<KEY, T> and Collection<T> and Set<T>
nonvirtual value_type LookupValue(ArgByValueType< KeyType > key, ArgByValueType< value_type > defaultValue=value_type{}) const
nonvirtual void erase(ArgByValueType< value_type > item)
nonvirtual bool Add(ArgByValueType< value_type > item)
nonvirtual optional< value_type > Lookup(ArgByValueType< KeyType > key) const
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual bool ContainsKey(ArgByValueType< key_type > key) const
nonvirtual optional< mapped_type > Lookup(ArgByValueType< key_type > key) const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
This COULD be easily used to read CSV files, or tab-delimited files, for example.
nonvirtual optional< IO::Network::SocketAddress > GetLocalAddress() const
nonvirtual PlatformNativeHandle GetNativeSocket() const
nonvirtual PortType GetPort() const
nonvirtual size_t GetRequiredSize() const
nonvirtual InternetAddress GetInternetAddress() const
nonvirtual bool IsInternetAddress() const
nonvirtual FamilyType GetAddressFamily() const
nonvirtual InterfacesByID GetAll()
nonvirtual optional< Interface > GetById(const Interface::SystemIDType &interfaceID)
nonvirtual optional< Interface > GetContainingAddress(const InternetAddress &ia)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual void GrowToSize_uninitialized(size_t nElements)
same as GrowToSize (), except leaves newly created elements uninitialized (requires is_trivially_copy...
nonvirtual size_t GetSize() const noexcept
void ThrowPOSIXErrNo(errno_t errNo=errno)
treats argument errNo as a POSIX errno value, and calls ThrowError () with an error_code constructed ...
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)
ConnectionlessSocket::Ptr New(SocketAddress::FamilyType family, Type socketKind, const optional< IPPROTO > &protocol=nullopt)
optional< InternetAddress > GetLocalAddressToReach(const SocketAddress &peer)
This machine's address for reaching peer - the local address a datagram sent to peer would carry,...
nonvirtual String ToString() const
optional< double > fSignalQuality
nonvirtual String ToString() const
optional< Containers::Set< Status > > fStatus
optional< Containers::Sequence< InternetAddress > > fDNSServers
optional< Containers::Sequence< InternetAddress > > fGateways
optional< uint64_t > fTransmitSpeedBaud
optional< Common::GUID > fNetworkGUID
optional< String > fDescription
SystemIDType fInterfaceID
optional< uint64_t > fReceiveLinkSpeedBaud
@ eDeviceVirtualInternalNetwork
optional< unsigned int > fIndex
optional< String > fHardwareAddress