Your message dated Mon, 20 Oct 2025 12:49:23 +0000
with message-id <[email protected]>
and subject line Bug#697367: fixed in tcpstat 1.5-9
has caused the Debian Bug report #697367,
regarding tcpstat hangs in capture mode when no packets arrive
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
697367: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=697367
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: tcpstat
Version: 1.5-7
Severity: normal
Tags: patch

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)

This bug is known and documented in the man page.
Packages based on upstream v1.5 code are affected.

Here is a patch against 1.5-7 that fixes it. Contacted upstream about
it, it is unclear if new versions of the package will be released, so
posting it here.

- main loop, fix untimely display in live capture mode:
      all: decoupled data logic and display logic,
      process.c: changed alarm handler to catch interval timeouts.
                 capture_seconds logic now on top of interval
                 logic.
- use setitimer() instead of ualarm(): not limited to 1s (linux)

Did a bit of testing, couldn't find anything it breaks from what i can
tell (under linux at least):

tcpstat works both in capture and file mode,
        -s now works in capture mode,
        intervals less and greater than 1s work in capture mode.
tcpprof and packetdump look fine also.

Cheers
--
Matthieu

diff -Nru tcpstat-1.5/configure.in tcpstat-1.5_fix/configure.in
--- tcpstat-1.5/configure.in	2013-01-04 14:12:58.000000000 +0100
+++ tcpstat-1.5_fix/configure.in	2013-01-04 14:01:07.000000000 +0100
@@ -102,7 +102,7 @@
 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 -Nru tcpstat-1.5/doc/tcpstat.1 tcpstat-1.5_fix/doc/tcpstat.1
--- tcpstat-1.5/doc/tcpstat.1	2013-01-04 14:12:58.000000000 +0100
+++ tcpstat-1.5_fix/doc/tcpstat.1	2013-01-04 14:01:01.000000000 +0100
@@ -345,11 +345,6 @@
 .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 -Nru tcpstat-1.5/include/config.h.in tcpstat-1.5_fix/include/config.h.in
--- tcpstat-1.5/include/config.h.in	2013-01-04 14:12:58.000000000 +0100
+++ tcpstat-1.5_fix/include/config.h.in	2013-01-04 14:01:07.000000000 +0100
@@ -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 -Nru tcpstat-1.5/include/tcpstat.h tcpstat-1.5_fix/include/tcpstat.h
--- tcpstat-1.5/include/tcpstat.h	2002-06-01 08:42:08.000000000 +0200
+++ tcpstat-1.5_fix/include/tcpstat.h	2013-01-04 14:01:01.000000000 +0100
@@ -234,8 +234,9 @@
 
 /* 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 -Nru tcpstat-1.5/lib/process.c tcpstat-1.5_fix/lib/process.c
--- tcpstat-1.5/lib/process.c	2002-06-01 08:42:09.000000000 +0200
+++ tcpstat-1.5_fix/lib/process.c	2013-01-04 14:01:07.000000000 +0100
@@ -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 @@
 	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 @@
  *   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 @@
 		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 @@
  *   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 @@
 	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 -Nru tcpstat-1.5/lib/utils.c tcpstat-1.5_fix/lib/utils.c
--- tcpstat-1.5/lib/utils.c	2002-01-02 22:05:55.000000000 +0100
+++ tcpstat-1.5_fix/lib/utils.c	2013-01-04 14:01:07.000000000 +0100
@@ -147,11 +147,18 @@
 }
 
 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 -Nru tcpstat-1.5/src/dump.c tcpstat-1.5_fix/src/dump.c
--- tcpstat-1.5/src/dump.c	2002-09-18 23:00:29.000000000 +0200
+++ tcpstat-1.5_fix/src/dump.c	2013-01-04 14:01:01.000000000 +0100
@@ -51,7 +51,7 @@
  */
 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 -Nru tcpstat-1.5/src/tcpprof.c tcpstat-1.5_fix/src/tcpprof.c
--- tcpstat-1.5/src/tcpprof.c	2002-01-19 05:31:37.000000000 +0100
+++ tcpstat-1.5_fix/src/tcpprof.c	2013-01-04 14:01:01.000000000 +0100
@@ -79,7 +79,7 @@
 	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 -Nru tcpstat-1.5/src/tcpstat.c tcpstat-1.5_fix/src/tcpstat.c
--- tcpstat-1.5/src/tcpstat.c	2002-07-27 02:42:05.000000000 +0200
+++ tcpstat-1.5_fix/src/tcpstat.c	2013-01-04 14:01:01.000000000 +0100
@@ -149,7 +149,7 @@
 	/* 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 @@
 	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 @@
 	    ts - sp->global.ts_bigbang > capture_seconds)
 		return;
 
-		/* After that, we need to see if there is an interval waiting
-		 * to be printed.
+	/* 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().
 		 */
-	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);
-		}
+	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 @@
 		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 @@
 	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 @@
 	stats.global.total_time += x;
 
 	do_the_printing(&stats, x, stats.ts_now);
