1 /*
2  * Copyright 2003,2005,2006 Bernhard Walle <bernhard@bwalle.de>
3  * Copyright 2010 Florian Rivoal <frivoal@gmail.com>
4  * -------------------------------------------------------------------------------------------------
5  *
6  *  This program is free software; you can redistribute it and/or modify it
7  *  under the terms of the GNU General Public License as published by the Free
8  *  Software Foundation; either version 2 of the License, or (at your option)
9  *  any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
18  * Ave, Cambridge, MA 02139, USA.
19  *
20  * -------------------------------------------------------------------------------------------------
21  */
22 
23 /*
24  * This is just a wrapper between the netload-plugin and the wormulon source.
25  * Wormulon is a small command-line util which displays the netload. You can find it
26  * at http://raisdorf.net/wormulon. Most sourcecode is taken from wormulon.
27  *
28  * Thanks to Hendrik Scholz. Only his work made it possible to support a large
29  * number of operating systems quickly without a library! Without him only
30  * Linux and FreeBSD (with foreign code from IceWM) would be supported.
31  */
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <libxfce4util/libxfce4util.h>
37 
38 
39 /* From Wormulon */
40 #include "net.h"
41 #include "os.h"
42 #include "wormulon.h"
43 #include "slurm.h"	/* slurm structs */
44 
45 #include <sys/types.h>
46 #include <errno.h>
47 
48 #if defined(__HPUX__)
49 # include "wormulon/hpux.h"
50 # include "wormulon/hpux.c"
51 #elif defined(__APPLE__)
52 # include "src/macos.h"
53 # include "src/macos.c"
54 #elif (defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__))
55 # include "wormulon/freebsd.h"
56 # include "wormulon/freebsd.c"
57 #elif defined(__linux__)
58 # include "wormulon/linux.h"
59 # include "wormulon/linux.c"
60 #elif (defined(__OpenBSD__) || defined(__MicroBSD__))
61 # include "wormulon/openbsd.h"
62 # include "wormulon/openbsd.c"
63 #elif defined(__NetBSD__)
64 # include "wormulon/netbsd.h"
65 # include "wormulon/netbsd.c"
66 #elif defined(__Solaris__)
67 # include "wormulon/solaris.h"
68 # include "wormulon/solaris.c"
69 #else
70 /* should not get here */
71 # error "OS not supported"
72 #endif
73 
74 
75 /* ---------------------------------------------------------------------------------------------- */
init_netload(netdata * data,const char * device)76 int init_netload(netdata* data, const char* device)
77 {
78     memset( data, 0, sizeof(netdata) );
79 
80     if (device == NULL || strlen(device) == 0)
81     {
82         return TRUE;
83     }
84 
85     g_strlcpy(data->ifdata.if_name, device, sizeof(data->ifdata.if_name));
86 
87     init_osspecific( data );
88 
89     data->ip_address[0] = 0;
90     data->ip_update_count = 0;
91     data->up = FALSE;
92     data->up_update_count = 0;
93 
94     if (checkinterface(data) != TRUE)
95 	{
96         data->correct_interface = FALSE;
97 		return FALSE;
98 	}
99 
100     /* init in a sane state */
101     get_stat(data);
102     data->backup_in  = data->stats.rx_bytes;
103     data->backup_out = data->stats.tx_bytes;
104 
105     data->correct_interface = TRUE;
106 
107     DBG("The netload plugin was initialized for '%s'.", device);
108 
109     return TRUE;
110 }
111 
112 
113 /* ---------------------------------------------------------------------------------------------- */
get_current_netload(netdata * data,unsigned long * in,unsigned long * out,unsigned long * tot)114 void get_current_netload(netdata* data, unsigned long *in, unsigned long *out, unsigned long *tot)
115 {
116     struct timeval curr_time;
117     double delta_t;
118 
119     if (! data->correct_interface)
120     {
121         if (in != NULL && out != NULL && tot != NULL)
122         {
123             *in = *out = *tot = 0;
124         }
125     }
126 
127     gettimeofday(&curr_time, NULL);
128 
129     delta_t = (double) ((curr_time.tv_sec  - data->prev_time.tv_sec) * 1000000L
130                              + (curr_time.tv_usec - data->prev_time.tv_usec)) / 1000000.0;
131 
132     /* update */
133     get_stat(data);
134     if (data->backup_in > data->stats.rx_bytes)
135     {
136         data->cur_in = (int)( data->stats.rx_bytes / delta_t + 0.5);
137     }
138     else
139     {
140         data->cur_in = (int)( (data->stats.rx_bytes - data->backup_in) / delta_t + 0.5);
141     }
142 
143     if (data->backup_out > data->stats.tx_bytes)
144     {
145         data->cur_out = (int)( data->stats.tx_bytes / delta_t + 0.5);
146     }
147     else
148     {
149         data->cur_out = (int)( (data->stats.tx_bytes - data->backup_out) / delta_t + 0.5);
150     }
151 
152     if (in != NULL && out != NULL && tot != NULL)
153     {
154         *in = data->cur_in;
155         *out = data->cur_out;
156         *tot = *in + *out;
157     }
158 
159     /* save 'new old' values */
160     data->backup_in = data->stats.rx_bytes;
161     data->backup_out = data->stats.tx_bytes;
162 
163     /* do the same with time */
164     data->prev_time.tv_sec = curr_time.tv_sec;
165     data->prev_time.tv_usec = curr_time.tv_usec;
166 }
167 
168 
169 /* ---------------------------------------------------------------------------------------------- */
get_name(netdata * data)170 char* get_name(netdata* data)
171 {
172     return data->ifdata.if_name;
173 }
174 
175 
176 /* ---------------------------------------------------------------------------------------------- */
get_interface_up(netdata * data)177 int get_interface_up(netdata* data)
178 {
179     int sockfd;
180     struct ifreq ifr;
181 
182     /* if the update count is non-zero */
183     if (data->up_update_count > 0)
184     {
185         data->up_update_count--;
186         return data->up;
187     }
188 
189     /* get the value from the operating system */
190     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
191     {
192         DBG("Error in socket: %s", strerror(errno));
193         return FALSE;
194     }
195 
196     g_snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", data->ifdata.if_name);
197     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0)
198     {
199         DBG("Error in ioctl(sockfd): %s", strerror(errno));
200         close(sockfd);
201         return FALSE;
202     }
203     close(sockfd);
204 
205     data->up = ((ifr.ifr_flags & IFF_UP) == IFF_UP) ? TRUE : FALSE;
206     data->up_update_count = UP_UPDATE_INTERVAL;
207 
208     return data->up;
209 }
210 
211 
212 /* ---------------------------------------------------------------------------------------------- */
get_ip_address(netdata * data)213 char* get_ip_address(netdata* data)
214 {
215     int sockfd;
216     struct ifreq ifr;
217     struct sockaddr_in *p_sa;
218 
219     /* use cached value if possible and if the update count is non-zero */
220     if (data->ip_address && data->ip_update_count > 0)
221     {
222         data->ip_update_count--;
223         return data->ip_address;
224     }
225 
226     /* get the value from the operating system */
227     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
228     {
229         DBG("Error in socket: %s", strerror(errno));
230         return NULL;
231     }
232 
233     g_snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", data->ifdata.if_name);
234     if (ioctl(sockfd, SIOCGIFADDR, &ifr) != 0)
235     {
236 	    if (errno != EADDRNOTAVAIL)
237         {
238             DBG("Error in ioctl(sockfd): %s", strerror(errno));
239         }
240         close(sockfd);
241         return NULL;
242     }
243     close(sockfd);
244 
245     p_sa = (struct sockaddr_in*) &ifr.ifr_addr;
246 
247     if (!inet_ntop(AF_INET, &p_sa->sin_addr, data->ip_address, IP_ADDRESS_LENGTH))
248     {
249         DBG("Error in inet_ntop: %s", strerror(errno));
250         return NULL;
251     }
252 
253     /* now updated */
254     data->ip_update_count = IP_UPDATE_INTERVAL;
255 
256     return data->ip_address;
257 }
258 
259 
260 /* ---------------------------------------------------------------------------------------------- */
close_netload(netdata * data)261 void close_netload(netdata* data)
262 {
263     /* We need not code here */
264 }
265 
266