201 removals
270 additions
1./* 1./* opyright (C) 2010 Ciriaco Garcia de Celis
2. * Copyright (C) 2010 Ciriaco Garcia de Celis
3. * 2. *
4. * This program is free software: you can redistribute it and/or 3. * This program is free software: you can redistribute it and/or
5. * modify it under the terms of the GNU General Public License as 4. * modify it under the terms of the GNU General Public License as
6. * published by the Free Software Foundation, either version 3 of 5. * published by the Free Software Foundation, either version 3 of
7. * the License, or (at your option) any later version. 6. * the License, or (at your option) any later version.
8. * 7. *
9. * This program is distributed in the hope that it will be useful, 8. * This program is distributed in the hope that it will be useful,
10. * but WITHOUT ANY WARRANTY; without even the implied warranty of 9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12. * GNU General Public License (GPL) for more details. 11. * GNU General Public License (GPL) for more details.
13. * 12. *
14. * You should have received a copy of the GNU GPL along with this 13. * You should have received a copy of the GNU GPL along with this
15. * program. If not, see <http://www.gnu.org/licenses/>. 14. * program. If not, see <http://www.gnu.org/licenses/>.
16. */ 15. */
17. 16.
18.// compile with "g++ -O3 -lrt netmon.cpp -o netmon" 17.// compile with "g++ -O3 -lrt netmon.cpp -o netmon"
19. 18.
20.#include <sys/stat.h> 19.#include <sys/stat.h>
21.#include <fcntl.h> 20.#include <fcntl.h>
22.#include <unistd.h> 21.#include <unistd.h>
23.#include <cstdio> 22.#include <cstdio>
24.#include <cstring> 23.#include <cstring>
25.#include <cstdlib> 24.#include <cstdlib>
26.#include <ctime> 25.#include <ctime>
27.#include <climits> 26.#include <climits>
27.#include <cctype>
28. 28.
29.#define STATE_FILE_BASE "/dev/shm/netmon" 29.#define STATE_FILE_BASE "/dev/shm/netmon"
30. 30.
31.int exitapp(int exitcode) 31.
32.{ 32.int exitapp(int exitcode) {
33. char errmsg[64]; 33. char errmsg[64];
34. sprintf(errmsg, "ERROR code %d", exitcode); 34. sprintf(errmsg, "ERROR code %d", exitcode);
35. write(1, errmsg, strlen(errmsg)); 35. write(1, errmsg, strlen(errmsg));
36. return exitcode; 36. exit(exitcode);
37. return exitcode;
37.} 38.}
38. 39.
39.int main(int argc, char** argv) 40.const int BLOCK_SIZE = 512;
40.{ 41.
41. if (argc < 2) 42.struct disk_stat {
42. { 43. long long read, write;
43. printf("usage: %s <network_interface> [CPU]\n", argv[0]); 44. double r_rate, w_rate;
44. return 1; 45. char name[16];
46.};
47.
48.const int MAX_STAT = 32;
49.class disk_stats {
50. disk_stat stat[MAX_STAT];
51. int total;
52. public:
53. disk_stats() : total(0) {}
54. const char* parse(const char* line, double seconds) {
55. if(total>=MAX_STAT) exitapp(11);
56. static char cad[256], buffer[256];
57. long long dummy;
58. disk_stat &ds = stat[total];
59. sscanf(line,"%lld %lld %s %lld %lld %lld %lld %lld %lld %lld",
60. &dummy,&dummy,ds.name,&dummy,&dummy,&ds.read,&dummy,&dummy,&dummy,&ds.write);
61. int len = strlen(ds.name);
62. if(!dummy) return 0;
63. if(isdigit(ds.name[len-1])) return 0;
64.
65. long long prev_read = 0, prev_write = 0;
66. sprintf(cad,"%s.%s.%d",STATE_FILE_BASE,ds.name,getuid());
67. int fd = open(cad, O_RDWR | O_CREAT, 0664);
68. if (fd < 0) exitapp(9);
69.
70. int bytes = read(fd, buffer, sizeof(buffer)-1);
71. if (bytes < 0) exitapp(10);
72. buffer[bytes] = 0;
73.
74. sscanf(buffer,"%lld %lld",&prev_read,&prev_write);
75. lseek(fd, 0, SEEK_SET);
76. sprintf(buffer,"%lld %lld",ds.read,ds.write);
77. write(fd, buffer, 64);
78. close(fd);
79.
80. ds.r_rate = (ds.read-prev_read)/seconds*BLOCK_SIZE/1024/1024;
81. ds.w_rate = (ds.write-prev_write)/seconds*BLOCK_SIZE/1024/1024;
82. if(ds.r_rate>0) {
83. if(ds.w_rate>0) sprintf(buffer," | %s: %3.0lf %3.0lf",ds.name,ds.r_rate,ds.w_rate);
84. else sprintf(buffer," | %s: %3.0lf .",ds.name,ds.r_rate);
85. } else {
86. if(ds.w_rate>0) sprintf(buffer," | %s: . %3.0lf",ds.name,ds.w_rate);
87. else sprintf(buffer," | %s: . .",ds.name);
88. }
89.
90. ++total;
91. return buffer;
45. } 92. }
93.};
46. 94.
47. bool reportCPU = (argc > 2) && (strcmp(argv[2], "CPU") == 0);
48. 95.
49. char buffer[4096], cad[256], *ni, *nf; 96.int main(int argc, char** argv) {
50. 97. if (argc < 2) {
51. // read network information 98. printf("usage: %s <network_interface>\n", argv[0]);
52. int fd = open("/proc/net/dev", O_RDONLY); 99. return 1;
53. if (fd < 0) return exitapp(2); 100. }
54. int bytes = read(fd, buffer, sizeof(buffer)-1);
55. close(fd);
56. if (bytes < 0) return exitapp(3);
57. buffer[bytes] = 0;
58. 101.
59. timespec tp; 102. char buffer[4096], cad[256], *ni, *nf;
60. clock_gettime(CLOCK_MONOTONIC, &tp);
61. long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec;
62. 103.
63. long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX; 104. // read network information
64. bool networkAvailable = false; 105. int fd = open("/proc/net/dev", O_RDONLY);
106. if (fd < 0) return exitapp(2);
107. int bytes = read(fd, buffer, sizeof(buffer)-1);
108. close(fd);
109. if (bytes < 0) return exitapp(3);
110. buffer[bytes] = 0;
65. 111.
66. // search for the proper network interface 112. timespec tp;
67. strcpy(cad, argv[1]); 113. clock_gettime(CLOCK_MONOTONIC, &tp);
68. strcat(cad, ":"); 114. long long nanoseconds = tp.tv_sec * 1000000000LL + tp.tv_nsec;
69. char *pif = strstr(buffer, cad);
70. if (pif != NULL)
71. {
72. networkAvailable = true;
73. 115.
74. // jump to the received bytes field 116. long long recv_bytes=LLONG_MAX, sent_bytes=LLONG_MAX;
75. ni = pif + strlen(cad); 117. bool networkAvailable = false;
76. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
77. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
78. *nf++ = 0;
79. 118.
80. // get the received bytes 119. // search for the proper network interface
81. recv_bytes = atoll(ni); 120. strcpy(cad, argv[1]);
121. strcat(cad, ":");
122. char *pif = strstr(buffer, cad);
123. if (pif) {
124. networkAvailable = true;
82. 125.
83. // jump to the sent bytes field 126. // jump to the received bytes field
84. for (int skip = 0; skip < 8; skip++) 127. ni = pif + strlen(cad);
85. { 128. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
86. ni = nf; 129. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
87. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; 130. *nf++ = 0;
88. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); 131.
89. if (!*nf) break; 132. // get the received bytes
90. *nf++ = 0; 133. recv_bytes = atoll(ni);
91. }
92. 134.
93. // get the sent bytes 135. // jump to the sent bytes field
94. sent_bytes = atoll(ni); 136. for (int skip = 0; skip < 8; skip++) {
137. ni = nf;
138. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
139. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
140. if (!*nf) break;
141. *nf++ = 0;
95. } 142. }
96. 143.
97. long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0; 144. // get the sent bytes
145. sent_bytes = atoll(ni);
146. }
98. 147.
99. if (reportCPU) 148. long long user_mode_time=0, user_mode_nice_time=0, system_mode_time=0, idle_time=0;
100. {
101. // read CPU information
102. fd = open("/proc/stat", O_RDONLY);
103. if (fd < 0) return exitapp(4);
104. bytes = read(fd, buffer, sizeof(buffer)-1);
105. close(fd);
106. if (bytes < 0) return exitapp(5);
107. buffer[bytes] = 0;
108. 149.
109. pif = strstr(buffer, "cpu "); 150. // read CPU information
110. if (pif != NULL) 151. fd = open("/proc/stat", O_RDONLY);
111. { 152. if (fd < 0) return exitapp(4);
112. ni = pif + 3; 153. bytes = read(fd, buffer, sizeof(buffer)-1);
113. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; 154. close(fd);
114. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++); 155. if (bytes < 0) return exitapp(5);
115. *nf++ = 0; 156. buffer[bytes] = 0;
116. 157.
117. // get the user mode time 158. pif = strstr(buffer, "cpu ");
118. user_mode_time = atoll(ni); 159. if (pif) {
160. ni = pif + 3;
161. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
162. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
163. *nf++ = 0;
119. 164.
120. ni = nf; 165. // get the user mode time
121. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; 166. user_mode_time = atoll(ni);
122. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
123. *nf++ = 0;
124. 167.
125. // get the user mode nice time 168. ni = nf;
126. user_mode_nice_time = atoll(ni); 169. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
170. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
171. *nf++ = 0;
127. 172.
128. ni = nf; 173. // get the user mode nice time
129. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; 174. user_mode_nice_time = atoll(ni);
130. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
131. *nf++ = 0;
132. 175.
133. // get the system mode time 176. ni = nf;
134. system_mode_time = atoll(ni); 177. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
178. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
179. *nf++ = 0;
135. 180.
136. ni = nf; 181. // get the system mode time
137. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++; 182. system_mode_time = atoll(ni);
138. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
139. *nf++ = 0;
140. 183.
141. // get the idle time 184. ni = nf;
142. idle_time = atoll(ni); 185. while (*ni && ((*ni == ' ') || (*ni == '\t'))) ni++;
143. } 186. for (nf = ni; *nf && (*nf != ' ') && (*nf != '\t'); nf++);
144. } 187. *nf++ = 0;
145. 188.
146. // read the received/sent bytes, date and CPU usage stored by a previous execution 189. // get the idle time
147. sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid()); 190. idle_time = atoll(ni);
148. fd = open(cad, O_RDWR | O_CREAT, 0664); 191. }
149. if (fd < 0) return exitapp(6);
150. bytes = read(fd, buffer, sizeof(buffer)-1);
151. if (bytes < 0)
152. {
153. close(fd);
154. return exitapp(7);
155. }
156. long long prev_recv_bytes, prev_sent_bytes, prev_nanoseconds = -1;
157. long long prev_user_mode_time, prev_user_mode_nice_time, prev_system_mode_time, prev_idle_time = -1;
158. if (bytes > 0)
159. {
160. prev_recv_bytes = atoll(buffer);
161. prev_sent_bytes = atoll(buffer+20);
162. prev_nanoseconds = atoll(buffer+40);
163. prev_user_mode_time = atoll(buffer+60);
164. prev_user_mode_nice_time = atoll(buffer+80);
165. prev_system_mode_time = atoll(buffer+100);
166. prev_idle_time = atoll(buffer+120);
167. }
168. 192.
169. // store in the file the current values for later use 193. // read the received/sent bytes, date and CPU usage stored by a previous execution
170. sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n", 194. sprintf(cad, "%s.%s.%d", STATE_FILE_BASE, argv[1], getuid());
171. recv_bytes, sent_bytes, nanoseconds, 195. fd = open(cad, O_RDWR | O_CREAT, 0664);
172. user_mode_time, user_mode_nice_time, system_mode_time, idle_time); 196. if (fd < 0) return exitapp(6);
173. lseek(fd, 0, SEEK_SET); 197. bytes = read(fd, buffer, sizeof(buffer)-1);
174. write(fd, buffer, 140); 198. if (bytes < 0) {
175. close(fd); 199. close(fd);
200. return exitapp(7);
201. }
202. long long prev_recv_bytes = 0, prev_sent_bytes = 0, prev_nanoseconds = -1;
203. long long prev_user_mode_time = 0, prev_user_mode_nice_time = 0, prev_system_mode_time = 0, prev_idle_time = -1;
204. if (bytes > 0) {
205. prev_recv_bytes = atoll(buffer);
206. prev_sent_bytes = atoll(buffer+20);
207. prev_nanoseconds = atoll(buffer+40);
208. prev_user_mode_time = atoll(buffer+60);
209. prev_user_mode_nice_time = atoll(buffer+80);
210. prev_system_mode_time = atoll(buffer+100);
211. prev_idle_time = atoll(buffer+120);
212. }
176. 213.
177. // generate the result 214. // store in the file the current values for later use
215. sprintf(buffer, "%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n%019lld\n",
216. recv_bytes, sent_bytes, nanoseconds,
217. user_mode_time, user_mode_nice_time, system_mode_time, idle_time);
218. lseek(fd, 0, SEEK_SET);
219. write(fd, buffer, 140);
220. close(fd);
178. 221.
179. strcpy(buffer, "<txt>"); 222. // generate the result
180. 223.
181. bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes); 224. strcpy(buffer, "<txt>");
225. long long elapsed = nanoseconds - prev_nanoseconds;
226. if (elapsed < 1) elapsed = 1;
227. double seconds = elapsed / 1000000000.0;
182. 228.
183. if (!networkAvailable) 229. // NETWORK
184. { 230. bool hasNet = networkAvailable && (prev_nanoseconds >= 0) && (recv_bytes >= prev_recv_bytes) && (sent_bytes >= prev_sent_bytes);
185. sprintf(cad, " %s is down", argv[1]);
186. strcat(buffer, cad);
187. }
188. else if (!hasNet)
189. {
190. strcat(buffer, " ? kbps IN \n ? kbps OUT");
191. }
192. else
193. {
194. long long elapsed = nanoseconds - prev_nanoseconds;
195. if (elapsed < 1) elapsed = 1;
196. double seconds = elapsed / 1000000000.0;
197. long long sent = sent_bytes - prev_sent_bytes;
198. long long received = recv_bytes - prev_recv_bytes;
199. long inbps = (long) (8 * received / seconds + 999); // adding 999 ensures "1" for any rate above 0
200. long outbps = (long) (8 * sent / seconds + 999);
201. if (inbps < 1000000)
202. sprintf(cad, "%6d kbps IN \n", inbps/1000);
203. else
204. sprintf(cad, "%6.3f Mbps IN \n", inbps/1000000.0);
205. strcat(buffer, cad);
206. 231.
207. if (outbps < 1000000) 232. if (!networkAvailable) {
208. sprintf(cad, "%6d kbps OUT", outbps/1000); 233. sprintf(cad, " %s is down", argv[1]);
209. else 234. strcat(buffer, cad);
210. sprintf(cad, "%6.3f Mbps OUT", outbps/1000000.0); 235. } else if (!hasNet) {
211. strcat(buffer, cad); 236. strcat(buffer, "D: - U: - ");
212. 237. } else {
213. } 238. long long sent = sent_bytes - prev_sent_bytes;
239. long long received = recv_bytes - prev_recv_bytes;
240. long inbps = (long) (8 * received / seconds + 999) / 8 / 1024; // adding 999 ensures "1" for any rate above 0
241. long outbps = (long) (8 * sent / seconds + 999) / 8 / 1024;
214. 242.
215. long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time 243. if (inbps < 1024) sprintf(cad, "D: %5ld KB/s ", inbps);
244. else sprintf(cad, "D: %5.0lf MB/s ", inbps/1024.0);
245. strcat(buffer, cad);
246.
247. if (outbps < 1024) sprintf(cad, " | U: %5ld KB/s ", outbps);
248. else sprintf(cad, " | U: %5.0lf MB/s ", outbps/1024.0);
249. strcat(buffer, cad);
250.
251. }
252.
253. long long cpu_used = user_mode_time + user_mode_nice_time + system_mode_time
216. - (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time); 254. - (prev_user_mode_time + prev_user_mode_nice_time + prev_system_mode_time);
217. long long total_cpu = cpu_used + (idle_time - prev_idle_time); 255. long long total_cpu = cpu_used + (idle_time - prev_idle_time);
218. bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0); 256. int total_ram = 0, ram_used = 0;
219. if (reportCPU) 257. bool hasCPU = (prev_idle_time >= 0) && (total_cpu > 0);
220. {
221. if (!hasCPU)
222. {
223. strcat(buffer, "\n ? % CPU");
224. }
225. else
226. {
227. sprintf(cad, "\n %5.1f%% CPU", cpu_used * 100.0 / total_cpu);
228. strcat(buffer, cad);
229. }
230. }
231. 258.
232. strcat(buffer, "</txt><tool>"); 259. // CPU
260. if (!hasCPU) sprintf(cad, " | CPU: %3lld",total_cpu);
261. else sprintf(cad, " | CPU: %3.0lf%%", cpu_used * 100.0 / total_cpu);
262. strcat(buffer, cad);
233. 263.
234. if (networkAvailable && hasNet) 264. // RAM
235. { 265. FILE *meminfo = fopen("/proc/meminfo", "r");
236. sprintf(cad, " %s:\n %.2f MB received \n %.2f MB sent ", 266. if(meminfo) {
237. argv[1], recv_bytes/1000000.0, sent_bytes/1000000.0); 267. char line[256];
238. strcat(buffer, cad); 268. while(fgets(line, sizeof(line), meminfo)) {
269. if(!total_ram && sscanf(line, "MemTotal: %d kB", &total_ram));
270. if(sscanf(line, "Active: %d kB", &ram_used) == 1) {
271. sprintf(cad," | RAM: %5d MB",ram_used/1024);
272. break;
273. }
239. } 274. }
275. fclose(meminfo);
276. if(!ram_used) sprintf(cad, " RAM: %5d MB",total_ram);
277. strcat(buffer,cad);
278. }
240. 279.
241. if (reportCPU && hasCPU) 280. // DISK
242. { 281. FILE *diskstat = fopen("/proc/diskstats","rt");
243. if (networkAvailable && hasNet) strcat(buffer, "\n"); 282. disk_stats dss;
244. long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time; 283. if(diskstat) {
245. sprintf(cad, " CPU usage:\n %5.1f%% since boot ", 284. char line[512];
246. total_used_cpu * 100.0 / (total_used_cpu + idle_time)); 285. while(fgets(line,sizeof(line),diskstat)) {
247. strcat(buffer, cad); 286. const char *cad = dss.parse(line,seconds);
287. if(!cad) continue;
288. strcat(buffer, cad);
248. } 289. }
290. fclose(diskstat);
291. }
249. 292.
250. strcat(buffer, "</tool>"); 293. strcat(buffer, "</txt><tool>");
251. 294.
252. write(1, buffer, strlen(buffer)); 295.
296. // TOOLTIPS
297. bool useNet = networkAvailable && hasNet;
298. if (useNet) {
299. sprintf(cad, " %s:\n %.2f MB received \n %.2f MB sent ",
300. argv[1], recv_bytes/1024.0/1024, sent_bytes/1024.0/1024);
301. strcat(buffer, cad);
302. }
303.
304. if (hasCPU) {
305. if (useNet) strcat(buffer, "\n");
306. long long total_used_cpu = user_mode_time + user_mode_nice_time + system_mode_time;
307. sprintf(cad, " CPU usage:\n %5.1f%% since boot \n",
308. total_used_cpu * 100.0 / (total_used_cpu + idle_time));
309. strcat(buffer, cad);
310. }
311.
312. sprintf(cad, " RAM usage:\n %5.1f%% of %d MB",
313. ram_used * 100.0 / total_ram, total_ram / 1024 );
314. strcat(buffer, cad);
315.
316. strcat(buffer, "</tool>");
253. 317.
254. return 0; 318. write(1, buffer, strlen(buffer));
319.
320. return 0;
255.}321.}
original text
changed text
Recommended videos