diff options
author | Jef Poskanzer <jef@mail.acme.com> | 2013-07-03 12:01:57 -0700 |
---|---|---|
committer | Jef Poskanzer <jef@mail.acme.com> | 2013-07-03 12:01:57 -0700 |
commit | c9693599958d82fba625e8facd8d4a92e0cc73ce (patch) | |
tree | ed8ca8fd1bc2fd09edd5d0ab609099be4121a937 | |
parent | 434e786fd065e8aee6d78adaf6ebcdc6909195d1 (diff) | |
download | iperf3-c9693599958d82fba625e8facd8d4a92e0cc73ce.tar.gz |
Added -I flag to ignore an initial period of data transfer,
defaulting to one second.
-rw-r--r-- | src/iperf.h | 5 | ||||
-rw-r--r-- | src/iperf3.1 | 5 | ||||
-rw-r--r-- | src/iperf_api.c | 197 | ||||
-rw-r--r-- | src/iperf_api.h | 12 | ||||
-rw-r--r-- | src/iperf_client_api.c | 147 | ||||
-rw-r--r-- | src/iperf_error.c | 3 | ||||
-rw-r--r-- | src/iperf_server_api.c | 105 | ||||
-rw-r--r-- | src/iperf_udp.c | 4 | ||||
-rw-r--r-- | src/locale.c | 5 | ||||
-rw-r--r-- | src/version.h | 4 |
10 files changed, 330 insertions, 157 deletions
diff --git a/src/iperf.h b/src/iperf.h index 808b6e4..00ae116 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -94,6 +94,7 @@ struct iperf_stream * stream can have a pointer to this */ int packet_count; + int ignored_packet_count; double jitter; double prev_transit; int outoforder_packets; @@ -134,6 +135,7 @@ struct iperf_test char *server_hostname; /* -c option */ char *bind_address; /* -B option */ int server_port; + int ignore; /* duration of ignore period (-I flag) */ int duration; /* total duration of test (-t flag) */ int ctrl_sck; @@ -159,10 +161,12 @@ struct iperf_test fd_set write_set; /* set of write sockets */ /* Interval related members */ + int ignoring; double stats_interval; double reporter_interval; void (*stats_callback) (struct iperf_test *); void (*reporter_callback) (struct iperf_test *); + Timer *ignore_timer; Timer *timer; int done; Timer *stats_timer; @@ -199,6 +203,7 @@ struct iperf_test #define uS_TO_NS 1000 #define SEC_TO_US 1000000LL #define UDP_RATE (1024 * 1024) /* 1 Mbps */ +#define IGNORE 1 /* seconds */ #define DURATION 10 /* seconds */ #define SEC_TO_NS 1000000000LL /* too big for enum/const on some platforms */ diff --git a/src/iperf3.1 b/src/iperf3.1 index 62aa9bc..e3c7030 100644 --- a/src/iperf3.1 +++ b/src/iperf3.1 @@ -103,6 +103,11 @@ set the IP 'type of service' .BR -Z ", " --zerocopy " " Use a "zero copy" method of sending data, such as sendfile(2), instead of the usual write(2). +.TP +.BR -I ", " --ignore " \fIn\fR" +Ignore the first n seconds of the test, to skip past the TCP slow-start +period. +The default is 1 second; to not ignore anything, use "-I 0". .SH AUTHORS Iperf was originally written by Mark Gates and Alex Warshavsky. diff --git a/src/iperf_api.c b/src/iperf_api.c index a8776ba..25a4997 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -87,6 +87,12 @@ iperf_get_control_socket(struct iperf_test *ipt) } int +iperf_get_test_ignore(struct iperf_test *ipt) +{ + return ipt->ignore; +} + +int iperf_get_test_duration(struct iperf_test *ipt) { return ipt->duration; @@ -179,6 +185,12 @@ iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck) } void +iperf_set_test_ignore(struct iperf_test *ipt, int ignore) +{ + ipt->ignore = ignore; +} + +void iperf_set_test_duration(struct iperf_test *ipt, int duration) { ipt->duration = duration; @@ -317,15 +329,15 @@ iperf_on_test_start(struct iperf_test *test) { if (test->json_output) { if (test->settings->bytes) - cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d bytes: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->settings->bytes)); + cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d ignore: %d bytes: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->ignore, (int64_t) test->settings->bytes)); else - cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d duration: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->duration)); + cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d ignore: %d duration: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->ignore, (int64_t) test->duration)); } else { if (test->verbose) { if (test->settings->bytes) - printf(test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->settings->bytes); + printf(test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->ignore, test->settings->bytes); else - printf(test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->duration); + printf(test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->ignore, test->duration); } } } @@ -450,6 +462,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"tos", required_argument, NULL, 'S'}, {"flowlabel", required_argument, NULL, 'L'}, {"zerocopy", no_argument, NULL, 'Z'}, + {"ignore", required_argument, NULL, 'I'}, {"help", no_argument, NULL, 'h'}, /* XXX: The following ifdef needs to be split up. linux-congestion is not @@ -466,7 +479,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) blksize = 0; server_flag = client_flag = rate_flag = 0; - while ((flag = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N46S:L:Zh", longopts, NULL)) != -1) { + while ((flag = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N46S:L:ZI:h", longopts, NULL)) != -1) { switch (flag) { case 'p': test->server_port = atoi(optarg); @@ -498,7 +511,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) test->debug = 1; break; case 'v': - fputs(version, stdout); + printf("%s\n", version); system("uname -a"); exit(0); case 's': @@ -612,6 +625,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) test->zerocopy = 1; client_flag = 1; break; + case 'I': + test->ignore = atoi(optarg); + if (test->ignore < 0 || test->ignore > 60) { + i_errno = IEIGNORE; + return -1; + } + client_flag = 1; + break; case 'h': default: usage_long(); @@ -662,8 +683,19 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return 0; } -static void -check_throttle(struct iperf_stream *sp, struct timeval *nowP) +int +iperf_set_send_state(struct iperf_test *test, char state) +{ + test->state = state; + if (Nwrite(test->ctrl_sck, &state, sizeof(state), Ptcp) < 0) { + i_errno = IESENDMESSAGE; + return -1; + } + return 0; +} + +void +iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP) { double seconds; uint64_t bits_per_second; @@ -703,7 +735,7 @@ iperf_send(struct iperf_test *test, fd_set *write_setP) } test->bytes_sent += r; if (test->settings->rate != 0) - check_throttle(sp, &now); + iperf_check_throttle(sp, &now); if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) break; } @@ -737,104 +769,24 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP) return 0; } -static void -test_timer_proc(TimerClientData client_data, struct timeval *nowP) -{ - struct iperf_test *test = client_data.p; - - test->done = 1; - test->timer = NULL; -} - -static void -stats_timer_proc(TimerClientData client_data, struct timeval *nowP) -{ - struct iperf_test *test = client_data.p; - - if (test->done) - return; - test->stats_callback(test); -} - -static void -reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) -{ - struct iperf_test *test = client_data.p; - - if (test->done) - return; - test->reporter_callback(test); -} - -static void -send_timer_proc(TimerClientData client_data, struct timeval *nowP) -{ - struct iperf_stream *sp = client_data.p; - - /* All we do here is set or clear the flag saying that this stream may - ** be sent to. The actual sending gets done in the send proc, after - ** checking the flag. - */ - check_throttle(sp, nowP); -} - int iperf_init_test(struct iperf_test *test) { - struct iperf_stream *sp; struct timeval now; - TimerClientData cd; + struct iperf_stream *sp; if (test->protocol->init) { if (test->protocol->init(test) < 0) return -1; } - /* Create timers. */ + /* Init each stream. */ if (gettimeofday(&now, NULL) < 0) { - i_errno = IEINITTEST; - return -1; - } - if (test->settings->bytes == 0) { - test->done = 0; - cd.p = test; - test->timer = tmr_create(&now, test_timer_proc, cd, test->duration * SEC_TO_US, 0); - if (test->timer == NULL) { - i_errno = IEINITTEST; - return -1; - } - } - - if (test->stats_interval != 0) { - cd.p = test; - test->stats_timer = tmr_create(&now, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); - if (test->stats_timer == NULL) { - i_errno = IEINITTEST; - return -1; - } - } - if (test->reporter_interval != 0) { - cd.p = test; - test->reporter_timer = tmr_create(&now, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); - if (test->reporter_timer == NULL) { - i_errno = IEINITTEST; - return -1; - } + i_errno = IEINITTEST; + return -1; } - - /* Init each stream. */ SLIST_FOREACH(sp, &test->streams, streams) { sp->result->start_time = now; - sp->green_light = 1; - if (test->settings->rate != 0) { - cd.p = sp; - sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1); - /* (Repeat every tenth second - arbitrary often value.) */ - if (sp->send_timer == NULL) { - i_errno = IEINITTEST; - return -1; - } - } } if (test->on_test_start) @@ -852,7 +804,6 @@ int iperf_exchange_parameters(struct iperf_test *test) { int s, msg; - char state; if (test->role == 'c') { @@ -865,11 +816,8 @@ iperf_exchange_parameters(struct iperf_test *test) return -1; if ((s = test->protocol->listen(test)) < 0) { - state = SERVER_ERROR; - if (Nwrite(test->ctrl_sck, &state, sizeof(state), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, SERVER_ERROR) != 0) return -1; - } msg = htonl(i_errno); if (Nwrite(test->ctrl_sck, (char*) &msg, sizeof(msg), Ptcp) < 0) { i_errno = IECTRLWRITE; @@ -887,11 +835,8 @@ iperf_exchange_parameters(struct iperf_test *test) test->prot_listener = s; // Send the control message to create streams and start the test - test->state = CREATE_STREAMS; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, CREATE_STREAMS) != 0) return -1; - } } @@ -953,6 +898,8 @@ send_parameters(struct iperf_test *test) cJSON_AddTrueToObject(j, "tcp"); else if (test->protocol->id == Pudp) cJSON_AddTrueToObject(j, "udp"); + if (test->ignore) + cJSON_AddIntToObject(j, "ignore", test->ignore); if (test->duration) cJSON_AddIntToObject(j, "time", test->duration); if (test->settings->bytes) @@ -1001,6 +948,8 @@ get_parameters(struct iperf_test *test) set_protocol(test, Ptcp); if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL) set_protocol(test, Pudp); + if ((j_p = cJSON_GetObjectItem(j, "ignore")) != NULL) + test->ignore = j_p->valueint; if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL) test->duration = j_p->valueint; if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL) @@ -1313,6 +1262,7 @@ iperf_defaults(struct iperf_test *testp) { struct protocol *tcp, *udp; + testp->ignore = IGNORE; testp->duration = DURATION; testp->server_port = PORT; testp->ctrl_sck = -1; @@ -1398,6 +1348,8 @@ iperf_free_test(struct iperf_test *test) free(test->server_hostname); free(test->bind_address); free(test->settings); + if (test->ignore_timer != NULL) + tmr_cancel(test->ignore_timer); if (test->timer != NULL) tmr_cancel(test->timer); if (test->stats_timer != NULL) @@ -1431,6 +1383,10 @@ iperf_reset_test(struct iperf_test *test) SLIST_REMOVE_HEAD(&test->streams, streams); iperf_free_stream(sp); } + if (test->ignore_timer != NULL) { + tmr_cancel(test->ignore_timer); + test->ignore_timer = NULL; + } if (test->timer != NULL) { tmr_cancel(test->timer); test->timer = NULL; @@ -1450,6 +1406,7 @@ iperf_reset_test(struct iperf_test *test) test->sender = 0; test->sender_has_retransmits = 0; set_protocol(test, Ptcp); + test->ignore = IGNORE; test->duration = DURATION; test->state = 0; test->server_hostname = NULL; @@ -1475,6 +1432,32 @@ iperf_reset_test(struct iperf_test *test) } +/* Reset all of a test's stats back to zero. Called when the ignoring +** period is over. +*/ +void +iperf_reset_stats(struct iperf_test *test) +{ + struct timeval now; + struct iperf_stream *sp; + struct iperf_stream_result *rp; + + test->bytes_sent = 0; + gettimeofday(&now, NULL); + SLIST_FOREACH(sp, &test->streams, streams) { + sp->ignored_packet_count = sp->packet_count; + sp->jitter = 0; + sp->outoforder_packets = 0; + sp->cnt_error = 0; + rp = sp->result; + rp->bytes_sent = rp->bytes_received = 0; + rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0; + rp->retransmits = 0; + rp->start_time = now; + } +} + + /**************************************************************************/ /** @@ -1649,7 +1632,7 @@ iperf_print_results(struct iperf_test *test) if (test->sender_has_retransmits) total_retransmits += sp->result->retransmits; } else { - total_packets += sp->packet_count; + total_packets += (sp->packet_count - sp->ignored_packet_count); lost_packets += sp->cnt_error; avg_jitter += sp->jitter; } @@ -1673,13 +1656,13 @@ iperf_print_results(struct iperf_test *test) printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); } } else { - out_of_order_percent = 100.0 * sp->cnt_error / sp->packet_count; + out_of_order_percent = 100.0 * sp->cnt_error / (sp->packet_count - sp->ignored_packet_count); if (test->json_output) - 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 outoforder: %d packets: %d percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) sp->packet_count, out_of_order_percent)); + 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 outoforder: %d packets: %d percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) (sp->packet_count - sp->ignored_packet_count), out_of_order_percent)); else { - printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, sp->packet_count, out_of_order_percent); + printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, (sp->packet_count - sp->ignored_packet_count), out_of_order_percent); if (test->role == 'c') - printf(report_datagrams, sp->socket, sp->packet_count); + printf(report_datagrams, sp->socket, (sp->packet_count - sp->ignored_packet_count)); if (sp->outoforder_packets > 0) printf(report_sum_outoforder, start_time, end_time, sp->cnt_error); } diff --git a/src/iperf_api.h b/src/iperf_api.h index 418eebc..883ca9f 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -45,6 +45,7 @@ struct iperf_stream; /* Getter routines for some fields inside iperf_test. */ int iperf_get_control_socket( struct iperf_test* ipt ); +int iperf_get_test_ignore( struct iperf_test* ipt ); int iperf_get_test_duration( struct iperf_test* ipt ); char iperf_get_test_role( struct iperf_test* ipt ); int iperf_get_test_blksize( struct iperf_test* ipt ); @@ -62,6 +63,7 @@ int iperf_get_test_may_use_sigalrm( struct iperf_test* ipt ); /* Setter routines for some fields inside iperf_test. */ void iperf_set_control_socket( struct iperf_test* ipt, int ctrl_sck ); +void iperf_set_test_ignore( struct iperf_test* ipt, int ignore ); void iperf_set_test_duration( struct iperf_test* ipt, int duration ); void iperf_set_test_reporter_interval( struct iperf_test* ipt, double reporter_interval ); void iperf_set_test_stats_interval( struct iperf_test* ipt, double stats_interval ); @@ -103,14 +105,12 @@ void connect_msg(struct iperf_stream * sp); */ void iperf_stats_callback(struct iperf_test * test); - /** * iperf_reporter_callback -- handles the report printing * */ void iperf_reporter_callback(struct iperf_test * test); - /** * iperf_new_test -- return a new iperf_test with default values * @@ -121,7 +121,6 @@ struct iperf_test *iperf_new_test(); int iperf_defaults(struct iperf_test * testp); - /** * iperf_free_test -- free resources used by test, calls iperf_free_stream to * free streams @@ -129,7 +128,6 @@ int iperf_defaults(struct iperf_test * testp); */ void iperf_free_test(struct iperf_test * testp); - /** * iperf_new_stream -- return a net iperf_stream with default values * @@ -163,6 +161,8 @@ long get_tcpinfo_total_retransmits(struct iperf_interval_results *irp); void print_tcpinfo(struct iperf_test *test); void build_tcpinfo_message(struct iperf_interval_results *r, char *message); +int iperf_set_send_state(struct iperf_test *test, char state); +void iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP); int iperf_send(struct iperf_test *, fd_set *) /* __attribute__((hot)) */; int iperf_recv(struct iperf_test *, fd_set *); void sig_handler(int); @@ -174,6 +174,7 @@ int iperf_exchange_results(struct iperf_test *); int iperf_init_test(struct iperf_test *); int iperf_parse_arguments(struct iperf_test *, int, char **); void iperf_reset_test(struct iperf_test *); +void iperf_reset_stats(struct iperf_test * test); struct protocol *get_protocol(struct iperf_test *, int); int set_protocol(struct iperf_test *, int); @@ -222,7 +223,8 @@ enum { IEINTERVAL = 9, // Report interval too large. Maxumum value = %dMAX_INTERVAL IEMSS = 10, // MSS too large. Maximum value = %dMAX_MSS IENOSENDFILE = 11, // This OS does not support sendfile - IEUNIMP = 12, // Not implemented yet + IEIGNORE = 12, // Bogus value for --ignore + IEUNIMP = 13, // Not implemented yet /* Test errors */ IENEWTEST = 100, // Unable to create a new test (check perror) IEINITTEST = 101, // Test initialization failed (check perror) diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index dc20e34..9ac8ffd 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -54,6 +54,133 @@ iperf_create_streams(struct iperf_test *test) return 0; } +static void +test_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + + test->timer = NULL; + test->done = 1; +} + +static void +stats_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + + if (test->done) + return; + test->stats_callback(test); +} + +static void +reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + + if (test->done) + return; + test->reporter_callback(test); +} + +static void +client_ignore_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + TimerClientData cd; + + test->ignore_timer = NULL; + test->ignoring = 0; + iperf_reset_stats(test); + if (test->verbose && !test->json_output) + printf("Finished ignore period, starting real test\n"); + + /* Create timers. */ + if (test->settings->bytes == 0) { + test->done = 0; + cd.p = test; + test->timer = tmr_create(nowP, test_timer_proc, cd, test->duration * SEC_TO_US, 0); + if (test->timer == NULL) { + i_errno = IEINITTEST; + return; + } + } + if (test->stats_interval != 0) { + cd.p = test; + test->stats_timer = tmr_create(nowP, stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); + if (test->stats_timer == NULL) { + i_errno = IEINITTEST; + return; + } + } + if (test->reporter_interval != 0) { + cd.p = test; + test->reporter_timer = tmr_create(nowP, reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); + if (test->reporter_timer == NULL) { + i_errno = IEINITTEST; + return; + } + } +} + +static int +create_client_ignore_timer(struct iperf_test * test) +{ + struct timeval now; + TimerClientData cd; + + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } + test->ignoring = 1; + cd.p = test; + test->ignore_timer = tmr_create(&now, client_ignore_timer_proc, cd, test->ignore * SEC_TO_US, 0); + if (test->ignore_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + return 0; +} + +static void +send_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_stream *sp = client_data.p; + + /* All we do here is set or clear the flag saying that this stream may + ** be sent to. The actual sending gets done in the send proc, after + ** checking the flag. + */ + iperf_check_throttle(sp, nowP); +} + +static int +create_send_timers(struct iperf_test * test) +{ + struct timeval now; + struct iperf_stream *sp; + TimerClientData cd; + + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } + SLIST_FOREACH(sp, &test->streams, streams) { + sp->green_light = 1; + if (test->settings->rate != 0) { + cd.p = sp; + sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1); + /* (Repeat every tenth second - arbitrary often value.) */ + if (sp->send_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + } + } + return 0; +} + int iperf_handle_message_client(struct iperf_test *test) { @@ -83,6 +210,10 @@ iperf_handle_message_client(struct iperf_test *test) case TEST_START: if (iperf_init_test(test) < 0) return -1; + if (create_client_ignore_timer(test) < 0) + return -1; + if (create_send_timers(test) < 0) + return -1; break; case TEST_RUNNING: break; @@ -170,11 +301,8 @@ iperf_client_end(struct iperf_test *test) /* show final summary */ test->reporter_callback(test); - test->state = IPERF_DONE; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, IPERF_DONE) != 0) return -1; - } return 0; } @@ -245,8 +373,8 @@ iperf_run_client(struct iperf_test * test) if (test->state == TEST_RUNNING) { - /* Is this our first time in TEST_RUNNING mode? */ - if (startup) { + /* Is this our first time really running? */ + if (startup && ! test->ignoring) { startup = 0; /* Can we switch to SIGALRM mode? There are a bunch of ** cases where either it won't work or it's ill-advised. @@ -287,6 +415,8 @@ iperf_run_client(struct iperf_test * test) } /* Is the test done yet? */ + if (test->ignoring) + continue; /* not done */ if (test->settings->bytes == 0) { if (!test->done) continue; /* not done */ @@ -297,11 +427,8 @@ iperf_run_client(struct iperf_test * test) /* Yes, done! Send TEST_END. */ cpu_util(&test->cpu_util); test->stats_callback(test); - test->state = TEST_END; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, TEST_END) != 0) return -1; - } /* And if we were doing SIGALRM, go back to select for the end. */ concurrency_model = CM_SELECT; } diff --git a/src/iperf_error.c b/src/iperf_error.c index c5d9910..ba0ad50 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -99,6 +99,9 @@ iperf_strerror(int i_errno) case IENOSENDFILE: snprintf(errstr, len, "this OS does not support sendfile"); break; + case IEIGNORE: + snprintf(errstr, len, "bogus value for --ignore"); + break; case IEUNIMP: snprintf(errstr, len, "an option you are trying to set is not implemented yet"); break; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index f8743fa..0ac42a8 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -121,11 +121,8 @@ iperf_accept(struct iperf_test *test) test->max_fd = (s > test->max_fd) ? s : test->max_fd; test->ctrl_sck = s; - test->state = PARAM_EXCHANGE; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0) return -1; - } if (iperf_exchange_parameters(test) < 0) { return -1; } @@ -180,20 +177,14 @@ iperf_handle_message_server(struct iperf_test *test) FD_CLR(sp->socket, &test->write_set); close(sp->socket); } - test->state = EXCHANGE_RESULTS; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) return -1; - } if (iperf_sum_results(test) < 0) return -1; if (iperf_exchange_results(test) < 0) return -1; - test->state = DISPLAY_RESULTS; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0) return -1; - } if (test->on_test_finish) test->on_test_finish(test); test->reporter_callback(test); @@ -251,6 +242,7 @@ iperf_test_reset(struct iperf_test *test) test->role = 's'; set_protocol(test, Ptcp); + test->ignore = IGNORE; test->duration = DURATION; test->state = 0; test->server_hostname = NULL; @@ -278,6 +270,46 @@ iperf_test_reset(struct iperf_test *test) memset(test->cookie, 0, COOKIE_SIZE); } +static void +server_ignore_timer_proc(TimerClientData client_data, struct timeval *nowP) +{ + struct iperf_test *test = client_data.p; + + test->ignore_timer = NULL; + test->ignoring = 0; + iperf_reset_stats(test); + if (test->verbose && !test->json_output) + printf("Finished ignore period, starting real test\n"); +} + +static int +create_server_ignore_timer(struct iperf_test * test) +{ + struct timeval now; + TimerClientData cd; + + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } + test->ignoring = 1; + cd.p = test; + test->ignore_timer = tmr_create(&now, server_ignore_timer_proc, cd, test->ignore * SEC_TO_US, 0); + if (test->ignore_timer == NULL) { + i_errno = IEINITTEST; + return -1; + } + return 0; +} + +static void +cleanup_server(struct iperf_test *test) +{ + /* Close open test sockets */ + close(test->ctrl_sck); + close(test->listener); +} + int iperf_run_server(struct iperf_test *test) { @@ -317,6 +349,7 @@ iperf_run_server(struct iperf_test *test) result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now)); if (result < 0 && errno != EINTR) { + cleanup_server(test); i_errno = IESELECT; return -1; } @@ -324,27 +357,34 @@ 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; } FD_CLR(test->listener, &read_set); } } if (FD_ISSET(test->ctrl_sck, &read_set)) { - if (iperf_handle_message_server(test) < 0) + if (iperf_handle_message_server(test) < 0) { + cleanup_server(test); return -1; + } FD_CLR(test->ctrl_sck, &read_set); } if (test->state == CREATE_STREAMS) { if (FD_ISSET(test->prot_listener, &read_set)) { - if ((s = test->protocol->accept(test)) < 0) + if ((s = test->protocol->accept(test)) < 0) { + cleanup_server(test); return -1; + } if (!is_closed(s)) { sp = iperf_new_stream(test, s); - if (!sp) + if (!sp) { + cleanup_server(test); return -1; + } FD_SET(s, &test->read_set); FD_SET(s, &test->write_set); @@ -366,6 +406,7 @@ iperf_run_server(struct iperf_test *test) FD_CLR(test->listener, &test->read_set); close(test->listener); if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { + cleanup_server(test); i_errno = IELISTEN; return -1; } @@ -375,30 +416,38 @@ iperf_run_server(struct iperf_test *test) } } test->prot_listener = -1; - test->state = TEST_START; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + if (iperf_set_send_state(test, TEST_START) != 0) { + cleanup_server(test); return -1; - } - if (iperf_init_test(test) < 0) + } + if (iperf_init_test(test) < 0) { + cleanup_server(test); return -1; - test->state = TEST_RUNNING; - if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { - i_errno = IESENDMESSAGE; + } + if (create_server_ignore_timer(test) < 0) { + cleanup_server(test); return -1; - } + } + if (iperf_set_send_state(test, TEST_RUNNING) != 0) { + cleanup_server(test); + return -1; + } } } if (test->state == TEST_RUNNING) { if (test->reverse) { // Reverse mode. Server sends. - if (iperf_send(test, &write_set) < 0) + if (iperf_send(test, &write_set) < 0) { + cleanup_server(test); return -1; + } } else { // Regular mode. Server receives. - if (iperf_recv(test, &read_set) < 0) + if (iperf_recv(test, &read_set) < 0) { + cleanup_server(test); return -1; + } } /* Run the timers. */ @@ -408,9 +457,7 @@ iperf_run_server(struct iperf_test *test) } } - /* Close open test sockets */ - close(test->ctrl_sck); - close(test->listener); + cleanup_server(test); if (test->json_output) { if (iperf_json_finish(test) < 0) diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 0d39890..00f02ed 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -37,7 +37,7 @@ iperf_udp_recv(struct iperf_stream *sp) { int r; int size = sp->settings->blksize; - int sec, usec, pcount; + uint32_t sec, usec, pcount; double transit = 0, d = 0; struct timeval sent_time, arrival_time; @@ -93,7 +93,7 @@ int iperf_udp_send(struct iperf_stream *sp) { int r; - uint64_t sec, usec, pcount; + uint32_t sec, usec, pcount; int size = sp->settings->blksize; struct timeval before; diff --git a/src/locale.c b/src/locale.c index cee3aa4..ccad751 100644 --- a/src/locale.c +++ b/src/locale.c @@ -99,6 +99,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n" " -S, --tos N set the IP 'type of service'\n" /* " -L, --flowlabel N set the IPv6 'flow label'\n" */ " -Z, --zerocopy use a 'zero copy' method of sending data\n" + " -I, --ignore N ignore the first n seconds\n" #ifdef NOT_YET_SUPPORTED /* still working on these */ " -D, --daemon run the server as a daemon\n" @@ -163,10 +164,10 @@ const char wait_server_threads[] = "Waiting for server threads to complete. Interrupt again to force quit.\n"; const char test_start_time[] = -"Starting Test: protocol: %s, %d streams, %d byte blocks, %d second test\n"; +"Starting Test: protocol: %s, %d streams, %d byte blocks, ignoring %d seconds, %d second test\n"; const char test_start_bytes[] = -"Starting Test: protocol: %s, %d streams, %d byte blocks, %llu bytes to send\n"; +"Starting Test: protocol: %s, %d streams, %d byte blocks, ignoring %d seconds, %llu bytes to send\n"; /* ------------------------------------------------------------------- diff --git a/src/version.h b/src/version.h index c8dfcbc..4a51b0e 100644 --- a/src/version.h +++ b/src/version.h @@ -7,5 +7,5 @@ * for complete information. */ -#define IPERF_VERSION "3.0-BETA5" -#define IPERF_VERSION_DATE "28 March 2013" +#define IPERF_VERSION "3.0-BETA6" +#define IPERF_VERSION_DATE "27 June 2013" |