aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
16 files changed, 421 insertions, 87 deletions
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);