| 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__ |