From e99faeae868f597f66310b8b3944adac3804d769 Mon Sep 17 00:00:00 2001 From: Brian Tierney Date: Tue, 10 Nov 2009 04:41:42 +0000 Subject: [PATCH] more cleanup and bug fixes --- src/LICENSE.txt | 8 + src/README.txt | 9 + src/TODO.txt | 24 +++ src/iperf.h | 6 +- src/iperf_api.c | 459 +++++++++++++++++++++++------------------ src/iperf_server_api.c | 72 ++++--- src/iperf_tcp.c | 5 +- src/main.c | 25 +-- src/net.c | 4 + 9 files changed, 353 insertions(+), 259 deletions(-) create mode 100644 src/LICENSE.txt create mode 100644 src/README.txt create mode 100644 src/TODO.txt diff --git a/src/LICENSE.txt b/src/LICENSE.txt new file mode 100644 index 0000000..c30eb93 --- /dev/null +++ b/src/LICENSE.txt @@ -0,0 +1,8 @@ + +/* + * Copyright (c) 2009, The Regents of the University of California, through + * Lawrence Berkeley National Laboratory (subject to receipt of any required + * approvals from the U.S. Dept. of Energy). All rights reserved. + */ + + diff --git a/src/README.txt b/src/README.txt new file mode 100644 index 0000000..6913f20 --- /dev/null +++ b/src/README.txt @@ -0,0 +1,9 @@ + +iperf3 should work on Linux, FreeBSD, and Mac OSX + +Prerequists: + libuuidgen + +To build, just type 'make' (or 'gmake' on FreeBSD) + + diff --git a/src/TODO.txt b/src/TODO.txt new file mode 100644 index 0000000..787788f --- /dev/null +++ b/src/TODO.txt @@ -0,0 +1,24 @@ + +Current list of things to fix/add to iperf 3.0 + +- finish/fix receive_result_from_server() + - also: should this be called for TCP too, or only UDP (currently its both, + but I think it should be UDP only, or maybe a command line option for TCP +- document and verify the 'state machine'. Is it an error to send messages in the wrong order? + - what is "STREAM_RUNNING" vs "TEST_RUNNING"?? +- (-i N) mode on server does not work +- verify placment of all timing calls and total_bytes_sent computations +- break up into client/sever files and TCP/UDP files +- much better/standard error handling throughout +- better packaging/makefile, README, LICENCE, etc files +- cleanup/fix/test UDP mode +- IPV6 +- add verbose and debug options +- add human readable vs machine readable output mode + (my idea on this is that "human readable" = compatable with old iperf, + and that "machine readable is all name=value pairs -blt ) +- lots more testing +- look for 'XXX' in code and address +- deamon mode +- see issue tracker for other wish list items + diff --git a/src/iperf.h b/src/iperf.h index a83fe66..345638d 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -110,9 +110,9 @@ struct iperf_test /* Select related parameters */ int max_fd; - fd_set read_set; - fd_set temp_set; - fd_set write_set; + fd_set read_set; /* set of read sockets */ + fd_set temp_set; /* temp set for select */ + fd_set write_set; /* set of write sockets */ int (*accept) (struct iperf_test *); struct iperf_stream *(*new_stream) (struct iperf_test *); diff --git a/src/iperf_api.c b/src/iperf_api.c index 4bc1d21..ed561db 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -39,7 +39,7 @@ #include "uuid.h" #include "locale.h" -jmp_buf env; /* to handle longjmp on signal */ +jmp_buf env; /* to handle longjmp on signal */ /*************************************************************/ @@ -53,25 +53,27 @@ jmp_buf env; /* to handle longjmp on signal */ * iperf_test structure -blt */ int -all_data_sent(struct iperf_test *test) +all_data_sent(struct iperf_test * test) { if (test->default_settings->bytes == 0) return 0; - else { - uint64_t total_bytes = 0; + else + { + uint64_t total_bytes = 0; struct iperf_stream *sp; sp = test->streams; - while (sp) { + while (sp) + { total_bytes += sp->result->bytes_sent; sp = sp->next; } - if (total_bytes >= (test->num_streams * test->default_settings->bytes)) { + if (total_bytes >= (test->num_streams * test->default_settings->bytes)) + { return 1; - } - else + } else return 0; } @@ -85,16 +87,16 @@ all_data_sent(struct iperf_test *test) */ void -exchange_parameters(struct iperf_test *test) +exchange_parameters(struct iperf_test * test) { - int result; + int result; struct iperf_stream *sp; struct param_exchange *param; - //printf("in exchange_parameters \n"); + printf("in exchange_parameters \n"); sp = test->streams; sp->settings->state = PARAM_EXCHANGE; - param = (struct param_exchange *)sp->buffer; + param = (struct param_exchange *) sp->buffer; get_uuid(test->default_settings->cookie); strncpy(param->cookie, test->default_settings->cookie, COOKIE_SIZE); @@ -108,7 +110,7 @@ exchange_parameters(struct iperf_test *test) param->format = test->default_settings->unit_format; #ifdef OLD_WAY - //printf(" sending exchange params: size = %d \n", (int)sizeof(struct param_exchange)); + //printf(" sending exchange params: size = %d \n", (int) sizeof(struct param_exchange)); /* XXX: can we use iperf_tcp_send for this? that would be cleaner */ result = send(sp->socket, sp->buffer, sizeof(struct param_exchange), 0); if (result < 0) @@ -117,11 +119,13 @@ exchange_parameters(struct iperf_test *test) //printf("result = %d state = %d, error = %d \n", result, sp->buffer[0], errno); /* get answer back from server */ - do { + do + { //printf("exchange_parameters: reading result from server .. \n"); result = recv(sp->socket, sp->buffer, sizeof(struct param_exchange), 0); } while (result == -1 && errno == EINTR); #else + printf(" sending exchange params: size = %d \n", (int) sizeof(struct param_exchange)); result = sp->snd(sp); if (result < 0) perror("Error sending exchange params to server"); @@ -130,7 +134,8 @@ exchange_parameters(struct iperf_test *test) if (result < 0) perror("Error getting exchange params ack from server"); - if (result > 0 && sp->buffer[0] == ACCESS_DENIED) { + if (result > 0 && sp->buffer[0] == ACCESS_DENIED) + { fprintf(stderr, "Busy server Detected. Try again later. Exiting.\n"); exit(-1); } @@ -144,24 +149,25 @@ exchange_parameters(struct iperf_test *test) */ void -add_interval_list(struct iperf_stream_result *rp, struct iperf_interval_results temp) +add_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results temp) { struct iperf_interval_results *n; - struct iperf_interval_results *ip = (struct iperf_interval_results *)malloc(sizeof(struct iperf_interval_results)); + struct iperf_interval_results *ip = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results)); ip->bytes_transferred = temp.bytes_transferred; ip->interval_duration = temp.interval_duration; ip->tcpInfo = temp.tcpInfo; - //printf("add_interval_list: Mbytes = %d, duration = %f \n", (int)(ip->bytes_transferred / 1000000), ip->interval_duration); + //printf("add_interval_list: Mbytes = %d, duration = %f \n", (int) (ip->bytes_transferred / 1000000), ip->interval_duration); - if (!rp->interval_results) { + if (!rp->interval_results) + { rp->interval_results = ip; - } - else { + } else + { n = rp->interval_results; - while (n->next) /* find the end of the list */ + while (n->next) /* find the end of the list */ n = n->next; n->next = ip; @@ -173,13 +179,14 @@ add_interval_list(struct iperf_stream_result *rp, struct iperf_interval_results /* for debugging only */ void -display_interval_list(struct iperf_stream_result *rp, int tflag) +display_interval_list(struct iperf_stream_result * rp, int tflag) { struct iperf_interval_results *n; n = rp->interval_results; - while (n) { + while (n) + { printf("Interval = %f\tBytes transferred = %llu\n", n->interval_duration, n->bytes_transferred); if (tflag) print_tcpinfo(n); @@ -194,18 +201,18 @@ display_interval_list(struct iperf_stream_result *rp, int tflag) */ void -receive_result_from_server(struct iperf_test *test) +receive_result_from_server(struct iperf_test * test) { - int result; + int result; struct iperf_stream *sp; - int size = 0; - char *buf = NULL; + int size = 0; + char *buf = NULL; printf("in receive_result_from_server \n"); sp = test->streams; size = MAX_RESULT_STRING; - buf = (char *)malloc(size); + buf = (char *) malloc(size); printf("receive_result_from_server: send ALL_STREAMS_END to server \n"); sp->settings->state = ALL_STREAMS_END; @@ -218,7 +225,8 @@ receive_result_from_server(struct iperf_test *test) /* receive from server */ printf("reading results (size=%d) back from server \n", size); - do { + do + { result = recv(sp->socket, buf, size, 0); } while (result == -1 && errno == EINTR); printf("Got size of results from server: %d \n", result); @@ -237,17 +245,17 @@ receive_result_from_server(struct iperf_test *test) */ void -connect_msg(struct iperf_stream *sp) +connect_msg(struct iperf_stream * sp) { - char ipl [512], ipr[512]; + char ipl[512], ipr[512]; - inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)&sp->local_addr)->sin_addr), (void *)ipl, sizeof(ipl)); - inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)&sp->remote_addr)->sin_addr), (void *)ipr, sizeof(ipr)); + inet_ntop(AF_INET, (void *) (&((struct sockaddr_in *) & sp->local_addr)->sin_addr), (void *) ipl, sizeof(ipl)); + inet_ntop(AF_INET, (void *) (&((struct sockaddr_in *) & sp->remote_addr)->sin_addr), (void *) ipr, sizeof(ipr)); printf("[%3d] local %s port %d connected to %s port %d\n", sp->socket, - ipl, ntohs(((struct sockaddr_in *)&sp->local_addr)->sin_port), - ipr, ntohs(((struct sockaddr_in *)&sp->remote_addr)->sin_port)); + ipl, ntohs(((struct sockaddr_in *) & sp->local_addr)->sin_port), + ipr, ntohs(((struct sockaddr_in *) & sp->remote_addr)->sin_port)); } /*************************************************************/ @@ -258,23 +266,26 @@ connect_msg(struct iperf_stream *sp) */ void -Display(struct iperf_test *test) +Display(struct iperf_test * test) { struct iperf_stream *n; n = test->streams; - int count = 1; + int count = 1; printf("===============DISPLAY==================\n"); - while (1) { - if (n) { + while (1) + { + if (n) + { if (test->role == 'c') - printf("position-%d\tsp=%d\tsocket=%d\tbytes sent=%llu\n", count++, (int)n, n->socket, n->result->bytes_sent); + printf("position-%d\tsp=%d\tsocket=%d\tbytes sent=%llu\n", count++, (int) n, n->socket, n->result->bytes_sent); else - printf("position-%d\tsp=%d\tsocket=%d\tbytes received=%llu\n", count++, (int)n, n->socket, n->result->bytes_received); + printf("position-%d\tsp=%d\tsocket=%d\tbytes received=%llu\n", count++, (int) n, n->socket, n->result->bytes_received); - if (n->next == NULL) { + if (n->next == NULL) + { printf("=================END====================\n"); fflush(stdout); break; @@ -292,15 +303,16 @@ iperf_new_test() struct iperf_test *testp; printf("in iperf_new_test: reinit default settings \n"); - testp = (struct iperf_test *)malloc(sizeof(struct iperf_test)); - if (!testp) { + testp = (struct iperf_test *) malloc(sizeof(struct iperf_test)); + if (!testp) + { perror("malloc"); return (NULL); } /* initialise everything to zero */ memset(testp, 0, sizeof(struct iperf_test)); - testp->default_settings = (struct iperf_settings *)malloc(sizeof(struct iperf_settings)); + testp->default_settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings)); memset(testp->default_settings, 0, sizeof(struct iperf_settings)); /* return an empty iperf_test* with memory alloted. */ @@ -309,7 +321,7 @@ iperf_new_test() /**************************************************************************/ void -iperf_defaults(struct iperf_test *testp) +iperf_defaults(struct iperf_test * testp) { testp->protocol = Ptcp; testp->role = 's'; @@ -337,15 +349,17 @@ iperf_defaults(struct iperf_test *testp) /**************************************************************************/ void -iperf_init_test(struct iperf_test *test) +iperf_init_test(struct iperf_test * test) { - char ubuf [UNIT_LEN]; + char ubuf[UNIT_LEN]; struct iperf_stream *sp; - int i , s = 0; + int i, s = 0; printf("in iperf_init_test \n"); - if (test->role == 's') { /* server */ - if (test->protocol == Pudp) { + if (test->role == 's') + { /* server */ + if (test->protocol == Pudp) + { test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port); if (test->listener_sock_udp < 0) exit(0); @@ -355,7 +369,8 @@ iperf_init_test(struct iperf_test *test) if (test->listener_sock_tcp < 0) exit(0); - if (test->protocol == Ptcp) { + if (test->protocol == Ptcp) + { if (set_tcp_windowsize(test->listener_sock_tcp, test->default_settings->socket_bufsize, SO_RCVBUF) < 0) perror("unable to set TCP window"); } @@ -365,27 +380,29 @@ iperf_init_test(struct iperf_test *test) printf("-----------------------------------------------------------\n"); printf("Server listening on %d\n", test->server_port); - int x; + int x; /* make sure we got what we asked for */ if ((x = get_tcp_windowsize(test->listener_sock_tcp, SO_RCVBUF)) < 0) perror("SO_RCVBUF"); - if (test->protocol == Ptcp) { + if (test->protocol == Ptcp) + { { - if (test->default_settings->socket_bufsize > 0) { - unit_snprintf(ubuf, UNIT_LEN, (double)x, 'A'); + if (test->default_settings->socket_bufsize > 0) + { + unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); printf("TCP window size: %s\n", ubuf); - } - else { + } else + { printf("Using TCP Autotuning \n"); } } } printf("-----------------------------------------------------------\n"); - } - else if (test->role == 'c') { /* Client */ + } else if (test->role == 'c') + { /* Client */ FD_ZERO(&test->write_set); FD_SET(s, &test->write_set); @@ -393,9 +410,11 @@ iperf_init_test(struct iperf_test *test) * XXX: I think we need to create a TCP control socket here too for * UDP mode -blt */ - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { s = netdial(test->protocol, test->server_hostname, test->server_port); - if (s < 0) { + if (s < 0) + { fprintf(stderr, "netdial failed\n"); exit(0); } @@ -414,7 +433,7 @@ iperf_init_test(struct iperf_test *test) /**************************************************************************/ void -iperf_free_test(struct iperf_test *test) +iperf_free_test(struct iperf_test * test) { free(test->default_settings); @@ -439,21 +458,23 @@ iperf_free_test(struct iperf_test *test) */ -void * -iperf_stats_callback(struct iperf_test *test) +void * +iperf_stats_callback(struct iperf_test * test) { - iperf_size_t cumulative_bytes = 0; - int i; + iperf_size_t cumulative_bytes = 0; + int i; struct iperf_stream *sp = test->streams; struct iperf_stream_result *rp = test->streams->result; struct iperf_interval_results *ip, temp; //printf("in stats_callback: num_streams = %d \n", test->num_streams); - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { rp = sp->result; - if (!rp->interval_results) { + if (!rp->interval_results) + { if (test->role == 'c') temp.bytes_transferred = rp->bytes_sent; else @@ -465,10 +486,11 @@ iperf_stats_callback(struct iperf_test *test) gettimeofday(&sp->result->end_time, NULL); add_interval_list(rp, temp); - } - else { + } else + { ip = sp->result->interval_results; - while (1) { + while (1) + { cumulative_bytes += ip->bytes_transferred; if (ip->next != NULL) ip = ip->next; @@ -508,17 +530,18 @@ iperf_stats_callback(struct iperf_test *test) * */ -char * -iperf_reporter_callback(struct iperf_test *test) +char * +iperf_reporter_callback(struct iperf_test * test) { - int total_packets = 0, lost_packets = 0, curr_state = 0; - char ubuf [UNIT_LEN]; - char nbuf [UNIT_LEN]; + int total_packets = 0, lost_packets = 0, curr_state = 0; + int first_stream = 1; + char ubuf[UNIT_LEN]; + char nbuf[UNIT_LEN]; struct iperf_stream *sp = NULL; - iperf_size_t bytes = 0; - double start_time, end_time; - char *message = (char *)malloc(MAX_RESULT_STRING); - char *message_final = (char *)malloc(MAX_RESULT_STRING); + iperf_size_t bytes = 0; + double start_time, end_time; + char *message = (char *) malloc(MAX_RESULT_STRING); + char *message_final = (char *) malloc(MAX_RESULT_STRING); memset(message_final, 0, strlen(message_final)); @@ -529,136 +552,160 @@ iperf_reporter_callback(struct iperf_test *test) curr_state = sp->settings->state; //printf("in iperf_reporter_callback: state = %d \n", curr_state); - if (curr_state == TEST_RUNNING) { + if (curr_state == TEST_RUNNING || curr_state == STREAM_RUNNING) + { /* print interval results */ - while (sp) { /* for each stream */ + while (sp) + { /* for each stream */ ip = sp->result->interval_results; - while (ip->next != NULL) { + while (ip->next != NULL) /* find end of list. XXX: why not just keep track of this pointer?? */ + { ip_prev = ip; ip = ip->next; } bytes += ip->bytes_transferred; - unit_snprintf(ubuf, UNIT_LEN, (double)(ip->bytes_transferred), 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) (ip->bytes_transferred), 'A'); - if (test->streams->result->interval_results->next != NULL) { + if (test->streams->result->interval_results->next != NULL) + { unit_snprintf(nbuf, UNIT_LEN, - (double)(ip->bytes_transferred / (ip->interval_duration - ip_prev->interval_duration)), + (double) (ip->bytes_transferred / (ip->interval_duration - ip_prev->interval_duration)), test->default_settings->unit_format); sprintf(message, report_bw_format, sp->socket, ip_prev->interval_duration, ip->interval_duration, ubuf, nbuf); - } - else { - sprintf(message, report_bw_header); - safe_strcat(message_final, message); + } else + { + if (first_stream) /* only print header for 1st stream */ + { + sprintf(message, report_bw_header); + safe_strcat(message_final, message); + first_stream = 0; + } - unit_snprintf(nbuf, UNIT_LEN, (double)(ip->bytes_transferred / ip->interval_duration), test->default_settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, (double) (ip->bytes_transferred / ip->interval_duration), test->default_settings->unit_format); sprintf(message, report_bw_format, sp->socket, 0.0, ip->interval_duration, ubuf, nbuf); } if (strlen(message_final) + strlen(message) < MAX_RESULT_STRING) safe_strcat(message_final, message); - else { + else + { printf("Error: results string too long \n"); return NULL; } - if (test->tcp_info) { + if (test->tcp_info) + { build_tcpinfo_message(ip, message); safe_strcat(message_final, message); } + //printf("reporter_callback: built interval string: %s \n", message_final); sp = sp->next; } /* while (sp) */ - if (test->num_streams > 1) { - unit_snprintf(ubuf, UNIT_LEN, (double)(bytes), 'A'); + if (test->num_streams > 1) /* sum of all streams */ + { + unit_snprintf(ubuf, UNIT_LEN, (double) (bytes), 'A'); - if (test->streams->result->interval_results->next != NULL) { - unit_snprintf(nbuf, UNIT_LEN, (double)(bytes / (ip->interval_duration - ip_prev->interval_duration)), + if (test->streams->result->interval_results->next != NULL) + { + unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / (ip->interval_duration - ip_prev->interval_duration)), test->default_settings->unit_format); sprintf(message, report_sum_bw_format, ip_prev->interval_duration, ip->interval_duration, ubuf, nbuf); - } - else { - unit_snprintf(nbuf, UNIT_LEN, (double)(bytes / ip->interval_duration), test->default_settings->unit_format); + } else + { + unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / ip->interval_duration), test->default_settings->unit_format); sprintf(message, report_sum_bw_format, 0.0, ip->interval_duration, ubuf, nbuf); } safe_strcat(message_final, message); - if (test->tcp_info) { + if (test->tcp_info) + { build_tcpinfo_message(ip, message); safe_strcat(message_final, message); } } - } - else if (curr_state == ALL_STREAMS_END || curr_state == RESULT_REQUEST) { - /* if TEST_RUNNING */ - sp = test->streams; + } else + { + if (curr_state == ALL_STREAMS_END || curr_state == RESULT_REQUEST) + { + /* if TEST_RUNNING */ + sp = test->streams; - while (sp) { - if (test->role == 'c') - bytes += sp->result->bytes_sent; - else - bytes += sp->result->bytes_received; + while (sp) + { + if (test->role == 'c') + bytes += sp->result->bytes_sent; + else + bytes += sp->result->bytes_received; - if (test->protocol == Pudp) { - total_packets += sp->packet_count; - lost_packets += sp->cnt_error; - } - start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); - end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); - - if (test->role == 'c') { - unit_snprintf(ubuf, UNIT_LEN, (double)(sp->result->bytes_sent), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)(sp->result->bytes_sent / end_time), test->default_settings->unit_format); - - } - else { - unit_snprintf(ubuf, UNIT_LEN, (double)(sp->result->bytes_received), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)(sp->result->bytes_received / end_time), test->default_settings->unit_format); - } - - if (test->protocol == Ptcp) { - sprintf(message, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); - safe_strcat(message_final, message); - } - else { /* UDP mode */ - sprintf(message, report_bw_jitter_loss_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)); - safe_strcat(message_final, message); - - if (test->role == 'c') { - sprintf(message, report_datagrams, sp->socket, sp->packet_count); - safe_strcat(message_final, message); + if (test->protocol == Pudp) + { + total_packets += sp->packet_count; + lost_packets += sp->cnt_error; } - if (sp->outoforder_packets > 0) - printf(report_sum_outoforder, start_time, end_time, sp->cnt_error); - } - /* - * XXX: we need to do something with any TCP_INFO results here - */ - sp = sp->next; - } /* while (sp) */ + start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); + end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); + if (test->role == 'c') + { + unit_snprintf(ubuf, UNIT_LEN, (double) (sp->result->bytes_sent), 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) (sp->result->bytes_sent / end_time), test->default_settings->unit_format); + + } else + { + unit_snprintf(ubuf, UNIT_LEN, (double) (sp->result->bytes_received), 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) (sp->result->bytes_received / end_time), test->default_settings->unit_format); + } + + if (test->protocol == Ptcp) + { + sprintf(message, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + safe_strcat(message_final, message); + } else + { /* UDP mode */ + sprintf(message, report_bw_jitter_loss_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)); + safe_strcat(message_final, message); + + if (test->role == 'c') + { + sprintf(message, report_datagrams, sp->socket, sp->packet_count); + safe_strcat(message_final, message); + } + if (sp->outoforder_packets > 0) + printf(report_sum_outoforder, start_time, end_time, sp->cnt_error); + } + /* + * XXX: we need to do something with any TCP_INFO results here + */ + sp = sp->next; + } + } /* while (sp) */ sp = test->streams; /* reset to first socket */ start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); - unit_snprintf(ubuf, UNIT_LEN, (double)bytes, 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)bytes / end_time, test->default_settings->unit_format); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) bytes / end_time, test->default_settings->unit_format); - if ((test->role == 'c' && test->num_streams > 1) || (test->role == 's')) { - if (test->protocol == Ptcp) { + if ((test->role == 'c' && test->num_streams > 1) || (test->role == 's')) + { + if (test->protocol == Ptcp) + { sprintf(message, report_sum_bw_format, start_time, end_time, ubuf, nbuf); safe_strcat(message_final, message); - } - else { - sprintf(message, report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, sp->jitter, lost_packets, total_packets, (double)(100.0 * lost_packets / total_packets)); + } else + { + sprintf(message, report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, sp->jitter, lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets)); safe_strcat(message_final, message); } - if ((test->print_mss != 0) && (test->role == 'c')) { + if ((test->print_mss != 0) && (test->role == 'c')) + { sprintf(message, "\nThe TCP maximum segment size mss = %d \n", getsock_tcp_mss(sp->socket)); safe_strcat(message_final, message); } @@ -675,16 +722,17 @@ safe_strcat(char *s1, char *s2) //printf(" adding string %s to end of string %s \n", s1, s1); if (strlen(s1) + strlen(s2) < MAX_RESULT_STRING) strcat(s1, s2); - else { + else + { printf("Error: results string too long \n"); - exit(-1); /* XXX: should return an error instead! */ + exit(-1); /* XXX: should return an error instead! */ //return -1; } } /**************************************************************************/ void -iperf_free_stream(struct iperf_stream *sp) +iperf_free_stream(struct iperf_stream * sp) { free(sp->buffer); free(sp->settings); @@ -695,25 +743,26 @@ iperf_free_stream(struct iperf_stream *sp) /**************************************************************************/ struct iperf_stream * -iperf_new_stream(struct iperf_test *testp) +iperf_new_stream(struct iperf_test * testp) { - int i = 0; + int i = 0; struct iperf_stream *sp; //printf("in iperf_new_stream \n"); - sp = (struct iperf_stream *)malloc(sizeof(struct iperf_stream)); - if (!sp) { + sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream)); + if (!sp) + { perror("malloc"); return (NULL); } memset(sp, 0, sizeof(struct iperf_stream)); printf("iperf_new_stream: Allocating new stream buffer: size = %d \n", testp->default_settings->blksize); - sp->buffer = (char *)malloc(testp->default_settings->blksize); - sp->settings = (struct iperf_settings *)malloc(sizeof(struct iperf_settings)); + sp->buffer = (char *) malloc(testp->default_settings->blksize); + sp->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings)); /* make a per stream copy of default_settings in each stream structure */ memcpy(sp->settings, testp->default_settings, sizeof(struct iperf_settings)); - sp->result = (struct iperf_stream_result *)malloc(sizeof(struct iperf_stream_result)); + sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result)); /* fill in buffer with random stuff */ /* XXX: probably better to use something truely random here */ @@ -723,7 +772,7 @@ iperf_new_stream(struct iperf_test *testp) sp->socket = -1; sp->packet_count = 0; - sp->stream_id = (int)sp; + sp->stream_id = (int) sp; sp->jitter = 0.0; sp->prev_transit = 0.0; sp->outoforder_packets = 0; @@ -743,20 +792,23 @@ iperf_new_stream(struct iperf_test *testp) /**************************************************************************/ void -iperf_init_stream(struct iperf_stream *sp, struct iperf_test *testp) +iperf_init_stream(struct iperf_stream * sp, struct iperf_test * testp) { - socklen_t len; + socklen_t len; len = sizeof(struct sockaddr_in); - if (getsockname(sp->socket, (struct sockaddr *)&sp->local_addr, &len) < 0) { + if (getsockname(sp->socket, (struct sockaddr *) & sp->local_addr, &len) < 0) + { perror("getsockname"); } - if (getpeername(sp->socket, (struct sockaddr *)&sp->remote_addr, &len) < 0) { + if (getpeername(sp->socket, (struct sockaddr *) & sp->remote_addr, &len) < 0) + { perror("getpeername"); } //printf("in init_stream: calling set_tcp_windowsize: %d \n", testp->default_settings->socket_bufsize); - if (testp->protocol == Ptcp) { + if (testp->protocol == Ptcp) + { if (set_tcp_windowsize(sp->socket, testp->default_settings->socket_bufsize, testp->role == 's' ? SO_RCVBUF : SO_SNDBUF) < 0) fprintf(stderr, "unable to set window size\n"); @@ -768,15 +820,16 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *testp) /**************************************************************************/ int -iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) +iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp) { struct iperf_stream *n; - if (!test->streams) { + if (!test->streams) + { test->streams = sp; return 1; - } - else { + } else + { n = test->streams; while (n->next) n = n->next; @@ -797,13 +850,14 @@ iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) */ struct iperf_stream * -find_stream_by_socket(struct iperf_test *test, int sock) +find_stream_by_socket(struct iperf_test * test, int sock) { struct iperf_stream *n; n = test->streams; - while (1) { + while (1) + { if (n->socket == sock) break; @@ -826,19 +880,19 @@ catcher(int sig) /**************************************************************************/ void -iperf_run_client(struct iperf_test *test) +iperf_run_client(struct iperf_test * test) { - int i , result = 0; + int i, result = 0; struct iperf_stream *sp, *np; - struct timer *timer, *stats_interval, *reporter_interval; - char *result_string = NULL; - char *prot = NULL; - int64_t delayus, adjustus, dtargus; - struct timeval tv; - int ret = 0; + struct timer *timer, *stats_interval, *reporter_interval; + char *result_string = NULL; + char *prot = NULL; + int64_t delayus, adjustus, dtargus; + struct timeval tv; + int ret = 0; struct sigaction sact; - //printf("in iperf_run_client \n"); + printf("in iperf_run_client \n"); tv.tv_sec = 15; /* timeout interval in seconds */ tv.tv_usec = 0; @@ -847,7 +901,8 @@ iperf_run_client(struct iperf_test *test) sact.sa_handler = catcher; sigaction(SIGINT, &sact, NULL); - if (test->protocol == Pudp) { + if (test->protocol == Pudp) + { dtargus = (int64_t) (test->default_settings->blksize) * SEC_TO_US * 8; dtargus /= test->default_settings->rate; @@ -858,7 +913,8 @@ iperf_run_client(struct iperf_test *test) printf("iperf_run_client: adjustus: %lld, delayus: %lld \n", adjustus, delayus); sp = test->streams; - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { sp->send_timer = new_timer(0, dtargus); sp = sp->next; } @@ -884,10 +940,11 @@ iperf_run_client(struct iperf_test *test) prot, test->num_streams, test->default_settings->blksize, test->duration); else printf("Starting Test: protocol: %s, %d streams, %d byte blocks, %d bytes to send\n", - prot, test->num_streams, test->default_settings->blksize, (int)test->default_settings->bytes); + prot, test->num_streams, test->default_settings->blksize, (int) test->default_settings->bytes); /* send data till the timer expires or bytes sent */ - while (!all_data_sent(test) && !timer->expired(timer)) { + while (!all_data_sent(test) && !timer->expired(timer)) + { #ifdef NEED_THIS /* not sure what this was for, so removed * -blt */ @@ -899,7 +956,8 @@ iperf_run_client(struct iperf_test *test) #endif sp = test->streams; - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { //printf("sending data to stream %d \n", i); result += sp->snd(sp); @@ -909,12 +967,15 @@ iperf_run_client(struct iperf_test *test) } - if ((test->stats_interval != 0) && stats_interval->expired(stats_interval)) { + if ((test->stats_interval != 0) && stats_interval->expired(stats_interval)) + { test->stats_callback(test); update_timer(stats_interval, test->stats_interval, 0); } - if ((test->reporter_interval != 0) && reporter_interval->expired(reporter_interval)) { + if ((test->reporter_interval != 0) && reporter_interval->expired(reporter_interval)) + { result_string = test->reporter_callback(test); + //printf("interval expired: printing results: \n"); puts(result_string); update_timer(reporter_interval, test->reporter_interval, 0); } @@ -932,10 +993,11 @@ iperf_run_client(struct iperf_test *test) printf("Test Complete. \n"); /* send STREAM_END packets */ np = test->streams; - do { /* send STREAM_END to all sockets */ + do + { /* send STREAM_END to all sockets */ sp = np; sp->settings->state = STREAM_END; - printf("sending state = STREAM_END to stream %d \n", sp->socket); + printf("sending state = STREAM_END to stream %d \n", sp->socket); sp->snd(sp); np = sp->next; } while (np); @@ -968,7 +1030,8 @@ iperf_run_client(struct iperf_test *test) /* Deleting all streams - CAN CHANGE FREE_STREAM FN */ sp = test->streams; np = sp; - do { + do + { sp = np; close(sp->socket); np = sp->next; diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index bffdcaa..999479c 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -128,10 +128,18 @@ iperf_run_server(struct iperf_test * test) printf("in iperf_run_server \n"); FD_ZERO(&test->read_set); - FD_SET(test->listener_sock_tcp, &test->read_set); - FD_SET(test->listener_sock_udp, &test->read_set); + FD_ZERO(&test->temp_set); + if (test->protocol == Ptcp) + { + /* add listener to the master set */ + FD_SET(test->listener_sock_tcp, &test->read_set); + test->max_fd = test->listener_sock_tcp; + } else + { + FD_SET(test->listener_sock_udp, &test->read_set); + test->max_fd = test->listener_sock_udp; + } - test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp; //printf("iperf_run_server: max_fd set to %d \n", test->max_fd); test->num_streams = 0; @@ -158,37 +166,38 @@ iperf_run_server(struct iperf_test * test) exit(0); } else if (result > 0) { - /* Accept a new TCP connection */ - if (FD_ISSET(test->listener_sock_tcp, &test->temp_set)) + if (test->protocol == Ptcp) { - test->protocol = Ptcp; - test->accept = iperf_tcp_accept; - if (test->accept < 0) - return; - test->new_stream = iperf_new_tcp_stream; - test->accept(test); - test->default_settings->state = TEST_RUNNING; - FD_CLR(test->listener_sock_tcp, &test->temp_set); - printf("iperf_run_server: accepted TCP connection \n"); - } - /* Accept a new UDP connection */ - else if (FD_ISSET(test->listener_sock_udp, &test->temp_set)) + /* Accept a new TCP connection */ + if (FD_ISSET(test->listener_sock_tcp, &test->temp_set)) + { + test->protocol = Ptcp; + test->accept = iperf_tcp_accept; + if (test->accept < 0) + return; + test->new_stream = iperf_new_tcp_stream; + test->accept(test); + test->default_settings->state = TEST_RUNNING; + FD_CLR(test->listener_sock_tcp, &test->temp_set); + printf("iperf_run_server: accepted TCP connection \n"); + } + } else { - test->protocol = Pudp; - test->accept = iperf_udp_accept; - if (test->accept < 0) - return; - test->new_stream = iperf_new_udp_stream; - test->accept(test); - test->default_settings->state = TEST_RUNNING; - FD_CLR(test->listener_sock_udp, &test->temp_set); + /* Accept a new UDP connection */ + if (FD_ISSET(test->listener_sock_udp, &test->temp_set)) + { + test->protocol = Pudp; + test->accept = iperf_udp_accept; + if (test->accept < 0) + return; + test->new_stream = iperf_new_udp_stream; + test->accept(test); + test->default_settings->state = TEST_RUNNING; + FD_CLR(test->listener_sock_udp, &test->temp_set); + printf("iperf_run_server: accepted UDP connection \n"); + } } /* Process the sockets for read operation */ - /* - * XXX: Need to try to read equal amounts from each socket, so - * keep track of last socket read from, and always start with the - * next socket - */ nfd = test->max_fd + 1; for (j = 0; j <= test->max_fd; j++) { @@ -196,7 +205,7 @@ iperf_run_server(struct iperf_test * test) if (FD_ISSET(j, &test->temp_set)) { //printf("iperf_run_server: data ready on socket %d \n", j); - /* find the correct stream - possibly time consuming */ + /* find the correct stream - possibly time consuming? */ np = find_stream_by_socket(test, j); message = np->rcv(np); /* get data from client using * receiver callback */ @@ -205,6 +214,7 @@ iperf_run_server(struct iperf_test * test) handle_message(test, message, np); if (message == TEST_END) break; /* test done, so break out of loop */ + } /* end if (FD_ISSET(j, &temp_set)) */ } /* end for (j=0;...) */ } /* end else (result>0) */ diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index cffcca9..e5d9b1f 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -282,10 +282,9 @@ iperf_tcp_accept(struct iperf_test * test) } else { sp = test->new_stream(test); - /* XXX: what is this for? */ - //setnonblocking(peersock); + setnonblocking(peersock); - FD_SET(peersock, &test->read_set); + FD_SET(peersock, &test->read_set); /* add new socket to master set */ test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd; //printf("iperf_tcp_accept: max_fd now set to: %d \n", test->max_fd ); diff --git a/src/main.c b/src/main.c index e6b1bae..a060900 100644 --- a/src/main.c +++ b/src/main.c @@ -1,33 +1,10 @@ /* - * Copyright (c) 2004, The Regents of the University of California, through + * Copyright (c) 2009, The Regents of the University of California, through * Lawrence Berkeley National Laboratory (subject to receipt of any required * approvals from the U.S. Dept. of Energy). All rights reserved. */ -/* - * TO DO list: - * finish/fix receive_result_from_server() - * - also: should this be called for TCP too, or only UDP (currently its both, - * but I think it should be UDP only, or maybe a command line option for TCP - * (and related to this, check, test, document 'state machine' aspect of this. - * eg: are TEST_START and TEST_END, and STREAM_END / ALL_STREAMS_END all required? - * is it an error to get these in a strange order? etc. ) - * verify placment of all timing calls and total_bytes_sent computations - * break up into client/sever files and TCP/UDP files - * much better/standard error handling throughout - * better packaging/makefile, README, LICENCE, etc files - * cleanup/fix/test UDP mode - * IPV6 - * add verbose and debug options - * add human readable vs machine readable output mode - * (my idea on this is that "human readable" = compatable with old iperf, - * and that "machine readable is all name=value pairs -blt ) - * lots more testing - * look for 'XXX' in code and address - * see issue tracker for other wish list items - */ - #include #include #include diff --git a/src/net.c b/src/net.c index 5cb4ed5..4bc1974 100644 --- a/src/net.c +++ b/src/net.c @@ -13,6 +13,10 @@ #include "net.h" #include "timer.h" +/* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ + * Copyright: http://swtch.com/libtask/COPYRIGHT +*/ + /* make connection to server */ int netdial(int proto, char *client, int port)