ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.80
Committed: Mon Oct 9 17:25:06 2006 UTC (17 years, 7 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: LIBSTATGRAB_0_17, LIBSTATGRAB_0_16, LIBSTATGRAB_0_15, LIBSTATGRAB_0_14
Changes since 1.79: +14 -2 lines
Log Message:
When checking the interface up status check the link status as well.

Suggested by: "Vassallo, Michelangelo (Michelangelo)" <vassallo@lucent.com>

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.80 * $Id: network_stats.c,v 1.79 2006/10/09 17:23:07 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 tdb 1.73 #include <linux/version.h>
53 ats 1.75 #include <asm/types.h>
54     /* These aren't defined by asm/types.h unless the kernel is being
55     compiled, but some versions of ethtool.h need them. */
56 pajs 1.27 typedef __uint8_t u8;
57     typedef __uint16_t u16;
58     typedef __uint32_t u32;
59 ats 1.42 typedef __uint64_t u64;
60 pajs 1.27 #include <linux/ethtool.h>
61     #include <linux/sockios.h>
62 ats 1.32 #include <unistd.h>
63 pajs 1.1 #endif
64 ats 1.18 #ifdef ALLBSD
65 pajs 1.14 #include <sys/types.h>
66     #include <sys/socket.h>
67     #include <ifaddrs.h>
68     #include <net/if.h>
69 pajs 1.26 #include <net/if_media.h>
70     #include <sys/ioctl.h>
71 tdb 1.58 #include <unistd.h>
72 pajs 1.14 #endif
73 tdb 1.76 #ifdef WIN32
74     #include <windows.h>
75     #include <Iphlpapi.h>
76     #include "win32.h"
77     #endif
78 pajs 1.1
79 ats 1.62 static void network_stat_init(sg_network_io_stats *s) {
80 ats 1.59 s->interface_name = NULL;
81     s->tx = 0;
82     s->rx = 0;
83     s->ipackets = 0;
84     s->opackets = 0;
85     s->ierrors = 0;
86     s->oerrors = 0;
87     s->collisions = 0;
88 pajs 1.3 }
89    
90 ats 1.62 static void network_stat_destroy(sg_network_io_stats *s) {
91 ats 1.59 free(s->interface_name);
92 pajs 1.1 }
93    
94 ats 1.62 VECTOR_DECLARE_STATIC(network_stats, sg_network_io_stats, 5,
95 tdb 1.65 network_stat_init, network_stat_destroy);
96 pajs 1.3
97 tdb 1.76 #ifdef WIN32
98     static PMIB_IFTABLE win32_get_devices()
99     {
100     PMIB_IFTABLE if_table;
101     PMIB_IFTABLE tmp;
102     unsigned long dwSize = 0;
103    
104     // Allocate memory for pointers
105     if_table = sg_malloc(sizeof(MIB_IFTABLE));
106     if(if_table == NULL) {
107     return NULL;
108     }
109    
110     // Get necessary size for the buffer
111     if(GetIfTable(if_table, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
112     tmp = sg_realloc(if_table, dwSize);
113     if(tmp == NULL) {
114     free(if_table);
115     return NULL;
116     }
117     if_table = tmp;
118     }
119    
120     // Get the data
121     if(GetIfTable(if_table, &dwSize, 0) != NO_ERROR) {
122     free(if_table);
123     return NULL;
124     }
125     return if_table;
126     }
127     #endif /* WIN32 */
128    
129 ats 1.62 sg_network_io_stats *sg_get_network_io_stats(int *entries){
130 ats 1.59 int interfaces;
131 ats 1.62 sg_network_io_stats *network_stat_ptr;
132 pajs 1.6
133     #ifdef SOLARIS
134 tdb 1.65 kstat_ctl_t *kc;
135     kstat_t *ksp;
136 pajs 1.1 kstat_named_t *knp;
137 pajs 1.6 #endif
138 pajs 1.3
139 pajs 1.6 #ifdef LINUX
140     FILE *f;
141 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
142 pajs 1.6 char line[8096];
143     regex_t regex;
144 ats 1.49 regmatch_t line_match[9];
145 pajs 1.14 #endif
146 ats 1.18 #ifdef ALLBSD
147 pajs 1.14 struct ifaddrs *net, *net_ptr;
148     struct if_data *net_data;
149     #endif
150 tdb 1.76 #ifdef WIN32
151     PMIB_IFTABLE if_table;
152     MIB_IFROW if_row;
153     int i, no, j;
154    
155     /* used for duplicate interface names. 5 for space, hash, up to two
156     * numbers and terminating slash */
157     char buf[5];
158     #endif
159 pajs 1.14
160 ats 1.18 #ifdef ALLBSD
161 pajs 1.14 if(getifaddrs(&net) != 0){
162 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
163 pajs 1.14 return NULL;
164     }
165    
166     interfaces=0;
167    
168     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
169     if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
170 ats 1.59
171     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
172 pajs 1.14 return NULL;
173     }
174     network_stat_ptr=network_stats+interfaces;
175    
176 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
177 tdb 1.65 net_ptr->ifa_name) < 0) {
178 ats 1.60 return NULL;
179     }
180 pajs 1.14 net_data=(struct if_data *)net_ptr->ifa_data;
181     network_stat_ptr->rx=net_data->ifi_ibytes;
182 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
183     network_stat_ptr->ipackets=net_data->ifi_ipackets;
184     network_stat_ptr->opackets=net_data->ifi_opackets;
185     network_stat_ptr->ierrors=net_data->ifi_ierrors;
186     network_stat_ptr->oerrors=net_data->ifi_oerrors;
187     network_stat_ptr->collisions=net_data->ifi_collisions;
188 pajs 1.14 network_stat_ptr->systime=time(NULL);
189     interfaces++;
190     }
191     freeifaddrs(net);
192 pajs 1.6 #endif
193 pajs 1.1
194 pajs 1.6 #ifdef SOLARIS
195 tdb 1.65 if ((kc = kstat_open()) == NULL) {
196 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
197 tdb 1.65 return NULL;
198     }
199 pajs 1.1
200 pajs 1.6 interfaces=0;
201 pajs 1.3
202 tdb 1.66 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
203 tdb 1.76 if (strcmp(ksp->ks_class, "net") == 0) {
204 tdb 1.65 kstat_read(kc, ksp, NULL);
205 pajs 1.1
206 pajs 1.7 #ifdef SOL7
207 tdb 1.53 #define LRX "rbytes"
208     #define LTX "obytes"
209     #define LIPACKETS "ipackets"
210     #define LOPACKETS "opackets"
211 pajs 1.7 #define VALTYPE value.ui32
212     #else
213 tdb 1.53 #define LRX "rbytes64"
214     #define LTX "obytes64"
215     #define LIPACKETS "ipackets64"
216     #define LOPACKETS "opackets64"
217 pajs 1.7 #define VALTYPE value.ui64
218     #endif
219    
220 tdb 1.53 /* Read rx */
221     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
222 ats 1.44 /* This is a network interface, but it doesn't
223     * have the rbytes/obytes values; for instance,
224     * the loopback devices have this behaviour
225     * (although they do track packets in/out). */
226 ats 1.55 /* FIXME: Show packet counts when byte counts
227     * not available. */
228 pajs 1.1 continue;
229     }
230 pajs 1.3
231 tdb 1.53 /* Create new network_stats */
232 ats 1.59 if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
233 tdb 1.78 kstat_close(kc);
234 pajs 1.1 return NULL;
235     }
236     network_stat_ptr=network_stats+interfaces;
237 tdb 1.53
238 tdb 1.79 /* Read interface name */
239     if (sg_update_string(&network_stat_ptr->interface_name,
240     ksp->ks_name) < 0) {
241     kstat_close(kc);
242     return NULL;
243     }
244    
245 tdb 1.53 /* Finish reading rx */
246 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
247 pajs 1.1
248 tdb 1.53 /* Read tx */
249     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
250 pajs 1.1 continue;
251     }
252 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
253 tdb 1.53
254     /* Read ipackets */
255     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
256     continue;
257     }
258     network_stat_ptr->ipackets=knp->VALTYPE;
259    
260     /* Read opackets */
261     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
262     continue;
263     }
264     network_stat_ptr->opackets=knp->VALTYPE;
265    
266     /* Read ierrors */
267     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
268     continue;
269     }
270     network_stat_ptr->ierrors=knp->value.ui32;
271    
272     /* Read oerrors */
273     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
274     continue;
275     }
276     network_stat_ptr->oerrors=knp->value.ui32;
277    
278     /* Read collisions */
279     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
280     continue;
281     }
282     network_stat_ptr->collisions=knp->value.ui32;
283    
284 pajs 1.3
285 tdb 1.53 /* Store systime */
286 pajs 1.3 network_stat_ptr->systime=time(NULL);
287 tdb 1.53
288 pajs 1.1 interfaces++;
289     }
290     }
291 pajs 1.2
292     kstat_close(kc);
293 pajs 1.6 #endif
294     #ifdef LINUX
295     f=fopen("/proc/net/dev", "r");
296     if(f==NULL){
297 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
298 pajs 1.6 return NULL;
299     }
300     /* read the 2 lines.. Its the title, so we dont care :) */
301     fgets(line, sizeof(line), f);
302     fgets(line, sizeof(line), f);
303    
304    
305 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){
306 tdb 1.66 sg_set_error(SG_ERROR_PARSE, NULL);
307 pajs 1.6 return NULL;
308     }
309    
310     interfaces=0;
311 pajs 1.1
312 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
313 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
314 pajs 1.6 continue;
315     }
316 ats 1.59
317     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
318     return NULL;
319 pajs 1.6 }
320 tdb 1.65 network_stat_ptr=network_stats+interfaces;
321 pajs 1.6
322     if(network_stat_ptr->interface_name!=NULL){
323     free(network_stat_ptr->interface_name);
324     }
325    
326 ats 1.62 network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]);
327     network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]);
328     network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]);
329     network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]);
330     network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]);
331     network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]);
332     network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]);
333     network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]);
334 pajs 1.6 network_stat_ptr->systime=time(NULL);
335    
336     interfaces++;
337     }
338 pajs 1.12 fclose(f);
339 pajs 1.13 regfree(&regex);
340 pajs 1.6
341     #endif
342 ats 1.20
343     #ifdef CYGWIN
344 tdb 1.66 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
345 ats 1.70 return NULL;
346     #endif
347     #ifdef HPUX
348     sg_set_error(SG_ERROR_UNSUPPORTED, "HP-UX");
349 ats 1.20 return NULL;
350     #endif
351    
352 tdb 1.76 #ifdef WIN32
353     interfaces = 0;
354    
355     if((if_table = win32_get_devices()) == NULL) {
356     sg_set_error(SG_ERROR_DEVICES, "network");
357     return NULL;
358     }
359    
360     if(VECTOR_RESIZE(network_stats, if_table->dwNumEntries) < 0) {
361     free(if_table);
362     return NULL;
363     }
364    
365     for (i=0; i<if_table->dwNumEntries; i++) {
366     network_stat_ptr=network_stats+i;
367     if_row = if_table->table[i];
368    
369     if(sg_update_string(&network_stat_ptr->interface_name,
370     if_row.bDescr) < 0) {
371     free(if_table);
372     return NULL;
373     }
374     network_stat_ptr->tx = if_row.dwOutOctets;
375     network_stat_ptr->rx = if_row.dwInOctets;
376     network_stat_ptr->ipackets = if_row.dwInUcastPkts + if_row.dwInNUcastPkts;
377     network_stat_ptr->opackets = if_row.dwOutUcastPkts + if_row.dwOutNUcastPkts;
378     network_stat_ptr->ierrors = if_row.dwInErrors;
379     network_stat_ptr->oerrors = if_row.dwOutErrors;
380     network_stat_ptr->collisions = 0; /* can't do that */
381     network_stat_ptr->systime = time(NULL);
382    
383     interfaces++;
384     }
385     free(if_table);
386    
387     /* Please say there's a nicer way to do this... If windows has two (or
388     * more) identical network cards, GetIfTable returns them with the same
389     * name, not like in Device Manager where the other has a #2 etc after
390     * it. So, add the #number here. Should we be doing this? Or should the
391     * end programs be dealing with duplicate names? Currently breaks
392     * watch.pl in rrdgraphing. But Unix does not have the issue of
393     * duplicate net device names.
394     */
395     for (i=0; i<interfaces; i++) {
396     no = 2;
397     for(j=i+1; j<interfaces; j++) {
398     network_stat_ptr=network_stats+j;
399     if(strcmp(network_stats[i].interface_name,
400     network_stat_ptr->interface_name) == 0) {
401     if(snprintf(buf, sizeof(buf), " #%d", no) < 0) {
402     break;
403     }
404     if(sg_concat_string(&network_stat_ptr->interface_name, buf) != 0) {
405     return NULL;
406     }
407    
408     no++;
409     }
410     }
411     }
412     #endif
413    
414 pajs 1.1 *entries=interfaces;
415    
416     return network_stats;
417 pajs 1.3 }
418    
419 ats 1.62 static long long transfer_diff(long long new, long long old){
420 tdb 1.76 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD) || defined(OPENBSD) || defined(WIN32)
421 ats 1.56 /* 32-bit quantities, so we must explicitly deal with wraparound. */
422     #define MAXVAL 0x100000000LL
423     if (new >= old) {
424     return new - old;
425     } else {
426     return MAXVAL + new - old;
427     }
428 pajs 1.8 #else
429 ats 1.56 /* 64-bit quantities, so plain subtraction works. */
430     return new - old;
431 pajs 1.8 #endif
432     }
433    
434 ats 1.62 sg_network_io_stats *sg_get_network_io_stats_diff(int *entries) {
435     VECTOR_DECLARE_STATIC(diff, sg_network_io_stats, 1,
436 tdb 1.65 network_stat_init, network_stat_destroy);
437 ats 1.62 sg_network_io_stats *src = NULL, *dest;
438 ats 1.59 int i, j, diff_count, new_count;
439 ats 1.24
440     if (network_stats == NULL) {
441     /* No previous stats, so we can't calculate a difference. */
442 ats 1.62 return sg_get_network_io_stats(entries);
443 pajs 1.3 }
444    
445 ats 1.24 /* Resize the results array to match the previous stats. */
446 ats 1.59 diff_count = VECTOR_SIZE(network_stats);
447     if (VECTOR_RESIZE(diff, diff_count) < 0) {
448 pajs 1.3 return NULL;
449     }
450    
451 ats 1.24 /* Copy the previous stats into the result. */
452     for (i = 0; i < diff_count; i++) {
453     src = &network_stats[i];
454     dest = &diff[i];
455 pajs 1.3
456 ats 1.62 if (sg_update_string(&dest->interface_name,
457 tdb 1.65 src->interface_name) < 0) {
458 ats 1.60 return NULL;
459 pajs 1.3 }
460 ats 1.24 dest->rx = src->rx;
461     dest->tx = src->tx;
462 tdb 1.47 dest->ipackets = src->ipackets;
463     dest->opackets = src->opackets;
464     dest->ierrors = src->ierrors;
465     dest->oerrors = src->oerrors;
466     dest->collisions = src->collisions;
467 ats 1.24 dest->systime = src->systime;
468     }
469 pajs 1.3
470 ats 1.24 /* Get a new set of stats. */
471 ats 1.62 if (sg_get_network_io_stats(&new_count) == NULL) {
472 ats 1.21 return NULL;
473     }
474 pajs 1.3
475 ats 1.24 /* For each previous stat... */
476     for (i = 0; i < diff_count; i++) {
477     dest = &diff[i];
478    
479     /* ... find the corresponding new stat ... */
480     for (j = 0; j < new_count; j++) {
481     /* Try the new stat in the same position first,
482     since that's most likely to be it. */
483     src = &network_stats[(i + j) % new_count];
484     if (strcmp(src->interface_name, dest->interface_name) == 0) {
485     break;
486     }
487     }
488     if (j == new_count) {
489     /* No match found. */
490     continue;
491 pajs 1.3 }
492    
493 ats 1.24 /* ... and subtract the previous stat from it to get the
494     difference. */
495     dest->rx = transfer_diff(src->rx, dest->rx);
496     dest->tx = transfer_diff(src->tx, dest->tx);
497 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
498     dest->opackets = transfer_diff(src->opackets, dest->opackets);
499     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
500     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
501     dest->collisions = transfer_diff(src->collisions, dest->collisions);
502 ats 1.24 dest->systime = src->systime - dest->systime;
503 pajs 1.3 }
504    
505 ats 1.24 *entries = diff_count;
506     return diff;
507     }
508 ats 1.59
509 ats 1.68 int sg_network_io_compare_name(const void *va, const void *vb) {
510     const sg_network_io_stats *a = (const sg_network_io_stats *)va;
511     const sg_network_io_stats *b = (const sg_network_io_stats *)vb;
512    
513     return strcmp(a->interface_name, b->interface_name);
514     }
515    
516 pajs 1.25 /* NETWORK INTERFACE STATS */
517    
518 ats 1.62 static void network_iface_stat_init(sg_network_iface_stats *s) {
519 ats 1.59 s->interface_name = NULL;
520     s->speed = 0;
521 tdb 1.74 s->duplex = SG_IFACE_DUPLEX_UNKNOWN;
522 pajs 1.25 }
523    
524 ats 1.62 static void network_iface_stat_destroy(sg_network_iface_stats *s) {
525 ats 1.59 free(s->interface_name);
526 pajs 1.25 }
527    
528 ats 1.62 sg_network_iface_stats *sg_get_network_iface_stats(int *entries){
529     VECTOR_DECLARE_STATIC(network_iface_stats, sg_network_iface_stats, 5,
530 tdb 1.65 network_iface_stat_init, network_iface_stat_destroy);
531 ats 1.62 sg_network_iface_stats *network_iface_stat_ptr;
532 ats 1.43 int ifaces = 0;
533 pajs 1.25
534     #ifdef SOLARIS
535 tdb 1.65 kstat_ctl_t *kc;
536     kstat_t *ksp;
537 pajs 1.25 kstat_named_t *knp;
538 ats 1.44 int sock;
539 pajs 1.25 #endif
540 pajs 1.26 #ifdef ALLBSD
541 tdb 1.65 struct ifaddrs *net, *net_ptr;
542 pajs 1.26 struct ifmediareq ifmed;
543 pajs 1.36 struct ifreq ifr;
544 ats 1.37 int sock;
545 pajs 1.26 int x;
546     #endif
547 pajs 1.27 #ifdef LINUX
548 tdb 1.65 FILE *f;
549     /* Horrible big enough, but it should be easily big enough */
550     char line[8096];
551 pajs 1.27 int sock;
552     #endif
553 tdb 1.76 #ifdef WIN32
554     PMIB_IFTABLE if_table;
555     MIB_IFROW if_row;
556     int i,j,no;
557     char buf[5];
558     #endif
559 ats 1.43
560 pajs 1.26 #ifdef ALLBSD
561 tdb 1.65 if(getifaddrs(&net) != 0){
562 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
563 tdb 1.65 return NULL;
564     }
565 pajs 1.26
566 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
567 pajs 1.26
568     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
569 tdb 1.65 if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
570 ats 1.59
571     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
572 tdb 1.65 return NULL;
573     }
574     network_iface_stat_ptr = network_iface_stats + ifaces;
575 pajs 1.26
576 ats 1.40 memset(&ifr, 0, sizeof(ifr));
577     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
578    
579     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
580     continue;
581     }
582     if((ifr.ifr_flags & IFF_UP) != 0){
583     network_iface_stat_ptr->up = 1;
584     }else{
585     network_iface_stat_ptr->up = 0;
586     }
587    
588 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
589 tdb 1.65 net_ptr->ifa_name) < 0) {
590 ats 1.60 return NULL;
591     }
592 ats 1.40
593     network_iface_stat_ptr->speed = 0;
594 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
595 ats 1.40 ifaces++;
596    
597 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
598 ats 1.62 sg_strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
599 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
600 ats 1.40 /* Not all interfaces support the media ioctls. */
601 pajs 1.26 continue;
602     }
603    
604     /* We may need to change this if we start doing wireless devices too */
605     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
606     /* Not a ETHER device */
607     continue;
608     }
609    
610     /* Only intrested in the first 4 bits) - Assuming only ETHER devices */
611     x = ifmed.ifm_active & 0x0f;
612     switch(x){
613     /* 10 Mbit connections. Speedy :) */
614     case(IFM_10_T):
615     case(IFM_10_2):
616     case(IFM_10_5):
617     case(IFM_10_STP):
618     case(IFM_10_FL):
619     network_iface_stat_ptr->speed = 10;
620     break;
621     /* 100 Mbit conneections */
622     case(IFM_100_TX):
623     case(IFM_100_FX):
624     case(IFM_100_T4):
625     case(IFM_100_VG):
626     case(IFM_100_T2):
627     network_iface_stat_ptr->speed = 100;
628     break;
629     /* 1000 Mbit connections */
630     case(IFM_1000_SX):
631     case(IFM_1000_LX):
632     case(IFM_1000_CX):
633 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
634     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
635 tdb 1.45 #endif
636     #ifdef IFM_1000_FX
637     case(IFM_1000_FX): /* FreeBSD 4 */
638     #endif
639     #ifdef IFM_1000_T
640     case(IFM_1000_T): /* FreeBSD 5 */
641 tdb 1.28 #endif
642 pajs 1.26 network_iface_stat_ptr->speed = 1000;
643     break;
644     /* We don't know what it is */
645     default:
646     network_iface_stat_ptr->speed = 0;
647     break;
648     }
649    
650     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
651 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
652 pajs 1.26 }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
653 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
654 pajs 1.26 }else{
655 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
656 pajs 1.26 }
657 pajs 1.36
658 pajs 1.26 }
659     freeifaddrs(net);
660 ats 1.37 close(sock);
661 pajs 1.26 #endif
662 pajs 1.25
663     #ifdef SOLARIS
664 ats 1.44 if ((kc = kstat_open()) == NULL) {
665 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
666 ats 1.44 return NULL;
667     }
668    
669     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
670 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
671 tdb 1.78 kstat_close(kc);
672 ats 1.44 return NULL;
673     }
674 pajs 1.25
675 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
676 tdb 1.76 if (strcmp(ksp->ks_class, "net") == 0) {
677 ats 1.44 struct ifreq ifr;
678    
679     kstat_read(kc, ksp, NULL);
680    
681     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
682     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
683     /* Not a network interface. */
684 pajs 1.25 continue;
685     }
686 ats 1.44
687 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
688 tdb 1.78 kstat_close(kc);
689 pajs 1.25 return NULL;
690     }
691 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
692 ats 1.44 ifaces++;
693    
694 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
695 tdb 1.65 ksp->ks_name) < 0) {
696 tdb 1.78 kstat_close(kc);
697 ats 1.60 return NULL;
698     }
699 pajs 1.25
700 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
701 tdb 1.80 if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) {
702     /* take in to account if link
703     * is up as well as interface */
704     if (knp->value.ui32 != 0u) {
705     network_iface_stat_ptr->up = 1;
706     } else {
707     network_iface_stat_ptr->up = 0;
708     }
709     }
710     else {
711     /* maintain compatibility */
712     network_iface_stat_ptr->up = 1;
713     }
714 ats 1.44 } else {
715 tdb 1.77 network_iface_stat_ptr->up = 0;
716 ats 1.44 }
717 pajs 1.35
718 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
719     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
720     } else {
721     network_iface_stat_ptr->speed = 0;
722 pajs 1.25 }
723    
724 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
725 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
726     switch (knp->value.ui32) {
727     case 1:
728 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
729 ats 1.44 break;
730     case 2:
731 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
732 ats 1.44 break;
733     }
734 pajs 1.33 }
735 pajs 1.25 }
736     }
737 ats 1.44
738     close(sock);
739 pajs 1.25 kstat_close(kc);
740 tdb 1.76 #endif
741 pajs 1.27 #ifdef LINUX
742     f = fopen("/proc/net/dev", "r");
743 tdb 1.65 if(f == NULL){
744 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
745 tdb 1.65 return NULL;
746     }
747 pajs 1.27
748     /* Setup stuff so we can do the ioctl to get the info */
749     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
750 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
751 pajs 1.27 return NULL;
752     }
753    
754     /* Ignore first 2 lines.. Just headings */
755 tdb 1.66 if((fgets(line, sizeof(line), f)) == NULL) {
756     sg_set_error(SG_ERROR_PARSE, NULL);
757     return NULL;
758     }
759     if((fgets(line, sizeof(line), f)) == NULL) {
760     sg_set_error(SG_ERROR_PARSE, NULL);
761     return NULL;
762     }
763 pajs 1.27
764 tdb 1.65 while((fgets(line, sizeof(line), f)) != NULL){
765     char *name, *ptr;
766     struct ifreq ifr;
767     struct ethtool_cmd ethcmd;
768     int err;
769 pajs 1.27
770     /* Get the interface name */
771 tdb 1.65 ptr = strchr(line, ':');
772     if (ptr == NULL) continue;
773     *ptr='\0';
774     name = line;
775     while(isspace(*(name))){
776     name++;
777     }
778 pajs 1.27
779 tdb 1.65 memset(&ifr, 0, sizeof ifr);
780     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
781 pajs 1.27
782 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
783     continue;
784     }
785 pajs 1.27
786     /* We have a good interface to add */
787 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
788 pajs 1.27 return NULL;
789     }
790     network_iface_stat_ptr = network_iface_stats + ifaces;
791 ats 1.60
792 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
793 tdb 1.65 name) < 0) {
794 ats 1.60 return NULL;
795     }
796 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
797 pajs 1.35 network_iface_stat_ptr->up = 1;
798 ats 1.38 } else {
799 pajs 1.35 network_iface_stat_ptr->up = 0;
800     }
801    
802 tdb 1.65 memset(&ethcmd, 0, sizeof ethcmd);
803     ethcmd.cmd = ETHTOOL_GSET;
804     ifr.ifr_data = (caddr_t) &ethcmd;
805 ats 1.38
806 tdb 1.65 err = ioctl(sock, SIOCETHTOOL, &ifr);
807     if (err == 0) {
808 ats 1.38 network_iface_stat_ptr->speed = ethcmd.speed;
809    
810     switch (ethcmd.duplex) {
811 tdb 1.72 case DUPLEX_FULL:
812 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
813 ats 1.38 break;
814 tdb 1.72 case DUPLEX_HALF:
815 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
816 ats 1.38 break;
817     default:
818 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
819 ats 1.38 }
820     } else {
821     /* Not all interfaces support the ethtool ioctl. */
822 ats 1.39 network_iface_stat_ptr->speed = 0;
823 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
824 pajs 1.27 }
825 ats 1.38
826 pajs 1.27 ifaces++;
827     }
828 pajs 1.30 close(sock);
829 ats 1.38 fclose(f);
830 pajs 1.27 #endif
831 ats 1.71 #ifdef CYGWIN
832     sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
833     return NULL;
834     #endif
835     #ifdef HPUX
836     sg_set_error(SG_ERROR_UNSUPPORTED, "HP-UX");
837     return NULL;
838 tdb 1.76 #endif
839     #ifdef WIN32
840     ifaces = 0;
841    
842     if((if_table = win32_get_devices()) == NULL) {
843     sg_set_error(SG_ERROR_DEVICES, "network interfaces");
844     return NULL;
845     }
846    
847     if(VECTOR_RESIZE(network_iface_stats, if_table->dwNumEntries) < 0) {
848     free(if_table);
849     return NULL;
850     }
851    
852     for(i=0; i<if_table->dwNumEntries; i++) {
853     network_iface_stat_ptr=network_iface_stats+i;
854     if_row = if_table->table[i];
855    
856     if(sg_update_string(&network_iface_stat_ptr->interface_name,
857     if_row.bDescr) < 0) {
858     free(if_table);
859     return NULL;
860     }
861     network_iface_stat_ptr->speed = if_row.dwSpeed /1000000;
862    
863     if((if_row.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
864     if_row.dwOperStatus ==
865     MIB_IF_OPER_STATUS_OPERATIONAL) &&
866     if_row.dwAdminStatus == 1) {
867     network_iface_stat_ptr->up = 1;
868     } else {
869     network_iface_stat_ptr->up = 0;
870     }
871    
872     ifaces++;
873     }
874     free(if_table);
875    
876     /* again with the renumbering */
877     for (i=0; i<ifaces; i++) {
878     no = 2;
879     for(j=i+1; j<ifaces; j++) {
880     network_iface_stat_ptr=network_iface_stats+j;
881     if(strcmp(network_iface_stats[i].interface_name,
882     network_iface_stat_ptr->interface_name) == 0) {
883     if(snprintf(buf, sizeof(buf), " #%d", no) < 0) {
884     break;
885     }
886     if(sg_concat_string(&network_iface_stat_ptr->interface_name, buf) != 0) {
887     return NULL;
888     }
889    
890     no++;
891     }
892     }
893     }
894 tdb 1.74 #endif
895    
896     #ifdef SG_ENABLE_DEPRECATED
897     network_iface_stat_ptr->dup = network_iface_stat_ptr->duplex;
898 ats 1.71 #endif
899    
900 pajs 1.26 *entries = ifaces;
901 pajs 1.25 return network_iface_stats;
902 ats 1.68 }
903    
904     int sg_network_iface_compare_name(const void *va, const void *vb) {
905     const sg_network_iface_stats *a = (const sg_network_iface_stats *)va;
906     const sg_network_iface_stats *b = (const sg_network_iface_stats *)vb;
907    
908     return strcmp(a->interface_name, b->interface_name);
909 pajs 1.25 }
910