/* * Copyright (c) 2018 Alastair Roy Poole * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) static void _freebsd_generic_network_status(uint64_t *in, uint64_t *out) { struct ifmibdata *ifmd; size_t len; int i, count; len = sizeof(count); if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, NULL, 0) == -1) return; ifmd = malloc(sizeof(struct ifmibdata)); if (!ifmd) return; for (i = 1; i <= count; i++) { int mib[] = { CTL_NET, PF_LINK, NETLINK_GENERIC, IFMIB_IFDATA, i, IFDATA_GENERAL }; len = sizeof(*ifmd); if (sysctl(mib, 6, ifmd, &len, NULL, 0) < 0) continue; if (!strcmp(ifmd->ifmd_name, "lo0")) continue; *in += ifmd->ifmd_data.ifi_ibytes; *out += ifmd->ifmd_data.ifi_obytes; } free(ifmd); } #endif #if defined(__OpenBSD__) static void _openbsd_generic_network_status(uint64_t *in, uint64_t *out) { struct ifaddrs *interfaces, *ifa; if (getifaddrs(&interfaces) < 0) return; int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) return; for (ifa = interfaces; ifa; ifa = ifa->ifa_next) { struct ifreq ifreq; struct if_data if_data; // TBC: Interfaces can have multiple addresses. // Using this netmask check we should be obtaining // the overall interface data across addresses. if (ifa->ifa_netmask != 0) continue; ifreq.ifr_data = (void *)&if_data; strncpy(ifreq.ifr_name, ifa->ifa_name, IFNAMSIZ - 1); if (ioctl(sock, SIOCGIFDATA, &ifreq) < 0) return; const struct if_data *ifi = &if_data; if (!LINK_STATE_IS_UP(ifi->ifi_link_state)) continue; if (ifi->ifi_type == IFT_ETHER || ifi->ifi_type == IFT_FASTETHER || ifi->ifi_type == IFT_GIGABITETHERNET || ifi->ifi_type == IFT_IEEE80211) { if (ifi->ifi_ibytes) *in += ifi->ifi_ibytes; if (ifi->ifi_obytes) *out += ifi->ifi_obytes; } } close(sock); } #endif #if defined(__linux__) static void _linux_generic_network_status(uint64_t *in, uint64_t *out) { FILE *f; char buf[4096], dummy_s[256]; unsigned long int tmp_in, tmp_out, dummy; f = fopen("/proc/net/dev", "r"); if (!f) return; while (fgets(buf, sizeof(buf), f)) { if (17 == sscanf(buf, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " "%lu %lu %lu %lu %lu\n", dummy_s, &tmp_in, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &tmp_out, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy)) { *in += tmp_in; *out += tmp_out; } } fclose(f); } #endif void system_network_transfer_get(network_t *usage) { uint64_t first_in = 0, first_out = 0; uint64_t last_in = 0, last_out = 0; #if defined(__linux__) _linux_generic_network_status(&first_in, &first_out); usleep(1000000); _linux_generic_network_status(&last_in, &last_out); #elif defined(__OpenBSD__) _openbsd_generic_network_status(&first_in, &first_out); usleep(1000000); _openbsd_generic_network_status(&last_in, &last_out); #elif defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) _freebsd_generic_network_status(&first_in, &first_out); usleep(1000000); _freebsd_generic_network_status(&last_in, &last_out); #endif usage->incoming = last_in - first_in; usage->outgoing = last_out - first_out; }