ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.72
Committed: Thu Feb 24 18:35:11 2005 UTC (19 years, 2 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_11_1
Changes since 1.71: +3 -3 lines
Log Message:
The labels in this case statement were the wrong way round, so the duplex
settings were being reported incorrectly on linux. Use the defines instead
of the values so we can be sure they're right.

Spotted by Pete.

File Contents

# User Rev Content
1 tdb 1.22 /*
2 tdb 1.64 * i-scream libstatgrab
3 tdb 1.15 * http://www.i-scream.org
4 tdb 1.22 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.22 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.22 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.22 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.23 *
21 tdb 1.72 * $Id: network_stats.c,v 1.71 2004/11/08 08:07:25 ats Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 tdb 1.4 #include <stdlib.h>
29 pajs 1.6 #include <string.h>
30 pajs 1.1 #include "statgrab.h"
31 ats 1.59 #include "vector.h"
32 ats 1.60 #include "tools.h"
33 tdb 1.11 #include <time.h>
34 pajs 1.1 #ifdef SOLARIS
35     #include <kstat.h>
36     #include <sys/sysinfo.h>
37 ats 1.44 #include <sys/types.h>
38     #include <sys/socket.h>
39     #include <sys/ioctl.h>
40     #include <net/if.h>
41     #include <netinet/in.h>
42     #include <sys/sockio.h>
43 tdb 1.61 #include <unistd.h>
44 pajs 1.6 #endif
45     #ifdef LINUX
46     #include <stdio.h>
47     #include <sys/types.h>
48 pajs 1.27 #include <sys/ioctl.h>
49     #include <sys/socket.h>
50     #include <net/if.h>
51     #include <ctype.h>
52     /* Stuff which could be defined by defining KERNEL, but
53     * that would be a bad idea, so we'll just declare it here
54     */
55     typedef __uint8_t u8;
56     typedef __uint16_t u16;
57     typedef __uint32_t u32;
58 ats 1.42 typedef __uint64_t u64;
59 pajs 1.27 #include <linux/ethtool.h>
60     #include <linux/sockios.h>
61 ats 1.32 #include <unistd.h>
62 pajs 1.1 #endif
63 ats 1.18 #ifdef ALLBSD
64 pajs 1.14 #include <sys/types.h>
65     #include <sys/socket.h>
66     #include <ifaddrs.h>
67     #include <net/if.h>
68 pajs 1.26 #include <net/if_media.h>
69     #include <sys/ioctl.h>
70 tdb 1.58 #include <unistd.h>
71 pajs 1.14 #endif
72 pajs 1.1
73 ats 1.62 static void network_stat_init(sg_network_io_stats *s) {
74 ats 1.59 s->interface_name = NULL;
75     s->tx = 0;
76     s->rx = 0;
77     s->ipackets = 0;
78     s->opackets = 0;
79     s->ierrors = 0;
80     s->oerrors = 0;
81     s->collisions = 0;
82 pajs 1.3 }
83    
84 ats 1.62 static void network_stat_destroy(sg_network_io_stats *s) {
85 ats 1.59 free(s->interface_name);
86 pajs 1.1 }
87    
88 ats 1.62 VECTOR_DECLARE_STATIC(network_stats, sg_network_io_stats, 5,
89 tdb 1.65 network_stat_init, network_stat_destroy);
90 pajs 1.3
91 ats 1.62 sg_network_io_stats *sg_get_network_io_stats(int *entries){
92 ats 1.59 int interfaces;
93 ats 1.62 sg_network_io_stats *network_stat_ptr;
94 pajs 1.6
95     #ifdef SOLARIS
96 tdb 1.65 kstat_ctl_t *kc;
97     kstat_t *ksp;
98 pajs 1.1 kstat_named_t *knp;
99 pajs 1.6 #endif
100 pajs 1.3
101 pajs 1.6 #ifdef LINUX
102     FILE *f;
103 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
104 pajs 1.6 char line[8096];
105     regex_t regex;
106 ats 1.49 regmatch_t line_match[9];
107 pajs 1.14 #endif
108 ats 1.18 #ifdef ALLBSD
109 pajs 1.14 struct ifaddrs *net, *net_ptr;
110     struct if_data *net_data;
111     #endif
112    
113 ats 1.18 #ifdef ALLBSD
114 pajs 1.14 if(getifaddrs(&net) != 0){
115 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
116 pajs 1.14 return NULL;
117     }
118    
119     interfaces=0;
120    
121     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
122     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
123 ats 1.59
124     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
125 pajs 1.14 return NULL;
126     }
127     network_stat_ptr=network_stats+interfaces;
128    
129 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
130 tdb 1.65 net_ptr->ifa_name) < 0) {
131 ats 1.60 return NULL;
132     }
133 pajs 1.14 net_data=(struct if_data *)net_ptr->ifa_data;
134     network_stat_ptr->rx=net_data->ifi_ibytes;
135 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
136     network_stat_ptr->ipackets=net_data->ifi_ipackets;
137     network_stat_ptr->opackets=net_data->ifi_opackets;
138     network_stat_ptr->ierrors=net_data->ifi_ierrors;
139     network_stat_ptr->oerrors=net_data->ifi_oerrors;
140     network_stat_ptr->collisions=net_data->ifi_collisions;
141 pajs 1.14 network_stat_ptr->systime=time(NULL);
142     interfaces++;
143     }
144     freeifaddrs(net);
145 pajs 1.6 #endif
146 pajs 1.1
147 pajs 1.6 #ifdef SOLARIS
148 tdb 1.65 if ((kc = kstat_open()) == NULL) {
149 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
150 tdb 1.65 return NULL;
151     }
152 pajs 1.1
153 pajs 1.6 interfaces=0;
154 pajs 1.3
155 tdb 1.66 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
156 tdb 1.65 if (!strcmp(ksp->ks_class, "net")) {
157     kstat_read(kc, ksp, NULL);
158 pajs 1.1
159 pajs 1.7 #ifdef SOL7
160 tdb 1.53 #define LRX "rbytes"
161     #define LTX "obytes"
162     #define LIPACKETS "ipackets"
163     #define LOPACKETS "opackets"
164 pajs 1.7 #define VALTYPE value.ui32
165     #else
166 tdb 1.53 #define LRX "rbytes64"
167     #define LTX "obytes64"
168     #define LIPACKETS "ipackets64"
169     #define LOPACKETS "opackets64"
170 pajs 1.7 #define VALTYPE value.ui64
171     #endif
172    
173 tdb 1.53 /* Read rx */
174     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
175 ats 1.44 /* This is a network interface, but it doesn't
176     * have the rbytes/obytes values; for instance,
177     * the loopback devices have this behaviour
178     * (although they do track packets in/out). */
179 ats 1.55 /* FIXME: Show packet counts when byte counts
180     * not available. */
181 pajs 1.1 continue;
182     }
183 pajs 1.3
184 tdb 1.53 /* Create new network_stats */
185 ats 1.59 if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
186 pajs 1.1 return NULL;
187     }
188     network_stat_ptr=network_stats+interfaces;
189 tdb 1.53
190     /* Finish reading rx */
191 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
192 pajs 1.1
193 tdb 1.53 /* Read tx */
194     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
195 pajs 1.1 continue;
196     }
197 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
198 tdb 1.53
199     /* Read ipackets */
200     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
201     continue;
202     }
203     network_stat_ptr->ipackets=knp->VALTYPE;
204    
205     /* Read opackets */
206     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
207     continue;
208     }
209     network_stat_ptr->opackets=knp->VALTYPE;
210    
211     /* Read ierrors */
212     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
213     continue;
214     }
215     network_stat_ptr->ierrors=knp->value.ui32;
216    
217     /* Read oerrors */
218     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
219     continue;
220     }
221     network_stat_ptr->oerrors=knp->value.ui32;
222    
223     /* Read collisions */
224     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
225     continue;
226     }
227     network_stat_ptr->collisions=knp->value.ui32;
228    
229     /* Read interface name */
230 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
231 tdb 1.65 ksp->ks_name) < 0) {
232 ats 1.60 return NULL;
233 pajs 1.1 }
234 pajs 1.3
235 tdb 1.53 /* Store systime */
236 pajs 1.3 network_stat_ptr->systime=time(NULL);
237 tdb 1.53
238 pajs 1.1 interfaces++;
239     }
240     }
241 pajs 1.2
242     kstat_close(kc);
243 pajs 1.6 #endif
244     #ifdef LINUX
245     f=fopen("/proc/net/dev", "r");
246     if(f==NULL){
247 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
248 pajs 1.6 return NULL;
249     }
250     /* read the 2 lines.. Its the title, so we dont care :) */
251     fgets(line, sizeof(line), f);
252     fgets(line, sizeof(line), f);
253    
254    
255 ats 1.50 if((regcomp(&regex, "^ *([^:]+): *([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +([0-9]+) +([0-9]+) +([0-9]+) +[0-9]+ +[0-9]+ +([0-9]+)", REG_EXTENDED))!=0){
256 tdb 1.66 sg_set_error(SG_ERROR_PARSE, NULL);
257 pajs 1.6 return NULL;
258     }
259    
260     interfaces=0;
261 pajs 1.1
262 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
263 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
264 pajs 1.6 continue;
265     }
266 ats 1.59
267     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
268     return NULL;
269 pajs 1.6 }
270 tdb 1.65 network_stat_ptr=network_stats+interfaces;
271 pajs 1.6
272     if(network_stat_ptr->interface_name!=NULL){
273     free(network_stat_ptr->interface_name);
274     }
275    
276 ats 1.62 network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]);
277     network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]);
278     network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]);
279     network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]);
280     network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]);
281     network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]);
282     network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]);
283     network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]);
284 pajs 1.6 network_stat_ptr->systime=time(NULL);
285    
286     interfaces++;
287     }
288 pajs 1.12 fclose(f);
289 pajs 1.13 regfree(&regex);
290 pajs 1.6
291     #endif
292 ats 1.20
293     #ifdef CYGWIN
294 tdb 1.66 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
295 ats 1.70 return NULL;
296     #endif
297     #ifdef HPUX
298     sg_set_error(SG_ERROR_UNSUPPORTED, "HP-UX");
299 ats 1.20 return NULL;
300     #endif
301    
302 pajs 1.1 *entries=interfaces;
303    
304     return network_stats;
305 pajs 1.3 }
306    
307 ats 1.62 static long long transfer_diff(long long new, long long old){
308 ats 1.56 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD) || defined(OPENBSD)
309     /* 32-bit quantities, so we must explicitly deal with wraparound. */
310     #define MAXVAL 0x100000000LL
311     if (new >= old) {
312     return new - old;
313     } else {
314     return MAXVAL + new - old;
315     }
316 pajs 1.8 #else
317 ats 1.56 /* 64-bit quantities, so plain subtraction works. */
318     return new - old;
319 pajs 1.8 #endif
320     }
321    
322 ats 1.62 sg_network_io_stats *sg_get_network_io_stats_diff(int *entries) {
323     VECTOR_DECLARE_STATIC(diff, sg_network_io_stats, 1,
324 tdb 1.65 network_stat_init, network_stat_destroy);
325 ats 1.62 sg_network_io_stats *src = NULL, *dest;
326 ats 1.59 int i, j, diff_count, new_count;
327 ats 1.24
328     if (network_stats == NULL) {
329     /* No previous stats, so we can't calculate a difference. */
330 ats 1.62 return sg_get_network_io_stats(entries);
331 pajs 1.3 }
332    
333 ats 1.24 /* Resize the results array to match the previous stats. */
334 ats 1.59 diff_count = VECTOR_SIZE(network_stats);
335     if (VECTOR_RESIZE(diff, diff_count) < 0) {
336 pajs 1.3 return NULL;
337     }
338    
339 ats 1.24 /* Copy the previous stats into the result. */
340     for (i = 0; i < diff_count; i++) {
341     src = &network_stats[i];
342     dest = &diff[i];
343 pajs 1.3
344 ats 1.62 if (sg_update_string(&dest->interface_name,
345 tdb 1.65 src->interface_name) < 0) {
346 ats 1.60 return NULL;
347 pajs 1.3 }
348 ats 1.24 dest->rx = src->rx;
349     dest->tx = src->tx;
350 tdb 1.47 dest->ipackets = src->ipackets;
351     dest->opackets = src->opackets;
352     dest->ierrors = src->ierrors;
353     dest->oerrors = src->oerrors;
354     dest->collisions = src->collisions;
355 ats 1.24 dest->systime = src->systime;
356     }
357 pajs 1.3
358 ats 1.24 /* Get a new set of stats. */
359 ats 1.62 if (sg_get_network_io_stats(&new_count) == NULL) {
360 ats 1.21 return NULL;
361     }
362 pajs 1.3
363 ats 1.24 /* For each previous stat... */
364     for (i = 0; i < diff_count; i++) {
365     dest = &diff[i];
366    
367     /* ... find the corresponding new stat ... */
368     for (j = 0; j < new_count; j++) {
369     /* Try the new stat in the same position first,
370     since that's most likely to be it. */
371     src = &network_stats[(i + j) % new_count];
372     if (strcmp(src->interface_name, dest->interface_name) == 0) {
373     break;
374     }
375     }
376     if (j == new_count) {
377     /* No match found. */
378     continue;
379 pajs 1.3 }
380    
381 ats 1.24 /* ... and subtract the previous stat from it to get the
382     difference. */
383     dest->rx = transfer_diff(src->rx, dest->rx);
384     dest->tx = transfer_diff(src->tx, dest->tx);
385 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
386     dest->opackets = transfer_diff(src->opackets, dest->opackets);
387     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
388     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
389     dest->collisions = transfer_diff(src->collisions, dest->collisions);
390 ats 1.24 dest->systime = src->systime - dest->systime;
391 pajs 1.3 }
392    
393 ats 1.24 *entries = diff_count;
394     return diff;
395     }
396 ats 1.59
397 ats 1.68 int sg_network_io_compare_name(const void *va, const void *vb) {
398     const sg_network_io_stats *a = (const sg_network_io_stats *)va;
399     const sg_network_io_stats *b = (const sg_network_io_stats *)vb;
400    
401     return strcmp(a->interface_name, b->interface_name);
402     }
403    
404 pajs 1.25 /* NETWORK INTERFACE STATS */
405    
406 ats 1.62 static void network_iface_stat_init(sg_network_iface_stats *s) {
407 ats 1.59 s->interface_name = NULL;
408     s->speed = 0;
409 ats 1.62 s->dup = SG_IFACE_DUPLEX_UNKNOWN;
410 pajs 1.25 }
411    
412 ats 1.62 static void network_iface_stat_destroy(sg_network_iface_stats *s) {
413 ats 1.59 free(s->interface_name);
414 pajs 1.25 }
415    
416 ats 1.62 sg_network_iface_stats *sg_get_network_iface_stats(int *entries){
417     VECTOR_DECLARE_STATIC(network_iface_stats, sg_network_iface_stats, 5,
418 tdb 1.65 network_iface_stat_init, network_iface_stat_destroy);
419 ats 1.62 sg_network_iface_stats *network_iface_stat_ptr;
420 ats 1.43 int ifaces = 0;
421 pajs 1.25
422     #ifdef SOLARIS
423 tdb 1.65 kstat_ctl_t *kc;
424     kstat_t *ksp;
425 pajs 1.25 kstat_named_t *knp;
426 ats 1.44 int sock;
427 pajs 1.25 #endif
428 pajs 1.26 #ifdef ALLBSD
429 tdb 1.65 struct ifaddrs *net, *net_ptr;
430 pajs 1.26 struct ifmediareq ifmed;
431 pajs 1.36 struct ifreq ifr;
432 ats 1.37 int sock;
433 pajs 1.26 int x;
434     #endif
435 pajs 1.27 #ifdef LINUX
436 tdb 1.65 FILE *f;
437     /* Horrible big enough, but it should be easily big enough */
438     char line[8096];
439 pajs 1.27 int sock;
440     #endif
441 ats 1.43
442 pajs 1.26 #ifdef ALLBSD
443 tdb 1.65 if(getifaddrs(&net) != 0){
444 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
445 tdb 1.65 return NULL;
446     }
447 pajs 1.26
448 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
449 pajs 1.26
450     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
451 tdb 1.65 if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
452 ats 1.59
453     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
454 tdb 1.65 return NULL;
455     }
456     network_iface_stat_ptr = network_iface_stats + ifaces;
457 pajs 1.26
458 ats 1.40 memset(&ifr, 0, sizeof(ifr));
459     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
460    
461     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
462     continue;
463     }
464     if((ifr.ifr_flags & IFF_UP) != 0){
465     network_iface_stat_ptr->up = 1;
466     }else{
467     network_iface_stat_ptr->up = 0;
468     }
469    
470 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
471 tdb 1.65 net_ptr->ifa_name) < 0) {
472 ats 1.60 return NULL;
473     }
474 ats 1.40
475     network_iface_stat_ptr->speed = 0;
476 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
477 ats 1.40 ifaces++;
478    
479 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
480 ats 1.62 sg_strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
481 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
482 ats 1.40 /* Not all interfaces support the media ioctls. */
483 pajs 1.26 continue;
484     }
485    
486     /* We may need to change this if we start doing wireless devices too */
487     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
488     /* Not a ETHER device */
489     continue;
490     }
491    
492     /* Only intrested in the first 4 bits) - Assuming only ETHER devices */
493     x = ifmed.ifm_active & 0x0f;
494     switch(x){
495     /* 10 Mbit connections. Speedy :) */
496     case(IFM_10_T):
497     case(IFM_10_2):
498     case(IFM_10_5):
499     case(IFM_10_STP):
500     case(IFM_10_FL):
501     network_iface_stat_ptr->speed = 10;
502     break;
503     /* 100 Mbit conneections */
504     case(IFM_100_TX):
505     case(IFM_100_FX):
506     case(IFM_100_T4):
507     case(IFM_100_VG):
508     case(IFM_100_T2):
509     network_iface_stat_ptr->speed = 100;
510     break;
511     /* 1000 Mbit connections */
512     case(IFM_1000_SX):
513     case(IFM_1000_LX):
514     case(IFM_1000_CX):
515 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
516     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
517 tdb 1.45 #endif
518     #ifdef IFM_1000_FX
519     case(IFM_1000_FX): /* FreeBSD 4 */
520     #endif
521     #ifdef IFM_1000_T
522     case(IFM_1000_T): /* FreeBSD 5 */
523 tdb 1.28 #endif
524 pajs 1.26 network_iface_stat_ptr->speed = 1000;
525     break;
526     /* We don't know what it is */
527     default:
528     network_iface_stat_ptr->speed = 0;
529     break;
530     }
531    
532     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
533 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
534 pajs 1.26 }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
535 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
536 pajs 1.26 }else{
537 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
538 pajs 1.26 }
539 pajs 1.36
540 pajs 1.26 }
541     freeifaddrs(net);
542 ats 1.37 close(sock);
543 pajs 1.26 #endif
544 pajs 1.25
545     #ifdef SOLARIS
546 ats 1.44 if ((kc = kstat_open()) == NULL) {
547 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
548 ats 1.44 return NULL;
549     }
550    
551     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
552 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
553 ats 1.44 return NULL;
554     }
555 pajs 1.25
556 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
557     if (!strcmp(ksp->ks_class, "net")) {
558     struct ifreq ifr;
559    
560     kstat_read(kc, ksp, NULL);
561    
562     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
563     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
564     /* Not a network interface. */
565 pajs 1.25 continue;
566     }
567 ats 1.44
568 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
569 pajs 1.25 return NULL;
570     }
571 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
572 ats 1.44 ifaces++;
573    
574 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
575 tdb 1.65 ksp->ks_name) < 0) {
576 ats 1.60 return NULL;
577     }
578 pajs 1.25
579 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
580     network_iface_stat_ptr->up = 1;
581     } else {
582     network_iface_stat_ptr->up = 1;
583     }
584 pajs 1.35
585 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
586     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
587     } else {
588     network_iface_stat_ptr->speed = 0;
589 pajs 1.25 }
590    
591 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
592 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
593     switch (knp->value.ui32) {
594     case 1:
595 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
596 ats 1.44 break;
597     case 2:
598 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
599 ats 1.44 break;
600     }
601 pajs 1.33 }
602 pajs 1.25 }
603     }
604 ats 1.44
605     close(sock);
606 pajs 1.25 kstat_close(kc);
607     #endif
608 pajs 1.27 #ifdef LINUX
609     f = fopen("/proc/net/dev", "r");
610 tdb 1.65 if(f == NULL){
611 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
612 tdb 1.65 return NULL;
613     }
614 pajs 1.27
615     /* Setup stuff so we can do the ioctl to get the info */
616     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
617 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
618 pajs 1.27 return NULL;
619     }
620    
621     /* Ignore first 2 lines.. Just headings */
622 tdb 1.66 if((fgets(line, sizeof(line), f)) == NULL) {
623     sg_set_error(SG_ERROR_PARSE, NULL);
624     return NULL;
625     }
626     if((fgets(line, sizeof(line), f)) == NULL) {
627     sg_set_error(SG_ERROR_PARSE, NULL);
628     return NULL;
629     }
630 pajs 1.27
631 tdb 1.65 while((fgets(line, sizeof(line), f)) != NULL){
632     char *name, *ptr;
633     struct ifreq ifr;
634     struct ethtool_cmd ethcmd;
635     int err;
636 pajs 1.27
637     /* Get the interface name */
638 tdb 1.65 ptr = strchr(line, ':');
639     if (ptr == NULL) continue;
640     *ptr='\0';
641     name = line;
642     while(isspace(*(name))){
643     name++;
644     }
645 pajs 1.27
646 tdb 1.65 memset(&ifr, 0, sizeof ifr);
647     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
648 pajs 1.27
649 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
650     continue;
651     }
652 pajs 1.27
653     /* We have a good interface to add */
654 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
655 pajs 1.27 return NULL;
656     }
657     network_iface_stat_ptr = network_iface_stats + ifaces;
658 ats 1.60
659 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
660 tdb 1.65 name) < 0) {
661 ats 1.60 return NULL;
662     }
663 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
664 pajs 1.35 network_iface_stat_ptr->up = 1;
665 ats 1.38 } else {
666 pajs 1.35 network_iface_stat_ptr->up = 0;
667     }
668    
669 tdb 1.65 memset(&ethcmd, 0, sizeof ethcmd);
670     ethcmd.cmd = ETHTOOL_GSET;
671     ifr.ifr_data = (caddr_t) &ethcmd;
672 ats 1.38
673 tdb 1.65 err = ioctl(sock, SIOCETHTOOL, &ifr);
674     if (err == 0) {
675 ats 1.38 network_iface_stat_ptr->speed = ethcmd.speed;
676    
677     switch (ethcmd.duplex) {
678 tdb 1.72 case DUPLEX_FULL:
679 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_FULL;
680 ats 1.38 break;
681 tdb 1.72 case DUPLEX_HALF:
682 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_HALF;
683 ats 1.38 break;
684     default:
685 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
686 ats 1.38 }
687     } else {
688     /* Not all interfaces support the ethtool ioctl. */
689 ats 1.39 network_iface_stat_ptr->speed = 0;
690 ats 1.62 network_iface_stat_ptr->dup = SG_IFACE_DUPLEX_UNKNOWN;
691 pajs 1.27 }
692 ats 1.38
693 pajs 1.27 ifaces++;
694     }
695 pajs 1.30 close(sock);
696 ats 1.38 fclose(f);
697 pajs 1.27 #endif
698 ats 1.71 #ifdef CYGWIN
699     sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
700     return NULL;
701     #endif
702     #ifdef HPUX
703     sg_set_error(SG_ERROR_UNSUPPORTED, "HP-UX");
704     return NULL;
705     #endif
706    
707 pajs 1.26 *entries = ifaces;
708 pajs 1.25 return network_iface_stats;
709 ats 1.68 }
710    
711     int sg_network_iface_compare_name(const void *va, const void *vb) {
712     const sg_network_iface_stats *a = (const sg_network_iface_stats *)va;
713     const sg_network_iface_stats *b = (const sg_network_iface_stats *)vb;
714    
715     return strcmp(a->interface_name, b->interface_name);
716 pajs 1.25 }
717