+	}
 
 	switch (action) {
 		case ACTION_INTERVAL:
@@ -459,7 +496,8 @@
 				 * 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 @@
 		 * are capturing.
 		 */
 	if (capture_seconds > 0.0 && capture_seconds < interval)
-		interval = -1.0;
+		interval = capture_seconds;
 
 	if (filename == NULL) {
 			/* Default read from interface */

--- End Message ---
--- Begin Message ---
Source: tcpstat
Source-Version: 1.5-9
Done: Emmanuel Arias <[email protected]>

We believe that the bug you reported is fixed in the latest version of
tcpstat, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to [email protected],
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Emmanuel Arias <[email protected]> (supplier of updated tcpstat package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing [email protected])


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Fri, 10 Oct 2025 13:27:14 +0200
Source: tcpstat
Architecture: source
Version: 1.5-9
Distribution: unstable
Urgency: medium
Maintainer: Package Salvaging Team <[email protected]>
Changed-By: Emmanuel Arias <[email protected]>
Closes: 697367 1115741
Changes:
 tcpstat (1.5-9) unstable; urgency=medium
 .
   [ Emmanuel Arias ]
   * Packaging update
   * Set Vcs-Fields (routine-update)
   * Standards-Version: 4.7.2 (routine-update)
   * Update VCS-* links.
   * Set Salvaging Team as Maintainer. Set Chrysostomos Nanakos and
     me as Uploaders.
     Closes: #1115741
   * Reorder sequence of d/control fields by cme (routine-update)
   * Secure URI in copyright format (routine-update)
   * Use secure URI in Homepage field.
   * d/patches/0004-Fix-time-interval-in-capture-mode.patch: Add patch to hangs
     in capture mode when package doesn't arrieve (Closes: #697367).
   * d/salsa-ci.yml: Enable Salsa-CI.
 .
   [ Andreas Tille ]
   * watch file standard 5
Checksums-Sha1:
 49a17c4c6fd94961a32acd91f92ce952345441f3 1978 tcpstat_1.5-9.dsc
 0e3afdcb1f8b8f50047756501e49d63dcdc9919d 11956 tcpstat_1.5-9.debian.tar.xz
 f2f50f32daebe00d0fe6e85f0c88e070253ed6e6 6087 tcpstat_1.5-9_amd64.buildinfo
Checksums-Sha256:
 e84e46ce0c1a01ddb36eb9df2ee8c2de00c7e0df9b09e7c53946cc3767f5c41e 1978 
tcpstat_1.5-9.dsc
 b1a4e964109cea888926714eb4dfd7a0db0bc6e197572e3353ae48c1fe4d6ef1 11956 
tcpstat_1.5-9.debian.tar.xz
 112513a21185ca67423e3ca38a7c2de530b7be0c41f6601ee8f996ee9a4d0836 6087 
tcpstat_1.5-9_amd64.buildinfo
Files:
 8ff4244f0fa29585c9988b87d6a33405 1978 net optional tcpstat_1.5-9.dsc
 d9794f22e453463b03c84a8482faedbf 11956 net optional tcpstat_1.5-9.debian.tar.xz
 852057002a6427f6b46e1d94b0446a31 6087 net optional 
tcpstat_1.5-9_amd64.buildinfo

-----BEGIN PGP SIGNATURE-----

iQJFBAEBCgAvFiEE8fAHMgoDVUHwpmPKV4oElNHGRtEFAmjo9F8RHHRpbGxlQGRl
Ymlhbi5vcmcACgkQV4oElNHGRtG7Tw//Sy70ObfNtXd4FvfE7OqGExF29TzGVfFg
uX8EkGKy79hditvsw/ptRR8B9dMP5YFre3TBoEinyz2NCnyycgEsBtV6f6PiA3Cd
DJVTQvRiMkcM6VtkT/+E7MFsXgr2IT7Bm8iR964bH1Q7sidw65biEyJFQQK24VhQ
Lj+RdMLHDuOJbiey7cf9TOqY2TTAxEJviGSivLwidJorpya/RyxX8zifyW1lCamF
YsR/SH/Z3cNonGtKRDOEUpQOgaNLvUlVwxyAo/R2e5oQAm19rfM3BO0lCHKmPFbJ
lMC4itlRQQPDHKSxiggSXSJVDBTwXGX4uA0KuGnf0lkALEroE8GjTHVCd9KjwvTG
AfYrEbP+a+7Dt20G2GbCPtrtViEaPM0Ojan8tSZZHbNBRtBIQhUewYqZRxxJFISX
SrpYt6/mAW7PcekBa+jzFrtNfeXOHoFAhpuE5cy490zV6chukxn7OCeAGYRC2uOv
NpSfGSEmgUGy+2gmHQGzBHsPIpsPfouAyxbd2CUXmEao6LWceEdFkRZHzqY9jD80
Iw9qXeVJDkQLWeohVghA/hOICybYzqXx9r1V9Dj6JJCAfeROfqtCg/lGWg7o/QG8
FzctkZ9DVvYTesFHEp0VSAyPQy+oVPyt1IZdAtXIWp1AJ/rB9yR6105mAcSo4Zyd
R+rRGiY0VBM=
=Yt0u
-----END PGP SIGNATURE-----

Attachment: pgp3xgi0sHi68.pgp
Description: PGP signature


--- End Message ---

Reply via email to