From b7b1b32afe949b2180bd54f280dbe0199a1dfaab Mon Sep 17 00:00:00 2001 From: Kevin Constantine Date: Tue, 9 Sep 2014 16:31:57 -0700 Subject: [PATCH 1/3] Add support for specifying client-side epemeral port -e/--cport now allows a user to specify the client-side port used for data transfer. Signed-off-by: Kevin Constantine --- src/iperf.h | 1 + src/iperf_api.c | 10 +++++++++- src/iperf_api.h | 1 + src/iperf_error.c | 3 +++ src/iperf_tcp.c | 5 +++++ src/locale.c | 4 ++++ 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/iperf.h b/src/iperf.h index 07ce9a2..dec9c7a 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -172,6 +172,7 @@ struct iperf_test signed char state; char *server_hostname; /* -c option */ char *bind_address; /* -B option */ + int *bind_port; /* -e option */ int server_port; int omit; /* duration of omit period (-O flag) */ int duration; /* total duration of test (-t flag) */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 068930f..435f032 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -584,6 +584,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"reverse", no_argument, NULL, 'R'}, {"window", required_argument, NULL, 'w'}, {"bind", required_argument, NULL, 'B'}, + {"cport", required_argument, NULL, 'e'}, {"set-mss", required_argument, NULL, 'M'}, {"no-delay", no_argument, NULL, 'N'}, {"version4", no_argument, NULL, '4'}, @@ -624,7 +625,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) blksize = 0; server_flag = client_flag = rate_flag = duration_flag = 0; - while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:h", longopts, NULL)) != -1) { + while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:k:l:P:Rw:B:e:M:N46S:L:ZO:F:A:T:C:dI:h", longopts, NULL)) != -1) { switch (flag) { case 'p': test->server_port = atoi(optarg); @@ -745,6 +746,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'B': test->bind_address = strdup(optarg); break; + case 'e': + test->bind_port = atoi(optarg); + break; case 'M': test->settings->mss = atoi(optarg); if (test->settings->mss > MAX_MSS) { @@ -876,6 +880,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return -1; } + if (!test->bind_address && test->bind_port) { + i_errno = IEBIND; + return -1; + } if (blksize == 0) { if (test->protocol->id == Pudp) blksize = DEFAULT_UDP_BLKSIZE; diff --git a/src/iperf_api.h b/src/iperf_api.h index ecac575..3c97cae 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -262,6 +262,7 @@ enum { IEENDCONDITIONS = 16, // Only one test end condition (-t, -n, -k) may be specified IELOGFILE = 17, // Can't open log file IENOSCTP = 18, // No SCTP support available + IEBIND = 19, // Local port specified with no local bind option /* Test errors */ IENEWTEST = 100, // Unable to create a new test (check perror) IEINITTEST = 101, // Test initialization failed (check perror) diff --git a/src/iperf_error.c b/src/iperf_error.c index ef1d1ef..6dd1dc1 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -104,6 +104,9 @@ iperf_strerror(int i_errno) case IEINTERVAL: snprintf(errstr, len, "invalid report interval (min = %g, max = %g seconds)", MIN_INTERVAL, MAX_INTERVAL); break; + case IEBIND: + snprintf(errstr, len, "--bind must be specified to use --cport"); + break; case IEMSS: snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS); break; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index cdf4cd2..0324e44 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -325,6 +325,11 @@ iperf_tcp_connect(struct iperf_test *test) } if (test->bind_address) { + struct sockaddr_in *lcladdr; + lcladdr = (struct sockaddr_in *)local_res->ai_addr; + lcladdr->sin_port = htons(test->bind_port); + local_res->ai_addr = (struct sockaddr *)lcladdr; + if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { saved_errno = errno; close(s); diff --git a/src/locale.c b/src/locale.c index 9e4c647..711d7f4 100644 --- a/src/locale.c +++ b/src/locale.c @@ -108,6 +108,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n" " -k, --blockcount #[KMG] number of blocks (packets) to transmit (instead of -t or -n)\n" " -l, --len #[KMG] length of buffer to read or write\n" " (default %d KB for TCP, %d KB for UDP)\n" + " -e, --cport bind to a specific client port (default: ephemeral port)\n" " -P, --parallel # number of parallel client streams to run\n" " -R, --reverse run in reverse mode (server sends, client receives)\n" " -w, --window #[KMG] TCP window size (socket buffer size)\n" @@ -171,6 +172,9 @@ const char client_port[] = const char bind_address[] = "Binding to local address %s\n"; +const char bind_port[] = +"Binding to local port %s\n"; + const char multicast_ttl[] = "Setting multicast TTL to %d\n"; From 499b1222308aa9423d71344485c8ac0b8b94f8cd Mon Sep 17 00:00:00 2001 From: Kevin Constantine Date: Mon, 15 Sep 2014 10:51:31 -0700 Subject: [PATCH 2/3] specify client-side port: Only support --cport Remove support for short-option -e Signed-off-by: Kevin Constantine --- src/iperf_api.c | 6 +++--- src/iperf_api.h | 1 + src/locale.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 435f032..82af6d6 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -584,7 +584,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"reverse", no_argument, NULL, 'R'}, {"window", required_argument, NULL, 'w'}, {"bind", required_argument, NULL, 'B'}, - {"cport", required_argument, NULL, 'e'}, + {"cport", required_argument, NULL, OPT_CLIENT_PORT}, {"set-mss", required_argument, NULL, 'M'}, {"no-delay", no_argument, NULL, 'N'}, {"version4", no_argument, NULL, '4'}, @@ -625,7 +625,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) blksize = 0; server_flag = client_flag = rate_flag = duration_flag = 0; - while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:k:l:P:Rw:B:e:M:N46S:L:ZO:F:A:T:C:dI:h", longopts, NULL)) != -1) { + while ((flag = getopt_long(argc, argv, "p:f:i:DVJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:h", longopts, NULL)) != -1) { switch (flag) { case 'p': test->server_port = atoi(optarg); @@ -746,7 +746,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'B': test->bind_address = strdup(optarg); break; - case 'e': + case OPT_CLIENT_PORT: test->bind_port = atoi(optarg); break; case 'M': diff --git a/src/iperf_api.h b/src/iperf_api.h index 3c97cae..a31a16b 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -30,6 +30,7 @@ struct iperf_stream; #define OPT_LOGFILE 2 #define OPT_GET_SERVER_OUTPUT 3 #define OPT_UDP_COUNTERS_64BIT 4 +#define OPT_CLIENT_PORT 5 /* states */ #define TEST_START 1 diff --git a/src/locale.c b/src/locale.c index 711d7f4..ab32772 100644 --- a/src/locale.c +++ b/src/locale.c @@ -108,7 +108,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n" " -k, --blockcount #[KMG] number of blocks (packets) to transmit (instead of -t or -n)\n" " -l, --len #[KMG] length of buffer to read or write\n" " (default %d KB for TCP, %d KB for UDP)\n" - " -e, --cport bind to a specific client port (default: ephemeral port)\n" + " --cport bind to a specific client port (default: ephemeral port)\n" " -P, --parallel # number of parallel client streams to run\n" " -R, --reverse run in reverse mode (server sends, client receives)\n" " -w, --window #[KMG] TCP window size (socket buffer size)\n" From 023fb45e7a945ccc905b4c7afc20ba2b68cf197b Mon Sep 17 00:00:00 2001 From: Kevin Constantine Date: Mon, 15 Sep 2014 10:57:43 -0700 Subject: [PATCH 3/3] specify client-side port: UDP support --cport can be specified for udp connections Signed-off-by: Kevin Constantine --- src/iperf_client_api.c | 3 ++- src/iperf_udp.c | 2 +- src/net.c | 9 ++++++++- src/net.h | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index dc0a65e..9020b87 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -268,7 +268,8 @@ iperf_connect(struct iperf_test *test) /* Create and connect the control channel */ if (test->ctrl_sck < 0) - test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->server_hostname, test->server_port); + // Create the control channel using an ephemeral port + test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, NULL, test->server_hostname, test->server_port); if (test->ctrl_sck < 0) { i_errno = IECONNECT; return -1; diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 38d0cc7..8633436 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -234,7 +234,7 @@ iperf_udp_connect(struct iperf_test *test) { int s, buf, sz; - if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->server_hostname, test->server_port)) < 0) { + if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port)) < 0) { i_errno = IESTREAMCONNECT; return -1; } diff --git a/src/net.c b/src/net.c index 72947d3..1fb4094 100644 --- a/src/net.c +++ b/src/net.c @@ -48,7 +48,7 @@ /* make connection to server */ int -netdial(int domain, int proto, char *local, char *server, int port) +netdial(int domain, int proto, char *local, int local_port, char *server, int port) { struct addrinfo hints, *local_res, *server_res; int s; @@ -76,6 +76,13 @@ netdial(int domain, int proto, char *local, char *server, int port) } if (local) { + if (local_port) { + struct sockaddr_in *lcladdr; + lcladdr = (struct sockaddr_in *)local_res->ai_addr; + lcladdr->sin_port = htons(local_port); + local_res->ai_addr = (struct sockaddr *)lcladdr; + } + if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { close(s); freeaddrinfo(local_res); diff --git a/src/net.h b/src/net.h index 1d6f390..5ab10ec 100644 --- a/src/net.h +++ b/src/net.h @@ -10,7 +10,7 @@ #ifndef __NET_H #define __NET_H -int netdial(int domain, int proto, char *local, char *server, int port); +int netdial(int domain, int proto, char *local, int local_port, char *server, int port); int netannounce(int domain, int proto, char *local, int port); int Nread(int fd, char *buf, size_t count, int prot); int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */;