diff --git a/src/iperf.h b/src/iperf.h index c9b2423..e2970c2 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -26,10 +26,9 @@ struct iperf_interval_results struct timeval interval_end_time; float interval_duration; #if defined(linux) || defined(__FreeBSD__) - struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) results here for - * Linux and FreeBSD stored here */ + struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) for Linux and FreeBSD */ #else - char *tcpInfo; /* just a placeholder */ + char *tcpInfo; /* just a placeholder */ #endif TAILQ_ENTRY(iperf_interval_results) irlistentries; void *custom_data; @@ -134,7 +133,6 @@ struct iperf_test int no_delay; /* -N option */ int output_format; /* -O option */ int reverse; /* -R option */ - int tcp_info; /* -T option - display getsockopt(TCP_INFO) results. */ int v6domain; /* -6 option */ int verbose; /* -V option - verbose mode */ diff --git a/src/iperf_api.c b/src/iperf_api.c index d93e515..6cee2b2 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -332,7 +332,6 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"parallel", required_argument, NULL, 'P'}, {"udp", no_argument, NULL, 'u'}, {"bind", required_argument, NULL, 'B'}, - {"tcpInfo", no_argument, NULL, 'T'}, {"bandwidth", required_argument, NULL, 'b'}, {"length", required_argument, NULL, 'l'}, {"window", required_argument, NULL, 'w'}, @@ -360,7 +359,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:RS:NTvh6VdM:f:", longopts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "c:p:st:uP:B:b:l:w:i:n:RS:Nvh6VdM:f:", longopts, NULL)) != -1) { switch (ch) { case 'c': if (test->role == 's') { @@ -488,14 +487,6 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'f': test->settings->unit_format = *optarg; break; - case 'T': -#if !defined(linux) && !defined(__FreeBSD__) - // XXX: Should check to make sure UDP mode isn't set! - warning("TCP_INFO (-T) is not supported on your current platform"); -#else - test->tcp_info = 1; -#endif - break; case '6': test->settings->domain = AF_INET6; break; @@ -1029,11 +1020,11 @@ JSON_read(int fd) void add_to_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results * new) { - struct iperf_interval_results *ip = NULL; + struct iperf_interval_results *irp = NULL; - ip = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results)); - memcpy(ip, new, sizeof(struct iperf_interval_results)); - TAILQ_INSERT_TAIL(&rp->interval_results, ip, irlistentries); + irp = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results)); + memcpy(irp, new, sizeof(struct iperf_interval_results)); + TAILQ_INSERT_TAIL(&rp->interval_results, irp, irlistentries); } @@ -1255,7 +1246,7 @@ iperf_stats_callback(struct iperf_test * test) { struct iperf_stream *sp; struct iperf_stream_result *rp = NULL; - struct iperf_interval_results *ip = NULL, temp; + struct iperf_interval_results *irp = NULL, temp; SLIST_FOREACH(sp, &test->streams, streams) { rp = sp->result; @@ -1265,9 +1256,9 @@ iperf_stats_callback(struct iperf_test * test) else temp.bytes_transferred = rp->bytes_received_this_interval; - ip = TAILQ_FIRST(&rp->interval_results); + irp = TAILQ_FIRST(&rp->interval_results); /* result->end_time contains timestamp of previous interval */ - if ( ip != NULL ) /* not the 1st interval */ + if ( irp != NULL ) /* not the 1st interval */ memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct timeval)); else /* or use timestamp from beginning */ memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct timeval)); @@ -1276,8 +1267,8 @@ iperf_stats_callback(struct iperf_test * test) memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct timeval)); temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time); //temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time); - if (test->tcp_info) - get_tcpinfo(sp, &temp); + if (has_tcpinfo()) + save_tcpinfo(sp, &temp); add_to_interval_list(rp, &temp); rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0; } @@ -1289,13 +1280,17 @@ iperf_print_intermediate(struct iperf_test *test) char ubuf[UNIT_LEN]; char nbuf[UNIT_LEN]; struct iperf_stream *sp = NULL; + struct iperf_interval_results *irp; iperf_size_t bytes = 0; + long retransmits = 0; double start_time, end_time; - struct iperf_interval_results *ip = NULL; SLIST_FOREACH(sp, &test->streams, streams) { print_interval_results(test, sp); - bytes += TAILQ_LAST(&sp->result->interval_results, irlisthead)->bytes_transferred; /* sum up all streams */ + /* sum up all streams */ + irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); + bytes += irp->bytes_transferred; + retransmits += get_tcpinfo_retransmits(irp); } if (bytes <=0 ) { /* this can happen if timer goes off just when client exits */ fprintf(stderr, "error: bytes <= 0!\n"); @@ -1304,18 +1299,18 @@ iperf_print_intermediate(struct iperf_test *test) /* next build string with sum of all streams */ if (test->num_streams > 1) { sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */ - ip = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */ + irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */ unit_snprintf(ubuf, UNIT_LEN, (double) (bytes), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / ip->interval_duration), + unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / irp->interval_duration), test->settings->unit_format); - start_time = timeval_diff(&sp->result->start_time,&ip->interval_start_time); - end_time = timeval_diff(&sp->result->start_time,&ip->interval_end_time); - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); - } - if (test->tcp_info) { - print_tcpinfo(test); + start_time = timeval_diff(&sp->result->start_time,&irp->interval_start_time); + end_time = timeval_diff(&sp->result->start_time,&irp->interval_end_time); + if (has_tcpinfo_retransmits()) + printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits); + else + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); } } @@ -1323,17 +1318,24 @@ static void iperf_print_results (struct iperf_test *test) { + long retransmits = 0, total_retransmits = 0; int total_packets = 0, lost_packets = 0; char ubuf[UNIT_LEN]; char nbuf[UNIT_LEN]; struct iperf_stream *sp = NULL; - iperf_size_t bytes_sent = 0, bytes_received = 0; - iperf_size_t total_sent = 0, total_received = 0; + iperf_size_t bytes_sent, total_sent = 0; + iperf_size_t bytes_received, total_received = 0; double start_time, end_time, avg_jitter; /* print final summary for all intervals */ - printf(report_bw_header); + if (test->protocol->id == Ptcp) + if (has_tcpinfo_retransmits()) + printf(report_bw_retrans_header); + else + printf(report_bw_header); + else + printf(report_bw_udp_header); start_time = 0.; sp = SLIST_FIRST(&test->streams); @@ -1345,7 +1347,12 @@ iperf_print_results (struct iperf_test *test) total_sent += bytes_sent; total_received += bytes_received; - if (test->protocol->id == Pudp) { + if (test->protocol->id == Ptcp) { + if (has_tcpinfo_retransmits()) { + retransmits = get_tcpinfo_retransmits(TAILQ_LAST(&sp->result->interval_results, irlisthead)); + total_retransmits += retransmits; + } + } else { total_packets += sp->packet_count; lost_packets += sp->cnt_error; avg_jitter += sp->jitter; @@ -1356,9 +1363,12 @@ iperf_print_results (struct iperf_test *test) unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_sent / end_time), test->settings->unit_format); if (test->protocol->id == Ptcp) { printf(" Sent\n"); - printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + if (has_tcpinfo_retransmits()) + printf(report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, retransmits); + else + printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); } else { - printf(report_bw_jitter_loss_format, sp->socket, start_time, + printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000, sp->cnt_error, sp->packet_count, (double) (100.0 * sp->cnt_error / sp->packet_count)); if (test->role == 'c') { @@ -1373,7 +1383,7 @@ iperf_print_results (struct iperf_test *test) unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_received / end_time), test->settings->unit_format); if (test->protocol->id == Ptcp) { printf(" Received\n"); - printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); } } } @@ -1383,22 +1393,21 @@ iperf_print_results (struct iperf_test *test) unit_snprintf(nbuf, UNIT_LEN, (double) total_sent / end_time, test->settings->unit_format); if (test->protocol->id == Ptcp) { printf(" Total sent\n"); - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); + if (has_tcpinfo_retransmits()) + printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits); + else + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A'); unit_snprintf(nbuf, UNIT_LEN, (double) (total_received / end_time), test->settings->unit_format); printf(" Total received\n"); - printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); + printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf); } else { avg_jitter /= test->num_streams; - printf(report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, avg_jitter, + printf(report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter, lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets)); } } - if (test->tcp_info) { - print_tcpinfo(test); - } - if (test->verbose) { printf("Host CPU Utilization: %.1f%%\n", test->cpu_util); printf("Remote CPU Utilization: %.1f%%\n", test->remote_cpu_util); @@ -1436,10 +1445,10 @@ print_interval_results(struct iperf_test * test, struct iperf_stream * sp) char ubuf[UNIT_LEN]; char nbuf[UNIT_LEN]; double st = 0., et = 0.; - struct iperf_interval_results *ir = NULL; + struct iperf_interval_results *irp = NULL; - ir = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */ - if (ir == NULL) { + irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */ + if (irp == NULL) { printf("print_interval_results Error: interval_results = NULL \n"); return; } @@ -1449,39 +1458,39 @@ print_interval_results(struct iperf_test * test, struct iperf_stream * sp) ** else if there's more than one stream, print the separator; ** else nothing. */ - if (timeval_equals(&sp->result->start_time, &ir->interval_start_time)) - printf(report_bw_header); + if (timeval_equals(&sp->result->start_time, &irp->interval_start_time)) + if (has_tcpinfo_retransmits()) + printf(report_bw_retrans_header); + else + printf(report_bw_header); else if (test->num_streams > 1) printf(report_bw_separator); } - unit_snprintf(ubuf, UNIT_LEN, (double) (ir->bytes_transferred), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double) (ir->bytes_transferred / ir->interval_duration), + unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) (irp->bytes_transferred / irp->interval_duration), test->settings->unit_format); - st = timeval_diff(&sp->result->start_time,&ir->interval_start_time); - et = timeval_diff(&sp->result->start_time,&ir->interval_end_time); + st = timeval_diff(&sp->result->start_time,&irp->interval_start_time); + et = timeval_diff(&sp->result->start_time,&irp->interval_end_time); - printf(report_bw_format, sp->socket, st, et, ubuf, nbuf); - -/* doing aggregate TCP_INFO reporting for now... - if (test->tcp_info) - print_tcpinfo(ir); -*/ - + if (has_tcpinfo_retransmits()) + printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, get_tcpinfo_retransmits(irp)); + else + printf(report_bw_format, sp->socket, st, et, ubuf, nbuf); } /**************************************************************************/ void iperf_free_stream(struct iperf_stream * sp) { - struct iperf_interval_results *ip, *np; + struct iperf_interval_results *irp, *nirp; /* XXX: need to free interval list too! */ free(sp->buffer); - for (ip = TAILQ_FIRST(&sp->result->interval_results); ip != TAILQ_END(sp->result->interval_results); ip = np) { - np = TAILQ_NEXT(ip, irlistentries); - free(ip); + for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != TAILQ_END(sp->result->interval_results); irp = nirp) { + nirp = TAILQ_NEXT(irp, irlistentries); + free(irp); } free(sp->result); free(sp->send_timer); diff --git a/src/iperf_api.h b/src/iperf_api.h index 2d38664..be828f6 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -147,8 +147,11 @@ int iperf_init_stream(struct iperf_stream *, struct iperf_test *); */ void iperf_free_stream(struct iperf_stream * sp); -void get_tcpinfo(struct iperf_stream *, struct iperf_interval_results *); -void print_tcpinfo(struct iperf_test *); +int has_tcpinfo(void); +int has_tcpinfo_retransmits(void); +void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp); +long get_tcpinfo_retransmits(struct iperf_interval_results *irp); +void print_tcpinfo(struct iperf_test *test); void build_tcpinfo_message(struct iperf_interval_results *r, char *message); void print_interval_results(struct iperf_test * test, struct iperf_stream *sp); diff --git a/src/locale.c b/src/locale.c index 9a06861..682e9a3 100644 --- a/src/locale.c +++ b/src/locale.c @@ -186,25 +186,34 @@ const char report_read_length_times[] = const char report_bw_header[] = "[ ID] Interval Transfer Bandwidth\n"; -const char report_bw_separator[] = -"- - - - - - - - - - - - - - - - - - - - - - - - -\n"; +const char report_bw_retrans_header[] = +"[ ID] Interval Transfer Bandwidth Retransmits\n"; + +const char report_bw_udp_header[] = +"[ ID] Interval Transfer Bandwidth Jitter Lost/Total \ +Datagrams\n"; const char report_bw_format[] = "[%3d] %4.2f-%4.2f sec %ss %ss/sec\n"; +const char report_bw_retrans_format[] = +"[%3d] %4.2f-%4.2f sec %ss %ss/sec %4ld\n"; + +const char report_bw_udp_format[] = +"[%3d] %4.2f-%4.2f sec %ss %ss/sec %5.3f ms %4d/%5d (%.2g%%)\n"; + const char report_sum_bw_format[] = "[SUM] %4.2f-%4.2f sec %ss %ss/sec\n"; -const char report_bw_jitter_loss_header[] = -"[ ID] Interval Transfer Bandwidth Jitter Lost/Total \ -Datagrams\n"; +const char report_sum_bw_retrans_format[] = +"[SUM] %4.2f-%4.2f sec %ss %ss/sec %4ld\n"; -const char report_bw_jitter_loss_format[] = -"[%3d] %4.2f-%4.2f sec %ss %ss/sec %5.3f ms %4d/%5d (%.2g%%)\n"; - -const char report_sum_bw_jitter_loss_format[] = +const char report_sum_bw_udp_format[] = "[SUM] %4.2f-%4.2f sec %ss %ss/sec %5.3f ms %4d/%5d (%.2g%%)\n"; +const char report_bw_separator[] = +"- - - - - - - - - - - - - - - - - - - - - - - - -\n"; + const char report_outoforder[] = "[%3d] %4.1f-%4.1f sec %d datagrams received out-of-order\n"; @@ -247,13 +256,13 @@ const char report_tcpInfo[] = const char reportCSV_bw_format[] = "%s,%s,%d,%.1f-%.1f,%qd,%qd\n"; -const char reportCSV_bw_jitter_loss_format[] = +const char reportCSV_bw_udp_format[] = "%s,%s,%d,%.1f-%.1f,%qd,%qd,%.3f,%d,%d,%.3f,%d\n"; #else // HAVE_PRINTF_QD const char reportCSV_bw_format[] = "%s,%s,%d,%.1f-%.1f,%lld,%lld\n"; -const char reportCSV_bw_jitter_loss_format[] = +const char reportCSV_bw_udp_format[] = "%s,%s,%d,%.1f-%.1f,%lld,%lld,%.3f,%d,%d,%.3f,%d\n"; #endif // HAVE_PRINTF_QD #else // HAVE_QUAD_SUPPORT @@ -261,13 +270,13 @@ const char reportCSV_bw_jitter_loss_format[] = const char reportCSV_bw_format[] = "%s,%s,%d,%.1f-%.1f,%I64d,%I64d\n"; -const char reportCSV_bw_jitter_loss_format[] = +const char reportCSV_bw_udp_format[] = "%s,%s,%d,%.1f-%.1f,%I64d,%I64d,%.3f,%d,%d,%.3f,%d\n"; #else const char reportCSV_bw_format[] = "%s,%s,%d,%.1f-%.1f,%d,%d\n"; -const char reportCSV_bw_jitter_loss_format[] = +const char reportCSV_bw_udp_format[] = "%s,%s,%d,%.1f-%.1f,%d,%d,%.3f,%d,%d,%.3f,%d\n"; #endif //WIN32 #endif //HAVE_QUAD_SUPPORT diff --git a/src/locale.h b/src/locale.h index 770b179..bdcd383 100644 --- a/src/locale.h +++ b/src/locale.h @@ -34,12 +34,15 @@ extern char test_start_bytes[]; extern char report_read_lengths[] ; extern char report_read_length_times[] ; extern char report_bw_header[] ; -extern char report_bw_separator[] ; +extern char report_bw_retrans_header[] ; +extern char report_bw_udp_header[] ; extern char report_bw_format[] ; +extern char report_bw_retrans_format[] ; +extern char report_bw_udp_format[] ; extern char report_sum_bw_format[] ; -extern char report_bw_jitter_loss_header[] ; -extern char report_bw_jitter_loss_format[] ; -extern char report_sum_bw_jitter_loss_format[] ; +extern char report_sum_bw_retrans_format[] ; +extern char report_sum_bw_udp_format[] ; +extern char report_bw_separator[] ; extern char report_outoforder[] ; extern char report_sum_outoforder[] ; extern char report_peer[] ; diff --git a/src/tcp_info.c b/src/tcp_info.c index e3fea87..6d696fe 100644 --- a/src/tcp_info.c +++ b/src/tcp_info.c @@ -39,34 +39,51 @@ #include "locale.h" /*************************************************************/ -void -get_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *rp) +int +has_tcpinfo(void) { #if defined(linux) || defined(__FreeBSD__) - socklen_t tcp_info_length; -// struct tcp_info tempinfo; -// struct iperf_stream *sp = SLIST_FIRST(&test->streams); + return 1; +#else + return 0; +#endif +} - tcp_info_length = sizeof(struct tcp_info); +/*************************************************************/ +int +has_tcpinfo_retransmits(void) +{ +#if defined(linux) + return 1; +#else + return 0; +#endif +} - if (getsockopt(sp->socket, IPPROTO_TCP, TCP_INFO, (void *)&rp->tcpInfo, &tcp_info_length) < 0) { +/*************************************************************/ +void +save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp) +{ +#if defined(linux) || defined(__FreeBSD__) + socklen_t tcp_info_length = sizeof(struct tcp_info); + + if (getsockopt(sp->socket, IPPROTO_TCP, TCP_INFO, (void *)&irp->tcpInfo, &tcp_info_length) < 0) perror("getsockopt"); - } - -/* - for (sp = SLIST_NEXT(sp, streams); sp != SLIST_END(&test->streams); - sp = SLIST_NEXT(sp, streams)) { - tcp_info_length = sizeof(struct tcp_info); - if (getsockopt(sp->socket, IPPROTO_TCP, TCP_INFO, (void *) &tempinfo, &tcp_info_length) < 0) { - perror("getsockopt"); - } - rp->tcpInfo.tcpi_retransmits += tempinfo.tcpi_retransmits; - } -*/ #endif return; } +/*************************************************************/ +long +get_tcpinfo_retransmits(struct iperf_interval_results *irp) +{ +#if defined(linux) + return irp->tcpInfo.tcpi_retransmits; +#else + return -1; +#endif +} + /*************************************************************/ //print_tcpinfo(struct iperf_interval_results *r) void diff --git a/src/version.h b/src/version.h index ac51035..c93be2b 100644 --- a/src/version.h +++ b/src/version.h @@ -7,5 +7,5 @@ * for complete information. */ -#define IPERF_VERSION "3.0-BETA4" -#define IPERF_VERSION_DATE "2 Aug 2010" +#define IPERF_VERSION "3.0-BETA5" +#define IPERF_VERSION_DATE "9 Nov 2012"