Mercurial > hg > orthanc
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 } |