From efdc02f7439da3609460a6234ea6a991d9fac480 Mon Sep 17 00:00:00 2001 From: sethdelliott Date: Wed, 30 Jun 2010 15:58:16 +0000 Subject: [PATCH] The server now runs until terminated by the user. Also fixed several memory leaks. --- src/iperf.h | 3 +- src/iperf_api.c | 30 +++++++++-------- src/iperf_server_api.c | 76 ++++++++++++++++++++++++++++++++---------- src/iperf_server_api.h | 2 ++ src/net.c | 4 +-- src/net.h | 4 +-- src/uuid.c | 13 +++++--- 7 files changed, 92 insertions(+), 40 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 50df2d4..9beec09 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -214,7 +214,8 @@ enum CLIENT_TERMINATE = 14, EXCHANGE_RESULTS = 15, DISPLAY_RESULTS = 16, - IPERF_DONE = 17, + IPERF_START = 17, + IPERF_DONE = 18, ACCESS_DENIED = -1, }; diff --git a/src/iperf_api.c b/src/iperf_api.c index 7ec0c73..e9461ff 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -173,9 +173,9 @@ iperf_send(struct iperf_test *test) update_timer(reporter_interval, test->reporter_interval, 0); } } else { - free(timer); - free(stats_interval); - free(reporter_interval); + free_timer(timer); + free_timer(stats_interval); + free_timer(reporter_interval); // Send TEST_DONE (ALL_STREAMS_END) message test->state = TEST_END; @@ -333,6 +333,9 @@ parse_parameters(struct iperf_test *test) break; } } + // XXX: optreset is not needed on ubuntu + optreset = 1; + optind = 0; free(params); @@ -363,7 +366,6 @@ iperf_exchange_parameters(struct iperf_test * test) test->prot_listener = netannounce(test->protocol, NULL, test->server_port + 1); FD_SET(test->prot_listener, &test->read_set); - FD_SET(test->prot_listener, &test->write_set); test->max_fd = (test->prot_listener > test->max_fd) ? test->prot_listener : test->max_fd; // Send the control message to create streams and start the test @@ -628,13 +630,12 @@ iperf_new_test() perror("malloc"); return (NULL); } - /* initialise everything to zero */ + /* initialize everything to zero */ memset(testp, 0, sizeof(struct iperf_test)); 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. */ return testp; } @@ -777,12 +778,6 @@ iperf_free_test(struct iperf_test * test) { free(test->default_settings); - // This funciton needs to be updated to free and close streams - // Currently it just sets the pointer to the streams list to NULL... - - close(test->listener_sock_tcp); - close(test->listener_sock_udp); - test->streams = NULL; test->accept = NULL; test->stats_callback = NULL; @@ -997,9 +992,15 @@ print_interval_results(struct iperf_test * test, struct iperf_stream * sp) void iperf_free_stream(struct iperf_stream * sp) { + struct iperf_interval_results *ip, *np; + /* XXX: need to free interval list too! */ free(sp->buffer); free(sp->settings); + for (ip = sp->result->interval_results; ip; ip = np) { + np = ip->next; + free(ip); + } free(sp->result); free(sp->send_timer); free(sp); @@ -1112,7 +1113,7 @@ iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp) int iperf_client_end(struct iperf_test *test) { - struct iperf_stream *sp; + struct iperf_stream *sp, *np; printf("Test Complete. Summary Results:\n"); /* show final summary */ @@ -1135,8 +1136,9 @@ iperf_client_end(struct iperf_test *test) //printf("Done getting/printing results. \n"); /* Deleting all streams - CAN CHANGE FREE_STREAM FN */ - for (sp = test->streams; sp != NULL; sp = sp->next) { + for (sp = test->streams; sp; sp = np) { close(sp->socket); + np = sp->next; iperf_free_stream(sp); } diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index be0e60e..2698110 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -82,7 +82,7 @@ iperf_server_listen(struct iperf_test *test) printf("-----------------------------------------------------------\n"); FD_ZERO(&test->read_set); - FD_ZERO(&test->temp_set); + FD_ZERO(&test->write_set); FD_SET(test->listener, &test->read_set); test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; @@ -140,6 +140,8 @@ iperf_accept(struct iperf_test *test) int iperf_handle_message_server(struct iperf_test *test) { + struct iperf_stream *sp; + if (read(test->ctrl_sck, &test->state, sizeof(char)) < 0) { // XXX: Needs to indicate read error return -1; @@ -154,6 +156,11 @@ iperf_handle_message_server(struct iperf_test *test) case TEST_RUNNING: break; case TEST_END: + for (sp = test->streams; sp; sp = sp->next) { + FD_CLR(sp->socket, &test->read_set); + FD_CLR(sp->socket, &test->write_set); + close(sp->socket); + } test->state = EXCHANGE_RESULTS; if (write(test->ctrl_sck, &test->state, sizeof(char)) < 0) { perror("write EXCHANGE_RESULTS"); @@ -181,11 +188,42 @@ iperf_handle_message_server(struct iperf_test *test) return 0; } +void +iperf_test_reset(struct iperf_test *test) +{ + struct iperf_stream *sp, *np; + struct iperf_settings *settings; + int listener; + + close(test->ctrl_sck); + + /* Free streams */ + for (sp = test->streams; sp; sp = np) { + np = sp->next; + iperf_free_stream(sp); + } + + /* Clear memory and reset defaults */ + memset(test->default_settings, 0, sizeof(struct iperf_settings)); + settings = test->default_settings; + listener = test->listener; + memset(test, 0, sizeof(struct iperf_test)); + test->role = 's'; + test->default_settings = settings; + iperf_defaults(test); + test->listener = listener; + FD_ZERO(&test->read_set); + FD_ZERO(&test->write_set); + FD_SET(test->listener, &test->read_set); + test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; +} + int iperf_run_server(struct iperf_test *test) { int result; - int streams_accepted = 0; + int streams_accepted; + fd_set temp_read_set, temp_write_set; struct timeval tv; // Open socket and listen @@ -207,43 +245,46 @@ iperf_run_server(struct iperf_test *test) exit(1); } - test->default_settings->state = TEST_RUNNING; + for (;;) { + test->state = IPERF_START; + streams_accepted = 0; + while (test->state != IPERF_DONE) { - // XXX: Move test->temp_set over to local fd_set - memcpy(&test->temp_set, &test->read_set, sizeof(fd_set)); + memcpy(&temp_read_set, &test->read_set, sizeof(fd_set)); + memcpy(&temp_write_set, &test->write_set, sizeof(fd_set)); tv.tv_sec = 15; tv.tv_usec = 0; - result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv); + result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv); if (result < 0 && errno != EINTR) { // Change the way this handles errors perror("select"); exit(1); } else if (result > 0) { - if (FD_ISSET(test->listener, &test->temp_set)) { + if (FD_ISSET(test->listener, &temp_read_set)) { if (iperf_accept(test) < 0) { fprintf(stderr, "iperf_accept: error accepting control socket. exiting...\n"); exit(1); } - FD_CLR(test->listener, &test->temp_set); + FD_CLR(test->listener, &temp_read_set); } - if (FD_ISSET(test->ctrl_sck, &test->temp_set)) { + if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { // Handle control messages iperf_handle_message_server(test); - FD_CLR(test->ctrl_sck, &test->temp_set); + FD_CLR(test->ctrl_sck, &temp_read_set); } if (test->state == CREATE_STREAMS) { - if (FD_ISSET(test->prot_listener, &test->temp_set)) { + if (FD_ISSET(test->prot_listener, &temp_read_set)) { // Spawn new streams // XXX: This works, but should it check cookies for authenticity // Also, currently it uses 5202 for stream connections. // Should this be fixed to use 5201 instead? iperf_tcp_accept(test); ++streams_accepted; - FD_CLR(test->prot_listener, &test->temp_set); + FD_CLR(test->prot_listener, &temp_read_set); } if (streams_accepted == test->num_streams) { FD_CLR(test->prot_listener, &test->read_set); @@ -266,14 +307,15 @@ iperf_run_server(struct iperf_test *test) } } + /* Clean up the last test */ + iperf_test_reset(test); + printf("\n"); + + } + // XXX: Need to put the above while loop into another control structure // that initiates a new test upon each connection rather than dying. - /* reset cookie when client is finished */ - /* XXX: which cookie to reset, and why is it stored to 2 places? */ - //memset(test->streams->settings->cookie, '\0', COOKIE_SIZE); - /* All memory for the previous run needs to be freed here */ - memset(test->default_settings->cookie, '\0', COOKIE_SIZE); return 0; } diff --git a/src/iperf_server_api.h b/src/iperf_server_api.h index e900f03..021e857 100644 --- a/src/iperf_server_api.h +++ b/src/iperf_server_api.h @@ -11,4 +11,6 @@ int iperf_acept(struct iperf_test *); int iperf_handle_message_server(struct iperf_test *); +void iperf_test_reset(struct iperf_test *); + #endif diff --git a/src/net.c b/src/net.c index c1c5af6..150f40a 100644 --- a/src/net.c +++ b/src/net.c @@ -98,7 +98,7 @@ netannounce(int proto, char *local, int port) /********************************************************************/ int -Nread(int fd, char *buf, int count, int prot) +Nread(int fd, void *buf, int count, int prot) { struct sockaddr from; socklen_t len = sizeof(from); @@ -135,7 +135,7 @@ Nread(int fd, char *buf, int count, int prot) */ int -Nwrite(int fd, char *buf, int count, int prot) +Nwrite(int fd, void *buf, int count, int prot) { register int n; register int nleft = count; diff --git a/src/net.h b/src/net.h index ccc3771..346a1ce 100644 --- a/src/net.h +++ b/src/net.h @@ -3,8 +3,8 @@ int netdial(int, char *, int); int netannounce(int, char *, int); -int Nwrite(int, char *, int, int); -int Nread(int, char *, int, int); +int Nwrite(int, void *, int, int); +int Nread(int, void *, int, int); int getsock_tcp_mss(int); int set_tcp_options(int, int, int); int setnonblocking(int); diff --git a/src/uuid.c b/src/uuid.c index 6f62eae..a0a2785 100644 --- a/src/uuid.c +++ b/src/uuid.c @@ -15,10 +15,11 @@ /* XXX: this code is not portable: not all versions of linux install libuuidgen - by default - * if not installed, may need to do something like this: - * yum install libuuid-devel - * apt-get install apt-get install + * by default + * + * if not installed, may need to do something like this: + * yum install libuuid-devel + * apt-get install uuid-dev */ @@ -39,4 +40,8 @@ get_uuid(char *temp) #error No uuid function specified #endif memcpy(temp, s, 37); + + // XXX: Freeing s only works if you HAVE_UUID_GENERATE + // Otherwise use rpc_string_free (?) + free(s); }