UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
netadapter_win32.cpp
Go to the documentation of this file.
1// Copyright (C) 2024+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
2// Redistribution only with this Copyright remark. Last modified: 2025-03-31
9#include <UPnPsdk/synclog.hpp>
11#include <umock/iphlpapi.hpp>
13
14
15namespace UPnPsdk {
16
17CNetadapter_platform::CNetadapter_platform(){
18 TRACE2(this, " Construct CNetadapter_platform()") //
19}
20
21CNetadapter_platform::~CNetadapter_platform() {
22 TRACE2(this, " Destruct CNetadapter_platform()")
23 this->free_adaptaddrs();
24}
25
26void CNetadapter_platform::get_first() {
27 // For the structure look at
28 // REF:_https://docs.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_addresses_lh
29 TRACE2(this, " Executing CNetadapter_platform::get_first()")
30
31 ULONG adapts_size{};
32 // Get Adapters addresses required size. Check with adapts_size = 0
33 // will fail with ERROR_BUFFER_OVERFLOW but returns required size.
34 ULONG ret = umock::iphlpapi_h.GetAdaptersAddresses(
35 AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, nullptr,
36 m_adapt_first, &adapts_size);
37 if (ret != ERROR_BUFFER_OVERFLOW) {
38 throw std::runtime_error(
39 UPnPsdk_LOGEXCEPT("MSG1120") "failed to get buffer size for list "
40 "of adapters (errid=" +
41 std::to_string(ret) + ").");
42 }
43
44 this->free_adaptaddrs();
45
46 // Allocate enough memory that size was detected above.
47 m_adapt_first = static_cast<PIP_ADAPTER_ADDRESSES>(malloc(adapts_size));
48 if (m_adapt_first == nullptr) {
49 throw std::runtime_error(UPnPsdk_LOGEXCEPT(
50 "MSG1121") "failed to allocate memory for list of adapters.");
51 }
52 // Do the call that will actually return the info.
53 ret = umock::iphlpapi_h.GetAdaptersAddresses(
54 AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, nullptr,
55 m_adapt_first, &adapts_size);
56 if (ret != ERROR_SUCCESS) {
57 throw std::runtime_error(
58 UPnPsdk_LOGEXCEPT(
59 "MSG1122") "failed to find list of adapters (errid=" +
60 std::to_string(ret) + ").");
61 }
62
63 m_adapt_current = m_adapt_first;
64 m_unicastaddr_current = m_adapt_current->FirstUnicastAddress;
65}
66
68 // A network adapter has several IP addresses. First the address list must
69 // be parsed and when at its end the next adapter must be selected. When
70 // entering this function there is no synchronous information as given in a
71 // loop (or two nested). I have to excamine the current state for the next
72 // action. Writing down a state table on paper has helped me.
73 TRACE2(this, " Executing CNetadapter_platform::get_next()")
74 if (m_adapt_current == nullptr) {
75 m_unicastaddr_current = nullptr;
76 return false;
77 }
78 if (m_adapt_current != nullptr && m_unicastaddr_current == nullptr) {
79 m_adapt_current = m_adapt_current->Next;
80 if (m_adapt_current == nullptr) {
81 return false;
82 } else {
83 m_unicastaddr_current = m_adapt_current->FirstUnicastAddress;
84 return true;
85 }
86 }
87 if (m_adapt_current != nullptr && m_unicastaddr_current != nullptr) {
88 m_unicastaddr_current = m_unicastaddr_current->Next;
89 if (m_unicastaddr_current == nullptr) {
90 m_adapt_current = m_adapt_current->Next;
91 if (m_adapt_current == nullptr) {
92 return false;
93 } else {
94 m_unicastaddr_current = m_adapt_current->FirstUnicastAddress;
95 return true;
96 }
97 } else {
98 return true;
99 }
100 }
101 throw std::invalid_argument(
102 UPnPsdk_LOGEXCEPT(
103 "MSG1123") "Failed to get next network adapter entry. This should "
104 "never "
105 "come up and must be fixed. m_adapt_current=" +
106 std::to_string(reinterpret_cast<uintptr_t>(m_adapt_current)) +
107 ", m_unicastaddr_current=" +
108 std::to_string(reinterpret_cast<uintptr_t>(m_unicastaddr_current)) +
109 "\n");
110}
111
112std::string CNetadapter_platform::name() const {
113 TRACE2(this, " Executing CNetadapter_platform::name()")
114 if (m_adapt_current == nullptr)
115 return "";
116
117 /* Partial fix for Windows: Friendly name is wchar string, but currently
118 * compatible names are char string. For now try to convert it, which will
119 * work with many (but not all) adapters. A full fix would require a lot of
120 * big changes (using UTF-8 as planned). */
121
122 // If I need this constant more than once, I'll make it global, Here it is
123 // used for the friendly name of a network adapter and is compatible to old
124 // gIF_NAME size. ('grep' is your friend)
125 constexpr size_t LINE_SIZE{180};
126
127 char if_name[LINE_SIZE]{};
128 size_t i;
129 wcstombs_s(&i, if_name, sizeof(if_name), m_adapt_current->FriendlyName,
130 sizeof(if_name) - 1); // -1 so the appended '\0' doesn't fall
131 // outside the allocated buffer
132 return if_name;
133}
134
135void CNetadapter_platform::sockaddr(SSockaddr& a_saddr) const {
136 TRACE2(this, " Executing CNetadapter_platform::sockaddr()")
137 if (m_adapt_current == nullptr) {
138 // If no information found then return an empty netaddress.
139 a_saddr = "";
140 } else {
141 // Copy address of the network adapter
142 memcpy(&a_saddr.ss,
143 reinterpret_cast<sockaddr_storage*>(
144 m_unicastaddr_current->Address.lpSockaddr),
145 sizeof(a_saddr.ss));
146 }
147}
148
149void CNetadapter_platform::socknetmask(SSockaddr& a_snetmask) const {
150 TRACE2(this, " Executing CNetadapter_platform::socknetmask()")
151 if (m_adapt_current != nullptr) {
152 bitmask_to_netmask(reinterpret_cast<sockaddr_storage*>(
153 m_unicastaddr_current->Address.lpSockaddr),
154 m_unicastaddr_current->OnLinkPrefixLength,
155 a_snetmask);
156 }
157}
158
159unsigned int CNetadapter_platform::bitmask() const {
160 TRACE2(this, " Executing CNetadapter_platform::bitmask()")
161 if (m_adapt_current == nullptr)
162 return 0;
163
164 return m_unicastaddr_current->OnLinkPrefixLength;
165}
166
167unsigned int CNetadapter_platform::index() const {
168 TRACE2(this, " Executing CNetadapter_platform::index()")
169 if (m_adapt_current == nullptr)
170 return 0;
171 // No matter if the adapter supports only IPv4 or only IPv6 or both, the
172 // adapter index should be always the same.
173 if (m_adapt_current->IfIndex != 0) // IPv4 interface
174 return m_adapt_current->IfIndex;
175 if (m_adapt_current->Ipv6IfIndex != 0) // IPv6 interface
176 return m_adapt_current->Ipv6IfIndex;
177 return 0; // neither IPv4 nor IPv6
178}
179
180
181// Private helper methods
182// ----------------------
183//
184void CNetadapter_platform::free_adaptaddrs() noexcept {
185 TRACE2(this, " Executing CNetadapter_platform::free_adaptaddrs()")
186 if (m_adapt_first != nullptr) {
187 free(m_adapt_first);
188 m_adapt_first = nullptr;
189 }
190 m_adapt_current = nullptr;
191 m_unicastaddr_current = nullptr;
192}
193
194inline void CNetadapter_platform::reset() noexcept {
195 TRACE2(this, " Executing CNetadapter_platform::reset()")
196 m_adapt_current = m_adapt_first;
197 m_unicastaddr_current = m_adapt_current == nullptr
198 ? nullptr
199 : m_adapt_current->FirstUnicastAddress;
200}
201
202} // namespace UPnPsdk
#define LINE_SIZE
Definition API.hpp:45
void sockaddr(SSockaddr &a_saddr) const override
Get socket address from current selected list entry.
void socknetmask(SSockaddr &a_snetmask) const override
Get socket address netmask from current selected list entry.
void reset() noexcept override
Reset pointer and point to the first entry of the local network adapter list if available.
bool get_next() override
Select next entry from the network adapter list that was initial loaded with get_first().
std::string name() const override
Get network adapter name from current selected list entry.
unsigned int bitmask() const override
Get prefix length from the ip address of the current selected local network adapter.
void get_first() override
Load a list of network adapters from the operating system and select its first entry.
unsigned int index() const override
Get index number from current selected list entry.
void bitmask_to_netmask(const ::sockaddr_storage *a_saddr, const unsigned int a_prefixlength, SSockaddr &a_saddrObj)
Get network address mask from address prefix bit number.
Reengineered Object Oriented UPnP+ program code.
Manage information about network adapters.
Define macro for synced logging to the console for detailed info and debug.