From 9a599d5f8d3960234251a7031d3b6667b676e2bb Mon Sep 17 00:00:00 2001 From: sethdelliott Date: Tue, 3 Aug 2010 21:38:48 +0000 Subject: [PATCH] Added support for setting the IP TOS (IPv4) and IPv6 Traffic Class (-S option) --- src/iperf_api.c | 40 ++++++++++++++++++++++++++++++++++------ src/iperf_api.h | 2 +- src/iperf_error.c | 10 +++++++++- src/iperf_error.h | 32 +++++++++++++++++--------------- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/iperf_api.c b/src/iperf_api.c index 1c8a973..62f37f8 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -199,7 +199,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) }; char ch; - while ((ch = getopt_long(argc, argv, "c:p:st:uP:B:b:l:w:i:n:mRNTvh6VdM:f:", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "c:p:st:uP:B:b:l:w:i:n:mRS:NTvh6VdM:f:", longopts, NULL)) != -1) { switch (ch) { case 'c': if (test->role == 's') { @@ -346,6 +346,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) } test->reverse = 1; break; + case 'S': + if (test->role == 's') { + i_errno = IECLIENTONLY; + return (-1); + } + // XXX: Checking for errors in strtol is not portable. Leave as is? + test->settings->tos = strtol(optarg, NULL, 0); + break; case 'v': printf(version); exit(0); @@ -556,6 +564,11 @@ package_parameters(struct iperf_test *test) strncat(pstring, optbuf, sizeof(pstring)); } + if (test->settings->tos) { + snprintf(optbuf, sizeof(optbuf), "-S %d ", test->settings->tos); + strncat(pstring, optbuf, sizeof(pstring)); + } + *pstring = (char) (strlen(pstring) - 1); if (Nwrite(test->ctrl_sck, pstring, strlen(pstring), Ptcp) < 0) { @@ -597,7 +610,7 @@ parse_parameters(struct iperf_test *test) } // XXX: Should we check for parameters exceeding maximum values here? - while ((ch = getopt(n, params, "pt:n:m:uNP:Rw:l:b:")) != -1) { + while ((ch = getopt(n, params, "pt:n:m:uNP:Rw:l:b:S:")) != -1) { switch (ch) { case 'p': set_protocol(test, Ptcp); @@ -632,6 +645,9 @@ parse_parameters(struct iperf_test *test) case 'b': test->settings->rate = atoll(optarg); break; + case 'S': + test->settings->tos = atoi(optarg); + break; } } #ifdef __APPLE__ @@ -697,7 +713,6 @@ iperf_exchange_results(struct iperf_test *test) /* Prepare results string and send to server */ results = NULL; size = 0; -// for (sp = test->streams; sp; sp = sp->next) { SLIST_FOREACH(sp, &test->streams, streams) { bytes_transferred = (test->reverse ? sp->result->bytes_received : sp->result->bytes_sent); snprintf(buf, 128, "%d:%llu,%lf,%d,%d\n", sp->id, bytes_transferred,sp->jitter, @@ -771,7 +786,6 @@ iperf_exchange_results(struct iperf_test *test) /* Prepare results string and send to client */ results = NULL; size = 0; -// for (sp = test->streams; sp; sp = sp->next) { SLIST_FOREACH(sp, &test->streams, streams) { bytes_transferred = (test->reverse ? sp->result->bytes_sent : sp->result->bytes_received); snprintf(buf, 128, "%d:%llu,%lf,%d,%d\n", sp->id, bytes_transferred, sp->jitter, @@ -1342,9 +1356,10 @@ iperf_new_stream(struct iperf_test *test, int s) /**************************************************************************/ int -iperf_init_stream(struct iperf_stream * sp, struct iperf_test * testp) +iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) { socklen_t len; + int opt; len = sizeof(struct sockaddr_storage); if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) { @@ -1356,6 +1371,20 @@ iperf_init_stream(struct iperf_stream * sp, struct iperf_test * testp) i_errno = IEINITSTREAM; return (-1); } + /* Set IP TOS */ + if ((opt = test->settings->tos)) { + if (test->settings->domain == AF_INET6) { + if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) { + i_errno = IESETCOS; + return (-1); + } + } else { + if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) { + i_errno = IESETTOS; + return (-1); + } + } + } return (0); } @@ -1382,7 +1411,6 @@ iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp) } } - void sig_handler(int sig) { diff --git a/src/iperf_api.h b/src/iperf_api.h index 5bdc771..60ac67e 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -81,7 +81,7 @@ void iperf_add_stream(struct iperf_test * test, struct iperf_stream * strea * iperf_init_stream -- init resources associated with test * */ -int iperf_init_stream(struct iperf_stream * sp, struct iperf_test * testp); +int iperf_init_stream(struct iperf_stream *, struct iperf_test *); /** * iperf_free_stream -- free resources associated with test diff --git a/src/iperf_error.c b/src/iperf_error.c index d4aeb64..e5a8238 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -131,7 +131,7 @@ iperf_strerror(int i_errno) snprintf(errstr, len, "The server has terminated"); break; case IEACCESSDENIED: - snprintf(errstr, len, "The server is busy running a test. try again later."); + snprintf(errstr, len, "The server is busy running a test. try again later"); break; case IESETNODELAY: snprintf(errstr, len, "Unable to set TCP NODELAY"); @@ -145,6 +145,14 @@ iperf_strerror(int i_errno) snprintf(errstr, len, "Unable to set socket buffer size"); perr = 1; break; + case IESETTOS: + snprintf(errstr, len, "Unable to set IP TOS"); + perr = 1; + break; + case IESETCOS: + snprintf(errstr, len, "Unable to set IPv6 traffic class"); + perr = 1; + break; case IEREUSEADDR: snprintf(errstr, len, "Unable to reuse address on socket"); perr = 1; diff --git a/src/iperf_error.h b/src/iperf_error.h index 04a645a..57c9546 100644 --- a/src/iperf_error.h +++ b/src/iperf_error.h @@ -52,25 +52,27 @@ enum { IESETNODELAY = 32, // Unable to set TCP NODELAY (check perror) IESETMSS = 33, // Unable to set TCP MSS (check perror) IESETBUF = 34, // Unable to set socket buffer size (check perror) - IEREUSEADDR = 35, // Unable to set reuse address on socket (check perror) - IENONBLOCKING = 36, // Unable to set socket to non-blocking (check perror) - IESETWINDOWSIZE = 37, // Unable to set socket window size (check perror) - IEPROTOCOL = 38, // Protocol does not exist + IESETTOS = 35, // Unable to set IP TOS (check perror) + IESETCOS = 36, // Unable to set IPv6 traffic class (check perror) + IEREUSEADDR = 37, // Unable to set reuse address on socket (check perror) + IENONBLOCKING = 38, // Unable to set socket to non-blocking (check perror) + IESETWINDOWSIZE = 39, // Unable to set socket window size (check perror) + IEPROTOCOL = 40, // Protocol does not exist /* Stream errors */ - IECREATESTREAM = 39, // Unable to create a new stream (check herror/perror) - IEINITSTREAM = 40, // Unable to initialize stream (check herror/perror) - IESTREAMLISTEN = 41, // Unable to start stream listener (check perror) - IESTREAMCONNECT = 42, // Unable to connect stream (check herror/perror) - IESTREAMACCEPT = 43, // Unable to accepte stream connection (check perror) - IESTREAMWRITE = 44, // Unable to write to stream socket (check perror) - IESTREAMREAD = 45, // Unable to read from stream (check perror) - IESTREAMCLOSE = 46, // Stream has closed unexpectedly - IESTREAMID = 47, // Stream has invalid ID + IECREATESTREAM = 41, // Unable to create a new stream (check herror/perror) + IEINITSTREAM = 42, // Unable to initialize stream (check herror/perror) + IESTREAMLISTEN = 43, // Unable to start stream listener (check perror) + IESTREAMCONNECT = 44, // Unable to connect stream (check herror/perror) + IESTREAMACCEPT = 45, // Unable to accepte stream connection (check perror) + IESTREAMWRITE = 46, // Unable to write to stream socket (check perror) + IESTREAMREAD = 47, // Unable to read from stream (check perror) + IESTREAMCLOSE = 48, // Stream has closed unexpectedly + IESTREAMID = 49, // Stream has invalid ID /* Timer errors */ - IENEWTIMER = 48, // Unable to create new timer (check perror) - IEUPDATETIMER = 49, // Unable to update timer (check perror) + IENEWTIMER = 50, // Unable to create new timer (check perror) + IEUPDATETIMER = 51, // Unable to update timer (check perror) }; #endif