File: 0004-Fix-time-interval-in-capture-mode.patch

package info (click to toggle)
tcpstat 1.5-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 732 kB
  • sloc: ansic: 2,327; sh: 439; makefile: 27
file content (452 lines) | stat: -rw-r--r-- 14,281 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
From: Emmanuel Arias <eamanu@debian.org>
Date: Fri, 19 Sep 2025 14:51:25 -0300
Subject: Fix time interval in capture mode

When running tcpstat in capture mode, output hangs while no packets
arrive. For example

  # tcpstat -i eth0 1

should print output every second, but instead hangs while there's no
network traffic. Missing output comes up all at once once a packet
arrives. (actually even when there is traffic the output timing is off,
but less obvious)

Author: lemonsqueeze <lemonsqueeze@gmx.com>
Bug-Debian:https://bugs.debian.org/697367
---
 configure.in        |  2 +-
 doc/tcpstat.1       |  5 ---
 include/config.h.in |  4 +--
 include/tcpstat.h   |  5 +--
 lib/process.c       | 69 +++++++++++++++++++++----------------
 lib/utils.c         | 15 +++++---
 src/dump.c          |  2 +-
 src/tcpprof.c       |  2 +-
 src/tcpstat.c       | 98 +++++++++++++++++++++++++++++++++++++----------------
 9 files changed, 127 insertions(+), 75 deletions(-)

diff --git a/configure.in b/configure.in
index 4d0c58c..c051772 100644
--- a/configure.in
+++ b/configure.in
@@ -101,7 +101,7 @@ AC_HEADER_TIME
 dnl ############################
 dnl Checks for library functions
 dnl ############################
