832 | | // Note: this may also work on other UNIX-like systems in addition to Macintosh |
833 | | #ifdef __APPLE__ |
834 | | |
835 | | #include <net/if.h> |
836 | | #include <net/if_dl.h> |
837 | | #include <net/route.h> |
838 | | |
839 | | // detect the network usage totals for the host. |
840 | | // |
841 | | int get_network_usage_totals(unsigned int& total_received, unsigned int& total_sent) { |
842 | | static size_t sysctlBufferSize = 0; |
843 | | static uint8_t *sysctlBuffer = NULL; |
844 | | |
845 | | int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; |
846 | | struct if_msghdr *ifmsg; |
847 | | size_t currentSize = 0; |
848 | | |
849 | | total_received = 0; |
850 | | total_sent = 0; |
851 | | |
852 | | if (sysctl(mib, 6, NULL, ¤tSize, NULL, 0) != 0) return errno; |
853 | | if (!sysctlBuffer || (currentSize > sysctlBufferSize)) { |
854 | | if (sysctlBuffer) free(sysctlBuffer); |
855 | | sysctlBufferSize = 0; |
856 | | sysctlBuffer = (uint8_t*)malloc(currentSize); |
857 | | if (!sysctlBuffer) return ERR_MALLOC; |
858 | | sysctlBufferSize = currentSize; |
859 | | } |
860 | | |
861 | | // Read in new data |
862 | | if (sysctl(mib, 6, sysctlBuffer, ¤tSize, NULL, 0) != 0) return errno; |
863 | | |
864 | | // Walk through the reply |
865 | | uint8_t *currentData = sysctlBuffer; |
866 | | uint8_t *currentDataEnd = sysctlBuffer + currentSize; |
867 | | |
868 | | while (currentData < currentDataEnd) { |
869 | | // Expecting interface data |
870 | | ifmsg = (struct if_msghdr *)currentData; |
871 | | if (ifmsg->ifm_type != RTM_IFINFO) { |
872 | | currentData += ifmsg->ifm_msglen; |
873 | | continue; |
874 | | } |
875 | | // Must not be loopback |
876 | | if (ifmsg->ifm_flags & IFF_LOOPBACK) { |
877 | | currentData += ifmsg->ifm_msglen; |
878 | | continue; |
879 | | } |
880 | | // Only look at link layer items |
881 | | struct sockaddr_dl *sdl = (struct sockaddr_dl *)(ifmsg + 1); |
882 | | if (sdl->sdl_family != AF_LINK) { |
883 | | currentData += ifmsg->ifm_msglen; |
884 | | continue; |
885 | | } |
886 | | |
887 | | #if 0 // Use this code if we want only Ethernet interface 0 |
888 | | if (!strcmp(sdl->sdl_data, "en0")) { |
889 | | total_received = ifmsg->ifm_data.ifi_ibytes; |
890 | | total_sent = ifmsg->ifm_data.ifi_obytes; |
891 | | return 0; |
892 | | } |
893 | | #else // Use this code if we want total of all non-loopback interfaces |
894 | | total_received += ifmsg->ifm_data.ifi_ibytes; |
895 | | total_sent += ifmsg->ifm_data.ifi_obytes; |
896 | | #endif |
897 | | } |
898 | | |
899 | | return 0; |
900 | | } |
901 | | |
902 | | |
903 | | #if defined(__i386__) || defined(__x86_64__) |
904 | | |
905 | | // Code to get maximum CPU temperature (Apple Intel only) |
906 | | // Adapted from Apple System Management Control (SMC) Tool under the GPL |
907 | | |
908 | | #define KERNEL_INDEX_SMC 2 |
909 | | |
910 | | #define SMC_CMD_READ_BYTES 5 |
911 | | #define SMC_CMD_READ_KEYINFO 9 |
912 | | |
913 | | typedef struct { |
914 | | char major; |
915 | | char minor; |
916 | | char build; |
917 | | char reserved[1]; |
918 | | UInt16 release; |
919 | | } SMCKeyData_vers_t; |
920 | | |
921 | | typedef struct { |
922 | | UInt16 version; |
923 | | UInt16 length; |
924 | | UInt32 cpuPLimit; |
925 | | UInt32 gpuPLimit; |
926 | | UInt32 memPLimit; |
927 | | } SMCKeyData_pLimitData_t; |
928 | | |
929 | | typedef struct { |
930 | | UInt32 dataSize; |
931 | | UInt32 dataType; |
932 | | char dataAttributes; |
933 | | } SMCKeyData_keyInfo_t; |
934 | | |
935 | | typedef char SMCBytes_t[32]; |
936 | | |
937 | | typedef struct { |
938 | | UInt32 key; |
939 | | SMCKeyData_vers_t vers; |
940 | | SMCKeyData_pLimitData_t pLimitData; |
941 | | SMCKeyData_keyInfo_t keyInfo; |
942 | | char result; |
943 | | char status; |
944 | | char data8; |
945 | | UInt32 data32; |
946 | | SMCBytes_t bytes; |
947 | | } SMCKeyData_t; |
948 | | |
949 | | static io_connect_t conn; |
950 | | |
951 | | kern_return_t SMCOpen() |
952 | | { |
953 | | kern_return_t result; |
954 | | mach_port_t masterPort; |
955 | | io_iterator_t iterator; |
956 | | io_object_t device; |
957 | | |
958 | | result = IOMasterPort(MACH_PORT_NULL, &masterPort); |
959 | | |
960 | | CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC"); |
961 | | result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator); |
962 | | if (result != kIOReturnSuccess) |
963 | | { |
964 | | return result; |
965 | | } |
966 | | |
967 | | device = IOIteratorNext(iterator); |
968 | | IOObjectRelease(iterator); |
969 | | if (device == 0) |
970 | | { |
971 | | return result; |
972 | | } |
973 | | |
974 | | result = IOServiceOpen(device, mach_task_self(), 0, &conn); |
975 | | IOObjectRelease(device); |
976 | | if (result != kIOReturnSuccess) |
977 | | { |
978 | | return result; |
979 | | } |
980 | | |
981 | | return kIOReturnSuccess; |
982 | | } |
983 | | |
984 | | kern_return_t SMCClose() |
985 | | { |
986 | | if (conn) { |
987 | | return IOServiceClose(conn); |
988 | | } |
989 | | return kIOReturnSuccess; |
990 | | } |
991 | | |
992 | | kern_return_t SMCReadKey(UInt32 key, SMCBytes_t val) { |
993 | | kern_return_t result; |
994 | | SMCKeyData_t inputStructure; |
995 | | SMCKeyData_t outputStructure; |
996 | | size_t structureOutputSize = 0; |
997 | | |
998 | | memset(&inputStructure, 0, sizeof(inputStructure)); |
999 | | memset(&outputStructure, 0, sizeof(outputStructure)); |
1000 | | memset(val, 0, sizeof(val)); |
1001 | | |
1002 | | inputStructure.key = key; |
1003 | | inputStructure.data8 = SMC_CMD_READ_KEYINFO; |
1004 | | |
1005 | | #if MAC_OS_X_VERSION_10_5 |
1006 | | result = IOConnectCallStructMethod(conn, |
1007 | | KERNEL_INDEX_SMC, |
1008 | | &inputStructure, |
1009 | | sizeof(inputStructure), |
1010 | | &inputStructure, |
1011 | | &structureOutputSize); |
1012 | | #else |
1013 | | result = IOConnectMethodStructureIStructureO(conn, |
1014 | | KERNEL_INDEX_SMC, |
1015 | | sizeof(inputStructure), |
1016 | | &structureOutputSize, |
1017 | | &inputStructure, |
1018 | | &outputStructure); |
1019 | | #endif |
1020 | | if (result != kIOReturnSuccess) { |
1021 | | return result; |
1022 | | } |
1023 | | |
1024 | | inputStructure.keyInfo.dataSize = outputStructure.keyInfo.dataSize; |
1025 | | inputStructure.data8 = SMC_CMD_READ_BYTES; |
1026 | | |
1027 | | #if MAC_OS_X_VERSION_10_5 |
1028 | | result = IOConnectCallStructMethod(conn, |
1029 | | KERNEL_INDEX_SMC, |
1030 | | &inputStructure, |
1031 | | sizeof(inputStructure), |
1032 | | &inputStructure, |
1033 | | &structureOutputSize); |
1034 | | #else |
1035 | | result = IOConnectMethodStructureIStructureO( |
1036 | | conn, KERNEL_INDEX_SMC, sizeof(inputStructure), &structureOutputSize), |
1037 | | &inputStructure, &outputStructure |
1038 | | ); |
1039 | | #endif |
1040 | | if (result != kIOReturnSuccess) { |
1041 | | return result; |
1042 | | } |
1043 | | |
1044 | | memcpy(val, outputStructure.bytes, sizeof(outputStructure.bytes)); |
1045 | | |
1046 | | return kIOReturnSuccess; |
1047 | | } |
1048 | | |
1049 | | |
1050 | | // Check up to 10 die temperatures (TC0D, TC1D, etc.) and |
1051 | | // 10 heatsink temperatures (TCAH, TCBH, etc.) |
1052 | | // Returns the highest current CPU temperature as degrees Celsius. |
1053 | | // Returns zero if it fails (or on a PowerPC Mac). |
1054 | | int get_max_cpu_temperature() { |
1055 | | kern_return_t result; |
1056 | | int maxTemp = 0, thisTemp, i; |
1057 | | union tempKey { |
1058 | | UInt32 word; |
1059 | | char bytes[4]; |
1060 | | }; |
1061 | | tempKey key; |
1062 | | SMCBytes_t val; |
1063 | | static bool skip[20]; |
1064 | | |
1065 | | // open connection to SMC kext if this is the first time |
1066 | | if (!conn) { |
1067 | | result = SMCOpen(); |
1068 | | if (result != kIOReturnSuccess) { |
1069 | | return 0; |
1070 | | } |
1071 | | } |
1072 | | |
1073 | | for (i=0; i<20; ++i) { |
1074 | | if (skip[i]) continue; |
1075 | | if (i < 10) { |
1076 | | key.word = 'TC0D'; |
1077 | | key.bytes[1] += i; // TC0D, TC1D, TC2D, etc. |
1078 | | } else { |
1079 | | key.word = 'TCAH'; |
1080 | | key.bytes[1] += (i - 10); // TCAH, TCBH, TCCH, etc. |
1081 | | } |
1082 | | result = SMCReadKey(key.word, val); |
1083 | | if (result != kIOReturnSuccess) { |
1084 | | skip[i] = true; |
1085 | | continue; |
1086 | | } |
1087 | | |
1088 | | if (val[0] < 1) { |
1089 | | skip[i] = true; |
1090 | | continue; |
1091 | | } |
1092 | | |
1093 | | thisTemp = val[0]; |
1094 | | if (val[1] & 0x80) ++thisTemp; |
1095 | | if (thisTemp > maxTemp) { |
1096 | | maxTemp = thisTemp; |
1097 | | } |
1098 | | } |
1099 | | |
1100 | | return maxTemp; |
1101 | | } |
1102 | | |
1103 | | #else // PowerPC |
1104 | | |
1105 | | int GetMaxCPUTemperature() { |
1106 | | return 0; |
1107 | | } |
1108 | | |
1109 | | #endif |
1110 | | #endif // __APPLE__ |