1 /*
2 * net usage plugin to fbpanel
3 *
4 * Copyright (C) 2004 by Alexandre Pereira da Silva <alexandre.pereira@poli.usp.br>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 /*A little bug fixed by Mykola <mykola@2ka.mipt.ru>:) */
22 /* FreeBSD code borrowed from patches to the lxpanel port */
23
24
25
26 #include "../chart/chart.h"
27
28 #if defined __FreeBSD__ || defined __DragonFly__
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/ioctl.h>
33 #include <ifaddrs.h>
34 #include <net/if.h>
35 #include <net/if_media.h>
36 #include <net/if_var.h>
37 #endif
38
39 #include <stdlib.h>
40 #include <string.h>
41
42 //#define DEBUGPRN
43 #include "dbg.h"
44
45
46 #define CHECK_PERIOD 2 /* second */
47
48 /* net.c */
49 struct net_stat {
50 gulong tx, rx;
51 };
52
53 typedef struct {
54 chart_priv chart;
55 struct net_stat net_prev;
56 int timer;
57 char *iface;
58 gint max_tx;
59 gint max_rx;
60 gulong max;
61 gchar *colors[2];
62 } net_priv;
63
64 static chart_class *k;
65
66
67 static void net_destructor(plugin_instance *p);
68
69
70 #if defined __linux__
71 static int
net_get_load(net_priv * c)72 net_get_load(net_priv *c)
73 {
74 struct net_stat net, net_diff;
75 FILE *stat;
76 float total[2];
77 char buf[256], *s = NULL;
78
79 ENTER;
80 memset(&net, 0, sizeof(net));
81 memset(&net_diff, 0, sizeof(net_diff));
82 stat = fopen("/proc/net/dev", "r");
83 if(!stat)
84 goto end;
85 fgets(buf, 256, stat);
86 fgets(buf, 256, stat);
87
88 while (!s && !feof(stat) && fgets(buf, 256, stat))
89 s = g_strrstr(buf, c->iface);
90 fclose(stat);
91 if (!s)
92 goto end;
93 s = g_strrstr(s, ":");
94 if (!s)
95 goto end;
96 s++;
97 if (sscanf(s,
98 "%lu %*d %*d %*d %*d %*d %*d %*d %lu",
99 &net.rx, &net.tx)!= 2) {
100 DBG("can't read %s statistics\n", c->iface);
101 goto end;
102 }
103 net_diff.tx = ((net.tx - c->net_prev.tx) >> 10) / CHECK_PERIOD;
104 net_diff.rx = ((net.rx - c->net_prev.rx) >> 10) / CHECK_PERIOD;
105 end:
106
107 c->net_prev = net;
108 total[0] = (float)(net_diff.tx) / c->max;
109 total[1] = (float)(net_diff.rx) / c->max;
110 DBG("%f %ul %ul\n", total, net_diff.tx, net_diff.rx);
111 k->add_tick(&c->chart, total);
112 g_snprintf(buf, sizeof(buf), "<b>%s:</b>\nD %lu Kbs, U %lu Kbs",
113 c->iface, net_diff.rx, net_diff.tx);
114 gtk_widget_set_tooltip_markup(((plugin_instance *)c)->pwid, buf);
115 RET(TRUE);
116
117 }
118 #elif defined __FreeBSD__ || defined __DragonFly__
119 static inline gboolean
parse_stats(char * buf,int prx_idx,int ptx_idx,gulong * in_packets,gulong * out_packets,int brx_idx,int btx_idx,gulong * in_bytes,gulong * out_bytes)120 parse_stats(char *buf,
121 int prx_idx,
122 int ptx_idx,
123 gulong * in_packets,
124 gulong * out_packets,
125 int brx_idx,
126 int btx_idx,
127 gulong * in_bytes,
128 gulong * out_bytes)
129 {
130 char *p;
131 int i;
132
133 p = strtok(buf, " \t\n");
134 for (i = 0; p; i++, p = strtok(NULL, " \t\n")) {
135 if (i == prx_idx)
136 *in_packets = g_ascii_strtoull(p, NULL, 10);
137 if (i == ptx_idx)
138 *out_packets = g_ascii_strtoull(p, NULL, 10);
139 if (i == brx_idx)
140 *in_bytes = g_ascii_strtoull(p, NULL, 10);
141 if (i == btx_idx)
142 *out_bytes = g_ascii_strtoull(p, NULL, 10);
143 }
144
145 if (i <= prx_idx || i <= ptx_idx || i <= brx_idx || i <= btx_idx)
146 return FALSE;
147
148 return TRUE;
149 }
150
151 static inline void
parse_header(char * buf,int * prx_idx,int * ptx_idx,int * brx_idx,int * btx_idx)152 parse_header(char *buf,
153 int *prx_idx,
154 int *ptx_idx,
155 int *brx_idx,
156 int *btx_idx)
157 {
158 char *p;
159 int i;
160
161 *prx_idx = *ptx_idx = -1;
162 *brx_idx = *btx_idx = -1;
163
164 p = strtok(buf, " \n\t");
165 for (i = 0; p; i++, p = strtok(NULL, " \t\n")) {
166 if (!strcmp(p, "Ipkts")) {
167 *prx_idx = i;
168 } else if (!strcmp(p, "Ibytes")) {
169 *brx_idx = i;
170 } else if (!strcmp(p, "Opkts")) {
171 *ptx_idx = i;
172 } else if (!strcmp(p, "Obytes")) {
173 *btx_idx = i;
174 }
175 }
176 }
177 static int
net_get_load(net_priv * c)178 net_get_load(net_priv * c)
179 {
180 struct net_stat net, net_diff;
181 float total[2];
182 GError *error;
183 char *command_line;
184 char **argv;
185 char *error_message = NULL;
186 int pipe_out;
187 gulong in_packets = -1;
188 gulong out_packets = -1;
189 gulong in_bytes = -1;
190 gulong out_bytes = -1;
191 char tooltip[256];
192
193 ENTER;
194 error = NULL;
195 command_line = g_strdup_printf("/usr/bin/netstat -n -I %s -b -f inet", c->iface);
196 DBG(command_line);
197 if (!g_shell_parse_argv(command_line, NULL, &argv, &error)) {
198 error_message = g_strdup_printf("Could not parse command line '%s': %s",
199 command_line,
200 error->message);
201 DBG(error_message);
202 g_error_free(error);
203 g_free(command_line);
204 RET(0);
205 }
206 g_free(command_line);
207
208 error = NULL;
209 if (g_spawn_async_with_pipes(NULL,
210 argv,
211 NULL,
212 0,
213 NULL,
214 NULL,
215 NULL,
216 NULL,
217 &pipe_out,
218 NULL,
219 &error)) {
220 GIOChannel *channel;
221 char *buf;
222 int prx_idx , ptx_idx;
223 int brx_idx , btx_idx;
224
225 channel = g_io_channel_unix_new(pipe_out);
226
227 g_io_channel_read_line(channel, &buf, NULL, NULL, NULL);
228 parse_header(buf, &prx_idx, &ptx_idx, &brx_idx, &btx_idx);
229 g_free(buf);
230
231 if (prx_idx == -1 || ptx_idx == -1 ||
232 brx_idx == -1 || btx_idx == -1) {
233 error_message = g_strdup("Could not parse 'netstat' output. Unknown format");
234 DBG(error_message);
235 goto error_shutdown;
236 }
237 g_io_channel_read_line(channel, &buf, NULL, NULL, NULL);
238
239 if (!parse_stats(buf,
240 prx_idx, ptx_idx, &in_packets, &out_packets,
241 brx_idx, btx_idx, &in_bytes, &out_bytes)) {
242 error_message = g_strdup_printf("Could not parse interface statistics from '%s'. "
243 "prx_idx = %d; ptx_idx = %d; brx_idx = %d; btx_idx = %d;",
244 buf, prx_idx, ptx_idx, brx_idx, btx_idx);
245 DBG(error_message);
246 goto error_shutdown;
247 } else if (in_packets == -1 || out_packets == -1 || in_bytes == -1 || out_bytes == -1) {
248 error_message = g_strdup_printf("Could not obtain information on interface '%s' from netstat",
249 c->iface);
250 DBG(error_message);
251 goto error_shutdown;
252 }
253 net.tx = out_bytes;
254 net.rx = in_bytes;
255
256 net_diff.tx = ((net.tx - c->net_prev.tx) >> 10) / CHECK_PERIOD;
257 net_diff.rx = ((net.rx - c->net_prev.rx) >> 10) / CHECK_PERIOD;
258
259 c->net_prev = net;
260 total[0] = (float)(net_diff.tx) / c->max;
261 total[1] = (float)(net_diff.rx) / c->max;
262 DBG("%f %ul %ul\n", total, net_diff.tx, net_diff.rx);
263 k->add_tick(&c->chart, total);
264 g_snprintf(tooltip, sizeof(tooltip), "<b>%s:</b>\nD %lu Kbs, U %lu Kbs",
265 c->iface, net_diff.rx, net_diff.tx);
266 gtk_widget_set_tooltip_markup(((plugin_instance *) c)->pwid, tooltip);
267
268 error_shutdown:
269 g_free(buf);
270 g_io_channel_unref(channel);
271 close(pipe_out);
272 } else {
273 error_message = g_strdup_printf("Error running /usr/bin/netstat for '%s': %s",
274 c->iface, error->message);
275 g_error_free(error);
276 }
277
278 g_strfreev(argv);
279
280 RET(TRUE);
281
282 }
283 #else
284
285 static int
net_get_load(net_priv * c)286 net_get_load(net_priv *c)
287 {
288 ENTER;
289 RET(0);
290 }
291
292 #endif
293
294
295 static int
net_constructor(plugin_instance * p)296 net_constructor(plugin_instance *p)
297 {
298 net_priv *c;
299
300 if (!(k = class_get("chart")))
301 RET(0);
302 if (!PLUGIN_CLASS(k)->constructor(p))
303 RET(0);
304 c = (net_priv *) p;
305
306 c->iface = "eth0";
307 c->max_rx = 120;
308 c->max_tx = 12;
309 c->colors[0] = "violet";
310 c->colors[1] = "blue";
311 XCG(p->xc, "interface", &c->iface, str);
312 XCG(p->xc, "RxLimit", &c->max_rx, int);
313 XCG(p->xc, "TxLimit", &c->max_tx, int);
314 XCG(p->xc, "TxColor", &c->colors[0], str);
315 XCG(p->xc, "RxColor", &c->colors[1], str);
316
317 c->max = c->max_rx + c->max_tx;
318 k->set_rows(&c->chart, 2, c->colors);
319 gtk_widget_set_tooltip_markup(((plugin_instance *)c)->pwid, "<b>Net</b>");
320 net_get_load(c);
321 c->timer = g_timeout_add(CHECK_PERIOD * 1000,
322 (GSourceFunc) net_get_load, (gpointer) c);
323 RET(1);
324 }
325
326
327 static void
net_destructor(plugin_instance * p)328 net_destructor(plugin_instance *p)
329 {
330 net_priv *c = (net_priv *) p;
331
332 ENTER;
333 if (c->timer)
334 g_source_remove(c->timer);
335 PLUGIN_CLASS(k)->destructor(p);
336 class_put("chart");
337 RET();
338 }
339
340
341 static plugin_class class = {
342 .count = 0,
343 .type = "net",
344 .name = "Net usage",
345 .version = "1.0",
346 .description = "Display net usage",
347 .priv_size = sizeof(net_priv),
348
349 .constructor = net_constructor,
350 .destructor = net_destructor,
351 };
352 static plugin_class *class_ptr = (plugin_class *) &class;
353