capt_get_packet(): check for key press only every 20ms
[iptraf-ng.git] / src / pktsize.c
blob27384d269248f9e259a793d024b04b4be3ada8ee
1 /* For terms of usage/redistribution/modification see the LICENSE file */
2 /* For authors and contributors see the AUTHORS file */
4 /***
6 pktsize.c - the packet size breakdown facility
8 ***/
10 #include "iptraf-ng-compat.h"
12 #include "tui/winops.h"
14 #include "attrs.h"
15 #include "dirs.h"
16 #include "fltdefs.h"
17 #include "ifaces.h"
18 #include "packet.h"
19 #include "deskman.h"
20 #include "error.h"
21 #include "pktsize.h"
22 #include "options.h"
23 #include "timer.h"
24 #include "log.h"
25 #include "logvars.h"
26 #include "promisc.h"
27 #include "capt.h"
29 #define SIZES 20
31 struct psizetab {
32 WINDOW *win;
33 PANEL *panel;
34 WINDOW *borderwin;
35 PANEL *borderpanel;
37 unsigned long size_in[SIZES + 1]; /* +1 for oversized count */
38 unsigned long size_out[SIZES + 1];
39 unsigned int mtu;
40 unsigned int interval;
41 unsigned int maxsize_in;
42 unsigned int maxsize_out;
46 static void rotate_size_log(int s __unused)
48 rotate_flag = 1;
49 strcpy(target_logname, current_logfile);
50 signal(SIGUSR1, rotate_size_log);
53 static void write_size_log(struct psizetab *table, unsigned long nsecs,
54 char *ifname, FILE *logfile)
56 char atime[TIME_TARGET_MAX];
57 int i;
59 genatime(time(NULL), atime);
60 fprintf(logfile, "*** Packet Size Distribution, generated %s\n\n",
61 atime);
62 fprintf(logfile, "Interface: %s MTU: %u\n\n", ifname, table->mtu);
63 fprintf(logfile, "Packet Size (bytes)\tIn\t\tOut\n");
65 for (i = 0; i < SIZES; i++) {
66 fprintf(logfile, "%u to %u:\t\t%8lu\t%8lu\n",
67 table->interval * i + 1,
68 table->interval * (i + 1),
69 table->size_in[i],
70 table->size_out[i]);
72 fprintf(logfile, "\nRunning time: %lu seconds\n", nsecs);
73 fflush(logfile);
76 static void psizetab_init(struct psizetab *table, char *ifname)
78 table->borderwin = newwin(LINES - 2, COLS, 1, 0);
79 table->borderpanel = new_panel(table->borderwin);
81 wattrset(table->borderwin, BOXATTR);
82 tx_box(table->borderwin, ACS_VLINE, ACS_HLINE);
83 mvwprintw(table->borderwin, 0, 1, " Packet Distribution by Size for interface %s ", ifname);
85 table->win = newwin(LINES - 4, COLS - 2, 2, 1);
86 table->panel = new_panel(table->win);
88 tx_stdwinset(table->win);
89 wtimeout(table->win, -1);
90 wattrset(table->win, STDATTR);
91 tx_colorwin(table->win);
93 wattrset(table->win, BOXATTR);
94 mvwprintw(table->win, 1, 1, "Packet Size (bytes)");
95 mvwprintw(table->win, 1, 23, "In Out");
96 mvwprintw(table->win, 1, 42, "Packet Size (bytes)");
97 mvwprintw(table->win, 1, 64, "In Out");
98 wattrset(table->win, HIGHATTR);
100 move(LINES - 1, 1);
101 stdexitkeyhelp();
103 update_panels();
104 doupdate();
107 static void psizetab_destroy(struct psizetab *table)
109 del_panel(table->panel);
110 delwin(table->win);
112 del_panel(table->borderpanel);
113 delwin(table->borderwin);
115 update_panels();
116 doupdate();
119 static void sizes_init(struct psizetab *table, unsigned int mtu)
121 table->mtu = mtu;
123 unsigned int interval = mtu / SIZES;
125 table->interval = interval;
127 wattrset(table->win, STDATTR);
128 for(unsigned int i = 0; i < SIZES; i++) {
129 int row, column;
131 table->size_in[i] = 0UL; /* initialize counters */
132 table->size_out[i] = 0UL;
134 if (i < SIZES / 2) {
135 row = i + 2;
136 column = 1;
137 } else {
138 row = (i - 10) + 2;
139 column = 42;
141 mvwprintw(table->win, row, column, "%5u to %5u:",
142 interval * i + 1, interval * (i + 1));
145 table->size_in[SIZES] = 0UL; /* initialize oversized counters */
146 table->size_out[SIZES] = 0UL;
147 table->maxsize_in = 0UL; /* initialize maxsize counters */
148 table->maxsize_out = 0UL;
150 mvwprintw(table->win, 12, 47, "oversized:");
151 mvwprintw(table->win, 14, 1, "max packet size in (bytes):");
152 mvwprintw(table->win, 15, 1, "max packet size out (bytes):");
154 mvwprintw(table->win, 17, 1,
155 "Interface MTU is %u bytes, not counting the data-link header.",
156 table->mtu);
157 mvwprintw(table->win, 18, 1,
158 "Maximum packet size is the MTU plus the data-link header length, but can be");
159 mvwprintw(table->win, 19, 1,
160 " bigger due to various offloading techniques of the interface.");
161 mvwprintw(table->win, 20, 1,
162 "Packet size computations include data-link headers, if any.");
165 static void update_size_distrib(struct psizetab *table, struct pkt_hdr *pkt)
167 /* -1 is to keep interval boundary lengths within the proper brackets */
168 unsigned int i = (pkt->pkt_len - 1) / table->interval;
170 if (i > SIZES)
171 i = SIZES; /* last entry is for lengths > MTU */
173 if (pkt->from->sll_pkttype == PACKET_OUTGOING) {
174 table->size_out[i]++;
175 if (table->maxsize_out < pkt->pkt_len)
176 table->maxsize_out = pkt->pkt_len;
177 } else {
178 table->size_in[i]++;
179 if (table->maxsize_in < pkt->pkt_len)
180 table->maxsize_in = pkt->pkt_len;
184 static void print_size_distrib(struct psizetab *table)
186 wattrset(table->win, HIGHATTR);
187 for (unsigned int i = 0; i < SIZES + 1; i++) { /* include oversized */
188 if (i < 10)
189 wmove(table->win, i + 2, 17);
190 else
191 wmove(table->win, (i - 10) + 2, 58);
193 wprintw(table->win, "%8lu %8lu",
194 table->size_in[i], table->size_out[i]);
196 mvwprintw(table->win, 14, 33, "%5u", table->maxsize_in);
197 mvwprintw(table->win, 15, 33, "%5u", table->maxsize_out);
200 static void psize_process_key(int ch)
202 switch (ch) {
203 case 12:
204 case 'l':
205 case 'L':
206 tx_refresh_screen();
207 break;
208 case 'x':
209 case 'X':
210 case 'q':
211 case 'Q':
212 case 27:
213 case 24:
214 exitloop = 1;
218 static void psize_process_packet(struct psizetab *table, struct pkt_hdr *pkt)
220 int pkt_result = packet_process(pkt, NULL, NULL, NULL,
221 MATCH_OPPOSITE_USECONFIG, 0);
223 if (pkt_result == PACKET_OK)
224 update_size_distrib(table, pkt);
227 void packet_size_breakdown(char *ifname, time_t facilitytime)
229 int ch;
231 int logging = options.logging;
232 FILE *logfile = NULL;
234 struct psizetab table;
236 struct capt capt;
238 struct pkt_hdr pkt;
240 if (!dev_up(ifname)) {
241 err_iface_down();
242 return;
245 psizetab_init(&table, ifname);
247 LIST_HEAD(promisc);
248 if (options.promisc) {
249 promisc_init(&promisc, ifname);
250 promisc_set_list(&promisc);
253 if (capt_init(&capt, ifname) == -1) {
254 write_error("Unable to initialize packet capture interface");
255 goto err;
258 int mtu = dev_get_mtu(ifname);
259 if (mtu < 0) {
260 write_error("Unable to obtain interface MTU");
261 goto err_close;
264 sizes_init(&table, mtu);
266 print_size_distrib(&table);
267 update_panels();
268 doupdate();
270 if (logging) {
271 if (strcmp(current_logfile, "") == 0) {
272 snprintf(current_logfile, 80, "%s-%s.log", PKTSIZELOG,
273 ifname);
275 if (!daemonized)
276 input_logfile(current_logfile, &logging);
280 if (logging) {
281 opentlog(&logfile, current_logfile);
283 if (logfile == NULL)
284 logging = 0;
286 if (logging) {
287 signal(SIGUSR1, rotate_size_log);
289 rotate_flag = 0;
290 writelog(logging, logfile,
291 "******** Packet size distribution facility started ********");
294 packet_init(&pkt);
296 exitloop = 0;
298 struct timeval now;
299 gettimeofday(&now, NULL);
300 struct timeval last_time = now;
301 struct timeval last_update = now;
303 time_t starttime = now.tv_sec;
304 time_t endtime = INT_MAX;
305 if (facilitytime != 0)
306 endtime = now.tv_sec + facilitytime * 60;
308 time_t log_next = INT_MAX;
309 if (logging)
310 log_next = now.tv_sec + options.logspan;
312 while (!exitloop) {
313 gettimeofday(&now, NULL);
315 if (now.tv_sec > last_time.tv_sec) {
316 printelapsedtime(now.tv_sec - starttime, 1, table.borderwin);
318 print_packet_drops(capt_get_dropped(&capt), table.borderwin, 49);
320 if (logging && (now.tv_sec > log_next)) {
321 check_rotate_flag(&logfile);
322 write_size_log(&table, now.tv_sec - starttime,
323 ifname, logfile);
324 log_next = now.tv_sec + options.logspan;
327 if (now.tv_sec > endtime)
328 exitloop = 1;
330 last_time = now;
333 if (screen_update_needed(&now, &last_update)) {
334 print_size_distrib(&table);
336 update_panels();
337 doupdate();
339 last_update = now;
342 if (capt_get_packet(&capt, &pkt, &ch, table.win) == -1) {
343 write_error("Packet receive failed");
344 exitloop = 1;
345 break;
348 if (ch != ERR)
349 psize_process_key(ch);
351 if (pkt.pkt_len > 0) {
352 psize_process_packet(&table, &pkt);
353 capt_put_packet(&capt, &pkt);
357 packet_destroy(&pkt);
359 if (logging) {
360 signal(SIGUSR1, SIG_DFL);
361 write_size_log(&table, time(NULL) - starttime, ifname, logfile);
362 writelog(logging, logfile,
363 "******** Packet size distribution facility stopped ********");
364 fclose(logfile);
366 strcpy(current_logfile, "");
368 err_close:
369 capt_destroy(&capt);
370 err:
371 if (options.promisc) {
372 promisc_restore_list(&promisc);
373 promisc_destroy(&promisc);
376 psizetab_destroy(&table);