-AC_CHECK_FUNCS(strtol strtoul ualarm perror inet_ntop)
+AC_CHECK_FUNCS(strtol strtoul setitimer perror inet_ntop)
 AC_CHECK_FUNCS(snprintf, , [
 echo "WARNING:  You don't seem to have snprintf() (Solaris 2.5.x?)"
 echo "          There may be a slight security problem without it."
diff --git a/doc/tcpstat.1 b/doc/tcpstat.1
index be60b1a..d0110ed 100644
--- a/doc/tcpstat.1
+++ b/doc/tcpstat.1
@@ -345,11 +345,6 @@ Cologne, Germany.
 .Pp
 Please send all bug reports to this address.
 .Sh BUGS
-Due to a bug in libpcap, tcpstat will hang indefinitely under Linux 
-when no packets arrive.  This is because the timeout in pcap_open_live()
-is ignored under Linux when the interface is idle, which causes pcap_dispatch()
-to never return.
-.Pp
 Not tested with link types other than Ethernet, PPP, and "None" types.  
 .Pp
 There may be problems reading non-IPv4 packets across platforms when
diff --git a/include/config.h.in b/include/config.h.in
index 67216e2..d9fb4ec 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -72,8 +72,8 @@
 /* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
 #undef HAVE_SYS_WAIT_H
 
-/* Define if you have the `ualarm' function. */
-#undef HAVE_UALARM
+/* Define if you have the `setitimer' function. */
+#undef HAVE_SETITIMER
 
 /* Define if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
diff --git a/include/tcpstat.h b/include/tcpstat.h
index 2ddf965..b43745c 100644
--- a/include/tcpstat.h
+++ b/include/tcpstat.h
@@ -234,8 +234,9 @@ typedef struct packet_data {
 
 /* process.c protos */
 int  get_dump_data(char *fname, char *filter, int flags,
-        Double capture_seconds, void (*hook)(packet_data *, void **),
-	void **args);
+		  Double interval, Double capture_seconds,
+		  void (*data_hook)(packet_data *, void **), void **args,
+		  void (*display_hook)(void **));
 
 /* print_packet.c protos */
 void print_packet(packet_data *p, int what_to_print);
diff --git a/lib/process.c b/lib/process.c
index 9eb7168..d297e81 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -30,16 +30,8 @@
 #include "tcpstat.h"
 #include "snoop.h"
 
-	/* Set alarm in 10 minute (600 seconds) steps
-	 * This is necessary, because ualarm() is usually limited:
-	 * FreeBSD, Solaris:	2^32/10^6 seconds (71m 35s)
-	 * Linux:	??
-	 */
-#define SECONDS_STEP	600.0
-
 packet_data	pdata;
 int		run;
-Double		seconds_left;
 
 struct	hook_and_sinker {
 	void 	(*hook)(packet_data *, void **);
@@ -48,10 +40,16 @@ struct	hook_and_sinker {
 	bpf_u_int32	linktype;
 };
 
-void process_catch_alarm(int a) {
-	seconds_left -= SECONDS_STEP;
-	if (seconds_left <= 0 || a == SIGINT) run = 0;
-	else my_alarm((seconds_left > SECONDS_STEP)? SECONDS_STEP : seconds_left);
+void sigint_handler(int a){
+    run = 0;
+}
+
+static pcap_t	*pd = 0;
+static int	interval_timeout = 0;
+
+void interval_timeout_handler(int a) {
+	interval_timeout = 1;
+	pcap_breakloop(pd);
 }
 
 #define MAGIC_SIZE	2
@@ -311,14 +309,14 @@ int get_snoop_data(char *fname, char *filter, int flags,
  *   calls a user function pointing to the data
  */
 int get_pcap_data(char *fname, char *filter, int flags,
-	Double capture_seconds, void (*hook)(packet_data *, void **),
-	void **args) {
-
-	pcap_t	*pd;
+		  Double interval, Double capture_seconds,
+		  void (*data_hook)(packet_data *, void **), void **args,
+		  void (*display_hook)(void **)) {
 	int	i;
 	char	ebuf[PCAP_ERRBUF_SIZE];
 	struct	bpf_program bpf_prog;
 	struct	hook_and_sinker	hs;
+	Double	seconds_left = capture_seconds;
 
 #define SNAPLEN	68	/* XXX: Doesn't belong here */
 	if (flags & GET_TCPD_DO_LIVE) {
@@ -350,24 +348,36 @@ int get_pcap_data(char *fname, char *filter, int flags,
 		fprintf(stderr, "pcap_setfilter(): %s\n", pcap_geterr(pd));
 		return -1;
 		}
-	hs.hook = hook;
+	hs.hook = data_hook;
 	hs.args = args;
 	hs.proc_flags = flags;
 	hs.linktype = (bpf_u_int32)pcap_datalink(pd);
 
 	run = 1;
-	seconds_left = capture_seconds;
 
 	/* only catch SIGINT when doing live reads, otherwise just exit */
 	if (flags & GET_TCPD_DO_LIVE)
-		(void)signal(SIGINT, process_catch_alarm);
-
-	if (capture_seconds > 0.0 && flags & GET_TCPD_DO_LIVE) {
-		(void)signal(SIGALRM, process_catch_alarm);
-		my_alarm((seconds_left > SECONDS_STEP)? SECONDS_STEP : seconds_left);
-		}
+		(void)signal(SIGINT, sigint_handler);
+	
+	if (flags & GET_TCPD_DO_LIVE && interval > 0.0) {
+	    (void)signal(SIGALRM, interval_timeout_handler);
+	    my_alarm(interval);
+	}
+	
 	while (run) {
 		i = pcap_dispatch(pd, -1, process_pcap, (u_char *)&hs);
+		if (interval_timeout)
+		{		    
+		    my_alarm(interval);
+		    interval_timeout = 0;
+		    if (display_hook)
+			display_hook(args);
+		    
+		    seconds_left -= interval;
+		    if (capture_seconds > 0.0 && seconds_left <= 0.0)
+			run = 0;
+		}
+
 		if (i == 0 && ! (flags & GET_TCPD_DO_LIVE)) run = 0;
 		if (i == -1) {
 			fprintf(stderr, "pcap_dispatch(): %s\n", pcap_geterr(pd) );
@@ -383,8 +393,9 @@ int get_pcap_data(char *fname, char *filter, int flags,
  *   calls a user function pointing to the data
  */
 int get_dump_data(char *fname, char *filter, int flags,
-	Double capture_seconds, void (*hook)(packet_data *, void **),
-	void **args) {
+		  Double interval, Double capture_seconds,
+		  void (*data_hook)(packet_data *, void **), void **args,
+		  void (*display_hook)(void **)) {
 	u_int df_type = 0;
 
 	df_type = PCAP_FILE_MAGIC;	/* Default to pcap format */
@@ -416,13 +427,13 @@ int get_dump_data(char *fname, char *filter, int flags,
 	switch(df_type) {
 		case PCAP_FILE_MAGIC:
 		case PCAP_FILE_MAGIC_RH:	/* Try RedHat format as well. */
-			return get_pcap_data(fname, filter, flags,
-				capture_seconds, hook, args);
+			return get_pcap_data(fname, filter, flags, interval,
+					     capture_seconds, data_hook, args, display_hook);
 			/* NOTREACHED */
 			break;
 		case SNOOP_FILE_MAGIC:
 			return get_snoop_data(fname, filter, flags,
-				capture_seconds, hook, args);
+				capture_seconds, data_hook, args);
 			/* NOTREACHED */
 			break;
 		default:
diff --git a/lib/utils.c b/lib/utils.c
index 7620c55..427c05d 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -147,11 +147,18 @@ char *my_safe_strcpy(char **dst, const char *src) {
 }
 
 void my_alarm(Double seconds) {
-#ifdef HAVE_UALARM
-	ualarm( (u_int) (seconds*1e6 + 0.5), 0);
+#ifdef HAVE_SETITIMER
+    struct itimerval it;
+    int s = seconds;
+    it.it_interval.tv_sec = 0;
+    it.it_interval.tv_usec = 0;
+    it.it_value.tv_sec = s;
+    it.it_value.tv_usec = (seconds - s) * 1e6;
+    setitimer(ITIMER_REAL, &it, 0);
 #else
-	alarm( (u_int) (seconds));
-#endif /* HAVE_UALARM */
+    /* drop microseconds part ... */   
+    alarm( (u_int) (seconds));
+#endif /* HAVE_SETITIMER */
 }
 
 #ifndef HAVE_INET_NTOP
diff --git a/src/dump.c b/src/dump.c
index 48abc00..8f8ddd4 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -51,7 +51,7 @@ void my_hook(packet_data *pd, void **args) {
  */
 void process_file(char *fname, u_int unused) {
         get_dump_data(fname, filterexpr, get_tcp_flags,
-		-1.0, my_hook, NULL);
+		      1.0, -1.0, my_hook, NULL, NULL);
 }
 
 int parse_show_types(char *in) {
diff --git a/src/tcpprof.c b/src/tcpprof.c
index 3d5bd39..7e7aced 100644
--- a/src/tcpprof.c
+++ b/src/tcpprof.c
@@ -79,7 +79,7 @@ void process_file(char *fname, u_int s_types, int flags, Double capture_seconds)
 	stats_initdb(s_types);
 
 	argv[0] = (void *) &s_types;
-	if (get_dump_data(fname, filterexpr, flags, capture_seconds, my_hook, argv) == 0)
+	if (get_dump_data(fname, filterexpr, flags, capture_seconds, capture_seconds, my_hook, argv, NULL) == 0)
 		show_results(s_types);
 
 	stats_closedb();
diff --git a/src/tcpstat.c b/src/tcpstat.c
index 6b86f7e..7d738c9 100644
--- a/src/tcpstat.c
+++ b/src/tcpstat.c
@@ -149,7 +149,7 @@ void show_interval(statistics *s, Double dt) {
 	/* Used in the PRINTVAL macro which follows */
 	char printval_str[BUF_SIZ];
 	int filedesc = 1;
-
+	
 	/* Handy macro for writing bytes to arbitrary file descriptors */
 #define PRINTVAL(x,y)	{			\
 	snprintf(printval_str, BUF_SIZ, (x),(y));	\
@@ -352,25 +352,31 @@ int do_the_printing(statistics *sp, Double elapsed, Double ts) {
 	return 0;
 }
 
+void
+check_init_stats(statistics *sp, double ts)
+{
+	if (sp->ts_interval_begin == 0.0) {
+			/* initialize stats if called for the first time */
+		reset_counters(sp);
+		sp->ts_interval_begin	= ts;
+		sp->global.ts_bigbang	= ts;
+		}
+}
+
+void snoop_file_display_logic(statistics *sp, double ts);
+
 /*
  * This fuction is called by pcap_loop (not really, but OK.)  It adds
  * a particular packet to the total statistical data.
  */
-void my_hook(packet_data *pd, void **args) {
+void data_hook(packet_data *pd, void **args) {
 	statistics	*sp;
-	Double		ts, elapsed;
+	Double		ts;
 
 	sp = (statistics *) args[0];
-
 	ts = 	(Double)pd->timestamp.tv_sec +
 		(Double)pd->timestamp.tv_usec/1.0e6;
-
-	if (sp->ts_interval_begin == 0.0) {
-			/* initialize stats if called for the first time */
-		reset_counters(sp);
-		sp->ts_interval_begin	= ts;
-		sp->global.ts_bigbang	= ts;
-		}
+	check_init_stats(sp, ts);
 
 		/* Before we add this packet to the statistics,
 		 * we need to check if we are actually done counting
@@ -381,21 +387,13 @@ void my_hook(packet_data *pd, void **args) {
 	    ts - sp->global.ts_bigbang > capture_seconds)
 		return;
 
-		/* After that, we need to see if there is an interval waiting
-		 * to be printed.
-		 */
-	elapsed = ts - sp->ts_interval_begin;
-	if ( (elapsed > interval && interval != -1.0) ||
-		(print_immediately && elapsed > 0.0) ) {
-
-		/* We got a packet past the boundry of the last interval,
-		 * so update stats, and print out the last interval that
-		 * has already expired.  There might be a packet handed to
-		 * this function at this point, but we can't include it in
-		 * the current statistic.
+	/* FIXME! get_pcap_data() should take care of this so we just
+	 *        provide it data_hook() and display_hook() and never
+	 *        have to invoke display stuff from within data_hook().
 		 */
-		do_the_printing(sp, elapsed, ts);
-		}
+	if (!(get_tcp_flags & GET_TCPD_DO_LIVE))
+	    snoop_file_display_logic(sp, ts);
+
 	sp->ts_now = ts;
 	sp->count.packets++;
 	sp->global.total_bytes += (Double)pd->packet_len;
@@ -420,13 +418,49 @@ void my_hook(packet_data *pd, void **args) {
 		sp->min_packetsize = pd->packet_len;
 }
 
+/* Display logic when reading from file, NOT for live captures.
+ * This should be done by get_pcap_data(), see comment above. */
+void snoop_file_display_logic(statistics *sp, double ts) {
+    double elapsed;
+    
+    /* After that, we need to see if there is an interval waiting
+     * to be printed.
+     */
+    elapsed = ts - sp->ts_interval_begin;
+    if ( (elapsed > interval && interval != -1.0) ||
+	 (print_immediately && elapsed > 0.0) ) {
+	
+	/* We got a packet past the boundry of the last interval,
+	 * so update stats, and print out the last interval that
+	 * has already expired.  There might be a packet handed to
+	 * this function at this point, but we can't include it in
+	 * the current statistic.
+	 */
+	do_the_printing(sp, elapsed, ts);
+    }
+}
+
+void display_hook(void **args) {
+    statistics	*sp;
+    Double	ts;
+    struct timeval   tv;
+
+    sp = (statistics *) args[0];
+    gettimeofday(&tv, NULL);
+    ts = (Double)tv.tv_sec +
+	 (Double)tv.tv_usec/1.0e6;
+    check_init_stats(sp, ts);
+
+    do_the_printing(sp, 0.0, ts);
+}
+
 /*
  * process_file() gets the data, and then displays the statistics
  */
 void process_file(char *fname, u_int unused) {
 	void		*argv[2];
 	statistics	stats;
-	Double		x;
+	Double		x = 0.0;
 
 	signal(SIGUSR1, catch_signal);
 
@@ -441,10 +475,12 @@ void process_file(char *fname, u_int unused) {
 	argv[0] = (void *) &stats;
 
 		/* Main Loop */
-        if (get_dump_data(fname, filterexpr, get_tcp_flags,
-		    capture_seconds, my_hook, argv))
+        if (get_dump_data(fname, filterexpr, get_tcp_flags, interval, 
+			  capture_seconds, data_hook, argv, display_hook))
 		return;
 
+	if (!(get_tcp_flags & GET_TCPD_DO_LIVE))
+	{
 	/* The last "interval" still needs to be computed.
 	 * Most of the work has been done.  Now do...
 	 */
@@ -452,6 +488,7 @@ void process_file(char *fname, u_int unused) {
 	stats.global.total_time += x;
 
 	do_the_printing(&stats, x, stats.ts_now);
+	}
 
 	switch (action) {
 		case ACTION_INTERVAL:
@@ -459,7 +496,8 @@ void process_file(char *fname, u_int unused) {
 				 * padding.  This is only useful when
 				 * reading data from a file.
 				 */
-			if (capture_seconds > 0.0) {
+			if (!(get_tcp_flags & GET_TCPD_DO_LIVE)&&
+			    capture_seconds > 0.0) {
 				while (stats.ts_now + x - stats.global.ts_bigbang < capture_seconds) {
 					do_the_printing(&stats, x, stats.ts_now);
 					stats.global.total_time += x;
@@ -623,7 +661,7 @@ int main(int argc, char **argv) {
 		 * are capturing.
 		 */
 	if (capture_seconds > 0.0 && capture_seconds < interval)
-		interval = -1.0;
+		interval = capture_seconds;
 
 	if (filename == NULL) {
 			/* Default read from interface */