ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.74
Committed: Wed Jul 13 09:31:54 2005 UTC (18 years, 10 months ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.73: +17 -13 lines
Log Message:
Change the name of the duplex value from "dup" to "duplex". This will
break the ABI, but we're changing the fs stats anyway. The API change
is minimal, so hopefully won't affect too many people.

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