-201 Removals
+270 Additions
/* /* opyright (C) 2010 Ciriaco Garcia de Celis
* Copyright (C) 2010 Ciriaco Garcia de Celis
* *
* This program is free software: you can redistribute it and/or * This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of * published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License (GPL) for more details. * GNU General Public License (GPL) for more details.
* *
* You should have received a copy of the GNU GPL along with this * You should have received a copy of the GNU GPL along with this
* program. If not, see <http://www.gnu.org/licenses/>. * program. If not, see <http://www.gnu.org/licenses/>.
*/ */
// compile with "g++ -O3 -lrt netmon.cpp -o netmon" // compile with "g++ -O3 -lrt netmon.cpp -o netmon"
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <climits> #include <climits>
#include <cctype>
#define STATE_FILE_BASE "/dev/shm/netmon" #define STATE_FILE_BASE "/dev/shm/netmon"
int exitapp(int exitcode)
{ int exitapp(int exitcode) {
char errmsg[64]; char errmsg[64];
sprintf(errmsg, "ERROR code %d", exitcode); sprintf(errmsg, "ERROR code %d", exitcode);
write(1, errmsg, strlen(errmsg)); write(1, errmsg, strlen(errmsg));
return exitcode; exit(exitcode);
return exitcode;
} }
int main(int argc, char** argv) const int BLOCK_SIZE = 512;
{
if (argc < 2) struct disk_stat {
{ long long read, write;
printf("usage: %s <network_interface> [CPU]\n", argv[0]); double r_rate, w_rate;
return 1; 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;
} }
};
bool reportCPU = (argc > 2) && (strcmp(argv[2], "CPU") == 0);
char buffer[4096], cad[256], *ni, *nf; int main(int argc, char** argv) {
if (argc < 2) {
// read network information printf("usage: %s <network_interface>\n", argv[0]);
int fd = open("/proc/net/dev", O_RDONLY); return 1;
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; char buffer[4096], cad[256], *ni, *nf;
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; // read network information
bool networkAvailable = false; 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;
// search for the proper network interface timespec tp;
strcpy(cad, argv[1]); clock_gettime(CLOCK_MONOTONIC, &tp);
strcat(cad, ":"); long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec;
char *pif = strstr(buffer, cad);
if (pif != NULL)
{
networkAvailable = true;
// jump to the received bytes field long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX;
ni = pif + strlen(cad); bool networkAvailable = false;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the received bytes // search for the proper network interface
recv_bytes = atoll(ni); strcpy(cad, argv[1]);
strcat(cad, ":");
char *pif = strstr(buffer, cad);
if (pif) {
networkAvailable = true;
// jump to the sent bytes field // jump to the received bytes field
for (int skip = 0; skip < 8; skip++) ni = pif + strlen(cad);
{ while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
ni = nf; for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; *nf++ = 0;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
if (!*nf) break; // get the received bytes
*nf++ = 0; recv_bytes = atoll(ni);
}
// get the sent bytes // jump to the sent bytes field
sent_bytes = atoll(ni); 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;
} }
long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0; // get the sent bytes
sent_bytes = atoll(ni);
}
if (reportCPU) 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 "); // read CPU information
if (pif != NULL) fd = open("/proc/stat", O_RDONLY);
{ if (fd < 0) return exitapp(4);
ni = pif + 3; bytes = read(fd, buffer, sizeof(buffer)-1);
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; close(fd);
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); if (bytes < 0) return exitapp(5);
*nf++ = 0; buffer[bytes] = 0;
// get the user mode time pif = strstr(buffer, "cpu ");
user_mode_time = atoll(ni); if (pif) {
ni = pif + 3;
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
ni = nf; // get the user mode time
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; user_mode_time = atoll(ni);
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the user mode nice time ni = nf;
user_mode_nice_time = atoll(ni); while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
ni = nf; // get the user mode nice time
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; user_mode_nice_time = atoll(ni);
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the system mode time ni = nf;
system_mode_time = atoll(ni); while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
ni = nf; // get the system mode time
while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; system_mode_time = atoll(ni);
for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
*nf++ = 0;
// get the idle time ni = nf;
idle_time = atoll(ni); while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
} for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
} *nf++ = 0;
// read the received/sent bytes, date and CPU usage stored by a previous execution // get the idle time
sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid()); idle_time = atoll(ni);
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, prev_sent_bytes, prev_nanoseconds = -1;
long long prev_user_mode_time, prev_user_mode_nice_time, prev_system_mode_time, 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 // read the received/sent bytes, date and CPU usage stored by a previous execution
sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n", sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid());
recv_bytes, sent_bytes, nanoseconds, fd = open(cad, O_RDWR | O_CREAT, 0664);
user_mode_time, user_mode_nice_time, system_mode_time, idle_time); if (fd < 0) return exitapp(6);
lseek(fd, 0, SEEK_SET); bytes = read(fd, buffer, sizeof(buffer)-1);
write(fd, buffer, 140); if (bytes < 0) {
close(fd); 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);
}
// generate the result // 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);
strcpy(buffer, "<txt>"); // generate the result
bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes); strcpy(buffer, "<txt>");
long long elapsed = nanoseconds - prev_nanoseconds;
if (elapsed < 1) elapsed = 1;
double seconds = elapsed / 1000000000.0;
if (!networkAvailable) // NETWORK
{ bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes);
sprintf(cad, " %s is down", argv[1]);
strcat(buffer, cad);
}
else if (!hasNet)
{
strcat(buffer, " ? kbps IN \n ? kbps OUT");
}
else
{
long long elapsed = nanoseconds - prev_nanoseconds;
if (elapsed < 1) elapsed = 1;
double seconds = elapsed / 1000000000.0;
long long sent = sent_bytes - prev_sent_bytes;
long long received = recv_bytes - prev_recv_bytes;
long inbps = (long) (8 * received / seconds + 999); // adding 999 ensures "1" for any rate above 0
long outbps = (long) (8 * sent / seconds + 999);
if (inbps < 1000000)
sprintf(cad, "%6d kbps IN \n", inbps/1000);
else
sprintf(cad, "%6.3f Mbps IN \n", inbps/1000000.0);
strcat(buffer, cad);
if (outbps < 1000000) if (!networkAvailable) {
sprintf(cad, "%6d kbps OUT", outbps/1000); sprintf(cad, " %s is down", argv[1]);
else strcat(buffer, cad);
sprintf(cad, "%6.3f Mbps OUT", outbps/1000000.0); } else if (!hasNet) {
strcat(buffer, cad); 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;
long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time 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); - (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time);
long long total_cpu = cpu_used + (idle_time - prev_idle_time); long long total_cpu = cpu_used + (idle_time - prev_idle_time);
bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0); int total_ram = 0, ram_used = 0;
if (reportCPU) bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0);
{
if (!hasCPU)
{
strcat(buffer, "\n ? % CPU");
}
else
{
sprintf(cad, "\n %5.1f%% CPU", cpu_used * 100.0 / total_cpu);
strcat(buffer, cad);
}
}
strcat(buffer, "</txt><tool>"); // CPU
if (!hasCPU) sprintf(cad, " | CPU: %3lld",total_cpu);
else sprintf(cad, " | CPU: %3.0lf%%", cpu_used * 100.0 / total_cpu);
strcat(buffer, cad);
if (networkAvailable && hasNet) // RAM
{ FILE *meminfo = fopen("/proc/meminfo", "r");
sprintf(cad, " %s:\n %.2f MB received \n %.2f MB sent ", if(meminfo) {
argv[1], recv_bytes/1000000.0, sent_bytes/1000000.0); char line[256];
strcat(buffer, cad); 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);
}
if (reportCPU && hasCPU) // DISK
{ FILE *diskstat = fopen("/proc/diskstats","rt");
if (networkAvailable && hasNet) strcat(buffer, "\n"); disk_stats dss;
long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time; if(diskstat) {
sprintf(cad, " CPU usage:\n %5.1f%% since boot ", char line[512];
total_used_cpu * 100.0 / (total_used_cpu + idle_time)); while(fgets(line,sizeof(line),diskstat)) {
strcat(buffer, cad); const char *cad = dss.parse(line,seconds);
if(!cad) continue;
strcat(buffer, cad);
} }
fclose(diskstat);
}
strcat(buffer, "</tool>"); strcat(buffer, "</txt><tool>");
write(1, buffer, strlen(buffer));
// 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>");
return 0; write(1, buffer, strlen(buffer));
return 0;
}}
Editor
Original Text
Changed Text