ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/network_stats.c
Revision: 1.82
Committed: Sun Oct 3 18:35:57 2010 UTC (13 years, 7 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.81: +426 -13 lines
Log Message:
Add support for AIX 5.x - 9.x.

Many thanks to Jens Rehsack <rehsack@googlemail.com> for providing the
patch for this work. Thanks!

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.82 * $Id: network_stats.c,v 1.81 2010/06/09 14:44:28 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.82 #ifdef AIX
74     #include <sys/types.h>
75     #include <sys/socket.h>
76     #include <net/if.h>
77     #include <errno.h>
78     #include <strings.h>
79     #include <sys/ioctl.h>
80     #include <unistd.h>
81     #include <libperfstat.h>
82     #endif
83     #ifdef HPUX
84     #include <fcntl.h>
85     #include <sys/types.h>
86     #include <sys/socket.h>
87     #include <net/if.h>
88     #include <errno.h>
89     #include <strings.h>
90     #include <sys/ioctl.h>
91     #include <unistd.h>
92     #include <sys/un.h>
93     #include <sys/stropts.h>
94     #include <sys/dlpi.h>
95     #include <sys/dlpi_ext.h>
96     #include <sys/mib.h>
97     #define HP_UX11 /* Currently no HP-UX below 11 is supported, fix here if this changes */
98     #endif
99 tdb 1.76 #ifdef WIN32
100     #include <windows.h>
101     #include <Iphlpapi.h>
102     #include "win32.h"
103     #endif
104 pajs 1.1
105 ats 1.62 static void network_stat_init(sg_network_io_stats *s) {
106 ats 1.59 s->interface_name = NULL;
107     s->tx = 0;
108     s->rx = 0;
109     s->ipackets = 0;
110     s->opackets = 0;
111     s->ierrors = 0;
112     s->oerrors = 0;
113     s->collisions = 0;
114 pajs 1.3 }
115    
116 ats 1.62 static void network_stat_destroy(sg_network_io_stats *s) {
117 ats 1.59 free(s->interface_name);
118 pajs 1.1 }
119    
120 ats 1.62 VECTOR_DECLARE_STATIC(network_stats, sg_network_io_stats, 5,
121 tdb 1.65 network_stat_init, network_stat_destroy);
122 pajs 1.3
123 tdb 1.76 #ifdef WIN32
124     static PMIB_IFTABLE win32_get_devices()
125     {
126     PMIB_IFTABLE if_table;
127     PMIB_IFTABLE tmp;
128     unsigned long dwSize = 0;
129    
130     // Allocate memory for pointers
131     if_table = sg_malloc(sizeof(MIB_IFTABLE));
132     if(if_table == NULL) {
133     return NULL;
134     }
135    
136     // Get necessary size for the buffer
137     if(GetIfTable(if_table, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
138     tmp = sg_realloc(if_table, dwSize);
139     if(tmp == NULL) {
140     free(if_table);
141     return NULL;
142     }
143     if_table = tmp;
144     }
145    
146     // Get the data
147     if(GetIfTable(if_table, &dwSize, 0) != NO_ERROR) {
148     free(if_table);
149     return NULL;
150     }
151     return if_table;
152     }
153     #endif /* WIN32 */
154    
155 ats 1.62 sg_network_io_stats *sg_get_network_io_stats(int *entries){
156 ats 1.59 int interfaces;
157 tdb 1.82 #ifndef AIX
158 ats 1.62 sg_network_io_stats *network_stat_ptr;
159 tdb 1.82 #endif
160     #ifdef HPUX
161     /*
162     * talk to Data Link Provider Interface aka /dev/dlpi
163     * see: http://docs.hp.com/hpux/onlinedocs/B2355-90139/B2355-90139.html
164     */
165     #define BUF_SIZE 40960
166    
167     u_long *ctrl_area = malloc(BUF_SIZE);
168     u_long *data_area = malloc(BUF_SIZE);
169     u_long *ppa_area = malloc(BUF_SIZE);
170     struct strbuf ctrl_buf = {BUF_SIZE, 0, (char*) ctrl_area};
171     struct strbuf data_buf = {BUF_SIZE, 0, (char*) data_area};
172    
173     dl_hp_ppa_info_t *ppa_info;
174     dl_hp_ppa_req_t *ppa_req;
175     dl_hp_ppa_ack_t *ppa_ack;
176     char name_buf[24];
177     int fd = -1, ppa_count, count, flags;
178     #endif
179 pajs 1.6
180     #ifdef SOLARIS
181 tdb 1.65 kstat_ctl_t *kc;
182     kstat_t *ksp;
183 pajs 1.1 kstat_named_t *knp;
184 pajs 1.6 #endif
185 pajs 1.3
186 pajs 1.6 #ifdef LINUX
187     FILE *f;
188 pajs 1.12 /* Horrible big enough, but it should be easily big enough */
189 pajs 1.6 char line[8096];
190     regex_t regex;
191 ats 1.49 regmatch_t line_match[9];
192 pajs 1.14 #endif
193 ats 1.18 #ifdef ALLBSD
194 pajs 1.14 struct ifaddrs *net, *net_ptr;
195     struct if_data *net_data;
196     #endif
197 tdb 1.76 #ifdef WIN32
198     PMIB_IFTABLE if_table;
199     MIB_IFROW if_row;
200     int i, no, j;
201    
202     /* used for duplicate interface names. 5 for space, hash, up to two
203     * numbers and terminating slash */
204     char buf[5];
205     #endif
206 tdb 1.82 #ifdef AIX
207     int i;
208     perfstat_netinterface_t *statp;
209     perfstat_id_t first;
210     #endif
211    
212     #ifdef HPUX
213     interfaces=0;
214    
215     if ((fd = open("/dev/dlpi", O_RDWR)) < 0) {
216     sg_set_error_with_errno(SG_ERROR_OPEN, "/dev/dlpi");
217     return NULL;
218     }
219    
220     ppa_req = (dl_hp_ppa_req_t *) ctrl_area;
221     ppa_ack = (dl_hp_ppa_ack_t *) ctrl_area;
222    
223     ppa_req->dl_primitive = DL_HP_PPA_REQ;
224    
225     ctrl_buf.len = sizeof(dl_hp_ppa_req_t);
226     if(putmsg(fd, &ctrl_buf, 0, 0) < 0) {
227     sg_set_error_with_errno(SG_ERROR_PUTMSG, "DL_HP_PPA_REQ");
228     return NULL;
229     }
230    
231     flags = 0;
232     ctrl_area[0] = 0;
233    
234     if (getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) {
235     sg_set_error_with_errno(SG_ERROR_GETMSG, "DL_HP_PPA_REQ");
236     return NULL;
237     }
238    
239     if (ppa_ack->dl_length == 0) {
240     sg_set_error_with_errno(SG_ERROR_PARSE, "DL_HP_PPA_REQ");
241     return NULL;
242     }
243    
244     // save all the PPA information
245     memcpy ((u_char*) ppa_area, (u_char*) ctrl_area + ppa_ack->dl_offset, ppa_ack->dl_length);
246     ppa_count = ppa_ack->dl_count;
247    
248     for (count = 0, ppa_info = (dl_hp_ppa_info_t*) ppa_area;
249     count < ppa_count;
250     count++) {
251     dl_get_statistics_req_t *get_statistics_req = (dl_get_statistics_req_t*) ctrl_area;
252     dl_get_statistics_ack_t *get_statistics_ack = (dl_get_statistics_ack_t*) ctrl_area;
253    
254     dl_attach_req_t *attach_req;
255     dl_detach_req_t *detach_req;
256     mib_ifEntry *mib_ptr;
257     #ifdef HP_UX11
258     mib_Dot3StatsEntry *mib_Dot3_ptr;
259     #endif
260    
261     attach_req = (dl_attach_req_t*) ctrl_area;
262     attach_req->dl_primitive = DL_ATTACH_REQ;
263     attach_req->dl_ppa = ppa_info[count].dl_ppa;
264     ctrl_buf.len = sizeof(dl_attach_req_t);
265     if (putmsg(fd, &ctrl_buf, 0, 0) < 0) {
266     sg_set_error_with_errno(SG_ERROR_PUTMSG, "DL_ATTACH_REQ");
267     return NULL;
268     }
269    
270     ctrl_area[0] = 0;
271     if (getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) {
272     sg_set_error_with_errno(SG_ERROR_GETMSG, "DL_ATTACH_REQ");
273     return NULL;
274     }
275    
276     get_statistics_req->dl_primitive = DL_GET_STATISTICS_REQ;
277     ctrl_buf.len = sizeof(dl_get_statistics_req_t);
278    
279     if (putmsg(fd, &ctrl_buf, NULL, 0) < 0) {
280     sg_set_error_with_errno(SG_ERROR_PUTMSG, "DL_GET_STATISTICS_REQ");
281     return NULL;
282     }
283    
284     flags = 0;
285     ctrl_area[0] = 0;
286    
287     if (getmsg(fd, &ctrl_buf, NULL, &flags) < 0) {
288     sg_set_error_with_errno(SG_ERROR_GETMSG, "DL_GET_STATISTICS_REQ");
289     return NULL;
290     }
291     if (get_statistics_ack->dl_primitive != DL_GET_STATISTICS_ACK) {
292     sg_set_error_with_errno(SG_ERROR_PARSE, "DL_GET_STATISTICS_ACK");
293     return NULL;
294     }
295    
296     mib_ptr = (mib_ifEntry*) ((u_char*) ctrl_area + get_statistics_ack->dl_stat_offset);
297    
298     if (0 == (mib_ptr->ifOper & 1)) {
299     continue;
300     }
301    
302     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
303     return NULL;
304     }
305     network_stat_ptr=network_stats+interfaces;
306    
307     snprintf( name_buf, sizeof(name_buf), "lan%d", ppa_info[count].dl_ppa );
308    
309     if (sg_update_string(&network_stat_ptr->interface_name, name_buf ) < 0 ) {
310     return NULL;
311     }
312     network_stat_ptr->rx = mib_ptr->ifInOctets;
313     network_stat_ptr->tx = mib_ptr->ifOutOctets;
314     network_stat_ptr->ipackets = mib_ptr->ifInUcastPkts + mib_ptr->ifInNUcastPkts;
315     network_stat_ptr->opackets = mib_ptr->ifOutUcastPkts + mib_ptr->ifOutNUcastPkts;
316     network_stat_ptr->ierrors = mib_ptr->ifInErrors;
317     network_stat_ptr->oerrors = mib_ptr->ifOutErrors;
318     #ifdef HP_UX11
319     mib_Dot3_ptr = (mib_Dot3StatsEntry *) (void *) ((int) mib_ptr + sizeof (mib_ifEntry));
320     network_stat_ptr->collisions = mib_Dot3_ptr->dot3StatsSingleCollisionFrames
321     + mib_Dot3_ptr->dot3StatsMultipleCollisionFrames;
322     #else
323     network_stat_ptr->collisions = 0; /* currently unknown */
324     #endif
325     network_stat_ptr->systime = time(NULL);
326     interfaces++;
327    
328     detach_req = (dl_detach_req_t*) ctrl_area;
329     detach_req->dl_primitive = DL_DETACH_REQ;
330     ctrl_buf.len = sizeof(dl_detach_req_t);
331     if (putmsg(fd, &ctrl_buf, 0, 0) < 0) {
332     sg_set_error_with_errno(SG_ERROR_PUTMSG, "DL_DETACH_REQ");
333     return NULL;
334     }
335    
336     ctrl_area[0] = 0;
337     flags = 0;
338     if (getmsg(fd, &ctrl_buf, &data_buf, &flags) < 0) {
339     sg_set_error_with_errno(SG_ERROR_GETMSG, "DL_DETACH_REQ");
340     return NULL;
341     }
342     }
343    
344     close(fd);
345    
346     free(ctrl_area);
347     free(data_area);
348     free(ppa_area);
349    
350     #endif
351 pajs 1.14
352 ats 1.18 #ifdef ALLBSD
353 tdb 1.82 if (getifaddrs(&net) != 0){
354 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
355 pajs 1.14 return NULL;
356     }
357    
358     interfaces=0;
359    
360     for(net_ptr=net;net_ptr!=NULL;net_ptr=net_ptr->ifa_next){
361 tdb 1.82 if (net_ptr->ifa_addr->sa_family != AF_LINK) continue;
362 ats 1.59
363     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
364 pajs 1.14 return NULL;
365     }
366     network_stat_ptr=network_stats+interfaces;
367    
368 ats 1.62 if (sg_update_string(&network_stat_ptr->interface_name,
369 tdb 1.65 net_ptr->ifa_name) < 0) {
370 ats 1.60 return NULL;
371     }
372 pajs 1.14 net_data=(struct if_data *)net_ptr->ifa_data;
373     network_stat_ptr->rx=net_data->ifi_ibytes;
374 tdb 1.46 network_stat_ptr->tx=net_data->ifi_obytes;
375     network_stat_ptr->ipackets=net_data->ifi_ipackets;
376     network_stat_ptr->opackets=net_data->ifi_opackets;
377     network_stat_ptr->ierrors=net_data->ifi_ierrors;
378     network_stat_ptr->oerrors=net_data->ifi_oerrors;
379     network_stat_ptr->collisions=net_data->ifi_collisions;
380 pajs 1.14 network_stat_ptr->systime=time(NULL);
381     interfaces++;
382     }
383     freeifaddrs(net);
384 pajs 1.6 #endif
385 tdb 1.82 #ifdef AIX
386     /* check how many perfstat_netinterface_t structures are available */
387     interfaces = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0);
388    
389     /* allocate enough memory for all the structures */
390     statp = calloc(interfaces, sizeof(perfstat_netinterface_t));
391    
392     /* set name to first interface */
393     strcpy(first.name, FIRST_NETINTERFACE);
394    
395     /* ask to get all the structures available in one call */
396     /* return code is number of structures returned */
397     interfaces = perfstat_netinterface(&first, statp, sizeof(perfstat_netinterface_t), interfaces);
398     if (-1 == interfaces) {
399     sg_set_error(SG_ERROR_SYSCTLBYNAME, "perfstat_netinterface");
400     free(statp);
401     return NULL;
402     }
403    
404     if (VECTOR_RESIZE(network_stats, interfaces) < 0) {
405     sg_set_error(SG_ERROR_MALLOC, NULL);
406     free(statp);
407     return NULL;
408     }
409 pajs 1.1
410 tdb 1.82 /* print statistics for each of the interfaces */
411     for (i = 0; i < interfaces; i++) {
412     if (sg_update_string(&network_stats[i].interface_name, statp[i].name) < 0) {
413     free(statp);
414     return NULL;
415     }
416     network_stats[i].tx = statp[i].obytes;
417     network_stats[i].rx = statp[i].ibytes;
418     network_stats[i].opackets = statp[i].opackets;
419     network_stats[i].ipackets = statp[i].ipackets;
420     network_stats[i].oerrors = statp[i].oerrors;
421     network_stats[i].ierrors = statp[i].ierrors;
422     network_stats[i].collisions = statp[i].collisions;
423     network_stats[i].systime = time(NULL);
424     }
425    
426     free(statp);
427     #endif
428 pajs 1.6 #ifdef SOLARIS
429 tdb 1.65 if ((kc = kstat_open()) == NULL) {
430 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
431 tdb 1.65 return NULL;
432     }
433 pajs 1.1
434 pajs 1.6 interfaces=0;
435 pajs 1.3
436 tdb 1.66 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
437 tdb 1.76 if (strcmp(ksp->ks_class, "net") == 0) {
438 tdb 1.65 kstat_read(kc, ksp, NULL);
439 pajs 1.1
440 pajs 1.7 #ifdef SOL7
441 tdb 1.53 #define LRX "rbytes"
442     #define LTX "obytes"
443     #define LIPACKETS "ipackets"
444     #define LOPACKETS "opackets"
445 pajs 1.7 #define VALTYPE value.ui32
446     #else
447 tdb 1.53 #define LRX "rbytes64"
448     #define LTX "obytes64"
449     #define LIPACKETS "ipackets64"
450     #define LOPACKETS "opackets64"
451 pajs 1.7 #define VALTYPE value.ui64
452     #endif
453    
454 tdb 1.53 /* Read rx */
455     if((knp=kstat_data_lookup(ksp, LRX))==NULL){
456 ats 1.44 /* This is a network interface, but it doesn't
457     * have the rbytes/obytes values; for instance,
458     * the loopback devices have this behaviour
459     * (although they do track packets in/out). */
460 ats 1.55 /* FIXME: Show packet counts when byte counts
461     * not available. */
462 pajs 1.1 continue;
463     }
464 pajs 1.3
465 tdb 1.53 /* Create new network_stats */
466 ats 1.59 if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
467 tdb 1.78 kstat_close(kc);
468 pajs 1.1 return NULL;
469     }
470     network_stat_ptr=network_stats+interfaces;
471 tdb 1.53
472 tdb 1.79 /* Read interface name */
473     if (sg_update_string(&network_stat_ptr->interface_name,
474     ksp->ks_name) < 0) {
475     kstat_close(kc);
476     return NULL;
477     }
478    
479 tdb 1.53 /* Finish reading rx */
480 pajs 1.7 network_stat_ptr->rx=knp->VALTYPE;
481 pajs 1.1
482 tdb 1.53 /* Read tx */
483     if((knp=kstat_data_lookup(ksp, LTX))==NULL){
484 pajs 1.1 continue;
485     }
486 pajs 1.7 network_stat_ptr->tx=knp->VALTYPE;
487 tdb 1.53
488     /* Read ipackets */
489     if((knp=kstat_data_lookup(ksp, LIPACKETS))==NULL){
490     continue;
491     }
492     network_stat_ptr->ipackets=knp->VALTYPE;
493    
494     /* Read opackets */
495     if((knp=kstat_data_lookup(ksp, LOPACKETS))==NULL){
496     continue;
497     }
498     network_stat_ptr->opackets=knp->VALTYPE;
499    
500     /* Read ierrors */
501     if((knp=kstat_data_lookup(ksp, "ierrors"))==NULL){
502     continue;
503     }
504     network_stat_ptr->ierrors=knp->value.ui32;
505    
506     /* Read oerrors */
507     if((knp=kstat_data_lookup(ksp, "oerrors"))==NULL){
508     continue;
509     }
510     network_stat_ptr->oerrors=knp->value.ui32;
511    
512     /* Read collisions */
513     if((knp=kstat_data_lookup(ksp, "collisions"))==NULL){
514     continue;
515     }
516     network_stat_ptr->collisions=knp->value.ui32;
517    
518 pajs 1.3
519 tdb 1.53 /* Store systime */
520 pajs 1.3 network_stat_ptr->systime=time(NULL);
521 tdb 1.53
522 pajs 1.1 interfaces++;
523     }
524     }
525 pajs 1.2
526     kstat_close(kc);
527 pajs 1.6 #endif
528     #ifdef LINUX
529     f=fopen("/proc/net/dev", "r");
530     if(f==NULL){
531 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
532 pajs 1.6 return NULL;
533     }
534     /* read the 2 lines.. Its the title, so we dont care :) */
535     fgets(line, sizeof(line), f);
536     fgets(line, sizeof(line), f);
537    
538    
539 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){
540 tdb 1.66 sg_set_error(SG_ERROR_PARSE, NULL);
541 pajs 1.6 return NULL;
542     }
543    
544     interfaces=0;
545 pajs 1.1
546 pajs 1.6 while((fgets(line, sizeof(line), f)) != NULL){
547 ats 1.51 if((regexec(&regex, line, 9, line_match, 0))!=0){
548 pajs 1.6 continue;
549     }
550 ats 1.59
551     if (VECTOR_RESIZE(network_stats, interfaces + 1) < 0) {
552     return NULL;
553 pajs 1.6 }
554 tdb 1.65 network_stat_ptr=network_stats+interfaces;
555 pajs 1.6
556     if(network_stat_ptr->interface_name!=NULL){
557     free(network_stat_ptr->interface_name);
558     }
559    
560 ats 1.62 network_stat_ptr->interface_name=sg_get_string_match(line, &line_match[1]);
561     network_stat_ptr->rx=sg_get_ll_match(line, &line_match[2]);
562     network_stat_ptr->tx=sg_get_ll_match(line, &line_match[5]);
563     network_stat_ptr->ipackets=sg_get_ll_match(line, &line_match[3]);
564     network_stat_ptr->opackets=sg_get_ll_match(line, &line_match[6]);
565     network_stat_ptr->ierrors=sg_get_ll_match(line, &line_match[4]);
566     network_stat_ptr->oerrors=sg_get_ll_match(line, &line_match[7]);
567     network_stat_ptr->collisions=sg_get_ll_match(line, &line_match[8]);
568 pajs 1.6 network_stat_ptr->systime=time(NULL);
569    
570     interfaces++;
571     }
572 pajs 1.12 fclose(f);
573 pajs 1.13 regfree(&regex);
574 pajs 1.6
575     #endif
576 ats 1.20
577     #ifdef CYGWIN
578 tdb 1.66 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
579 ats 1.70 return NULL;
580     #endif
581 ats 1.20
582 tdb 1.76 #ifdef WIN32
583     interfaces = 0;
584    
585     if((if_table = win32_get_devices()) == NULL) {
586     sg_set_error(SG_ERROR_DEVICES, "network");
587     return NULL;
588     }
589    
590     if(VECTOR_RESIZE(network_stats, if_table->dwNumEntries) < 0) {
591     free(if_table);
592     return NULL;
593     }
594    
595     for (i=0; i<if_table->dwNumEntries; i++) {
596     network_stat_ptr=network_stats+i;
597     if_row = if_table->table[i];
598    
599     if(sg_update_string(&network_stat_ptr->interface_name,
600     if_row.bDescr) < 0) {
601     free(if_table);
602     return NULL;
603     }
604     network_stat_ptr->tx = if_row.dwOutOctets;
605     network_stat_ptr->rx = if_row.dwInOctets;
606     network_stat_ptr->ipackets = if_row.dwInUcastPkts + if_row.dwInNUcastPkts;
607     network_stat_ptr->opackets = if_row.dwOutUcastPkts + if_row.dwOutNUcastPkts;
608     network_stat_ptr->ierrors = if_row.dwInErrors;
609     network_stat_ptr->oerrors = if_row.dwOutErrors;
610     network_stat_ptr->collisions = 0; /* can't do that */
611     network_stat_ptr->systime = time(NULL);
612    
613     interfaces++;
614     }
615     free(if_table);
616    
617     /* Please say there's a nicer way to do this... If windows has two (or
618     * more) identical network cards, GetIfTable returns them with the same
619     * name, not like in Device Manager where the other has a #2 etc after
620     * it. So, add the #number here. Should we be doing this? Or should the
621     * end programs be dealing with duplicate names? Currently breaks
622     * watch.pl in rrdgraphing. But Unix does not have the issue of
623     * duplicate net device names.
624     */
625     for (i=0; i<interfaces; i++) {
626     no = 2;
627     for(j=i+1; j<interfaces; j++) {
628     network_stat_ptr=network_stats+j;
629     if(strcmp(network_stats[i].interface_name,
630     network_stat_ptr->interface_name) == 0) {
631     if(snprintf(buf, sizeof(buf), " #%d", no) < 0) {
632     break;
633     }
634     if(sg_concat_string(&network_stat_ptr->interface_name, buf) != 0) {
635     return NULL;
636     }
637    
638     no++;
639     }
640     }
641     }
642     #endif
643    
644 pajs 1.1 *entries=interfaces;
645    
646     return network_stats;
647 pajs 1.3 }
648    
649 ats 1.62 static long long transfer_diff(long long new, long long old){
650 tdb 1.76 #if defined(SOL7) || defined(LINUX) || defined(FREEBSD) || defined(DFBSD) || defined(OPENBSD) || defined(WIN32)
651 ats 1.56 /* 32-bit quantities, so we must explicitly deal with wraparound. */
652     #define MAXVAL 0x100000000LL
653     if (new >= old) {
654     return new - old;
655     } else {
656     return MAXVAL + new - old;
657     }
658 pajs 1.8 #else
659 ats 1.56 /* 64-bit quantities, so plain subtraction works. */
660     return new - old;
661 pajs 1.8 #endif
662     }
663    
664 ats 1.62 sg_network_io_stats *sg_get_network_io_stats_diff(int *entries) {
665     VECTOR_DECLARE_STATIC(diff, sg_network_io_stats, 1,
666 tdb 1.65 network_stat_init, network_stat_destroy);
667 ats 1.62 sg_network_io_stats *src = NULL, *dest;
668 ats 1.59 int i, j, diff_count, new_count;
669 ats 1.24
670     if (network_stats == NULL) {
671     /* No previous stats, so we can't calculate a difference. */
672 ats 1.62 return sg_get_network_io_stats(entries);
673 pajs 1.3 }
674    
675 ats 1.24 /* Resize the results array to match the previous stats. */
676 ats 1.59 diff_count = VECTOR_SIZE(network_stats);
677     if (VECTOR_RESIZE(diff, diff_count) < 0) {
678 pajs 1.3 return NULL;
679     }
680    
681 ats 1.24 /* Copy the previous stats into the result. */
682     for (i = 0; i < diff_count; i++) {
683     src = &network_stats[i];
684     dest = &diff[i];
685 pajs 1.3
686 ats 1.62 if (sg_update_string(&dest->interface_name,
687 tdb 1.65 src->interface_name) < 0) {
688 ats 1.60 return NULL;
689 pajs 1.3 }
690 ats 1.24 dest->rx = src->rx;
691     dest->tx = src->tx;
692 tdb 1.47 dest->ipackets = src->ipackets;
693     dest->opackets = src->opackets;
694     dest->ierrors = src->ierrors;
695     dest->oerrors = src->oerrors;
696     dest->collisions = src->collisions;
697 ats 1.24 dest->systime = src->systime;
698     }
699 pajs 1.3
700 ats 1.24 /* Get a new set of stats. */
701 ats 1.62 if (sg_get_network_io_stats(&new_count) == NULL) {
702 ats 1.21 return NULL;
703     }
704 pajs 1.3
705 ats 1.24 /* For each previous stat... */
706     for (i = 0; i < diff_count; i++) {
707     dest = &diff[i];
708    
709     /* ... find the corresponding new stat ... */
710     for (j = 0; j < new_count; j++) {
711     /* Try the new stat in the same position first,
712     since that's most likely to be it. */
713     src = &network_stats[(i + j) % new_count];
714     if (strcmp(src->interface_name, dest->interface_name) == 0) {
715     break;
716     }
717     }
718     if (j == new_count) {
719     /* No match found. */
720     continue;
721 pajs 1.3 }
722    
723 ats 1.24 /* ... and subtract the previous stat from it to get the
724     difference. */
725     dest->rx = transfer_diff(src->rx, dest->rx);
726     dest->tx = transfer_diff(src->tx, dest->tx);
727 tdb 1.47 dest->ipackets = transfer_diff(src->ipackets, dest->ipackets);
728     dest->opackets = transfer_diff(src->opackets, dest->opackets);
729     dest->ierrors = transfer_diff(src->ierrors, dest->ierrors);
730     dest->oerrors = transfer_diff(src->oerrors, dest->oerrors);
731     dest->collisions = transfer_diff(src->collisions, dest->collisions);
732 ats 1.24 dest->systime = src->systime - dest->systime;
733 pajs 1.3 }
734    
735 ats 1.24 *entries = diff_count;
736     return diff;
737     }
738 ats 1.59
739 ats 1.68 int sg_network_io_compare_name(const void *va, const void *vb) {
740     const sg_network_io_stats *a = (const sg_network_io_stats *)va;
741     const sg_network_io_stats *b = (const sg_network_io_stats *)vb;
742    
743     return strcmp(a->interface_name, b->interface_name);
744     }
745    
746 pajs 1.25 /* NETWORK INTERFACE STATS */
747    
748 ats 1.62 static void network_iface_stat_init(sg_network_iface_stats *s) {
749 ats 1.59 s->interface_name = NULL;
750     s->speed = 0;
751 tdb 1.74 s->duplex = SG_IFACE_DUPLEX_UNKNOWN;
752 pajs 1.25 }
753    
754 ats 1.62 static void network_iface_stat_destroy(sg_network_iface_stats *s) {
755 ats 1.59 free(s->interface_name);
756 pajs 1.25 }
757    
758 ats 1.62 sg_network_iface_stats *sg_get_network_iface_stats(int *entries){
759     VECTOR_DECLARE_STATIC(network_iface_stats, sg_network_iface_stats, 5,
760 tdb 1.65 network_iface_stat_init, network_iface_stat_destroy);
761 ats 1.62 sg_network_iface_stats *network_iface_stat_ptr;
762 ats 1.43 int ifaces = 0;
763 pajs 1.25
764     #ifdef SOLARIS
765 tdb 1.65 kstat_ctl_t *kc;
766     kstat_t *ksp;
767 pajs 1.25 kstat_named_t *knp;
768 ats 1.44 int sock;
769 pajs 1.25 #endif
770 pajs 1.26 #ifdef ALLBSD
771 tdb 1.82 struct ifmediareq ifmed;
772 tdb 1.65 struct ifaddrs *net, *net_ptr;
773 pajs 1.36 struct ifreq ifr;
774 ats 1.37 int sock;
775 pajs 1.26 int x;
776     #endif
777 pajs 1.27 #ifdef LINUX
778 tdb 1.65 FILE *f;
779     /* Horrible big enough, but it should be easily big enough */
780     char line[8096];
781 pajs 1.27 int sock;
782     #endif
783 tdb 1.76 #ifdef WIN32
784     PMIB_IFTABLE if_table;
785     MIB_IFROW if_row;
786     int i,j,no;
787     char buf[5];
788     #endif
789 tdb 1.82 #ifdef AIX
790     int fd, n;
791     size_t pagesize;
792     struct ifreq *ifr, *lifr, iff;
793     struct ifconf ifc;
794     #endif
795     #ifdef HPUX
796     int fd;
797     struct ifreq *ifr, *lifr, iff;
798     struct ifconf ifc;
799     #endif
800 ats 1.43
801 pajs 1.26 #ifdef ALLBSD
802 tdb 1.65 if(getifaddrs(&net) != 0){
803 ats 1.69 sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
804 tdb 1.65 return NULL;
805     }
806 pajs 1.26
807 ats 1.37 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == 0) return NULL;
808 pajs 1.26
809     for(net_ptr=net; net_ptr!=NULL; net_ptr=net_ptr->ifa_next){
810 tdb 1.65 if(net_ptr->ifa_addr->sa_family != AF_LINK) continue;
811 ats 1.59
812     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
813 tdb 1.65 return NULL;
814     }
815     network_iface_stat_ptr = network_iface_stats + ifaces;
816 pajs 1.26
817 ats 1.40 memset(&ifr, 0, sizeof(ifr));
818     strncpy(ifr.ifr_name, net_ptr->ifa_name, sizeof(ifr.ifr_name));
819    
820     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0){
821     continue;
822     }
823     if((ifr.ifr_flags & IFF_UP) != 0){
824     network_iface_stat_ptr->up = 1;
825     }else{
826     network_iface_stat_ptr->up = 0;
827     }
828    
829 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
830 tdb 1.65 net_ptr->ifa_name) < 0) {
831 ats 1.60 return NULL;
832     }
833 ats 1.40
834     network_iface_stat_ptr->speed = 0;
835 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
836 ats 1.40 ifaces++;
837    
838 pajs 1.26 memset(&ifmed, 0, sizeof(struct ifmediareq));
839 ats 1.62 sg_strlcpy(ifmed.ifm_name, net_ptr->ifa_name, sizeof(ifmed.ifm_name));
840 ats 1.37 if(ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifmed) == -1){
841 ats 1.40 /* Not all interfaces support the media ioctls. */
842 pajs 1.26 continue;
843     }
844    
845     /* We may need to change this if we start doing wireless devices too */
846     if( (ifmed.ifm_active | IFM_ETHER) != ifmed.ifm_active ){
847     /* Not a ETHER device */
848     continue;
849     }
850    
851 tdb 1.81 /* Assuming only ETHER devices */
852     x = IFM_SUBTYPE(ifmed.ifm_active);
853 pajs 1.26 switch(x){
854     /* 10 Mbit connections. Speedy :) */
855     case(IFM_10_T):
856     case(IFM_10_2):
857     case(IFM_10_5):
858     case(IFM_10_STP):
859     case(IFM_10_FL):
860     network_iface_stat_ptr->speed = 10;
861     break;
862 tdb 1.81 /* 100 Mbit connections */
863 pajs 1.26 case(IFM_100_TX):
864     case(IFM_100_FX):
865     case(IFM_100_T4):
866     case(IFM_100_VG):
867     case(IFM_100_T2):
868     network_iface_stat_ptr->speed = 100;
869     break;
870     /* 1000 Mbit connections */
871     case(IFM_1000_SX):
872     case(IFM_1000_LX):
873     case(IFM_1000_CX):
874 tdb 1.54 #if defined(IFM_1000_TX) && !defined(OPENBSD)
875     case(IFM_1000_TX): /* FreeBSD 4 and others (but NOT OpenBSD)? */
876 tdb 1.45 #endif
877     #ifdef IFM_1000_FX
878     case(IFM_1000_FX): /* FreeBSD 4 */
879     #endif
880     #ifdef IFM_1000_T
881     case(IFM_1000_T): /* FreeBSD 5 */
882 tdb 1.28 #endif
883 pajs 1.26 network_iface_stat_ptr->speed = 1000;
884     break;
885     /* We don't know what it is */
886     default:
887     network_iface_stat_ptr->speed = 0;
888     break;
889     }
890    
891     if( (ifmed.ifm_active | IFM_FDX) == ifmed.ifm_active ){
892 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
893 pajs 1.26 }else if( (ifmed.ifm_active | IFM_HDX) == ifmed.ifm_active ){
894 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
895 pajs 1.26 }else{
896 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
897 pajs 1.26 }
898     }
899     freeifaddrs(net);
900 ats 1.37 close(sock);
901 pajs 1.26 #endif
902 pajs 1.25
903 tdb 1.82 #ifdef AIX
904     /*
905     * Fix up variable length of struct ifr
906     */
907     #ifndef _SIZEOF_ADDR_IFREQ
908     #define _SIZEOF_ADDR_IFREQ(ifr) \
909     (((ifr).ifr_addr.sa_len > sizeof(struct sockaddr)) \
910     ? sizeof(struct ifreq) - sizeof(struct sockaddr) + (ifr).ifr_addr.sa_len \
911     : sizeof(struct ifreq))
912     #endif
913    
914     if ((pagesize = sysconf(_SC_PAGESIZE)) == ((size_t)-1)) {
915     sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE");
916     return NULL;
917     }
918    
919     if ((fd = socket (PF_INET, SOCK_DGRAM, 0)) == -1) {
920     return NULL;
921     }
922    
923     n = 2;
924     ifr = (struct ifreq *)malloc( n*pagesize );
925     if( NULL == ifr ) {
926     sg_set_error_with_errno(SG_ERROR_MALLOC, NULL);
927     close (fd);
928     return NULL;
929     }
930     bzero(&ifc, sizeof(ifc));
931     ifc.ifc_req = ifr;
932     ifc.ifc_len = n * pagesize;
933     while( ( ioctl( fd, SIOCGIFCONF, &ifc ) == -1 ) ||
934     ( ((size_t)ifc.ifc_len) >= ( (n-1) * pagesize)) )
935     {
936     n *= 2;
937     ifr = (struct ifreq *)realloc( ifr, n*pagesize );
938     if( NULL == ifr ) {
939     free( ifc.ifc_req );
940     close (fd);
941     sg_set_error_with_errno(SG_ERROR_MALLOC, NULL);
942     return NULL;
943     }
944     ifc.ifc_req = ifr;
945     ifc.ifc_len = n * pagesize;
946     }
947    
948     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
949     for ( ifr = ifc.ifc_req;
950     ifr < lifr;
951     ifr = (struct ifreq *)&(((char *)ifr)[_SIZEOF_ADDR_IFREQ(*ifr)]) )
952     {
953     struct sockaddr *sa = &ifr->ifr_addr;
954    
955     if(sa->sa_family != AF_LINK)
956     continue;
957    
958     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
959     free( ifc.ifc_req );
960     close (fd);
961     return NULL;
962     }
963     network_iface_stat_ptr = network_iface_stats + ifaces;
964    
965     memset(&iff, 0, sizeof(iff));
966     strncpy(iff.ifr_name, ifr->ifr_name, sizeof(iff.ifr_name));
967    
968     if (ioctl(fd, SIOCGIFFLAGS, &iff) < 0) {
969     continue;
970     }
971    
972     if ((iff.ifr_flags & IFF_UP) != 0) {
973     network_iface_stat_ptr->up = 1;
974     } else {
975     network_iface_stat_ptr->up = 0;
976     }
977     if (sg_update_string(&network_iface_stat_ptr->interface_name,
978     ifr->ifr_name) < 0) {
979     close (fd);
980     free( ifc.ifc_req );
981     return NULL;
982     }
983    
984     network_iface_stat_ptr->speed = 0;
985     network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
986     ifaces++;
987     }
988    
989     close (fd);
990     free( ifc.ifc_req );
991     #endif
992    
993     #ifdef HPUX
994     /*
995     * Fix up variable length of struct ifr
996     */
997     #ifndef _SA_LEN
998     #define _SA_LEN(sa) \
999     ((sa).sa_family == AF_UNIX ? sizeof(struct sockaddr_un) : \
1000     (sa).sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : \
1001     sizeof(struct sockaddr))
1002     #endif
1003    
1004     #ifndef _SIZEOF_ADDR_IFREQ
1005     #define _SIZEOF_ADDR_IFREQ(ifr) \
1006     ((_SA_LEN((ifr).ifr_addr) > sizeof(struct sockaddr)) \
1007     ? sizeof(struct ifreq) - sizeof(struct sockaddr) + _SA_LEN((ifr).ifr_addr) \
1008     : sizeof(struct ifreq))
1009     #endif
1010     if ((fd = socket (PF_INET, SOCK_DGRAM, 0)) == -1) {
1011     return NULL;
1012     }
1013    
1014     bzero(&ifc, sizeof(ifc));
1015     if (ioctl (fd, SIOCGIFNUM, &ifc) != -1) {
1016     ifr = calloc(sizeof (*ifr), ifc.ifc_len);
1017     if( NULL == ifr ) {
1018     close (fd);
1019     sg_set_error_with_errno(SG_ERROR_MALLOC, NULL);
1020     return NULL;
1021     }
1022     ifc.ifc_req = ifr;
1023     ifc.ifc_len *= sizeof (*ifr);
1024     if (ioctl (fd, SIOCGIFCONF, &ifc) == -1) {
1025     free (ifr);
1026     close (fd);
1027     sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
1028     return NULL;
1029     }
1030     } else {
1031     close (fd);
1032     sg_set_error_with_errno(SG_ERROR_GETIFADDRS, NULL);
1033     return NULL;
1034     }
1035    
1036     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
1037     for ( ifr = ifc.ifc_req;
1038     ifr < lifr;
1039     ifr = (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*ifr)) )
1040     {
1041     if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
1042     free( ifc.ifc_req );
1043     close (fd);
1044     return NULL;
1045     }
1046     network_iface_stat_ptr = network_iface_stats + ifaces;
1047    
1048     bzero(&iff, sizeof(iff));
1049     strncpy(iff.ifr_name, ifr->ifr_name, sizeof(iff.ifr_name));
1050    
1051     if (ioctl(fd, SIOCGIFFLAGS, &iff) < 0) {
1052     continue;
1053     }
1054    
1055     if ((iff.ifr_flags & IFF_UP) != 0) {
1056     network_iface_stat_ptr->up = 1;
1057     } else {
1058     network_iface_stat_ptr->up = 0;
1059     }
1060     if (sg_update_string(&network_iface_stat_ptr->interface_name,
1061     ifr->ifr_name) < 0) {
1062     close (fd);
1063     free( ifc.ifc_req );
1064     return NULL;
1065     }
1066    
1067     /**
1068     * for physical devices we now could ask /dev/dlpi for speed and type,
1069     * but for monitoring we don't care
1070     */
1071     network_iface_stat_ptr->speed = 0;
1072     network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
1073     ifaces++;
1074     }
1075    
1076     close (fd);
1077     free( ifc.ifc_req );
1078     #endif
1079    
1080 pajs 1.25 #ifdef SOLARIS
1081 ats 1.44 if ((kc = kstat_open()) == NULL) {
1082 tdb 1.66 sg_set_error(SG_ERROR_KSTAT_OPEN, NULL);
1083 ats 1.44 return NULL;
1084     }
1085    
1086     if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
1087 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
1088 tdb 1.78 kstat_close(kc);
1089 ats 1.44 return NULL;
1090     }
1091 pajs 1.25
1092 ats 1.44 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1093 tdb 1.76 if (strcmp(ksp->ks_class, "net") == 0) {
1094 ats 1.44 struct ifreq ifr;
1095    
1096     kstat_read(kc, ksp, NULL);
1097    
1098     strncpy(ifr.ifr_name, ksp->ks_name, sizeof ifr.ifr_name);
1099     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
1100     /* Not a network interface. */
1101 pajs 1.25 continue;
1102     }
1103 ats 1.44
1104 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
1105 tdb 1.78 kstat_close(kc);
1106 pajs 1.25 return NULL;
1107     }
1108 pajs 1.26 network_iface_stat_ptr = network_iface_stats + ifaces;
1109 ats 1.44 ifaces++;
1110    
1111 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
1112 tdb 1.65 ksp->ks_name) < 0) {
1113 tdb 1.78 kstat_close(kc);
1114 ats 1.60 return NULL;
1115     }
1116 pajs 1.25
1117 ats 1.44 if ((ifr.ifr_flags & IFF_UP) != 0) {
1118 tdb 1.80 if ((knp = kstat_data_lookup(ksp, "link_up")) != NULL) {
1119     /* take in to account if link
1120     * is up as well as interface */
1121     if (knp->value.ui32 != 0u) {
1122     network_iface_stat_ptr->up = 1;
1123     } else {
1124     network_iface_stat_ptr->up = 0;
1125     }
1126     }
1127     else {
1128     /* maintain compatibility */
1129     network_iface_stat_ptr->up = 1;
1130     }
1131 ats 1.44 } else {
1132 tdb 1.77 network_iface_stat_ptr->up = 0;
1133 ats 1.44 }
1134 pajs 1.35
1135 ats 1.44 if ((knp = kstat_data_lookup(ksp, "ifspeed")) != NULL) {
1136     network_iface_stat_ptr->speed = knp->value.ui64 / (1000 * 1000);
1137     } else {
1138     network_iface_stat_ptr->speed = 0;
1139 pajs 1.25 }
1140    
1141 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
1142 ats 1.44 if ((knp = kstat_data_lookup(ksp, "link_duplex")) != NULL) {
1143     switch (knp->value.ui32) {
1144     case 1:
1145 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
1146 ats 1.44 break;
1147     case 2:
1148 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
1149 ats 1.44 break;
1150     }
1151 pajs 1.33 }
1152 pajs 1.25 }
1153     }
1154 ats 1.44
1155     close(sock);
1156 pajs 1.25 kstat_close(kc);
1157 tdb 1.76 #endif
1158 pajs 1.27 #ifdef LINUX
1159     f = fopen("/proc/net/dev", "r");
1160 tdb 1.65 if(f == NULL){
1161 ats 1.69 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/net/dev");
1162 tdb 1.65 return NULL;
1163     }
1164 pajs 1.27
1165     /* Setup stuff so we can do the ioctl to get the info */
1166     if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
1167 ats 1.69 sg_set_error_with_errno(SG_ERROR_SOCKET, NULL);
1168 pajs 1.27 return NULL;
1169     }
1170    
1171     /* Ignore first 2 lines.. Just headings */
1172 tdb 1.66 if((fgets(line, sizeof(line), f)) == NULL) {
1173     sg_set_error(SG_ERROR_PARSE, NULL);
1174     return NULL;
1175     }
1176     if((fgets(line, sizeof(line), f)) == NULL) {
1177     sg_set_error(SG_ERROR_PARSE, NULL);
1178     return NULL;
1179     }
1180 pajs 1.27
1181 tdb 1.65 while((fgets(line, sizeof(line), f)) != NULL){
1182     char *name, *ptr;
1183     struct ifreq ifr;
1184     struct ethtool_cmd ethcmd;
1185     int err;
1186 pajs 1.27
1187     /* Get the interface name */
1188 tdb 1.65 ptr = strchr(line, ':');
1189     if (ptr == NULL) continue;
1190     *ptr='\0';
1191     name = line;
1192     while(isspace(*(name))){
1193     name++;
1194     }
1195 pajs 1.27
1196 tdb 1.65 memset(&ifr, 0, sizeof ifr);
1197     strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1198 pajs 1.27
1199 ats 1.38 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
1200     continue;
1201     }
1202 pajs 1.27
1203     /* We have a good interface to add */
1204 ats 1.59 if (VECTOR_RESIZE(network_iface_stats, ifaces + 1) < 0) {
1205 pajs 1.27 return NULL;
1206     }
1207     network_iface_stat_ptr = network_iface_stats + ifaces;
1208 ats 1.60
1209 ats 1.62 if (sg_update_string(&network_iface_stat_ptr->interface_name,
1210 tdb 1.65 name) < 0) {
1211 ats 1.60 return NULL;
1212     }
1213 ats 1.38 if ((ifr.ifr_flags & IFF_UP) != 0) {
1214 pajs 1.35 network_iface_stat_ptr->up = 1;
1215 ats 1.38 } else {
1216 pajs 1.35 network_iface_stat_ptr->up = 0;
1217     }
1218    
1219 tdb 1.65 memset(&ethcmd, 0, sizeof ethcmd);
1220     ethcmd.cmd = ETHTOOL_GSET;
1221     ifr.ifr_data = (caddr_t) &ethcmd;
1222 ats 1.38
1223 tdb 1.65 err = ioctl(sock, SIOCETHTOOL, &ifr);
1224     if (err == 0) {
1225 ats 1.38 network_iface_stat_ptr->speed = ethcmd.speed;
1226    
1227     switch (ethcmd.duplex) {
1228 tdb 1.72 case DUPLEX_FULL:
1229 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_FULL;
1230 ats 1.38 break;
1231 tdb 1.72 case DUPLEX_HALF:
1232 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_HALF;
1233 ats 1.38 break;
1234     default:
1235 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
1236 ats 1.38 }
1237     } else {
1238     /* Not all interfaces support the ethtool ioctl. */
1239 ats 1.39 network_iface_stat_ptr->speed = 0;
1240 tdb 1.74 network_iface_stat_ptr->duplex = SG_IFACE_DUPLEX_UNKNOWN;
1241 pajs 1.27 }
1242 ats 1.38
1243 pajs 1.27 ifaces++;
1244     }
1245 pajs 1.30 close(sock);
1246 ats 1.38 fclose(f);
1247 pajs 1.27 #endif
1248 ats 1.71 #ifdef CYGWIN
1249     sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
1250     return NULL;
1251     #endif
1252 tdb 1.76 #ifdef WIN32
1253     ifaces = 0;
1254    
1255     if((if_table = win32_get_devices()) == NULL) {
1256     sg_set_error(SG_ERROR_DEVICES, "network interfaces");
1257     return NULL;
1258     }
1259    
1260     if(VECTOR_RESIZE(network_iface_stats, if_table->dwNumEntries) < 0) {
1261     free(if_table);
1262     return NULL;
1263     }
1264    
1265     for(i=0; i<if_table->dwNumEntries; i++) {
1266     network_iface_stat_ptr=network_iface_stats+i;
1267     if_row = if_table->table[i];
1268    
1269     if(sg_update_string(&network_iface_stat_ptr->interface_name,
1270     if_row.bDescr) < 0) {
1271     free(if_table);
1272     return NULL;
1273     }
1274     network_iface_stat_ptr->speed = if_row.dwSpeed /1000000;
1275    
1276     if((if_row.dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED ||
1277     if_row.dwOperStatus ==
1278     MIB_IF_OPER_STATUS_OPERATIONAL) &&
1279     if_row.dwAdminStatus == 1) {
1280     network_iface_stat_ptr->up = 1;
1281     } else {
1282     network_iface_stat_ptr->up = 0;
1283     }
1284    
1285     ifaces++;
1286     }
1287     free(if_table);
1288    
1289     /* again with the renumbering */
1290     for (i=0; i<ifaces; i++) {
1291     no = 2;
1292     for(j=i+1; j<ifaces; j++) {
1293     network_iface_stat_ptr=network_iface_stats+j;
1294     if(strcmp(network_iface_stats[i].interface_name,
1295     network_iface_stat_ptr->interface_name) == 0) {
1296     if(snprintf(buf, sizeof(buf), " #%d", no) < 0) {
1297     break;
1298     }
1299     if(sg_concat_string(&network_iface_stat_ptr->interface_name, buf) != 0) {
1300     return NULL;
1301     }
1302    
1303     no++;
1304     }
1305     }
1306     }
1307 tdb 1.74 #endif
1308    
1309     #ifdef SG_ENABLE_DEPRECATED
1310     network_iface_stat_ptr->dup = network_iface_stat_ptr->duplex;
1311 ats 1.71 #endif
1312    
1313 pajs 1.26 *entries = ifaces;
1314 pajs 1.25 return network_iface_stats;
1315 ats 1.68 }
1316    
1317     int sg_network_iface_compare_name(const void *va, const void *vb) {
1318     const sg_network_iface_stats *a = (const sg_network_iface_stats *)va;
1319     const sg_network_iface_stats *b = (const sg_network_iface_stats *)vb;
1320    
1321     return strcmp(a->interface_name, b->interface_name);
1322 pajs 1.25 }
1323