aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-08-18 16:24:55 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-08-18 16:24:55 +0000
commit6505f976c2ed431621aad97eae297255bcb5f662 (patch)
tree721420473c607e66455dc8270e13734482d32de5
parent7e04f70fe377dec2875e73fdf297a659d37b0a52 (diff)
parentc5cac7b0eb71ebeb6595f85104ae3a5b24356dbe (diff)
downloadiperf3-6505f976c2ed431621aad97eae297255bcb5f662.tar.gz
Upgrade iperf3 to 3.9 am: c5cac7b0eb
Original change: https://android-review.googlesource.com/c/platform/external/iperf3/+/1402114 Change-Id: I64e3d07ca9ebcf8949a256b17cd3a5c08ae4ebfe
-rw-r--r--METADATA6
-rw-r--r--RELNOTES.md36
-rw-r--r--aclocal.m413
-rw-r--r--config/iperf_config_static_bin.m45
-rwxr-xr-xconfigure116
-rw-r--r--configure.ac8
-rw-r--r--docs/conf.py4
-rw-r--r--docs/faq.rst67
-rw-r--r--docs/news.rst20
-rw-r--r--src/iperf.h18
-rw-r--r--src/iperf3.133
-rw-r--r--src/iperf_api.c249
-rw-r--r--src/iperf_api.h35
-rw-r--r--src/iperf_auth.c4
-rw-r--r--src/iperf_client_api.c27
-rw-r--r--src/iperf_config.h.in2
-rw-r--r--src/iperf_error.c44
-rw-r--r--src/iperf_locale.c10
-rw-r--r--src/iperf_sctp.c28
-rw-r--r--src/iperf_server_api.c32
-rw-r--r--src/iperf_udp.c8
-rw-r--r--src/iperf_util.c8
-rw-r--r--src/iperf_util.h2
-rw-r--r--src/net.c4
-rw-r--r--src/net.h4
-rwxr-xr-xtest_commands.sh8
26 files changed, 617 insertions, 174 deletions
diff --git a/METADATA b/METADATA
index 51a13c1..8199d28 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@ third_party {
type: GIT
value: "https://github.com/esnet/iperf.git"
}
- version: "3.8"
+ version: "3.9"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 7
- day: 10
+ month: 8
+ day: 17
}
}
diff --git a/RELNOTES.md b/RELNOTES.md
index ae52d83..21f0801 100644
--- a/RELNOTES.md
+++ b/RELNOTES.md
@@ -1,6 +1,40 @@
iperf3 Release Notes
====================
+iperf 3.9 2020-08-17
+--------------------
+
+* Notable user-visible changes
+
+ * A --timestamps flag has been added, which prepends a timestamp to
+ each output line. An optional argument to this flag, which is a
+ format specification to strftime(3), allows for custom timestamp
+ formats (#909, #1028).
+
+ * A --server-bitrate-limit flag has been added as a server-side
+ command-line argument. It allows a server to enforce a maximum
+ throughput rate; client connections that specify a higher bitrate
+ or exceed this bitrate during a test will be terminated. The
+ bitrate is expressed in bits per second, with an optional trailing
+ slash and integer count that specifies an averaging interval over
+ which to enforce the limit (#999).
+
+ * A bug that caused increased CPU usage with the --bidir option has
+ been fixed (#1011).
+
+* Notable developer-visible changes
+
+ * Fixed various minor memory leaks (#1023).
+
+iperf 3.8.1 2020-06-10
+----------------------
+
+* Notable user-visible changes
+
+ * A regression with "make install", where the libiperf shared
+ library files were not getting installed, has been fixed (#1013 /
+ #1014).
+
iperf 3.8 2020-06-08
--------------------
@@ -32,7 +66,7 @@ iperf 3.8 2020-06-08
* Notable developer-visible changes
- * The embedded version of cJSON has been updated to 1.3.17 (#978).
+ * The embedded version of cJSON has been updated to 1.7.13 (#978).
* Some server authentication functions have been added to the API
(#911).
diff --git a/aclocal.m4 b/aclocal.m4
index 9310d8b..df70996 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1081,16 +1081,11 @@ _LT_EOF
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]][[,.]]*)
+ darwin*)
+ case ${MACOSX_DEPLOYMENT_TARGET},$host in
+ 10.[[012]],*|,*powerpc*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*)
+ *)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
diff --git a/config/iperf_config_static_bin.m4 b/config/iperf_config_static_bin.m4
index c72efe5..5229394 100644
--- a/config/iperf_config_static_bin.m4
+++ b/config/iperf_config_static_bin.m4
@@ -1,8 +1,9 @@
# Also link binaries as static
AC_ARG_ENABLE([static-bin],
AS_HELP_STRING([--enable-static-bin], [link iperf3 binary statically]),
- [enable_static_bin=yes
- AC_DISABLE_SHARED],
+ [enable_static=yes
+ enable_shared=no
+ enable_static_bin=yes],
[:])
AM_CONDITIONAL([ENABLE_STATIC_BIN], [test x$enable_static_bin = xno])
diff --git a/configure b/configure
index 1ebaffb..ee03ab2 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for iperf 3.8.
+# Generated by GNU Autoconf 2.69 for iperf 3.9.
#
# Report bugs to <https://github.com/esnet/iperf>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='iperf'
PACKAGE_TARNAME='iperf'
-PACKAGE_VERSION='3.8'
-PACKAGE_STRING='iperf 3.8'
+PACKAGE_VERSION='3.9'
+PACKAGE_STRING='iperf 3.9'
PACKAGE_BUGREPORT='https://github.com/esnet/iperf'
PACKAGE_URL='https://software.es.net/iperf/'
@@ -763,8 +763,8 @@ ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_static_bin
-enable_shared
enable_silent_rules
+enable_shared
enable_static
with_pic
enable_fast_install
@@ -1328,7 +1328,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures iperf 3.8 to adapt to many kinds of systems.
+\`configure' configures iperf 3.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1398,7 +1398,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of iperf 3.8:";;
+ short | recursive ) echo "Configuration of iperf 3.9:";;
esac
cat <<\_ACEOF
@@ -1407,9 +1407,9 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-static-bin link iperf3 binary statically
- --enable-shared[=PKGS] build shared libraries [default=no]
--enable-silent-rules less verbose build output (undo: "make V=1")
--disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-shared[=PKGS] build shared libraries [default=yes]
--enable-static[=PKGS] build static libraries [default=yes]
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
@@ -1516,7 +1516,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-iperf configure 3.8
+iperf configure 3.9
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1885,7 +1885,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by iperf $as_me 3.8, which was
+It was created by iperf $as_me 3.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2293,38 +2293,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# Also link binaries as static
# Check whether --enable-static-bin was given.
if test "${enable_static_bin+set}" = set; then :
- enableval=$enable_static_bin; enable_static_bin=yes
- # Check whether --enable-shared was given.
-if test "${enable_shared+set}" = set; then :
- enableval=$enable_shared; p=${PACKAGE-default}
- case $enableval in
- yes) enable_shared=yes ;;
- no) enable_shared=no ;;
- *)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else
- enable_shared=no
-fi
-
-
-
-
-
-
-
-
-
+ enableval=$enable_static_bin; enable_static=yes
+ enable_shared=no
+ enable_static_bin=yes
else
:
fi
@@ -2870,7 +2841,7 @@ fi
# Define the identity of the package.
PACKAGE='iperf'
- VERSION='3.8'
+ VERSION='3.9'
cat >>confdefs.h <<_ACEOF
@@ -7465,16 +7436,11 @@ $as_echo "$lt_cv_ld_force_load" >&6; }
_lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[012][,.]*)
+ darwin*)
+ case ${MACOSX_DEPLOYMENT_TARGET},$host in
+ 10.[012],*|,*powerpc*)
_lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*)
+ *)
_lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
@@ -7824,6 +7790,36 @@ done
enable_win32_dll=no
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
# Check whether --enable-static was given.
if test "${enable_static+set}" = set; then :
@@ -12946,9 +12942,7 @@ fi
# Check if enable profiling
# Check whether --enable-profiling was given.
if test "${enable_profiling+set}" = set; then :
- enableval=$enable_profiling; enable_profiling=yes
-else
- :
+ enableval=$enable_profiling;
fi
if test x$enable_profiling = xyes; then
@@ -13415,7 +13409,7 @@ if test "x$ac_cv_header_netinet_sctp_h" = xyes; then :
#define HAVE_NETINET_SCTP_H 1
_ACEOF
-$as_echo "#define HAVE_SCTP 1" >>confdefs.h
+$as_echo "#define HAVE_SCTP_H 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sctp_bindx" >&5
$as_echo_n "checking for library containing sctp_bindx... " >&6; }
@@ -14573,7 +14567,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by iperf $as_me 3.8, which was
+This file was extended by iperf $as_me 3.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14640,7 +14634,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-iperf config.status 3.8
+iperf config.status 3.9
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -14769,9 +14763,9 @@ AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
sed_quote_subst='$sed_quote_subst'
double_quote_subst='$double_quote_subst'
delay_variable_subst='$delay_variable_subst'
-enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
@@ -15803,13 +15797,13 @@ available_tags=''
# ### BEGIN LIBTOOL CONFIG
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
# Which release of libtool.m4 was used?
macro_version=$macro_version
macro_revision=$macro_revision
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
# Whether or not to build static libraries.
build_old_libs=$enable_static
diff --git a/configure.ac b/configure.ac
index 25c44bb..939cf0a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@
# file for complete information.
# Initialize the autoconf system for the specified tool, version and mailing list
-AC_INIT(iperf, 3.8, https://github.com/esnet/iperf, iperf, https://software.es.net/iperf/)
+AC_INIT(iperf, 3.9, https://github.com/esnet/iperf, iperf, https://software.es.net/iperf/)
m4_include([config/ax_check_openssl.m4])
m4_include([config/iperf_config_static_bin.m4])
AC_LANG(C)
@@ -58,9 +58,7 @@ fi
# Check if enable profiling
AC_ARG_ENABLE([profiling],
- AS_HELP_STRING([--enable-profiling], [Enable iperf3 profiling binary]),
- [enable_profiling=yes],
- [:])
+ AS_HELP_STRING([--enable-profiling], [Enable iperf3 profiling binary]))
AM_CONDITIONAL([ENABLE_PROFILING], [test x$enable_profiling = xyes])
# Checks for header files.
@@ -119,7 +117,7 @@ AC_ARG_WITH([sctp],
if $try_sctp; then
AC_CHECK_HEADERS([sys/socket.h])
AC_CHECK_HEADERS([netinet/sctp.h],
- AC_DEFINE([HAVE_SCTP], [1], [Have SCTP support.])
+ AC_DEFINE([HAVE_SCTP_H], [1], [Have SCTP support.])
AC_SEARCH_LIBS(sctp_bindx, [sctp])
AC_CHECK_TYPES([struct sctp_assoc_value], [], [],
[[#include <netinet/sctp.h>]]),
diff --git a/docs/conf.py b/docs/conf.py
index 17aa556..083a3bf 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -52,10 +52,10 @@ copyright = u'2014-2020, ESnet'
# built documents.
#
# The short X.Y version.
-version = '3.7'
+version = '3.8.1'
# The full version, including alpha/beta/rc tags.
-release = '3.7'
+release = '3.8.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/faq.rst b/docs/faq.rst
index c7170cc..d7d182e 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -65,7 +65,9 @@ How can I build a statically-linked executable of iperf3?
generation of shared libraries and link the executable
statically. For iperf-3.8 or later, configuring as ``configure
--enable-static-bin`` is another, shorter way to accomplish
- this.
+ this. If SCTP is installed on the system it might also be
+ necessary to pass the ``--without-sctp`` flag at configure
+ time.
#. Compile as normal.
@@ -74,10 +76,16 @@ How can I build a statically-linked executable of iperf3?
How can I build on a system that doesn't support profiled executables?
This problem has been noted by users attempting to build iperf3 for
- Android systems. There are several workarounds. In order from least
+ Android systems, as well as some recent versions of macOS.
+ There are several workarounds. In order from least
effort to most effort:
- #. Beginning with iperf-3.6, the ``--disable-profiling`` flag can be
+ #. Beginning with iperf-3.8, profiled executables are actually not
+ built by default, so this question becomes somewhat moot. Pass
+ the ``--enable-profiling`` flag to ``configure`` to build
+ profiled executables.
+
+ #. In iperf-3.6 and iperf-3.7, the ``--disable-profiling`` flag can be
passed to ``configure`` to disable the building of profiled
object files and the profiled executable.
@@ -119,6 +127,59 @@ I'm seeing quite a bit of unexpected UDP loss. Why?
iperf3 UDP does not seem to work at bandwidths less than 100Kbps. Why?
You'll need to reduce the default packet length to get UDP rates of less that 100Kbps. Try ``-l100``.
+TCP throughput drops to (almost) zero during a test, what's going on?
+ A drop in throughput to almost zero, except maybe for the first
+ reported interval(s), may be related to problems in NIC TCP Offload,
+ which is used to offload TCP functionality to the NIC (see
+ https://en.wikipedia.org/wiki/TCP_offload_engine). The goal of TCP
+ Offload is to save main CPU performance, mainly in the areas of
+ segmentation and reassembly of large packets and checksum
+ computation.
+
+ When TCP packets are sent with the "Don't Fragment" flag set, which
+ is the recommended setting, segmentation is done by the TCP stack
+ based on the reported next hop MSS in the ICMP Fragmentation Needed
+ message. With TCP Offload, active segmentation is done by the NIC on
+ the sending side, which is known as TCP Segmentation offload (TSO)
+ or in Windows as Large Send Offload (LSO). It seems that there are
+ TSO/LSO implementations which for some reason ignore the reported
+ MSS and therefore don’t perform segmentation. In these cases, when
+ large packets are sent, e.g. the default iperf3 128KB (131,072
+ bytes), iperf3 will show that data was sent in the first interval,
+ but since the packets don’t get to the server, no ack is received
+ and therefore no data is sent in the following intervals. It may
+ happen that after certain timeout the main CPU will re-send the
+ packet by re-segmenting it, and in these cases data will get to the
+ server after a while. However, it seems that segmentation is not
+ automatically continued with the next packet, so the data transfer
+ rate be very low.
+
+ The recommended solution in such a case is to disable TSO/LSO, at
+ least on the relevant port. See for example:
+ https://atomicit.ca/kb/articles/slow-network-speed-windows-10/. If
+ that doesn’t help then "Don't Fragment" TCP flag may be
+ disabled. See for example:
+ https://support.microsoft.com/en-us/help/900926/recommended-tcp-ip-settings-for-wan-links-with-a-mtu-size-of-less-than. However,
+ note that disabling the “Don’t Fragment” flag may cause other
+ issues.
+
+ To test whether TSO/LSO may be the problem, do the following:
+
+ * If different machine configurations are used for the client and
+ server, try the iperf3 reverse mode (``-R``). If TSO/LSO is only
+ enabled on the client machine, this test should succeed.
+ * Reduce the sending length to a small value that should not require
+ segmentation, using the iperf3 ``-l`` option, e.g. ``-l 512``. It
+ may also help to reduce the MTU by using the iperf3 ``-M`` option,
+ e.g. ``-M 1460``.
+ * Using tools like Wireshark, identify the required MSS in the ICMP
+ Fragmentation Needed messages (if reported). Run tests with the
+ ``-l`` value set to 2 times the MSS and then 4 times, 6 times,
+ etc. With TSO/LSO issue in each test the throughput should be
+ reduced more. It may help to increase the testing time beyond the
+ default 10 seconds to better see the behavior (iperf3 ``-t``
+ option).
+
What congestion control algorithms are supported?
On Linux, run this command to see the available congestion control
algorithms (note that some algorithms are packaged as kernel
diff --git a/docs/news.rst b/docs/news.rst
index 4104d36..72c0d93 100644
--- a/docs/news.rst
+++ b/docs/news.rst
@@ -1,13 +1,31 @@
iperf3 Project News
===================
+2020-06-10: iperf-3.8.1 released
+---------------------------------
+
+| URL: https://downloads.es.net/pub/iperf/iperf-3.8.1.tar.gz
+| SHA256: ``e5b080f3273a8a715a4100f13826ac2ca31cc7b1315925631b2ecf64957ded96 iperf-3.8.1.tar.gz``
+
+iperf 3.8.1 fixes a regression with ``make install`` in iperf 3.8. It
+is otherwise identical to iperf 3.8.
+
+2020-06-08: iperf-3.8 released
+-------------------------------
+
+| URL: https://downloads.es.net/pub/iperf/iperf-3.8.tar.gz
+| SHA256: ``edc1c317b0ae31925e5eb84f0295faefbaa1db3229f4693e11d954d114de4bcd iperf-3.8.tar.gz``
+
+iperf 3.8 contains minor bugfixes and enhancements.
+
+
2019-06-21: iperf-3.7 released
-------------------------------
| URL: https://downloads.es.net/pub/iperf/iperf-3.7.tar.gz
| SHA256: ``d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c iperf-3.7.tar.gz``
-iperf 3.6 adds the ``--bidir`` flag for bidirectional tests, includes
+iperf 3.7 adds the ``--bidir`` flag for bidirectional tests, includes
some minor enhancements, and fixes a number of bugs. More details can
be found in the release notes.
diff --git a/src/iperf.h b/src/iperf.h
index 6ce77f5..5b1da46 100644
--- a/src/iperf.h
+++ b/src/iperf.h
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2019, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -68,7 +68,9 @@
#include <openssl/evp.h>
#endif // HAVE_SSL
+#if !defined(__IPERF_API_H)
typedef uint64_t iperf_size_t;
+#endif // __IPERF_API_H
struct iperf_interval_results
{
@@ -135,7 +137,10 @@ struct iperf_settings
int domain; /* AF_INET or AF_INET6 */
int socket_bufsize; /* window size for TCP */
int blksize; /* size of read/writes (-l) */
- uint64_t rate; /* target data rate for application pacing*/
+ iperf_size_t rate; /* target data rate for application pacing*/
+ iperf_size_t bitrate_limit; /* server's maximum allowed total data rate for all streams*/
+ double bitrate_limit_interval; /* interval for avaraging total data rate */
+ int bitrate_limit_stats_per_interval; /* calculated number of stats periods for averaging total data rate */
uint64_t fqrate; /* target data rate for FQ pacing*/
int pacing_timer; /* pacing timer in microseconds */
int burst; /* packets per burst */
@@ -298,6 +303,8 @@ struct iperf_test
int forceflush; /* --forceflush - flushing output at every interval */
int multisend;
int repeating_payload; /* --repeating-payload */
+ int timestamps; /* --timestamps */
+ char *timestamp_format;
char *json_output_string; /* rendered JSON output if json_output is set */
/* Select related parameters */
@@ -328,6 +335,11 @@ struct iperf_test
iperf_size_t bytes_received;
iperf_size_t blocks_received;
+ iperf_size_t bitrate_limit_stats_count; /* Number of stats periods accumulated for server's total bitrate average */
+ iperf_size_t *bitrate_limit_intervals_traffic_bytes; /* Pointer to a cyclic array that includes the last interval's bytes transferred */
+ iperf_size_t bitrate_limit_last_interval_index; /* Index of the last interval traffic insrted into the cyclic array */
+ int bitrate_limit_exceeded; /* Set by callback routine when average data rate exceeded the server's bitrate limit */
+
char cookie[COOKIE_SIZE];
// struct iperf_stream *streams; /* pointer to list of struct stream */
SLIST_HEAD(slisthead, iperf_stream) streams;
@@ -385,6 +397,8 @@ struct iperf_test
#define MAX_MSS (9 * 1024)
#define MAX_STREAMS 128
+#define TIMESTAMP_FORMAT "%c "
+
extern int gerror; /* error value from getaddrinfo(3), for use in internal error handling */
#endif /* !__IPERF_H */
diff --git a/src/iperf3.1 b/src/iperf3.1
index 93fe7b9..97d66ed 100644
--- a/src/iperf3.1
+++ b/src/iperf3.1
@@ -1,4 +1,4 @@
-.TH IPERF3 1 "June 2019" ESnet "User Manuals"
+.TH IPERF3 1 "July 2020" ESnet "User Manuals"
.SH NAME
iperf3 \- perform network throughput tests
.SH SYNOPSIS
@@ -153,6 +153,14 @@ send output to a log file.
force flushing output at every interval.
Used to avoid buffering when sending output to pipe.
.TP
+.BR --timestamps " [\fIformat\fR]"
+prepend a timestamp at the start of each output line.
+By default, timestamps have the format emitted by
+.BR ctime ( 1 ).
+Optionally, a format specification can be passed to customize the
+timestamps, see
+.BR strftime ( 3 ).
+.TP
.BR -d ", " --debug " "
emit debugging output.
Primarily (perhaps exclusively) of use to developers.
@@ -177,6 +185,15 @@ write a file with the process ID, most useful when running as a daemon.
.BR -1 ", " --one-off
handle one client connection, then exit.
.TP
+.BR --server-bitrate-limit " \fIn\fR[KMGT]"
+set a limit on the server side, which will cause a test to abort if
+the client specifies a test of more than \fIn\fR bits per second, or
+if the average data sent or received by the client (including all data
+streams) is greater than \fIn\fR bits per second. The default limit
+is zero, which implies no limit. The interval over which to average
+the data rate is 5 seconds by default, but can be specified by adding
+a '/' and a number to the bitrate specifier.
+.TP
.BR --rsa-private-key-path " \fIfile\fR"
path to the RSA private key (not password-protected) used to decrypt
authentication credentials from the client (if built with OpenSSL
@@ -209,7 +226,7 @@ connection establishment.
Providing a shorter value may speed up detection of a down iperf3
server.
.TP
-.BR -b ", " --bitrate " \fIn\fR[KM]"
+.BR -b ", " --bitrate " \fIn\fR[KMGT]"
set target bitrate to \fIn\fR bits/sec (default 1 Mbit/sec for UDP,
unlimited for TCP/SCTP).
If there are multiple streams (\-P flag), the throughput limit is applied
@@ -226,7 +243,7 @@ Compare with the \--fq-rate flag.
This option replaces the \--bandwidth flag, which is now deprecated
but (at least for now) still accepted.
.TP
-.BR --pacing-timer " \fIn\fR[KMG]"
+.BR --pacing-timer " \fIn\fR[KMGT]"
set pacing timer interval in microseconds (default 1000 microseconds,
or 1 ms).
This controls iperf3's internal pacing timer for the \-b/\--bitrate
@@ -236,7 +253,7 @@ Smaller values of the pacing timer parameter smooth out the traffic
emitted by iperf3, but potentially at the cost of performance due to
more frequent timer processing.
.TP
-.BR --fq-rate " \fIn\fR[KM]"
+.BR --fq-rate " \fIn\fR[KMGT]"
Set a rate to be used with fair-queueing based socket-level pacing,
in bits per second.
This pacing (if specified) will be in addition to any pacing due to
@@ -253,13 +270,13 @@ It is equivalent to specifying --fq-rate=0.
.BR -t ", " --time " \fIn\fR"
time in seconds to transmit for (default 10 secs)
.TP
-.BR -n ", " --bytes " \fIn\fR[KM]"
+.BR -n ", " --bytes " \fIn\fR[KMGT]"
number of bytes to transmit (instead of \-t)
.TP
-.BR -k ", " --blockcount " \fIn\fR[KM]"
+.BR -k ", " --blockcount " \fIn\fR[KMGT]"
number of blocks (packets) to transmit (instead of \-t or \-n)
.TP
-.BR -l ", " --length " \fIn\fR[KM]"
+.BR -l ", " --length " \fIn\fR[KMGT]"
length of buffer to read or write. For TCP tests, the default value
is 128KB.
In the case of UDP, iperf3 tries to dynamically determine a reasonable
@@ -282,7 +299,7 @@ client
test in both directions (normal and reverse), with both the client and
server sending and receiving data simultaneously
.TP
-.BR -w ", " --window " \fIn\fR[KM]"
+.BR -w ", " --window " \fIn\fR[KMGT]"
window size / socket buffer size (this gets sent to the server and used on that side too)
.TP
.BR -M ", " --set-mss " \fIn\fR"
diff --git a/src/iperf_api.c b/src/iperf_api.c
index ed643b7..88fed30 100644
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
@@ -57,6 +57,7 @@
#include <sched.h>
#include <setjmp.h>
#include <stdarg.h>
+#include <math.h>
#if defined(HAVE_CPUSET_SETAFFINITY)
#include <sys/param.h>
@@ -76,9 +77,9 @@
#include "iperf_api.h"
#include "iperf_udp.h"
#include "iperf_tcp.h"
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
#include "iperf_sctp.h"
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
#include "timer.h"
#include "cjson.h"
@@ -119,7 +120,7 @@ usage_long(FILE *f)
}
-void warning(char *str)
+void warning(const char *str)
{
fprintf(stderr, "warning: %s\n", str);
}
@@ -164,6 +165,24 @@ iperf_get_test_rate(struct iperf_test *ipt)
}
uint64_t
+iperf_get_test_bitrate_limit(struct iperf_test *ipt)
+{
+ return ipt->settings->bitrate_limit;
+}
+
+double
+iperf_get_test_bitrate_limit_interval(struct iperf_test *ipt)
+{
+ return ipt->settings->bitrate_limit_interval;
+}
+
+int
+iperf_get_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt)
+{
+ return ipt->settings->bitrate_limit_stats_per_interval;
+}
+
+uint64_t
iperf_get_test_fqrate(struct iperf_test *ipt)
{
return ipt->settings->fqrate;
@@ -242,6 +261,18 @@ iperf_get_test_num_streams(struct iperf_test *ipt)
}
int
+iperf_get_test_timestamps(struct iperf_test *ipt)
+{
+ return ipt->timestamps;
+}
+
+const char *
+iperf_get_test_timestamp_format(struct iperf_test *ipt)
+{
+ return ipt->timestamp_format;
+}
+
+int
iperf_get_test_repeating_payload(struct iperf_test *ipt)
{
return ipt->repeating_payload;
@@ -401,7 +432,7 @@ iperf_set_test_blksize(struct iperf_test *ipt, int blksize)
}
void
-iperf_set_test_logfile(struct iperf_test *ipt, char *logfile)
+iperf_set_test_logfile(struct iperf_test *ipt, const char *logfile)
{
ipt->logfile = strdup(logfile);
}
@@ -413,6 +444,24 @@ iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
}
void
+iperf_set_test_bitrate_limit_maximum(struct iperf_test *ipt, uint64_t total_rate)
+{
+ ipt->settings->bitrate_limit = total_rate;
+}
+
+void
+iperf_set_test_bitrate_limit_interval(struct iperf_test *ipt, uint64_t bitrate_limit_interval)
+{
+ ipt->settings->bitrate_limit_interval = bitrate_limit_interval;
+}
+
+void
+iperf_set_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt, uint64_t bitrate_limit_stats_per_interval)
+{
+ ipt->settings->bitrate_limit_stats_per_interval = bitrate_limit_stats_per_interval;
+}
+
+void
iperf_set_test_fqrate(struct iperf_test *ipt, uint64_t fqrate)
{
ipt->settings->fqrate = fqrate;
@@ -466,6 +515,18 @@ iperf_set_test_repeating_payload(struct iperf_test *ipt, int repeating_payload)
ipt->repeating_payload = repeating_payload;
}
+void
+iperf_set_test_timestamps(struct iperf_test *ipt, int timestamps)
+{
+ ipt->timestamps = timestamps;
+}
+
+void
+iperf_set_test_timestamp_format(struct iperf_test *ipt, const char *tf)
+{
+ ipt->timestamp_format = strdup(tf);
+}
+
static void
check_sender_has_retransmits(struct iperf_test *ipt)
{
@@ -496,13 +557,13 @@ iperf_set_test_role(struct iperf_test *ipt, char role)
}
void
-iperf_set_test_server_hostname(struct iperf_test *ipt, char *server_hostname)
+iperf_set_test_server_hostname(struct iperf_test *ipt, const char *server_hostname)
{
ipt->server_hostname = strdup(server_hostname);
}
void
-iperf_set_test_template(struct iperf_test *ipt, char *tmp_template)
+iperf_set_test_template(struct iperf_test *ipt, const char *tmp_template)
{
ipt->tmp_template = strdup(tmp_template);
}
@@ -557,38 +618,38 @@ iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
#if defined(HAVE_SSL)
void
-iperf_set_test_client_username(struct iperf_test *ipt, char *client_username)
+iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username)
{
ipt->settings->client_username = strdup(client_username);
}
void
-iperf_set_test_client_password(struct iperf_test *ipt, char *client_password)
+iperf_set_test_client_password(struct iperf_test *ipt, const char *client_password)
{
ipt->settings->client_password = strdup(client_password);
}
void
-iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, char *client_rsa_pubkey_base64)
+iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, const char *client_rsa_pubkey_base64)
{
ipt->settings->client_rsa_pubkey = load_pubkey_from_base64(client_rsa_pubkey_base64);
}
void
-iperf_set_test_server_authorized_users(struct iperf_test *ipt, char *server_authorized_users)
+iperf_set_test_server_authorized_users(struct iperf_test *ipt, const char *server_authorized_users)
{
ipt->server_authorized_users = strdup(server_authorized_users);
}
void
-iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, char *server_rsa_privkey_base64)
+iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64)
{
ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
}
#endif // HAVE_SSL
void
-iperf_set_test_bind_address(struct iperf_test *ipt, char *bnd_address)
+iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address)
{
ipt->bind_address = strdup(bnd_address);
}
@@ -612,7 +673,7 @@ iperf_set_test_tos(struct iperf_test *ipt, int tos)
}
void
-iperf_set_test_extra_data(struct iperf_test *ipt, char *dat)
+iperf_set_test_extra_data(struct iperf_test *ipt, const char *dat)
{
ipt->extra_data = strdup(dat);
}
@@ -816,6 +877,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"udp", no_argument, NULL, 'u'},
{"bitrate", required_argument, NULL, 'b'},
{"bandwidth", required_argument, NULL, 'b'},
+ {"server-bitrate-limit", required_argument, NULL, OPT_SERVER_BITRATE_LIMIT},
{"time", required_argument, NULL, 't'},
{"bytes", required_argument, NULL, 'n'},
{"blockcount", required_argument, NULL, 'k'},
@@ -840,6 +902,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"omit", required_argument, NULL, 'O'},
{"file", required_argument, NULL, 'F'},
{"repeating-payload", no_argument, NULL, OPT_REPEATING_PAYLOAD},
+ {"timestamps", optional_argument, NULL, OPT_TIMESTAMPS},
#if defined(HAVE_CPU_AFFINITY)
{"affinity", required_argument, NULL, 'A'},
#endif /* HAVE_CPU_AFFINITY */
@@ -848,7 +911,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"congestion", required_argument, NULL, 'C'},
{"linux-congestion", required_argument, NULL, 'C'},
#endif /* HAVE_TCP_CONGESTION */
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
{"sctp", no_argument, NULL, OPT_SCTP},
{"nstreams", required_argument, NULL, OPT_NUMSTREAMS},
{"xbind", required_argument, NULL, 'X'},
@@ -968,14 +1031,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
client_flag = 1;
break;
case OPT_SCTP:
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
set_protocol(test, Psctp);
client_flag = 1;
break;
-#else /* HAVE_SCTP */
+#else /* HAVE_SCTP_H */
i_errno = IEUNIMP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
case OPT_NUMSTREAMS:
#if defined(linux) || defined(__FreeBSD__)
@@ -1001,6 +1064,21 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
rate_flag = 1;
client_flag = 1;
break;
+ case OPT_SERVER_BITRATE_LIMIT:
+ slash = strchr(optarg, '/');
+ if (slash) {
+ *slash = '\0';
+ ++slash;
+ test->settings->bitrate_limit_interval = atof(slash);
+ if (test->settings->bitrate_limit_interval != 0 && /* Using same Max/Min limits as for Stats Interval */
+ (test->settings->bitrate_limit_interval < MIN_INTERVAL || test->settings->bitrate_limit_interval > MAX_INTERVAL) ) {
+ i_errno = IETOTALINTERVAL;
+ return -1;
+ }
+ }
+ test->settings->bitrate_limit = unit_atof_rate(optarg);
+ server_flag = 1;
+ break;
case 't':
test->duration = atoi(optarg);
if (test->duration > MAX_TIME) {
@@ -1149,6 +1227,15 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
test->repeating_payload = 1;
client_flag = 1;
break;
+ case OPT_TIMESTAMPS:
+ iperf_set_test_timestamps(test, 1);
+ if (optarg) {
+ iperf_set_test_timestamp_format(test, optarg);
+ }
+ else {
+ iperf_set_test_timestamp_format(test, TIMESTAMP_FORMAT);
+ }
+ break;
case 'O':
test->omit = atoi(optarg);
if (test->omit < 0 || test->omit > 60) {
@@ -1292,6 +1379,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)
client_password = strdup(client_password);
else if (iperf_getpass(&client_password, &s, stdin) < 0){
+ i_errno = IESETCLIENTAUTH;
return -1;
}
if (test_load_pubkey_from_file(client_rsa_public_key) < 0){
@@ -1374,6 +1462,13 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
return -1;
}
+ /* Set Total-rate average interval to multiplicity of State interval */
+ if (test->settings->bitrate_limit_interval != 0) {
+ test->settings->bitrate_limit_stats_per_interval =
+ (test->settings->bitrate_limit_interval <= test->stats_interval ?
+ 1 : round(test->settings->bitrate_limit_interval/test->stats_interval) );
+ }
+
/* Show warning if JSON output is used with explicit report format */
if ((test->json_output) && (test->settings->unit_format != 'a')) {
warning("Report format (-f) flag ignored with JSON output (-J)");
@@ -1436,6 +1531,45 @@ iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
}
}
+/* Verify that average traffic is not greater than the specifid limit */
+void
+iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)
+{
+ double seconds;
+ uint64_t bits_per_second;
+ iperf_size_t total_bytes;
+ int i;
+
+ if (test->done || test->settings->bitrate_limit == 0) // Continue only if check should be done
+ return;
+
+ /* Add last inetrval's transffered bytes to the array */
+ if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)
+ test->bitrate_limit_last_interval_index = 0;
+ test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;
+
+ /* Ensure that enough stats periods passed to allow averaging throughput */
+ test->bitrate_limit_stats_count += 1;
+ if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)
+ return;
+
+ /* Calculating total bytes traffic to be averaged */
+ for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {
+ total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];
+ }
+
+ seconds = test->stats_interval * test->settings->bitrate_limit_stats_per_interval;
+ bits_per_second = total_bytes * 8 / seconds;
+ if (test->debug) {
+ iperf_printf(test,"Interval %" PRIu64 " - throughput %" PRIu64 " bps (limit %" PRIu64 ")\n", test->bitrate_limit_stats_count, bits_per_second, test->settings->bitrate_limit);
+ }
+
+ if (bits_per_second > test->settings->bitrate_limit) {
+ iperf_err(test, "Total throughput of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", bits_per_second, test->settings->bitrate_limit);
+ test->bitrate_limit_exceeded = 1;
+ }
+}
+
int
iperf_send(struct iperf_test *test, fd_set *write_setP)
{
@@ -1480,7 +1614,8 @@ iperf_send(struct iperf_test *test, fd_set *write_setP)
if (test->settings->burst != 0) {
iperf_time_now(&now);
SLIST_FOREACH(sp, &test->streams, streams)
- iperf_check_throttle(sp, &now);
+ if (sp->sender)
+ iperf_check_throttle(sp, &now);
}
if (write_setP != NULL)
SLIST_FOREACH(sp, &test->streams, streams)
@@ -1562,7 +1697,7 @@ iperf_create_send_timers(struct iperf_test * test)
}
SLIST_FOREACH(sp, &test->streams, streams) {
sp->green_light = 1;
- if (test->settings->rate != 0) {
+ if (test->settings->rate != 0 && sp->sender) {
cd.p = sp;
sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
if (sp->send_timer == NULL) {
@@ -1654,6 +1789,7 @@ iperf_exchange_parameters(struct iperf_test *test)
}
return -1;
}
+
FD_SET(s, &test->read_set);
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
test->prot_listener = s;
@@ -2289,6 +2425,14 @@ iperf_new_test()
}
memset(test->settings, 0, sizeof(struct iperf_settings));
+ test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);
+ if (!test->bitrate_limit_intervals_traffic_bytes) {
+ free(test);
+ i_errno = IENEWTEST;
+ return NULL;
+ }
+ memset(test->bitrate_limit_intervals_traffic_bytes, 0, sizeof(sizeof(iperf_size_t) * MAX_INTERVAL));
+
/* By default all output goes to stdout */
test->outfile = stdout;
@@ -2322,9 +2466,9 @@ int
iperf_defaults(struct iperf_test *testp)
{
struct protocol *tcp, *udp;
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
struct protocol *sctp;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
testp->omit = OMIT;
testp->duration = DURATION;
@@ -2356,6 +2500,9 @@ iperf_defaults(struct iperf_test *testp)
testp->settings->socket_bufsize = 0; /* use autotuning */
testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
testp->settings->rate = 0;
+ testp->settings->bitrate_limit = 0;
+ testp->settings->bitrate_limit_interval = 5;
+ testp->settings->bitrate_limit_stats_per_interval = 0;
testp->settings->fqrate = 0;
testp->settings->pacing_timer = 1000;
testp->settings->burst = 0;
@@ -2403,7 +2550,7 @@ iperf_defaults(struct iperf_test *testp)
set_protocol(testp, Ptcp);
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
sctp = protocol_new();
if (!sctp) {
protocol_free(tcp);
@@ -2421,7 +2568,7 @@ iperf_defaults(struct iperf_test *testp)
sctp->init = iperf_sctp_init;
SLIST_INSERT_AFTER(udp, sctp, protocols);
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
testp->on_new_stream = iperf_on_new_stream;
testp->on_test_start = iperf_on_test_start;
@@ -2497,6 +2644,8 @@ iperf_free_test(struct iperf_test *test)
free(test->congestion_used);
if (test->remote_congestion_used)
free(test->remote_congestion_used);
+ if (test->timestamp_format)
+ free(test->timestamp_format);
if (test->omit_timer != NULL)
tmr_cancel(test->omit_timer);
if (test->timer != NULL)
@@ -2513,6 +2662,15 @@ iperf_free_test(struct iperf_test *test)
free(prot);
}
+ if (test->logfile) {
+ free(test->logfile);
+ test->logfile = NULL;
+ if (test->outfile) {
+ fclose(test->outfile);
+ test->outfile = NULL;
+ }
+ }
+
if (test->server_output_text) {
free(test->server_output_text);
test->server_output_text = NULL;
@@ -2544,6 +2702,10 @@ iperf_free_test(struct iperf_test *test)
}
}
+ /* Free interval's traffic array for avrage rate calculations */
+ if (test->bitrate_limit_intervals_traffic_bytes != NULL)
+ free(test->bitrate_limit_intervals_traffic_bytes);
+
/* XXX: Why are we setting these values to NULL? */
// test->streams = NULL;
test->stats_callback = NULL;
@@ -2556,6 +2718,7 @@ void
iperf_reset_test(struct iperf_test *test)
{
struct iperf_stream *sp;
+ int i;
/* Free streams */
while (!SLIST_EMPTY(&test->streams)) {
@@ -2609,6 +2772,13 @@ iperf_reset_test(struct iperf_test *test)
test->other_side_has_retransmits = 0;
+ test->bitrate_limit_stats_count = 0;
+ test->bitrate_limit_last_interval_index = 0;
+ test->bitrate_limit_exceeded = 0;
+
+ for (i = 0; i < MAX_INTERVAL; i++)
+ test->bitrate_limit_intervals_traffic_bytes[i] = 0;
+
test->reverse = 0;
test->bidirectional = 0;
test->no_delay = 0;
@@ -2712,12 +2882,16 @@ iperf_stats_callback(struct iperf_test *test)
struct iperf_stream_result *rp = NULL;
struct iperf_interval_results *irp, temp;
struct iperf_time temp_time;
+ iperf_size_t total_interval_bytes_transferred = 0;
temp.omitted = test->omitting;
SLIST_FOREACH(sp, &test->streams, streams) {
rp = sp->result;
temp.bytes_transferred = sp->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;
-
+
+ // Total bytes transferred this interval
+ total_interval_bytes_transferred += rp->bytes_sent_this_interval + rp->bytes_received_this_interval;
+
irp = TAILQ_LAST(&rp->interval_results, irlisthead);
/* result->end_time contains timestamp of previous interval */
if ( irp != NULL ) /* not the 1st interval */
@@ -2776,6 +2950,11 @@ iperf_stats_callback(struct iperf_test *test)
add_to_interval_list(rp, &temp);
rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
}
+
+ /* Verify that total server's throughput is not above specified limit */
+ if (test->role == 's') {
+ iperf_check_total_rate(test, total_interval_bytes_transferred);
+ }
}
/**
@@ -4135,11 +4314,24 @@ iperf_clearaffinity(struct iperf_test *test)
#endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
}
+char iperf_timestr[100];
+
int
iperf_printf(struct iperf_test *test, const char* format, ...)
{
va_list argp;
int r = -1;
+ time_t now;
+ struct tm *ltm = NULL;
+ char *ct = NULL;
+
+ /* Timestamp if requested */
+ if (iperf_get_test_timestamps(test)) {
+ time(&now);
+ ltm = localtime(&now);
+ strftime(iperf_timestr, sizeof(iperf_timestr), iperf_get_test_timestamp_format(test), ltm);
+ ct = iperf_timestr;
+ }
/*
* There are roughly two use cases here. If we're the client,
@@ -4154,6 +4346,9 @@ iperf_printf(struct iperf_test *test, const char* format, ...)
* to be buffered up anyway.
*/
if (test->role == 'c') {
+ if (ct) {
+ fprintf(test->outfile, "%s", ct);
+ }
if (test->title)
fprintf(test->outfile, "%s: ", test->title);
va_start(argp, format);
@@ -4162,8 +4357,12 @@ iperf_printf(struct iperf_test *test, const char* format, ...)
}
else if (test->role == 's') {
char linebuffer[1024];
+ int i = 0;
+ if (ct) {
+ i = sprintf(linebuffer, "%s", ct);
+ }
va_start(argp, format);
- r = vsnprintf(linebuffer, sizeof(linebuffer), format, argp);
+ r = vsnprintf(linebuffer + i, sizeof(linebuffer), format, argp);
va_end(argp);
fprintf(test->outfile, "%s", linebuffer);
diff --git a/src/iperf_api.h b/src/iperf_api.h
index 3770b37..a51b773 100644
--- a/src/iperf_api.h
+++ b/src/iperf_api.h
@@ -45,6 +45,10 @@ struct iperf_interval_results;
struct iperf_stream;
struct iperf_time;
+#if !defined(__IPERF_H)
+typedef uint64_t iperf_size_t;
+#endif // __IPERF_H
+
/* default settings */
#define Ptcp SOCK_STREAM
#define Pudp SOCK_DGRAM
@@ -73,6 +77,8 @@ struct iperf_time;
#define OPT_REPEATING_PAYLOAD 18
#define OPT_EXTRA_DATA 19
#define OPT_BIDIRECTIONAL 20
+#define OPT_SERVER_BITRATE_LIMIT 21
+#define OPT_TIMESTAMPS 22
/* states */
#define TEST_START 1
@@ -113,6 +119,8 @@ double iperf_get_test_reporter_interval( struct iperf_test* ipt );
double iperf_get_test_stats_interval( struct iperf_test* ipt );
int iperf_get_test_num_streams( struct iperf_test* ipt );
int iperf_get_test_repeating_payload( struct iperf_test* ipt );
+int iperf_get_test_timestamps( struct iperf_test* ipt );
+const char* iperf_get_test_timestamp_format( struct iperf_test* ipt );
int iperf_get_test_server_port( struct iperf_test* ipt );
char* iperf_get_test_server_hostname( struct iperf_test* ipt );
char* iperf_get_test_template( struct iperf_test* ipt );
@@ -139,7 +147,7 @@ void iperf_set_test_reporter_interval( struct iperf_test* ipt, double reporter_i
void iperf_set_test_stats_interval( struct iperf_test* ipt, double stats_interval );
void iperf_set_test_state( struct iperf_test* ipt, signed char state );
void iperf_set_test_blksize( struct iperf_test* ipt, int blksize );
-void iperf_set_test_logfile( struct iperf_test* ipt, char *logfile );
+void iperf_set_test_logfile( struct iperf_test* ipt, const char *logfile );
void iperf_set_test_rate( struct iperf_test* ipt, uint64_t rate );
void iperf_set_test_pacing_timer( struct iperf_test* ipt, int pacing_timer );
void iperf_set_test_bytes( struct iperf_test* ipt, uint64_t bytes );
@@ -149,28 +157,30 @@ void iperf_set_test_server_port( struct iperf_test* ipt, int server_port );
void iperf_set_test_socket_bufsize( struct iperf_test* ipt, int socket_bufsize );
void iperf_set_test_num_streams( struct iperf_test* ipt, int num_streams );
void iperf_set_test_repeating_payload( struct iperf_test* ipt, int repeating_payload );
+void iperf_set_test_timestamps( struct iperf_test* ipt, int timestamps );
+void iperf_set_test_timestamp_format( struct iperf_test*, const char *tf );
void iperf_set_test_role( struct iperf_test* ipt, char role );
-void iperf_set_test_server_hostname( struct iperf_test* ipt, char* server_hostname );
-void iperf_set_test_template( struct iperf_test *ipt, char *tmp_template );
+void iperf_set_test_server_hostname( struct iperf_test* ipt, const char* server_hostname );
+void iperf_set_test_template( struct iperf_test *ipt, const char *tmp_template );
void iperf_set_test_reverse( struct iperf_test* ipt, int reverse );
void iperf_set_test_json_output( struct iperf_test* ipt, int json_output );
int iperf_has_zerocopy( void );
void iperf_set_test_zerocopy( struct iperf_test* ipt, int zerocopy );
void iperf_set_test_get_server_output( struct iperf_test* ipt, int get_server_output );
-void iperf_set_test_bind_address( struct iperf_test* ipt, char *bind_address );
+void iperf_set_test_bind_address( struct iperf_test* ipt, const char *bind_address );
void iperf_set_test_udp_counters_64bit( struct iperf_test* ipt, int udp_counters_64bit );
void iperf_set_test_one_off( struct iperf_test* ipt, int one_off );
void iperf_set_test_tos( struct iperf_test* ipt, int tos );
-void iperf_set_test_extra_data( struct iperf_test* ipt, char *dat );
+void iperf_set_test_extra_data( struct iperf_test* ipt, const char *dat );
void iperf_set_test_bidirectional( struct iperf_test* ipt, int bidirectional);
void iperf_set_test_no_delay( struct iperf_test* ipt, int no_delay);
#if defined(HAVE_SSL)
-void iperf_set_test_client_username(struct iperf_test *ipt, char *client_username);
-void iperf_set_test_client_password(struct iperf_test *ipt, char *client_password);
-void iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, char *client_rsa_pubkey_base64);
-void iperf_set_test_server_authorized_users(struct iperf_test *ipt, char *server_authorized_users);
-void iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, char *server_rsa_privkey_base64);
+void iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username);
+void iperf_set_test_client_password(struct iperf_test *ipt, const char *client_password);
+void iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, const char *client_rsa_pubkey_base64);
+void iperf_set_test_server_authorized_users(struct iperf_test *ipt, const char *server_authorized_users);
+void iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64);
#endif // HAVE_SSL
void iperf_set_test_connect_timeout(struct iperf_test *ipt, int ct);
@@ -268,7 +278,7 @@ void iperf_catch_sigend(void (*handler)(int));
void iperf_got_sigend(struct iperf_test *test) __attribute__ ((noreturn));
void usage(void);
void usage_long(FILE * f);
-void warning(char *);
+void warning(const char *);
int iperf_exchange_results(struct iperf_test *);
int iperf_init_test(struct iperf_test *);
int iperf_create_send_timers(struct iperf_test *);
@@ -301,6 +311,7 @@ int iperf_accept(struct iperf_test *);
int iperf_handle_message_server(struct iperf_test *);
int iperf_create_pidfile(struct iperf_test *);
int iperf_delete_pidfile(struct iperf_test *);
+void iperf_check_total_rate(struct iperf_test *, iperf_size_t);
/* JSON output routines. */
int iperf_json_start(struct iperf_test *);
@@ -348,6 +359,8 @@ enum {
IEBADFORMAT = 24, // Bad format argument to -f
IEREVERSEBIDIR = 25, // Iperf cannot be both reverse and bidirectional
IEBADPORT = 26, // Bad port number
+ IETOTALRATE = 27, // Total required bandwidth is larger than server's limit
+ IETOTALINTERVAL = 28, // Invalid time interval for calculating average data rate
/* Test errors */
IENEWTEST = 100, // Unable to create a new test (check perror)
IEINITTEST = 101, // Test initialization failed (check perror)
diff --git a/src/iperf_auth.c b/src/iperf_auth.c
index 46211e0..eb4610f 100644
--- a/src/iperf_auth.c
+++ b/src/iperf_auth.c
@@ -174,6 +174,7 @@ EVP_PKEY *load_pubkey_from_base64(const char *buffer) {
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, key, key_len);
+ free(key);
EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
BIO_free(bio);
return (pkey);
@@ -199,6 +200,7 @@ EVP_PKEY *load_privkey_from_base64(const char *buffer) {
BIO* bio = BIO_new(BIO_s_mem());
BIO_write(bio, key, key_len);
+ free(key);
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
return (pkey);
@@ -304,7 +306,7 @@ int encode_auth_setting(const char *username, const char *password, EVP_PKEY *pu
return (0); //success
}
-int decode_auth_setting(int enable_debug, char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
+int decode_auth_setting(int enable_debug, const char *authtoken, EVP_PKEY *private_key, char **username, char **password, time_t *ts){
unsigned char *encrypted_b64 = NULL;
size_t encrypted_len_b64;
Base64Decode(authtoken, &encrypted_b64, &encrypted_len_b64);
diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c
index 20ea6fd..d0edf7d 100644
--- a/src/iperf_client_api.c
+++ b/src/iperf_client_api.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2018, The Regents of the University of
+ * iperf, Copyright (c) 2014-2020, The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -478,7 +478,7 @@ iperf_run_client(struct iperf_test * test)
/* Start the client and connect to the server */
if (iperf_connect(test) < 0)
- return -1;
+ goto cleanup_and_fail;
/* Begin calculating CPU utilization */
cpu_util(NULL);
@@ -492,12 +492,12 @@ iperf_run_client(struct iperf_test * test)
result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
if (result < 0 && errno != EINTR) {
i_errno = IESELECT;
- return -1;
+ goto cleanup_and_fail;
}
if (result > 0) {
if (FD_ISSET(test->ctrl_sck, &read_set)) {
if (iperf_handle_message_client(test) < 0) {
- return -1;
+ goto cleanup_and_fail;
}
FD_CLR(test->ctrl_sck, &read_set);
}
@@ -521,17 +521,17 @@ iperf_run_client(struct iperf_test * test)
if (test->mode == BIDIRECTIONAL)
{
if (iperf_send(test, &write_set) < 0)
- return -1;
+ goto cleanup_and_fail;
if (iperf_recv(test, &read_set) < 0)
- return -1;
+ goto cleanup_and_fail;
} else if (test->mode == SENDER) {
// Regular mode. Client sends.
if (iperf_send(test, &write_set) < 0)
- return -1;
+ goto cleanup_and_fail;
} else {
// Reverse mode. Client receives.
if (iperf_recv(test, &read_set) < 0)
- return -1;
+ goto cleanup_and_fail;
}
@@ -557,7 +557,7 @@ iperf_run_client(struct iperf_test * test)
cpu_util(test->cpu_util);
test->stats_callback(test);
if (iperf_set_send_state(test, TEST_END) != 0)
- return -1;
+ goto cleanup_and_fail;
}
}
// If we're in reverse mode, continue draining the data
@@ -567,7 +567,7 @@ iperf_run_client(struct iperf_test * test)
// from the client side.
else if (test->mode == RECEIVER && test->state == TEST_END) {
if (iperf_recv(test, &read_set) < 0)
- return -1;
+ goto cleanup_and_fail;
}
}
@@ -582,4 +582,11 @@ iperf_run_client(struct iperf_test * test)
iflush(test);
return 0;
+
+ cleanup_and_fail:
+ iperf_client_end(test);
+ if (test->json_output)
+ iperf_json_finish(test);
+ iflush(test);
+ return -1;
}
diff --git a/src/iperf_config.h.in b/src/iperf_config.h.in
index e543cbd..1a7cbec 100644
--- a/src/iperf_config.h.in
+++ b/src/iperf_config.h.in
@@ -40,7 +40,7 @@
#undef HAVE_SCHED_SETAFFINITY
/* Have SCTP support. */
-#undef HAVE_SCTP
+#undef HAVE_SCTP_H
/* Define to 1 if you have the `sendfile' function. */
#undef HAVE_SENDFILE
diff --git a/src/iperf_error.c b/src/iperf_error.c
index c6e5ee4..cfe4cbd 100644
--- a/src/iperf_error.c
+++ b/src/iperf_error.c
@@ -35,12 +35,25 @@
int gerror;
+char iperf_timestrerr[100];
+
/* Do a printf to stderr. */
void
iperf_err(struct iperf_test *test, const char *format, ...)
{
va_list argp;
char str[1000];
+ time_t now;
+ struct tm *ltm = NULL;
+ char *ct = NULL;
+
+ /* Timestamp if requested */
+ if (test != NULL && test->timestamps) {
+ time(&now);
+ ltm = localtime(&now);
+ strftime(iperf_timestrerr, sizeof(iperf_timestrerr), test->timestamp_format, ltm);
+ ct = iperf_timestrerr;
+ }
va_start(argp, format);
vsnprintf(str, sizeof(str), format, argp);
@@ -48,9 +61,15 @@ iperf_err(struct iperf_test *test, const char *format, ...)
cJSON_AddStringToObject(test->json_top, "error", str);
else
if (test && test->outfile && test->outfile != stdout) {
+ if (ct) {
+ fprintf(test->outfile, "%s", ct);
+ }
fprintf(test->outfile, "iperf3: %s\n", str);
}
else {
+ if (ct) {
+ fprintf(stderr, "%s", ct);
+ }
fprintf(stderr, "iperf3: %s\n", str);
}
va_end(argp);
@@ -62,6 +81,17 @@ iperf_errexit(struct iperf_test *test, const char *format, ...)
{
va_list argp;
char str[1000];
+ time_t now;
+ struct tm *ltm = NULL;
+ char *ct = NULL;
+
+ /* Timestamp if requested */
+ if (test != NULL && test->timestamps) {
+ time(&now);
+ ltm = localtime(&now);
+ strftime(iperf_timestrerr, sizeof(iperf_timestrerr), "%c ", ltm);
+ ct = iperf_timestrerr;
+ }
va_start(argp, format);
vsnprintf(str, sizeof(str), format, argp);
@@ -70,9 +100,15 @@ iperf_errexit(struct iperf_test *test, const char *format, ...)
iperf_json_finish(test);
} else
if (test && test->outfile && test->outfile != stdout) {
+ if (ct) {
+ fprintf(test->outfile, "%s", ct);
+ }
fprintf(test->outfile, "iperf3: %s\n", str);
}
else {
+ if (ct) {
+ fprintf(stderr, "%s", ct);
+ }
fprintf(stderr, "iperf3: %s\n", str);
}
va_end(argp);
@@ -385,7 +421,13 @@ iperf_strerror(int int_errno)
case IEREVERSEBIDIR:
snprintf(errstr, len, "cannot be both reverse and bidirectional");
break;
-
+ case IETOTALRATE:
+ snprintf(errstr, len, "total required bandwidth is larger than server limit");
+ break;
+ default:
+ snprintf(errstr, len, "int_errno=%d", int_errno);
+ perr = 1;
+ break;
}
/* Append the result of strerror() or gai_strerror() if appropriate */
diff --git a/src/iperf_locale.c b/src/iperf_locale.c
index 2dd5a5b..d5a5354 100644
--- a/src/iperf_locale.c
+++ b/src/iperf_locale.c
@@ -109,6 +109,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -J, --json output in JSON format\n"
" --logfile f send output to a log file\n"
" --forceflush force flushing output at every interval\n"
+ " --timestamps <format> emit a timestamp at the start of each output line\n"
+ " (using optional format string as per strftime(3))\n"
+
" -d, --debug emit debugging output\n"
" -v, --version show version information and quit\n"
" -h, --help show this message and quit\n"
@@ -117,6 +120,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" -D, --daemon run the server as a daemon\n"
" -I, --pidfile file write PID file\n"
" -1, --one-off handle one client connection then exit\n"
+ " --server-bitrate-limit #[KMG][/#] server's total bit rate limit (default 0 = no limit)\n"
+ " (optional slash and number of secs interval for averaging\n"
+ " total data rate. Default is 5 seconds)\n"
#if defined(HAVE_SSL)
" --rsa-private-key-path path to the RSA private key used to decrypt\n"
" authentication credentials\n"
@@ -125,11 +131,11 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
#endif //HAVE_SSL
"Client specific:\n"
" -c, --client <host> run in client mode, connecting to <host>\n"
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
" --sctp use SCTP rather than TCP\n"
" -X, --xbind <name> bind SCTP association to links\n"
" --nstreams # number of SCTP streams\n"
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
" -u, --udp use UDP rather than TCP\n"
" --connect-timeout # timeout for control connection setup (ms)\n"
" -b, --bitrate #[KMG][/#] target bitrate in bits/sec (0 for unlimited)\n"
diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c
index 0bc98ba..e0c1ec1 100644
--- a/src/iperf_sctp.c
+++ b/src/iperf_sctp.c
@@ -57,7 +57,7 @@
int
iperf_sctp_recv(struct iperf_stream *sp)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
int r;
r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
@@ -78,7 +78,7 @@ iperf_sctp_recv(struct iperf_stream *sp)
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -89,7 +89,7 @@ iperf_sctp_recv(struct iperf_stream *sp)
int
iperf_sctp_send(struct iperf_stream *sp)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
int r;
r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp);
@@ -103,7 +103,7 @@ iperf_sctp_send(struct iperf_stream *sp)
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -115,7 +115,7 @@ iperf_sctp_send(struct iperf_stream *sp)
int
iperf_sctp_accept(struct iperf_test * test)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
int s;
signed char rbuf = ACCESS_DENIED;
char cookie[COOKIE_SIZE];
@@ -148,7 +148,7 @@ iperf_sctp_accept(struct iperf_test * test)
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -159,7 +159,7 @@ iperf_sctp_accept(struct iperf_test * test)
int
iperf_sctp_listen(struct iperf_test *test)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
struct addrinfo hints, *res;
char portstr[6];
int s, opt, saved_errno;
@@ -270,7 +270,7 @@ iperf_sctp_listen(struct iperf_test *test)
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -281,7 +281,7 @@ iperf_sctp_listen(struct iperf_test *test)
int
iperf_sctp_connect(struct iperf_test *test)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
int s, opt, saved_errno;
char portstr[6];
struct addrinfo hints, *local_res, *server_res;
@@ -527,7 +527,7 @@ iperf_sctp_connect(struct iperf_test *test)
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -535,12 +535,12 @@ iperf_sctp_connect(struct iperf_test *test)
int
iperf_sctp_init(struct iperf_test *test)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
return 0;
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
@@ -552,7 +552,7 @@ iperf_sctp_init(struct iperf_test *test)
int
iperf_sctp_bindx(struct iperf_test *test, int s, int is_server)
{
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
struct addrinfo hints;
char portstr[6];
char *servname;
@@ -701,5 +701,5 @@ out:
#else
i_errno = IENOSCTP;
return -1;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
}
diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c
index 40d99bc..e2ddf7f 100644
--- a/src/iperf_server_api.c
+++ b/src/iperf_server_api.c
@@ -1,5 +1,5 @@
/*
- * iperf, Copyright (c) 2014-2018 The Regents of the University of
+ * iperf, Copyright (c) 2014-2020 The Regents of the University of
* California, through Lawrence Berkeley National Laboratory (subject
* to receipt of any required approvals from the U.S. Dept. of
* Energy). All rights reserved.
@@ -354,6 +354,15 @@ create_server_omit_timer(struct iperf_test * test)
static void
cleanup_server(struct iperf_test *test)
{
+ struct iperf_stream *sp;
+
+ /* Close open streams */
+ SLIST_FOREACH(sp, &test->streams, streams) {
+ FD_CLR(sp->socket, &test->read_set);
+ FD_CLR(sp->socket, &test->write_set);
+ close(sp->socket);
+ }
+
/* Close open test sockets */
if (test->ctrl_sck) {
close(test->ctrl_sck);
@@ -437,12 +446,20 @@ iperf_run_server(struct iperf_test *test)
while (test->state != IPERF_DONE) {
+ // Check if average transfer rate was exceeded (condition set in the callback routines)
+ if (test->bitrate_limit_exceeded) {
+ cleanup_server(test);
+ i_errno = IETOTALRATE;
+ return -1;
+ }
+
memcpy(&read_set, &test->read_set, sizeof(fd_set));
memcpy(&write_set, &test->write_set, sizeof(fd_set));
iperf_time_now(&now);
timeout = tmr_timeout(&now);
result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
+
if (result < 0 && errno != EINTR) {
cleanup_server(test);
i_errno = IESELECT;
@@ -596,6 +613,17 @@ iperf_run_server(struct iperf_test *test)
}
}
test->prot_listener = -1;
+
+ /* Ensure that total requested data rate is not above limit */
+ iperf_size_t total_requested_rate = test->num_streams * test->settings->rate * (test->mode == BIDIRECTIONAL? 2 : 1);
+ if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) {
+ iperf_err(test, "Client total requested throughput rate of %" PRIu64 " bps exceeded %" PRIu64 " bps limit",
+ total_requested_rate, test->settings->bitrate_limit);
+ cleanup_server(test);
+ i_errno = IETOTALRATE;
+ return -1;
+ }
+
if (iperf_set_send_state(test, TEST_START) != 0) {
cleanup_server(test);
return -1;
@@ -647,7 +675,7 @@ iperf_run_server(struct iperf_test *test)
return -1;
}
}
- }
+ }
}
if (result == 0 ||
diff --git a/src/iperf_udp.c b/src/iperf_udp.c
index ab6be5e..2fd7bf5 100644
--- a/src/iperf_udp.c
+++ b/src/iperf_udp.c
@@ -52,7 +52,13 @@
#if defined(HAVE_INTTYPES_H)
# include <inttypes.h>
#else
-# define PRIu64 "llu"
+# ifndef PRIu64
+# if sizeof(long) == 8
+# define PRIu64 "lu"
+# else
+# define PRIu64 "llu"
+# endif
+# endif
#endif
/* iperf_udp_recv
diff --git a/src/iperf_util.c b/src/iperf_util.c
index 412397a..9ca1eec 100644
--- a/src/iperf_util.c
+++ b/src/iperf_util.c
@@ -111,7 +111,7 @@ void fill_with_repeating_pattern(void *out, size_t outsize)
*/
void
-make_cookie(char *cookie)
+make_cookie(const char *cookie)
{
unsigned char *out = (unsigned char*)cookie;
size_t pos;
@@ -267,7 +267,7 @@ get_optional_features(void)
numfeatures++;
#endif /* HAVE_FLOWLABEL */
-#if defined(HAVE_SCTP)
+#if defined(HAVE_SCTP_H)
if (numfeatures > 0) {
strncat(features, ", ",
sizeof(features) - strlen(features) - 1);
@@ -275,7 +275,7 @@ get_optional_features(void)
strncat(features, "SCTP",
sizeof(features) - strlen(features) - 1);
numfeatures++;
-#endif /* HAVE_SCTP */
+#endif /* HAVE_SCTP_H */
#if defined(HAVE_TCP_CONGESTION)
if (numfeatures > 0) {
@@ -402,7 +402,7 @@ iperf_json_printf(const char *format, ...)
/* Debugging routine to dump out an fd_set. */
void
-iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds)
+iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds)
{
int fd;
int comma;
diff --git a/src/iperf_util.h b/src/iperf_util.h
index 76bfd20..b109af2 100644
--- a/src/iperf_util.h
+++ b/src/iperf_util.h
@@ -54,7 +54,7 @@ const char* get_optional_features(void);
cJSON* iperf_json_printf(const char *format, ...);
-void iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds);
+void iperf_dump_fdset(FILE *fp, const char *str, int nfds, fd_set *fds);
#ifndef HAVE_DAEMON
extern int daemon(int nochdir, int noclose);
diff --git a/src/net.c b/src/net.c
index b475ed0..8fde9c3 100644
--- a/src/net.c
+++ b/src/net.c
@@ -121,7 +121,7 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
/* make connection to server */
int
-netdial(int domain, int proto, char *local, int local_port, char *server, int port, int timeout)
+netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout)
{
struct addrinfo hints, *local_res, *server_res;
int s, saved_errno;
@@ -218,7 +218,7 @@ netdial(int domain, int proto, char *local, int local_port, char *server, int po
/***************************************************************/
int
-netannounce(int domain, int proto, char *local, int port)
+netannounce(int domain, int proto, const char *local, int port)
{
struct addrinfo hints, *res;
char portstr[6];
diff --git a/src/net.h b/src/net.h
index 3738d6a..80a2161 100644
--- a/src/net.h
+++ b/src/net.h
@@ -28,8 +28,8 @@
#define __NET_H
int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout);
-int netdial(int domain, int proto, char *local, int local_port, char *server, int port, int timeout);
-int netannounce(int domain, int proto, char *local, int port);
+int netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout);
+int netannounce(int domain, int proto, const char *local, int port);
int Nread(int fd, char *buf, size_t count, int prot);
int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */;
int has_sendfile(void);
diff --git a/test_commands.sh b/test_commands.sh
index 2ed0f82..146d1da 100755
--- a/test_commands.sh
+++ b/test_commands.sh
@@ -29,12 +29,20 @@ host=$1
# force V6
./src/iperf3 -c $host -6 -t 5
./src/iperf3 -c $host -6 -u -t 5
+# FQ rate
+./src/iperf3 -c $host -V -t 5 --fq-rate 5m
+./src/iperf3 -c $host -u -V -t 5 --fq-rate 5m
+# SCTP
+./src/iperf3 -c $host --sctp -V -t 5
# parallel streams
./src/iperf3 -c $host -P 3 -t 5
./src/iperf3 -c $host -u -P 3 -t 5
# reverse mode
./src/iperf3 -c $host -P 2 -t 5 -R
./src/iperf3 -c $host -u -P 2 -t 5 -R
+# bidirectional mode
+./src/iperf3 -c $host -P 2 -t 5 --bidir
+./src/iperf3 -c $host -u -P 2 -t 5 --bidir
# zero copy
./src/iperf3 -c $host -Z -t 5
./src/iperf3 -c $host -Z -t 5 -R