From 7ee92be6fdf8d3718202ab42aefb028d3a7eac94 Mon Sep 17 00:00:00 2001 From: UeiWang Date: Fri, 12 May 2023 22:47:29 +0800 Subject: Darwin: add NetworkIOMeter support --- darwin/Platform.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) (limited to 'darwin') diff --git a/darwin/Platform.c b/darwin/Platform.c index f72f8aec..387910e1 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -14,6 +14,10 @@ in the source distribution for its full text. #include #include #include +#include +#include +#include +#include #include #include @@ -138,6 +142,7 @@ const MeterClass* const Platform_meterTypes[] = { &ZfsArcMeter_class, &ZfsCompressedArcMeter_class, &DiskIOMeter_class, + &NetworkIOMeter_class, &FileDescriptorMeter_class, &BlankMeter_class, NULL @@ -467,10 +472,65 @@ bool Platform_getDiskIO(DiskIOData* data) { return true; } +/* Caution: Given that interfaces are dynamic, and it is not possible to get statistics on interfaces that no longer exist, + if some interface disappears between the time of two samples, the values of the second sample may be lower than those of + the first one. */ bool Platform_getNetworkIO(NetworkIOData* data) { - // TODO - (void)data; - return false; + int mib[6] = {CTL_NET, + PF_ROUTE, /* routing messages */ + 0, /* protocal number, currently always 0 */ + 0, /* select all address families */ + NET_RT_IFLIST2, /* interface list with addresses */ + 0}; + + for (size_t retry = 0; retry < 4; retry++) { + size_t len = 0; + + /* Determine len */ + if (sysctl(mib, ARRAYSIZE(mib), NULL, &len, NULL, 0) < 0 || len == 0) + return false; + + len += 16 * retry * retry * sizeof(struct if_msghdr2); + char *buf = xMalloc(len); + + if (sysctl(mib, ARRAYSIZE(mib), buf, &len, NULL, 0) < 0) { + free(buf); + if (errno == ENOMEM && retry < 3) + continue; + else + return false; + } + + uint64_t bytesReceived_sum = 0, packetsReceived_sum = 0, bytesTransmitted_sum = 0, packetsTransmitted_sum = 0; + + for (char *next = buf; next < buf + len;) { + void *tmp = (void*) next; + struct if_msghdr *ifm = (struct if_msghdr*) tmp; + + next += ifm->ifm_msglen; + + if (ifm->ifm_type != RTM_IFINFO2) + continue; + + struct if_msghdr2 *ifm2 = (struct if_msghdr2*) ifm; + + if (ifm2->ifm_data.ifi_type != IFT_LOOP) { /* do not count loopback traffic */ + bytesReceived_sum += ifm2->ifm_data.ifi_ibytes; + packetsReceived_sum += ifm2->ifm_data.ifi_ipackets; + bytesTransmitted_sum += ifm2->ifm_data.ifi_obytes; + packetsTransmitted_sum += ifm2->ifm_data.ifi_opackets; + } + } + + data->bytesReceived = bytesReceived_sum; + data->packetsReceived = packetsReceived_sum; + data->bytesTransmitted = bytesTransmitted_sum; + data->packetsTransmitted = packetsTransmitted_sum; + + free(buf); + } + + return true; } void Platform_getBattery(double* percent, ACPresence* isOnAC) { -- cgit v1.2.3