$NetBSD: patch-ab,v 1.4 2019/06/15 15:01:03 christos Exp $

1. handle SIGCLD portably
2. define a large enough value for SO_LINGER that does not fail
3. add a runtime option -U <seconds>

--- nttcp.c.orig	2000-12-18 05:16:54.000000000 -0500
+++ nttcp.c	2019-06-15 10:56:28.798775017 -0400
@@ -136,9 +136,9 @@
 #endif /* aix */ 
 
 /*====================================================================*/
-#if defined(FreeBSD)
+#ifndef SIGCLD
 #define	SIGCLD	SIGCHLD
-#endif /*FreeBSD*/
+#endif /*SIGCLD*/
 
 /*====================================================================*/
 #if defined(BSD42)
@@ -268,6 +268,7 @@
 \t-n#	number of source bufs written to network (default 2048)\n\
 \t-u	use UDP instead of TCP\n\
 \t-g#us	gap in micro seconds between UDP packets (default 0s)\n\
+\t-U#	run until a number of seconds have elapsed\n\
 \t-d	set SO_DEBUG in sockopt\n\
 \t-D	don't buffer TCP writes (sets TCP_NODELAY socket option)\n\
 \t-w#	set the send buffer space to #kilobytes, which is\n\
@@ -310,9 +311,15 @@
 	setitimer(ITIMER_REAL, &itval, Nil(struct itimerval))
 #define	Suspend(msec)	SetItVal(msec); pause()
 
+/*
+ * we use 32767 (9 hours) because this is the largest implementation-specific
+ * value that we can since on the BSD's the kernel linger value is
+ * unsigned short, on opensolaris is int, and on linux is unsigned long
+ * scaled by HZ.
+ */
 struct linger Ling = {
 	1,		/* option on */
-	1000000		/* linger time, for our control connection */
+	32767		/* linger time, for our control connection */
 };
 
 /* global variables needed by StartTimer, StopTimer */
@@ -346,6 +353,7 @@
     int FixedDataSize;		/* if>0: calc BufCnt/BufLen from this */
     int Window,	SndWin, RcvWin; /* TCP window sizes */
     int	Verbose;		/* ==1: more diagnostics */
+    int RunTime;		/* approximate runtime in seconds */
     char *MulticastChannel;	/* we send multicast traffic */
     short MulticastPort;	
     int GapLength;		/* Gap length between packets */
@@ -496,6 +504,13 @@
     SysCalls=0;
 }
 
+int CheckTimer() {
+    TimeVal now;
+
+    gettimeofday(&now, (struct timezone *)0);
+    return opt.RunTime < (now.tv_sec - time0.tv_sec);
+}
+
 void StopTimer(double *cput, double *realt) {
     /* delivers in cput:  the amount of cpu time in seconds
      *          in realt: the real time in seconds
@@ -878,6 +893,7 @@
     opt->Verbose=0;		/* ==1: more diagnostics */
     opt->GapLength=0;		/* no delay, send as fast as possible */
     opt->inetd= 0;		/* ==1: run in inetd mode */
+    opt->RunTime = 0;		/* run effectively forever (ie BufCnt is limiting factor) */
     opt->Service= GetService();	/* the service-port to listen to */
     opt->MulticastChannel= NULL;
     opt->MulticastPort= 0;
@@ -1013,6 +1029,10 @@
 #endif /*MULTICAST*/
 	    break;
 	  }
+	  case 'U':
+	    GetSizeValue(&argc, &argv, &opt->RunTime, 1000000000,
+	      "runtime");
+	    break;
 	  default: {
 	    strcpy(MsgBuf, "unknown option: ");
 	    strncat(MsgBuf, argv[0], sizeof(MsgBuf)-strlen(MsgBuf)-1);
@@ -1427,6 +1447,10 @@
 	    sprintf(OptBuf, "-g%d", opt.GapLength);
 	    StrVecAppend(RemOpt, OptBuf);
 	}
+	if (opt.RunTime > 0) {
+	    sprintf(OptBuf, "-U%d", opt.RunTime);
+	    StrVecAppend(RemOpt, OptBuf);
+	}
 	if (opt.MulticastChannel) {
 	    sprintf(OptBuf, "-m%s:%d",
 	      opt.MulticastChannel, opt.MulticastPort);
@@ -1781,9 +1805,17 @@
 	    else
 		Pattern(buf, opt.BufLen);
 	    StartTimer();
-	    while (n-- && Nwrite(fd, buf, opt.BufLen) == opt.BufLen) {
+	    while (Nwrite(fd, buf, opt.BufLen) == opt.BufLen) {
 		nBytes+= opt.BufLen;
 		nBuffer++;
+		if (opt.RunTime == 0) {
+		    if (--n == 0)
+			break;
+		} else {
+		    /* XXX: tune how often to check if timer has expired? */
+		    if ((nBuffer % 100 == 0) && CheckTimer())
+			break;
+		}
 	    }
 	    StopTimer(&cput, &realt);
 	    opt.GapLength= 0;
@@ -1797,9 +1829,17 @@
 	    nBytes= 0;
 	    nBuffer= 0;
 	    StartTimer();
-	    while (n-- && Nwrite(fd, buf, opt.BufLen) == opt.BufLen) {
+	    while (Nwrite(fd, buf, opt.BufLen) == opt.BufLen) {
 		nBytes+= opt.BufLen;
 		nBuffer++;
+		if (opt.RunTime == 0) {
+		    if (--n == 0)
+			break;
+		} else {
+		    /* XXX: tune how often to check if timer has expired? */
+		    if ((nBuffer % 100 == 0) && CheckTimer())
+			break;
+		}
 	    }
 	    StopTimer(&cput, &realt);
 	}
