summaryrefslogtreecommitdiff
path: root/netspeed/src/backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'netspeed/src/backend.c')
-rw-r--r--netspeed/src/backend.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/netspeed/src/backend.c b/netspeed/src/backend.c
new file mode 100644
index 00000000..17bbef24
--- /dev/null
+++ b/netspeed/src/backend.c
@@ -0,0 +1,330 @@
+/* backend.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Netspeed Applet was writen by Jörgen Scheibengruber <[email protected]>
+ *
+ * Mate Netspeed Applet migrated by Stefano Karapetsas <[email protected]>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(sun) && defined(__SVR4)
+#include <sys/sockio.h>
+#endif
+
+#include <glibtop/netlist.h>
+#include <glibtop/netload.h>
+
+#ifdef HAVE_IW
+ #include <iwlib.h>
+#endif /* HAVE_IW */
+
+#include "backend.h"
+
+gboolean
+is_dummy_device(const char* device)
+{
+ glibtop_netload netload;
+ glibtop_get_netload(&netload, device);
+
+ if (netload.if_flags & (1 << GLIBTOP_IF_FLAGS_LOOPBACK))
+ return TRUE;
+
+ /* Skip interfaces without any IPv4/IPv6 address (or
+ those with only a LINK ipv6 addr) However we need to
+ be able to exclude these while still keeping the
+ value so when they get online (with NetworkManager
+ for example) we don't get a suddent peak. Once we're
+ able to get this, ignoring down interfaces will be
+ possible too. */
+ if (!(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS6)
+ && netload.scope6 != GLIBTOP_IF_IN6_SCOPE_LINK)
+ && !(netload.flags & (1 << GLIBTOP_NETLOAD_ADDRESS)))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/* Check for all available devices. This really should be
+ * portable for at least all plattforms using the gnu c lib
+ * TODO: drop it, use glibtop_get_netlist directly / gchar**
+ */
+GList*
+get_available_devices(void)
+{
+ glibtop_netlist buf;
+ char **devices, **dev;
+ GList *device_glist = NULL;
+
+ devices = glibtop_get_netlist(&buf);
+
+ for(dev = devices; *dev; ++dev) {
+ device_glist = g_list_prepend(device_glist, g_strdup(*dev));
+ }
+
+ g_strfreev(devices);
+
+ return device_glist;
+}
+
+const gchar*
+get_default_route(void)
+{
+ FILE *fp;
+ static char device[50];
+
+ fp = fopen("/proc/net/route", "r");
+
+ if (fp == NULL) return NULL;
+
+ while (!feof(fp)) {
+ char buffer[1024];
+ unsigned int ip, gw, flags, ref, use, metric, mask, mtu, window, irtt;
+ int retval;
+ char *rv;
+
+ rv = fgets(buffer, 1024, fp);
+ if (!rv) {
+ break;
+ }
+
+ retval = sscanf(buffer, "%49s %x %x %x %u %u %u %x %u %u %u",
+ device, &ip, &gw, &flags, &ref, &use, &metric, &mask, &mtu, &window, &irtt);
+
+ if (retval != 11) continue;
+
+ if (gw == 0 && !is_dummy_device(device)) {
+ fclose(fp);
+ return device;
+ }
+ }
+ fclose(fp);
+ return NULL;
+}
+
+
+void
+free_devices_list(GList *list)
+{
+ g_list_foreach(list, (GFunc)g_free, NULL);
+ g_list_free(list);
+}
+
+
+/* Frees a DevInfo struct and all the stuff it contains
+ */
+void
+free_device_info(DevInfo *devinfo)
+{
+ g_free(devinfo->name);
+ g_free(devinfo->ip);
+ g_free(devinfo->netmask);
+ g_free(devinfo->ptpip);
+ g_free(devinfo->hwaddr);
+ g_free(devinfo->ipv6);
+ g_free(devinfo->essid);
+ g_free(devinfo->tx_rate);
+ g_free(devinfo->rx_rate);
+ g_free(devinfo->sum_rate);
+}
+
+
+
+
+static char*
+format_ipv4(guint32 ip)
+{
+ char *str = g_malloc(INET_ADDRSTRLEN);
+ inet_ntop(AF_INET, &ip, str, INET_ADDRSTRLEN);
+ return str;
+}
+
+
+static char*
+format_ipv6(const guint8 ip[16])
+{
+ char *str = g_malloc(INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, ip, str, INET6_ADDRSTRLEN);
+ return str;
+}
+
+
+/* TODO:
+ these stuff are not portable because of ioctl
+*/
+static void
+get_ptp_info(DevInfo *devinfo)
+{
+ int fd = -1;
+ struct ifreq request = {};
+
+ g_strlcpy(request.ifr_name, devinfo->name, sizeof request.ifr_name);
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return;
+
+ if (ioctl(fd, SIOCGIFDSTADDR, &request) >= 0) {
+ struct sockaddr_in* addr;
+ addr = (struct sockaddr_in*)&request.ifr_dstaddr;
+ devinfo->ptpip = format_ipv4(addr->sin_addr.s_addr);
+ }
+
+ close(fd);
+}
+
+
+
+
+void
+get_device_info(const char *device, DevInfo *devinfo)
+{
+ glibtop_netload netload;
+ guint8 *hw;
+
+ g_assert(device);
+
+ memset(devinfo, 0, sizeof *devinfo);
+
+ devinfo->name = g_strdup(device);
+ devinfo->type = DEV_UNKNOWN;
+
+ glibtop_get_netload(&netload, device);
+ devinfo->tx = netload.bytes_out;
+ devinfo->rx = netload.bytes_in;
+
+ devinfo->up = (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_UP) ? TRUE : FALSE);
+ devinfo->running = (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_RUNNING) ? TRUE : FALSE);
+
+ devinfo->ip = format_ipv4(netload.address);
+ devinfo->netmask = format_ipv4(netload.subnet);
+ devinfo->ipv6 = format_ipv6(netload.address6);
+ devinfo->qual = 0;
+ devinfo->essid = NULL;
+
+ hw = netload.hwaddress;
+ if (hw[6] || hw[7]) {
+ devinfo->hwaddr = g_strdup_printf(
+ "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+ hw[0], hw[1], hw[2], hw[3],
+ hw[4], hw[5], hw[6], hw[7]);
+ } else {
+ devinfo->hwaddr = g_strdup_printf(
+ "%02X:%02X:%02X:%02X:%02X:%02X",
+ hw[0], hw[1], hw[2],
+ hw[3], hw[4], hw[5]);
+ }
+ /* stolen from gnome-applets/multiload/linux-proc.c */
+
+ if(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_LOOPBACK)) {
+ devinfo->type = DEV_LO;
+ }
+
+#ifdef HAVE_IW
+
+ else if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_WIRELESS)) {
+ devinfo->type = DEV_WIRELESS;
+ get_wireless_info (devinfo);
+ }
+
+#endif /* HAVE_IW */
+
+ else if(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_POINTOPOINT)) {
+ if (g_str_has_prefix(device, "plip")) {
+ devinfo->type = DEV_PLIP;
+ }
+ else if (g_str_has_prefix(device, "sl")) {
+ devinfo->type = DEV_SLIP;
+ }
+ else {
+ devinfo->type = DEV_PPP;
+ }
+
+ get_ptp_info(devinfo);
+ }
+ else {
+ devinfo->type = DEV_ETHERNET;
+ }
+}
+
+gboolean
+compare_device_info(const DevInfo *a, const DevInfo *b)
+{
+ g_assert(a && b);
+ g_assert(a->name && b->name);
+
+ if (!g_str_equal(a->name, b->name)) return TRUE;
+ if (a->ip && b->ip) {
+ if (!g_str_equal(a->ip, b->ip)) return TRUE;
+ } else {
+ if (a->ip || b->ip) return TRUE;
+ }
+ /* Ignore hwaddr, ptpip and netmask... I think this is ok */
+ if (a->up != b->up) return TRUE;
+ if (a->running != b->running) return TRUE;
+
+ return FALSE;
+}
+#ifdef HAVE_IW
+void
+get_wireless_info (DevInfo *devinfo)
+{
+ int fd;
+ int newqual;
+ wireless_info info = {0};
+
+ fd = iw_sockets_open ();
+
+ if (fd < 0)
+ return;
+
+ if (iw_get_basic_config (fd, devinfo->name, &info.b) < 0)
+ goto out;
+
+ if (info.b.has_essid) {
+ if ((!devinfo->essid) || (strcmp (devinfo->essid, info.b.essid) != 0)) {
+ devinfo->essid = g_strdup (info.b.essid);
+ }
+ } else {
+ devinfo->essid = NULL;
+ }
+
+ if (iw_get_stats (fd, devinfo->name, &info.stats, &info.range, info.has_range) >= 0)
+ info.has_stats = 1;
+
+ if (info.has_stats) {
+ if ((iw_get_range_info(fd, devinfo->name, &info.range) >= 0) && (info.range.max_qual.qual > 0)) {
+ newqual = 0.5f + (100.0f * info.stats.qual.qual) / (1.0f * info.range.max_qual.qual);
+ } else {
+ newqual = info.stats.qual.qual;
+ }
+
+ newqual = CLAMP(newqual, 0, 100);
+ if (devinfo->qual != newqual)
+ devinfo->qual = newqual;
+
+ } else {
+ devinfo->qual = 0;
+ }
+
+ goto out;
+out:
+ if (fd != -1)
+ close (fd);
+}
+#endif /* HAVE_IW */