# HG changeset patch # User Sebastien Jodogne # Date 1614690370 -3600 # Node ID 8a7523da6a9b08ae04d4438c90927c28f48ef983 # Parent 1de2fc0363cb67d4619e39db1f656cf180927086 added SystemToolbox::GetMacAddresses() diff -r 1de2fc0363cb -r 8a7523da6a9b OrthancFramework/Sources/SystemToolbox.cpp --- a/OrthancFramework/Sources/SystemToolbox.cpp Tue Mar 02 10:16:06 2021 +0100 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Tue Mar 02 14:06:10 2021 +0100 @@ -25,30 +25,39 @@ #if defined(_WIN32) +# include // For GetMacAddresses(), must be included before "windows.h" # include -# include // For "_spawnvp()" and "_getpid()" -# include // For "environ" + +# include // For GetMacAddresses() +# include // For "_spawnvp()" and "_getpid()" +# include // For "environ" #else -# include // For "execvp()" -# include // For "waitpid()" +# include // For GetMacAddresses() +# include // For GetMacAddresses() +# include // For GetMacAddresses() +# include // For "waitpid()" +# include // For "execvp()" #endif #if defined(__APPLE__) && defined(__MACH__) -# include /* _NSGetExecutablePath */ -# include /* PATH_MAX */ +# include // PATH_MAX +# include // _NSGetExecutablePath +# include // For GetMacAddresses() +# include // For GetMacAddresses() +# include // For GetMacAddresses() #endif #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) -# include /* PATH_MAX */ +# include // PATH_MAX # include # include #endif #if defined(__OpenBSD__) -# include // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS" +# include // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS" #endif @@ -63,6 +72,10 @@ #include #include +#include +#include + + /*========================================================================= The section below comes from the Boost 1.68.0 project: @@ -913,4 +926,210 @@ f.close(); } + + +#if defined(_WIN32) + void SystemToolbox::GetMacAddresses(std::set& target) + { + target.clear(); + + // 15Ko is the recommanded size to start with + std::vector buffer(15 * 1024); + + for (unsigned int iteration = 0; iteration < 3; iteration++) + { + ULONG outBufLen = static_cast(buffer.size()); + DWORD result = GetAdaptersAddresses + (AF_UNSPEC, 0, NULL, + reinterpret_cast(&buffer[0]), &outBufLen); + + if (result == NO_ERROR) + { + IP_ADAPTER_ADDRESSES* current = + reinterpret_cast(&buffer[0]); + + while (current != NULL) + { + if (current->PhysicalAddressLength == 6 && + (current->PhysicalAddress[0] != 0 || + current->PhysicalAddress[1] != 0 || + current->PhysicalAddress[2] != 0 || + current->PhysicalAddress[3] != 0 || + current->PhysicalAddress[4] != 0 || + current->PhysicalAddress[5] != 0)) + { + char tmp[32]; + sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x", + (unsigned char) current->PhysicalAddress[0], + (unsigned char) current->PhysicalAddress[1], + (unsigned char) current->PhysicalAddress[2], + (unsigned char) current->PhysicalAddress[3], + (unsigned char) current->PhysicalAddress[4], + (unsigned char) current->PhysicalAddress[5]); + target.insert(tmp); + } + + current = current->Next; + } + + return; + } + else if (result != ERROR_BUFFER_OVERFLOW || + iteration >= 3 || + outBufLen == 0) + { + return; + } + else + { + buffer.resize(outBufLen); + iteration++; + } + } + } + +#else + namespace + { + class SocketRaii : public boost::noncopyable + { + private: + int socket_; + + public: + SocketRaii() + { + socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + } + + ~SocketRaii() + { + if (socket_ != -1) + { + close(socket_); + } + } + + int GetDescriptor() const + { + return socket_; + } + }; + + + class NetworkInterfaces : public boost::noncopyable + { + private: + struct if_nameindex* list_; + struct if_nameindex* current_; + + public: + NetworkInterfaces() + { + list_ = if_nameindex(); + current_ = list_; + } + + ~NetworkInterfaces() + { + if (list_ != NULL) + { + if_freenameindex(list_); + } + } + + bool IsDone() const + { + return (current_ == NULL || + (current_->if_index == 0 && + current_->if_name == NULL)); + } + + const char* GetCurrentName() const + { + assert(!IsDone()); + return current_->if_name; + } + + unsigned int GetCurrentIndex() const + { + assert(!IsDone()); + return current_->if_index; + } + + void Next() + { + assert(!IsDone()); + current_++; + } + }; + } + + + void SystemToolbox::GetMacAddresses(std::set& target) + { + target.clear(); + + SocketRaii socket; + + if (socket.GetDescriptor() != 1) + { + NetworkInterfaces interfaces; + + while (!interfaces.IsDone()) + { +#if defined(__APPLE__) && defined(__MACH__) + int mib[6]; + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = interfaces.GetCurrentIndex(); + + size_t len; + if (sysctl(mib, 6, NULL, &len, NULL, 0) == 0 && + len > 0) + { + std::string tmp; + tmp.resize(len); + if (sysctl(mib, 6, &tmp[0], &len, NULL, 0) == 0) + { + struct if_msghdr* ifm = reinterpret_cast(&tmp[0]); + struct sockaddr_dl* sdl = reinterpret_cast(ifm + 1); + + if (sdl->sdl_type == IFT_ETHER) // Only consider Ethernet interfaces + { + const unsigned char* mac = reinterpret_cast(LLADDR(sdl)); + char tmp[32]; + sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + target.insert(tmp); + } + } + } + +#else + struct ifreq ifr; + strcpy(ifr.ifr_name, interfaces.GetCurrentName()); + + if (ioctl(socket.GetDescriptor(), SIOCGIFFLAGS, &ifr) == 0 && + !(ifr.ifr_flags & IFF_LOOPBACK) && // ignore loopback interface + ioctl(socket.GetDescriptor(), SIOCGIFHWADDR, &ifr) == 0) + { + const unsigned char* mac = reinterpret_cast(ifr.ifr_hwaddr.sa_data); + + char tmp[32]; + sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + target.insert(tmp); + } +#endif + + interfaces.Next(); + } + } + } + +#endif } diff -r 1de2fc0363cb -r 8a7523da6a9b OrthancFramework/Sources/SystemToolbox.h --- a/OrthancFramework/Sources/SystemToolbox.h Tue Mar 02 10:16:06 2021 +0100 +++ b/OrthancFramework/Sources/SystemToolbox.h Tue Mar 02 14:06:10 2021 +0100 @@ -119,5 +119,7 @@ uint64_t start, // Inclusive uint64_t end, // Exclusive bool throwIfOverflow); + + static void GetMacAddresses(std::set& target); }; } diff -r 1de2fc0363cb -r 8a7523da6a9b OrthancFramework/UnitTestsSources/FrameworkTests.cpp --- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Tue Mar 02 10:16:06 2021 +0100 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Tue Mar 02 14:06:10 2021 +0100 @@ -1424,3 +1424,17 @@ ASSERT_THROW(tmp.ReadRange(s, 2, 1, true), OrthancException); } #endif + + +#if ORTHANC_SANDBOXED != 1 +TEST(Toolbox, GetMacAddressess) +{ + std::set mac; + SystemToolbox::GetMacAddresses(mac); + + for (std::set::const_iterator it = mac.begin(); it != mac.end(); ++it) + { + printf("MAC address: [%s]\n", it->c_str()); + } +} +#endif