comparison OrthancFramework/Sources/SystemToolbox.cpp @ 4538:8a7523da6a9b

added SystemToolbox::GetMacAddresses()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 02 Mar 2021 14:06:10 +0100
parents c1f36fd13730
children beb8ba8a0b12
comparison
equal deleted inserted replaced
4537:1de2fc0363cb 4538:8a7523da6a9b
23 #include "PrecompiledHeaders.h" 23 #include "PrecompiledHeaders.h"
24 #include "SystemToolbox.h" 24 #include "SystemToolbox.h"
25 25
26 26
27 #if defined(_WIN32) 27 #if defined(_WIN32)
28 # include <winsock2.h> // For GetMacAddresses(), must be included before "windows.h"
28 # include <windows.h> 29 # include <windows.h>
29 # include <process.h> // For "_spawnvp()" and "_getpid()" 30
30 # include <stdlib.h> // For "environ" 31 # include <iphlpapi.h> // For GetMacAddresses()
32 # include <process.h> // For "_spawnvp()" and "_getpid()"
33 # include <stdlib.h> // For "environ"
31 #else 34 #else
32 # include <unistd.h> // For "execvp()" 35 # include <net/if.h> // For GetMacAddresses()
33 # include <sys/wait.h> // For "waitpid()" 36 # include <netinet/in.h> // For GetMacAddresses()
37 # include <sys/ioctl.h> // For GetMacAddresses()
38 # include <sys/wait.h> // For "waitpid()"
39 # include <unistd.h> // For "execvp()"
34 #endif 40 #endif
35 41
36 42
37 #if defined(__APPLE__) && defined(__MACH__) 43 #if defined(__APPLE__) && defined(__MACH__)
38 # include <mach-o/dyld.h> /* _NSGetExecutablePath */ 44 # include <limits.h> // PATH_MAX
39 # include <limits.h> /* PATH_MAX */ 45 # include <mach-o/dyld.h> // _NSGetExecutablePath
46 # include <net/if_dl.h> // For GetMacAddresses()
47 # include <net/if_types.h> // For GetMacAddresses()
48 # include <sys/sysctl.h> // For GetMacAddresses()
40 #endif 49 #endif
41 50
42 51
43 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) 52 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
44 # include <limits.h> /* PATH_MAX */ 53 # include <limits.h> // PATH_MAX
45 # include <signal.h> 54 # include <signal.h>
46 # include <unistd.h> 55 # include <unistd.h>
47 #endif 56 #endif
48 57
49 58
50 #if defined(__OpenBSD__) 59 #if defined(__OpenBSD__)
51 # include <sys/sysctl.h> // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS" 60 # include <sys/sysctl.h> // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS"
52 #endif 61 #endif
53 62
54 63
55 #include "Logging.h" 64 #include "Logging.h"
56 #include "OrthancException.h" 65 #include "OrthancException.h"
60 #include <boost/iostreams/stream.hpp> 69 #include <boost/iostreams/stream.hpp>
61 #include <boost/filesystem.hpp> 70 #include <boost/filesystem.hpp>
62 #include <boost/filesystem/fstream.hpp> 71 #include <boost/filesystem/fstream.hpp>
63 #include <boost/date_time/posix_time/posix_time.hpp> 72 #include <boost/date_time/posix_time/posix_time.hpp>
64 #include <boost/thread.hpp> 73 #include <boost/thread.hpp>
74
75 #include <cassert>
76 #include <string.h>
77
65 78
66 79
67 /*========================================================================= 80 /*=========================================================================
68 The section below comes from the Boost 1.68.0 project: 81 The section below comes from the Boost 1.68.0 project:
69 https://github.com/boostorg/program_options/blob/boost-1.68.0/src/parsers.cpp 82 https://github.com/boostorg/program_options/blob/boost-1.68.0/src/parsers.cpp
911 content.clear(); 924 content.clear();
912 } 925 }
913 926
914 f.close(); 927 f.close();
915 } 928 }
929
930
931 #if defined(_WIN32)
932 void SystemToolbox::GetMacAddresses(std::set<std::string>& target)
933 {
934 target.clear();
935
936 // 15Ko is the recommanded size to start with
937 std::vector<char> buffer(15 * 1024);
938
939 for (unsigned int iteration = 0; iteration < 3; iteration++)
940 {
941 ULONG outBufLen = static_cast<ULONG>(buffer.size());
942 DWORD result = GetAdaptersAddresses
943 (AF_UNSPEC, 0, NULL,
944 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(&buffer[0]), &outBufLen);
945
946 if (result == NO_ERROR)
947 {
948 IP_ADAPTER_ADDRESSES* current =
949 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(&buffer[0]);
950
951 while (current != NULL)
952 {
953 if (current->PhysicalAddressLength == 6 &&
954 (current->PhysicalAddress[0] != 0 ||
955 current->PhysicalAddress[1] != 0 ||
956 current->PhysicalAddress[2] != 0 ||
957 current->PhysicalAddress[3] != 0 ||
958 current->PhysicalAddress[4] != 0 ||
959 current->PhysicalAddress[5] != 0))
960 {
961 char tmp[32];
962 sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x",
963 (unsigned char) current->PhysicalAddress[0],
964 (unsigned char) current->PhysicalAddress[1],
965 (unsigned char) current->PhysicalAddress[2],
966 (unsigned char) current->PhysicalAddress[3],
967 (unsigned char) current->PhysicalAddress[4],
968 (unsigned char) current->PhysicalAddress[5]);
969 target.insert(tmp);
970 }
971
972 current = current->Next;
973 }
974
975 return;
976 }
977 else if (result != ERROR_BUFFER_OVERFLOW ||
978 iteration >= 3 ||
979 outBufLen == 0)
980 {
981 return;
982 }
983 else
984 {
985 buffer.resize(outBufLen);
986 iteration++;
987 }
988 }
989 }
990
991 #else
992 namespace
993 {
994 class SocketRaii : public boost::noncopyable
995 {
996 private:
997 int socket_;
998
999 public:
1000 SocketRaii()
1001 {
1002 socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
1003 }
1004
1005 ~SocketRaii()
1006 {
1007 if (socket_ != -1)
1008 {
1009 close(socket_);
1010 }
1011 }
1012
1013 int GetDescriptor() const
1014 {
1015 return socket_;
1016 }
1017 };
1018
1019
1020 class NetworkInterfaces : public boost::noncopyable
1021 {
1022 private:
1023 struct if_nameindex* list_;
1024 struct if_nameindex* current_;
1025
1026 public:
1027 NetworkInterfaces()
1028 {
1029 list_ = if_nameindex();
1030 current_ = list_;
1031 }
1032
1033 ~NetworkInterfaces()
1034 {
1035 if (list_ != NULL)
1036 {
1037 if_freenameindex(list_);
1038 }
1039 }
1040
1041 bool IsDone() const
1042 {
1043 return (current_ == NULL ||
1044 (current_->if_index == 0 &&
1045 current_->if_name == NULL));
1046 }
1047
1048 const char* GetCurrentName() const
1049 {
1050 assert(!IsDone());
1051 return current_->if_name;
1052 }
1053
1054 unsigned int GetCurrentIndex() const
1055 {
1056 assert(!IsDone());
1057 return current_->if_index;
1058 }
1059
1060 void Next()
1061 {
1062 assert(!IsDone());
1063 current_++;
1064 }
1065 };
1066 }
1067
1068
1069 void SystemToolbox::GetMacAddresses(std::set<std::string>& target)
1070 {
1071 target.clear();
1072
1073 SocketRaii socket;
1074
1075 if (socket.GetDescriptor() != 1)
1076 {
1077 NetworkInterfaces interfaces;
1078
1079 while (!interfaces.IsDone())
1080 {
1081 #if defined(__APPLE__) && defined(__MACH__)
1082 int mib[6];
1083 mib[0] = CTL_NET;
1084 mib[1] = AF_ROUTE;
1085 mib[2] = 0;
1086 mib[3] = AF_LINK;
1087 mib[4] = NET_RT_IFLIST;
1088 mib[5] = interfaces.GetCurrentIndex();
1089
1090 size_t len;
1091 if (sysctl(mib, 6, NULL, &len, NULL, 0) == 0 &&
1092 len > 0)
1093 {
1094 std::string tmp;
1095 tmp.resize(len);
1096 if (sysctl(mib, 6, &tmp[0], &len, NULL, 0) == 0)
1097 {
1098 struct if_msghdr* ifm = reinterpret_cast<struct if_msghdr*>(&tmp[0]);
1099 struct sockaddr_dl* sdl = reinterpret_cast<struct sockaddr_dl*>(ifm + 1);
1100
1101 if (sdl->sdl_type == IFT_ETHER) // Only consider Ethernet interfaces
1102 {
1103 const unsigned char* mac = reinterpret_cast<const unsigned char*>(LLADDR(sdl));
1104 char tmp[32];
1105 sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x",
1106 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1107 target.insert(tmp);
1108 }
1109 }
1110 }
1111
1112 #else
1113 struct ifreq ifr;
1114 strcpy(ifr.ifr_name, interfaces.GetCurrentName());
1115
1116 if (ioctl(socket.GetDescriptor(), SIOCGIFFLAGS, &ifr) == 0 &&
1117 !(ifr.ifr_flags & IFF_LOOPBACK) && // ignore loopback interface
1118 ioctl(socket.GetDescriptor(), SIOCGIFHWADDR, &ifr) == 0)
1119 {
1120 const unsigned char* mac = reinterpret_cast<const unsigned char*>(ifr.ifr_hwaddr.sa_data);
1121
1122 char tmp[32];
1123 sprintf(tmp, "%02x:%02x:%02x:%02x:%02x:%02x",
1124 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1125 target.insert(tmp);
1126 }
1127 #endif
1128
1129 interfaces.Next();
1130 }
1131 }
1132 }
1133
1134 #endif
916 } 1135 }