diff -ruN iperf-2.0.14a-20201204/include/Locale.h iperf-2.0.14a-20201211/include/Locale.h --- iperf-2.0.14a-20201204/include/Locale.h 2020-12-02 12:40:54.000000000 +0800 +++ iperf-2.0.14a-20201211/include/Locale.h 2020-12-12 04:46:16.000000000 +0800 @@ -352,6 +352,13 @@ extern const char warn_compat_and_peer_exchange[]; extern const char warn_seqno_wrap[]; + +extern const char warn_start_before_now[]; + +extern const char error_starttime_exceeds[]; + +extern const char error_delaytime_exceeds[]; + #ifdef __cplusplus } /* end extern "C" */ #endif diff -ruN iperf-2.0.14a-20201204/include/Reporter.h iperf-2.0.14a-20201211/include/Reporter.h --- iperf-2.0.14a-20201204/include/Reporter.h 2020-12-02 11:41:03.000000000 +0800 +++ iperf-2.0.14a-20201211/include/Reporter.h 2020-12-12 08:54:31.000000000 +0800 @@ -241,7 +241,7 @@ struct ConnectionInfo { struct ReportCommon *common; double connecttime; - double txholdbacktime; + struct timeval txholdbacktime; struct timeval epochStartTime; int winsize; char peerversion[PEERVERBUFSIZE]; diff -ruN iperf-2.0.14a-20201204/include/Settings.hpp iperf-2.0.14a-20201211/include/Settings.hpp --- iperf-2.0.14a-20201204/include/Settings.hpp 2020-12-01 02:53:55.000000000 +0800 +++ iperf-2.0.14a-20201211/include/Settings.hpp 2020-12-12 05:43:22.000000000 +0800 @@ -88,7 +88,7 @@ #define MAXDIFFTXSTART 3600 // maximum difference in seconds to bound --txdelay-time, // if this is too large and w/o keep-alives the connect may drop -#define MAXDIFFTXDELAY 60 +#define MAXDIFFTXDELAY 3600 // maximum inter packet gap (or write delay) for UDP packets #define MAXIPGSECS 60 #define CSVPEERLIMIT ((REPORT_ADDRLEN * 2) + 40) diff -ruN iperf-2.0.14a-20201204/include/version.h iperf-2.0.14a-20201211/include/version.h --- iperf-2.0.14a-20201204/include/version.h 2020-12-05 06:51:09.000000000 +0800 +++ iperf-2.0.14a-20201211/include/version.h 2020-12-12 14:51:05.000000000 +0800 @@ -1,4 +1,4 @@ #define IPERF_VERSION "2.0.14a" -#define IPERF_VERSION_DATE "4 December 2020" +#define IPERF_VERSION_DATE "11 Dec 2020" #define IPERF_VERSION_MAJORHEX 0x00020000 #define IPERF_VERSION_MINORHEX 0x000E0000 diff -ruN iperf-2.0.14a-20201204/man/iperf.1 iperf-2.0.14a-20201211/man/iperf.1 --- iperf-2.0.14a-20201204/man/iperf.1 2020-12-01 02:53:55.000000000 +0800 +++ iperf-2.0.14a-20201211/man/iperf.1 2020-12-10 05:31:31.000000000 +0800 @@ -134,9 +134,9 @@ Enable IPv6 reception by setting the domain and socket to AF_INET6 (Can receive on both IPv4 and IPv6) .SH "CLIENT SPECIFIC OPTIONS" .TP -.BR -b ", " --bandwidth " \fIn\fR[kmgKMG] | \fIn\fRpps" +.BR -b ", " --bandwidth " \fIn\fR[kmgKMG][,\fIn\fR[kmgKMG]] | \fIn\fR\fR[kmgKMG]pps" set target bandwidth to \fIn\fR bits/sec (default 1 Mbit/sec) or -\fIn\fR packets per sec. This may be used with TCP or UDP. For variable loads use format mean,standard deviation +\fIn\fR packets per sec. This may be used with TCP or UDP. Optionally, for variable loads, use format of mean,standard deviation .TP .BR -c ", " --client " \fI\fIhost\fR | \fIhost\fR%\fIdevice\fR" run in client mode, connecting to \fIhost\fR where the optional %dev will SO_BINDTODEVICE that output interface (requires root and see NOTES) diff -ruN iperf-2.0.14a-20201204/src/Client.cpp iperf-2.0.14a-20201211/src/Client.cpp --- iperf-2.0.14a-20201204/src/Client.cpp 2020-12-04 14:03:02.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Client.cpp 2020-12-12 10:46:34.000000000 +0800 @@ -256,12 +256,12 @@ // o Second is a holdback, a relative amount of seconds between the connect and data xfers // check for an epoch based start time if (!isServerReverse(mSettings)) { + reportstruct->packetLen = SendFirstPayload(); if (isTxStartTime(mSettings)) { clock_usleep_abstime(&mSettings->txstart_epoch); } else if (isTxHoldback(mSettings)) { TxDelay(); } - reportstruct->packetLen = SendFirstPayload(); } else { reportstruct->packetLen = 0; } @@ -585,8 +585,6 @@ reportstruct->packetTime.tv_usec = now.getUsecs(); while (InProgress() && !fatalwrite_err) { // Add tokens per the loop time - // clock_gettime is much cheaper than gettimeofday() so - // use it if possible. time2.setnow(); if (isVaryLoad(mSettings)) { static Timestamp time3; @@ -915,6 +913,10 @@ } } else { bytecnt -= currLen; + if (!bytecnt) + reportstruct->transit_ready = 1; + else + reportstruct->transit_ready = 0; // adjust bytecnt so last packet of burst is greater or equal to min packet if ((bytecnt > 0) && (bytecnt < udp_payload_minimum)) { bytecnt = udp_payload_minimum; diff -ruN iperf-2.0.14a-20201204/src/Locale.c iperf-2.0.14a-20201211/src/Locale.c --- iperf-2.0.14a-20201204/src/Locale.c 2020-12-05 06:51:09.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Locale.c 2020-12-12 14:38:04.000000000 +0800 @@ -277,11 +277,8 @@ const char report_sumcnt_bw_header[] = "[SUM-cnt] Interval Transfer Bandwidth\n"; -const char client_report_epoch_start[] = -"[%3d] Client traffic to start at %s (%ld.%ld in epoch/unix format)\n"; - const char client_report_epoch_start_current[] = -"[%3d] Client traffic to start at %s (%ld.%ld) current time %s\n"; +"[%3d] Client traffic to start in %d seconds at %s current time is %s\n"; const char client_write_size[] = "Write buffer size"; @@ -372,7 +369,7 @@ "%s" IPERFTimeFrmt " sec %ss %ss/sec %d/%d %8.0f pps\n"; const char report_bw_pps_enhanced_isoch_header[] = -"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err PPS frames:tx/slips\n"; +"[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Write/Err PPS isoch:tx/miss/slip\n"; const char report_bw_pps_enhanced_isoch_format[] = "%s" IPERFTimeFrmt " sec %ss %ss/sec %d/%d %8.0f pps %3d/%d/%d\n"; @@ -402,11 +399,11 @@ const char report_bw_jitter_loss_enhanced_isoch_header[] = "[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \ - Latency avg/min/max/stdev PPS NetPwr Frames/Lost\n"; + Latency avg/min/max/stdev PPS NetPwr Isoch:rx/lost\n"; const char report_bw_jitter_loss_enhanced_isoch_triptime_header[] = "[ ID] Interval" IPERFTimeSpace "Transfer Bandwidth Jitter Lost/Total \ - Latency avg/min/max/stdev PPS Rx/inP NetPwr Frames/Lost\n"; + Latency avg/min/max/stdev PPS Rx/inP NetPwr Isoch:rx/lost\n"; const char report_bw_jitter_loss_enhanced_isoch_format[] = "%s" IPERFTimeFrmt " sec %ss %ss/sec %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %s %s %3d/%d\n"; @@ -433,7 +430,7 @@ "%s" IPERFFTimeFrmt "(%0.4f) sec %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) %.3f/%.3f/%.3f/%.3f ms %.0f pps %2.0f pkts %s\n"; const char report_frame_jitter_loss_suppress_enhanced_format[] = -"%s" IPERFTimeFrmt "(%0.4f) sec %ld %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps\n"; +"%s" IPERFTimeFrmt "(%0.4f) sec %" PRIdMAX " %ss %ss/sec %" PRIdMAX " %6.3f ms %" PRIdMAX "/%" PRIdMAX " (%.2g%%) -/-/-/- ms %.0f pps\n"; const char report_frame_tcp_enhanced_header[] = "[ ID] Interval(f-transit)" IPERFFTimeSpace "Transfer Bandwidth FrameID\n"; @@ -604,6 +601,15 @@ const char warn_compat_and_peer_exchange[] = "WARNING: Options of '-C' '--compatibility' AND '-X' '--peerdetect' are mutually exclusive, --peerdetect ignored\n"; + +const char warn_start_before_now[] = +"[%3d] WARNING: --txstart-time (%" PRIdMAX ".%" PRIdMAX ") %s is before now %s\n"; + +const char error_starttime_exceeds[] = +"ERROR: --txstart-time (%" PRIdMAX ".%" PRIdMAX ") %s exceeds max scheduled delay of %d secs\n"; + +const char error_delaytime_exceeds[] = +"ERROR: --txdelay-time of %d seconds is more than the supported delay of %d seconds\n"; #ifdef __cplusplus } /* end extern "C" */ diff -ruN iperf-2.0.14a-20201204/src/ReportOutputs.c iperf-2.0.14a-20201211/src/ReportOutputs.c --- iperf-2.0.14a-20201204/src/ReportOutputs.c 2020-12-03 03:06:18.000000000 +0800 +++ iperf-2.0.14a-20201211/src/ReportOutputs.c 2020-12-12 14:47:47.000000000 +0800 @@ -548,7 +548,7 @@ (stats->cntIPG / stats->IPGsum), llaw_buf, netpower_buf, - stats->isochstats.framecnt, stats->isochstats.framelostcnt); + stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed); } } if (stats->latency_histogram) { @@ -586,8 +586,7 @@ stats->sock_callstats.write.WriteCnt, stats->sock_callstats.write.WriteErr, (stats->cntIPG ? (stats->cntIPG / stats->IPGsum) : 0.0), - stats->isochstats.framecnt, - stats->isochstats.framelostcnt, stats->isochstats.slipcnt); + stats->isochstats.cntFrames, stats->isochstats.cntFramesMissed, stats->isochstats.cntSlips); } // Sum reports @@ -1095,9 +1094,6 @@ b += strlen(b); } } - if (report->txholdbacktime > 0) { - snprintf(b, SNBUFFERSIZE-strlen(b), " (ht=%4.2f s)", report->txholdbacktime);; - } if (local->sa_family == AF_INET) { inet_ntop(AF_INET, &((struct sockaddr_in*)local)->sin_addr, local_addr, REPORT_ADDRLEN); } @@ -1141,26 +1137,45 @@ outbuffer); } #endif - if ((report->epochStartTime.tv_sec) && (report->common->ThreadMode == kMode_Client) && !isServerReverse(report->common)) { - struct tm ts; - char start_timebuf[80]; + if ((report->common->ThreadMode == kMode_Client) && !isServerReverse(report->common)) { + if (isTxHoldback(report->common) || isTxStartTime(report->common)) { + struct tm ts; + char start_timebuf[80]; + struct timeval now; + struct timeval start; #ifdef HAVE_CLOCK_GETTIME - // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz" - ts = *localtime(&report->epochStartTime.tv_sec); - strftime(start_timebuf, sizeof(start_timebuf), "%Y-%m-%d %H:%M:%S", &ts); - struct timespec t1; - clock_gettime(CLOCK_REALTIME, &t1); - ts = *localtime(&t1.tv_sec); - char now_timebuf[80]; - strftime(now_timebuf, sizeof(now_timebuf), "%Y-%m-%d %H:%M:%S (%Z)", &ts); - printf(client_report_epoch_start_current, report->common->transferID, start_timebuf, report->epochStartTime.tv_sec, report->epochStartTime.tv_usec, now_timebuf); + struct timespec t1; + clock_gettime(CLOCK_REALTIME, &t1); + now.tv_sec = t1.tv_sec; + now.tv_usec = t1.tv_nsec / 1000; #else - // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz" - ts = *localtime(&report->epochStartTime.tv_sec); - strftime(start_timebuf, sizeof(start_timebuf), "%Y-%m-%d %H:%M:%S (%Z)", &ts); - printf(client_report_epoch_start, report->common->transferID, start_timebuf, report->epochStartTime.tv_sec, report->epochStartTime.tv_usec); + gettimeofday(&now, NULL); #endif - fflush(stdout); + ts = *localtime(&now.tv_sec); + char now_timebuf[80]; + strftime(now_timebuf, sizeof(now_timebuf), "%Y-%m-%d %H:%M:%S (%Z)", &ts); + // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz" + int seconds_from_now; + if (isTxHoldback(report->common)) { + seconds_from_now = report->txholdbacktime.tv_sec; + if (report->txholdbacktime.tv_usec > 0) + seconds_from_now++; + start.tv_sec = now.tv_sec + seconds_from_now; + ts = *localtime(&start.tv_sec); + } else { + ts = *localtime(&report->epochStartTime.tv_sec); + seconds_from_now = ceil(TimeDifference(report->epochStartTime, now)); + } + strftime(start_timebuf, sizeof(start_timebuf), "%Y-%m-%d %H:%M:%S", &ts); + if (seconds_from_now > 0) { + printf(client_report_epoch_start_current, report->common->transferID, seconds_from_now, \ + start_timebuf, now_timebuf); + } else { + printf(warn_start_before_now, report->common->transferID, report->epochStartTime.tv_sec, \ + report->epochStartTime.tv_usec, start_timebuf, now_timebuf); + } + fflush(stdout); + } } } diff -ruN iperf-2.0.14a-20201204/src/Reporter.c iperf-2.0.14a-20201211/src/Reporter.c --- iperf-2.0.14a-20201204/src/Reporter.c 2020-12-04 13:56:43.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Reporter.c 2020-12-11 07:32:30.000000000 +0800 @@ -1020,6 +1020,11 @@ stats->cntError = 0; stats->cntDatagrams = stats->PacketID - stats->total.Datagrams.prev; stats->cntIPG = stats->total.IPG.current - stats->total.IPG.prev; + if (isIsochronous(stats->common)) { + stats->isochstats.cntFrames = stats->isochstats.framecnt.current - stats->isochstats.framecnt.prev; + stats->isochstats.cntFramesMissed = stats->isochstats.framelostcnt.current - stats->isochstats.framelostcnt.prev; + stats->isochstats.cntSlips = stats->isochstats.slipcnt.current - stats->isochstats.slipcnt.prev; + } if (stats->total.Datagrams.current == 1) stats->jitter = 0; if (sumstats) { @@ -1081,6 +1086,11 @@ stats->transit.meanTransit = stats->transit.totmeanTransit; stats->transit.m2Transit = stats->transit.totm2Transit; stats->transit.vdTransit = stats->transit.totvdTransit; + if (isIsochronous(stats->common)) { + stats->isochstats.cntFrames = stats->isochstats.framecnt.current; + stats->isochstats.cntFramesMissed = stats->isochstats.framelostcnt.current; + stats->isochstats.cntSlips = stats->isochstats.slipcnt.current; + } if (stats->latency_histogram) { stats->latency_histogram->final = 1; } @@ -1159,6 +1169,11 @@ stats->cntBytes = stats->total.Bytes.current - stats->total.Bytes.prev; stats->cntDatagrams = stats->total.Datagrams.current - stats->total.Datagrams.prev; stats->cntIPG = stats->total.IPG.current - stats->total.IPG.prev; + if (isIsochronous(stats->common)) { + stats->isochstats.cntFrames = stats->isochstats.framecnt.current - stats->isochstats.framecnt.prev; + stats->isochstats.cntFramesMissed = stats->isochstats.framelostcnt.current - stats->isochstats.framelostcnt.prev; + stats->isochstats.cntSlips = stats->isochstats.slipcnt.current - stats->isochstats.slipcnt.prev; + } if (sumstats) { sumstats->total.Bytes.current += stats->cntBytes; sumstats->sock_callstats.write.WriteErr += stats->sock_callstats.write.WriteErr; @@ -1186,6 +1201,11 @@ stats->cntIPG = stats->total.IPG.current; stats->cntDatagrams = stats->PacketID; stats->IPGsum = TimeDifference(stats->ts.packetTime, stats->ts.startTime); + if (isIsochronous(stats->common)) { + stats->isochstats.cntFrames = stats->isochstats.framecnt.current; + stats->isochstats.cntFramesMissed = stats->isochstats.framelostcnt.current; + stats->isochstats.cntSlips = stats->isochstats.slipcnt.current; + } } else { if (stats->ts.iEnd > 0) { stats->cntIPG = (stats->total.IPG.current - stats->total.IPG.prev); diff -ruN iperf-2.0.14a-20201204/src/Reports.c iperf-2.0.14a-20201211/src/Reports.c --- iperf-2.0.14a-20201204/src/Reports.c 2020-12-02 05:31:53.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Reports.c 2020-12-12 14:39:09.000000000 +0800 @@ -315,6 +315,7 @@ creport->connect_times.vd = 0; creport->connect_times.m2 = 0; creport->connect_times.mean = 0; + creport->txholdbacktime = thread->txholdback_timer; return creport; } @@ -663,6 +664,7 @@ (inSettings->mThreadMode != kMode_Client ? 0 : 1) ); } creport->common->winsize_requested = inSettings->mTCPWin; + creport->txholdbacktime = inSettings->txholdback_timer; #ifdef HAVE_THREAD_DEBUG thread_debug("Init connection report %p", reporthdr); #endif diff -ruN iperf-2.0.14a-20201204/src/Server.cpp iperf-2.0.14a-20201211/src/Server.cpp --- iperf-2.0.14a-20201204/src/Server.cpp 2020-12-01 13:40:12.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Server.cpp 2020-12-09 13:44:01.000000000 +0800 @@ -692,6 +692,9 @@ reportstruct->burstsize = ntohl(udp_pkt->isoch.burstsize); reportstruct->burstperiod = ntohl(udp_pkt->isoch.burstperiod); reportstruct->remaining = ntohl(udp_pkt->isoch.remaining); + if ((reportstruct->remaining == rxlen) && ((reportstruct->frameID - reportstruct->prevframeID) == 1)) { + reportstruct->transit_ready = 1; + } } } diff -ruN iperf-2.0.14a-20201204/src/Settings.cpp iperf-2.0.14a-20201211/src/Settings.cpp --- iperf-2.0.14a-20201204/src/Settings.cpp 2020-12-01 03:02:49.000000000 +0800 +++ iperf-2.0.14a-20201211/src/Settings.cpp 2020-12-12 08:59:10.000000000 +0800 @@ -1049,19 +1049,34 @@ fprintf(stderr, "ERROR: option of --sum-only requires -P greater than 1\n"); bail = true; } - if (isTxStartTime(mExtSettings)) { + if (isTxHoldback(mExtSettings) && isTxStartTime(mExtSettings)) { + fprintf(stdout,"ERROR: options of --txstart-time and --txdelay-time are mutually exclusive\n"); + bail = true; + } else if (isTxStartTime(mExtSettings) || isTxHoldback(mExtSettings)) { Timestamp now; long nowsecs = now.getSecs(); - if (((nowsecs - mExtSettings->txstart_epoch.tv_sec) > 0) \ - || ((nowsecs == mExtSettings->txstart_epoch.tv_sec) && (now.getUsecs() > mExtSettings->txstart_epoch.tv_usec))) { - fprintf(stderr, "WARNING: --txstart-time of before now ignored\n"); - unsetTxStartTime(mExtSettings); + // fill out the formats in the event they are needed per an time error + char start_timebuf[80]; + struct tm ts = *localtime(&mExtSettings->txstart_epoch.tv_sec); + strftime(start_timebuf, sizeof(start_timebuf), "(%Y-%m-%d %H:%M:%S %Z)", &ts); + char now_timebuf[80]; + ts = *localtime(&nowsecs); + strftime(now_timebuf, sizeof(now_timebuf), "%Y-%m-%d %H:%M:%S %Z", &ts); + if (isTxStartTime(mExtSettings)) { + if (mExtSettings->txstart_epoch.tv_sec < 0) { + fprintf(stderr, "ERROR: --txstart-time must be a postive value\n"); + unsetTxStartTime(mExtSettings); + bail = true; + } else if ((mExtSettings->txstart_epoch.tv_sec - now.getSecs()) > MAXDIFFTXSTART) { + printf(error_starttime_exceeds, mExtSettings->txstart_epoch.tv_sec, mExtSettings->txstart_epoch.tv_usec, \ + start_timebuf, MAXDIFFTXSTART); + bail = true; + } + } else if (mExtSettings->txholdback_timer.tv_sec > MAXDIFFTXDELAY) { + printf(error_delaytime_exceeds, mExtSettings->txholdback_timer.tv_sec, MAXDIFFTXDELAY); + bail = true; } } - if (isTxHoldback(mExtSettings) && isTxStartTime(mExtSettings)) { - fprintf(stdout,"ERROR: options of --txstart-time and --txdelay-time are mutually exclusive\n"); - bail = true; - } if (isUDP(mExtSettings)) { if (isPeerVerDetect(mExtSettings)) { fprintf(stderr, "ERROR: option of -X or --peer-detect not supported with -u UDP\n"); @@ -1116,23 +1131,9 @@ fprintf(stderr, "ERROR: option --no-udp-fin requires -u UDP\n"); bail = true; } - if (isTxHoldback(mExtSettings)) { - Timestamp now; - if (mExtSettings->txholdback_timer.tv_sec > MAXDIFFTXDELAY) { - fprintf(stdout,"ERROR: Fail because --txdelay-time is not within %d seconds of now\n", MAXDIFFTXDELAY); - bail = true; - } - if (isConnectOnly(mExtSettings)) { - fprintf(stdout,"ERROR: Fail because --txdelay-time and --connect-only cannot be applied together\n"); - bail = true; ; - } - } - } - if (isTxStartTime(mExtSettings)) { - Timestamp now; - if ((mExtSettings->txstart_epoch.tv_sec- now.getSecs()) > MAXDIFFTXSTART) { - fprintf(stdout,"ERROR: Fail because --txstart-time is not within %d seconds of now\n", MAXDIFFTXSTART); - bail = true; + if (isTxHoldback(mExtSettings) && isConnectOnly(mExtSettings)) { + fprintf(stdout,"ERROR: Fail because --txdelay-time and --connect-only cannot be applied together\n"); + bail = true; ; } } if (isRxHistogram(mExtSettings)) {