1/* $Id: getifstats.c,v 1.12 2013/04/29 10:18:20 nanard Exp $ */ 2/* MiniUPnP project 3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 4 * (c) 2006-2013 Thomas Bernard 5 * This software is subject to the conditions detailed 6 * in the LICENCE file provided within the distribution */ 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <syslog.h> 11#include <string.h> 12#include <time.h> 13 14#include "../config.h" 15#include "../getifstats.h" 16 17#ifdef GET_WIRELESS_STATS 18#include <unistd.h> 19#include <sys/ioctl.h> 20#include <arpa/inet.h> 21#include <linux/wireless.h> 22#endif /* GET_WIRELESS_STATS */ 23 24/* that is the answer */ 25#define BAUDRATE_DEFAULT 4200000 26 27int 28getifstats(const char * ifname, struct ifdata * data) 29{ 30 FILE *f; 31 char line[512]; 32 char * p; 33 int i; 34 int r = -1; 35 char fname[64]; 36#ifdef ENABLE_GETIFSTATS_CACHING 37 static time_t cache_timestamp = 0; 38 static struct ifdata cache_data; 39 time_t current_time; 40#endif /* ENABLE_GETIFSTATS_CACHING */ 41 if(!data) 42 return -1; 43 data->baudrate = BAUDRATE_DEFAULT; 44 data->opackets = 0; 45 data->ipackets = 0; 46 data->obytes = 0; 47 data->ibytes = 0; 48 if(!ifname || ifname[0]=='\0') 49 return -1; 50#ifdef ENABLE_GETIFSTATS_CACHING 51 current_time = time(NULL); 52 if(current_time == ((time_t)-1)) { 53 syslog(LOG_ERR, "getifstats() : time() error : %m"); 54 } else { 55 if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) { 56 /* return cached data */ 57 memcpy(data, &cache_data, sizeof(struct ifdata)); 58 return 0; 59 } 60 } 61#endif /* ENABLE_GETIFSTATS_CACHING */ 62 f = fopen("/proc/net/dev", "r"); 63 if(!f) { 64 syslog(LOG_ERR, "getifstats() : cannot open /proc/net/dev : %m"); 65 return -1; 66 } 67 /* discard the two header lines */ 68 if(!fgets(line, sizeof(line), f) || !fgets(line, sizeof(line), f)) { 69 syslog(LOG_ERR, "getifstats() : error reading /proc/net/dev : %m"); 70 } 71 while(fgets(line, sizeof(line), f)) { 72 p = line; 73 while(*p==' ') p++; 74 i = 0; 75 while(ifname[i] == *p) { 76 p++; i++; 77 } 78 /* TODO : how to handle aliases ? */ 79 if(ifname[i] || *p != ':') 80 continue; 81 p++; 82 while(*p==' ') p++; 83 data->ibytes = strtoul(p, &p, 0); 84 while(*p==' ') p++; 85 data->ipackets = strtoul(p, &p, 0); 86 /* skip 6 columns */ 87 for(i=6; i>0 && *p!='\0'; i--) { 88 while(*p==' ') p++; 89 while(*p!=' ' && *p) p++; 90 } 91 while(*p==' ') p++; 92 data->obytes = strtoul(p, &p, 0); 93 while(*p==' ') p++; 94 data->opackets = strtoul(p, &p, 0); 95 r = 0; 96 break; 97 } 98 fclose(f); 99 /* get interface speed */ 100 /* NB! some interfaces, like ppp, don't support speed queries */ 101 snprintf(fname, sizeof(fname), "/sys/class/net/%s/speed", ifname); 102 f = fopen(fname, "r"); 103 if(f) { 104 if(fgets(line, sizeof(line), f)) { 105 i = atoi(line); /* 65535 means unknown */ 106 if(i > 0 && i < 65535) 107 data->baudrate = 1000000*i; 108 } 109 fclose(f); 110 } 111#ifdef GET_WIRELESS_STATS 112 if(data->baudrate == BAUDRATE_DEFAULT) { 113 struct iwreq iwr; 114 int s; 115 s = socket(AF_INET, SOCK_DGRAM, 0); 116 if(s >= 0) { 117 strncpy(iwr.ifr_name, ifname, IFNAMSIZ); 118 if(ioctl(s, SIOCGIWRATE, &iwr) >= 0) { 119 data->baudrate = iwr.u.bitrate.value; 120 } 121 close(s); 122 } 123 } 124#endif /* GET_WIRELESS_STATS */ 125#ifdef ENABLE_GETIFSTATS_CACHING 126 if(r==0 && current_time!=((time_t)-1)) { 127 /* cache the new data */ 128 cache_timestamp = current_time; 129 memcpy(&cache_data, data, sizeof(struct ifdata)); 130 } 131#endif /* ENABLE_GETIFSTATS_CACHING */ 132 return r; 133} 134 135