1 /*
2  * Copyright (c) 2021 Jan Ziak <0xe2.0x9a.0x9b@xfce.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include "network.h"
33 
34 #ifdef HAVE_LIBGTOP
35 
36 #include <glibtop/netlist.h>
37 #include <glibtop/netload.h>
38 
39 static gint
read_netload_libgtop(gulong * bytes)40 read_netload_libgtop (gulong *bytes)
41 {
42     glibtop_netlist netlist;
43     char **interfaces, **i;
44 
45     interfaces = glibtop_get_netlist (&netlist);
46     if (!interfaces)
47         return -1;
48 
49     *bytes = 0;
50     for (i = interfaces; *i != NULL; i++)
51     {
52         glibtop_netload netload;
53         glibtop_get_netload (&netload, *i);
54         *bytes += netload.bytes_total;
55     }
56 
57     return 0;
58 }
59 
60 #else
61 
62 static gint
read_netload_libgtop(gulong * bytes)63 read_netload_libgtop (gulong *bytes)
64 {
65     return -1;
66 }
67 
68 #endif
69 
70 static const char *const PROC_NET_NETSTAT = "/proc/net/netstat";
71 
72 static gint
read_netload_proc(gulong * bytes)73 read_netload_proc (gulong *bytes)
74 {
75     char buf[4*1024];
76     const char *s;
77     unsigned long long dummy, in_octets, out_octets;
78 
79     {
80         FILE *fd;
81         size_t size;
82 
83         fd = fopen (PROC_NET_NETSTAT, "r");
84         if (!fd)
85             return -1;
86 
87         if ((size = fread (buf, sizeof (*buf), G_N_ELEMENTS (buf) - 1, fd)) == 0)
88         {
89             fclose(fd);
90             return -1;
91         }
92         buf[size] = '\0';
93 
94         if (fclose (fd) != 0)
95             return -1;
96     }
97 
98     /* Skip first 3 lines */
99     s = buf;
100     s = strchr(s, '\n'); if (!s) return -1;
101     s++;
102     s = strchr(s, '\n'); if (!s) return -1;
103     s++;
104     s = strchr(s, '\n'); if (!s) return -1;
105     s++;
106 
107     if (sscanf (s, "IpExt: %llu %llu %llu %llu %llu %llu %llu %llu",
108                 &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
109                 &in_octets, &out_octets) != 8)
110         return -1;
111 
112     *bytes = in_octets + out_octets;
113     return 0;
114 }
115 
116 gint
read_netload(gulong * net,gulong * NTotal)117 read_netload (gulong *net, gulong *NTotal)
118 {
119     static guint64 bytes[2];
120     static gint64 time[2];
121 
122     *net = 0;
123     *NTotal = 0;
124 
125     time[1] = g_get_monotonic_time ();
126 
127     if (read_netload_proc (&bytes[1]) != 0)
128         if (read_netload_libgtop (&bytes[1]) != 0)
129             return -1;
130 
131     if (time[0] != 0 && G_LIKELY (time[1] > time[0]) && G_LIKELY (bytes[1] >= bytes[0]))
132     {
133         guint64 diff_bits = 8 * (bytes[1] - bytes[0]);
134         gdouble diff_time = (time[1] - time[0]) / 1e6;
135         *net = MIN (100 * diff_bits / diff_time / MAX_BANDWIDTH_BITS, 100);
136         *NTotal = diff_bits / diff_time;
137     }
138 
139     bytes[0] = bytes[1];
140     time[0] = time[1];
141 
142     return 0;
143 }
144 
145