From d95a44479668b301c123ab81b662aea72c797556 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 16 Nov 2018 11:00:40 -0800 Subject: [PATCH 01/45] Support SO_BINDTODEVICE This lets iperf work better with multi-homed machines and VRF. Signed-off-by: Ben Greear --- docs/invoking.rst | 4 ++++ src/iperf.h | 2 ++ src/iperf_api.c | 20 ++++++++++++++++++++ src/iperf_api.h | 2 ++ src/iperf_client_api.c | 2 +- src/iperf_locale.c | 4 ++++ src/iperf_locale.h | 1 + src/iperf_sctp.c | 37 +++++++++++++++++++++++++++++++++---- src/iperf_server_api.c | 6 ++++-- src/iperf_tcp.c | 36 +++++++++++++++++++++++++++++++++--- src/iperf_udp.c | 9 ++++++--- src/libiperf.3 | 1 + src/net.c | 36 +++++++++++++++++++++++++++++++++--- src/net.h | 4 ++-- 14 files changed, 146 insertions(+), 18 deletions(-) diff --git a/docs/invoking.rst b/docs/invoking.rst index 37677424a..713087bf4 100644 --- a/docs/invoking.rst +++ b/docs/invoking.rst @@ -159,6 +159,10 @@ the executable. bind to the specific interface associated with address host. If the host has multiple interfaces, it will use the first inter- face by default. + + --bind_dev + bind to the specific network device. This calls SO_BINDTODEVICE, + and may require root permissions. -V, --verbose give more detailed output diff --git a/src/iperf.h b/src/iperf.h index 6ce77f59b..652806158 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -40,6 +40,7 @@ # define _GNU_SOURCE #endif #include +#include // for IFNAMSIZ #if defined(HAVE_CPUSET_SETAFFINITY) #include @@ -252,6 +253,7 @@ struct iperf_test char *server_hostname; /* -c option */ char *tmp_template; char *bind_address; /* first -B option */ + char *bind_dev; /* bind to network device */ TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */ int bind_port; /* --cport option */ int server_port; diff --git a/src/iperf_api.c b/src/iperf_api.c index 3b7e45ef6..efe9dd0b0 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -303,6 +303,12 @@ iperf_get_test_bind_address(struct iperf_test *ipt) return ipt->bind_address; } +char * +iperf_get_test_bind_dev(struct iperf_test *ipt) +{ + return ipt->bind_dev; +} + int iperf_get_test_udp_counters_64bit(struct iperf_test *ipt) { @@ -583,6 +589,12 @@ iperf_set_test_bind_address(struct iperf_test *ipt, char *bnd_address) ipt->bind_address = strdup(bnd_address); } +void +iperf_set_test_bind_dev(struct iperf_test *ipt, char *bnd_dev) +{ + ipt->bind_dev = strdup(bnd_dev); +} + void iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit) { @@ -808,6 +820,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL}, {"window", required_argument, NULL, 'w'}, {"bind", required_argument, NULL, 'B'}, + {"bind_dev", required_argument, NULL, OPT_BIND_DEV}, {"cport", required_argument, NULL, OPT_CLIENT_PORT}, {"set-mss", required_argument, NULL, 'M'}, {"no-delay", no_argument, NULL, 'N'}, @@ -1044,6 +1057,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'B': test->bind_address = strdup(optarg); break; + case OPT_BIND_DEV: + test->bind_dev = strdup(optarg); + break; case OPT_CLIENT_PORT: portno = atoi(optarg); if (portno < 1 || portno > 65535) { @@ -1243,6 +1259,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) usage_long(stdout); exit(0); default: + printf("arg: %d (%c)\n", + (int)flag, (char)flag); usage_long(stderr); exit(1); } @@ -2429,6 +2447,8 @@ iperf_free_test(struct iperf_test *test) free(test->tmp_template); if (test->bind_address) free(test->bind_address); + if (test->bind_dev) + free(test->bind_dev); if (!TAILQ_EMPTY(&test->xbind_addrs)) { struct xbind_entry *xbe; diff --git a/src/iperf_api.h b/src/iperf_api.h index 7643b17ce..74ad5a0e8 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -73,6 +73,7 @@ struct iperf_time; #define OPT_REPEATING_PAYLOAD 18 #define OPT_EXTRA_DATA 19 #define OPT_BIDIRECTIONAL 20 +#define OPT_BIND_DEV 21 /* states */ #define TEST_START 1 @@ -402,6 +403,7 @@ enum { /* Timer errors */ IENEWTIMER = 300, // Unable to create new timer (check perror) IEUPDATETIMER = 301, // Unable to update timer (check perror) + IEBINDDEV = 302, // Unable to bind-to-device (check perror, maybe permissions?) }; diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 20ea6fda5..1b6d7ffd2 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -336,7 +336,7 @@ iperf_connect(struct iperf_test *test) /* Create and connect the control channel */ if (test->ctrl_sck < 0) // Create the control channel using an ephemeral port - test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); + test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); if (test->ctrl_sck < 0) { i_errno = IECONNECT; return -1; diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 0d8a7ecc5..ca8cf535a 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -105,6 +105,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " -A, --affinity n/n,m set CPU affinity\n" #endif /* HAVE_CPU_AFFINITY */ " -B, --bind bind to the interface associated with the address \n" + " --bind_dev bind to the network interface with SO_BINDTODEVICE\n" " -V, --verbose more detailed output\n" " -J, --json output in JSON format\n" " --logfile f send output to a log file\n" @@ -225,6 +226,9 @@ const char client_port[] = const char bind_address[] = "Binding to local address %s\n"; +const char bind_dev[] = +"Binding to local network device %s\n"; + const char bind_port[] = "Binding to local port %s\n"; diff --git a/src/iperf_locale.h b/src/iperf_locale.h index ad784a69a..1df6f638f 100644 --- a/src/iperf_locale.h +++ b/src/iperf_locale.h @@ -36,6 +36,7 @@ extern const char seperator_line[]; extern const char server_port[] ; extern const char client_port[] ; extern const char bind_address[] ; +extern const char bind_dev[] ; extern const char multicast_ttl[] ; extern const char join_multicast[] ; extern const char client_datagram_size[] ; diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index 06e1e230a..5fbdab393 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -49,7 +49,6 @@ #include "net.h" - /* iperf_sctp_recv * * receives the data for SCTP @@ -189,6 +188,21 @@ iperf_sctp_listen(struct iperf_test *test) return -1; } + if (test->bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET6)) { @@ -260,7 +274,7 @@ iperf_sctp_connect(struct iperf_test *test) #if defined(HAVE_SCTP) int s, opt, saved_errno; char portstr[6]; - struct addrinfo hints, *local_res, *server_res; + struct addrinfo hints, *local_res = NULL, *server_res = NULL; if (test->bind_address) { memset(&hints, 0, sizeof(hints)); @@ -285,13 +299,28 @@ iperf_sctp_connect(struct iperf_test *test) s = socket(server_res->ai_family, SOCK_STREAM, IPPROTO_SCTP); if (s < 0) { - if (test->bind_address) - freeaddrinfo(local_res); + freeaddrinfo(local_res); freeaddrinfo(server_res); i_errno = IESTREAMCONNECT; return -1; } + if (test->bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(local_res); + freeaddrinfo(server_res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + /* * Various ways to bind the local end of the connection. * 1. --bind (with or without --cport). diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 40d99bc1e..447d9a456 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -70,7 +70,8 @@ int iperf_server_listen(struct iperf_test *test) { retry: - if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { + if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, + test->server_port)) < 0) { if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { /* If we get "Address family not supported by protocol", that ** probably means we were compiled with IPv6 but the running @@ -585,7 +586,8 @@ iperf_run_server(struct iperf_test *test) FD_CLR(test->listener, &test->read_set); close(test->listener); test->listener = 0; - if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { + if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, + test->server_port)) < 0) { cleanup_server(test); i_errno = IELISTEN; return -1; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 232aaa169..0fd93aeaf 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -195,6 +195,21 @@ iperf_tcp_listen(struct iperf_test *test) return -1; } + if (test->bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + if (test->no_delay) { opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { @@ -364,7 +379,7 @@ iperf_tcp_listen(struct iperf_test *test) int iperf_tcp_connect(struct iperf_test *test) { - struct addrinfo hints, *local_res, *server_res; + struct addrinfo hints, *local_res = NULL, *server_res = NULL; char portstr[6]; int s, opt; socklen_t optlen; @@ -393,13 +408,28 @@ iperf_tcp_connect(struct iperf_test *test) } if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) { - if (test->bind_address) - freeaddrinfo(local_res); + freeaddrinfo(local_res); freeaddrinfo(server_res); i_errno = IESTREAMCONNECT; return -1; } + if (test->bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + test->bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(local_res); + freeaddrinfo(server_res); + i_errno = IEBINDDEV; + errno = saved_errno; + return -1; + } + } + /* * Various ways to bind the local end of the connection. * 1. --bind (with or without --cport). diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 3d37dab67..28f29b5ae 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -417,7 +417,8 @@ iperf_udp_accept(struct iperf_test *test) /* * Create a new "listening" socket to replace the one we were using before. */ - test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); + test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, + test->server_port); if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; return -1; @@ -449,7 +450,8 @@ iperf_udp_listen(struct iperf_test *test) { int s; - if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { + if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, + test->server_port)) < 0) { i_errno = IESTREAMLISTEN; return -1; } @@ -476,7 +478,8 @@ iperf_udp_connect(struct iperf_test *test) int rc; /* Create and bind our local socket. */ - if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { + if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, + test->server_hostname, test->server_port, -1)) < 0) { i_errno = IESTREAMCONNECT; return -1; } diff --git a/src/libiperf.3 b/src/libiperf.3 index e88516d86..a91e882c7 100644 --- a/src/libiperf.3 +++ b/src/libiperf.3 @@ -25,6 +25,7 @@ Setting test parameters: .nf void iperf_set_test_role( struct iperf_test *pt, char role ); void iperf_set_test_bind_address( struct iperf_test *t, char *bind_address ); + void iperf_set_test_bind_dev( struct iperf_test *t, char *bind_dev ); void iperf_set_test_server_hostname( struct iperf_test *t, char *server_host ); void iperf_set_test_server_port( struct iperf_test *t, int server_port ); void iperf_set_test_duration( struct iperf_test *t, int duration ); diff --git a/src/net.c b/src/net.c index 96fb7ede1..4ca57003c 100644 --- a/src/net.c +++ b/src/net.c @@ -60,6 +60,7 @@ #include #endif /* HAVE_POLL_H */ +#include "iperf.h" #include "iperf_util.h" #include "net.h" #include "timer.h" @@ -120,9 +121,9 @@ 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, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout) { - struct addrinfo hints, *local_res, *server_res; + struct addrinfo hints, *local_res = NULL, *server_res = NULL; int s, saved_errno; if (local) { @@ -147,6 +148,21 @@ netdial(int domain, int proto, char *local, int local_port, char *server, int po return -1; } + if (bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(local_res); + freeaddrinfo(server_res); + errno = saved_errno; + return -1; + } + } + /* Bind the local address if given a name (with or without --cport) */ if (local) { if (local_port) { @@ -217,7 +233,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, char *local, const char* bind_dev, int port) { struct addrinfo hints, *res; char portstr[6]; @@ -254,6 +270,20 @@ netannounce(int domain, int proto, char *local, int port) return -1; } + if (bind_dev) { +#ifdef SO_BINDTODEVICE + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, + bind_dev, IFNAMSIZ) < 0) +#endif + { + saved_errno = errno; + close(s); + freeaddrinfo(res); + errno = saved_errno; + return -1; + } + } + opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) { diff --git a/src/net.h b/src/net.h index 3738d6ae8..c85c1a661 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, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout); +int netannounce(int domain, int proto, char *local, const char* bind_dev, 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); From 57d7294a45d4a1d8ac7740ea241a525a63d9dcbc Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 16 Nov 2018 16:09:26 -0800 Subject: [PATCH 02/45] Exit process if we cannot write to outfile. This lets process exit when pipe is closed, for instance when piping output of iperf3 to a script for post processing. Signed-off-by: Ben Greear --- src/iperf_api.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index efe9dd0b0..d4fb6cb3b 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -4139,11 +4139,13 @@ iperf_printf(struct iperf_test *test, const char* format, ...) * easily exceed the size of the line buffer, but which don't need * to be buffered up anyway. */ + int rv; if (test->role == 'c') { if (test->title) fprintf(test->outfile, "%s: ", test->title); va_start(argp, format); r = vfprintf(test->outfile, format, argp); + rv = r; va_end(argp); } else if (test->role == 's') { @@ -4151,7 +4153,7 @@ iperf_printf(struct iperf_test *test, const char* format, ...) va_start(argp, format); r = vsnprintf(linebuffer, sizeof(linebuffer), format, argp); va_end(argp); - fprintf(test->outfile, "%s", linebuffer); + rv = fprintf(test->outfile, "%s", linebuffer); if (test->role == 's' && iperf_get_test_get_server_output(test)) { struct iperf_textline *l = (struct iperf_textline *) malloc(sizeof(struct iperf_textline)); @@ -4159,11 +4161,19 @@ iperf_printf(struct iperf_test *test, const char* format, ...) TAILQ_INSERT_TAIL(&(test->server_output_list), l, textlineentries); } } + + if (rv < 0) { + /* If printing output fails, go ahead and exit, probably broken pipe */ + iperf_errexit(test, "print to outfile failed: %s\n", strerror(errno)); + } return r; } int iflush(struct iperf_test *test) { - return fflush(test->outfile); + int rv = fflush(test->outfile); + if (rv < 0) { + iperf_errexit(test, "fflush on outfile failed: %s\n", strerror(errno)); + } } From 85a0bd86bf4147ee6cd6e803fd385989e93fe0bd Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 19 Dec 2018 15:27:47 -0800 Subject: [PATCH 03/45] Allow pidfile in client mode too. Automated use of iperf needs a way to clean up client-mode connections too, so let the pidfile work in either mode. Signed-off-by: Ben Greear --- src/iperf3.1 | 6 +++--- src/iperf_api.c | 1 - src/iperf_locale.c | 2 +- src/main.c | 12 +++++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/iperf3.1 b/src/iperf3.1 index 731855e2e..ac8c156c1 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -153,6 +153,9 @@ send output to a log file. force flushing output at every interval. Used to avoid buffering when sending output to pipe. .TP +.BR -I ", " --pidfile " \fIfile\fR" +write a file with the process ID, useful for automated process cleanup. +.TP .BR -d ", " --debug " " emit debugging output. Primarily (perhaps exclusively) of use to developers. @@ -171,9 +174,6 @@ run in server mode .BR -D ", " --daemon " " run the server in background as a daemon .TP -.BR -I ", " --pidfile " \fIfile\fR" -write a file with the process ID, most useful when running as a daemon. -.TP .BR -1 ", " --one-off handle one client connection, then exit. .TP diff --git a/src/iperf_api.c b/src/iperf_api.c index d4fb6cb3b..f2d16b79f 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1199,7 +1199,6 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) break; case 'I': test->pidfile = strdup(optarg); - server_flag = 1; break; case OPT_LOGFILE: test->logfile = strdup(optarg); diff --git a/src/iperf_locale.c b/src/iperf_locale.c index ca8cf535a..7d70531ef 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -110,13 +110,13 @@ 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" + " -I, --pidfile file write PID file\n" " -d, --debug emit debugging output\n" " -v, --version show version information and quit\n" " -h, --help show this message and quit\n" "Server specific:\n" " -s, --server run in server mode\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" #if defined(HAVE_SSL) " --rsa-private-key-path path to the RSA private key used to decrypt\n" diff --git a/src/main.c b/src/main.c index fe10a2f4d..4bddecb48 100644 --- a/src/main.c +++ b/src/main.c @@ -133,6 +133,11 @@ run(struct iperf_test *test) /* Ignore SIGPIPE to simplify error handling */ signal(SIGPIPE, SIG_IGN); + if (iperf_create_pidfile(test) < 0) { + i_errno = IEPIDFILE; + iperf_errexit(test, "error - %s", iperf_strerror(i_errno)); + } + switch (test->role) { case 's': if (test->daemon) { @@ -143,10 +148,6 @@ run(struct iperf_test *test) iperf_errexit(test, "error - %s", iperf_strerror(i_errno)); } } - if (iperf_create_pidfile(test) < 0) { - i_errno = IEPIDFILE; - iperf_errexit(test, "error - %s", iperf_strerror(i_errno)); - } for (;;) { int rc; rc = iperf_run_server(test); @@ -165,7 +166,6 @@ run(struct iperf_test *test) break; } } - iperf_delete_pidfile(test); break; case 'c': if (iperf_run_client(test) < 0) @@ -176,6 +176,8 @@ run(struct iperf_test *test) break; } + iperf_delete_pidfile(test); + iperf_catch_sigend(SIG_DFL); signal(SIGPIPE, SIG_DFL); From 5c523fe841d8852e3f3ac5c14ce5279c77c47774 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 20 Dec 2018 14:09:04 -0800 Subject: [PATCH 04/45] Print out netdev and local-ip we bind to. Or empty string if not specified: ----------------------------------------------------------- Server listening on wlan0 5201 ----------------------------------------------------------- Signed-off-by: Ben Greear --- src/iperf_server_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 447d9a456..198b0cf98 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -89,7 +89,9 @@ iperf_server_listen(struct iperf_test *test) if (!test->json_output) { iperf_printf(test, "-----------------------------------------------------------\n"); - iperf_printf(test, "Server listening on %d\n", test->server_port); + iperf_printf(test, "Server listening on %s %s %d\n", + test->bind_dev ? test->bind_dev : "", + test->bind_address ? test->bind_address : "", test->server_port); iperf_printf(test, "-----------------------------------------------------------\n"); if (test->forceflush) iflush(test); From 095abe2195a885a0c3607b0d2a6c39d9e8b17e91 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 11 Feb 2019 07:30:14 -0800 Subject: [PATCH 05/45] Allow specifying precision. This gives better control over the normal text output, for instance: with --precision 4: onnecting to host 10.2.8.1, port 5201 [ 5] local 10.2.8.86 port 55430 connected to 10.2.8.1 port 5201 [ ID] Interval Transfer Bitrate Retr Cwnd [ 5] 0.00-1.00 sec 72538.45 KBytes 72531.4849 KBytes/sec 0 6506.10 KBytes [ 5] 1.00-2.00 sec 49024.00 KBytes 49023.2169 KBytes/sec 0 6506.10 KBytes [ 5] 2.00-3.00 sec 48640.00 KBytes 48641.7019 KBytes/sec 0 6506.10 KBytes ... - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bitrate Retr [ 5] 0.00-60.00 sec 2907.71 MBytes 49624.8823 KBytes/sec 0 sender [ 5] 0.00-60.04 sec 2878.48 MBytes 49092.3559 KBytes/sec receiver Signed-off-by: Ben Greear --- src/iperf.h | 1 + src/iperf_api.c | 49 ++++++++++++++++++++++--------------- src/iperf_locale.c | 1 + src/t_units.c | 20 +++++++-------- src/units.c | 61 +++++++++++++++++++++++++++++++++------------- src/units.h | 4 +-- 6 files changed, 88 insertions(+), 48 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 652806158..bd25f3c58 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -147,6 +147,7 @@ struct iperf_settings iperf_size_t bytes; /* number of bytes to send */ iperf_size_t blocks; /* number of blocks (packets) to send */ char unit_format; /* -f */ + int unit_precision; /* --precision */ int num_ostreams; /* SCTP initmsg settings */ #if defined(HAVE_SSL) char *authtoken; /* Authentication token */ diff --git a/src/iperf_api.c b/src/iperf_api.c index f2d16b79f..813eb8210 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -800,6 +800,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) { {"port", required_argument, NULL, 'p'}, {"format", required_argument, NULL, 'f'}, + {"precision", required_argument, NULL, 'r'}, {"interval", required_argument, NULL, 'i'}, {"daemon", no_argument, NULL, 'D'}, {"one-off", no_argument, NULL, '1'}, @@ -886,7 +887,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL; #endif /* HAVE_SSL */ - while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) { + while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rr:w:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) { switch (flag) { case 'p': portno = atoi(optarg); @@ -896,6 +897,13 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } test->server_port = portno; break; + case 'r': + test->settings->unit_precision = atoi(optarg); + if (test->settings->unit_precision < -1) + test->settings->unit_precision = 1; + else if (test->settings->unit_precision > 30) + test->settings->unit_precision = 30; + break; case 'f': if (!optarg) { i_errno = IEBADFORMAT; @@ -2346,6 +2354,7 @@ iperf_defaults(struct iperf_test *testp) testp->settings->domain = AF_UNSPEC; testp->settings->unit_format = 'a'; + testp->settings->unit_precision = -1; /* auto */ testp->settings->socket_bufsize = 0; /* use autotuning */ testp->settings->blksize = DEFAULT_TCP_BLKSIZE; testp->settings->rate = 0; @@ -2926,9 +2935,9 @@ iperf_print_intermediate(struct iperf_test *test) if (sp) { irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */ - unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A', test->settings->unit_precision); bandwidth = (double) bytes / (double) irp->interval_duration; - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); iperf_time_diff(&sp->result->start_time,&irp->interval_start_time, &temp_time); start_time = iperf_time_in_secs(&temp_time); @@ -3152,14 +3161,15 @@ iperf_print_results(struct iperf_test *test) avg_jitter += sp->jitter; } - unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A', test->settings->unit_precision); + if (sender_time > 0.0) { bandwidth = (double) bytes_sent / (double) sender_time; } else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { if (test->sender_has_retransmits) { /* Sender summary, TCP and SCTP with retransmits. */ @@ -3242,7 +3252,7 @@ iperf_print_results(struct iperf_test *test) percent_sent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 ); percent_received = (int) ( ( (double) bytes_received / (double) sb.st_size ) * 100.0 ); } - unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A'); + unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A', test->settings->unit_precision); if (test->json_output) cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d received: %d size: %d percent_sent: %d percent_received: %d filename: %s", (int64_t) bytes_sent, (int64_t) bytes_received, (int64_t) sb.st_size, (int64_t) percent_sent, (int64_t) percent_received, test->diskfile_name)); else @@ -3250,20 +3260,20 @@ iperf_print_results(struct iperf_test *test) iperf_printf(test, report_diskfile, ubuf, sbuf, percent_sent, test->diskfile_name); } else { - unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A', test->settings->unit_precision); iperf_printf(test, report_diskfile, ubuf, sbuf, percent_received, test->diskfile_name); } } } - unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A', test->settings->unit_precision); if (receiver_time > 0) { bandwidth = (double) bytes_received / (double) receiver_time; } else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { /* Receiver summary, TCP and SCTP */ if (test->json_output) @@ -3305,7 +3315,7 @@ iperf_print_results(struct iperf_test *test) } if (test->num_streams > 1 || test->json_output) { - unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A', test->settings->unit_precision); /* If no tests were run, arbitrarily set bandwidth to 0. */ if (sender_time > 0.0) { bandwidth = (double) total_sent / (double) sender_time; @@ -3313,7 +3323,7 @@ iperf_print_results(struct iperf_test *test) else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { if (test->sender_has_retransmits) { /* Summary sum, TCP with retransmits. */ @@ -3340,7 +3350,7 @@ iperf_print_results(struct iperf_test *test) iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); } } - unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A', test->settings->unit_precision); /* If no tests were run, set received bandwidth to 0 */ if (receiver_time > 0.0) { bandwidth = (double) total_received / (double) receiver_time; @@ -3348,7 +3358,7 @@ iperf_print_results(struct iperf_test *test) else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); if (test->json_output) cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender)); else @@ -3378,12 +3388,12 @@ iperf_print_results(struct iperf_test *test) * server. Output whatever we have. */ if (! (test->role == 's' && !stream_must_be_sender) ) { - unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A', test->settings->unit_precision); iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, sender_total_packets, 0.0, "sender"); } if (! (test->role == 's' && stream_must_be_sender) ) { - unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A', test->settings->unit_precision); /* Compute received bandwidth. */ if (end_time > 0.0) { bandwidth = (double) total_received / (double) receiver_time; @@ -3391,7 +3401,7 @@ iperf_print_results(struct iperf_test *test) else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, "receiver"); } } @@ -3558,14 +3568,14 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * } } - unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A', test->settings->unit_precision); if (irp->interval_duration > 0.0) { bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration; } else { bandwidth = 0.0; } - unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format, test->settings->unit_precision); iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time); st = iperf_time_in_secs(&temp_time); @@ -3578,7 +3588,7 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * if (test->json_output) cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender)); else { - unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A'); + unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A', test->settings->unit_precision); iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:""); } } else { @@ -4175,4 +4185,5 @@ iflush(struct iperf_test *test) if (rv < 0) { iperf_errexit(test, "fflush on outfile failed: %s\n", strerror(errno)); } + return rv; } diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 7d70531ef..93e76a37a 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -99,6 +99,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" "Server or Client:\n" " -p, --port # server port to listen on/connect to\n" " -f, --format [kmgtKMGT] format to report: Kbits, Mbits, Gbits, Tbits\n" + " -r, --precision [-1 - 30] decimal precision for format to report\n" " -i, --interval # seconds between periodic throughput reports\n" " -F, --file name xmit/recv the specified file\n" #if defined(HAVE_CPU_AFFINITY) diff --git a/src/t_units.c b/src/t_units.c index 8fd8bd92e..e11dc9a8c 100644 --- a/src/t_units.c +++ b/src/t_units.c @@ -73,37 +73,37 @@ main(int argc, char **argv) llu = (iperf_size_t) d; assert(llu == unit_atoi("3t")); - unit_snprintf(s, 11, 1024.0, 'A'); + unit_snprintf(s, 11, 1024.0, 'A', -1); assert(strncmp(s, "1.00 KByte", 11) == 0); - unit_snprintf(s, 11, 1024.0 * 1024.0, 'A'); + unit_snprintf(s, 11, 1024.0 * 1024.0, 'A', -1); assert(strncmp(s, "1.00 MByte", 11) == 0); - unit_snprintf(s, 11, 1000.0, 'k'); + unit_snprintf(s, 11, 1000.0, 'k', -1); assert(strncmp(s, "8.00 Kbit", 11) == 0); - unit_snprintf(s, 11, 1000.0 * 1000.0, 'a'); + unit_snprintf(s, 11, 1000.0 * 1000.0, 'a', -1); assert(strncmp(s, "8.00 Mbit", 11) == 0); d = 4.0 * 1024 * 1024 * 1024; - unit_snprintf(s, 11, d, 'A'); + unit_snprintf(s, 11, d, 'A', -1); assert(strncmp(s, "4.00 GByte", 11) == 0); - unit_snprintf(s, 11, d, 'a'); + unit_snprintf(s, 11, d, 'a', -1); assert(strncmp(s, "34.4 Gbit", 11) == 0); d = 4.0 * 1024 * 1024 * 1024 * 1024; - unit_snprintf(s, 11, d, 'A'); + unit_snprintf(s, 11, d, 'A', -1); assert(strncmp(s, "4.00 TByte", 11) == 0); - unit_snprintf(s, 11, d, 'a'); + unit_snprintf(s, 11, d, 'a', -1); assert(strncmp(s, "35.2 Tbit", 11) == 0); d = 4.0 * 1024 * 1024 * 1024 * 1024 * 1024; - unit_snprintf(s, 11, d, 'A'); + unit_snprintf(s, 11, d, 'A', -1); assert(strncmp(s, "4096 TByte", 11) == 0); - unit_snprintf(s, 11, d, 'a'); + unit_snprintf(s, 11, d, 'a', -1); assert(strncmp(s, "36029 Tbit", 11) == 0); return 0; diff --git a/src/units.c b/src/units.c index 7376a0b7f..e547ed057 100644 --- a/src/units.c +++ b/src/units.c @@ -1,3 +1,4 @@ + /*--------------------------------------------------------------- * Copyright (c) 1999,2000,2001,2002,2003 * The Board of Trustees of the University of Illinois @@ -263,14 +264,18 @@ extern "C" * adaptive picks the "best" one based on the number. * s should be at least 11 chars long * (4 digits + space + 5 chars max + null) + * If precision == -1, treat that as old behavior that tries to do 4 characters, + * otherwise, use it as decimial precision. * ------------------------------------------------------------------- */ void unit_snprintf(char *s, int inLen, - double inNum, char inFormat) + double inNum, char inFormat, int precision) { int conv; const char *suffix; const char *format; + char format_custom[40]; + int p = precision; /* convert to bits for [bkmga] */ if (!isupper((int) inFormat)) @@ -303,14 +308,30 @@ extern "C" if (isupper((int) inFormat)) { - while (tmpNum >= 1024.0 && conv < TERA_CONV) + double max = 1024.0; + int z; + for (z = 0; z 2 && precision < 2) + precision = 2; + while (tmpNum >= max && conv < TERA_CONV) { tmpNum /= 1024.0; conv++; } } else { - while (tmpNum >= 1000.0 && conv < TERA_CONV) + double max = 1000.0; + int z; + for (z = 0; z 2 && precision < 2) + precision = 2; + while (tmpNum >= max && conv < TERA_CONV) { tmpNum /= 1000.0; conv++; @@ -330,22 +351,28 @@ extern "C" suffix = label_byte[conv]; } - /* print such that we always fit in 4 places */ - if (inNum < 9.995) - { /* 9.995 would be rounded to 10.0 */ - format = "%4.2f %s";/* #.## */ - } else if (inNum < 99.95) - { /* 99.95 would be rounded to 100 */ - format = "%4.1f %s";/* ##.# */ - } else if (inNum < 999.5) - { /* 999.5 would be rounded to 1000 */ - format = "%4.0f %s";/* ### */ - } else - { /* 1000-1024 fits in 4 places If not using + if (precision == -1) { + /* print such that we always fit in 4 places */ + if (inNum < 9.995) + { /* 9.995 would be rounded to 10.0 */ + format = "%4.2f %s";/* #.## */ + } else if (inNum < 99.95) + { /* 99.95 would be rounded to 100 */ + format = "%4.1f %s";/* ##.# */ + } else if (inNum < 999.5) + { /* 999.5 would be rounded to 1000 */ + format = "%4.0f %s";/* ### */ + } else + { /* 1000-1024 fits in 4 places If not using * Adaptive sizes then this code will not * control spaces */ - format = "%4.0f %s";/* #### */ - } + format = "%4.0f %s";/* #### */ + } + } + else { + snprintf(format_custom, sizeof(format_custom), "%%0.%df %%s", precision); + format = format_custom; + } snprintf(s, inLen, format, inNum, suffix); } /* end unit_snprintf */ diff --git a/src/units.h b/src/units.h index 6ab921613..d37ea783f 100644 --- a/src/units.h +++ b/src/units.h @@ -25,10 +25,10 @@ * file for complete information. */ enum { - UNIT_LEN = 32 + UNIT_LEN = 64 }; double unit_atof( const char *s ); double unit_atof_rate( const char *s ); iperf_size_t unit_atoi( const char *s ); -void unit_snprintf( char *s, int inLen, double inNum, char inFormat ); +void unit_snprintf( char *s, int inLen, double inNum, char inFormat, int precision ); From 6aa4c808a24a3b3726c2764721ad6ddcb224beba Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sun, 20 Oct 2019 20:59:54 -0700 Subject: [PATCH 06/45] iperf3: Support cross-compiling with mingw to create win32 executable. Needs more testing. Signed-off-by: Ben Greear --- README.md | 20 +++++ configure | 9 +- configure.ac | 9 +- src/Makefile.mingw | 66 +++++++++++++++ src/cjson.c | 2 +- src/dscp.c | 2 +- src/iperf.h | 62 +++++++++++++- src/iperf_api.c | 23 ++--- src/iperf_api.h | 3 + src/iperf_auth.c | 19 ++++- src/iperf_auth.h | 133 +++++++++++++++++++++++++++++ src/iperf_client_api.c | 9 +- src/iperf_error.c | 1 - src/iperf_sctp.c | 4 + src/iperf_sctp.h | 4 + src/iperf_server_api.c | 4 +- src/iperf_tcp.c | 34 ++++---- src/iperf_udp.c | 18 ++-- src/iperf_util.c | 14 ++++ src/iperf_util.h | 3 + src/main.c | 27 +++++- src/net.c | 185 +++++++++++++++++++++++++++++++++++++++-- src/net.h | 4 + src/tcp_info.c | 4 +- src/units.c | 2 + 25 files changed, 598 insertions(+), 63 deletions(-) create mode 100644 src/Makefile.mingw diff --git a/README.md b/README.md index 356784b3b..1472470d1 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,26 @@ None. (Note: If configure fails, try running `./bootstrap.sh` first) +### Building with mingw ### + autoconf; cross-configure.sh; cd src && make -f Makefile.mingw + +It will fail with mysterious errors if you do not copy these libraries from +the build machine to the install dir on the windows machine (possibly not all of these +are needed) + + Directory: C:\Users\Ben Greear\Desktop\iperf + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +-a--- 10/20/2019 8:51 PM 326195 iperf3.exe +-a--- 10/20/2019 8:37 PM 1690887 libcrypto-10.dll +-a--- 10/20/2019 8:37 PM 1013208 libgcc_s_sjlj-1.dll +-a--- 10/20/2019 8:33 PM 67090 libgnurx-0.dll +-a--- 10/20/2019 8:35 PM 393870 libssl-10.dll +-a--- 10/20/2019 8:47 PM 62672 libwinpthread-1.dll +-a--- 10/20/2019 8:33 PM 91368 zlib1.dll + + Invoking iperf3 --------------- diff --git a/configure b/configure index 217f1279d..3fcca43c6 100755 --- a/configure +++ b/configure @@ -12130,6 +12130,11 @@ CC=$lt_save_CC +case "$host" in + *-mingw*) + LDFLAGS="$LDFLAGS -lws2_32" +esac + # Add -Wall if we are using GCC. if test "x$GCC" = "xyes"; then CFLAGS="$CFLAGS -Wall" @@ -12390,7 +12395,7 @@ if test "$ac_res" != no; then : else echo "socket()" -exit 1 +#exit 1 fi @@ -12453,7 +12458,7 @@ if test "$ac_res" != no; then : else echo "inet_ntop()" -exit 1 +#exit 1 fi diff --git a/configure.ac b/configure.ac index d27af7d08..4c6e916ef 100644 --- a/configure.ac +++ b/configure.ac @@ -47,6 +47,11 @@ AC_PROG_RANLIB AC_PROG_LN_S AC_PROG_LIBTOOL +case "$host" in + *-mingw*) + LDFLAGS="$LDFLAGS -lws2_32" +esac + # Add -Wall if we are using GCC. if test "x$GCC" = "xyes"; then CFLAGS="$CFLAGS -Wall" @@ -74,13 +79,13 @@ exit 1 # On illumos we need -lsocket AC_SEARCH_LIBS(socket, [socket], [], [ echo "socket()" -exit 1 +#exit 1 ]) # On illumos inet_ntop in in -lnsl AC_SEARCH_LIBS(inet_ntop, [nsl], [], [ echo "inet_ntop()" -exit 1 +#exit 1 ]) # Checks for typedefs, structures, and compiler characteristics. diff --git a/src/Makefile.mingw b/src/Makefile.mingw new file mode 100644 index 000000000..a02effa08 --- /dev/null +++ b/src/Makefile.mingw @@ -0,0 +1,66 @@ + +#CC = i386-mingw32-gcc +#CCC = i386-mingw32-g++ +CC = i686-w64-mingw32-gcc +CCC = i686-w64-mingw32-g++ +AR = i686-w64-mingw32-ar +RANLIB = i686-w64-mingw32-ranlib + + +# WINVER 0501 is XP (2003), and higher +# WINVER 0600 is Vista +CCFLAGS = $(BASIC_CCFLAGS) -DHAVE_SNPRINTF -DHAVE_VSNPRINTF \ + -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 -DHAVE_REMOTE + +BASIC_LDLIBS=-lm -lws2_32 +LDLIBS = $(BASIC_LDLIBS) -liphlpapi -lz -lssl -lcrypto + +LDFLAGS := $(LDFLAGS) + +# Other main classes +# t_api.c t_timer.c t_units.c t_uuid.c + +# makefile template +COMMON_SRCS = cjson.c iperf_auth.c iperf_locale.c iperf_tcp.c \ + iperf_util.c units.c \ + dscp.c iperf_client_api.c iperf_sctp.c iperf_time.c main.c tcp_info.c \ + iperf_api.c iperf_error.c iperf_server_api.c iperf_udp.c net.c timer.c + +COMMON_OBJS = cjson.o iperf_auth.o iperf_locale.o iperf_tcp.o \ + iperf_util.o units.o \ + dscp.o iperf_client_api.o iperf_sctp.o iperf_time.o main.o tcp_info.o \ + iperf_api.o iperf_error.o iperf_server_api.o iperf_udp.o net.o timer.o + + +TARG = iperf3.exe + +ALL_OBJS=${COMMON_OBJS} +ALL_SRCS=${COMMON_SRCS} + +${TARG}: $(COMMON_OBJS) + $(CC) $(CCFLAGS) $(LDFLAGS) -o ${TARG} $(COMMON_OBJS)\ + $(LDLIBS) \ + -lwinmm -lsetupapi -luuid + +$(ALL_OBJS): %.o: %.c Makefile.mingw + @echo " " + @echo "Making object file $<" + $(CC) $(CCFLAGS) -c $< + +clean: + rm -f ${ALL_OBJS} + +purge: clean + rm -f *~ *.flc *lo *.o *.la ${TARG} \ + make.depend *.dll *.exe + +ifneq "$(PURGEMEHARDER)" "1" +# Dependencies are supposed to be in a file ``make.depend'' +# which is inclduded by make. +include make.depend +# Because of the following rule, ``make'' will attempt to +# create ``make.depend'' if it does not exist or if one +# of the files in $(COMMON_SRCS) is more recent than ``make.depend'' +make.depend: $(ALL_SRCS) Makefile.mingw + $(CC) -M $(CCFLAGS) $(ALL_SRCS) > make.depend +endif diff --git a/src/cjson.c b/src/cjson.c index a31874dbf..cd4034472 100644 --- a/src/cjson.c +++ b/src/cjson.c @@ -372,7 +372,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) /* overflow of int, use LLONG_MAX if possible */ if (needed <= LLONG_MAX) { - newsize = LLONG_MAX; + newsize = (size_t)LLONG_MAX; } else { diff --git a/src/dscp.c b/src/dscp.c index 329b3043d..d3f03bef5 100644 --- a/src/dscp.c +++ b/src/dscp.c @@ -31,7 +31,7 @@ #include #ifdef WIN32 -#define strcasecmp(a,b) _stricmp(a,b) +//#define strcasecmp(a,b) _stricmp(a,b) #define snprintf _snprintf #endif diff --git a/src/iperf.h b/src/iperf.h index bd25f3c58..e534d0232 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -29,18 +29,72 @@ #include "iperf_config.h" +#ifndef __WIN32__ +#include +#include +#include +#include +#include +#include +#include +#include // for IFNAMSIZ +#include +#include +#else +#include +#include +typedef int socklen_t; + +/* From here: https://github.com/eclipse/paho.mqtt.c/issues/577 */ +#define htonll(x) ((1==htonl(1)) ? (x) : ((((uint64_t)htonl((x)) & 0xFFFFFFFFUL)) << 32) | ((uint64_t)(htonl((uint32_t)((x)))) >> 32)) +#define ntohll(x) ((1==ntohl(1)) ? (x) : ((((uint64_t)ntohl((x)) & 0xFFFFFFFFUL)) << 32) | ((uint64_t)(ntohl((uint32_t)((x)))) >> 32)) + +#define LODWORD(l) ((DWORD)((DWORDLONG)(l))) +#define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF)) + +/* implementation of mman for windows */ +#ifndef SYS_MMAN_H +#define SYS_MMAN_H + +#define PROT_NONE 0x00 /* No access. */ +#define PROT_READ 0x04 /* Pages can be read. */ +#define PROT_WRITE 0x02 /* Pages can be written. */ +#define PROT_EXEC 0x01 /* Pages can be executed. */ + +/* Flags contain mapping type, sharing type and options. */ + +/* Mapping type (must choose one and only one of these). */ +#define MAP_FILE 0x0001 /* Mapped from a file or device. */ +#define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */ +#define MAP_TYPE 0x000f /* Mask for type field. */ +#define MAP_ANONYMOUS MAP_ANON /* Linux name. */ + +/* Sharing types (must choose one and only one of these). */ +#define MAP_COPY 0x0020 /* Virtual copy of region at mapping time. */ +#define MAP_SHARED 0x0010 /* Share changes. */ +#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */ + +/* Other flags. */ +#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */ +#define MAP_NOEXTEND 0x0200 /* For MAP_FILE, don't change file size. */ +#define MAP_HASSEMPHORE 0x0400 /* Region may contain semaphores. */ +#define MAP_INHERIT 0x0800 /* Region is retained after exec. */ + +#define MAP_FAILED ((void *)-1) + +void *mmap (void *, size_t, int, int, int, off_t); +int munmap (void *, size_t); +#endif +#endif + #include #include #ifdef HAVE_STDINT_H #include #endif -#include -#include #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif -#include -#include // for IFNAMSIZ #if defined(HAVE_CPUSET_SETAFFINITY) #include diff --git a/src/iperf_api.c b/src/iperf_api.c index 813eb8210..be25191ce 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -41,18 +41,11 @@ #include #include #include -#include #include -#include -#include -#include #ifdef HAVE_STDINT_H #include #endif -#include #include -#include -#include #include #include #include @@ -3780,7 +3773,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) if ((opt = test->settings->tos)) { if (getsockdomain(sp->socket) == AF_INET6) { #ifdef IPV6_TCLASS - if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) { + if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, (const char*)&opt, sizeof(opt)) < 0) { i_errno = IESETCOS; return -1; } @@ -3789,7 +3782,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) return -1; #endif } else { - if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) { + if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, (const char*)&opt, sizeof(opt)) < 0) { i_errno = IESETTOS; return -1; } @@ -3882,7 +3875,9 @@ diskfile_recv(struct iperf_stream *sp) r = sp->rcv2(sp); if (r > 0) { (void) write(sp->diskfile_fd, sp->buffer, r); +#ifndef __WIN32__ (void) fsync(sp->diskfile_fd); +#endif } return r; } @@ -3893,7 +3888,9 @@ iperf_catch_sigend(void (*handler)(int)) { signal(SIGINT, handler); signal(SIGTERM, handler); +#ifndef __WIN32__ signal(SIGHUP, handler); +#endif } /** @@ -3929,6 +3926,10 @@ iperf_got_sigend(struct iperf_test *test) iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno)); } +#ifdef __WIN32__ + +#endif + /* Try to write a PID file if requested, return -1 on an error. */ int iperf_create_pidfile(struct iperf_test *test) @@ -3947,6 +3948,7 @@ iperf_create_pidfile(struct iperf_test *test) pid = atoi(buf); if (pid > 0) { +#ifndef __WIN32__ /* don't know how to kill on windows */ /* See if the process exists. */ if (kill(pid, 0) == 0) { /* @@ -3958,6 +3960,7 @@ iperf_create_pidfile(struct iperf_test *test) test->pidfile = NULL; iperf_errexit(test, "Another instance of iperf3 appears to be running"); } +#endif } } } @@ -4148,7 +4151,7 @@ iperf_printf(struct iperf_test *test, const char* format, ...) * easily exceed the size of the line buffer, but which don't need * to be buffered up anyway. */ - int rv; + int rv = -1; if (test->role == 'c') { if (test->title) fprintf(test->outfile, "%s: ", test->title); diff --git a/src/iperf_api.h b/src/iperf_api.h index 74ad5a0e8..bebf81feb 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -27,7 +27,9 @@ #ifndef __IPERF_API_H #define __IPERF_API_H +#ifndef __WIN32__ #include +#endif #include #include #include @@ -38,6 +40,7 @@ extern "C" { /* open extern "C" */ #endif +#include "iperf.h" struct iperf_test; struct iperf_stream_result; diff --git a/src/iperf_auth.c b/src/iperf_auth.c index 0a5f53323..23fc23f7c 100644 --- a/src/iperf_auth.c +++ b/src/iperf_auth.c @@ -25,16 +25,18 @@ * for complete information. */ -#include "iperf_config.h" +#include "iperf_auth.h" +#include #include #include -#include #include /* FreeBSD needs _WITH_GETLINE to enable the getline() declaration */ #define _WITH_GETLINE #include +#ifndef __WIN32__ #include +#endif #if defined(HAVE_SSL) @@ -116,7 +118,12 @@ int Base64Encode(const unsigned char* buffer, const size_t length, char** b64tex BIO_write(bio, buffer, length); BIO_flush(bio); BIO_get_mem_ptr(bio, &bufferPtr); +#ifndef __WIN32__ *b64text = strndup( (*bufferPtr).data, (*bufferPtr).length ); +#else + *b64text = malloc((*bufferPtr).length); + strncpy(*b64text, (*bufferPtr).data, (*bufferPtr).length); +#endif BIO_free_all(bio); return (0); //success @@ -275,7 +282,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); @@ -303,9 +310,10 @@ int decode_auth_setting(int enable_debug, char *authtoken, EVP_PKEY *private_key #endif //HAVE_SSL ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) { - struct termios old, new; ssize_t nread; +#ifndef __WIN32__ + struct termios old, new; /* Turn echoing off and fail if we can't. */ if (tcgetattr (fileno (stream), &old) != 0) return -1; @@ -313,13 +321,16 @@ ssize_t iperf_getpass (char **lineptr, size_t *n, FILE *stream) { new.c_lflag &= ~ECHO; if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0) return -1; +#endif /* Read the password. */ printf("Password: "); nread = getline (lineptr, n, stream); +#ifndef __WIN32__ /* Restore terminal. */ (void) tcsetattr (fileno (stream), TCSAFLUSH, &old); +#endif //strip the \n or \r\n chars char *buf = *lineptr; diff --git a/src/iperf_auth.h b/src/iperf_auth.h index 0dd6c4cdc..3f5ce64a9 100644 --- a/src/iperf_auth.h +++ b/src/iperf_auth.h @@ -25,10 +25,143 @@ * for complete information. */ +#include "iperf_config.h" + #include #include #include +#ifdef __WIN32__ + +typedef intptr_t ssize_t; + +ssize_t getline(char **lineptr, size_t *n, FILE *stream); + +/* Replacement termios.h for MinGW32. + Copyright (C) 2008 CodeSourcery, Inc. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +typedef unsigned char cc_t; +typedef unsigned int tcflag_t; + +#define NCCS 18 + +struct termios +{ + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_cc[NCCS]; +}; + +#define VEOF 0 +#define VEOL 1 +#define VERASE 2 +#define VINTR 3 +#define VKILL 4 +#define VMIN 5 +#define VQUIT 6 +#define VSTART 7 +#define VSTOP 8 +#define VSUSP 9 +#define VTIME 10 +#define VEOL2 11 +#define VWERASE 12 +#define VREPRINT 13 +#define VLNEXT 15 +#define VDISCARD 16 + +#define _POSIX_VDISABLE '\0' + +#define BRKINT 0x1 +#define ICRNL 0x2 +#define IGNBRK 0x4 +#define IGNCR 0x8 +#define IGNPAR 0x10 +#define INLCR 0x20 +#define INPCK 0x40 +#define ISTRIP 0x80 +#define IXANY 0x100 +#define IXOFF 0x200 +#define IXON 0x400 +#define PARMRK 0x800 + +#define OPOST 0x1 +#define ONLCR 0x2 +#define OCRNL 0x4 +#define ONOCR 0x8 +#define ONLRET 0x10 +#define OFILL 0x20 + +#define CSIZE 0x3 +#define CS5 0x0 +#define CS6 0x1 +#define CS7 0x2 +#define CS8 0x3 +#define CSTOPB 0x4 +#define CREAD 0x8 +#define PARENB 0x10 +#define PARODD 0x20 +#define HUPCL 0x40 +#define CLOCAL 0x80 + +#define ECHO 0x1 +#define ECHOE 0x2 +#define ECHOK 0x4 +#define ECHONL 0x8 +#define ICANON 0x10 +#define IEXTEN 0x20 +#define ISIG 0x40 +#define NOFLSH 0x80 +#define TOSTOP 0x100 +#define FLUSHO 0x200 + +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#define TCIOFF 0 +#define TCION 1 +#define TCOOFF 2 +#define TCOON 3 + +int tcgetattr (int fd, struct termios *buf); +int tcsetattr (int fd, int actions, const struct termios *buf); +int tcdrain (int fd); +int tcflow (int fd, int action); + +/* We want to intercept TIOCGWINSZ, but not FIONREAD. No need to forward + TIOCSWINSZ; readline only uses it to suspend if in the background. + Readline doesn't make any other ioctl calls on mingw. */ + +#include + +struct winsize +{ + unsigned short ws_row; + unsigned short ws_col; +}; + +int mingw_getwinsize (struct winsize *window_size); +#define TIOCGWINSZ 0x42424240 +#define TIOCSWINSZ 0x42424241 +#define ioctl(fd, op, arg) \ + (((op) == TIOCGWINSZ) ? mingw_getwinsize (arg) \ + : ((op) == TIOCSWINSZ) ? -1 \ + : ioctlsocket (fd, op, arg)) + +#endif /* win32 */ + int test_load_pubkey_from_file(const char *public_keyfile); int test_load_private_key_from_file(const char *private_keyfile); EVP_PKEY *load_pubkey_from_file(const char *file); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 1b6d7ffd2..81bf2d610 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -32,10 +32,12 @@ #include #include #include +#ifndef __WIN32__ #include #include #include #include +#endif #include "iperf.h" #include "iperf_api.h" @@ -354,7 +356,12 @@ iperf_connect(struct iperf_test *test) socklen_t len; len = sizeof(opt); - if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) { +#ifdef __WIN32__ + if (1) +#else + if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) +#endif + { test->ctrl_sck_mss = 0; } else { diff --git a/src/iperf_error.c b/src/iperf_error.c index fd3cccca6..068c44e2b 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -26,7 +26,6 @@ */ #include #include -#include #include #include #include diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index 5fbdab393..7bf93a1fc 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -24,6 +24,8 @@ * This code is distributed under a BSD style license, see the LICENSE * file for complete information. */ +#ifndef __WIN32__ + #include "iperf_config.h" #include @@ -684,3 +686,5 @@ iperf_sctp_bindx(struct iperf_test *test, int s, int is_server) return -1; #endif /* HAVE_SCTP */ } + +#endif /* win32 */ diff --git a/src/iperf_sctp.h b/src/iperf_sctp.h index 764c410df..2848b1e9c 100644 --- a/src/iperf_sctp.h +++ b/src/iperf_sctp.h @@ -24,6 +24,8 @@ * This code is distributed under a BSD style license, see the LICENSE * file for complete information. */ +#ifndef __WIN32__ + #ifndef IPERF_SCTP_H #define IPERF_SCTP_H @@ -66,3 +68,5 @@ int iperf_sctp_init(struct iperf_test *test); int iperf_sctp_bindx(struct iperf_test *test, int s, int is_server); #endif + +#endif diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 198b0cf98..6b891afe2 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -35,16 +35,18 @@ #include #include #include +#ifndef __WIN32__ #include #include #include #include #include +#include +#endif #ifdef HAVE_STDINT_H #include #endif #include -#include #include #include diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 0fd93aeaf..69fdb2563 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -29,12 +29,14 @@ #include #include #include +#ifndef __WIN32__ #include #include #include #include -#include #include +#endif +#include #include #include "iperf.h" @@ -96,7 +98,7 @@ iperf_tcp_send(struct iperf_stream *sp) sp->result->bytes_sent_this_interval += r; if (sp->test->debug) - printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); + printf("sent %d bytes of %d, total %llu\n", r, sp->settings->blksize, (long long unsigned)sp->result->bytes_sent); return r; } @@ -212,7 +214,7 @@ iperf_tcp_listen(struct iperf_test *test) if (test->no_delay) { opt = 1; - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(res); @@ -222,6 +224,7 @@ iperf_tcp_listen(struct iperf_test *test) } } // XXX: Setting MSS is very buggy! +#ifndef __WIN32__ if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; @@ -232,8 +235,9 @@ iperf_tcp_listen(struct iperf_test *test) return -1; } } +#endif if ((opt = test->settings->socket_bufsize)) { - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(res); @@ -241,7 +245,7 @@ iperf_tcp_listen(struct iperf_test *test) i_errno = IESETBUF; return -1; } - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(res); @@ -274,7 +278,7 @@ iperf_tcp_listen(struct iperf_test *test) } } opt = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(res); @@ -295,7 +299,7 @@ iperf_tcp_listen(struct iperf_test *test) else opt = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - (char *) &opt, sizeof(opt)) < 0) { + (const char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(res); @@ -327,7 +331,7 @@ iperf_tcp_listen(struct iperf_test *test) /* Read back and verify the sender socket buffer size */ optlen = sizeof(sndbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; close(s); errno = saved_errno; @@ -344,7 +348,7 @@ iperf_tcp_listen(struct iperf_test *test) /* Read back and verify the receiver socket buffer size */ optlen = sizeof(rcvbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; close(s); errno = saved_errno; @@ -494,7 +498,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Set socket options */ if (test->no_delay) { opt = 1; - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(server_res); @@ -503,6 +507,7 @@ iperf_tcp_connect(struct iperf_test *test) return -1; } } +#ifndef __WIN32__ if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; @@ -513,8 +518,9 @@ iperf_tcp_connect(struct iperf_test *test) return -1; } } +#endif if ((opt = test->settings->socket_bufsize)) { - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(server_res); @@ -522,7 +528,7 @@ iperf_tcp_connect(struct iperf_test *test) i_errno = IESETBUF; return -1; } - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; close(s); freeaddrinfo(server_res); @@ -534,7 +540,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Read back and verify the sender socket buffer size */ optlen = sizeof(sndbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; close(s); freeaddrinfo(server_res); @@ -552,7 +558,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Read back and verify the receiver socket buffer size */ optlen = sizeof(rcvbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; close(s); freeaddrinfo(server_res); diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 28f29b5ae..65d97ca0a 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -30,14 +30,16 @@ #include #include #include +#ifndef __WIN32__ #include #include #include +#include +#endif #ifdef HAVE_STDINT_H #include #endif #include -#include #include "iperf.h" #include "iperf_api.h" @@ -270,11 +272,11 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) socklen_t optlen; if ((opt = test->settings->socket_bufsize)) { - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&opt, sizeof(opt)) < 0) { i_errno = IESETBUF; return -1; } - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&opt, sizeof(opt)) < 0) { i_errno = IESETBUF; return -1; } @@ -282,7 +284,7 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) /* Read back and verify the sender socket buffer size */ optlen = sizeof(sndbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { i_errno = IESETBUF; return -1; } @@ -304,7 +306,7 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) /* Read back and verify the receiver socket buffer size */ optlen = sizeof(rcvbuf_actual); - if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) { + if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcvbuf_actual, &optlen) < 0) { i_errno = IESETBUF; return -1; } @@ -359,7 +361,7 @@ iperf_udp_accept(struct iperf_test *test) * of the socket to the client. */ len = sizeof(sa_peer); - if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { + if ((sz = recvfrom(test->prot_listener, (char*)&buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { i_errno = IESTREAMACCEPT; return -1; } @@ -533,7 +535,7 @@ iperf_udp_connect(struct iperf_test *test) /* 30 sec timeout for a case when there is a network problem. */ tv.tv_sec = 30; tv.tv_usec = 0; - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval)); + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval)); #endif /* @@ -550,7 +552,7 @@ iperf_udp_connect(struct iperf_test *test) /* * Wait until the server replies back to us. */ - if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) { + if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { i_errno = IESTREAMREAD; return -1; } diff --git a/src/iperf_util.c b/src/iperf_util.c index 412397a08..c246849e4 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -37,11 +37,13 @@ #include #include #include +#ifndef __WIN32__ #include #include #include #include #include +#endif #include #include #include @@ -189,6 +191,11 @@ timeval_diff(struct timeval * tv0, struct timeval * tv1) void cpu_util(double pcpu[3]) { +#ifdef __WIN32__ + pcpu[0] = 0; + pcpu[1] = 0; + pcpu[2] = 0; +#else static struct iperf_time last; static clock_t clast; static struct rusage rlast; @@ -221,11 +228,15 @@ cpu_util(double pcpu[3]) pcpu[0] = (((ctemp - clast) * 1000000.0 / CLOCKS_PER_SEC) / timediff) * 100; pcpu[1] = (userdiff / timediff) * 100; pcpu[2] = (systemdiff / timediff) * 100; +#endif } const char * get_system_info(void) { +#ifdef __WIN32__ + return "Windows"; +#else static char buf[1024]; struct utsname uts; @@ -236,6 +247,7 @@ get_system_info(void) uts.release, uts.version, uts.machine); return buf; +#endif } @@ -425,6 +437,7 @@ iperf_dump_fdset(FILE *fp, char *str, int nfds, fd_set *fds) * Cobbled together from various daemon(3) implementations, * not intended to be general-purpose. */ #ifndef HAVE_DAEMON +#ifndef __WIN32__ int daemon(int nochdir, int noclose) { pid_t pid = 0; @@ -482,6 +495,7 @@ int daemon(int nochdir, int noclose) return (0); } #endif /* HAVE_DAEMON */ +#endif /* Compatibility version of getline(3) for systems that don't have it.. */ #ifndef HAVE_GETLINE diff --git a/src/iperf_util.h b/src/iperf_util.h index 76bfd20fe..dfaeb23d1 100644 --- a/src/iperf_util.h +++ b/src/iperf_util.h @@ -29,8 +29,11 @@ #include "iperf_config.h" #include "cjson.h" +#ifndef __WIN32__ #include +#endif #include +#include "iperf.h" int readentropy(void *out, size_t outsize); diff --git a/src/main.c b/src/main.c index 4bddecb48..832e172c2 100644 --- a/src/main.c +++ b/src/main.c @@ -36,11 +36,7 @@ #ifdef HAVE_STDINT_H #include #endif -#include #include -#include -#include -#include #include "iperf.h" #include "iperf_api.h" @@ -58,6 +54,20 @@ main(int argc, char **argv) { struct iperf_test *test; +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 0 ); + if ((err = WSAStartup( wVersionRequested, &wsaData )) != 0) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + fprintf(stderr, "ERROR: Could not load Winsock 2.0 DLLs, err: %d\n", err); + return err; + } +#endif + // XXX: Setting the process affinity requires root on most systems. // Is this a feature we really need? #ifdef TEST_PROC_AFFINITY @@ -93,6 +103,7 @@ main(int argc, char **argv) #endif test = iperf_new_test(); + if (!test) iperf_errexit(NULL, "create new test error - %s", iperf_strerror(i_errno)); iperf_defaults(test); /* sets defaults */ @@ -130,8 +141,10 @@ run(struct iperf_test *test) if (setjmp(sigend_jmp_buf)) iperf_got_sigend(test); +#ifndef __WIN32__ /* Ignore SIGPIPE to simplify error handling */ signal(SIGPIPE, SIG_IGN); +#endif if (iperf_create_pidfile(test) < 0) { i_errno = IEPIDFILE; @@ -141,12 +154,16 @@ run(struct iperf_test *test) switch (test->role) { case 's': if (test->daemon) { +#ifndef __WIN32__ int rc; rc = daemon(0, 0); if (rc < 0) { i_errno = IEDAEMON; iperf_errexit(test, "error - %s", iperf_strerror(i_errno)); } +#else + iperf_errexit(test, "daemon mode not supported on windows."); +#endif } for (;;) { int rc; @@ -179,7 +196,9 @@ run(struct iperf_test *test) iperf_delete_pidfile(test); iperf_catch_sigend(SIG_DFL); +#ifndef __WIN32__ signal(SIGPIPE, SIG_DFL); +#endif return 0; } diff --git a/src/net.c b/src/net.c index 4ca57003c..681c37e6e 100644 --- a/src/net.c +++ b/src/net.c @@ -29,12 +29,14 @@ #include #include #include +#ifndef __WIN32__ #include #include #include #include -#include #include +#endif +#include #include #include #include @@ -72,6 +74,28 @@ */ extern int gerror; +#ifdef __WIN32__ + +void nonblock(int s) { + unsigned long nb = 1; + if (ioctlsocket(s, FIONBIO, &nb) == SOCKET_ERROR) { + //VLOG_ERR(VLOG << "Error setting Connection FIONBIO: " + // << WSAGetLastError()); + } + else { + //VLOG << "Made socket: " << s << " non-blocking: " << msg << endl; + } +} +#else +void nonblock(int s) { + //VLOG_TRC(VLOG << "in other nonblock, msg: " << msg << endl); + if (fcntl(s, F_SETFL, O_NDELAY) == -1) { + //VLOG << "ERROR: fcntl (!LINUX), executing nonblock: " + // << LFSTRERROR << endl; + }//if +}//nonblock +#endif + /* * timeout_connect adapted from netcat, via OpenBSD and FreeBSD * Copyright (c) 2001 Eric Jackson @@ -80,25 +104,42 @@ int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout) { - struct pollfd pfd; socklen_t optlen; int flags, optval; int ret; flags = 0; if (timeout != -1) { - flags = fcntl(s, F_GETFL, 0); - if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) - return -1; +#ifndef __WIN32__ + flags = fcntl(s, F_GETFL, 0); +#endif + nonblock(s); } if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { +#ifndef __WIN32__ + struct pollfd pfd; pfd.fd = s; pfd.events = POLLOUT; - if ((ret = poll(&pfd, 1, timeout)) == 1) { + if ((ret = poll(&pfd, 1, timeout)) == 1) +#else + fd_set write_fds; + FD_ZERO(&write_fds); //Zero out the file descriptor set + FD_SET(s, &write_fds); //Set the current socket file descriptor into the set + + //We are going to use select to wait for the socket to connect + struct timeval tv; //Time value struct declaration + tv.tv_sec = timeout / 1000; //The second portion of the struct + tv.tv_usec = (timeout % 1000) * 1000; //The microsecond portion of the struct + + //DEBUG: This is ALWAYS 1 + int select_ret = select(s + 1, NULL, &write_fds, NULL, &tv); + if (select_ret == 1) +#endif + { optlen = sizeof(optval); if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, - &optval, &optlen)) == 0) { + (char*)&optval, &optlen)) == 0) { errno = optval; ret = optval == 0 ? 0 : -1; } @@ -109,8 +150,12 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, ret = -1; } - if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) - ret = -1; + if (timeout != -1) { +#ifndef __WIN32__ + fcntl(s, F_SETFL, flags); +#endif + /* TODO: Implement this for Windows? */ + } return (ret); } @@ -486,6 +531,14 @@ Nsendfile(int fromfd, int tofd, const char *buf, size_t count) int setnonblocking(int fd, int nonblocking) { +#ifdef __WIN32__ + if (nonblocking) { + nonblock(fd); + return 0; + } + else + return -1; /*not supported currently */ +#else int flags, newflags; flags = fcntl(fd, F_GETFL, 0); @@ -503,6 +556,7 @@ setnonblocking(int fd, int nonblocking) return -1; } return 0; +#endif } /****************************************************************************/ @@ -518,3 +572,116 @@ getsockdomain(int sock) } return ((struct sockaddr *) &sa)->sa_family; } + + +#ifdef __WIN32__ + +// From 'mairix', under LGPL evidently + +/* The mmap/munmap implementation was shamelessly stolen, with minimal + changes, from libgwc32, a Windows port of glibc. */ + +static DWORD granularity = 0; +static int isw9x = -1; + +void * +mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset) +{ + void *map = NULL; + char *gran_addr = addr; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD cfm_flags = 0, mvf_flags = 0, sysgran; + off_t gran_offset = offset, filelen = _filelength(fd); + off_t mmlen = len; + + if (!granularity) + { + SYSTEM_INFO si; + + GetSystemInfo (&si); + granularity = si.dwAllocationGranularity; + } + sysgran = granularity; + + switch (prot) { + case PROT_READ | PROT_WRITE | PROT_EXEC: + case PROT_WRITE | PROT_EXEC: + cfm_flags = PAGE_EXECUTE_READWRITE; + mvf_flags = FILE_MAP_ALL_ACCESS; + break; + case PROT_READ | PROT_WRITE: + cfm_flags = PAGE_READWRITE; + mvf_flags = FILE_MAP_ALL_ACCESS; + break; + case PROT_WRITE: + cfm_flags = PAGE_READWRITE; + mvf_flags = FILE_MAP_WRITE; + break; + case PROT_READ: + cfm_flags = PAGE_READONLY; + mvf_flags = FILE_MAP_READ; + break; + case PROT_NONE: + cfm_flags = PAGE_NOACCESS; + mvf_flags = FILE_MAP_READ; + break; + case PROT_EXEC: + cfm_flags = PAGE_EXECUTE; + mvf_flags = FILE_MAP_READ; + break; + } + if (flags & MAP_PRIVATE) + { + if (isw9x == -1) + isw9x = ((DWORD)(LOBYTE (LOWORD (GetVersion()))) < 5); + if (isw9x == 1) + cfm_flags = PAGE_WRITECOPY; + mvf_flags = FILE_MAP_COPY; + } + if (flags & MAP_FIXED) + { + gran_offset = offset; + gran_addr = addr; + } + else + { + gran_offset = offset & ~(sysgran - 1); + gran_addr = (char *) (((DWORD) gran_addr / sysgran) * sysgran); + } + mmlen = (filelen < gran_offset + len ? filelen - gran_offset : len); + + handle = CreateFileMapping ((HANDLE) _get_osfhandle(fd), NULL, cfm_flags, + 0, mmlen, NULL); + if (!handle) + { + errno = EINVAL; /* FIXME */ + return MAP_FAILED; + } + map = MapViewOfFileEx (handle, mvf_flags, HIDWORD(gran_offset), + LODWORD(gran_offset), (SIZE_T) mmlen, + (LPVOID) gran_addr); + if (map == NULL && (flags & MAP_FIXED)) + { + map = MapViewOfFileEx (handle, mvf_flags, HIDWORD(gran_offset), + LODWORD(gran_offset), (SIZE_T) mmlen, + (LPVOID) NULL); + } + CloseHandle(handle); + + if (map == NULL) + { + errno = EINVAL; /* FIXME */ + return MAP_FAILED; + } + return map; +} + +int munmap (void *addr, size_t len) +{ + if (!UnmapViewOfFile (addr)) + return -1; + return 0; +} + +/* End of ISC stuff */ +#endif diff --git a/src/net.h b/src/net.h index c85c1a661..c247a251e 100644 --- a/src/net.h +++ b/src/net.h @@ -27,6 +27,10 @@ #ifndef __NET_H #define __NET_H +#include "iperf.h" + +void nonblock(int s); + int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout); int netannounce(int domain, int proto, char *local, const char* bind_dev, int port); diff --git a/src/tcp_info.c b/src/tcp_info.c index bfbb9ea4c..7d3f51a72 100644 --- a/src/tcp_info.c +++ b/src/tcp_info.c @@ -47,9 +47,11 @@ #include #include #include +#ifndef __WIN32__ #include -#include #include +#endif +#include #include #include "iperf.h" diff --git a/src/units.c b/src/units.c index e547ed057..92c11cd00 100644 --- a/src/units.c +++ b/src/units.c @@ -58,7 +58,9 @@ #ifdef HAVE_STDINT_H #include #endif +#ifndef __WIN32__ #include +#endif #include #include From d49cc948cfe3c021890c703804973d15ce76d6d2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 21 Oct 2019 14:08:59 -0700 Subject: [PATCH 07/45] Fix windows problems and bad socket management. Must use send/recv instead of read/write on windows. Must use closesocket() instead of close() for sockets on windows. Use rand() instead of /dev/urandom on windows. Cannot use 'unlink' on opened file in windows. Check windows-specific socket error reporting instead of errno. Fix lots of places where sockets could be closed and not un-assigned or leaked. Probably more bugs remain. Signed-off-by: Ben Greear --- src/Makefile.mingw | 1 + src/iperf.h | 9 ++++ src/iperf_api.c | 27 +++++++++- src/iperf_client_api.c | 17 ++++--- src/iperf_server_api.c | 32 +++++++----- src/iperf_tcp.c | 111 +++++++++++++++++++++++------------------ src/iperf_udp.c | 15 +++++- src/iperf_util.c | 22 +++++--- src/main.c | 10 ++++ src/net.c | 53 +++++++++++++++----- 10 files changed, 207 insertions(+), 90 deletions(-) diff --git a/src/Makefile.mingw b/src/Makefile.mingw index a02effa08..e8ae50782 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -9,6 +9,7 @@ RANLIB = i686-w64-mingw32-ranlib # WINVER 0501 is XP (2003), and higher # WINVER 0600 is Vista +BASIC_CCFLAGS = -g -O2 CCFLAGS = $(BASIC_CCFLAGS) -DHAVE_SNPRINTF -DHAVE_VSNPRINTF \ -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 -DHAVE_REMOTE diff --git a/src/iperf.h b/src/iperf.h index e534d0232..a2e0d79df 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -40,11 +40,20 @@ #include // for IFNAMSIZ #include #include + +#define STRERROR strerror(errno) +#define ERRNO errno +#define closesocket close + #else #include #include typedef int socklen_t; +const char* winstrerror(); +#define STRERROR winstrerror() +#define ERRNO WSAGetLastError() + /* From here: https://github.com/eclipse/paho.mqtt.c/issues/577 */ #define htonll(x) ((1==htonl(1)) ? (x) : ((((uint64_t)htonl((x)) & 0xFFFFFFFFUL)) << 32) | ((uint64_t)(htonl((uint32_t)((x)))) >> 32)) #define ntohll(x) ((1==ntohl(1)) ? (x) : ((((uint64_t)ntohl((x)) & 0xFFFFFFFFUL)) << 32) | ((uint64_t)(ntohl((uint32_t)((x)))) >> 32)) diff --git a/src/iperf_api.c b/src/iperf_api.c index be25191ce..b6146eeba 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1506,6 +1506,7 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP) SLIST_FOREACH(sp, &test->streams, streams) { if (FD_ISSET(sp->socket, read_setP) && !sp->sender) { if ((r = sp->rcv(sp)) < 0) { + fprintf(stderr, "Failed rcv: %s socket: %d\n", STRERROR, sp->socket); i_errno = IESTREAMREAD; return r; } @@ -3625,8 +3626,9 @@ iperf_free_stream(struct iperf_stream *sp) /* XXX: need to free interval list too! */ munmap(sp->buffer, sp->test->settings->blksize); close(sp->buffer_fd); - if (sp->diskfile_fd >= 0) + if (sp->diskfile_fd >= 0) { close(sp->diskfile_fd); + } for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != NULL; irp = nirp) { nirp = TAILQ_NEXT(irp, irlistentries); free(irp); @@ -3649,7 +3651,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template); } else { //find the system temporary dir *unix, windows, cygwin support - char* tempdir = getenv("TMPDIR"); + const char* tempdir = getenv("TMPDIR"); if (tempdir == 0){ tempdir = getenv("TEMP"); } @@ -3657,13 +3659,22 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) tempdir = getenv("TMP"); } if (tempdir == 0){ +#ifndef __WIN32__ tempdir = "/tmp"; +#else + tempdir = ""; // CWD +#endif } +#ifndef __WIN32__ snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir); +#else + snprintf(template, sizeof(template) / sizeof(char), "%s\\iperf3.XXXXXX", tempdir); +#endif } sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream)); if (!sp) { + fprintf(stderr, "Failed to malloc iperf-stream.\n"); i_errno = IECREATESTREAM; return NULL; } @@ -3676,6 +3687,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result)); if (!sp->result) { free(sp); + fprintf(stderr, "Failed to malloc sp->result.\n"); i_errno = IECREATESTREAM; return NULL; } @@ -3684,20 +3696,30 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) TAILQ_INIT(&sp->result->interval_results); /* Create and randomize the buffer */ + errno = 0; sp->buffer_fd = mkstemp(template); if (sp->buffer_fd == -1) { + fprintf(stderr, "Failed to mkstemp %s (%s)\n", template, STRERROR); i_errno = IECREATESTREAM; free(sp->result); free(sp); return NULL; } + + // Windows will not allow one to unlink an open file, unfortunately. +#ifndef __WIN32__ + errno = 0; if (unlink(template) < 0) { + fprintf(stderr, "Failed to unlink temp file: %s (%s)\n", template, STRERROR); i_errno = IECREATESTREAM; free(sp->result); free(sp); return NULL; } +#endif + if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) { + fprintf(stderr, "Failed to truncate, fd: %d blksize: %d\n", sp->buffer_fd, test->settings->blksize); i_errno = IECREATESTREAM; free(sp->result); free(sp); @@ -3705,6 +3727,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) } sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0); if (sp->buffer == MAP_FAILED) { + fprintf(stderr, "Failed to mmap.\n"); i_errno = IECREATESTREAM; free(sp->result); free(sp); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 81bf2d610..51c6a1273 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -76,7 +76,7 @@ iperf_create_streams(struct iperf_test *test, int sender) if (test->congestion) { if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { saved_errno = errno; - close(s); + closesocket(s); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -87,7 +87,7 @@ iperf_create_streams(struct iperf_test *test, int sender) char ca[TCP_CA_NAME_MAX + 1]; if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { saved_errno = errno; - close(s); + closesocket(s); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -107,8 +107,10 @@ iperf_create_streams(struct iperf_test *test, int sender) if (s > test->max_fd) test->max_fd = s; sp = iperf_new_stream(test, s, sender); - if (!sp) + if (!sp) { + closesocket(s); return -1; + } /* Perform the new stream callback */ if (test->on_new_stream) @@ -434,7 +436,8 @@ iperf_client_end(struct iperf_test *test) /* Close all stream sockets */ SLIST_FOREACH(sp, &test->streams, streams) { - close(sp->socket); + closesocket(sp->socket); + sp->socket = -1; } /* show final summary */ @@ -444,8 +447,10 @@ iperf_client_end(struct iperf_test *test) return -1; /* Close control socket */ - if (test->ctrl_sck) - close(test->ctrl_sck); + if (test->ctrl_sck != -1) { + closesocket(test->ctrl_sck); + test->ctrl_sck = -1; + } return 0; } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 6b891afe2..9e940592e 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -124,7 +124,10 @@ iperf_accept(struct iperf_test *test) if (test->ctrl_sck == -1) { /* Server free, accept new client */ test->ctrl_sck = s; - if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { + int rv = Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp); + if (rv < 0) { + fprintf(stderr, "Accept problem, ctrl-sck: %d s: %d listener: %d Nread rv: %d\n", + test->ctrl_sck, s, test->listener, rv); i_errno = IERECVCOOKIE; return -1; } @@ -147,9 +150,10 @@ iperf_accept(struct iperf_test *test) */ if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { i_errno = IESENDMESSAGE; + closesocket(s); return -1; } - close(s); + closesocket(s); } return 0; @@ -186,7 +190,7 @@ iperf_handle_message_server(struct iperf_test *test) SLIST_FOREACH(sp, &test->streams, streams) { FD_CLR(sp->socket, &test->read_set); FD_CLR(sp->socket, &test->write_set); - close(sp->socket); + closesocket(sp->socket); } test->reporter_callback(test); if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) @@ -216,7 +220,7 @@ iperf_handle_message_server(struct iperf_test *test) SLIST_FOREACH(sp, &test->streams, streams) { FD_CLR(sp->socket, &test->read_set); FD_CLR(sp->socket, &test->write_set); - close(sp->socket); + closesocket(sp->socket); } test->state = IPERF_DONE; break; @@ -242,10 +246,11 @@ server_timer_proc(TimerClientData client_data, struct iperf_time *nowP) while (!SLIST_EMPTY(&test->streams)) { sp = SLIST_FIRST(&test->streams); SLIST_REMOVE_HEAD(&test->streams, streams); - close(sp->socket); + closesocket(sp->socket); iperf_free_stream(sp); } - close(test->ctrl_sck); + closesocket(test->ctrl_sck); + test->ctrl_sck = -1; } static void @@ -361,10 +366,12 @@ cleanup_server(struct iperf_test *test) { /* Close open test sockets */ if (test->ctrl_sck) { - close(test->ctrl_sck); + closesocket(test->ctrl_sck); + test->ctrl_sck = -1; } if (test->listener) { - close(test->listener); + closesocket(test->listener); + test->listener = -1; } /* Cancel any remaining timers. */ @@ -388,6 +395,7 @@ cleanup_server(struct iperf_test *test) tmr_cancel(test->timer); test->timer = NULL; } + test->state = IPERF_DONE; } @@ -509,7 +517,7 @@ iperf_run_server(struct iperf_test *test) } else { saved_errno = errno; - close(s); + closesocket(s); cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; @@ -522,7 +530,7 @@ iperf_run_server(struct iperf_test *test) char ca[TCP_CA_NAME_MAX + 1]; if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { saved_errno = errno; - close(s); + closesocket(s); cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; @@ -584,11 +592,11 @@ iperf_run_server(struct iperf_test *test) if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { if (test->protocol->id != Ptcp) { FD_CLR(test->prot_listener, &test->read_set); - close(test->prot_listener); + closesocket(test->prot_listener); } else { if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { FD_CLR(test->listener, &test->read_set); - close(test->listener); + closesocket(test->listener); test->listener = 0; if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 69fdb2563..9b4da6cd4 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -60,8 +60,10 @@ iperf_tcp_recv(struct iperf_stream *sp) r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp); - if (r < 0) + if (r < 0) { + fprintf(stderr, "tcp-recv, failed (%s), socket: %d\n", STRERROR, sp->socket); return r; + } /* Only count bytes received while we're in the correct state. */ if (sp->test->state == TEST_RUNNING) { @@ -133,7 +135,8 @@ iperf_tcp_accept(struct iperf_test * test) i_errno = IESENDMESSAGE; return -1; } - close(s); + closesocket(s); + return -1; } return s; @@ -168,7 +171,8 @@ iperf_tcp_listen(struct iperf_test *test) char portstr[6]; FD_CLR(s, &test->read_set); - close(s); + closesocket(s); + test->listener = -1; snprintf(portstr, 6, "%d", test->server_port); memset(&hints, 0, sizeof(hints)); @@ -204,7 +208,7 @@ iperf_tcp_listen(struct iperf_test *test) #endif { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); i_errno = IEBINDDEV; errno = saved_errno; @@ -216,7 +220,7 @@ iperf_tcp_listen(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IESETNODELAY; @@ -228,7 +232,7 @@ iperf_tcp_listen(struct iperf_test *test) if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IESETMSS; @@ -239,7 +243,7 @@ iperf_tcp_listen(struct iperf_test *test) if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IESETBUF; @@ -247,40 +251,43 @@ iperf_tcp_listen(struct iperf_test *test) } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IESETBUF; return -1; } } + #if defined(HAVE_SO_MAX_PACING_RATE) - /* If fq socket pacing is specified, enable it. */ - if (test->settings->fqrate) { - /* Convert bits per second to bytes per second */ - unsigned int fqrate = test->settings->fqrate / 8; - if (fqrate > 0) { - if (test->debug) { - printf("Setting fair-queue socket pacing to %u\n", fqrate); - } - if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { - warning("Unable to set socket pacing"); - } - } - } + /* If fq socket pacing is specified, enable it. */ + if (test->settings->fqrate) { + /* Convert bits per second to bytes per second */ + unsigned int fqrate = test->settings->fqrate / 8; + if (fqrate > 0) { + if (test->debug) { + printf("Setting fair-queue socket pacing to %u\n", fqrate); + } + if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { + warning("Unable to set socket pacing"); + } + } + } #endif /* HAVE_SO_MAX_PACING_RATE */ - { - unsigned int rate = test->settings->rate / 8; - if (rate > 0) { - if (test->debug) { - printf("Setting application pacing to %u\n", rate); - } - } - } + + { + unsigned int rate = test->settings->rate / 8; + if (rate > 0) { + if (test->debug) { + printf("Setting application pacing to %u\n", rate); + } + } + } + opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IEREUSEADDR; @@ -301,7 +308,7 @@ iperf_tcp_listen(struct iperf_test *test) if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IEV6ONLY; @@ -312,7 +319,7 @@ iperf_tcp_listen(struct iperf_test *test) if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; i_errno = IESTREAMLISTEN; @@ -323,6 +330,9 @@ iperf_tcp_listen(struct iperf_test *test) if (listen(s, INT_MAX) < 0) { i_errno = IESTREAMLISTEN; + saved_errno = errno; + closesocket(s); + errno = saved_errno; return -1; } @@ -333,11 +343,13 @@ iperf_tcp_listen(struct iperf_test *test) optlen = sizeof(sndbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); + test->listener = -1; errno = saved_errno; i_errno = IESETBUF; return -1; } + if (test->debug) { printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize); } @@ -350,7 +362,8 @@ iperf_tcp_listen(struct iperf_test *test) optlen = sizeof(rcvbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); + test->listener = -1; errno = saved_errno; i_errno = IESETBUF; return -1; @@ -425,7 +438,7 @@ iperf_tcp_connect(struct iperf_test *test) #endif { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(local_res); freeaddrinfo(server_res); i_errno = IEBINDDEV; @@ -445,7 +458,7 @@ iperf_tcp_connect(struct iperf_test *test) if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(local_res); freeaddrinfo(server_res); errno = saved_errno; @@ -478,7 +491,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Unknown protocol */ else { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IEPROTOCOL; @@ -487,7 +500,7 @@ iperf_tcp_connect(struct iperf_test *test) if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESTREAMCONNECT; @@ -500,7 +513,7 @@ iperf_tcp_connect(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETNODELAY; @@ -511,7 +524,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETMSS; @@ -522,7 +535,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -530,7 +543,7 @@ iperf_tcp_connect(struct iperf_test *test) } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -542,7 +555,7 @@ iperf_tcp_connect(struct iperf_test *test) optlen = sizeof(sndbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -560,7 +573,7 @@ iperf_tcp_connect(struct iperf_test *test) optlen = sizeof(rcvbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -584,7 +597,7 @@ iperf_tcp_connect(struct iperf_test *test) if (test->settings->flowlabel) { if (server_res->ai_addr->sa_family != AF_INET6) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -604,7 +617,7 @@ iperf_tcp_connect(struct iperf_test *test) if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -615,7 +628,7 @@ iperf_tcp_connect(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -651,7 +664,7 @@ iperf_tcp_connect(struct iperf_test *test) if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESTREAMCONNECT; @@ -663,7 +676,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Send cookie for verification */ if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { saved_errno = errno; - close(s); + closesocket(s); errno = saved_errno; i_errno = IESENDCOOKIE; return -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 65d97ca0a..d7f138b63 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -431,7 +431,12 @@ iperf_udp_accept(struct iperf_test *test) /* Let the client know we're ready "accept" another UDP "stream" */ buf = 987654321; /* any content will work here */ - if (write(s, &buf, sizeof(buf)) < 0) { +#ifdef __WIN32__ + if (send(s, (const char*)&buf, sizeof(buf), 0) < 0) +#else + if (write(s, &buf, sizeof(buf)) < 0) +#endif + { i_errno = IESTREAMWRITE; return -1; } @@ -543,7 +548,12 @@ iperf_udp_connect(struct iperf_test *test) * The server learns our address by obtaining its peer's address. */ buf = 123456789; /* this can be pretty much anything */ - if (write(s, &buf, sizeof(buf)) < 0) { +#ifdef __WIN32__ + if (send(s, (const char*)&buf, sizeof(buf), 0) < 0) +#else + if (write(s, &buf, sizeof(buf)) < 0) +#endif + { // XXX: Should this be changed to IESTREAMCONNECT? i_errno = IESTREAMWRITE; return -1; @@ -553,6 +563,7 @@ iperf_udp_connect(struct iperf_test *test) * Wait until the server replies back to us. */ if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { + fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); i_errno = IESTREAMREAD; return -1; } diff --git a/src/iperf_util.c b/src/iperf_util.c index c246849e4..920cea4e2 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -67,10 +67,18 @@ int readentropy(void *out, size_t outsize) if (frandom == NULL) { frandom = fopen(rndfile, "rb"); if (frandom == NULL) { - iperf_errexit(NULL, "error - failed to open %s: %s\n", - rndfile, strerror(errno)); + // use rand() instead (this could be way more efficient but doesn't matter much) + unsigned char* dest = (unsigned char*)out; + for (size_t i = 0; iai_addr, local_res->ai_addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(local_res); freeaddrinfo(server_res); errno = saved_errno; @@ -255,7 +255,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; return -1; @@ -265,7 +265,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(server_res); errno = saved_errno; return -1; @@ -322,7 +322,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) #endif { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; return -1; @@ -333,7 +333,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; return -1; @@ -355,7 +355,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; return -1; @@ -365,7 +365,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { saved_errno = errno; - close(s); + closesocket(s); freeaddrinfo(res); errno = saved_errno; return -1; @@ -376,7 +376,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) if (proto == SOCK_STREAM) { if (listen(s, INT_MAX) < 0) { saved_errno = errno; - close(s); + closesocket(s); errno = saved_errno; return -1; } @@ -397,12 +397,26 @@ Nread(int fd, char *buf, size_t count, int prot) register size_t nleft = count; while (nleft > 0) { + errno = 0; +#ifndef __WIN32__ r = read(fd, buf, nleft); +#else + r = recv(fd, buf, nleft, 0); +#endif if (r < 0) { +#ifndef __WIN32__ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) +#else + if (WSAGetLastError() == WSAEWOULDBLOCK) +#endif + { break; - else + } + else { + fprintf(stderr, "Error in Nread (%s) fd: %d\n", + STRERROR, fd); return NET_HARDERROR; + } } else if (r == 0) break; @@ -424,7 +438,12 @@ Nwrite(int fd, const char *buf, size_t count, int prot) register size_t nleft = count; while (nleft > 0) { + errno = 0; +#ifndef __WIN32__ r = write(fd, buf, nleft); +#else + r = send(fd, buf, nleft, 0); +#endif if (r < 0) { switch (errno) { case EINTR: @@ -438,10 +457,18 @@ Nwrite(int fd, const char *buf, size_t count, int prot) return NET_SOFTERROR; default: - return NET_HARDERROR; +#ifdef __WIN32__ + if (WSAGetLastError() == WSAEWOULDBLOCK) + return count - nleft; +#endif + return NET_HARDERROR; } - } else if (r == 0) - return NET_SOFTERROR; + } else if (r == 0) { + if ((count - nleft) == 0) + return NET_SOFTERROR; + else + return (count - nleft); /* already wrote some */ + } nleft -= r; buf += r; } From 7f6c513b73218e79758523f3daf0938f844bb144 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 12:18:00 -0700 Subject: [PATCH 08/45] Add lots of debugging. Tracking down problem where client trying to send udp to server fails after the first connection. Signed-off-by: Ben Greear --- src/iperf_api.c | 58 ++++++++++++++++++++++++++++++++++----- src/iperf_api.h | 16 +++++++---- src/iperf_client_api.c | 10 +++---- src/iperf_server_api.c | 62 ++++++++++++++++++++++++++++-------------- src/iperf_tcp.c | 2 +- src/iperf_udp.c | 3 +- src/iperf_util.c | 1 + 7 files changed, 111 insertions(+), 41 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index b6146eeba..3d2eabdc6 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1436,10 +1436,10 @@ iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP) bits_per_second = sp->result->bytes_sent * 8 / seconds; if (bits_per_second < sp->test->settings->rate) { sp->green_light = 1; - FD_SET(sp->socket, &sp->test->write_set); + IFD_SET(sp->socket, &sp->test->write_set, sp->test); } else { sp->green_light = 0; - FD_CLR(sp->socket, &sp->test->write_set); + IFD_CLR(sp->socket, &sp->test->write_set, sp->test); } } @@ -1492,7 +1492,7 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) if (write_setP != NULL) SLIST_FOREACH(sp, &test->streams, streams) if (FD_ISSET(sp->socket, write_setP)) - FD_CLR(sp->socket, write_setP); + IFD_CLR(sp->socket, write_setP, test); return 0; } @@ -1512,7 +1512,7 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP) } test->bytes_received += r; ++test->blocks_received; - FD_CLR(sp->socket, read_setP); + IFD_CLR(sp->socket, read_setP, test); } } @@ -1645,7 +1645,7 @@ iperf_exchange_parameters(struct iperf_test *test) #endif //HAVE_SSL if ((s = test->protocol->listen(test)) < 0) { - if (iperf_set_send_state(test, SERVER_ERROR) != 0) + if (iperf_set_send_state(test, SERVER_ERROR) != 0) return -1; err = htonl(i_errno); if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { @@ -1659,8 +1659,12 @@ 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; + + if (test->debug) { + fprintf(stderr, "iperf-exchange-parameters, setting read FD: %d.\n", s); + } + + IFD_SET(s, &test->read_set, test); test->prot_listener = s; // Send the control message to create streams and start the test @@ -1672,6 +1676,45 @@ iperf_exchange_parameters(struct iperf_test *test) return 0; } +void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { + if (test->debug) { + fprintf(stderr, "FD-SET, fd: %d at %s:%d\n", + fd, file, line); + } + FD_SET(fd, fdset); + if (fd > test->max_fd) + test->max_fd = fd; +} + +void _fd_clr(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { + if (test->debug) { + fprintf(stderr, "FD-CLR, fd: %d at %s:%d\n", + fd, file, line); + } + FD_CLR(fd, fdset); +} + +const char* iperf_get_state_str(int s) { + switch (s) { + case TEST_START: return "START"; + case TEST_RUNNING: return "RUNNING"; + case TEST_END: return "END"; + case PARAM_EXCHANGE: return "PARAM-EXCHANGE"; + case STREAM_RUNNING: return "STREAM-RUNNING"; + case CREATE_STREAMS: return "CREATE-STREAMS"; + case SERVER_TERMINATE: return "SERVER-TERMINATE"; + case CLIENT_TERMINATE: return "CLIENT-TERMINATE"; + case EXCHANGE_RESULTS: return "EXCHANGE-RESULTS"; + case DISPLAY_RESULTS: return "DISPLAY-RESULTS"; + case IPERF_START: return "IPERF-START"; + case IPERF_DONE: return "IPERF-DONE"; + case ACCESS_DENIED: return "ACCESS-DENIED"; + case SERVER_ERROR: return "SERVER-ERROR"; + default: + return "UNKNOWN"; + } +} + /*************************************************************/ int @@ -2613,6 +2656,7 @@ iperf_reset_test(struct iperf_test *test) FD_ZERO(&test->read_set); FD_ZERO(&test->write_set); + test->max_fd = 0; test->num_streams = 1; test->settings->socket_bufsize = 0; diff --git a/src/iperf_api.h b/src/iperf_api.h index bebf81feb..670799bf7 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -81,12 +81,12 @@ struct iperf_time; /* states */ #define TEST_START 1 #define TEST_RUNNING 2 -#define RESULT_REQUEST 3 /* not used */ +//#define RESULT_REQUEST 3 /* not used */ #define TEST_END 4 -#define STREAM_BEGIN 5 /* not used */ -#define STREAM_RUNNING 6 /* not used */ -#define STREAM_END 7 /* not used */ -#define ALL_STREAMS_END 8 /* not used */ +//#define STREAM_BEGIN 5 /* not used */ +#define STREAM_RUNNING 6 +//#define STREAM_END 7 /* not used */ +//#define ALL_STREAMS_END 8 /* not used */ #define PARAM_EXCHANGE 9 #define CREATE_STREAMS 10 #define SERVER_TERMINATE 11 @@ -98,6 +98,12 @@ struct iperf_time; #define ACCESS_DENIED (-1) #define SERVER_ERROR (-2) +const char* iperf_get_state_str(int s); +void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line); +void _fd_clr(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line); +#define IFD_SET(a, b, c) _fd_set(a, b, c, __FILE__, __LINE__) +#define IFD_CLR(a, b, c) _fd_clr(a, b, c, __FILE__, __LINE__) + /* Getter routines for some fields inside iperf_test. */ int iperf_get_verbose( struct iperf_test* ipt ); int iperf_get_control_socket( struct iperf_test* ipt ); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 51c6a1273..16eaedd28 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -101,10 +101,9 @@ iperf_create_streams(struct iperf_test *test, int sender) #endif /* HAVE_TCP_CONGESTION */ if (sender) - FD_SET(s, &test->write_set); + IFD_SET(s, &test->write_set, test); else - FD_SET(s, &test->read_set); - if (s > test->max_fd) test->max_fd = s; + IFD_SET(s, &test->read_set, test); sp = iperf_new_stream(test, s, sender); if (!sp) { @@ -351,8 +350,7 @@ iperf_connect(struct iperf_test *test) return -1; } - FD_SET(test->ctrl_sck, &test->read_set); - if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck; + IFD_SET(test->ctrl_sck, &test->read_set, test); int opt; socklen_t len; @@ -511,7 +509,7 @@ iperf_run_client(struct iperf_test * test) if (iperf_handle_message_client(test) < 0) { return -1; } - FD_CLR(test->ctrl_sck, &read_set); + IFD_CLR(test->ctrl_sck, &read_set, test); } } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 9e940592e..8bc7d53ab 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -101,8 +101,7 @@ iperf_server_listen(struct iperf_test *test) FD_ZERO(&test->read_set); FD_ZERO(&test->write_set); - FD_SET(test->listener, &test->read_set); - if (test->listener > test->max_fd) test->max_fd = test->listener; + IFD_SET(test->listener, &test->read_set, test); return 0; } @@ -115,6 +114,10 @@ iperf_accept(struct iperf_test *test) socklen_t len; struct sockaddr_storage addr; + if (test->debug) { + fprintf(stderr, "iperf-accept called.\n"); + } + len = sizeof(addr); if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { i_errno = IEACCEPT; @@ -131,8 +134,7 @@ iperf_accept(struct iperf_test *test) i_errno = IERECVCOOKIE; return -1; } - FD_SET(test->ctrl_sck, &test->read_set); - if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck; + IFD_SET(test->ctrl_sck, &test->read_set, test); if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0) return -1; @@ -188,9 +190,10 @@ iperf_handle_message_server(struct iperf_test *test) cpu_util(test->cpu_util); test->stats_callback(test); SLIST_FOREACH(sp, &test->streams, streams) { - FD_CLR(sp->socket, &test->read_set); - FD_CLR(sp->socket, &test->write_set); + IFD_CLR(sp->socket, &test->read_set, test); + IFD_CLR(sp->socket, &test->write_set, test); closesocket(sp->socket); + sp->socket = -1; } test->reporter_callback(test); if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) @@ -218,9 +221,10 @@ iperf_handle_message_server(struct iperf_test *test) // XXX: Remove this line below! iperf_err(test, "the client has terminated"); SLIST_FOREACH(sp, &test->streams, streams) { - FD_CLR(sp->socket, &test->read_set); - FD_CLR(sp->socket, &test->write_set); + IFD_CLR(sp->socket, &test->read_set, test); + IFD_CLR(sp->socket, &test->write_set, test); closesocket(sp->socket); + sp->socket = -1; } test->state = IPERF_DONE; break; @@ -455,8 +459,24 @@ iperf_run_server(struct iperf_test *test) iperf_time_now(&now); timeout = tmr_timeout(&now); + if (test->debug) { + if (timeout) + fprintf(stderr, "timeout: %d.%06d max-fd: %d\n", timeout->tv_sec, timeout->tv_usec, test->max_fd); + else + fprintf(stderr, "timeout NULL, max-fd: %d\n", test->max_fd); + } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); + + if (test->debug) { + fprintf(stderr, "select result: %d, listener: %d ISSET-listener: %d test-state: %d(%s)\n", + result, test->listener, FD_ISSET(test->listener, &read_set), test->state, + iperf_get_state_str(test->state)); + fprintf(stderr, "prot-listener: %d ISSET: %d max-fd: %d\n", + test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); + } + if (result < 0 && errno != EINTR) { + fprintf(stderr, "Cleaning server, select had error: %s\n", STRERROR); cleanup_server(test); i_errno = IESELECT; return -1; @@ -468,7 +488,7 @@ iperf_run_server(struct iperf_test *test) cleanup_server(test); return -1; } - FD_CLR(test->listener, &read_set); + IFD_CLR(test->listener, &read_set, test); // Set streams number if (test->mode == BIDIRECTIONAL) { @@ -488,7 +508,7 @@ iperf_run_server(struct iperf_test *test) cleanup_server(test); return -1; } - FD_CLR(test->ctrl_sck, &read_set); + IFD_CLR(test->ctrl_sck, &read_set, test); } if (test->state == CREATE_STREAMS) { @@ -499,6 +519,10 @@ iperf_run_server(struct iperf_test *test) return -1; } + if (test->debug) { + fprintf(stderr, "create-streams, accepted socket: %d\n", s); + } + #if defined(HAVE_TCP_CONGESTION) if (test->protocol->id == Ptcp) { if (test->congestion) { @@ -562,11 +586,9 @@ iperf_run_server(struct iperf_test *test) } if (sp->sender) - FD_SET(s, &test->write_set); + IFD_SET(s, &test->write_set, test); else - FD_SET(s, &test->read_set); - - if (s > test->max_fd) test->max_fd = s; + IFD_SET(s, &test->read_set, test); /* * If the protocol isn't UDP, or even if it is but @@ -585,19 +607,20 @@ iperf_run_server(struct iperf_test *test) flag = -1; } } - FD_CLR(test->prot_listener, &read_set); + IFD_CLR(test->prot_listener, &read_set, test); } if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { if (test->protocol->id != Ptcp) { - FD_CLR(test->prot_listener, &test->read_set); + IFD_CLR(test->prot_listener, &test->read_set, test); closesocket(test->prot_listener); + test->prot_listener = -1; } else { if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { - FD_CLR(test->listener, &test->read_set); + IFD_CLR(test->listener, &test->read_set, test); closesocket(test->listener); - test->listener = 0; + test->listener = -1; if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { cleanup_server(test); @@ -605,8 +628,7 @@ iperf_run_server(struct iperf_test *test) return -1; } test->listener = s; - FD_SET(test->listener, &test->read_set); - if (test->listener > test->max_fd) test->max_fd = test->listener; + IFD_SET(test->listener, &test->read_set, test); } } test->prot_listener = -1; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 9b4da6cd4..3af2ea10b 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -170,7 +170,7 @@ iperf_tcp_listen(struct iperf_test *test) struct addrinfo hints, *res; char portstr[6]; - FD_CLR(s, &test->read_set); + IFD_CLR(s, &test->read_set, test); closesocket(s); test->listener = -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index d7f138b63..7eedf9f15 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -426,8 +426,7 @@ iperf_udp_accept(struct iperf_test *test) return -1; } - FD_SET(test->prot_listener, &test->read_set); - test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd; + IFD_SET(test->prot_listener, &test->read_set, test); /* Let the client know we're ready "accept" another UDP "stream" */ buf = 987654321; /* any content will work here */ diff --git a/src/iperf_util.c b/src/iperf_util.c index 920cea4e2..42cbc564b 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -156,6 +156,7 @@ is_closed(int fd) tv.tv_usec = 0; if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { + fprintf(stderr, "is-closed, had error for fd: %d: %s", fd, STRERROR); if (errno == EBADF) return 1; } From 3511259f0009b56011fccf61d4f97c26b31500a7 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 12:20:08 -0700 Subject: [PATCH 09/45] Add a bit more state debugging. --- src/iperf_server_api.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 8bc7d53ab..c33f38049 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -461,9 +461,13 @@ iperf_run_server(struct iperf_test *test) timeout = tmr_timeout(&now); if (test->debug) { if (timeout) - fprintf(stderr, "timeout: %d.%06d max-fd: %d\n", timeout->tv_sec, timeout->tv_usec, test->max_fd); + fprintf(stderr, "timeout: %d.%06d max-fd: %d state: %d (%s)\n", + timeout->tv_sec, timeout->tv_usec, test->max_fd, + test->state, iperf_get_state_str(test->state)); + else - fprintf(stderr, "timeout NULL, max-fd: %d\n", test->max_fd); + fprintf(stderr, "timeout NULL, max-fd: %d state: %d(%s)\n", test->max_fd, + test->state, iperf_get_state_str(test->state)); } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); From 1bca8c37dd9236b964f81d0caf78656c4c591fa2 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 14:09:23 -0700 Subject: [PATCH 10/45] Add hexdump debugging to socket read/write calls. Help with debugging the protocol and interactions. --- src/iperf_api.c | 36 +++++++++---------- src/iperf_client_api.c | 9 +++-- src/iperf_server_api.c | 6 ++-- src/iperf_tcp.c | 10 +++--- src/iperf_udp.c | 4 +-- src/iperf_util.c | 81 ++++++++++++++++++++++++++++++++++++++++++ src/iperf_util.h | 3 ++ src/net.c | 14 ++++++-- src/net.h | 4 +-- 9 files changed, 130 insertions(+), 37 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 3d2eabdc6..7ab7f359b 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -87,9 +87,9 @@ static int send_results(struct iperf_test *test); static int get_results(struct iperf_test *test); static int diskfile_send(struct iperf_stream *sp); static int diskfile_recv(struct iperf_stream *sp); -static int JSON_write(int fd, cJSON *json); +static int JSON_write(int fd, cJSON *json, struct iperf_test *test); static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams); -static cJSON *JSON_read(int fd); +static cJSON *JSON_read(int fd, struct iperf_test *test); /*************************** Print usage functions ****************************/ @@ -1196,7 +1196,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) #endif /* HAVE_TCP_CONGESTION */ break; case 'd': - test->debug = 1; + test->debug++; break; case 'I': test->pidfile = strdup(optarg); @@ -1415,7 +1415,7 @@ int iperf_set_send_state(struct iperf_test *test, signed char state) { test->state = state; - if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) { + if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp, test) < 0) { i_errno = IESENDMESSAGE; return -1; } @@ -1636,7 +1636,7 @@ iperf_exchange_parameters(struct iperf_test *test) return -1; i_errno = IEAUTHTEST; err = htonl(i_errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { + if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { i_errno = IECTRLWRITE; return -1; } @@ -1648,12 +1648,12 @@ iperf_exchange_parameters(struct iperf_test *test) if (iperf_set_send_state(test, SERVER_ERROR) != 0) return -1; err = htonl(i_errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { + if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { i_errno = IECTRLWRITE; return -1; } err = htonl(errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { + if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { i_errno = IECTRLWRITE; return -1; } @@ -1816,7 +1816,7 @@ send_parameters(struct iperf_test *test) printf("send_parameters:\n%s\n", cJSON_Print(j)); } - if (JSON_write(test->ctrl_sck, j) < 0) { + if (JSON_write(test->ctrl_sck, j, test) < 0) { i_errno = IESENDPARAMS; r = -1; } @@ -1834,7 +1834,7 @@ get_parameters(struct iperf_test *test) cJSON *j; cJSON *j_p; - j = JSON_read(test->ctrl_sck); + j = JSON_read(test->ctrl_sck, test); if (j == NULL) { i_errno = IERECVPARAMS; r = -1; @@ -2012,7 +2012,7 @@ send_results(struct iperf_test *test) printf("send_results\n%s\n", str); free(str); } - if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) { + if (r == 0 && JSON_write(test->ctrl_sck, j, test) < 0) { i_errno = IESENDRESULTS; r = -1; } @@ -2052,7 +2052,7 @@ get_results(struct iperf_test *test) int retransmits; struct iperf_stream *sp; - j = JSON_read(test->ctrl_sck); + j = JSON_read(test->ctrl_sck, test); if (j == NULL) { i_errno = IERECVRESULTS; r = -1; @@ -2187,7 +2187,7 @@ get_results(struct iperf_test *test) /*************************************************************/ static int -JSON_write(int fd, cJSON *json) +JSON_write(int fd, cJSON *json, struct iperf_test *test) { uint32_t hsize, nsize; char *str; @@ -2199,10 +2199,10 @@ JSON_write(int fd, cJSON *json) else { hsize = strlen(str); nsize = htonl(hsize); - if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp) < 0) + if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp, test) < 0) r = -1; else { - if (Nwrite(fd, str, hsize, Ptcp) < 0) + if (Nwrite(fd, str, hsize, Ptcp, test) < 0) r = -1; } free(str); @@ -2213,7 +2213,7 @@ JSON_write(int fd, cJSON *json) /*************************************************************/ static cJSON * -JSON_read(int fd) +JSON_read(int fd, struct iperf_test *test) { uint32_t hsize, nsize; char *str; @@ -2225,12 +2225,12 @@ JSON_read(int fd) * Then read the JSON into a buffer and parse it. Return a parsed JSON * structure, NULL if there was an error. */ - if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) { + if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp, test) >= 0) { hsize = ntohl(nsize); /* Allocate a buffer to hold the JSON */ str = (char *) calloc(sizeof(char), hsize+1); /* +1 for trailing null */ if (str != NULL) { - rc = Nread(fd, str, hsize, Ptcp); + rc = Nread(fd, str, hsize, Ptcp, test); if (rc >= 0) { /* * We should be reading in the number of bytes corresponding to the @@ -3987,7 +3987,7 @@ iperf_got_sigend(struct iperf_test *test) if (test->ctrl_sck >= 0) { test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE; - (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp); + (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test); } i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM; iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno)); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 16eaedd28..98e45d13e 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -236,8 +236,7 @@ iperf_handle_message_client(struct iperf_test *test) int rval; int32_t err; - /*!!! Why is this read() and not Nread()? */ - if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) { + if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test)) <= 0) { if (rval == 0) { i_errno = IECTRLCLOSE; return -1; @@ -306,12 +305,12 @@ iperf_handle_message_client(struct iperf_test *test) i_errno = IEACCESSDENIED; return -1; case SERVER_ERROR: - if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { + if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { i_errno = IECTRLREAD; return -1; } i_errno = ntohl(err); - if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { + if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { i_errno = IECTRLREAD; return -1; } @@ -345,7 +344,7 @@ iperf_connect(struct iperf_test *test) return -1; } - if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { + if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test) < 0) { i_errno = IESENDCOOKIE; return -1; } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index c33f38049..60ded5058 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -127,7 +127,7 @@ iperf_accept(struct iperf_test *test) if (test->ctrl_sck == -1) { /* Server free, accept new client */ test->ctrl_sck = s; - int rv = Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp); + int rv = Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test); if (rv < 0) { fprintf(stderr, "Accept problem, ctrl-sck: %d s: %d listener: %d Nread rv: %d\n", test->ctrl_sck, s, test->listener, rv); @@ -150,7 +150,7 @@ iperf_accept(struct iperf_test *test) * Don't try to read from the socket. It could block an ongoing test. * Just send ACCESS_DENIED. */ - if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { + if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test) < 0) { i_errno = IESENDMESSAGE; closesocket(s); return -1; @@ -170,7 +170,7 @@ iperf_handle_message_server(struct iperf_test *test) struct iperf_stream *sp; // XXX: Need to rethink how this behaves to fit API - if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) { + if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test)) <= 0) { if (rval == 0) { iperf_err(test, "the client has unexpectedly closed the connection"); i_errno = IECTRLCLOSE; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 3af2ea10b..76d2a5b84 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -58,7 +58,7 @@ iperf_tcp_recv(struct iperf_stream *sp) { int r; - r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp); + r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp, sp->test); if (r < 0) { fprintf(stderr, "tcp-recv, failed (%s), socket: %d\n", STRERROR, sp->socket); @@ -91,7 +91,7 @@ iperf_tcp_send(struct iperf_stream *sp) if (sp->test->zerocopy) r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize); else - r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp); + r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp, sp->test); if (r < 0) return r; @@ -125,13 +125,13 @@ iperf_tcp_accept(struct iperf_test * test) return -1; } - if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { + if (Nread(s, cookie, COOKIE_SIZE, Ptcp, test) < 0) { i_errno = IERECVCOOKIE; return -1; } if (strcmp(test->cookie, cookie) != 0) { - if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { + if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test) < 0) { i_errno = IESENDMESSAGE; return -1; } @@ -674,7 +674,7 @@ iperf_tcp_connect(struct iperf_test *test) freeaddrinfo(server_res); /* Send cookie for verification */ - if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { + if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp, test) < 0) { saved_errno = errno; closesocket(s); errno = saved_errno; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 7eedf9f15..195fcd7d9 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -70,7 +70,7 @@ iperf_udp_recv(struct iperf_stream *sp) double transit = 0, d = 0; struct iperf_time sent_time, arrival_time, temp_time; - r = Nread(sp->socket, sp->buffer, size, Pudp); + r = Nread(sp->socket, sp->buffer, size, Pudp, sp->test); /* * If we got an error in the read, or if we didn't read anything @@ -227,7 +227,7 @@ iperf_udp_send(struct iperf_stream *sp) } - r = Nwrite(sp->socket, sp->buffer, size, Pudp); + r = Nwrite(sp->socket, sp->buffer, size, Pudp, sp->test); if (r < 0) return r; diff --git a/src/iperf_util.c b/src/iperf_util.c index 42cbc564b..16d16c86d 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -164,6 +164,87 @@ is_closed(int fd) } +const char* hexdump(const unsigned char* msg, int len, int show_decode, + int add_newlines) { + static char retval[24000]; + int bytes_per_line = 16; + char* buf = retval; + int maxlen = sizeof(retval) - 1; + buf[0] = 0; + + unsigned short tmp = 0; + int i; + int sofar = 0; + int count = 0; + + for (i = 0; i= maxlen) + return retval; + + if (add_newlines && ((i + 1) % bytes_per_line == 0)) { + if (show_decode) { + count = snprintf(buf, maxlen - sofar, " "); + buf += count; + if (sofar >= maxlen) + return retval; + for (int j = i - (bytes_per_line - 1); j<=i; j++) { + if (isprint(msg[j])) { + count = snprintf(buf, maxlen - sofar, "%c", msg[j]); + } + else { + count = snprintf(buf, maxlen - sofar, "."); + } + if (sofar >= maxlen) + return retval; + buf += count; + }//for + } + count = snprintf(buf, maxlen - sofar, "\n"); + if (sofar >= maxlen) + return retval; + buf += count; + }//if + }//for + + if (show_decode) { + // do final char translations. + int q = (i) % bytes_per_line; + int offset = i-q; + count = snprintf(buf, maxlen - sofar, " "); + buf += count; + if (sofar >= maxlen) + return retval; + for (int l = 0; l< bytes_per_line-q; l++) { + //space, where the hex would have gone. + count = snprintf(buf, maxlen - sofar, " "); + buf += count; + if (sofar >= maxlen) + return retval; + } + + //VLOG << "q: " << q << " offset: " << offset << " i: " << i << endl; + for (int j = 0; j= maxlen) + return retval; + buf += count; + }//for + } + return retval; +}//hexdump + + double timeval_to_double(struct timeval * tv) { diff --git a/src/iperf_util.h b/src/iperf_util.h index dfaeb23d1..9863d4cf5 100644 --- a/src/iperf_util.h +++ b/src/iperf_util.h @@ -35,6 +35,9 @@ #include #include "iperf.h" +const char* hexdump(const unsigned char* msg, int len, int show_decode, + int add_newlines); + int readentropy(void *out, size_t outsize); void fill_with_repeating_pattern(void *out, size_t outsize); diff --git a/src/net.c b/src/net.c index 12f669bac..11893c08c 100644 --- a/src/net.c +++ b/src/net.c @@ -391,8 +391,9 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) /********************************************************************/ int -Nread(int fd, char *buf, size_t count, int prot) +Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) { + char* oldbuf = buf; register ssize_t r; register size_t nleft = count; @@ -423,6 +424,10 @@ Nread(int fd, char *buf, size_t count, int prot) nleft -= r; buf += r; } + if (test && test->debug > 1) { + fprintf(stderr, "Nread:\n"); + fprintf(stderr, hexdump(oldbuf, count - nleft, 1, 1)); + } return count - nleft; } @@ -432,11 +437,16 @@ Nread(int fd, char *buf, size_t count, int prot) */ int -Nwrite(int fd, const char *buf, size_t count, int prot) +Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) { register ssize_t r; register size_t nleft = count; + if (test && test->debug > 1) { + fprintf(stderr, "Nwrite:\n"); + fprintf(stderr, hexdump(buf, count, 1, 1)); + } + while (nleft > 0) { errno = 0; #ifndef __WIN32__ diff --git a/src/net.h b/src/net.h index c247a251e..f24301f3c 100644 --- a/src/net.h +++ b/src/net.h @@ -34,8 +34,8 @@ void nonblock(int s); int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout); int netannounce(int domain, int proto, char *local, const char* bind_dev, 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 Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test); +int Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) /* __attribute__((hot)) */; int has_sendfile(void); int Nsendfile(int fromfd, int tofd, const char *buf, size_t count) /* __attribute__((hot)) */; int setnonblocking(int fd, int nonblocking); From afacb7330ecaf0068463ad373bb1cdcac4363e4c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 15:33:34 -0700 Subject: [PATCH 11/45] More debugging around client-side udp transactions. And some cleanup along the way. Signed-off-by: Ben Greear --- src/iperf_api.c | 2 +- src/iperf_client_api.c | 8 +++++++- src/iperf_sctp.c | 10 +++++----- src/iperf_server_api.c | 4 ++-- src/iperf_udp.c | 36 +++++++++++++++++++++++++++++++----- src/iperf_util.c | 2 ++ src/net.c | 12 +++++++++--- src/net.h | 3 ++- 8 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 7ab7f359b..d9aadabea 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -774,7 +774,7 @@ iperf_on_connect(struct iperf_test *test) } } if (test->settings->rate) - iperf_printf(test, " Target Bitrate: %llu\n", test->settings->rate); + iperf_printf(test, " Target Bitrate: %llu\n", (unsigned long long)test->settings->rate); } } diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 98e45d13e..dd752ab05 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -62,6 +62,11 @@ iperf_create_streams(struct iperf_test *test, int sender) #endif /* HAVE_TCP_CONGESTION */ struct iperf_stream *sp; + if (test->debug) { + fprintf(stderr, "iperf-create-streams, num-streams: %d\n", + test->num_streams); + } + int orig_bind_port = test->bind_port; for (i = 0; i < test->num_streams; ++i) { @@ -338,7 +343,8 @@ iperf_connect(struct iperf_test *test) /* Create and connect the control channel */ if (test->ctrl_sck < 0) // Create the control channel using an ephemeral port - test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout); + test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, + test->server_hostname, test->server_port, test->settings->connect_timeout, test); if (test->ctrl_sck < 0) { i_errno = IECONNECT; return -1; diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index 7bf93a1fc..9c4e25220 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -61,7 +61,7 @@ iperf_sctp_recv(struct iperf_stream *sp) #if defined(HAVE_SCTP) int r; - r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp); + r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Psctp, sp->test); if (r < 0) return r; @@ -93,7 +93,7 @@ iperf_sctp_send(struct iperf_stream *sp) #if defined(HAVE_SCTP) int r; - r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp); + r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Psctp, sp->test); if (r < 0) return r; @@ -130,13 +130,13 @@ iperf_sctp_accept(struct iperf_test * test) return -1; } - if (Nread(s, cookie, COOKIE_SIZE, Psctp) < 0) { + if (Nread(s, cookie, COOKIE_SIZE, Psctp, test) < 0) { i_errno = IERECVCOOKIE; return -1; } if (strcmp(test->cookie, cookie) != 0) { - if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp) < 0) { + if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Psctp, test) < 0) { i_errno = IESENDMESSAGE; return -1; } @@ -480,7 +480,7 @@ iperf_sctp_connect(struct iperf_test *test) freeaddrinfo(server_res); /* Send cookie for verification */ - if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp) < 0) { + if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp, test) < 0) { saved_errno = errno; close(s); errno = saved_errno; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 60ded5058..2f6f0a21f 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -461,8 +461,8 @@ iperf_run_server(struct iperf_test *test) timeout = tmr_timeout(&now); if (test->debug) { if (timeout) - fprintf(stderr, "timeout: %d.%06d max-fd: %d state: %d (%s)\n", - timeout->tv_sec, timeout->tv_usec, test->max_fd, + fprintf(stderr, "timeout: %ld.%06ld max-fd: %d state: %d (%s)\n", + (long)(timeout->tv_sec), (long)(timeout->tv_usec), test->max_fd, test->state, iperf_get_state_str(test->state)); else diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 195fcd7d9..5fb38b7de 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -289,7 +289,7 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) return -1; } if (test->debug) { - printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize); + printf("SNDBUF is %u, expecting %u, fd: %d\n", sndbuf_actual, test->settings->socket_bufsize, s); } if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) { i_errno = IESETBUF2; @@ -311,7 +311,7 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) return -1; } if (test->debug) { - printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize); + printf("RCVBUF is %u, expecting %u fd: %d\n", rcvbuf_actual, test->settings->socket_bufsize, s); } if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) { i_errno = IESETBUF2; @@ -376,6 +376,7 @@ iperf_udp_accept(struct iperf_test *test) if (rc < 0) /* error */ return rc; + /* * If the socket buffer was too small, but it was the default * size, then try explicitly setting it to something larger. @@ -423,6 +424,7 @@ iperf_udp_accept(struct iperf_test *test) test->server_port); if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; + closesocket(s); return -1; } @@ -437,6 +439,7 @@ iperf_udp_accept(struct iperf_test *test) #endif { i_errno = IESTREAMWRITE; + closesocket(s); return -1; } @@ -483,18 +486,25 @@ iperf_udp_connect(struct iperf_test *test) #endif int rc; + if (test->debug) { + fprintf(stderr, "udp-connect called\n"); + } + /* Create and bind our local socket. */ if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, - test->server_hostname, test->server_port, -1)) < 0) { + test->server_hostname, test->server_port, -1, test)) < 0) { i_errno = IESTREAMCONNECT; return -1; } /* Check and set socket buffer sizes */ rc = iperf_udp_buffercheck(test, s); - if (rc < 0) + if (rc < 0) { /* error */ + closesocket(s); return rc; + } + /* * If the socket buffer was too small, but it was the default * size, then try explicitly setting it to something larger. @@ -506,8 +516,10 @@ iperf_udp_connect(struct iperf_test *test) bufsize); test->settings->socket_bufsize = bufsize; rc = iperf_udp_buffercheck(test, s); - if (rc < 0) + if (rc < 0) { + closesocket(s); return rc; + } } } @@ -547,6 +559,12 @@ iperf_udp_connect(struct iperf_test *test) * The server learns our address by obtaining its peer's address. */ buf = 123456789; /* this can be pretty much anything */ + if (test->debug) { + fprintf(stderr, "sending '123456789' to peer to let them know we are here: %s", + hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + } + + // This sucks: UDP messages can be lost and will not automatically be retransmitted. #ifdef __WIN32__ if (send(s, (const char*)&buf, sizeof(buf), 0) < 0) #else @@ -555,18 +573,26 @@ iperf_udp_connect(struct iperf_test *test) { // XXX: Should this be changed to IESTREAMCONNECT? i_errno = IESTREAMWRITE; + closesocket(s); return -1; } + if (test->debug) { + fprintf(stderr, "waiting to receive response from server\n"); + } /* * Wait until the server replies back to us. */ if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); + closesocket(s); i_errno = IESTREAMREAD; return -1; } + if (test->debug) { + fprintf(stderr, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + } return s; } diff --git a/src/iperf_util.c b/src/iperf_util.c index 16d16c86d..cc5b5900e 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -38,6 +38,7 @@ #include #include #ifndef __WIN32__ +#include #include #include #include @@ -240,6 +241,7 @@ const char* hexdump(const unsigned char* msg, int len, int show_decode, return retval; buf += count; }//for + snprintf(buf, maxlen - sofar, "\n"); } return retval; }//hexdump diff --git a/src/net.c b/src/net.c index 11893c08c..51eee7ac8 100644 --- a/src/net.c +++ b/src/net.c @@ -166,7 +166,8 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, /* make connection to server */ int -netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout) +netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, + struct iperf_test *test) { struct addrinfo hints, *local_res = NULL, *server_res = NULL; int s, saved_errno; @@ -193,6 +194,11 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port return -1; } + if (test->debug) { + fprintf(stderr, "netdial, domain: %d proto: %d local: %s bind-dev: %s local-port: %d server: %s:%d timeout: %d, socket: %d\n", + domain, proto, local, bind_dev, local_port, server, port, timeout, s); + } + if (bind_dev) { #ifdef SO_BINDTODEVICE if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, @@ -426,7 +432,7 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) } if (test && test->debug > 1) { fprintf(stderr, "Nread:\n"); - fprintf(stderr, hexdump(oldbuf, count - nleft, 1, 1)); + fprintf(stderr, hexdump((const unsigned char*)oldbuf, count - nleft, 1, 1)); } return count - nleft; } @@ -444,7 +450,7 @@ Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) if (test && test->debug > 1) { fprintf(stderr, "Nwrite:\n"); - fprintf(stderr, hexdump(buf, count, 1, 1)); + fprintf(stderr, hexdump((const unsigned char*)buf, count, 1, 1)); } while (nleft > 0) { diff --git a/src/net.h b/src/net.h index f24301f3c..01ea59fa3 100644 --- a/src/net.h +++ b/src/net.h @@ -32,7 +32,8 @@ void nonblock(int s); int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); -int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout); +int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, + struct iperf_test *test); int netannounce(int domain, int proto, char *local, const char* bind_dev, int port); int Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test); int Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) /* __attribute__((hot)) */; From 42160426dc35edc8cdae2d774054c1a92edab214 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 16:05:23 -0700 Subject: [PATCH 12/45] More debugging around netannounce. --- src/iperf_server_api.c | 6 +++--- src/iperf_udp.c | 13 +++++++++++-- src/net.c | 9 ++++++++- src/net.h | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 2f6f0a21f..a9097191c 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -72,8 +72,8 @@ int iperf_server_listen(struct iperf_test *test) { retry: - if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, - test->server_port)) < 0) { + if ((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, + test->server_port, test)) < 0) { if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { /* If we get "Address family not supported by protocol", that ** probably means we were compiled with IPv6 but the running @@ -626,7 +626,7 @@ iperf_run_server(struct iperf_test *test) closesocket(test->listener); test->listener = -1; if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, - test->server_port)) < 0) { + test->server_port, test)) < 0) { cleanup_server(test); i_errno = IELISTEN; return -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 5fb38b7de..abdacc947 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -421,7 +421,11 @@ iperf_udp_accept(struct iperf_test *test) * Create a new "listening" socket to replace the one we were using before. */ test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, - test->server_port); + test->server_port, test); + if (test->debug) { + fprintf(stderr, "udp-accept, new prot-listener socket: %d\n", test->prot_listener); + } + if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; closesocket(s); @@ -460,11 +464,16 @@ iperf_udp_listen(struct iperf_test *test) int s; if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, - test->server_port)) < 0) { + test->server_port, test)) < 0) { i_errno = IESTREAMLISTEN; return -1; } + if (test->debug) { + fprintf(stderr, "iperf-udp-listen, fd: %d\n", s); + } + + /* * The caller will put this value into test->prot_listener. */ diff --git a/src/net.c b/src/net.c index 51eee7ac8..bb370a318 100644 --- a/src/net.c +++ b/src/net.c @@ -284,7 +284,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port /***************************************************************/ int -netannounce(int domain, int proto, char *local, const char* bind_dev, int port) +netannounce(int domain, int proto, char *local, const char* bind_dev, int port, struct iperf_test *test) { struct addrinfo hints, *res; char portstr[6]; @@ -292,6 +292,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) snprintf(portstr, 6, "%d", port); memset(&hints, 0, sizeof(hints)); + /* * If binding to the wildcard address with no explicit address * family specified, then force us to get an AF_INET6 socket. On @@ -316,6 +317,12 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port) return -1; s = socket(res->ai_family, proto, 0); + + if (test->debug) { + fprintf(stderr, "netannounce, domain: %d proto: %d local: %s bind-dev: %s port: %d fd: %d\n", + domain, proto, local, bind_dev, port, s); + } + if (s < 0) { freeaddrinfo(res); return -1; diff --git a/src/net.h b/src/net.h index 01ea59fa3..c80fedb09 100644 --- a/src/net.h +++ b/src/net.h @@ -34,7 +34,7 @@ void nonblock(int s); int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, struct iperf_test *test); -int netannounce(int domain, int proto, char *local, const char* bind_dev, int port); +int netannounce(int domain, int proto, char *local, const char* bind_dev, int port, struct iperf_test *test); int Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test); int Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) /* __attribute__((hot)) */; int has_sendfile(void); From ee7ef1c321c33d0c6876fab9d061847c9e0dfbda Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 16:06:17 -0700 Subject: [PATCH 13/45] Remove un-needed fd-clear. Signed-off-by: Ben Greear --- src/iperf_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index d9aadabea..07810835b 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1512,7 +1512,7 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP) } test->bytes_received += r; ++test->blocks_received; - IFD_CLR(sp->socket, read_setP, test); + /* IFD_CLR(sp->socket, read_setP, test); // Don't see how this is helpful. --Ben */ } } From 5925cc24adc99f3eeb4ce7955805318f9d40c3c6 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 16:16:36 -0700 Subject: [PATCH 14/45] Retry udp connect message. UDP is lossy, so maybe this will help reliability a bit. Signed-off-by: Ben Greear --- src/iperf_udp.c | 75 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/src/iperf_udp.c b/src/iperf_udp.c index abdacc947..c938c286f 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -490,6 +490,7 @@ int iperf_udp_connect(struct iperf_test *test) { int s, buf, sz; + int i; #ifdef SO_RCVTIMEO struct timeval tv; #endif @@ -573,36 +574,66 @@ iperf_udp_connect(struct iperf_test *test) hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); } - // This sucks: UDP messages can be lost and will not automatically be retransmitted. + for (i = 0; i<30; i++) { + fd_set read_fds; + FD_ZERO(&read_fds); //Zero out the file descriptor set + FD_SET(s, &read_fds); //Set the current socket file descriptor into the set + + /* UDP messages can be lost and will not automatically be retransmitted. + * so we will retry and use select to not block forever. + */ #ifdef __WIN32__ - if (send(s, (const char*)&buf, sizeof(buf), 0) < 0) + if (send(s, (const char*)&buf, sizeof(buf), 0) < 0) #else - if (write(s, &buf, sizeof(buf)) < 0) + if (write(s, &buf, sizeof(buf)) < 0) #endif - { - // XXX: Should this be changed to IESTREAMCONNECT? - i_errno = IESTREAMWRITE; - closesocket(s); - return -1; - } + { + // XXX: Should this be changed to IESTREAMCONNECT? + i_errno = IESTREAMWRITE; + closesocket(s); + return -1; + } - if (test->debug) { - fprintf(stderr, "waiting to receive response from server\n"); - } - /* - * Wait until the server replies back to us. - */ - if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { - fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); - closesocket(s); - i_errno = IESTREAMREAD; - return -1; + if (test->debug) { + fprintf(stderr, "waiting to receive response from server\n"); + } + + /* + * Wait until the server replies back to us. + */ + //We are going to use select to wait for the socket to connect + struct timeval tv; + tv.tv_sec = 1; //The second portion of the struct + tv.tv_usec = 0; //The microsecond portion of the struct + + int select_ret = select(s + 1, &read_fds, NULL, NULL, &tv); + if (select_ret == 1) { + if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { + fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); + closesocket(s); + i_errno = IESTREAMREAD; + return -1; + } + + if (test->debug) { + fprintf(stderr, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + } + } + else { + if (test->debug) { + fprintf(stderr, "No response from server, will retry: %d / 30", i); + } + } + return s; } + /* if here, we could not get a response in time. */ if (test->debug) { - fprintf(stderr, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + fprintf(stderr, "Did not receive UDP connect response in time.\n"); } - return s; + closesocket(s); + i_errno = IESTREAMREAD; + return -1; } From a1ac79e10e8ce47474176633bc17eb864aa96b0c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 16:36:16 -0700 Subject: [PATCH 15/45] Fix udp-connect retry logic, fix printing hexdump of socket communications. --- src/iperf_server_api.c | 2 ++ src/iperf_udp.c | 4 ++-- src/net.c | 24 ++++++++++++++++++++---- src/net.h | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index a9097191c..563557920 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -468,6 +468,7 @@ iperf_run_server(struct iperf_test *test) else fprintf(stderr, "timeout NULL, max-fd: %d state: %d(%s)\n", test->max_fd, test->state, iperf_get_state_str(test->state)); + print_fdset(test->max_fd, &read_set, &write_set); } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); @@ -477,6 +478,7 @@ iperf_run_server(struct iperf_test *test) iperf_get_state_str(test->state)); fprintf(stderr, "prot-listener: %d ISSET: %d max-fd: %d\n", test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); + print_fdset(test->max_fd, &read_set, &write_set); } if (result < 0 && errno != EINTR) { diff --git a/src/iperf_udp.c b/src/iperf_udp.c index c938c286f..435cb4d99 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -618,13 +618,13 @@ iperf_udp_connect(struct iperf_test *test) if (test->debug) { fprintf(stderr, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); } + return s; } else { if (test->debug) { - fprintf(stderr, "No response from server, will retry: %d / 30", i); + fprintf(stderr, "No response from server, will retry: %d / 30\n", i); } } - return s; } /* if here, we could not get a response in time. */ diff --git a/src/net.c b/src/net.c index bb370a318..a3e203383 100644 --- a/src/net.c +++ b/src/net.c @@ -96,6 +96,24 @@ void nonblock(int s) { }//nonblock #endif +void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set) { + fprintf(stderr, "read/write FD sets: "); + for (int i = 0; i<=max_fd; i++) { + if (FD_ISSET(i, read_set)) { + if (FD_ISSET(i, write_set)) { + fprintf(stderr, "%i RW ", i); + } + else { + fprintf(stderr, "%i RO ", i); + } + } + else if (FD_ISSET(i, write_set)) { + fprintf(stderr, "%i WO ", i); + } + } + fprintf(stderr, "\n"); +} + /* * timeout_connect adapted from netcat, via OpenBSD and FreeBSD * Copyright (c) 2001 Eric Jackson @@ -438,8 +456,7 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) buf += r; } if (test && test->debug > 1) { - fprintf(stderr, "Nread:\n"); - fprintf(stderr, hexdump((const unsigned char*)oldbuf, count - nleft, 1, 1)); + fprintf(stderr, "Nread:\n%s", hexdump((const unsigned char*)oldbuf, count - nleft, 1, 1)); } return count - nleft; } @@ -456,8 +473,7 @@ Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) register size_t nleft = count; if (test && test->debug > 1) { - fprintf(stderr, "Nwrite:\n"); - fprintf(stderr, hexdump((const unsigned char*)buf, count, 1, 1)); + fprintf(stderr, "Nwrite:\n%s", hexdump((const unsigned char*)buf, count, 1, 1)); } while (nleft > 0) { diff --git a/src/net.h b/src/net.h index c80fedb09..e968c67e0 100644 --- a/src/net.h +++ b/src/net.h @@ -31,6 +31,8 @@ void nonblock(int s); +void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set); + int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, struct iperf_test *test); From ef3c28d270560a02dcd63b9db81403a97fbff279 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 16:52:30 -0700 Subject: [PATCH 16/45] Never block select more than one second in server mode. Might help work around hung server situation seen in udp tests. --- src/timer.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/timer.c b/src/timer.c index 33923c79c..b30875b63 100644 --- a/src/timer.c +++ b/src/timer.c @@ -159,16 +159,27 @@ tmr_timeout( struct iperf_time* nowP ) static struct timeval timeout; getnow( nowP, &now ); + + /* For reasons I do not understand, the iperf server will sometimes hang in + * select and not accept new connections until some keyboard input happens + * (on Windows, at least). So, never block more than one second in select + * to try to mitigate this. --Ben + */ + timeout.tv_sec = 1; + timeout.tv_usec = 0; + /* Since the list is sorted, we only need to look at the first timer. */ - if ( timers == NULL ) - return NULL; - past = iperf_time_diff(&timers->time, &now, &diff); - if (past) - usecs = 0; - else - usecs = iperf_time_in_usecs(&diff); - timeout.tv_sec = usecs / 1000000LL; - timeout.tv_usec = usecs % 1000000LL; + if (timers) { + past = iperf_time_diff(&timers->time, &now, &diff); + if (past) + usecs = 0; + else + usecs = iperf_time_in_usecs(&diff); + timeout.tv_sec = usecs / 1000000LL; + timeout.tv_usec = usecs % 1000000LL; + if (timeout.tv_sec > 1) + timeout.tv_sec = 1; + } return &timeout; } From 715b773dfd96062c646c1e151fbac2444719e6a8 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 17:01:57 -0700 Subject: [PATCH 17/45] Do not block forever in udp-accept. Try for up to 30 seconds, using select to keep us from blocking. --- src/iperf_udp.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 435cb4d99..53e25d5c1 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -348,6 +348,7 @@ iperf_udp_accept(struct iperf_test *test) socklen_t len; int sz, s; int rc; + int i; /* * Get the current outstanding socket. This socket will be used to handle @@ -355,17 +356,46 @@ iperf_udp_accept(struct iperf_test *test) */ s = test->prot_listener; - /* - * Grab the UDP packet sent by the client. From that we can extract the - * client's address, and then use that information to bind the remote side - * of the socket to the client. - */ - len = sizeof(sa_peer); - if ((sz = recvfrom(test->prot_listener, (char*)&buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { - i_errno = IESTREAMACCEPT; - return -1; + for (i = 0; i<30; i++) { + fd_set read_fds; + FD_ZERO(&read_fds); //Zero out the file descriptor set + FD_SET(test->prot_listener, &read_fds); //Set the current socket file descriptor into the set + + /* Don't block forever if the peer messed up or cannot otherwise send frame + * this direction. + */ + struct timeval tv; + tv.tv_sec = 1; //The second portion of the struct + tv.tv_usec = 0; //The microsecond portion of the struct + + int select_ret = select(test->prot_listener + 1, &read_fds, NULL, NULL, &tv); + if (select_ret == 1) { + /* + * Grab the UDP packet sent by the client. From that we can extract the + * client's address, and then use that information to bind the remote side + * of the socket to the client. + */ + len = sizeof(sa_peer); + if ((sz = recvfrom(test->prot_listener, (char*)&buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { + i_errno = IESTREAMACCEPT; + return -1; + } + goto got_response; + } + else { + if (test->debug) { + fprintf(stderr, "Did not receive response, try %d / 30, in udp-accept.\n", + i); + } + } } + /* If here, we did not get a response in time. */ + fprintf(stderr, "Did not receive frame within 30 seconds in udp-accept.\n"); + i_errno = IESTREAMACCEPT; + return -1; + +got_response: if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { i_errno = IESTREAMACCEPT; return -1; From 9900d02b1357aee6bdac7d7c366bcda055d2bea1 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 17:18:02 -0700 Subject: [PATCH 18/45] Fix jitter calculation. On the first time we receive a packet, set jitter to zero and mark the previous time. Otherwise, the first jitter report is incorrect. Signed-off-by: Ben Greear --- src/iperf_api.c | 1 + src/iperf_udp.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 07810835b..9b8203752 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2726,6 +2726,7 @@ iperf_reset_stats(struct iperf_test *test) sp->omitted_cnt_error = sp->cnt_error; sp->omitted_outoforder_packets = sp->outoforder_packets; sp->jitter = 0; + sp->prev_transit = 0; rp = sp->result; rp->bytes_sent_omit = rp->bytes_sent; rp->bytes_received = 0; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 53e25d5c1..d67e7eae5 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -169,11 +169,16 @@ iperf_udp_recv(struct iperf_stream *sp) iperf_time_diff(&arrival_time, &sent_time, &temp_time); transit = iperf_time_in_secs(&temp_time); - d = transit - sp->prev_transit; - if (d < 0) - d = -d; - sp->prev_transit = transit; - sp->jitter += (d - sp->jitter) / 16.0; + if (sp->prev_transit) { + d = transit - sp->prev_transit; + if (d < 0) + d = -d; + sp->jitter += (d - sp->jitter) / 16.0; + } + else { + sp->jitter = 0; + } + sp->prev_transit = transit; } else { if (sp->test->debug) From e4b36b3b9c0d196040d81238efd91e10a73257b4 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 22 Oct 2019 17:29:56 -0700 Subject: [PATCH 19/45] Fix memory leak of json print object. Signed-off-by: Ben Greear --- src/iperf_api.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 9b8203752..31db9dcd0 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1813,7 +1813,9 @@ send_parameters(struct iperf_test *test) cJSON_AddStringToObject(j, "client_version", IPERF_VERSION); if (test->debug) { - printf("send_parameters:\n%s\n", cJSON_Print(j)); + char* jp = cJSON_Print(j); + printf("send_parameters:\n%s\n", jp); + free(jp); } if (JSON_write(test->ctrl_sck, j, test) < 0) { @@ -3498,7 +3500,9 @@ iperf_print_results(struct iperf_test *test) /* Print server output if we're on the client and it was requested/provided */ if (test->role == 'c' && iperf_get_test_get_server_output(test) && !test->json_output) { if (test->json_server_output) { - iperf_printf(test, "\nServer JSON output:\n%s\n", cJSON_Print(test->json_server_output)); + char* jp = cJSON_Print(test->json_server_output); + iperf_printf(test, "\nServer JSON output:\n%s\n", jp); + free(jp); cJSON_Delete(test->json_server_output); test->json_server_output = NULL; } From b8fc74a2ce152861cb67dbc8850a08870353329d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 23 Oct 2019 06:12:02 -0700 Subject: [PATCH 20/45] Support packaging nsis installer for Windows. And add a note about this being 'ct' specific iperf so users are not confused. Signed-off-by: Ben Greear --- README.md | 9 +- src/Makefile.mingw | 17 ++- src/iperf.nsis | 272 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 5 deletions(-) create mode 100644 src/iperf.nsis diff --git a/README.md b/README.md index 1472470d1..afe27f654 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ iperf3: A TCP, UDP, and SCTP network bandwidth measurement tool ================================================================ +NOTE +------ + +Modified by Candela Technologies to support compilation for Windows +(using mingw cross-compiler on Linux) and other bug fixes and features. + +https://github.com/greearb/iperf + Summary ------- @@ -71,7 +79,6 @@ Mode LastWriteTime Length Name -a--- 10/20/2019 8:33 PM 67090 libgnurx-0.dll -a--- 10/20/2019 8:35 PM 393870 libssl-10.dll -a--- 10/20/2019 8:47 PM 62672 libwinpthread-1.dll --a--- 10/20/2019 8:33 PM 91368 zlib1.dll Invoking iperf3 diff --git a/src/Makefile.mingw b/src/Makefile.mingw index e8ae50782..b18e610d4 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -13,8 +13,8 @@ BASIC_CCFLAGS = -g -O2 CCFLAGS = $(BASIC_CCFLAGS) -DHAVE_SNPRINTF -DHAVE_VSNPRINTF \ -DWINVER=0x0600 -D_WIN32_WINNT=0x0600 -DHAVE_REMOTE -BASIC_LDLIBS=-lm -lws2_32 -LDLIBS = $(BASIC_LDLIBS) -liphlpapi -lz -lssl -lcrypto +BASIC_LDLIBS=-lws2_32 +LDLIBS = $(BASIC_LDLIBS) -liphlpapi -lssl -lcrypto LDFLAGS := $(LDFLAGS) @@ -40,14 +40,23 @@ ALL_SRCS=${COMMON_SRCS} ${TARG}: $(COMMON_OBJS) $(CC) $(CCFLAGS) $(LDFLAGS) -o ${TARG} $(COMMON_OBJS)\ - $(LDLIBS) \ - -lwinmm -lsetupapi -luuid + $(LDLIBS) $(ALL_OBJS): %.o: %.c Makefile.mingw @echo " " @echo "Making object file $<" $(CC) $(CCFLAGS) -c $< +package_win32: ${TARG} + # Copy libraries into place so we can package them. + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll ./ + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libssl-10.dll ./ + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll ./ + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll ./ + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgnurx-0.dll ./ + cp ../LICENSE ./license.txt + makensis iperf.nsis + clean: rm -f ${ALL_OBJS} diff --git a/src/iperf.nsis b/src/iperf.nsis new file mode 100644 index 000000000..9bcdf912e --- /dev/null +++ b/src/iperf.nsis @@ -0,0 +1,272 @@ +; iper3-ct install script for NSIS. --Ben Greear +RequestExecutionLevel highest + +!include "MUI2.nsh" +!include "InstallOptions.nsh" + +; ------------------------------- +; Start + +!define LFS_VER 3.7-ct +!define MUI_PRODUCT "iperf3-ct {LFS_VER}" +!define LF_INSTALL_DIR "iperf3-ct" + +CRCCheck On + +;-------------------------------- +;General + +Name "iperf3-ct ${LFS_VER} Installer" +OutFile "iperf3-ct-${LFS_VER}-installer.exe" + +ShowInstDetails "hide" +ShowUninstDetails "hide" +SetCompressor "lzma" +; install icon +;!define MUI_ICON "Installer-box-server-256.ico" +; server desktop icon +;!define DT_ICON "brass_anvil_lh_server.ico" +; server lfconfig icon +;!define CF_ICON "brass_anvil_lh_config.ico" +; uninstaller icon +;!define MUI_UNICON ${MUI_ICON} + +; !define MUI_HEADERIMAGE +; !define MUI_HEADERIMAGE_RIGHT +; !define MUI_HEADERIMAGE_BITMAP "candela_swirl_small-57h.bmp" +; !define MUI_HEADERIMAGE_UNBITMAP "candela_swirl_small-57h.bmp" + +;-------------------------------- +;Folder selection page + +InstallDir "$PROGRAMFILES\${LF_INSTALL_DIR}" +InstallDirRegKey HKCU "Software\iperf3-ct" "" + + +;-------------------------------- +;Modern UI Configuration +!define MUI_ABORTWARNING +!define MUI_UNINSTALLER +!define MUI_WELCOMEPAGE + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "license.txt" +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_COMPONENTS +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" + +!define SMP_INST "$SMPROGRAMS\${LF_INSTALL_DIR}" + + +; ! macro plugin_init +; !echo "${NSISDIR}\Plugins\x86-unicode\InstallOptions.dll" +; !if /FileExists '"${NSISDIR}\Plugins\x86-unicode\InstallOptions.dll"' +!if `"${NSISDIR}\Plugins\x86-unicode\InstallOptions.dll"` + !echo "trying try_unicode_install_opts" + !define found_install_opts "${NSISDIR}\Plugins\x86-unicode\InstallOptions.dll" +!elseif /FileExists "${NSISDIR}\Plugins\x86-ansi\InstallOptions.dll" + !echo "trying try_ansi_install_opts" + !define found_install_opts "${NSISDIR}\Plugins\x86-ansi\InstallOptions.dll" +!elseif /FileExists "${NSISDIR}\Plugins\InstallOptions.dll" + !echo "trying old_install_opts: $found_install_opts" + !define found_install_opts "${NSISDIR}\Plugins\InstallOptions.dll" +!endif + +!ifdef found_install_opts + !echo "installoptions.dll: ${found_install_opts}" + ;ReserveFile /plugin "${found_install_opts}" +!else + !echo "no installoptions.dll $found_install_opts" +!endif +; ! macroend + + +Function .onInit + InitPluginsDir + + !ifdef found_install_opts + !echo "found_install_opts: ${found_install_opts}" + ReserveFile /plugin "${found_install_opts}" + !endif +FunctionEnd + + +;-------------------------------- +;Installer Sections +Section "install" Installation + +;Add files + SetOutPath "$INSTDIR" + +; Remove some old .dll files that could conflict with new +; installs (for instance, if we are using non-OEM winpcap) +; Delete "$INSTDIR\packet.dll" + + File "iperf3.exe" +; File ${MUI_ICON} +; File ${DT_ICON} +; File ${CF_ICON} + File "libwinpthread-1.dll" + File "libssl-10.dll" + File "libcrypto-10.dll" + File "libgcc_s_sjlj-1.dll" + File "libgnurx-0.dll" + +;write uninstall information to the registry + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${LF_INSTALL_DIR}" "DisplayName" "${MUI_PRODUCT} (remove only)" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${LF_INSTALL_DIR}" "UninstallString" "$INSTDIR\Uninstall.exe" + + WriteUninstaller "$INSTDIR\Uninstall.exe" + +SectionEnd + + +;-------------------------------- +;Uninstaller Section +Section "Uninstall" + +;Delete Files + RMDir /r "$INSTDIR\*.*" + +;Remove the installation directory + RMDir "$INSTDIR" + +;Delete Uninstaller And Unistall Registry Entries + DeleteRegKey HKLM "SOFTWARE\${LF_INSTALL_DIR}" + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${LF_INSTALL_DIR}" + +SectionEnd + +;Function that calls a messagebox when installation finished correctly +Function .onInstSuccess + MessageBox MB_OK \ + '${MUI_PRODUCT} was installed. Change to the install directory and run .\iperf3.exe --help for usage help' +FunctionEnd + +Function un.onUninstSuccess + ;MessageBox MB_OK "You have successfully uninstalled ${MUI_PRODUCT}." +FunctionEnd + +;------------------------------------------------------------------------------ +; FindWindowClose +; +; Closes a window if open. Also prompts user if closing fails. +; Use by passing the window class and title on the stack. +; You must pass both even if one is empty (i.e. ""). +; +; Usage: +; Push ThunderRT6FormDC +; Push "Visual Basic Form Name" +; Call FindWindowClose +; + +Function FindWindowClose + Exch $0 + Exch + Exch $1 + Push $2 + Push $3 + find: + FindWindow $2 $1 $0 + IntCmp $2 0 nowindow + MessageBox MB_YESNO "$0 must be stopped before continuing install. Would you like it stopped now?" IDNO nowindow + SendMessage $2 16 "" "" + Sleep 500 + FindWindow $2 $1 $0 + IntCmp $2 0 nowindow + MessageBox MB_OK|MB_ICONSTOP "An instance of the program $0 is running. Please close it and press OK to continue." + Goto find + nowindow: + ;MessageBox MB_OK "Program $0 is not running." + Pop $3 + Pop $2 + Pop $1 + Pop $0 +FunctionEnd + + +Function un.confirm_again + MessageBox MB_YESNO "Do you really want to uninstall ${LFS_VER} now?" IDYES dont_abt + Abort + dont_abt: +FunctionEnd + +;------------------------------------------------------------------------------ +; GetWindowsVersion +; +; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ +; Returns on top of stack +; +; Windows Version (95, 98, ME, NT x.x, 2000) +; or +; '' (Unknown Windows Version) +; +; Usage: +; Call GetWindowsVersion +; Pop $0 +; ; at this point $0 is "NT 4.0" or whatnot + +Function GetWindowsVersion + Push $0 + Push $9 + ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + StrCmp $0 "" 0 lbl_winnt + ; we are not NT. + ReadRegStr $0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion VersionNumber + + StrCpy $9 $0 1 + StrCmp $9 '4' 0 lbl_error + + StrCpy $9 $0 3 + + StrCmp $9 '4.0' lbl_win32_95 + StrCmp $9 '4.9' lbl_win32_ME lbl_win32_98 + + lbl_win32_95: + StrCpy $0 '95' + Goto lbl_done + + lbl_win32_98: + StrCpy $0 '98' + Goto lbl_done + + lbl_win32_ME: + StrCpy $0 'ME' + Goto lbl_done + + lbl_winnt: + + StrCpy $9 $0 1 + StrCmp $9 '3' lbl_winnt_x + StrCmp $9 '4' lbl_winnt_x + StrCmp $9 '5' lbl_winnt_5 lbl_error + + lbl_winnt_x: + StrCpy $0 "NT $0" 6 + Goto lbl_done + + lbl_winnt_5: + StrCmp $0 "5.1" lbl_wxp + Strcpy $0 '2000' + Goto lbl_done + lbl_wxp: + Strcpy $0 'XP' + Goto lbl_done + + lbl_error: + Strcpy $0 '' + lbl_done: + Pop $9 + Exch $0 +FunctionEnd + +; eof From a9cecdee7ca80bdc0b12bcbba65d65d239addf86 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 23 Oct 2019 07:19:51 -0700 Subject: [PATCH 21/45] Fix build on older C compilers. Cannot declare variables in for loops. Signed-off-by: Ben Greear --- src/iperf_util.c | 11 +++++++---- src/net.c | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/iperf_util.c b/src/iperf_util.c index cc5b5900e..59ba48449 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -70,7 +70,8 @@ int readentropy(void *out, size_t outsize) if (frandom == NULL) { // use rand() instead (this could be way more efficient but doesn't matter much) unsigned char* dest = (unsigned char*)out; - for (size_t i = 0; i= maxlen) return retval; - for (int j = i - (bytes_per_line - 1); j<=i; j++) { + for (j = i - (bytes_per_line - 1); j<=i; j++) { if (isprint(msg[j])) { count = snprintf(buf, maxlen - sofar, "%c", msg[j]); } @@ -217,11 +219,12 @@ const char* hexdump(const unsigned char* msg, int len, int show_decode, // do final char translations. int q = (i) % bytes_per_line; int offset = i-q; + int l, j; count = snprintf(buf, maxlen - sofar, " "); buf += count; if (sofar >= maxlen) return retval; - for (int l = 0; l< bytes_per_line-q; l++) { + for (l = 0; l< bytes_per_line-q; l++) { //space, where the hex would have gone. count = snprintf(buf, maxlen - sofar, " "); buf += count; @@ -230,7 +233,7 @@ const char* hexdump(const unsigned char* msg, int len, int show_decode, } //VLOG << "q: " << q << " offset: " << offset << " i: " << i << endl; - for (int j = 0; j Date: Wed, 23 Oct 2019 10:55:15 -0700 Subject: [PATCH 22/45] Windows cannot support setting ToS: Warn and continue. Signed-off-by: Ben Greear --- src/iperf_api.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/iperf_api.c b/src/iperf_api.c index 31db9dcd0..de9bc8196 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -3843,6 +3843,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) /* Set IP TOS */ if ((opt = test->settings->tos)) { +#ifndef __WIN32__ /* windows does not support setting ToS */ if (getsockdomain(sp->socket) == AF_INET6) { #ifdef IPV6_TCLASS if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, (const char*)&opt, sizeof(opt)) < 0) { @@ -3859,6 +3860,10 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) return -1; } } +#else + fprintf(stderr, "WARNING: ToS: 0x%x requested, but windows does not support setting ToS. Ignoring.\n", + test->settings->tos); +#endif } return 0; From e0af34ab4c76108b7f219ce7e5ae759a8821cf88 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 23 Oct 2019 15:48:02 -0700 Subject: [PATCH 23/45] Improve debugging. Still seeing lockups, though less often than at first. Add more debugging to try to understand where it is happening. --- src/iperf_api.c | 4 ++-- src/iperf_server_api.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index de9bc8196..4f0512ea9 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1677,7 +1677,7 @@ iperf_exchange_parameters(struct iperf_test *test) } void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { - if (test->debug) { + if (test->debug > 1) { fprintf(stderr, "FD-SET, fd: %d at %s:%d\n", fd, file, line); } @@ -1687,7 +1687,7 @@ void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, i } void _fd_clr(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { - if (test->debug) { + if (test->debug > 1) { fprintf(stderr, "FD-CLR, fd: %d at %s:%d\n", fd, file, line); } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 563557920..e0e6ef2ff 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -417,6 +417,7 @@ iperf_run_server(struct iperf_test *test) struct iperf_time now; struct timeval* timeout; int flag; + unsigned long last_dbg = 0; if (test->logfile) if (iperf_open_logfile(test) < 0) @@ -459,7 +460,7 @@ iperf_run_server(struct iperf_test *test) iperf_time_now(&now); timeout = tmr_timeout(&now); - if (test->debug) { + if (test->debug > 1 || (test->debug && (last_dbg != now.secs))) { if (timeout) fprintf(stderr, "timeout: %ld.%06ld max-fd: %d state: %d (%s)\n", (long)(timeout->tv_sec), (long)(timeout->tv_usec), test->max_fd, @@ -472,13 +473,14 @@ iperf_run_server(struct iperf_test *test) } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); - if (test->debug) { + if (test->debug > 1 || (test->debug && (last_dbg != now.secs))) { fprintf(stderr, "select result: %d, listener: %d ISSET-listener: %d test-state: %d(%s)\n", result, test->listener, FD_ISSET(test->listener, &read_set), test->state, iperf_get_state_str(test->state)); fprintf(stderr, "prot-listener: %d ISSET: %d max-fd: %d\n", test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); print_fdset(test->max_fd, &read_set, &write_set); + last_dbg = now.secs; } if (result < 0 && errno != EINTR) { From cbb57260ec8e4d8cdb3674d3735ca7ebcacc4fb1 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 09:52:54 -0700 Subject: [PATCH 24/45] Remove un-needed is_closed() logic. We already test for error conditions that would cause the socket to be closed so remove this check. --- src/iperf_server_api.c | 68 +++++++++++++++++++++--------------------- src/iperf_util.c | 30 ------------------- src/iperf_util.h | 2 -- 3 files changed, 34 insertions(+), 66 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index e0e6ef2ff..87081e371 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -576,44 +576,44 @@ iperf_run_server(struct iperf_test *test) } #endif /* HAVE_TCP_CONGESTION */ - if (!is_closed(s)) { - - if (rec_streams_accepted != streams_to_rec) { - flag = 0; - ++rec_streams_accepted; - } else if (send_streams_accepted != streams_to_send) { - flag = 1; - ++send_streams_accepted; - } + // This code used to check if socket was is-closed, but we specifically test + // and return if it is closed above, so no need for that check here. + + if (rec_streams_accepted != streams_to_rec) { + flag = 0; + ++rec_streams_accepted; + } else if (send_streams_accepted != streams_to_send) { + flag = 1; + ++send_streams_accepted; + } - if (flag != -1) { - sp = iperf_new_stream(test, s, flag); - if (!sp) { - cleanup_server(test); - return -1; - } + if (flag != -1) { + sp = iperf_new_stream(test, s, flag); + if (!sp) { + cleanup_server(test); + return -1; + } - if (sp->sender) - IFD_SET(s, &test->write_set, test); - else - IFD_SET(s, &test->read_set, test); - - /* - * If the protocol isn't UDP, or even if it is but - * we're the receiver, set nonblocking sockets. - * We need this to allow a server receiver to - * maintain interactivity with the control channel. - */ - if (test->protocol->id != Pudp || - !sp->sender) { - setnonblocking(s, 1); - } + if (sp->sender) + IFD_SET(s, &test->write_set, test); + else + IFD_SET(s, &test->read_set, test); + + /* + * If the protocol isn't UDP, or even if it is but + * we're the receiver, set nonblocking sockets. + * We need this to allow a server receiver to + * maintain interactivity with the control channel. + */ + if (test->protocol->id != Pudp || + !sp->sender) { + setnonblocking(s, 1); + } - if (test->on_new_stream) - test->on_new_stream(sp); + if (test->on_new_stream) + test->on_new_stream(sp); - flag = -1; - } + flag = -1; } IFD_CLR(test->prot_listener, &read_set, test); } diff --git a/src/iperf_util.c b/src/iperf_util.c index 59ba48449..1f3a11210 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -136,36 +136,6 @@ make_cookie(char *cookie) out[pos] = '\0'; } - -/* is_closed - * - * Test if the file descriptor fd is closed. - * - * Iperf uses this function to test whether a TCP stream socket - * is closed, because accepting and denying an invalid connection - * in iperf_tcp_accept is not considered an error. - */ - -int -is_closed(int fd) -{ - struct timeval tv; - fd_set readset; - - FD_ZERO(&readset); - FD_SET(fd, &readset); - tv.tv_sec = 0; - tv.tv_usec = 0; - - if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { - fprintf(stderr, "is-closed, had error for fd: %d: %s", fd, STRERROR); - if (errno == EBADF) - return 1; - } - return 0; -} - - const char* hexdump(const unsigned char* msg, int len, int show_decode, int add_newlines) { static char retval[24000]; diff --git a/src/iperf_util.h b/src/iperf_util.h index 9863d4cf5..87d77f303 100644 --- a/src/iperf_util.h +++ b/src/iperf_util.h @@ -44,8 +44,6 @@ void fill_with_repeating_pattern(void *out, size_t outsize); void make_cookie(char *); -int is_closed(int); - double timeval_to_double(struct timeval *tv); int timeval_equals(struct timeval *tv0, struct timeval *tv1); From cfe7ea43386943bbacb1b93a247d5c240b6b1e19 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 11:08:20 -0700 Subject: [PATCH 25/45] Add comments, and remove some un-needed calls to clear FDs Select will take care of re-setting the FDs on the next loop, no need to clear them in the socket processing logic. Signed-off-by: Ben Greear --- src/iperf_server_api.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 87081e371..9740063eb 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -489,14 +489,15 @@ iperf_run_server(struct iperf_test *test) i_errno = IESELECT; return -1; } + if (result > 0) { + // Check listener socket if (FD_ISSET(test->listener, &read_set)) { if (test->state != CREATE_STREAMS) { if (iperf_accept(test) < 0) { cleanup_server(test); return -1; } - IFD_CLR(test->listener, &read_set, test); // Set streams number if (test->mode == BIDIRECTIONAL) { @@ -511,12 +512,13 @@ iperf_run_server(struct iperf_test *test) } } } + + // Check control socket if (FD_ISSET(test->ctrl_sck, &read_set)) { if (iperf_handle_message_server(test) < 0) { cleanup_server(test); return -1; } - IFD_CLR(test->ctrl_sck, &read_set, test); } if (test->state == CREATE_STREAMS) { @@ -615,17 +617,18 @@ iperf_run_server(struct iperf_test *test) flag = -1; } - IFD_CLR(test->prot_listener, &read_set, test); } if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { if (test->protocol->id != Ptcp) { + // Stop listening for more protocol connections, we are full. IFD_CLR(test->prot_listener, &test->read_set, test); closesocket(test->prot_listener); test->prot_listener = -1; } else { if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { + // Re-open protocol listener socket, I am not sure why. --Ben IFD_CLR(test->listener, &test->read_set, test); closesocket(test->listener); test->listener = -1; @@ -691,8 +694,8 @@ iperf_run_server(struct iperf_test *test) return -1; } } - } - } + }/* if test is running state */ + }/* if some file descriptor has data to read/write */ if (result == 0 || (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { From 766542768d796339d15a7447fb679da6e1b5525b Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 13:51:03 -0700 Subject: [PATCH 26/45] Make all sockets non-blocking. Add helper methods to block on read/write operations for a defined amount of time. Check that full amounts were read/written, where previous code would have had bad logic on partial reads. Signed-off-by: Ben Greear --- src/iperf_api.c | 23 ++-- src/iperf_client_api.c | 10 +- src/iperf_error.c | 251 +++++++++++++++-------------------------- src/iperf_sctp.c | 2 +- src/iperf_server_api.c | 57 ++++++---- src/iperf_tcp.c | 25 +++- src/iperf_time.c | 10 ++ src/iperf_time.h | 2 + src/iperf_udp.c | 1 + src/net.c | 137 +++++++++++++++++----- src/net.h | 7 ++ 11 files changed, 292 insertions(+), 233 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 4f0512ea9..9cf6808cf 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1415,7 +1415,7 @@ int iperf_set_send_state(struct iperf_test *test, signed char state) { test->state = state; - if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp, test) < 0) { + if (waitWrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp, test, ctrl_wait_ms) != sizeof(state)) { i_errno = IESENDMESSAGE; return -1; } @@ -1636,7 +1636,7 @@ iperf_exchange_parameters(struct iperf_test *test) return -1; i_errno = IEAUTHTEST; err = htonl(i_errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { + if (waitWrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test, ctrl_wait_ms) != sizeof(err)) { i_errno = IECTRLWRITE; return -1; } @@ -1648,12 +1648,12 @@ iperf_exchange_parameters(struct iperf_test *test) if (iperf_set_send_state(test, SERVER_ERROR) != 0) return -1; err = htonl(i_errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { + if (waitWrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test, ctrl_wait_ms) != sizeof(err)) { i_errno = IECTRLWRITE; return -1; } err = htonl(errno); - if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { + if (waitWrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test, ctrl_wait_ms) != sizeof(err)) { i_errno = IECTRLWRITE; return -1; } @@ -2201,10 +2201,10 @@ JSON_write(int fd, cJSON *json, struct iperf_test *test) else { hsize = strlen(str); nsize = htonl(hsize); - if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp, test) < 0) + if (waitWrite(fd, (char*) &nsize, sizeof(nsize), Ptcp, test, ctrl_wait_ms) < 0) r = -1; else { - if (Nwrite(fd, str, hsize, Ptcp, test) < 0) + if (waitWrite(fd, str, hsize, Ptcp, test, ctrl_wait_ms) != hsize) r = -1; } free(str); @@ -2227,12 +2227,12 @@ JSON_read(int fd, struct iperf_test *test) * Then read the JSON into a buffer and parse it. Return a parsed JSON * structure, NULL if there was an error. */ - if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp, test) >= 0) { + if (waitRead(fd, (char*) &nsize, sizeof(nsize), Ptcp, test, ctrl_wait_ms) == sizeof(nsize)) { hsize = ntohl(nsize); /* Allocate a buffer to hold the JSON */ str = (char *) calloc(sizeof(char), hsize+1); /* +1 for trailing null */ if (str != NULL) { - rc = Nread(fd, str, hsize, Ptcp, test); + rc = waitRead(fd, str, hsize, Ptcp, test, ctrl_wait_ms); if (rc >= 0) { /* * We should be reading in the number of bytes corresponding to the @@ -2247,8 +2247,11 @@ JSON_read(int fd, struct iperf_test *test) printf("WARNING: Size of data read does not correspond to offered length\n"); } } + else { + fprintf(stderr, "WARNING: Error waiting for json read, hsize: %d, errno: %s", hsize, STRERROR); + } + free(str); } - free(str); } return json; } @@ -3997,7 +4000,7 @@ iperf_got_sigend(struct iperf_test *test) if (test->ctrl_sck >= 0) { test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE; - (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test); + waitWrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms); } i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM; iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno)); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index dd752ab05..818dad26c 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -241,7 +241,7 @@ iperf_handle_message_client(struct iperf_test *test) int rval; int32_t err; - if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test)) <= 0) { + if ((rval = waitRead(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms)) != sizeof(signed char)) { if (rval == 0) { i_errno = IECTRLCLOSE; return -1; @@ -310,12 +310,12 @@ iperf_handle_message_client(struct iperf_test *test) i_errno = IEACCESSDENIED; return -1; case SERVER_ERROR: - if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { + if (waitRead(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test, ctrl_wait_ms) != sizeof(err)) { i_errno = IECTRLREAD; return -1; } i_errno = ntohl(err); - if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test) < 0) { + if (waitRead(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp, test, ctrl_wait_ms) != sizeof(err)) { i_errno = IECTRLREAD; return -1; } @@ -350,7 +350,9 @@ iperf_connect(struct iperf_test *test) return -1; } - if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test) < 0) { + setnonblocking(test->ctrl_sck, 1); + + if (waitWrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms) != COOKIE_SIZE) { i_errno = IESENDCOOKIE; return -1; } diff --git a/src/iperf_error.c b/src/iperf_error.c index 068c44e2b..5659dd5c7 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -92,306 +92,231 @@ iperf_strerror(int int_errno) len = sizeof(errstr); memset(errstr, 0, len); + /* Put text on same line as error to make grepping easier */ switch (int_errno) { - case IENONE: - snprintf(errstr, len, "no error"); + case IENONE: snprintf(errstr, len, "no error"); break; - case IESERVCLIENT: - snprintf(errstr, len, "cannot be both server and client"); + case IESERVCLIENT: snprintf(errstr, len, "cannot be both server and client"); break; - case IENOROLE: - snprintf(errstr, len, "must either be a client (-c) or server (-s)"); + case IENOROLE: snprintf(errstr, len, "must either be a client (-c) or server (-s)"); break; - case IESERVERONLY: - snprintf(errstr, len, "some option you are trying to set is server only"); + case IESERVERONLY: snprintf(errstr, len, "some option you are trying to set is server only"); break; - case IECLIENTONLY: - snprintf(errstr, len, "some option you are trying to set is client only"); + case IECLIENTONLY: snprintf(errstr, len, "some option you are trying to set is client only"); break; - case IEDURATION: - snprintf(errstr, len, "test duration too long (maximum = %d seconds)", MAX_TIME); + case IEDURATION: snprintf(errstr, len, "test duration too long (maximum = %d seconds)", MAX_TIME); break; - case IENUMSTREAMS: - snprintf(errstr, len, "number of parallel streams too large (maximum = %d)", MAX_STREAMS); + case IENUMSTREAMS: snprintf(errstr, len, "number of parallel streams too large (maximum = %d)", MAX_STREAMS); break; - case IEBLOCKSIZE: - snprintf(errstr, len, "block size too large (maximum = %d bytes)", MAX_BLOCKSIZE); + case IEBLOCKSIZE: snprintf(errstr, len, "block size too large (maximum = %d bytes)", MAX_BLOCKSIZE); break; - case IEBUFSIZE: - snprintf(errstr, len, "socket buffer size too large (maximum = %d bytes)", MAX_TCP_BUFFER); + case IEBUFSIZE: snprintf(errstr, len, "socket buffer size too large (maximum = %d bytes)", MAX_TCP_BUFFER); break; - case IEINTERVAL: - snprintf(errstr, len, "invalid report interval (min = %g, max = %g seconds)", MIN_INTERVAL, MAX_INTERVAL); + case IEINTERVAL: snprintf(errstr, len, "invalid report interval (min = %g, max = %g seconds)", MIN_INTERVAL, MAX_INTERVAL); break; - case IEBIND: /* UNUSED */ - snprintf(errstr, len, "--bind must be specified to use --cport"); + case IEBIND: /* UNUSED */ snprintf(errstr, len, "--bind must be specified to use --cport"); break; - case IEUDPBLOCKSIZE: - snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE); + case IEUDPBLOCKSIZE: snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE); break; - case IEBADTOS: - snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)"); + case IEBADTOS: snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)"); break; - case IESETCLIENTAUTH: - snprintf(errstr, len, "you must specify username (max 20 chars), password (max 20 chars) and a path to a valid public rsa client to be used"); + case IESETCLIENTAUTH: snprintf(errstr, len, "you must specify username (max 20 chars), password (max 20 chars) and a path to a valid public rsa client to be used"); break; - case IESETSERVERAUTH: - snprintf(errstr, len, "you must specify path to a valid private rsa server to be used and a user credential file"); + case IESETSERVERAUTH: snprintf(errstr, len, "you must specify path to a valid private rsa server to be used and a user credential file"); break; - case IEBADFORMAT: - snprintf(errstr, len, "bad format specifier (valid formats are in the set [kmgtKMGT])"); + case IEBADFORMAT: snprintf(errstr, len, "bad format specifier (valid formats are in the set [kmgtKMGT])"); break; - case IEBADPORT: - snprintf(errstr, len, "port number must be between 1 and 65535 inclusive"); + case IEBADPORT: snprintf(errstr, len, "port number must be between 1 and 65535 inclusive"); break; - case IEMSS: - snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS); + case IEMSS: snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS); break; - case IENOSENDFILE: - snprintf(errstr, len, "this OS does not support sendfile"); + case IENOSENDFILE: snprintf(errstr, len, "this OS does not support sendfile"); break; - case IEOMIT: - snprintf(errstr, len, "bogus value for --omit"); + case IEOMIT: snprintf(errstr, len, "bogus value for --omit"); break; - case IEUNIMP: - snprintf(errstr, len, "an option you are trying to set is not implemented yet"); + case IEUNIMP: snprintf(errstr, len, "an option you are trying to set is not implemented yet"); break; - case IEFILE: - snprintf(errstr, len, "unable to open -F file"); + case IEFILE: snprintf(errstr, len, "unable to open -F file"); perr = 1; break; - case IEBURST: - snprintf(errstr, len, "invalid burst count (maximum = %d)", MAX_BURST); + case IEBURST: snprintf(errstr, len, "invalid burst count (maximum = %d)", MAX_BURST); break; - case IEENDCONDITIONS: - snprintf(errstr, len, "only one test end condition (-t, -n, -k) may be specified"); + case IEENDCONDITIONS: snprintf(errstr, len, "only one test end condition (-t, -n, -k) may be specified"); break; - case IELOGFILE: - snprintf(errstr, len, "unable to open log file"); + case IELOGFILE: snprintf(errstr, len, "unable to open log file"); perr = 1; break; - case IENOSCTP: - snprintf(errstr, len, "no SCTP support available"); + case IENOSCTP: snprintf(errstr, len, "no SCTP support available"); break; - case IENEWTEST: - snprintf(errstr, len, "unable to create a new test"); + case IENEWTEST: snprintf(errstr, len, "unable to create a new test"); perr = 1; break; - case IEINITTEST: - snprintf(errstr, len, "test initialization failed"); + case IEINITTEST: snprintf(errstr, len, "test initialization failed"); perr = 1; break; - case IEAUTHTEST: - snprintf(errstr, len, "test authorization failed"); + case IEAUTHTEST: snprintf(errstr, len, "test authorization failed"); break; - case IELISTEN: - snprintf(errstr, len, "unable to start listener for connections"); + case IELISTEN: snprintf(errstr, len, "unable to start listener for connections"); herr = 1; perr = 1; break; - case IECONNECT: - snprintf(errstr, len, "unable to connect to server"); + case IECONNECT: snprintf(errstr, len, "unable to connect to server"); perr = 1; herr = 1; break; - case IEACCEPT: - snprintf(errstr, len, "unable to accept connection from client"); + case IEACCEPT: snprintf(errstr, len, "unable to accept connection from client"); herr = 1; perr = 1; break; - case IESENDCOOKIE: - snprintf(errstr, len, "unable to send cookie to server"); + case IESENDCOOKIE: snprintf(errstr, len, "unable to send cookie to server"); perr = 1; break; - case IERECVCOOKIE: - snprintf(errstr, len, "unable to receive cookie at server"); + case IERECVCOOKIE: snprintf(errstr, len, "unable to receive cookie at server"); perr = 1; break; - case IECTRLWRITE: - snprintf(errstr, len, "unable to write to the control socket"); + case IECTRLWRITE: snprintf(errstr, len, "unable to write to the control socket"); perr = 1; break; - case IECTRLREAD: - snprintf(errstr, len, "unable to read from the control socket"); + case IECTRLREAD: snprintf(errstr, len, "unable to read from the control socket"); perr = 1; break; - case IECTRLCLOSE: - snprintf(errstr, len, "control socket has closed unexpectedly"); + case IECTRLCLOSE: snprintf(errstr, len, "control socket has closed unexpectedly"); break; - case IEMESSAGE: - snprintf(errstr, len, "received an unknown control message"); + case IEMESSAGE: snprintf(errstr, len, "received an unknown control message"); break; - case IESENDMESSAGE: - snprintf(errstr, len, "unable to send control message"); + case IESENDMESSAGE: snprintf(errstr, len, "unable to send control message"); perr = 1; break; - case IERECVMESSAGE: - snprintf(errstr, len, "unable to receive control message"); + case IERECVMESSAGE: snprintf(errstr, len, "unable to receive control message"); perr = 1; break; - case IESENDPARAMS: - snprintf(errstr, len, "unable to send parameters to server"); + case IESENDPARAMS: snprintf(errstr, len, "unable to send parameters to server"); perr = 1; break; - case IERECVPARAMS: - snprintf(errstr, len, "unable to receive parameters from client"); + case IERECVPARAMS: snprintf(errstr, len, "unable to receive parameters from client"); perr = 1; break; - case IEPACKAGERESULTS: - snprintf(errstr, len, "unable to package results"); + case IEPACKAGERESULTS: snprintf(errstr, len, "unable to package results"); perr = 1; break; - case IESENDRESULTS: - snprintf(errstr, len, "unable to send results"); + case IESENDRESULTS: snprintf(errstr, len, "unable to send results"); perr = 1; break; - case IERECVRESULTS: - snprintf(errstr, len, "unable to receive results"); + case IERECVRESULTS: snprintf(errstr, len, "unable to receive results"); perr = 1; break; - case IESELECT: - snprintf(errstr, len, "select failed"); + case IESELECT: snprintf(errstr, len, "select failed"); perr = 1; break; - case IECLIENTTERM: - snprintf(errstr, len, "the client has terminated"); + case IECLIENTTERM: snprintf(errstr, len, "the client has terminated"); break; - case IESERVERTERM: - snprintf(errstr, len, "the server has terminated"); + case IESERVERTERM: snprintf(errstr, len, "the server has terminated"); break; - case IEACCESSDENIED: - snprintf(errstr, len, "the server is busy running a test. try again later"); + case IEACCESSDENIED: snprintf(errstr, len, "the server is busy running a test. try again later"); break; - case IESETNODELAY: - snprintf(errstr, len, "unable to set TCP/SCTP NODELAY"); + case IESETNODELAY: snprintf(errstr, len, "unable to set TCP/SCTP NODELAY"); perr = 1; break; - case IESETMSS: - snprintf(errstr, len, "unable to set TCP/SCTP MSS"); + case IESETMSS: snprintf(errstr, len, "unable to set TCP/SCTP MSS"); perr = 1; break; - case IESETBUF: - snprintf(errstr, len, "unable to set socket buffer size"); + case IESETBUF: snprintf(errstr, len, "unable to set socket buffer size"); perr = 1; break; - case IESETTOS: - snprintf(errstr, len, "unable to set IP TOS"); + case IESETTOS: snprintf(errstr, len, "unable to set IP TOS"); perr = 1; break; - case IESETCOS: - snprintf(errstr, len, "unable to set IPv6 traffic class"); + case IESETCOS: snprintf(errstr, len, "unable to set IPv6 traffic class"); perr = 1; break; - case IESETFLOW: - snprintf(errstr, len, "unable to set IPv6 flow label"); + case IESETFLOW: snprintf(errstr, len, "unable to set IPv6 flow label"); break; - case IEREUSEADDR: - snprintf(errstr, len, "unable to reuse address on socket"); + case IEREUSEADDR: snprintf(errstr, len, "unable to reuse address on socket"); perr = 1; break; - case IENONBLOCKING: - snprintf(errstr, len, "unable to set socket to non-blocking"); + case IENONBLOCKING: snprintf(errstr, len, "unable to set socket to non-blocking"); perr = 1; break; - case IESETWINDOWSIZE: - snprintf(errstr, len, "unable to set socket window size"); + case IESETWINDOWSIZE: snprintf(errstr, len, "unable to set socket window size"); perr = 1; break; - case IEPROTOCOL: - snprintf(errstr, len, "protocol does not exist"); + case IEPROTOCOL: snprintf(errstr, len, "protocol does not exist"); break; - case IEAFFINITY: - snprintf(errstr, len, "unable to set CPU affinity"); + case IEAFFINITY: snprintf(errstr, len, "unable to set CPU affinity"); perr = 1; break; - case IEDAEMON: - snprintf(errstr, len, "unable to become a daemon"); + case IEDAEMON: snprintf(errstr, len, "unable to become a daemon"); perr = 1; break; - case IECREATESTREAM: - snprintf(errstr, len, "unable to create a new stream"); + case IECREATESTREAM: snprintf(errstr, len, "unable to create a new stream"); herr = 1; perr = 1; break; - case IEINITSTREAM: - snprintf(errstr, len, "unable to initialize stream"); + case IEINITSTREAM: snprintf(errstr, len, "unable to initialize stream"); herr = 1; perr = 1; break; - case IESTREAMLISTEN: - snprintf(errstr, len, "unable to start stream listener"); + case IESTREAMLISTEN: snprintf(errstr, len, "unable to start stream listener"); herr = 1; perr = 1; break; - case IESTREAMCONNECT: - snprintf(errstr, len, "unable to connect stream"); + case IESTREAMCONNECT: snprintf(errstr, len, "unable to connect stream"); herr = 1; perr = 1; break; - case IESTREAMACCEPT: - snprintf(errstr, len, "unable to accept stream connection"); + case IESTREAMACCEPT: snprintf(errstr, len, "unable to accept stream connection"); perr = 1; break; - case IESTREAMWRITE: - snprintf(errstr, len, "unable to write to stream socket"); + case IESTREAMWRITE: snprintf(errstr, len, "unable to write to stream socket"); perr = 1; break; - case IESTREAMREAD: - snprintf(errstr, len, "unable to read from stream socket"); + case IESTREAMREAD: snprintf(errstr, len, "unable to read from stream socket"); perr = 1; break; - case IESTREAMCLOSE: - snprintf(errstr, len, "stream socket has closed unexpectedly"); + case IESTREAMCLOSE: snprintf(errstr, len, "stream socket has closed unexpectedly"); break; - case IESTREAMID: - snprintf(errstr, len, "stream has an invalid id"); + case IESTREAMID: snprintf(errstr, len, "stream has an invalid id"); break; - case IENEWTIMER: - snprintf(errstr, len, "unable to create new timer"); + case IENEWTIMER: snprintf(errstr, len, "unable to create new timer"); perr = 1; break; - case IEUPDATETIMER: - snprintf(errstr, len, "unable to update timer"); + case IEUPDATETIMER: snprintf(errstr, len, "unable to update timer"); perr = 1; break; - case IESETCONGESTION: - snprintf(errstr, len, "unable to set TCP_CONGESTION: " - "Supplied congestion control algorithm not supported on this host"); + case IESETCONGESTION: snprintf(errstr, len, "unable to set TCP_CONGESTION: " + "Supplied congestion control algorithm not supported on this host"); break; - case IEPIDFILE: - snprintf(errstr, len, "unable to write PID file"); + case IEPIDFILE: snprintf(errstr, len, "unable to write PID file"); perr = 1; break; - case IEV6ONLY: - snprintf(errstr, len, "Unable to set/reset IPV6_V6ONLY"); + case IEV6ONLY: snprintf(errstr, len, "Unable to set/reset IPV6_V6ONLY"); perr = 1; break; - case IESETSCTPDISABLEFRAG: - snprintf(errstr, len, "unable to set SCTP_DISABLE_FRAGMENTS"); + case IESETSCTPDISABLEFRAG: snprintf(errstr, len, "unable to set SCTP_DISABLE_FRAGMENTS"); perr = 1; break; - case IESETSCTPNSTREAM: - snprintf(errstr, len, "unable to set SCTP_INIT num of SCTP streams\n"); + case IESETSCTPNSTREAM: snprintf(errstr, len, "unable to set SCTP_INIT num of SCTP streams\n"); perr = 1; break; - case IESETPACING: - snprintf(errstr, len, "unable to set socket pacing"); + case IESETPACING: snprintf(errstr, len, "unable to set socket pacing"); perr = 1; break; - case IESETBUF2: - snprintf(errstr, len, "socket buffer size not set correctly"); + case IESETBUF2: snprintf(errstr, len, "socket buffer size not set correctly"); break; - case IEREVERSEBIDIR: - snprintf(errstr, len, "cannot be both reverse and bidirectional"); - break; - + case IEREVERSEBIDIR: snprintf(errstr, len, "cannot be both reverse and bidirectional"); + break; } /* Append the result of strerror() or gai_strerror() if appropriate */ if (herr || perr) strncat(errstr, ": ", len - strlen(errstr) - 1); +#ifndef __WIN32__ if (errno && perr) strncat(errstr, strerror(errno), len - strlen(errstr) - 1); +#else + if (perr) + strncat(errstr, STRERROR, len - strlen(errstr) - 1); +#endif else if (herr && gerror) { strncat(errstr, gai_strerror(gerror), len - strlen(errstr) - 1); gerror = 0; diff --git a/src/iperf_sctp.c b/src/iperf_sctp.c index 9c4e25220..0ff91f2ae 100644 --- a/src/iperf_sctp.c +++ b/src/iperf_sctp.c @@ -480,7 +480,7 @@ iperf_sctp_connect(struct iperf_test *test) freeaddrinfo(server_res); /* Send cookie for verification */ - if (Nwrite(s, test->cookie, COOKIE_SIZE, Psctp, test) < 0) { + if (waitWrite(s, test->cookie, COOKIE_SIZE, Psctp, test, ctrl_wait_ms) != COOKIE_SIZE) { saved_errno = errno; close(s); errno = saved_errno; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 9740063eb..b744f73d8 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -99,6 +99,8 @@ iperf_server_listen(struct iperf_test *test) iflush(test); } + setnonblocking(test->listener, 1); + FD_ZERO(&test->read_set); FD_ZERO(&test->write_set); IFD_SET(test->listener, &test->read_set, test); @@ -109,7 +111,7 @@ iperf_server_listen(struct iperf_test *test) int iperf_accept(struct iperf_test *test) { - int s; + int s = -1; signed char rbuf = ACCESS_DENIED; socklen_t len; struct sockaddr_storage addr; @@ -127,22 +129,23 @@ iperf_accept(struct iperf_test *test) if (test->ctrl_sck == -1) { /* Server free, accept new client */ test->ctrl_sck = s; - int rv = Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test); - if (rv < 0) { - fprintf(stderr, "Accept problem, ctrl-sck: %d s: %d listener: %d Nread rv: %d\n", + + int rv = waitRead(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms); + if (rv != COOKIE_SIZE) { + fprintf(stderr, "Accept problem, ctrl-sck: %d s: %d listener: %d waitRead rv: %d\n", test->ctrl_sck, s, test->listener, rv); i_errno = IERECVCOOKIE; - return -1; + goto out_err; } IFD_SET(test->ctrl_sck, &test->read_set, test); if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0) - return -1; + goto out_err; if (iperf_exchange_parameters(test) < 0) - return -1; + goto out_err; if (test->server_affinity != -1) if (iperf_setaffinity(test, test->server_affinity) != 0) - return -1; + goto out_err; if (test->on_connect) test->on_connect(test); } else { @@ -150,15 +153,22 @@ iperf_accept(struct iperf_test *test) * Don't try to read from the socket. It could block an ongoing test. * Just send ACCESS_DENIED. */ - if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test) < 0) { + if (waitWrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test, ctrl_wait_ms) != sizeof(rbuf)) { i_errno = IESENDMESSAGE; - closesocket(s); - return -1; + goto out_err; } closesocket(s); } return 0; + +out_err: + if (s >= 0) { + closesocket(s); + if (test->ctrl_sck == s) + test->ctrl_sck = -1; + } + return -1; } @@ -170,7 +180,7 @@ iperf_handle_message_server(struct iperf_test *test) struct iperf_stream *sp; // XXX: Need to rethink how this behaves to fit API - if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test)) <= 0) { + if ((rval = waitRead(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms)) != sizeof(signed char)) { if (rval == 0) { iperf_err(test, "the client has unexpectedly closed the connection"); i_errno = IECTRLCLOSE; @@ -369,11 +379,11 @@ static void cleanup_server(struct iperf_test *test) { /* Close open test sockets */ - if (test->ctrl_sck) { + if (test->ctrl_sck != -1) { closesocket(test->ctrl_sck); test->ctrl_sck = -1; } - if (test->listener) { + if (test->listener != -1) { closesocket(test->listener); test->listener = -1; } @@ -529,6 +539,10 @@ iperf_run_server(struct iperf_test *test) return -1; } + /* Use non-blocking IO so we don't accidentally end up + * hanging on socket operations. */ + setnonblocking(s, 1); + if (test->debug) { fprintf(stderr, "create-streams, accepted socket: %d\n", s); } @@ -596,22 +610,12 @@ iperf_run_server(struct iperf_test *test) return -1; } + // TODO: For read+write, do we need to set this fd in both sets? if (sp->sender) IFD_SET(s, &test->write_set, test); else IFD_SET(s, &test->read_set, test); - /* - * If the protocol isn't UDP, or even if it is but - * we're the receiver, set nonblocking sockets. - * We need this to allow a server receiver to - * maintain interactivity with the control channel. - */ - if (test->protocol->id != Pudp || - !sp->sender) { - setnonblocking(s, 1); - } - if (test->on_new_stream) test->on_new_stream(sp); @@ -638,6 +642,9 @@ iperf_run_server(struct iperf_test *test) i_errno = IELISTEN; return -1; } + + setnonblocking(s, 1); + test->listener = s; IFD_SET(test->listener, &test->read_set, test); } diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 76d2a5b84..872ec838c 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -120,18 +120,23 @@ iperf_tcp_accept(struct iperf_test * test) struct sockaddr_storage addr; len = sizeof(addr); + + /* Wait a bit until the peer attempts a connection */ + waitSocketReadable(test->listener, ctrl_wait_ms); + if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { + fprintf(stderr, "tcp-accept, accept failed: %s\n", STRERROR); i_errno = IESTREAMCONNECT; return -1; } - if (Nread(s, cookie, COOKIE_SIZE, Ptcp, test) < 0) { + if (waitRead(s, cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms) != COOKIE_SIZE) { i_errno = IERECVCOOKIE; return -1; } if (strcmp(test->cookie, cookie) != 0) { - if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test) < 0) { + if (waitWrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test, ctrl_wait_ms) != sizeof(rbuf)) { i_errno = IESENDMESSAGE; return -1; } @@ -146,6 +151,7 @@ iperf_tcp_accept(struct iperf_test * test) /* iperf_tcp_listen * * start up a listener for TCP stream connections + * Returns non-blocking socket. */ int iperf_tcp_listen(struct iperf_test *test) @@ -201,6 +207,8 @@ iperf_tcp_listen(struct iperf_test *test) return -1; } + setnonblocking(s, 1); + if (test->bind_dev) { #ifdef SO_BINDTODEVICE if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, @@ -392,6 +400,7 @@ iperf_tcp_listen(struct iperf_test *test) * This function is roughly similar to netdial(), and may indeed have * been derived from it at some point, but it sets many TCP-specific * options between socket creation and connection. + * Returns non-blocking socket */ int iperf_tcp_connect(struct iperf_test *test) @@ -408,6 +417,7 @@ iperf_tcp_connect(struct iperf_test *test) hints.ai_family = test->settings->domain; hints.ai_socktype = SOCK_STREAM; if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) { + fprintf(stderr, "tcp-connect, getaddrinfo failed: %s\n", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -420,6 +430,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) { if (test->bind_address) freeaddrinfo(local_res); + fprintf(stderr, "tcp-connect, getaddrinfo (server) failed: %s\n", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -427,10 +438,13 @@ iperf_tcp_connect(struct iperf_test *test) if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) { freeaddrinfo(local_res); freeaddrinfo(server_res); + fprintf(stderr, "tcp-connect, socket() failed: %s\n", STRERROR); i_errno = IESTREAMCONNECT; return -1; } + setnonblocking(s, 1); + if (test->bind_dev) { #ifdef SO_BINDTODEVICE if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, @@ -457,6 +471,7 @@ iperf_tcp_connect(struct iperf_test *test) lcladdr->sin_port = htons(test->bind_port); if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { + fprintf(stderr, "tcp-connect, bind() failed: %s\n", STRERROR); saved_errno = errno; closesocket(s); freeaddrinfo(local_res); @@ -499,6 +514,7 @@ iperf_tcp_connect(struct iperf_test *test) } if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { + fprintf(stderr, "tcp-connect, bind2() failed: %s\n", STRERROR); saved_errno = errno; closesocket(s); freeaddrinfo(server_res); @@ -662,7 +678,8 @@ iperf_tcp_connect(struct iperf_test *test) } } - if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { + if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && !eWouldBlock()) { + fprintf(stderr, "tcp-connect, connect() failed: %s\n", STRERROR); saved_errno = errno; closesocket(s); freeaddrinfo(server_res); @@ -674,7 +691,7 @@ iperf_tcp_connect(struct iperf_test *test) freeaddrinfo(server_res); /* Send cookie for verification */ - if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp, test) < 0) { + if (waitWrite(s, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms) != COOKIE_SIZE) { saved_errno = errno; closesocket(s); errno = saved_errno; diff --git a/src/iperf_time.c b/src/iperf_time.c index 5f94dc011..11bd9a57b 100644 --- a/src/iperf_time.c +++ b/src/iperf_time.c @@ -65,6 +65,16 @@ iperf_time_now(struct iperf_time *time1) #endif +uint64_t getCurMs() { + struct iperf_time tv; + uint64_t rv; + iperf_time_now(&tv); + rv = tv.secs * 1000; + rv += tv.usecs / 1000; + return rv; +} + + /* iperf_time_add_usecs * * Add a number of microseconds to a iperf_time. diff --git a/src/iperf_time.h b/src/iperf_time.h index 588ee2624..10c668ab3 100644 --- a/src/iperf_time.h +++ b/src/iperf_time.h @@ -46,4 +46,6 @@ uint64_t iperf_time_in_usecs(struct iperf_time *time); double iperf_time_in_secs(struct iperf_time *time); +uint64_t getCurMs(); + #endif diff --git a/src/iperf_udp.c b/src/iperf_udp.c index d67e7eae5..f9e8c8746 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -538,6 +538,7 @@ iperf_udp_connect(struct iperf_test *test) /* Create and bind our local socket. */ if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1, test)) < 0) { + fprintf(stderr, "udp-connect, netdial() failed: %s\n", STRERROR); i_errno = IESTREAMCONNECT; return -1; } diff --git a/src/net.c b/src/net.c index a0360fbf7..e7d1cc8cd 100644 --- a/src/net.c +++ b/src/net.c @@ -74,6 +74,9 @@ */ extern int gerror; +int ctrl_wait_ms = 5000; + + #ifdef __WIN32__ void nonblock(int s) { @@ -118,6 +121,7 @@ void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set) { /* * timeout_connect adapted from netcat, via OpenBSD and FreeBSD * Copyright (c) 2001 Eric Jackson + * Now it assumes non-blocking socket passed in. */ int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, @@ -128,14 +132,8 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int ret; flags = 0; - if (timeout != -1) { -#ifndef __WIN32__ - flags = fcntl(s, F_GETFL, 0); -#endif - nonblock(s); - } - if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { + if ((ret = connect(s, name, namelen)) != 0 && eWouldBlock()) { #ifndef __WIN32__ struct pollfd pfd; pfd.fd = s; @@ -151,9 +149,8 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, tv.tv_sec = timeout / 1000; //The second portion of the struct tv.tv_usec = (timeout % 1000) * 1000; //The microsecond portion of the struct - //DEBUG: This is ALWAYS 1 - int select_ret = select(s + 1, NULL, &write_fds, NULL, &tv); - if (select_ret == 1) + int ret = select(s + 1, NULL, &write_fds, NULL, &tv); + if (ret == 1) #endif { optlen = sizeof(optval); @@ -169,19 +166,13 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, ret = -1; } - if (timeout != -1) { -#ifndef __WIN32__ - fcntl(s, F_SETFL, flags); -#endif - /* TODO: Implement this for Windows? */ - } - return (ret); } /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ * Copyright: http://swtch.com/libtask/COPYRIGHT -*/ + * Returns non-blocking socket. + */ /* make connection to server */ int @@ -213,6 +204,8 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port return -1; } + setnonblocking(s, 1); + if (test->debug) { fprintf(stderr, "netdial, domain: %d proto: %d local: %s bind-dev: %s local-port: %d server: %s:%d timeout: %d, socket: %d\n", domain, proto, local, bind_dev, local_port, server, port, timeout, s); @@ -288,7 +281,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port } ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); - if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { + if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && !eWouldBlock()) { saved_errno = errno; closesocket(s); freeaddrinfo(server_res); @@ -418,8 +411,105 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, } +int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int timeout_ms) +{ + int sofar = 0; + uint64_t timeout_at = getCurMs() + timeout_ms; + fd_set read_fds; + struct timeval tv; + uint64_t now, sleep_for; + int select_ret; + + while (1) { + int r = Nread(fd, buf + sofar, count - sofar, prot, test); + if (r < 0) { + if (sofar == 0) + return r; + return sofar; + } + sofar += r; + if (sofar == count) + return sofar; + now = getCurMs(); + if (now >= timeout_at) + return sofar; + + /* not done, call select with timout so we don't busy-spin */ + sleep_for = timeout_at - now; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + tv.tv_sec = sleep_for / 1000; + tv.tv_usec = (sleep_for % 1000) * 1000; + + select_ret = select(fd + 1, &read_fds, NULL, NULL, &tv); + if (select_ret <= 0) + return sofar; + } +} + +int waitSocketReadable(int fd, int wait_for_ms) { + fd_set read_fds; + struct timeval tv; + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + tv.tv_sec = wait_for_ms / 1000; + tv.tv_usec = (wait_for_ms % 1000) * 1000; + + return select(fd + 1, &read_fds, NULL, NULL, &tv); +} + +int waitWrite(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int timeout_ms) +{ + int sofar = 0; + uint64_t timeout_at = getCurMs() + timeout_ms; + fd_set write_fds; + struct timeval tv; + uint64_t now, sleep_for; + int select_ret; + + while (1) { + int r = Nwrite(fd, buf + sofar, count - sofar, prot, test); + if (r < 0) { + if (sofar == 0) + return r; + return sofar; + } + sofar += r; + if (sofar == count) + return sofar; + now = getCurMs(); + if (now >= timeout_at) + return sofar; + + /* not done, call select with timout so we don't busy-spin */ + sleep_for = timeout_at - now; + + FD_ZERO(&write_fds); + FD_SET(fd, &write_fds); + + tv.tv_sec = sleep_for / 1000; + tv.tv_usec = (sleep_for % 1000) * 1000; + + select_ret = select(fd + 1, NULL, &write_fds, NULL, &tv); + if (select_ret <= 0) + return sofar; + } +} + +int eWouldBlock() { +#ifndef __WIN32__ + return (errno == EINPROGRESS || errno == EAGAIN); +#else + return WSAGetLastError() == WSAEWOULDBLOCK; +#endif +} + /*******************************************************************/ -/* reads 'count' bytes from a socket */ +/* reads up to 'count' bytes from a socket */ /********************************************************************/ int @@ -437,12 +527,7 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) r = recv(fd, buf, nleft, 0); #endif if (r < 0) { -#ifndef __WIN32__ - if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) -#else - if (WSAGetLastError() == WSAEWOULDBLOCK) -#endif - { + if (eWouldBlock() || errno == EINTR) { break; } else { diff --git a/src/net.h b/src/net.h index e968c67e0..8059da76a 100644 --- a/src/net.h +++ b/src/net.h @@ -29,6 +29,10 @@ #include "iperf.h" +extern int ctrl_wait_ms; + +int eWouldBlock(); + void nonblock(int s); void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set); @@ -37,7 +41,10 @@ int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int t int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, struct iperf_test *test); int netannounce(int domain, int proto, char *local, const char* bind_dev, int port, struct iperf_test *test); +int waitSocketReadable(int fd, int wait_for_ms); +int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int timeout_ms); int Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test); +int waitWrite(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int timeout_ms); int Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) /* __attribute__((hot)) */; int has_sendfile(void); int Nsendfile(int fromfd, int tofd, const char *buf, size_t count) /* __attribute__((hot)) */; From 5a339eab1735ec8f1e896918dca2d7f9ad36a892 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 15:05:53 -0700 Subject: [PATCH 27/45] debugging: Add timestamps to some logging, log state changes. --- src/iperf_api.c | 19 ++++++++++--- src/iperf_api.h | 2 ++ src/iperf_client_api.c | 10 ++++--- src/iperf_error.c | 6 +++-- src/iperf_server_api.c | 61 +++++++++++++++++++++++++----------------- src/iperf_tcp.c | 4 +-- src/iperf_udp.c | 4 +-- src/main.c | 3 +++ src/net.c | 19 ++++++------- 9 files changed, 81 insertions(+), 47 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 9cf6808cf..b98b28583 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1411,10 +1411,20 @@ int iperf_open_logfile(struct iperf_test *test) return 0; } +void iperf_set_state(struct iperf_test *test, signed char state, const char* dbg) +{ + if (test->debug) { + fprintf(stderr, "test: %p state: %d(%s) ==> %d(%s) dbg: %s\n", + test, test->state, iperf_get_state_str(test->state), + state, iperf_get_state_str(state), dbg); + } + test->state = state; +} + int iperf_set_send_state(struct iperf_test *test, signed char state) { - test->state = state; + iperf_set_state(test, state, __FUNCTION__); if (waitWrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp, test, ctrl_wait_ms) != sizeof(state)) { i_errno = IESENDMESSAGE; return -1; @@ -1696,6 +1706,7 @@ void _fd_clr(int fd, fd_set* fdset, struct iperf_test *test, const char* file, i const char* iperf_get_state_str(int s) { switch (s) { + case TEST_INIT: return "INIT"; case TEST_START: return "START"; case TEST_RUNNING: return "RUNNING"; case TEST_END: return "END"; @@ -2642,7 +2653,7 @@ iperf_reset_test(struct iperf_test *test) #if defined(HAVE_CPUSET_SETAFFINITY) CPU_ZERO(&test->cpumask); #endif /* HAVE_CPUSET_SETAFFINITY */ - test->state = 0; + iperf_set_state(test, TEST_INIT, __FUNCTION__); test->ctrl_sck = -1; test->prot_listener = -1; @@ -3992,14 +4003,14 @@ iperf_got_sigend(struct iperf_test *test) test->done = 1; cpu_util(test->cpu_util); test->stats_callback(test); - test->state = DISPLAY_RESULTS; /* change local state only */ + iperf_set_state(test, DISPLAY_RESULTS, __FUNCTION__); /* change local state only */ if (test->on_test_finish) test->on_test_finish(test); test->reporter_callback(test); } if (test->ctrl_sck >= 0) { - test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE; + iperf_set_state(test, (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE, "got-sig-end"); waitWrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms); } i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM; diff --git a/src/iperf_api.h b/src/iperf_api.h index 670799bf7..bb5d56760 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -79,6 +79,7 @@ struct iperf_time; #define OPT_BIND_DEV 21 /* states */ +#define TEST_INIT 0 #define TEST_START 1 #define TEST_RUNNING 2 //#define RESULT_REQUEST 3 /* not used */ @@ -267,6 +268,7 @@ long get_pmtu(struct iperf_interval_results *irp); void print_tcpinfo(struct iperf_test *test); void build_tcpinfo_message(struct iperf_interval_results *r, char *message); +void iperf_set_state(struct iperf_test *test, signed char state, const char* dbg); int iperf_set_send_state(struct iperf_test *test, signed char state); void iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP); int iperf_send(struct iperf_test *, fd_set *) /* __attribute__((hot)) */; diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 818dad26c..a99aeceff 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -240,8 +240,9 @@ iperf_handle_message_client(struct iperf_test *test) { int rval; int32_t err; + signed char s; - if ((rval = waitRead(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms)) != sizeof(signed char)) { + if ((rval = waitRead(test->ctrl_sck, (char*) &s, sizeof(s), Ptcp, test, ctrl_wait_ms)) != sizeof(s)) { if (rval == 0) { i_errno = IECTRLCLOSE; return -1; @@ -250,6 +251,9 @@ iperf_handle_message_client(struct iperf_test *test) return -1; } } + else { + iperf_set_state(test, s, __FUNCTION__); + } switch (test->state) { case PARAM_EXCHANGE: @@ -302,9 +306,9 @@ iperf_handle_message_client(struct iperf_test *test) */ signed char oldstate = test->state; cpu_util(test->cpu_util); - test->state = DISPLAY_RESULTS; + iperf_set_state(test, DISPLAY_RESULTS, __FUNCTION__); test->reporter_callback(test); - test->state = oldstate; + iperf_set_state(test, oldstate, __FUNCTION__); return -1; case ACCESS_DENIED: i_errno = IEACCESSDENIED; diff --git a/src/iperf_error.c b/src/iperf_error.c index 5659dd5c7..7a24dbb53 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -47,10 +47,12 @@ iperf_err(struct iperf_test *test, const char *format, ...) cJSON_AddStringToObject(test->json_top, "error", str); else if (test && test->outfile && test->outfile != stdout) { - fprintf(test->outfile, "iperf3: %s\n", str); + fprintf(test->outfile, "%llu %s iperf3: %s\n", + getCurMs(), iperf_get_state_str(test->state), str); } else { - fprintf(stderr, "iperf3: %s\n", str); + fprintf(stderr, "%llu %s iperf3: %s\n", + getCurMs(), iperf_get_state_str(test->state), str); } va_end(argp); } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index b744f73d8..fc179fa5f 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -117,7 +117,7 @@ iperf_accept(struct iperf_test *test) struct sockaddr_storage addr; if (test->debug) { - fprintf(stderr, "iperf-accept called.\n"); + iperf_err(test, "iperf-accept called.\n"); } len = sizeof(addr); @@ -132,8 +132,8 @@ iperf_accept(struct iperf_test *test) int rv = waitRead(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms); if (rv != COOKIE_SIZE) { - fprintf(stderr, "Accept problem, ctrl-sck: %d s: %d listener: %d waitRead rv: %d\n", - test->ctrl_sck, s, test->listener, rv); + iperf_err(test, "Accept problem, ctrl-sck: %d s: %d listener: %d waitRead rv: %d\n", + test->ctrl_sck, s, test->listener, rv); i_errno = IERECVCOOKIE; goto out_err; } @@ -178,19 +178,23 @@ iperf_handle_message_server(struct iperf_test *test) { int rval; struct iperf_stream *sp; + signed char s; // XXX: Need to rethink how this behaves to fit API - if ((rval = waitRead(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp, test, ctrl_wait_ms)) != sizeof(signed char)) { + if ((rval = waitRead(test->ctrl_sck, (char*) &s, sizeof(s), Ptcp, test, ctrl_wait_ms)) != sizeof(s)) { + iperf_err(test, "The client has unexpectedly closed the connection (handle-message-server): %s", + STRERROR); if (rval == 0) { - iperf_err(test, "the client has unexpectedly closed the connection"); i_errno = IECTRLCLOSE; - test->state = IPERF_DONE; - return 0; + return -1; } else { i_errno = IERECVMESSAGE; return -1; } } + else { + iperf_set_state(test, s, __FUNCTION__); + } switch(test->state) { case TEST_START: @@ -224,9 +228,9 @@ iperf_handle_message_server(struct iperf_test *test) // ending summary statistics. signed char oldstate = test->state; cpu_util(test->cpu_util); - test->state = DISPLAY_RESULTS; + iperf_set_state(test, DISPLAY_RESULTS, __FUNCTION__); test->reporter_callback(test); - test->state = oldstate; + iperf_set_state(test, oldstate, __FUNCTION__); // XXX: Remove this line below! iperf_err(test, "the client has terminated"); @@ -236,7 +240,7 @@ iperf_handle_message_server(struct iperf_test *test) closesocket(sp->socket); sp->socket = -1; } - test->state = IPERF_DONE; + iperf_set_state(test, IPERF_DONE, __FUNCTION__); break; default: i_errno = IEMESSAGE; @@ -409,7 +413,7 @@ cleanup_server(struct iperf_test *test) tmr_cancel(test->timer); test->timer = NULL; } - test->state = IPERF_DONE; + iperf_set_state(test, IPERF_DONE, __FUNCTION__); } @@ -422,7 +426,7 @@ iperf_run_server(struct iperf_test *test) #if defined(HAVE_TCP_CONGESTION) int saved_errno; #endif /* HAVE_TCP_CONGESTION */ - fd_set read_set, write_set; + fd_set read_set, write_set, exc_set; struct iperf_stream *sp; struct iperf_time now; struct timeval* timeout; @@ -459,7 +463,7 @@ iperf_run_server(struct iperf_test *test) // Begin calculating CPU utilization cpu_util(NULL); - test->state = IPERF_START; + iperf_set_state(test, IPERF_START, __FUNCTION__); send_streams_accepted = 0; rec_streams_accepted = 0; @@ -467,34 +471,35 @@ iperf_run_server(struct iperf_test *test) memcpy(&read_set, &test->read_set, sizeof(fd_set)); memcpy(&write_set, &test->write_set, sizeof(fd_set)); + //memcpy(&exc_set, &test->exc_set, sizeof(fd_set)); iperf_time_now(&now); timeout = tmr_timeout(&now); if (test->debug > 1 || (test->debug && (last_dbg != now.secs))) { if (timeout) - fprintf(stderr, "timeout: %ld.%06ld max-fd: %d state: %d (%s)\n", - (long)(timeout->tv_sec), (long)(timeout->tv_usec), test->max_fd, - test->state, iperf_get_state_str(test->state)); + iperf_err(test, "timeout: %ld.%06ld max-fd: %d state: %d (%s)", + (long)(timeout->tv_sec), (long)(timeout->tv_usec), test->max_fd, + test->state, iperf_get_state_str(test->state)); else - fprintf(stderr, "timeout NULL, max-fd: %d state: %d(%s)\n", test->max_fd, - test->state, iperf_get_state_str(test->state)); + iperf_err(test, "timeout NULL, max-fd: %d state: %d(%s)", test->max_fd, + test->state, iperf_get_state_str(test->state)); print_fdset(test->max_fd, &read_set, &write_set); } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); if (test->debug > 1 || (test->debug && (last_dbg != now.secs))) { - fprintf(stderr, "select result: %d, listener: %d ISSET-listener: %d test-state: %d(%s)\n", - result, test->listener, FD_ISSET(test->listener, &read_set), test->state, - iperf_get_state_str(test->state)); - fprintf(stderr, "prot-listener: %d ISSET: %d max-fd: %d\n", - test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); + iperf_err(test, "select result: %d, listener: %d ISSET-listener: %d test-state: %d(%s)", + result, test->listener, FD_ISSET(test->listener, &read_set), test->state, + iperf_get_state_str(test->state)); + iperf_err(test, "prot-listener: %d ISSET: %d max-fd: %d\n", + test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); print_fdset(test->max_fd, &read_set, &write_set); last_dbg = now.secs; } if (result < 0 && errno != EINTR) { - fprintf(stderr, "Cleaning server, select had error: %s\n", STRERROR); + iperf_err(test, "Cleaning server, select had error: %s", STRERROR); cleanup_server(test); i_errno = IESELECT; return -1; @@ -544,7 +549,7 @@ iperf_run_server(struct iperf_test *test) setnonblocking(s, 1); if (test->debug) { - fprintf(stderr, "create-streams, accepted socket: %d\n", s); + iperf_err(test, "create-streams, accepted socket: %d\n", s); } #if defined(HAVE_TCP_CONGESTION) @@ -707,11 +712,17 @@ iperf_run_server(struct iperf_test *test) if (result == 0 || (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { /* Run the timers. */ + if (test->debug) + iperf_err(test, "Running timers..\n"); iperf_time_now(&now); tmr_run(&now); + if (test->debug) + iperf_err(test, "Done with timers..\n"); } } + if (test->debug) + iperf_err(test, "Done with server loop, cleaning up server.\n"); cleanup_server(test); if (test->json_output) { diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 872ec838c..8198c0fef 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -99,8 +99,8 @@ iperf_tcp_send(struct iperf_stream *sp) sp->result->bytes_sent += r; sp->result->bytes_sent_this_interval += r; - if (sp->test->debug) - printf("sent %d bytes of %d, total %llu\n", r, sp->settings->blksize, (long long unsigned)sp->result->bytes_sent); + if (sp->test->debug > 1) + printf("tcp: sent %d bytes of %d, total %llu\n", r, sp->settings->blksize, (long long unsigned)sp->result->bytes_sent); return r; } diff --git a/src/iperf_udp.c b/src/iperf_udp.c index f9e8c8746..dc7386538 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -240,8 +240,8 @@ iperf_udp_send(struct iperf_stream *sp) sp->result->bytes_sent += r; sp->result->bytes_sent_this_interval += r; - if (sp->test->debug) - printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); + if (sp->test->debug > 1) + printf("udp: sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); return r; } diff --git a/src/main.c b/src/main.c index 277fb0532..cb61ad848 100644 --- a/src/main.c +++ b/src/main.c @@ -174,6 +174,9 @@ run(struct iperf_test *test) iperf_errexit(test, "exiting"); } } + else { + iperf_err(test, "Finished with iperf_run_srver.."); + } iperf_reset_test(test); if (iperf_get_test_one_off(test)) { /* Authentication failure doesn't count for 1-off test */ diff --git a/src/net.c b/src/net.c index e7d1cc8cd..8b4f19d9c 100644 --- a/src/net.c +++ b/src/net.c @@ -66,6 +66,7 @@ #include "iperf_util.h" #include "net.h" #include "timer.h" +#include "iperf_api.h" /* * Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this @@ -101,7 +102,7 @@ void nonblock(int s) { void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set) { int i; - fprintf(stderr, "read/write FD sets: "); + fprintf(stderr, "%llu read/write FD sets: ", getCurMs()); for (i = 0; i<=max_fd; i++) { if (FD_ISSET(i, read_set)) { if (FD_ISSET(i, write_set)) { @@ -207,8 +208,8 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port setnonblocking(s, 1); if (test->debug) { - fprintf(stderr, "netdial, domain: %d proto: %d local: %s bind-dev: %s local-port: %d server: %s:%d timeout: %d, socket: %d\n", - domain, proto, local, bind_dev, local_port, server, port, timeout, s); + iperf_err(test, "netdial, domain: %d proto: %d local: %s bind-dev: %s local-port: %d server: %s:%d timeout: %d, socket: %d\n", + domain, proto, local, bind_dev, local_port, server, port, timeout, s); } if (bind_dev) { @@ -331,8 +332,8 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, s = socket(res->ai_family, proto, 0); if (test->debug) { - fprintf(stderr, "netannounce, domain: %d proto: %d local: %s bind-dev: %s port: %d fd: %d\n", - domain, proto, local, bind_dev, port, s); + iperf_err(test, "netannounce, domain: %d proto: %d local: %s bind-dev: %s port: %d fd: %d\n", + domain, proto, local, bind_dev, port, s); } if (s < 0) { @@ -531,8 +532,8 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) break; } else { - fprintf(stderr, "Error in Nread (%s) fd: %d\n", - STRERROR, fd); + iperf_err(test, "Error in Nread (%s) fd: %d\n", + STRERROR, fd); return NET_HARDERROR; } } else if (r == 0) @@ -542,7 +543,7 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) buf += r; } if (test && test->debug > 1) { - fprintf(stderr, "Nread:\n%s", hexdump((const unsigned char*)oldbuf, count - nleft, 1, 1)); + iperf_err(test, "Nread:\n%s", hexdump((const unsigned char*)oldbuf, count - nleft, 1, 1)); } return count - nleft; } @@ -559,7 +560,7 @@ Nwrite(int fd, const char *buf, size_t count, int prot, struct iperf_test *test) register size_t nleft = count; if (test && test->debug > 1) { - fprintf(stderr, "Nwrite:\n%s", hexdump((const unsigned char*)buf, count, 1, 1)); + iperf_err(test, "Nwrite:\n%s", hexdump((const unsigned char*)buf, count, 1, 1)); } while (nleft > 0) { From 46f335f0ff241854a26dd6400a52dba9edb6596e Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 15:59:02 -0700 Subject: [PATCH 28/45] Use helper method to close sockets. This will clean up the read/write fd sets and also set any stored fds in 'test' to -1. Should help make sure we don't accidentally use closed file descriptors and simplifies some of the code. --- src/iperf.h | 1 - src/iperf_api.c | 5 ++-- src/iperf_client_api.c | 16 ++++------ src/iperf_server_api.c | 66 +++++++++++++++--------------------------- src/iperf_tcp.c | 58 ++++++++++++++++++------------------- src/iperf_udp.c | 14 ++++----- src/net.c | 38 ++++++++++++++++++------ src/net.h | 1 + 8 files changed, 97 insertions(+), 102 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index a2e0d79df..1db85785a 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -43,7 +43,6 @@ #define STRERROR strerror(errno) #define ERRNO errno -#define closesocket close #else #include diff --git a/src/iperf_api.c b/src/iperf_api.c index b98b28583..65f615ff8 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1501,8 +1501,9 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) } if (write_setP != NULL) SLIST_FOREACH(sp, &test->streams, streams) - if (FD_ISSET(sp->socket, write_setP)) - IFD_CLR(sp->socket, write_setP, test); + if (sp->socket >= 0) + if (FD_ISSET(sp->socket, write_setP)) + IFD_CLR(sp->socket, write_setP, test); return 0; } diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index a99aeceff..515d4d223 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -81,7 +81,7 @@ iperf_create_streams(struct iperf_test *test, int sender) if (test->congestion) { if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -92,7 +92,7 @@ iperf_create_streams(struct iperf_test *test, int sender) char ca[TCP_CA_NAME_MAX + 1]; if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -107,12 +107,11 @@ iperf_create_streams(struct iperf_test *test, int sender) if (sender) IFD_SET(s, &test->write_set, test); - else - IFD_SET(s, &test->read_set, test); + IFD_SET(s, &test->read_set, test); sp = iperf_new_stream(test, s, sender); if (!sp) { - closesocket(s); + iclosesocket(s, test); return -1; } @@ -445,7 +444,7 @@ iperf_client_end(struct iperf_test *test) /* Close all stream sockets */ SLIST_FOREACH(sp, &test->streams, streams) { - closesocket(sp->socket); + iclosesocket(sp->socket, test); sp->socket = -1; } @@ -456,10 +455,7 @@ iperf_client_end(struct iperf_test *test) return -1; /* Close control socket */ - if (test->ctrl_sck != -1) { - closesocket(test->ctrl_sck); - test->ctrl_sck = -1; - } + iclosesocket(test->ctrl_sck, test); return 0; } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index fc179fa5f..b48842b31 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -130,6 +130,8 @@ iperf_accept(struct iperf_test *test) /* Server free, accept new client */ test->ctrl_sck = s; + setnonblocking(s, 1); + int rv = waitRead(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms); if (rv != COOKIE_SIZE) { iperf_err(test, "Accept problem, ctrl-sck: %d s: %d listener: %d waitRead rv: %d\n", @@ -150,24 +152,16 @@ iperf_accept(struct iperf_test *test) test->on_connect(test); } else { /* - * Don't try to read from the socket. It could block an ongoing test. - * Just send ACCESS_DENIED. + * Just send ACCESS_DENIED, ignore any error, don't care if we cannot send the bytes immediately. */ - if (waitWrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test, ctrl_wait_ms) != sizeof(rbuf)) { - i_errno = IESENDMESSAGE; - goto out_err; - } - closesocket(s); + Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp, test); + iclosesocket(s, test); } return 0; out_err: - if (s >= 0) { - closesocket(s); - if (test->ctrl_sck == s) - test->ctrl_sck = -1; - } + iclosesocket(s, test); return -1; } @@ -181,9 +175,11 @@ iperf_handle_message_server(struct iperf_test *test) signed char s; // XXX: Need to rethink how this behaves to fit API + if (test->debug) + iperf_err(test, "Calling waitRead in handle-message-server, fd: %d", test->ctrl_sck); if ((rval = waitRead(test->ctrl_sck, (char*) &s, sizeof(s), Ptcp, test, ctrl_wait_ms)) != sizeof(s)) { - iperf_err(test, "The client has unexpectedly closed the connection (handle-message-server): %s", - STRERROR); + iperf_err(test, "The client has unexpectedly closed the connection (handle-message-server): %s rval: %d", + STRERROR, rval); if (rval == 0) { i_errno = IECTRLCLOSE; return -1; @@ -204,9 +200,7 @@ iperf_handle_message_server(struct iperf_test *test) cpu_util(test->cpu_util); test->stats_callback(test); SLIST_FOREACH(sp, &test->streams, streams) { - IFD_CLR(sp->socket, &test->read_set, test); - IFD_CLR(sp->socket, &test->write_set, test); - closesocket(sp->socket); + iclosesocket(sp->socket, test); sp->socket = -1; } test->reporter_callback(test); @@ -235,9 +229,7 @@ iperf_handle_message_server(struct iperf_test *test) // XXX: Remove this line below! iperf_err(test, "the client has terminated"); SLIST_FOREACH(sp, &test->streams, streams) { - IFD_CLR(sp->socket, &test->read_set, test); - IFD_CLR(sp->socket, &test->write_set, test); - closesocket(sp->socket); + iclosesocket(sp->socket, test); sp->socket = -1; } iperf_set_state(test, IPERF_DONE, __FUNCTION__); @@ -264,11 +256,10 @@ server_timer_proc(TimerClientData client_data, struct iperf_time *nowP) while (!SLIST_EMPTY(&test->streams)) { sp = SLIST_FIRST(&test->streams); SLIST_REMOVE_HEAD(&test->streams, streams); - closesocket(sp->socket); + iclosesocket(sp->socket, test); iperf_free_stream(sp); } - closesocket(test->ctrl_sck); - test->ctrl_sck = -1; + iclosesocket(test->ctrl_sck, test); } static void @@ -383,14 +374,8 @@ static void cleanup_server(struct iperf_test *test) { /* Close open test sockets */ - if (test->ctrl_sck != -1) { - closesocket(test->ctrl_sck); - test->ctrl_sck = -1; - } - if (test->listener != -1) { - closesocket(test->listener); - test->listener = -1; - } + iclosesocket(test->ctrl_sck, test); + iclosesocket(test->listener, test); /* Cancel any remaining timers. */ if (test->stats_timer != NULL) { @@ -426,7 +411,7 @@ iperf_run_server(struct iperf_test *test) #if defined(HAVE_TCP_CONGESTION) int saved_errno; #endif /* HAVE_TCP_CONGESTION */ - fd_set read_set, write_set, exc_set; + fd_set read_set, write_set; struct iperf_stream *sp; struct iperf_time now; struct timeval* timeout; @@ -471,7 +456,6 @@ iperf_run_server(struct iperf_test *test) memcpy(&read_set, &test->read_set, sizeof(fd_set)); memcpy(&write_set, &test->write_set, sizeof(fd_set)); - //memcpy(&exc_set, &test->exc_set, sizeof(fd_set)); iperf_time_now(&now); timeout = tmr_timeout(&now); @@ -570,7 +554,7 @@ iperf_run_server(struct iperf_test *test) } else { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; @@ -583,7 +567,7 @@ iperf_run_server(struct iperf_test *test) char ca[TCP_CA_NAME_MAX + 1]; if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; @@ -618,8 +602,8 @@ iperf_run_server(struct iperf_test *test) // TODO: For read+write, do we need to set this fd in both sets? if (sp->sender) IFD_SET(s, &test->write_set, test); - else - IFD_SET(s, &test->read_set, test); + // Always set read, that way we can detect broken sockets. + IFD_SET(s, &test->read_set, test); if (test->on_new_stream) test->on_new_stream(sp); @@ -632,15 +616,11 @@ iperf_run_server(struct iperf_test *test) if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { if (test->protocol->id != Ptcp) { // Stop listening for more protocol connections, we are full. - IFD_CLR(test->prot_listener, &test->read_set, test); - closesocket(test->prot_listener); - test->prot_listener = -1; + iclosesocket(test->prot_listener, test); } else { if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { // Re-open protocol listener socket, I am not sure why. --Ben - IFD_CLR(test->listener, &test->read_set, test); - closesocket(test->listener); - test->listener = -1; + iclosesocket(test->listener, test); if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port, test)) < 0) { cleanup_server(test); diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 8198c0fef..a4b5247b3 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -140,7 +140,7 @@ iperf_tcp_accept(struct iperf_test * test) i_errno = IESENDMESSAGE; return -1; } - closesocket(s); + iclosesocket(s, test); return -1; } @@ -176,9 +176,7 @@ iperf_tcp_listen(struct iperf_test *test) struct addrinfo hints, *res; char portstr[6]; - IFD_CLR(s, &test->read_set, test); - closesocket(s); - test->listener = -1; + iclosesocket(s, test); snprintf(portstr, 6, "%d", test->server_port); memset(&hints, 0, sizeof(hints)); @@ -216,7 +214,7 @@ iperf_tcp_listen(struct iperf_test *test) #endif { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); i_errno = IEBINDDEV; errno = saved_errno; @@ -228,7 +226,7 @@ iperf_tcp_listen(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IESETNODELAY; @@ -240,7 +238,7 @@ iperf_tcp_listen(struct iperf_test *test) if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IESETMSS; @@ -251,7 +249,7 @@ iperf_tcp_listen(struct iperf_test *test) if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IESETBUF; @@ -259,7 +257,7 @@ iperf_tcp_listen(struct iperf_test *test) } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IESETBUF; @@ -295,7 +293,7 @@ iperf_tcp_listen(struct iperf_test *test) opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IEREUSEADDR; @@ -316,7 +314,7 @@ iperf_tcp_listen(struct iperf_test *test) if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IEV6ONLY; @@ -327,7 +325,7 @@ iperf_tcp_listen(struct iperf_test *test) if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; i_errno = IESTREAMLISTEN; @@ -339,7 +337,7 @@ iperf_tcp_listen(struct iperf_test *test) if (listen(s, INT_MAX) < 0) { i_errno = IESTREAMLISTEN; saved_errno = errno; - closesocket(s); + iclosesocket(s, test); errno = saved_errno; return -1; } @@ -351,7 +349,7 @@ iperf_tcp_listen(struct iperf_test *test) optlen = sizeof(sndbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); test->listener = -1; errno = saved_errno; i_errno = IESETBUF; @@ -370,7 +368,7 @@ iperf_tcp_listen(struct iperf_test *test) optlen = sizeof(rcvbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); test->listener = -1; errno = saved_errno; i_errno = IESETBUF; @@ -452,7 +450,7 @@ iperf_tcp_connect(struct iperf_test *test) #endif { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(local_res); freeaddrinfo(server_res); i_errno = IEBINDDEV; @@ -473,7 +471,7 @@ iperf_tcp_connect(struct iperf_test *test) if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { fprintf(stderr, "tcp-connect, bind() failed: %s\n", STRERROR); saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(local_res); freeaddrinfo(server_res); errno = saved_errno; @@ -506,7 +504,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Unknown protocol */ else { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IEPROTOCOL; @@ -516,7 +514,7 @@ iperf_tcp_connect(struct iperf_test *test) if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { fprintf(stderr, "tcp-connect, bind2() failed: %s\n", STRERROR); saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESTREAMCONNECT; @@ -529,7 +527,7 @@ iperf_tcp_connect(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETNODELAY; @@ -540,7 +538,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETMSS; @@ -551,7 +549,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -559,7 +557,7 @@ iperf_tcp_connect(struct iperf_test *test) } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -571,7 +569,7 @@ iperf_tcp_connect(struct iperf_test *test) optlen = sizeof(sndbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&sndbuf_actual, &optlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -589,7 +587,7 @@ iperf_tcp_connect(struct iperf_test *test) optlen = sizeof(rcvbuf_actual); if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcvbuf_actual, &optlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETBUF; @@ -613,7 +611,7 @@ iperf_tcp_connect(struct iperf_test *test) if (test->settings->flowlabel) { if (server_res->ai_addr->sa_family != AF_INET6) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -633,7 +631,7 @@ iperf_tcp_connect(struct iperf_test *test) if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -644,7 +642,7 @@ iperf_tcp_connect(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESETFLOW; @@ -681,7 +679,7 @@ iperf_tcp_connect(struct iperf_test *test) if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && !eWouldBlock()) { fprintf(stderr, "tcp-connect, connect() failed: %s\n", STRERROR); saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; i_errno = IESTREAMCONNECT; @@ -693,7 +691,7 @@ iperf_tcp_connect(struct iperf_test *test) /* Send cookie for verification */ if (waitWrite(s, test->cookie, COOKIE_SIZE, Ptcp, test, ctrl_wait_ms) != COOKIE_SIZE) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); errno = saved_errno; i_errno = IESENDCOOKIE; return -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index dc7386538..cc52cc1ef 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -463,7 +463,7 @@ iperf_udp_accept(struct iperf_test *test) if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; - closesocket(s); + iclosesocket(s, test); return -1; } @@ -478,7 +478,7 @@ iperf_udp_accept(struct iperf_test *test) #endif { i_errno = IESTREAMWRITE; - closesocket(s); + iclosesocket(s, test); return -1; } @@ -547,7 +547,7 @@ iperf_udp_connect(struct iperf_test *test) rc = iperf_udp_buffercheck(test, s); if (rc < 0) { /* error */ - closesocket(s); + iclosesocket(s, test); return rc; } @@ -563,7 +563,7 @@ iperf_udp_connect(struct iperf_test *test) test->settings->socket_bufsize = bufsize; rc = iperf_udp_buffercheck(test, s); if (rc < 0) { - closesocket(s); + iclosesocket(s, test); return rc; } } @@ -626,7 +626,7 @@ iperf_udp_connect(struct iperf_test *test) { // XXX: Should this be changed to IESTREAMCONNECT? i_errno = IESTREAMWRITE; - closesocket(s); + iclosesocket(s, test); return -1; } @@ -646,7 +646,7 @@ iperf_udp_connect(struct iperf_test *test) if (select_ret == 1) { if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); - closesocket(s); + iclosesocket(s, test); i_errno = IESTREAMREAD; return -1; } @@ -667,7 +667,7 @@ iperf_udp_connect(struct iperf_test *test) if (test->debug) { fprintf(stderr, "Did not receive UDP connect response in time.\n"); } - closesocket(s); + iclosesocket(s, test); i_errno = IESTREAMREAD; return -1; } diff --git a/src/net.c b/src/net.c index 8b4f19d9c..48cffff5f 100644 --- a/src/net.c +++ b/src/net.c @@ -219,7 +219,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port #endif { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(local_res); freeaddrinfo(server_res); errno = saved_errno; @@ -237,7 +237,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(local_res); freeaddrinfo(server_res); errno = saved_errno; @@ -274,7 +274,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; return -1; @@ -284,7 +284,7 @@ netdial(int domain, int proto, char *local, const char* bind_dev, int local_port ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && !eWouldBlock()) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(server_res); errno = saved_errno; return -1; @@ -348,7 +348,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, #endif { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; return -1; @@ -359,7 +359,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; return -1; @@ -381,7 +381,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt)) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; return -1; @@ -391,7 +391,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); freeaddrinfo(res); errno = saved_errno; return -1; @@ -402,7 +402,7 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, if (proto == SOCK_STREAM) { if (listen(s, INT_MAX) < 0) { saved_errno = errno; - closesocket(s); + iclosesocket(s, test); errno = saved_errno; return -1; } @@ -411,6 +411,26 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, return s; } +void iclosesocket(int s, struct iperf_test *test) { + if (s < 0) + return; +#ifdef __WIN32__ + closesocket(s); +#else + close(s); +#endif + if (test) { + if (s == test->ctrl_sck) + test->ctrl_sck = -1; + if (s == test->listener) + test->listener = -1; + if (s == test->prot_listener) + test->prot_listener = -1; + IFD_CLR(s, &test->read_set, test); + IFD_CLR(s, &test->write_set, test); + } +} + int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int timeout_ms) { diff --git a/src/net.h b/src/net.h index 8059da76a..16ca4f870 100644 --- a/src/net.h +++ b/src/net.h @@ -33,6 +33,7 @@ extern int ctrl_wait_ms; int eWouldBlock(); +void iclosesocket(int s, struct iperf_test *test); void nonblock(int s); void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set); From 2e39014426ccb12a6332b817e2b8fbd922495f52 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 24 Oct 2019 16:32:47 -0700 Subject: [PATCH 29/45] Fix hang in waitRead Was not properly dealing with end-of-stream return value in Nread. --- src/iperf_server_api.c | 6 +++--- src/iperf_udp.c | 4 ++-- src/net.c | 24 +++++++++++++++++++++--- src/net.h | 1 + 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index b48842b31..e77239432 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -175,12 +175,12 @@ iperf_handle_message_server(struct iperf_test *test) signed char s; // XXX: Need to rethink how this behaves to fit API - if (test->debug) - iperf_err(test, "Calling waitRead in handle-message-server, fd: %d", test->ctrl_sck); + //if (test->debug) + // iperf_err(test, "Calling waitRead in handle-message-server, fd: %d", test->ctrl_sck); if ((rval = waitRead(test->ctrl_sck, (char*) &s, sizeof(s), Ptcp, test, ctrl_wait_ms)) != sizeof(s)) { iperf_err(test, "The client has unexpectedly closed the connection (handle-message-server): %s rval: %d", STRERROR, rval); - if (rval == 0) { + if ((rval == 0) || (rval == NET_HANGUP)) { i_errno = IECTRLCLOSE; return -1; } else { diff --git a/src/iperf_udp.c b/src/iperf_udp.c index cc52cc1ef..c49e81058 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -107,8 +107,8 @@ iperf_udp_recv(struct iperf_stream *sp) sent_time.usecs = usec; } - if (sp->test->debug) - fprintf(stderr, "pcount %" PRIu64 " packet_count %d\n", pcount, sp->packet_count); + if (sp->test->debug > 1) + iperf_err(sp->test, "udp pcount %" PRIu64 " packet_count %d\n", pcount, sp->packet_count); /* * Try to handle out of order packets. The way we do this diff --git a/src/net.c b/src/net.c index 48cffff5f..7b60cedf6 100644 --- a/src/net.c +++ b/src/net.c @@ -442,7 +442,14 @@ int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int select_ret; while (1) { - int r = Nread(fd, buf + sofar, count - sofar, prot, test); + int r; + + if (test->debug > 1) + iperf_err(test, "waitRead, calling Nread, fd: %d count: %d sofar: %d", fd, count, sofar); + r = Nread(fd, buf + sofar, count - sofar, prot, test); + if (test->debug > 1) + iperf_err(test, "waitRead, Nread, fd: %d count: %d sofar: %d rv: %d", + fd, count, sofar, r); if (r < 0) { if (sofar == 0) return r; @@ -465,6 +472,9 @@ int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, tv.tv_usec = (sleep_for % 1000) * 1000; select_ret = select(fd + 1, &read_fds, NULL, NULL, &tv); + if (test->debug > 1) + iperf_err(test, "waitRead, done with select, fd: %d count: %d sofar: %d select-ret: %d", + fd, count, sofar, select_ret); if (select_ret <= 0) return sofar; } @@ -556,8 +566,16 @@ Nread(int fd, char *buf, size_t count, int prot, struct iperf_test *test) STRERROR, fd); return NET_HARDERROR; } - } else if (r == 0) - break; + } else if (r == 0) { + // End of socket has happened + if (buf != oldbuf) { + // We read something first, though, report it as successful read + break; + } + else { + return NET_HANGUP; + } + } nleft -= r; buf += r; diff --git a/src/net.h b/src/net.h index 16ca4f870..cb743fb89 100644 --- a/src/net.h +++ b/src/net.h @@ -55,5 +55,6 @@ int parse_qos(const char *tos); #define NET_SOFTERROR -1 #define NET_HARDERROR -2 +#define NET_HANGUP -3 /* socket has been closed */ #endif /* __NET_H */ From 837c682594d561a8181007a6c7ee30c32fb2a9c7 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 07:44:53 -0700 Subject: [PATCH 30/45] Stop test if it has been in create-streams state for more than 5 seconds. A buggy or killed client could cause this to happen. --- src/iperf.h | 1 + src/iperf_api.c | 4 +++- src/iperf_error.c | 10 ++++++---- src/iperf_server_api.c | 10 ++++++++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 1db85785a..9325196cd 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -381,6 +381,7 @@ struct iperf_test int done; Timer *stats_timer; Timer *reporter_timer; + uint64_t create_streams_state_at; /* when did we enter the create-streams state? */ double cpu_util[3]; /* cpu utilization of the test - total, user, system */ double remote_cpu_util[3]; /* cpu utilization for the remote host/client - total, user, system */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 65f615ff8..f1f011374 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1672,13 +1672,14 @@ iperf_exchange_parameters(struct iperf_test *test) } if (test->debug) { - fprintf(stderr, "iperf-exchange-parameters, setting read FD: %d.\n", s); + iperf_err(test, "iperf-exchange-parameters, setting read FD: %d.\n", s); } IFD_SET(s, &test->read_set, test); test->prot_listener = s; // Send the control message to create streams and start the test + test->create_streams_state_at = getCurMs(); if (iperf_set_send_state(test, CREATE_STREAMS) != 0) return -1; @@ -2655,6 +2656,7 @@ iperf_reset_test(struct iperf_test *test) CPU_ZERO(&test->cpumask); #endif /* HAVE_CPUSET_SETAFFINITY */ iperf_set_state(test, TEST_INIT, __FUNCTION__); + test->create_streams_state_at = 0; test->ctrl_sck = -1; test->prot_listener = -1; diff --git a/src/iperf_error.c b/src/iperf_error.c index 7a24dbb53..cb033765d 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -47,12 +47,14 @@ iperf_err(struct iperf_test *test, const char *format, ...) cJSON_AddStringToObject(test->json_top, "error", str); else if (test && test->outfile && test->outfile != stdout) { - fprintf(test->outfile, "%llu %s iperf3: %s\n", - getCurMs(), iperf_get_state_str(test->state), str); + fprintf(test->outfile, "%llu %s %s iperf3: %s\n", + getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", + iperf_get_state_str(test->state), str); } else { - fprintf(stderr, "%llu %s iperf3: %s\n", - getCurMs(), iperf_get_state_str(test->state), str); + fprintf(stderr, "%llu %s %s iperf3: %s\n", + getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", + iperf_get_state_str(test->state), str); } va_end(argp); } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index e77239432..e459b550d 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -699,6 +699,16 @@ iperf_run_server(struct iperf_test *test) if (test->debug) iperf_err(test, "Done with timers..\n"); } + + if (test->state == CREATE_STREAMS) { + // If it has been too long, then consider the test a failure and return. + if (test->create_streams_state_at + 5000 < getCurMs()) { + iperf_err(test, "Test has been in create-streams state for: %llums, aborting.\n", + (unsigned long long)(getCurMs() - test->create_streams_state_at)); + cleanup_server(test); + return -1; + } + } } if (test->debug) From 98df879efa9f1f8e69af0bf37c63bc877f4e2456 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 07:47:16 -0700 Subject: [PATCH 31/45] Fix compile warnings. --- src/iperf_error.c | 4 ++-- src/net.c | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/iperf_error.c b/src/iperf_error.c index cb033765d..a2a6b6961 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -48,12 +48,12 @@ iperf_err(struct iperf_test *test, const char *format, ...) else if (test && test->outfile && test->outfile != stdout) { fprintf(test->outfile, "%llu %s %s iperf3: %s\n", - getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", + (unsigned long long)getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", iperf_get_state_str(test->state), str); } else { fprintf(stderr, "%llu %s %s iperf3: %s\n", - getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", + (unsigned long long)getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", iperf_get_state_str(test->state), str); } va_end(argp); diff --git a/src/net.c b/src/net.c index 7b60cedf6..64b5263fd 100644 --- a/src/net.c +++ b/src/net.c @@ -102,7 +102,7 @@ void nonblock(int s) { void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set) { int i; - fprintf(stderr, "%llu read/write FD sets: ", getCurMs()); + fprintf(stderr, "%llu read/write FD sets: ", (unsigned long long)getCurMs()); for (i = 0; i<=max_fd; i++) { if (FD_ISSET(i, read_set)) { if (FD_ISSET(i, write_set)) { @@ -129,11 +129,9 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout) { socklen_t optlen; - int flags, optval; + int optval; int ret; - flags = 0; - if ((ret = connect(s, name, namelen)) != 0 && eWouldBlock()) { #ifndef __WIN32__ struct pollfd pfd; From c64cb643f4681539c894817c3ec5d3a3653a4bfb Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 11:40:34 -0700 Subject: [PATCH 32/45] Use stdout instead of stderr for windows errors. Stderr seems to block writing to console sometimes (win-7, powershell), but stdout appears to work better. --- src/iperf_api.c | 46 +++++++++++++++++---------------------- src/iperf_api.h | 1 - src/iperf_client_api.c | 11 +++------- src/iperf_error.c | 23 ++++++++++++++++---- src/iperf_server_api.c | 14 ++++++------ src/iperf_tcp.c | 16 +++++++------- src/iperf_udp.c | 49 ++++++++++++++++++------------------------ src/net.c | 12 +++++------ src/net.h | 2 +- 9 files changed, 85 insertions(+), 89 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index f1f011374..05192a4cf 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -108,12 +108,6 @@ usage_long(FILE *f) } -void warning(char *str) -{ - fprintf(stderr, "warning: %s\n", str); -} - - /************** Getter routines for some fields inside iperf_test *************/ int @@ -1383,15 +1377,15 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) /* 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)"); + iperf_err(test, "Report format (-f) flag ignored with JSON output (-J)"); } /* Show warning if JSON output is used with verbose or debug flags */ if (test->json_output && test->verbose) { - warning("Verbose output (-v) may interfere with JSON output (-J)"); + iperf_err(test, "Verbose output (-v) may interfere with JSON output (-J)"); } if (test->json_output && test->debug) { - warning("Debug output (-d) may interfere with JSON output (-J)"); + iperf_err(test, "Debug output (-d) may interfere with JSON output (-J)"); } return 0; @@ -1414,9 +1408,9 @@ int iperf_open_logfile(struct iperf_test *test) void iperf_set_state(struct iperf_test *test, signed char state, const char* dbg) { if (test->debug) { - fprintf(stderr, "test: %p state: %d(%s) ==> %d(%s) dbg: %s\n", - test, test->state, iperf_get_state_str(test->state), - state, iperf_get_state_str(state), dbg); + iperf_err(test, "test: %p state: %d(%s) ==> %d(%s) dbg: %s\n", + test, test->state, iperf_get_state_str(test->state), + state, iperf_get_state_str(state), dbg); } test->state = state; } @@ -1517,7 +1511,7 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP) SLIST_FOREACH(sp, &test->streams, streams) { if (FD_ISSET(sp->socket, read_setP) && !sp->sender) { if ((r = sp->rcv(sp)) < 0) { - fprintf(stderr, "Failed rcv: %s socket: %d\n", STRERROR, sp->socket); + iperf_err(test, "Failed rcv: %s socket: %d\n", STRERROR, sp->socket); i_errno = IESTREAMREAD; return r; } @@ -1690,8 +1684,8 @@ iperf_exchange_parameters(struct iperf_test *test) void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { if (test->debug > 1) { - fprintf(stderr, "FD-SET, fd: %d at %s:%d\n", - fd, file, line); + iperf_err(test, "FD-SET, fd: %d at %s:%d", + fd, file, line); } FD_SET(fd, fdset); if (fd > test->max_fd) @@ -1700,8 +1694,8 @@ void _fd_set(int fd, fd_set* fdset, struct iperf_test *test, const char* file, i void _fd_clr(int fd, fd_set* fdset, struct iperf_test *test, const char* file, int line) { if (test->debug > 1) { - fprintf(stderr, "FD-CLR, fd: %d at %s:%d\n", - fd, file, line); + iperf_err(test, "FD-CLR, fd: %d at %s:%d", + fd, file, line); } FD_CLR(fd, fdset); } @@ -2261,7 +2255,7 @@ JSON_read(int fd, struct iperf_test *test) } } else { - fprintf(stderr, "WARNING: Error waiting for json read, hsize: %d, errno: %s", hsize, STRERROR); + iperf_err(test, "WARNING: Error waiting for json read, hsize: %d, errno: %s", hsize, STRERROR); } free(str); } @@ -3740,7 +3734,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream)); if (!sp) { - fprintf(stderr, "Failed to malloc iperf-stream.\n"); + iperf_err(test, "Failed to malloc iperf-stream.\n"); i_errno = IECREATESTREAM; return NULL; } @@ -3753,7 +3747,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result)); if (!sp->result) { free(sp); - fprintf(stderr, "Failed to malloc sp->result.\n"); + iperf_err(test, "Failed to malloc sp->result."); i_errno = IECREATESTREAM; return NULL; } @@ -3765,7 +3759,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) errno = 0; sp->buffer_fd = mkstemp(template); if (sp->buffer_fd == -1) { - fprintf(stderr, "Failed to mkstemp %s (%s)\n", template, STRERROR); + iperf_err(test, "Failed to mkstemp %s (%s)", template, STRERROR); i_errno = IECREATESTREAM; free(sp->result); free(sp); @@ -3776,7 +3770,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) #ifndef __WIN32__ errno = 0; if (unlink(template) < 0) { - fprintf(stderr, "Failed to unlink temp file: %s (%s)\n", template, STRERROR); + iperf_err(test, "Failed to unlink temp file: %s (%s)", template, STRERROR); i_errno = IECREATESTREAM; free(sp->result); free(sp); @@ -3785,7 +3779,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) #endif if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) { - fprintf(stderr, "Failed to truncate, fd: %d blksize: %d\n", sp->buffer_fd, test->settings->blksize); + iperf_err(test, "Failed to truncate, fd: %d blksize: %d", sp->buffer_fd, test->settings->blksize); i_errno = IECREATESTREAM; free(sp->result); free(sp); @@ -3793,7 +3787,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) } sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0); if (sp->buffer == MAP_FAILED) { - fprintf(stderr, "Failed to mmap.\n"); + iperf_err(test, "Failed to mmap."); i_errno = IECREATESTREAM; free(sp->result); free(sp); @@ -3878,8 +3872,8 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) } } #else - fprintf(stderr, "WARNING: ToS: 0x%x requested, but windows does not support setting ToS. Ignoring.\n", - test->settings->tos); + iperf_err(test, "WARNING: ToS: 0x%x requested, but windows does not support setting ToS. Ignoring.\n", + test->settings->tos); #endif } diff --git a/src/iperf_api.h b/src/iperf_api.h index bb5d56760..04763f98b 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -277,7 +277,6 @@ 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 *); int iperf_exchange_results(struct iperf_test *); int iperf_init_test(struct iperf_test *); int iperf_create_send_timers(struct iperf_test *); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 515d4d223..df785914e 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -379,10 +379,7 @@ iperf_connect(struct iperf_test *test) test->ctrl_sck_mss = opt; } else { - char str[128]; - snprintf(str, sizeof(str), - "Ignoring nonsense TCP MSS %d", opt); - warning(str); + iperf_err(test, "Ignoring nonsense TCP MSS %d", opt); test->ctrl_sck_mss = 0; } @@ -426,10 +423,8 @@ iperf_connect(struct iperf_test *test) */ if (test->ctrl_sck_mss > 0 && test->settings->blksize > test->ctrl_sck_mss) { - char str[128]; - snprintf(str, sizeof(str), - "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss); - warning(str); + iperf_err(test, "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", + test->settings->blksize, test->ctrl_sck_mss); } } diff --git a/src/iperf_error.c b/src/iperf_error.c index a2a6b6961..62ee265ac 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -41,21 +41,36 @@ iperf_err(struct iperf_test *test, const char *format, ...) va_list argp; char str[1000]; + /* For reasons that I don't understand, when I run iperf with debugging on windows, + * (inside power-shell on win 7 specifically) + * Then it appears it blocks on writing to stderr fairly often, until I hit enter in + * the shell. + * I do not see the problem writing to stdout. So, switch err messages to stdout for + * windows. --Ben + */ +#ifdef __WIN32__ + #define __OFILE stdout +#else + #define __OFILE stderr +#endif + va_start(argp, format); vsnprintf(str, sizeof(str), format, argp); - if (test != NULL && test->json_output && test->json_top != NULL) + if (test != NULL && test->json_output && test->json_top != NULL) { cJSON_AddStringToObject(test->json_top, "error", str); - else - if (test && test->outfile && test->outfile != stdout) { + } + else { + if (test && test->outfile && test->outfile != __OFILE) { fprintf(test->outfile, "%llu %s %s iperf3: %s\n", (unsigned long long)getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", iperf_get_state_str(test->state), str); } else { - fprintf(stderr, "%llu %s %s iperf3: %s\n", + fprintf(__OFILE, "%llu %s %s iperf3: %s\n", (unsigned long long)getCurMs(), test->protocol ? test->protocol->name : "NULL-PROTO", iperf_get_state_str(test->state), str); } + } va_end(argp); } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index e459b550d..57136a015 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -80,7 +80,7 @@ iperf_server_listen(struct iperf_test *test) ** kernel does not actually do IPv6. This is not too unusual, ** v6 support is and perhaps always will be spotty. */ - warning("this system does not seem to support IPv6 - trying IPv4"); + iperf_err(test, "this system does not seem to support IPv6 - trying IPv4"); test->settings->domain = AF_INET; goto retry; } else { @@ -468,7 +468,7 @@ iperf_run_server(struct iperf_test *test) else iperf_err(test, "timeout NULL, max-fd: %d state: %d(%s)", test->max_fd, test->state, iperf_get_state_str(test->state)); - print_fdset(test->max_fd, &read_set, &write_set); + print_fdset(test->max_fd, &read_set, &write_set, test); } result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); @@ -476,9 +476,9 @@ iperf_run_server(struct iperf_test *test) iperf_err(test, "select result: %d, listener: %d ISSET-listener: %d test-state: %d(%s)", result, test->listener, FD_ISSET(test->listener, &read_set), test->state, iperf_get_state_str(test->state)); - iperf_err(test, "prot-listener: %d ISSET: %d max-fd: %d\n", + iperf_err(test, "prot-listener: %d ISSET: %d max-fd: %d", test->prot_listener, FD_ISSET(test->prot_listener, &read_set), test->max_fd); - print_fdset(test->max_fd, &read_set, &write_set); + print_fdset(test->max_fd, &read_set, &write_set, test); last_dbg = now.secs; } @@ -550,7 +550,7 @@ iperf_run_server(struct iperf_test *test) * continue. */ if (errno == ENOENT) { - warning("TCP congestion control algorithm not supported"); + iperf_err(test, "TCP congestion control algorithm not supported"); } else { saved_errno = errno; @@ -692,11 +692,11 @@ iperf_run_server(struct iperf_test *test) if (result == 0 || (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { /* Run the timers. */ - if (test->debug) + if (test->debug > 1) iperf_err(test, "Running timers..\n"); iperf_time_now(&now); tmr_run(&now); - if (test->debug) + if (test->debug > 1) iperf_err(test, "Done with timers..\n"); } diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index a4b5247b3..d5389f39b 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -61,7 +61,7 @@ iperf_tcp_recv(struct iperf_stream *sp) r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp, sp->test); if (r < 0) { - fprintf(stderr, "tcp-recv, failed (%s), socket: %d\n", STRERROR, sp->socket); + iperf_err(sp->test, "tcp-recv, failed (%s), socket: %d\n", STRERROR, sp->socket); return r; } @@ -125,7 +125,7 @@ iperf_tcp_accept(struct iperf_test * test) waitSocketReadable(test->listener, ctrl_wait_ms); if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { - fprintf(stderr, "tcp-accept, accept failed: %s\n", STRERROR); + iperf_err(test, "tcp-accept, accept failed: %s", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -415,7 +415,7 @@ iperf_tcp_connect(struct iperf_test *test) hints.ai_family = test->settings->domain; hints.ai_socktype = SOCK_STREAM; if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) { - fprintf(stderr, "tcp-connect, getaddrinfo failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, getaddrinfo failed: %s", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -428,7 +428,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) { if (test->bind_address) freeaddrinfo(local_res); - fprintf(stderr, "tcp-connect, getaddrinfo (server) failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, getaddrinfo (server) failed: %s", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -436,7 +436,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) { freeaddrinfo(local_res); freeaddrinfo(server_res); - fprintf(stderr, "tcp-connect, socket() failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, socket() failed: %s", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -469,7 +469,7 @@ iperf_tcp_connect(struct iperf_test *test) lcladdr->sin_port = htons(test->bind_port); if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { - fprintf(stderr, "tcp-connect, bind() failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, bind() failed: %s\n", STRERROR); saved_errno = errno; iclosesocket(s, test); freeaddrinfo(local_res); @@ -512,7 +512,7 @@ iperf_tcp_connect(struct iperf_test *test) } if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { - fprintf(stderr, "tcp-connect, bind2() failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, bind2() failed: %s\n", STRERROR); saved_errno = errno; iclosesocket(s, test); freeaddrinfo(server_res); @@ -677,7 +677,7 @@ iperf_tcp_connect(struct iperf_test *test) } if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && !eWouldBlock()) { - fprintf(stderr, "tcp-connect, connect() failed: %s\n", STRERROR); + iperf_err(test, "tcp-connect, connect() failed: %s\n", STRERROR); saved_errno = errno; iclosesocket(s, test); freeaddrinfo(server_res); diff --git a/src/iperf_udp.c b/src/iperf_udp.c index c49e81058..19075904a 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -151,7 +151,8 @@ iperf_udp_recv(struct iperf_stream *sp) /* Log the out-of-order packet */ if (sp->test->debug) - fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", pcount, sp->packet_count, sp->socket); + iperf_err(sp->test, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", + pcount, sp->packet_count, sp->socket); } /* @@ -301,11 +302,8 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) return -1; } if (test->settings->blksize > sndbuf_actual) { - char str[80]; - snprintf(str, sizeof(str), - "Block size %d > sending socket buffer size %d", - test->settings->blksize, sndbuf_actual); - warning(str); + iperf_err(test, "Block size %d > sending socket buffer size %d", + test->settings->blksize, sndbuf_actual); rc = 1; } @@ -323,11 +321,8 @@ iperf_udp_buffercheck(struct iperf_test *test, int s) return -1; } if (test->settings->blksize > rcvbuf_actual) { - char str[80]; - snprintf(str, sizeof(str), - "Block size %d > receiving socket buffer size %d", - test->settings->blksize, rcvbuf_actual); - warning(str); + iperf_err(test, "Block size %d > receiving socket buffer size %d", + test->settings->blksize, rcvbuf_actual); rc = 1; } @@ -389,14 +384,13 @@ iperf_udp_accept(struct iperf_test *test) } else { if (test->debug) { - fprintf(stderr, "Did not receive response, try %d / 30, in udp-accept.\n", - i); + iperf_err(test, "Did not receive response, try %d / 30, in udp-accept.", i); } } } /* If here, we did not get a response in time. */ - fprintf(stderr, "Did not receive frame within 30 seconds in udp-accept.\n"); + iperf_err(test, "Did not receive frame within 30 seconds in udp-accept."); i_errno = IESTREAMACCEPT; return -1; @@ -438,7 +432,7 @@ iperf_udp_accept(struct iperf_test *test) printf("Setting fair-queue socket pacing to %u\n", fqrate); } if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { - warning("Unable to set socket pacing"); + iperf_err(test, "Unable to set socket pacing"); } } } @@ -458,7 +452,7 @@ iperf_udp_accept(struct iperf_test *test) test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port, test); if (test->debug) { - fprintf(stderr, "udp-accept, new prot-listener socket: %d\n", test->prot_listener); + iperf_err(test, "udp-accept, new prot-listener socket: %d", test->prot_listener); } if (test->prot_listener < 0) { @@ -505,10 +499,9 @@ iperf_udp_listen(struct iperf_test *test) } if (test->debug) { - fprintf(stderr, "iperf-udp-listen, fd: %d\n", s); + iperf_err(test, "iperf-udp-listen, fd: %d", s); } - /* * The caller will put this value into test->prot_listener. */ @@ -532,13 +525,13 @@ iperf_udp_connect(struct iperf_test *test) int rc; if (test->debug) { - fprintf(stderr, "udp-connect called\n"); + iperf_err(test, "udp-connect called"); } /* Create and bind our local socket. */ if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1, test)) < 0) { - fprintf(stderr, "udp-connect, netdial() failed: %s\n", STRERROR); + iperf_err(test, "udp-connect, netdial() failed: %s", STRERROR); i_errno = IESTREAMCONNECT; return -1; } @@ -579,7 +572,7 @@ iperf_udp_connect(struct iperf_test *test) printf("Setting fair-queue socket pacing to %u\n", fqrate); } if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { - warning("Unable to set socket pacing"); + iperf_err(test, "Unable to set socket pacing"); } } } @@ -606,8 +599,8 @@ iperf_udp_connect(struct iperf_test *test) */ buf = 123456789; /* this can be pretty much anything */ if (test->debug) { - fprintf(stderr, "sending '123456789' to peer to let them know we are here: %s", - hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + iperf_err(test, "sending '123456789' to peer to let them know we are here: %s", + hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); } for (i = 0; i<30; i++) { @@ -631,7 +624,7 @@ iperf_udp_connect(struct iperf_test *test) } if (test->debug) { - fprintf(stderr, "waiting to receive response from server\n"); + iperf_err(test, "waiting to receive response from server"); } /* @@ -645,27 +638,27 @@ iperf_udp_connect(struct iperf_test *test) int select_ret = select(s + 1, &read_fds, NULL, NULL, &tv); if (select_ret == 1) { if ((sz = recv(s, (char*)&buf, sizeof(buf), 0)) < 0) { - fprintf(stderr, "Failed recv: %s socket: %d\n", STRERROR, s); + iperf_err(test, "Failed recv: %s socket: %d", STRERROR, s); iclosesocket(s, test); i_errno = IESTREAMREAD; return -1; } if (test->debug) { - fprintf(stderr, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); + iperf_err(test, "Received response from server: %s", hexdump((const unsigned char*)(&buf), sizeof(buf), 1, 1)); } return s; } else { if (test->debug) { - fprintf(stderr, "No response from server, will retry: %d / 30\n", i); + iperf_err(test, "No response from server, will retry: %d / 30", i); } } } /* if here, we could not get a response in time. */ if (test->debug) { - fprintf(stderr, "Did not receive UDP connect response in time.\n"); + iperf_err(test, "Did not receive UDP connect response in time."); } iclosesocket(s, test); i_errno = IESTREAMREAD; diff --git a/src/net.c b/src/net.c index 64b5263fd..2ebc2f85f 100644 --- a/src/net.c +++ b/src/net.c @@ -100,23 +100,23 @@ void nonblock(int s) { }//nonblock #endif -void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set) { +void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set, struct iperf_test *test) { int i; - fprintf(stderr, "%llu read/write FD sets: ", (unsigned long long)getCurMs()); + iperf_err(test, "%llu read/write FD sets: ", (unsigned long long)getCurMs()); for (i = 0; i<=max_fd; i++) { if (FD_ISSET(i, read_set)) { if (FD_ISSET(i, write_set)) { - fprintf(stderr, "%i RW ", i); + fprintf(stdout, "%i RW ", i); } else { - fprintf(stderr, "%i RO ", i); + fprintf(stdout, "%i RO ", i); } } else if (FD_ISSET(i, write_set)) { - fprintf(stderr, "%i WO ", i); + fprintf(stdout, "%i WO ", i); } } - fprintf(stderr, "\n"); + fprintf(stdout, "\n"); } /* diff --git a/src/net.h b/src/net.h index cb743fb89..7749d4286 100644 --- a/src/net.h +++ b/src/net.h @@ -36,7 +36,7 @@ int eWouldBlock(); void iclosesocket(int s, struct iperf_test *test); void nonblock(int s); -void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set); +void print_fdset(int max_fd, fd_set* read_set, fd_set* write_set, struct iperf_test *test); int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout); int netdial(int domain, int proto, char *local, const char* bind_dev, int local_port, char *server, int port, int timeout, From b6217ecac1abe8318ddb142e7a53b46a611cea18 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 12:06:40 -0700 Subject: [PATCH 33/45] Fix compile on Linux. --- src/iperf_tcp.c | 4 ++-- src/iperf_udp.c | 13 ++++++------- src/net.c | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index d5389f39b..8862b4c11 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -275,7 +275,7 @@ iperf_tcp_listen(struct iperf_test *test) printf("Setting fair-queue socket pacing to %u\n", fqrate); } if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { - warning("Unable to set socket pacing"); + iperf_err(test, "Unable to set socket pacing"); } } } @@ -662,7 +662,7 @@ iperf_tcp_connect(struct iperf_test *test) printf("Setting fair-queue socket pacing to %u\n", fqrate); } if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { - warning("Unable to set socket pacing"); + iperf_err(test, "Unable to set socket pacing"); } } } diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 19075904a..6ccda65f3 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -605,8 +605,6 @@ iperf_udp_connect(struct iperf_test *test) for (i = 0; i<30; i++) { fd_set read_fds; - FD_ZERO(&read_fds); //Zero out the file descriptor set - FD_SET(s, &read_fds); //Set the current socket file descriptor into the set /* UDP messages can be lost and will not automatically be retransmitted. * so we will retry and use select to not block forever. @@ -632,8 +630,11 @@ iperf_udp_connect(struct iperf_test *test) */ //We are going to use select to wait for the socket to connect struct timeval tv; - tv.tv_sec = 1; //The second portion of the struct - tv.tv_usec = 0; //The microsecond portion of the struct + tv.tv_sec = 1; + tv.tv_usec = 0; + + FD_ZERO(&read_fds); + FD_SET(s, &read_fds); int select_ret = select(s + 1, &read_fds, NULL, NULL, &tv); if (select_ret == 1) { @@ -657,9 +658,7 @@ iperf_udp_connect(struct iperf_test *test) } /* if here, we could not get a response in time. */ - if (test->debug) { - iperf_err(test, "Did not receive UDP connect response in time."); - } + iperf_err(test, "Did not receive UDP connect response in time."); iclosesocket(s, test); i_errno = IESTREAMREAD; return -1; diff --git a/src/net.c b/src/net.c index 2ebc2f85f..0273120cd 100644 --- a/src/net.c +++ b/src/net.c @@ -443,11 +443,11 @@ int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, int r; if (test->debug > 1) - iperf_err(test, "waitRead, calling Nread, fd: %d count: %d sofar: %d", fd, count, sofar); + iperf_err(test, "waitRead, calling Nread, fd: %d count: %d sofar: %d", fd, (int)count, sofar); r = Nread(fd, buf + sofar, count - sofar, prot, test); if (test->debug > 1) iperf_err(test, "waitRead, Nread, fd: %d count: %d sofar: %d rv: %d", - fd, count, sofar, r); + fd, (int)count, sofar, r); if (r < 0) { if (sofar == 0) return r; @@ -472,7 +472,7 @@ int waitRead(int fd, char *buf, size_t count, int prot, struct iperf_test *test, select_ret = select(fd + 1, &read_fds, NULL, NULL, &tv); if (test->debug > 1) iperf_err(test, "waitRead, done with select, fd: %d count: %d sofar: %d select-ret: %d", - fd, count, sofar, select_ret); + fd, (int)count, sofar, select_ret); if (select_ret <= 0) return sofar; } From 9ffff809563dfa9165c47d82448d1aa57c138097 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 13:38:46 -0700 Subject: [PATCH 34/45] Move cleanup-server to one location. And make sure that we close the prot_listener socket. Signed-off-by: Ben Greear --- src/iperf_api.h | 1 + src/iperf_server_api.c | 24 ++---------------------- src/main.c | 1 + 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/iperf_api.h b/src/iperf_api.h index 04763f98b..3690afe23 100755 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -303,6 +303,7 @@ int iperf_handle_message_client(struct iperf_test *); int iperf_client_end(struct iperf_test *); /* Server routines. */ +void cleanup_server(struct iperf_test *test); int iperf_run_server(struct iperf_test *); int iperf_server_listen(struct iperf_test *); int iperf_accept(struct iperf_test *); diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 57136a015..5da8059a1 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -370,12 +370,12 @@ create_server_omit_timer(struct iperf_test * test) return 0; } -static void -cleanup_server(struct iperf_test *test) +void cleanup_server(struct iperf_test *test) { /* Close open test sockets */ iclosesocket(test->ctrl_sck, test); iclosesocket(test->listener, test); + iclosesocket(test->prot_listener, test); /* Cancel any remaining timers. */ if (test->stats_timer != NULL) { @@ -484,7 +484,6 @@ iperf_run_server(struct iperf_test *test) if (result < 0 && errno != EINTR) { iperf_err(test, "Cleaning server, select had error: %s", STRERROR); - cleanup_server(test); i_errno = IESELECT; return -1; } @@ -494,7 +493,6 @@ iperf_run_server(struct iperf_test *test) if (FD_ISSET(test->listener, &read_set)) { if (test->state != CREATE_STREAMS) { if (iperf_accept(test) < 0) { - cleanup_server(test); return -1; } @@ -515,7 +513,6 @@ iperf_run_server(struct iperf_test *test) // Check control socket if (FD_ISSET(test->ctrl_sck, &read_set)) { if (iperf_handle_message_server(test) < 0) { - cleanup_server(test); return -1; } } @@ -524,7 +521,6 @@ iperf_run_server(struct iperf_test *test) if (FD_ISSET(test->prot_listener, &read_set)) { if ((s = test->protocol->accept(test)) < 0) { - cleanup_server(test); return -1; } @@ -555,7 +551,6 @@ iperf_run_server(struct iperf_test *test) else { saved_errno = errno; iclosesocket(s, test); - cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -568,7 +563,6 @@ iperf_run_server(struct iperf_test *test) if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { saved_errno = errno; iclosesocket(s, test); - cleanup_server(test); errno = saved_errno; i_errno = IESETCONGESTION; return -1; @@ -595,7 +589,6 @@ iperf_run_server(struct iperf_test *test) if (flag != -1) { sp = iperf_new_stream(test, s, flag); if (!sp) { - cleanup_server(test); return -1; } @@ -623,7 +616,6 @@ iperf_run_server(struct iperf_test *test) iclosesocket(test->listener, test); if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port, test)) < 0) { - cleanup_server(test); i_errno = IELISTEN; return -1; } @@ -636,28 +628,22 @@ iperf_run_server(struct iperf_test *test) } test->prot_listener = -1; if (iperf_set_send_state(test, TEST_START) != 0) { - cleanup_server(test); return -1; } if (iperf_init_test(test) < 0) { - cleanup_server(test); return -1; } if (create_server_timers(test) < 0) { - cleanup_server(test); return -1; } if (create_server_omit_timer(test) < 0) { - cleanup_server(test); return -1; } if (test->mode != RECEIVER) if (iperf_create_send_timers(test) < 0) { - cleanup_server(test); return -1; } if (iperf_set_send_state(test, TEST_RUNNING) != 0) { - cleanup_server(test); return -1; } } @@ -666,23 +652,19 @@ iperf_run_server(struct iperf_test *test) if (test->state == TEST_RUNNING) { if (test->mode == BIDIRECTIONAL) { if (iperf_recv(test, &read_set) < 0) { - cleanup_server(test); return -1; } if (iperf_send(test, &write_set) < 0) { - cleanup_server(test); return -1; } } else if (test->mode == SENDER) { // Reverse mode. Server sends. if (iperf_send(test, &write_set) < 0) { - cleanup_server(test); return -1; } } else { // Regular mode. Server receives. if (iperf_recv(test, &read_set) < 0) { - cleanup_server(test); return -1; } } @@ -705,7 +687,6 @@ iperf_run_server(struct iperf_test *test) if (test->create_streams_state_at + 5000 < getCurMs()) { iperf_err(test, "Test has been in create-streams state for: %llums, aborting.\n", (unsigned long long)(getCurMs() - test->create_streams_state_at)); - cleanup_server(test); return -1; } } @@ -713,7 +694,6 @@ iperf_run_server(struct iperf_test *test) if (test->debug) iperf_err(test, "Done with server loop, cleaning up server.\n"); - cleanup_server(test); if (test->json_output) { if (iperf_json_finish(test) < 0) diff --git a/src/main.c b/src/main.c index cb61ad848..81a0c898f 100644 --- a/src/main.c +++ b/src/main.c @@ -177,6 +177,7 @@ run(struct iperf_test *test) else { iperf_err(test, "Finished with iperf_run_srver.."); } + cleanup_server(test); iperf_reset_test(test); if (iperf_get_test_one_off(test)) { /* Authentication failure doesn't count for 1-off test */ From d61ed5b17fa2dcfb943ee3d78d1744c0ce7169f1 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 14:16:23 -0700 Subject: [PATCH 35/45] Clean up streams in test cleanup code. Otherwise, if client looses connection half way through a test, sockets may be leaked and that will cause future problems with accepting new protocol connections. --- src/iperf_server_api.c | 11 ++++++++++- src/net.c | 33 ++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 5da8059a1..76ed8f603 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -377,6 +377,15 @@ void cleanup_server(struct iperf_test *test) iclosesocket(test->listener, test); iclosesocket(test->prot_listener, test); + /* Free streams */ + struct iperf_stream *sp; + while (!SLIST_EMPTY(&test->streams)) { + sp = SLIST_FIRST(&test->streams); + SLIST_REMOVE_HEAD(&test->streams, streams); + iclosesocket(sp->socket, test); + iperf_free_stream(sp); + } + /* Cancel any remaining timers. */ if (test->stats_timer != NULL) { tmr_cancel(test->stats_timer); @@ -626,7 +635,7 @@ iperf_run_server(struct iperf_test *test) IFD_SET(test->listener, &test->read_set, test); } } - test->prot_listener = -1; + if (iperf_set_send_state(test, TEST_START) != 0) { return -1; } diff --git a/src/net.c b/src/net.c index 0273120cd..94921a24d 100644 --- a/src/net.c +++ b/src/net.c @@ -410,23 +410,34 @@ netannounce(int domain, int proto, char *local, const char* bind_dev, int port, } void iclosesocket(int s, struct iperf_test *test) { + int rv; + if (s < 0) return; + + if (test->debug) { + iperf_err(test, "Closing socket: %d", s); + } + #ifdef __WIN32__ - closesocket(s); + rv = closesocket(s); #else - close(s); + rv = close(s); #endif - if (test) { - if (s == test->ctrl_sck) - test->ctrl_sck = -1; - if (s == test->listener) - test->listener = -1; - if (s == test->prot_listener) - test->prot_listener = -1; - IFD_CLR(s, &test->read_set, test); - IFD_CLR(s, &test->write_set, test); + + if (rv < 0) { + iperf_err(test, "Error closing socket %d, rv: %d, error: %s", + s, rv, STRERROR); } + + if (s == test->ctrl_sck) + test->ctrl_sck = -1; + if (s == test->listener) + test->listener = -1; + if (s == test->prot_listener) + test->prot_listener = -1; + IFD_CLR(s, &test->read_set, test); + IFD_CLR(s, &test->write_set, test); } From a1e3330b896cfb9e6742c328ecb80ce338696137 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 14:28:30 -0700 Subject: [PATCH 36/45] Rename stream id to stream_id Make it easier to search for. --- src/iperf.h | 2 +- src/iperf_api.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 9325196cd..4a3ad5bd1 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -230,7 +230,7 @@ struct iperf_stream int local_port; int remote_port; int socket; - int id; + int stream_id; int sender; /* XXX: is settings just a pointer to the same struct in iperf_test? if not, should it be? */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 05192a4cf..e73536f73 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2000,7 +2000,7 @@ send_results(struct iperf_test *test) cJSON_AddItemToArray(j_streams, j_stream); bytes_transferred = sp->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received; retransmits = (sp->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1; - cJSON_AddNumberToObject(j_stream, "id", sp->id); + cJSON_AddNumberToObject(j_stream, "id", sp->stream_id); cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred); cJSON_AddNumberToObject(j_stream, "retransmits", retransmits); cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter); @@ -2122,7 +2122,8 @@ get_results(struct iperf_test *test) cerror = j_errors->valueint; pcount = j_packets->valueint; SLIST_FOREACH(sp, &test->streams, streams) - if (sp->id == sid) break; + if (sp->stream_id == sid) + break; if (sp == NULL) { i_errno = IESTREAMID; r = -1; @@ -3889,7 +3890,7 @@ iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) if (SLIST_EMPTY(&test->streams)) { SLIST_INSERT_HEAD(&test->streams, sp, streams); - sp->id = 1; + sp->stream_id = 1; } else { // for (n = test->streams, i = 2; n->next; n = n->next, ++i); i = 2; @@ -3898,7 +3899,7 @@ iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) ++i; } SLIST_INSERT_AFTER(prev, sp, streams); - sp->id = i; + sp->stream_id = i; } } From f4c2c5472dee0665d779b7a452fef94f7e6a503a Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 25 Oct 2019 14:44:39 -0700 Subject: [PATCH 37/45] Use stream_id for 'id' instead of the stream socket. That way, the id doesn't change when we close a socket (and safely set it to -1). --- src/iperf_api.c | 85 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index e73536f73..a48094ad8 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -2311,9 +2311,9 @@ connect_msg(struct iperf_stream *sp) } if (sp->test->json_output) - cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("socket: %d local_host: %s local_port: %d remote_host: %s remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport)); + cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("id: %d socket: %d local_host: %s local_port: %d remote_host: %s remote_port: %d", (int64_t)sp->stream_id, (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport)); else - iperf_printf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport); + iperf_printf(sp->test, report_connected, sp->stream_id, ipl, lport, ipr, rport); } @@ -3227,26 +3227,41 @@ iperf_print_results(struct iperf_test *test) if (test->sender_has_retransmits) { /* Sender summary, TCP and SCTP with retransmits. */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender)); + cJSON_AddItemToObject(json_summary_stream, "sender", + iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d sender: %b", + (int64_t) sp->stream_id, + (int64_t) sp->socket, (double) start_time, (double) sender_time, + (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, + (int64_t) sp->result->stream_retrans, + (int64_t) sp->result->stream_max_snd_cwnd, + (int64_t) sp->result->stream_max_rtt, + (int64_t) sp->result->stream_min_rtt, + (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), + stream_must_be_sender)); else if (test->role == 's' && !sp->sender) { if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->socket); + iperf_printf(test, report_sender_not_available_format, sp->stream_id); } else { - iperf_printf(test, report_bw_retrans_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); + iperf_printf(test, report_bw_retrans_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); } } else { /* Sender summary, TCP and SCTP without retransmits. */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, stream_must_be_sender)); + cJSON_AddItemToObject(json_summary_stream, "sender", + iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", + (int64_t)sp->stream_id, (int64_t) sp->socket, + (double) start_time, (double) sender_time, + (double) sender_time, (int64_t) bytes_sent, + bandwidth * 8, stream_must_be_sender)); else if (test->role == 's' && !sp->sender) { if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->socket); + iperf_printf(test, report_sender_not_available_format, sp->stream_id); } else { - iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); + iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); } } } else { @@ -3275,7 +3290,15 @@ iperf_print_results(struct iperf_test *test) * instead. */ int packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count; - cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), stream_must_be_sender)); + cJSON_AddItemToObject(json_summary_stream, "udp", + iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d sender: %b", + (int64_t)sp->stream_id, (int64_t) sp->socket, (double) start_time, + (double) sender_time, (double) sender_time, (int64_t) bytes_sent, + bandwidth * 8, (double) sp->jitter * 1000.0, + (int64_t) (sp->cnt_error - sp->omitted_cnt_error), + (int64_t) (packet_count - sp->omitted_packet_count), + (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), + stream_must_be_sender)); } else { /* @@ -3287,10 +3310,10 @@ iperf_print_results(struct iperf_test *test) */ if (test->role == 's' && !sp->sender) { if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->socket); + iperf_printf(test, report_sender_not_available_format, sp->stream_id); } else { - iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender); + iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender); } if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0) iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); @@ -3330,14 +3353,18 @@ iperf_print_results(struct iperf_test *test) if (test->protocol->id == Ptcp || test->protocol->id == Psctp) { /* Receiver summary, TCP and SCTP */ if (test->json_output) - cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender)); + cJSON_AddItemToObject(json_summary_stream, "receiver", + iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", + (int64_t)sp->stream_id, (int64_t) sp->socket, (double) start_time, + (double) receiver_time, (double) end_time, (int64_t) bytes_received, + bandwidth * 8, stream_must_be_sender)); else if (test->role == 's' && sp->sender) { if (test->verbose) - iperf_printf(test, report_receiver_not_available_format, sp->socket); + iperf_printf(test, report_receiver_not_available_format, sp->stream_id); } else { - iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); + iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); } } else { @@ -3356,10 +3383,10 @@ iperf_print_results(struct iperf_test *test) if (test->role == 's' && sp->sender) { if (test->verbose) - iperf_printf(test, report_receiver_not_available_format, sp->socket); + iperf_printf(test, report_receiver_not_available_format, sp->stream_id); } else { - iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver); + iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver); } } } @@ -3641,25 +3668,35 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * if (test->sender_has_retransmits == 1 && sp->sender) { /* Interval, TCP with retransmits. */ if (test->json_output) - cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender)); + cJSON_AddItemToArray(json_interval_streams, + iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %b", + (int64_t)sp->stream_id, (int64_t) sp->socket, (double) st, (double) et, + (double) irp->interval_duration, (int64_t) irp->bytes_transferred, + bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, + (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, + irp->omitted, sp->sender)); else { unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A', test->settings->unit_precision); - iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:""); + iperf_printf(test, report_bw_retrans_cwnd_format, sp->stream_id, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:""); } } else { /* Interval, TCP without retransmits. */ if (test->json_output) - cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted, sp->sender)); + cJSON_AddItemToArray(json_interval_streams, + iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b sender: %b", + (int64_t)sp->stream_id, (int64_t) sp->socket, (double) st, (double) et, + (double) irp->interval_duration, (int64_t) irp->bytes_transferred, + bandwidth * 8, irp->omitted, sp->sender)); else - iperf_printf(test, report_bw_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->omitted?report_omitted:""); + iperf_printf(test, report_bw_format, sp->stream_id, mbuf, st, et, ubuf, nbuf, irp->omitted?report_omitted:""); } } else { /* Interval, UDP. */ if (sp->sender) { if (test->json_output) - cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f packets: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_packet_count, irp->omitted, sp->sender)); + cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f packets: %d omitted: %b sender: %b", (int64_t)sp->stream_id, (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_packet_count, irp->omitted, sp->sender)); else - iperf_printf(test, report_bw_udp_sender_format, sp->socket, mbuf, st, et, ubuf, nbuf, zbuf, irp->interval_packet_count, irp->omitted?report_omitted:""); + iperf_printf(test, report_bw_udp_sender_format, sp->stream_id, mbuf, st, et, ubuf, nbuf, zbuf, irp->interval_packet_count, irp->omitted?report_omitted:""); } else { if (irp->interval_packet_count > 0) { lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count; @@ -3668,9 +3705,9 @@ print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON * lost_percent = 0.0; } if (test->json_output) - cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted, sp->sender)); + cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("id: %d socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b sender: %b", (int64_t)sp->stream_id, (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted, sp->sender)); else - iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:""); + iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:""); } } From 3aa196130a26b31e40266a632c15346ed397559d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 10:48:16 -0700 Subject: [PATCH 38/45] Fix reporting peer's results in server mode when server is sender. Signed-off-by: Ben Greear --- src/iperf_api.c | 18 ++++-------------- src/iperf_server_api.c | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index a48094ad8..2b1171525 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -3359,13 +3359,7 @@ iperf_print_results(struct iperf_test *test) (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender)); else - if (test->role == 's' && sp->sender) { - if (test->verbose) - iperf_printf(test, report_receiver_not_available_format, sp->stream_id); - } - else { - iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); - } + iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); } else { /* @@ -3381,13 +3375,9 @@ iperf_print_results(struct iperf_test *test) lost_percent = 0.0; } - if (test->role == 's' && sp->sender) { - if (test->verbose) - iperf_printf(test, report_receiver_not_available_format, sp->stream_id); - } - else { - iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver); - } + iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, receiver_time, ubuf, nbuf, + sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), + (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver); } } } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 76ed8f603..1ceeb359a 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -203,7 +203,6 @@ iperf_handle_message_server(struct iperf_test *test) iclosesocket(sp->socket, test); sp->socket = -1; } - test->reporter_callback(test); if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) return -1; if (iperf_exchange_results(test) < 0) @@ -212,6 +211,7 @@ iperf_handle_message_server(struct iperf_test *test) return -1; if (test->on_test_finish) test->on_test_finish(test); + test->reporter_callback(test); break; case IPERF_DONE: break; From 9c767ceed545709c04b6336ad216656d58a4b92c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 10:51:27 -0700 Subject: [PATCH 39/45] Fix summary stats exhange in client mode when server is sender. Signed-off-by: Ben Greear --- src/iperf.h | 1 + src/iperf_api.c | 22 ++++++++++++++++------ src/iperf_client_api.c | 38 +++++++++++++++++++++----------------- src/iperf_tcp.c | 3 ++- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 4a3ad5bd1..90e196fd5 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -382,6 +382,7 @@ struct iperf_test Timer *stats_timer; Timer *reporter_timer; uint64_t create_streams_state_at; /* when did we enter the create-streams state? */ + uint64_t done_at_ms; double cpu_util[3]; /* cpu utilization of the test - total, user, system */ double remote_cpu_util[3]; /* cpu utilization for the remote host/client - total, user, system */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 2b1171525..4f6ed1a4d 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -1505,22 +1505,31 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) int iperf_recv(struct iperf_test *test, fd_set *read_setP) { + int valid_sock = 0; int r; struct iperf_stream *sp; SLIST_FOREACH(sp, &test->streams, streams) { + if (sp->socket < 0) + continue; + valid_sock++; if (FD_ISSET(sp->socket, read_setP) && !sp->sender) { if ((r = sp->rcv(sp)) < 0) { - iperf_err(test, "Failed rcv: %s socket: %d\n", STRERROR, sp->socket); - i_errno = IESTREAMREAD; - return r; + iperf_err(test, "Failed rcv: %s socket: %d", STRERROR, sp->socket); + iclosesocket(sp->socket, test); + sp->socket = -1; + valid_sock--; } - test->bytes_received += r; - ++test->blocks_received; - /* IFD_CLR(sp->socket, read_setP, test); // Don't see how this is helpful. --Ben */ + else { + test->bytes_received += r; + ++test->blocks_received; + /* IFD_CLR(sp->socket, read_setP, test); // Don't see how this is helpful. --Ben */ + } } } + if (valid_sock == 0) + return -1; return 0; } @@ -2652,6 +2661,7 @@ iperf_reset_test(struct iperf_test *test) #endif /* HAVE_CPUSET_SETAFFINITY */ iperf_set_state(test, TEST_INIT, __FUNCTION__); test->create_streams_state_at = 0; + test->done_at_ms = 0; test->ctrl_sck = -1; test->prot_listener = -1; diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index df785914e..e4e1dd96b 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -128,6 +128,8 @@ test_timer_proc(TimerClientData client_data, struct iperf_time *nowP) { struct iperf_test *test = client_data.p; + if (test->debug) + iperf_err(test, "test-timer-proc, setting done."); test->timer = NULL; test->done = 1; } @@ -168,7 +170,7 @@ create_client_timers(struct iperf_test * test) test->timer = test->stats_timer = test->reporter_timer = NULL; if (test->duration != 0) { test->done = 0; - test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0); + test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit) * SEC_TO_US, 0); if (test->timer == NULL) { i_errno = IEINITTEST; return -1; @@ -535,7 +537,7 @@ iperf_run_client(struct iperf_test * test) if (iperf_send(test, &write_set) < 0) return -1; if (iperf_recv(test, &read_set) < 0) - return -1; + test->done = 1; // peer could have just closed the connection since test was done. } else if (test->mode == SENDER) { // Regular mode. Client sends. if (iperf_send(test, &write_set) < 0) @@ -543,7 +545,7 @@ iperf_run_client(struct iperf_test * test) } else { // Reverse mode. Client receives. if (iperf_recv(test, &read_set) < 0) - return -1; + test->done = 1; // peer could have just closed the connection since test was done. } @@ -552,19 +554,12 @@ iperf_run_client(struct iperf_test * test) tmr_run(&now); /* Is the test done yet? */ - if ((!test->omitting) && - ((test->duration != 0 && test->done) || - (test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) || - (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks))) { - - // Unset non-blocking for non-UDP tests - if (test->protocol->id != Pudp) { - SLIST_FOREACH(sp, &test->streams, streams) { - setnonblocking(sp->socket, 0); - } - } + if (test->done || + (test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) || + (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)) { /* Yes, done! Send TEST_END. */ + iperf_err(test, "test is done"); test->done = 1; cpu_util(test->cpu_util); test->stats_callback(test); @@ -578,10 +573,19 @@ iperf_run_client(struct iperf_test * test) // and gets blocked, so it can't receive state changes // from the client side. else if (test->mode == RECEIVER && test->state == TEST_END) { - if (iperf_recv(test, &read_set) < 0) - return -1; + if (iperf_recv(test, &read_set) < 0) { + /* Recv sockets have been drained, wait a bit to see if we can exchange results */ + if (test->done_at_ms == 0) { + test->done_at_ms = getCurMs(); + } + else { + if (test->done_at_ms + 3000 < getCurMs()) { // 3 seconds to exchange results + break; + } + } + } } - } + }/* while test state is not done */ if (test->json_output) { if (iperf_json_finish(test) < 0) diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 8862b4c11..6ed2b1019 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -61,7 +61,8 @@ iperf_tcp_recv(struct iperf_stream *sp) r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp, sp->test); if (r < 0) { - iperf_err(sp->test, "tcp-recv, failed (%s), socket: %d\n", STRERROR, sp->socket); + if (sp->test->debug) // normal to hit this in tcp client receive mode. + iperf_err(sp->test, "tcp-recv, failed (%s), socket: %d", STRERROR, sp->socket); return r; } From 22757a2da4e8d9480bddc7ad73b3eed55b3df2de Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 11:04:58 -0700 Subject: [PATCH 40/45] Fix server-side summary reporting when peer is sender. --- src/iperf_api.c | 58 +++++++--------------------------------------- src/iperf_locale.c | 4 ---- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 4f6ed1a4d..09a49e677 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -3249,13 +3249,8 @@ iperf_print_results(struct iperf_test *test) (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender)); else - if (test->role == 's' && !sp->sender) { - if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->stream_id); - } - else { - iperf_printf(test, report_bw_retrans_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); - } + iperf_printf(test, report_bw_retrans_format, sp->stream_id, mbuf, start_time, + sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); } else { /* Sender summary, TCP and SCTP without retransmits. */ if (test->json_output) @@ -3266,13 +3261,7 @@ iperf_print_results(struct iperf_test *test) (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, stream_must_be_sender)); else - if (test->role == 's' && !sp->sender) { - if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->stream_id); - } - else { - iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); - } + iperf_printf(test, report_bw_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); } } else { /* Sender summary, UDP. */ @@ -3311,20 +3300,8 @@ iperf_print_results(struct iperf_test *test) stream_must_be_sender)); } else { - /* - * Due to ordering of messages on the control channel, - * the server cannot report on client-side summary - * statistics. If we're the server, omit one set of - * summary statistics to avoid giving meaningless - * results. - */ - if (test->role == 's' && !sp->sender) { - if (test->verbose) - iperf_printf(test, report_sender_not_available_format, sp->stream_id); - } - else { - iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender); - } + iperf_printf(test, report_bw_udp_format, sp->stream_id, mbuf, start_time, sender_time, ubuf, nbuf, + 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender); if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0) iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); } @@ -3410,25 +3387,14 @@ iperf_print_results(struct iperf_test *test) if (test->json_output) cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, stream_must_be_sender)); else - if (test->role == 's' && !stream_must_be_sender) { - if (test->verbose) - iperf_printf(test, report_sender_not_available_summary_format, "SUM"); - } - else { - iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, sender_time, ubuf, nbuf, total_retransmits, report_sender); - } + iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, sender_time, + ubuf, nbuf, total_retransmits, report_sender); } else { /* Summary sum, TCP without retransmits. */ if (test->json_output) cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, stream_must_be_sender)); else - if (test->role == 's' && !stream_must_be_sender) { - if (test->verbose) - iperf_printf(test, report_sender_not_available_summary_format, "SUM"); - } - else { - iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); - } + iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender); } unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A', test->settings->unit_precision); /* If no tests were run, set received bandwidth to 0 */ @@ -3442,13 +3408,7 @@ iperf_print_results(struct iperf_test *test) if (test->json_output) cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender)); else - if (test->role == 's' && stream_must_be_sender) { - if (test->verbose) - iperf_printf(test, report_receiver_not_available_summary_format, "SUM"); - } - else { - iperf_printf(test, report_sum_bw_format, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); - } + iperf_printf(test, report_sum_bw_format, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver); } else { /* Summary sum, UDP. */ avg_jitter /= test->num_streams; diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 93e76a37a..5464f1cec 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -415,10 +415,6 @@ const char report_local[] = "local"; const char report_remote[] = "remote"; const char report_sender[] = "sender"; const char report_receiver[] = "receiver"; -const char report_sender_not_available_format[] = "[%3d] (sender statistics not available)\n"; -const char report_sender_not_available_summary_format[] = "[%3s] (sender statistics not available)\n"; -const char report_receiver_not_available_format[] = "[%3d] (receiver statistics not available)\n"; -const char report_receiver_not_available_summary_format[] = "[%3s] (receiver statistics not available)\n"; #if defined(linux) const char report_tcpInfo[] = From e3ff364c61786d68e5554218e2baa7fa5e31e514 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 11:09:22 -0700 Subject: [PATCH 41/45] Update rls notes. --- RELNOTES.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/RELNOTES.md b/RELNOTES.md index ff02ba9ba..30e6dfa0c 100644 --- a/RELNOTES.md +++ b/RELNOTES.md @@ -1,6 +1,22 @@ iperf3 Release Notes ==================== +iperf 3.7-CT: Changes from upstream iperf3 + + * Make sockets non-blocking to fix various ways the client and server can hang. + + * Server will recover from client doing bad things or dying unexpectedly. + + * Fix socket leaks + + * Report summary stats in all cases on both client and server. + + * Allow compiling for win32 using mingw cross-compiler. + + * Add lots of optionally-enabled debugging to help understand what is going on when + adding new features or debugging problems. + + iperf 3.7 2019-06-21 -------------------- From ae300c1b46fab97e07bae454a76c1f58e6962c5c Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 13:10:57 -0700 Subject: [PATCH 42/45] Allow reading more than blksize for TCP connections. No need to force reader to read small bits when we are stream based anyway. And, use smaller writesize when setting MSS is not available (ie, windows). --- src/iperf.h | 1 + src/iperf_api.c | 22 ++++++++++++++-------- src/iperf_tcp.c | 20 +++++++++++++++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 90e196fd5..a0a7e5d05 100755 --- a/src/iperf.h +++ b/src/iperf.h @@ -198,6 +198,7 @@ struct iperf_settings int domain; /* AF_INET or AF_INET6 */ int socket_bufsize; /* window size for TCP */ int blksize; /* size of read/writes (-l) */ + int buflen; /* read/write buffer len, for tcp rcv, can be larger than blksize */ uint64_t rate; /* target data rate for application pacing*/ uint64_t fqrate; /* target data rate for FQ pacing*/ int pacing_timer; /* pacing timer in microseconds */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 09a49e677..7e94594c3 100755 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -381,6 +381,8 @@ void iperf_set_test_blksize(struct iperf_test *ipt, int blksize) { ipt->settings->blksize = blksize; + if (ipt->settings->buflen < blksize) + ipt->settings->buflen = blksize; } void @@ -1345,6 +1347,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return -1; } test->settings->blksize = blksize; + if (blksize < DEFAULT_TCP_BLKSIZE) + test->settings->buflen = DEFAULT_TCP_BLKSIZE; + else + test->settings->buflen = blksize; if (!rate_flag) test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0; @@ -3682,7 +3688,7 @@ iperf_free_stream(struct iperf_stream *sp) struct iperf_interval_results *irp, *nirp; /* XXX: need to free interval list too! */ - munmap(sp->buffer, sp->test->settings->blksize); + munmap(sp->buffer, sp->test->settings->buflen); close(sp->buffer_fd); if (sp->diskfile_fd >= 0) { close(sp->diskfile_fd); @@ -3776,14 +3782,14 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) } #endif - if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) { - iperf_err(test, "Failed to truncate, fd: %d blksize: %d", sp->buffer_fd, test->settings->blksize); + if (ftruncate(sp->buffer_fd, test->settings->buflen) < 0) { + iperf_err(test, "Failed to truncate, fd: %d buflen: %d", sp->buffer_fd, test->settings->buflen); i_errno = IECREATESTREAM; free(sp->result); free(sp); return NULL; } - sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0); + sp->buffer = (char *) mmap(NULL, test->settings->buflen, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0); if (sp->buffer == MAP_FAILED) { iperf_err(test, "Failed to mmap."); i_errno = IECREATESTREAM; @@ -3802,7 +3808,7 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR); if (sp->diskfile_fd == -1) { i_errno = IEFILE; - munmap(sp->buffer, sp->test->settings->blksize); + munmap(sp->buffer, sp->test->settings->buflen); free(sp->result); free(sp); return NULL; @@ -3816,13 +3822,13 @@ iperf_new_stream(struct iperf_test *test, int s, int sender) /* Initialize stream */ if (test->repeating_payload) - fill_with_repeating_pattern(sp->buffer, test->settings->blksize); + fill_with_repeating_pattern(sp->buffer, test->settings->buflen); else - ret = readentropy(sp->buffer, test->settings->blksize); + ret = readentropy(sp->buffer, test->settings->buflen); if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) { close(sp->buffer_fd); - munmap(sp->buffer, sp->test->settings->blksize); + munmap(sp->buffer, sp->test->settings->buflen); free(sp->result); free(sp); return NULL; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 6ed2b1019..454cfaaa8 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -88,11 +88,21 @@ int iperf_tcp_send(struct iperf_stream *sp) { int r; + int wsize = sp->settings->blksize; - if (sp->test->zerocopy) - r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize); - else - r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp, sp->test); + if (sp->test->zerocopy) { + r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, wsize); + } + else { +#ifdef __WIN32__ + if (sp->settings->mss) { + // Windows cannot do mss, send smaller block-sizes instead. + if (sp->settings->mss < sp->settings->blksize) + wsize = sp->settings->mss; + } +#endif + r = Nwrite(sp->socket, sp->buffer, wsize, Ptcp, sp->test); + } if (r < 0) return r; @@ -101,7 +111,7 @@ iperf_tcp_send(struct iperf_stream *sp) sp->result->bytes_sent_this_interval += r; if (sp->test->debug > 1) - printf("tcp: sent %d bytes of %d, total %llu\n", r, sp->settings->blksize, (long long unsigned)sp->result->bytes_sent); + printf("tcp: sent %d bytes of %d, total %llu\n", r, wsize, (long long unsigned)sp->result->bytes_sent); return r; } From 21ea36c7559bb9b3e9f0259e65891393b001945f Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 28 Oct 2019 14:39:58 -0700 Subject: [PATCH 43/45] Update rls notes. --- RELNOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELNOTES.md b/RELNOTES.md index 30e6dfa0c..a75bb6327 100644 --- a/RELNOTES.md +++ b/RELNOTES.md @@ -3,6 +3,8 @@ iperf3 Release Notes iperf 3.7-CT: Changes from upstream iperf3 + * Support SO_BINDTODEVICE + * Make sockets non-blocking to fix various ways the client and server can hang. * Server will recover from client doing bad things or dying unexpectedly. From d4c14aa1571f4c1938ac6cee770bc7266d451927 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 29 Oct 2019 12:50:04 -0700 Subject: [PATCH 44/45] Add zlib1.dll to the windows installer. Required for it to work. Signed-off-by: Ben Greear --- src/Makefile.mingw | 1 + src/iperf.nsis | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Makefile.mingw b/src/Makefile.mingw index b18e610d4..0f2b51f18 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -54,6 +54,7 @@ package_win32: ${TARG} cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libcrypto-10.dll ./ cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll ./ cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgnurx-0.dll ./ + cp /usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll ./ cp ../LICENSE ./license.txt makensis iperf.nsis diff --git a/src/iperf.nsis b/src/iperf.nsis index 9bcdf912e..337c501fe 100644 --- a/src/iperf.nsis +++ b/src/iperf.nsis @@ -120,6 +120,7 @@ Section "install" Installation File "libcrypto-10.dll" File "libgcc_s_sjlj-1.dll" File "libgnurx-0.dll" + File "zlib1.dll" ;write uninstall information to the registry WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${LF_INSTALL_DIR}" "DisplayName" "${MUI_PRODUCT} (remove only)" From 04af26ae486502a85dba81b2786f6ea782a74d31 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 12 Dec 2019 16:49:48 -0800 Subject: [PATCH 45/45] Fix busy-spin in client mode, make sure test eventually completes. Not sure exactly how I got to the old state, but there was a timer not being run because we were not in running state, but were evidently waiting on report from server which did not come. Signed-off-by: Ben Greear --- src/iperf_client_api.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index e4e1dd96b..18b9a3377 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -499,6 +499,7 @@ iperf_run_client(struct iperf_test * test) startup = 1; while (test->state != IPERF_DONE) { + int ran_timers = 0; memcpy(&read_set, &test->read_set, sizeof(fd_set)); memcpy(&write_set, &test->write_set, sizeof(fd_set)); iperf_time_now(&now); @@ -552,6 +553,7 @@ iperf_run_client(struct iperf_test * test) /* Run the timers. */ iperf_time_now(&now); tmr_run(&now); + ran_timers = 1; /* Is the test done yet? */ if (test->done || @@ -559,7 +561,7 @@ iperf_run_client(struct iperf_test * test) (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)) { /* Yes, done! Send TEST_END. */ - iperf_err(test, "test is done"); + //iperf_err(test, "test is done"); test->done = 1; cpu_util(test->cpu_util); test->stats_callback(test); @@ -573,18 +575,25 @@ iperf_run_client(struct iperf_test * test) // and gets blocked, so it can't receive state changes // from the client side. else if (test->mode == RECEIVER && test->state == TEST_END) { - if (iperf_recv(test, &read_set) < 0) { - /* Recv sockets have been drained, wait a bit to see if we can exchange results */ - if (test->done_at_ms == 0) { - test->done_at_ms = getCurMs(); - } - else { - if (test->done_at_ms + 3000 < getCurMs()) { // 3 seconds to exchange results - break; - } + iperf_recv(test, &read_set); + + /* Recv sockets have been drained, wait a bit to see if we can exchange results */ + if (test->done_at_ms == 0) { + test->done_at_ms = getCurMs(); + } + else { + if (test->done_at_ms + 3000 < getCurMs()) { // 3 seconds to exchange results + iperf_err(test, "Did not finish exchanging results within 3 seconds."); + break; } } } + + if (!ran_timers) { + /* Run the timers. */ + iperf_time_now(&now); + tmr_run(&now); + } }/* while test state is not done */ if (test->json_output) {