6#ifndef WIN32_LEAN_AND_MEAN
7#define WIN32_LEAN_AND_MEAN
28constexpr std::string_view kNpcapDevicePrefix = R
"(\Device\NPF_)";
34std::wstring Utf8ToWide(
const std::string& value)
41 if (value.size() >
static_cast<std::size_t
>(std::numeric_limits<int>::max()))
46 const int sourceLength =
static_cast<int>(value.size());
47 const int requiredLength = MultiByteToWideChar(
55 if (requiredLength <= 0)
60 std::wstring result(
static_cast<std::size_t
>(requiredLength), L
'\0');
62 const int convertedLength = MultiByteToWideChar(
70 if (convertedLength != requiredLength)
82std::string NormalizeWindowsInterfaceName(
const std::string& interface)
84 if (interface.starts_with(kNpcapDevicePrefix))
86 return interface.substr(kNpcapDevicePrefix.size());
95 if (interface.empty())
97 throw SocketError(
"Interface name cannot be empty");
100 const std::string normalizedInterface = NormalizeWindowsInterfaceName(interface);
101 const std::wstring wideInterface = Utf8ToWide(normalizedInterface);
103 ULONG bufferSize = 15U * 1024U;
104 std::vector<std::uint8_t>
buffer(bufferSize);
106 PIP_ADAPTER_ADDRESSES adapters =
nullptr;
107 ULONG result = ERROR_BUFFER_OVERFLOW;
109 while (result == ERROR_BUFFER_OVERFLOW)
111 buffer.resize(bufferSize);
112 adapters =
reinterpret_cast<PIP_ADAPTER_ADDRESSES
>(
buffer.data());
114 result = GetAdaptersAddresses(
122 if (result != NO_ERROR)
124 throw SocketError(
"Failed to enumerate Windows network interfaces: error " +
125 std::to_string(result));
128 for (
const IP_ADAPTER_ADDRESSES* adapter = adapters;
130 adapter = adapter->Next)
132 const bool adapterNameMatches =
133 adapter->AdapterName !=
nullptr && normalizedInterface == adapter->AdapterName;
135 const bool friendlyNameMatches =
136 adapter->FriendlyName !=
nullptr &&
137 !wideInterface.empty() &&
138 wideInterface == adapter->FriendlyName;
140 const bool descriptionMatches =
141 adapter->Description !=
nullptr &&
142 !wideInterface.empty() &&
143 wideInterface == adapter->Description;
145 if (!adapterNameMatches && !friendlyNameMatches && !descriptionMatches)
152 throw SocketError(
"Interface '" + interface +
153 "' does not expose a six-byte MAC address");
158 adapter->PhysicalAddress,
165 throw SocketError(
"Network interface not found: '" + interface +
"'");
170 std::vector<wchar_t>
buffer(512U);
174 const DWORD
length = GetModuleFileNameW(
177 static_cast<DWORD
>(
buffer.size()));
181 const DWORD
error = GetLastError();
182 throw std::runtime_error(
183 "Failed to get executable path: " + std::to_string(
error));
188 return std::filesystem::path(
195 if (
buffer.size() >
static_cast<std::size_t
>(std::numeric_limits<DWORD>::max()))
197 throw std::runtime_error(
"Executable path exceeds the supported Windows path length");
Declares exceptions and error types used by the PROFINET IO controller stack.
MacAddress GetInterfaceMac(const std::string &interface)
Get the MAC address assigned to a network interface.
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
std::filesystem::path GetExecutableDirectory()
Retrieves the absolute directory path of the currently running executable.
constexpr int macAddressLength
Constant lenght of a mac address.
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.