Created
July 28, 2014 14:45
-
-
Save kokizzu/97618566f6d70d038fa4 to your computer and use it in GitHub Desktop.
modified netmon applet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* opyright (C) 2010 Ciriaco Garcia de Celis | |
* | |
* This program is free software: you can redistribute it and/or | |
* modify it under the terms of the GNU General Public License as | |
* published by the Free Software Foundation, either version 3 of | |
* the License, or (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License (GPL) for more details. | |
* | |
* You should have received a copy of the GNU GPL along with this | |
* program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
// compile with "g++ -O3 -lrt netmon.cpp -o netmon" | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <cstdio> | |
#include <cstring> | |
#include <cstdlib> | |
#include <ctime> | |
#include <climits> | |
#include <cctype> | |
#define STATE_FILE_BASE "/dev/shm/netmon" | |
int exitapp(int exitcode) { | |
char errmsg[64]; | |
sprintf(errmsg, "ERROR code %d", exitcode); | |
write(1, errmsg, strlen(errmsg)); | |
exit(exitcode); | |
return exitcode; | |
} | |
const int BLOCK_SIZE = 512; | |
struct disk_stat { | |
long long read, write; | |
double r_rate, w_rate; | |
char name[16]; | |
}; | |
const int MAX_STAT = 32; | |
class disk_stats { | |
disk_stat stat[MAX_STAT]; | |
int total; | |
public: | |
disk_stats() : total(0) {} | |
const char* parse(const char* line, double seconds) { | |
if(total>=MAX_STAT) exitapp(11); | |
static char cad[256], buffer[256]; | |
long long dummy; | |
disk_stat &ds = stat[total]; | |
sscanf(line,"%lld %lld %s %lld %lld %lld %lld %lld %lld %lld", | |
&dummy,&dummy,ds.name,&dummy,&dummy,&ds.read,&dummy,&dummy,&dummy,&ds.write); | |
int len = strlen(ds.name); | |
if(!dummy) return 0; | |
if(isdigit(ds.name[len-1])) return 0; | |
long long prev_read = 0, prev_write = 0; | |
sprintf(cad,"%s.%s.%d",STATE_FILE_BASE,ds.name,getuid()); | |
int fd = open(cad, O_RDWR | O_CREAT, 0664); | |
if (fd < 0) exitapp(9); | |
int bytes = read(fd, buffer, sizeof(buffer)-1); | |
if (bytes < 0) exitapp(10); | |
buffer[bytes] = 0; | |
sscanf(buffer,"%lld %lld",&prev_read,&prev_write); | |
lseek(fd, 0, SEEK_SET); | |
sprintf(buffer,"%lld %lld",ds.read,ds.write); | |
write(fd, buffer, 64); | |
close(fd); | |
ds.r_rate = (ds.read-prev_read)/seconds*BLOCK_SIZE/1024/1024; | |
ds.w_rate = (ds.write-prev_write)/seconds*BLOCK_SIZE/1024/1024; | |
if(ds.r_rate>0) { | |
if(ds.w_rate>0) sprintf(buffer," | %s: %3.0lf %3.0lf",ds.name,ds.r_rate,ds.w_rate); | |
else sprintf(buffer," | %s: %3.0lf .",ds.name,ds.r_rate); | |
} else { | |
if(ds.w_rate>0) sprintf(buffer," | %s: . %3.0lf",ds.name,ds.w_rate); | |
else sprintf(buffer," | %s: . .",ds.name); | |
} | |
++total; | |
return buffer; | |
} | |
}; | |
int main(int argc, char** argv) { | |
if (argc < 2) { | |
printf("usage: %s <network_interface>\n", argv[0]); | |
return 1; | |
} | |
char buffer[4096], cad[256], *ni, *nf; | |
// read network information | |
int fd = open("/proc/net/dev", O_RDONLY); | |
if (fd < 0) return exitapp(2); | |
int bytes = read(fd, buffer, sizeof(buffer)-1); | |
close(fd); | |
if (bytes < 0) return exitapp(3); | |
buffer[bytes] = 0; | |
timespec tp; | |
clock_gettime(CLOCK_MONOTONIC, &tp); | |
long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec; | |
long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX; | |
bool networkAvailable = false; | |
// search for the proper network interface | |
strcpy(cad, argv[1]); | |
strcat(cad, ":"); | |
char *pif = strstr(buffer, cad); | |
if (pif) { | |
networkAvailable = true; | |
// jump to the received bytes field | |
ni = pif + strlen(cad); | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
*nf++ = 0; | |
// get the received bytes | |
recv_bytes = atoll(ni); | |
// jump to the sent bytes field | |
for (int skip = 0; skip < 8; skip++) { | |
ni = nf; | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
if (!*nf) break; | |
*nf++ = 0; | |
} | |
// get the sent bytes | |
sent_bytes = atoll(ni); | |
} | |
long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0; | |
// read CPU information | |
fd = open("/proc/stat", O_RDONLY); | |
if (fd < 0) return exitapp(4); | |
bytes = read(fd, buffer, sizeof(buffer)-1); | |
close(fd); | |
if (bytes < 0) return exitapp(5); | |
buffer[bytes] = 0; | |
pif = strstr(buffer, "cpu "); | |
if (pif) { | |
ni = pif + 3; | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
*nf++ = 0; | |
// get the user mode time | |
user_mode_time = atoll(ni); | |
ni = nf; | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
*nf++ = 0; | |
// get the user mode nice time | |
user_mode_nice_time = atoll(ni); | |
ni = nf; | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
*nf++ = 0; | |
// get the system mode time | |
system_mode_time = atoll(ni); | |
ni = nf; | |
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; | |
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); | |
*nf++ = 0; | |
// get the idle time | |
idle_time = atoll(ni); | |
} | |
// read the received/sent bytes, date and CPU usage stored by a previous execution | |
sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid()); | |
fd = open(cad, O_RDWR | O_CREAT, 0664); | |
if (fd < 0) return exitapp(6); | |
bytes = read(fd, buffer, sizeof(buffer)-1); | |
if (bytes < 0) { | |
close(fd); | |
return exitapp(7); | |
} | |
long long prev_recv_bytes = 0, prev_sent_bytes = 0, prev_nanoseconds = -1; | |
long long prev_user_mode_time = 0, prev_user_mode_nice_time = 0, prev_system_mode_time = 0, prev_idle_time = -1; | |
if (bytes > 0) { | |
prev_recv_bytes = atoll(buffer); | |
prev_sent_bytes = atoll(buffer+20); | |
prev_nanoseconds = atoll(buffer+40); | |
prev_user_mode_time = atoll(buffer+60); | |
prev_user_mode_nice_time = atoll(buffer+80); | |
prev_system_mode_time = atoll(buffer+100); | |
prev_idle_time = atoll(buffer+120); | |
} | |
// store in the file the current values for later use | |
sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n", | |
recv_bytes, sent_bytes, nanoseconds, | |
user_mode_time, user_mode_nice_time, system_mode_time, idle_time); | |
lseek(fd, 0, SEEK_SET); | |
write(fd, buffer, 140); | |
close(fd); | |
// generate the result | |
strcpy(buffer, "<txt>"); | |
long long elapsed = nanoseconds - prev_nanoseconds; | |
if (elapsed < 1) elapsed = 1; | |
double seconds = elapsed / 1000000000.0; | |
// NETWORK | |
bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes); | |
if (!networkAvailable) { | |
sprintf(cad, " %s is down", argv[1]); | |
strcat(buffer, cad); | |
} else if (!hasNet) { | |
strcat(buffer, "D: - U: - "); | |
} else { | |
long long sent = sent_bytes - prev_sent_bytes; | |
long long received = recv_bytes - prev_recv_bytes; | |
long inbps = (long) (8 * received / seconds + 999) / 8 / 1024; // adding 999 ensures "1" for any rate above 0 | |
long outbps = (long) (8 * sent / seconds + 999) / 8 / 1024; | |
if (inbps < 1024) sprintf(cad, "D: %5ld KB/s ", inbps); | |
else sprintf(cad, "D: %5.0lf MB/s ", inbps/1024.0); | |
strcat(buffer, cad); | |
if (outbps < 1024) sprintf(cad, " | U: %5ld KB/s ", outbps); | |
else sprintf(cad, " | U: %5.0lf MB/s ", outbps/1024.0); | |
strcat(buffer, cad); | |
} | |
long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time | |
- (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time); | |
long long total_cpu = cpu_used + (idle_time - prev_idle_time); | |
int total_ram = 0, ram_used = 0; | |
bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0); | |
// CPU | |
if (!hasCPU) sprintf(cad, " | CPU: %3lld",total_cpu); | |
else sprintf(cad, " | CPU: %3.0lf%%", cpu_used * 100.0 / total_cpu); | |
strcat(buffer, cad); | |
// RAM | |
FILE *meminfo = fopen("/proc/meminfo", "r"); | |
if(meminfo) { | |
char line[256]; | |
while(fgets(line, sizeof(line), meminfo)) { | |
if(!total_ram && sscanf(line, "MemTotal: %d kB", &total_ram)); | |
if(sscanf(line, "Active: %d kB", &ram_used) == 1) { | |
sprintf(cad," | RAM: %5d MB",ram_used/1024); | |
break; | |
} | |
} | |
fclose(meminfo); | |
if(!ram_used) sprintf(cad, " RAM: %5d MB",total_ram); | |
strcat(buffer,cad); | |
} | |
// DISK | |
FILE *diskstat = fopen("/proc/diskstats","rt"); | |
disk_stats dss; | |
if(diskstat) { | |
char line[512]; | |
while(fgets(line,sizeof(line),diskstat)) { | |
const char *cad = dss.parse(line,seconds); | |
if(!cad) continue; | |
strcat(buffer, cad); | |
} | |
fclose(diskstat); | |
} | |
strcat(buffer, "</txt><tool>"); | |
// TOOLTIPS | |
bool useNet = networkAvailable && hasNet; | |
if (useNet) { | |
sprintf(cad, " %s:\n %.2f MB received \n %.2f MB sent ", | |
argv[1], recv_bytes/1024.0/1024, sent_bytes/1024.0/1024); | |
strcat(buffer, cad); | |
} | |
if (hasCPU) { | |
if (useNet) strcat(buffer, "\n"); | |
long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time; | |
sprintf(cad, " CPU usage:\n %5.1f%% since boot \n", | |
total_used_cpu * 100.0 / (total_used_cpu + idle_time)); | |
strcat(buffer, cad); | |
} | |
sprintf(cad, " RAM usage:\n %5.1f%% of %d MB", | |
ram_used * 100.0 / total_ram, total_ram / 1024 ); | |
strcat(buffer, cad); | |
strcat(buffer, "</tool>"); | |
write(1, buffer, strlen(buffer)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment