Added -I flag to ignore an initial period of data transfer,

defaulting to one second.
This commit is contained in:
Jef Poskanzer 2013-07-03 12:01:57 -07:00
parent 434e786fd0
commit c969359995
10 changed files with 331 additions and 158 deletions

View File

@ -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 */

View File

@ -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.

View File

@ -86,6 +86,12 @@ iperf_get_control_socket(struct iperf_test *ipt)
return ipt->ctrl_sck;
}
int
iperf_get_test_ignore(struct iperf_test *ipt)
{
return ipt->ignore;
}
int
iperf_get_test_duration(struct iperf_test *ipt)
{
@ -178,6 +184,12 @@ iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
ipt->ctrl_sck = 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)
{
@ -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. */
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;
}
}
/* Init each stream. */
if (gettimeofday(&now, NULL) < 0) {
i_errno = IEINITTEST;
return -1;
}
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);
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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";
/* -------------------------------------------------------------------

View File

@ -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"