136 lines
3.3 KiB
C
136 lines
3.3 KiB
C
/* $Id: getifstats.c,v 1.12 2013/04/29 10:18:20 nanard Exp $ */
|
|
/* MiniUPnP project
|
|
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
|
* (c) 2006-2013 Thomas Bernard
|
|
* This software is subject to the conditions detailed
|
|
* in the LICENCE file provided within the distribution */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <syslog.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "../config.h"
|
|
#include "../getifstats.h"
|
|
|
|
#ifdef GET_WIRELESS_STATS
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <arpa/inet.h>
|
|
#include <linux/wireless.h>
|
|
#endif /* GET_WIRELESS_STATS */
|
|
|
|
/* that is the answer */
|
|
#define BAUDRATE_DEFAULT 4200000
|
|
|
|
int
|
|
getifstats(const char * ifname, struct ifdata * data)
|
|
{
|
|
FILE *f;
|
|
char line[512];
|
|
char * p;
|
|
int i;
|
|
int r = -1;
|
|
char fname[64];
|
|
#ifdef ENABLE_GETIFSTATS_CACHING
|
|
static time_t cache_timestamp = 0;
|
|
static struct ifdata cache_data;
|
|
time_t current_time;
|
|
#endif /* ENABLE_GETIFSTATS_CACHING */
|
|
if(!data)
|
|
return -1;
|
|
data->baudrate = BAUDRATE_DEFAULT;
|
|
data->opackets = 0;
|
|
data->ipackets = 0;
|
|
data->obytes = 0;
|
|
data->ibytes = 0;
|
|
if(!ifname || ifname[0]=='\0')
|
|
return -1;
|
|
#ifdef ENABLE_GETIFSTATS_CACHING
|
|
current_time = time(NULL);
|
|
if(current_time == ((time_t)-1)) {
|
|
syslog(LOG_ERR, "getifstats() : time() error : %m");
|
|
} else {
|
|
if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
|
|
/* return cached data */
|
|
memcpy(data, &cache_data, sizeof(struct ifdata));
|
|
return 0;
|
|
}
|
|
}
|
|
#endif /* ENABLE_GETIFSTATS_CACHING */
|
|
f = fopen("/proc/net/dev", "r");
|
|
if(!f) {
|
|
syslog(LOG_ERR, "getifstats() : cannot open /proc/net/dev : %m");
|
|
return -1;
|
|
}
|
|
/* discard the two header lines */
|
|
if(!fgets(line, sizeof(line), f) || !fgets(line, sizeof(line), f)) {
|
|
syslog(LOG_ERR, "getifstats() : error reading /proc/net/dev : %m");
|
|
}
|
|
while(fgets(line, sizeof(line), f)) {
|
|
p = line;
|
|
while(*p==' ') p++;
|
|
i = 0;
|
|
while(ifname[i] == *p) {
|
|
p++; i++;
|
|
}
|
|
/* TODO : how to handle aliases ? */
|
|
if(ifname[i] || *p != ':')
|
|
continue;
|
|
p++;
|
|
while(*p==' ') p++;
|
|
data->ibytes = strtoul(p, &p, 0);
|
|
while(*p==' ') p++;
|
|
data->ipackets = strtoul(p, &p, 0);
|
|
/* skip 6 columns */
|
|
for(i=6; i>0 && *p!='\0'; i--) {
|
|
while(*p==' ') p++;
|
|
while(*p!=' ' && *p) p++;
|
|
}
|
|
while(*p==' ') p++;
|
|
data->obytes = strtoul(p, &p, 0);
|
|
while(*p==' ') p++;
|
|
data->opackets = strtoul(p, &p, 0);
|
|
r = 0;
|
|
break;
|
|
}
|
|
fclose(f);
|
|
/* get interface speed */
|
|
snprintf(fname, sizeof(fname), "/sys/class/net/%s/speed", ifname);
|
|
f = fopen(fname, "r");
|
|
if(f) {
|
|
if(fgets(line, sizeof(line), f)) {
|
|
i = atoi(line); /* 65535 means unknown */
|
|
if(i > 0 && i < 65535)
|
|
data->baudrate = 1000000*i;
|
|
}
|
|
fclose(f);
|
|
} else {
|
|
syslog(LOG_WARNING, "cannot read %s file : %m", fname);
|
|
}
|
|
#ifdef GET_WIRELESS_STATS
|
|
if(data->baudrate == BAUDRATE_DEFAULT) {
|
|
struct iwreq iwr;
|
|
int s;
|
|
s = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if(s >= 0) {
|
|
strncpy(iwr.ifr_name, ifname, IFNAMSIZ);
|
|
if(ioctl(s, SIOCGIWRATE, &iwr) >= 0) {
|
|
data->baudrate = iwr.u.bitrate.value;
|
|
}
|
|
close(s);
|
|
}
|
|
}
|
|
#endif /* GET_WIRELESS_STATS */
|
|
#ifdef ENABLE_GETIFSTATS_CACHING
|
|
if(r==0 && current_time!=((time_t)-1)) {
|
|
/* cache the new data */
|
|
cache_timestamp = current_time;
|
|
memcpy(&cache_data, data, sizeof(struct ifdata));
|
|
}
|
|
#endif /* ENABLE_GETIFSTATS_CACHING */
|
|
return r;
|
|
}
|
|
|