diff --git a/src/cjson.c b/src/cjson.c index f75407d..7a3a4f4 100644 --- a/src/cjson.c +++ b/src/cjson.c @@ -132,7 +132,7 @@ static double ipow( double n, int exp ) /* Parse the input text to generate a number, and populate the result into item. */ static const char *parse_number( cJSON *item, const char *num ) { - long long i = 0; + int64_t i = 0; double f = 0; int isint = 1; int sign = 1, scale = 0, subscale = 0, signsubscale = 1; @@ -930,7 +930,7 @@ cJSON *cJSON_CreateBool( int b ) return item; } -cJSON *cJSON_CreateInt( long long num ) +cJSON *cJSON_CreateInt( int64_t num ) { cJSON *item = cJSON_New_Item(); if ( item ) { @@ -981,7 +981,7 @@ cJSON *cJSON_CreateObject( void ) /* Create Arrays. */ -cJSON *cJSON_CreateIntArray( long long *numbers, int count ) +cJSON *cJSON_CreateIntArray( int64_t *numbers, int count ) { int i; cJSON *n = 0, *p = 0, *a = cJSON_CreateArray(); diff --git a/src/cjson.h b/src/cjson.h index e86629f..d4449e6 100644 --- a/src/cjson.h +++ b/src/cjson.h @@ -47,7 +47,7 @@ typedef struct cJSON { int type; /* The type of the item, as above. */ char *valuestring; /* The item's string, if type==cJSON_String */ - long long valueint; /* The item's number, if type==cJSON_Number */ + int64_t valueint; /* The item's number, if type==cJSON_Number */ double valuefloat; /* The item's number, if type==cJSON_Number */ char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ @@ -86,14 +86,14 @@ extern cJSON *cJSON_CreateNull( void ); extern cJSON *cJSON_CreateTrue( void ); extern cJSON *cJSON_CreateFalse( void ); extern cJSON *cJSON_CreateBool( int b ); -extern cJSON *cJSON_CreateInt( long long num ); +extern cJSON *cJSON_CreateInt( int64_t num ); extern cJSON *cJSON_CreateFloat( double num ); extern cJSON *cJSON_CreateString( const char *string ); extern cJSON *cJSON_CreateArray( void ); extern cJSON *cJSON_CreateObject( void ); /* These utilities create an Array of count items. */ -extern cJSON *cJSON_CreateIntArray( long long *numbers, int count ); +extern cJSON *cJSON_CreateIntArray( int64_t *numbers, int count ); extern cJSON *cJSON_CreateFloatArray( double *numbers, int count ); extern cJSON *cJSON_CreateStringArray( const char **strings, int count ); diff --git a/src/iperf.h b/src/iperf.h index 74e41dc..f6a17f5 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -15,6 +15,7 @@ #include #include #include +#include "timer.h" #include "queue.h" typedef uint64_t iperf_size_t; @@ -76,7 +77,8 @@ struct iperf_stream /* non configurable members */ struct iperf_stream_result *result; /* structure pointer to result */ - struct timer *send_timer; + Timer *send_timer; + int udp_green_light; char *buffer; /* data to send */ /* @@ -149,9 +151,10 @@ struct iperf_test double reporter_interval; void (*stats_callback) (struct iperf_test *); void (*reporter_callback) (struct iperf_test *); - struct timer *timer; - struct timer *stats_timer; - struct timer *reporter_timer; + Timer *timer; + int done; + Timer *stats_timer; + Timer *reporter_timer; double cpu_util; /* cpu utilization of the test */ double remote_cpu_util; /* cpu utilization for the remote host/client */ diff --git a/src/iperf_api.c b/src/iperf_api.c index 4ceb1d7..a82f49f 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -228,7 +228,7 @@ get_protocol(struct iperf_test *test, int prot_id) if (prot == NULL) i_errno = IEPROTOCOL; - return (prot); + return prot; } int @@ -239,13 +239,13 @@ set_protocol(struct iperf_test *test, int prot_id) SLIST_FOREACH(prot, &test->protocols, protocols) { if (prot->id == prot_id) { test->protocol = prot; - return (0); + return 0; } } i_errno = IEPROTOCOL; - return (-1); + return -1; } @@ -312,9 +312,6 @@ iperf_on_connect(struct iperf_test *test) void iperf_on_test_finish(struct iperf_test *test) { - if (test->verbose) { - printf("Test Complete. Summary Results:\n"); - } } @@ -364,7 +361,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'c': if (test->role == 's') { i_errno = IESERVCLIENT; - return (-1); + return -1; } else { test->role = 'c'; test->server_hostname = (char *) malloc(strlen(optarg)+1); @@ -377,7 +374,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 's': if (test->role == 'c') { i_errno = IESERVCLIENT; - return (-1); + return -1; } else { test->role = 's'; } @@ -385,12 +382,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 't': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->duration = atoi(optarg); if (test->duration > MAX_TIME) { i_errno = IEDURATION; - return (-1); + return -1; } break; case 'u': @@ -398,7 +395,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) warning("ignoring client only argument --udp (-u)"); /* XXX: made a warning i_errno = IECLIENTONLY; - return (-1); + return -1; */ } set_protocol(test, Pudp); @@ -407,12 +404,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'P': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->num_streams = atoi(optarg); if (test->num_streams > MAX_STREAMS) { i_errno = IENUMSTREAMS; - return (-1); + return -1; } break; case 'B': @@ -422,31 +419,31 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'b': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->settings->rate = unit_atof(optarg); break; case 'l': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->settings->blksize = unit_atoi(optarg); if (test->settings->blksize > MAX_BLOCKSIZE) { i_errno = IEBLOCKSIZE; - return (-1); + return -1; } break; case 'w': // XXX: This is a socket buffer, not specific to TCP if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->settings->socket_bufsize = unit_atof(optarg); if (test->settings->socket_bufsize > MAX_TCP_BUFFER) { i_errno = IEBUFSIZE; - return (-1); + return -1; } break; case 'i': @@ -456,32 +453,32 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) test->reporter_interval = atof(optarg); if (test->stats_interval > MAX_INTERVAL) { i_errno = IEINTERVAL; - return (-1); + return -1; } break; case 'n': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->settings->bytes = unit_atoi(optarg); break; case 'N': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->no_delay = 1; break; case 'M': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->settings->mss = atoi(optarg); if (test->settings->mss > MAX_MSS) { i_errno = IEMSS; - return (-1); + return -1; } break; case 'f': @@ -499,14 +496,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) case 'R': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } test->reverse = 1; break; case 'S': if (test->role == 's') { i_errno = IECLIENTONLY; - return (-1); + return -1; } // XXX: Checking for errors in strtol is not portable. Leave as is? test->settings->tos = strtol(optarg, NULL, 0); @@ -529,14 +526,14 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) if ((test->role != 'c') && (test->role != 's')) { i_errno = IENOROLE; - return (-1); + return -1; } if (test->verbose) { fputs(version, stdout); system("uname -a"); } - return (0); + return 0; } int @@ -544,11 +541,11 @@ all_data_sent(struct iperf_test * test) { if (test->settings->bytes > 0) { if (test->bytes_sent >= (test->num_streams * test->settings->bytes)) { - return (1); + return 1; } } - return (0); + return 0; } int @@ -567,14 +564,14 @@ iperf_send(struct iperf_test *test) result = select(test->max_fd + 1, NULL, &temp_write_set, NULL, &tv); if (result < 0 && errno != EINTR) { i_errno = IESELECT; - return (-1); + return -1; } if (result > 0) { SLIST_FOREACH(sp, &test->streams, streams) { if (FD_ISSET(sp->socket, &temp_write_set)) { if ((bytes_sent = sp->snd(sp)) < 0) { i_errno = IESTREAMWRITE; - return (-1); + return -1; } test->bytes_sent += bytes_sent; FD_CLR(sp->socket, &temp_write_set); @@ -582,7 +579,7 @@ iperf_send(struct iperf_test *test) } } - return (0); + return 0; } int @@ -601,14 +598,14 @@ iperf_recv(struct iperf_test *test) result = select(test->max_fd + 1, &temp_read_set, NULL, NULL, &tv); if (result < 0) { i_errno = IESELECT; - return (-1); + return -1; } if (result > 0) { SLIST_FOREACH(sp, &test->streams, streams) { if (FD_ISSET(sp->socket, &temp_read_set)) { if ((bytes_sent = sp->rcv(sp)) < 0) { i_errno = IESTREAMREAD; - return (-1); + return -1; } test->bytes_sent += bytes_sent; FD_CLR(sp->socket, &temp_read_set); @@ -616,55 +613,84 @@ iperf_recv(struct iperf_test *test) } } - return (0); + 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); } int iperf_init_test(struct iperf_test *test) { struct iperf_stream *sp; - time_t sec; - time_t usec; + struct timeval now; + TimerClientData cd; if (test->protocol->init) { if (test->protocol->init(test) < 0) - return (-1); + return -1; } - /* Set timers */ + /* Create timers. */ + if (gettimeofday(&now, NULL) < 0) { + i_errno = IEINITTEST; + return -1; + } if (test->settings->bytes == 0) { - test->timer = new_timer(test->duration, 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) - return (-1); + return -1; } if (test->stats_interval != 0) { - sec = (time_t) test->stats_interval; - usec = (test->stats_interval - sec) * SEC_TO_US; - test->stats_timer = new_timer(sec, usec); + 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) - return (-1); + return -1; } if (test->reporter_interval != 0) { - sec = (time_t) test->reporter_interval; - usec = (test->reporter_interval - sec) * SEC_TO_US; - test->reporter_timer = new_timer(sec, usec); + 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) - return (-1); + return -1; } /* Set start time */ - SLIST_FOREACH(sp, &test->streams, streams) { - if (gettimeofday(&sp->result->start_time, NULL) < 0) { - i_errno = IEINITTEST; - return (-1); - } - } + SLIST_FOREACH(sp, &test->streams, streams) + sp->result->start_time = now; if (test->on_test_start) test->on_test_start(test); - return (0); + return 0; } /** @@ -681,30 +707,30 @@ iperf_exchange_parameters(struct iperf_test * test) if (test->role == 'c') { if (send_parameters(test) < 0) - return (-1); + return -1; } else { if (get_parameters(test) < 0) - return (-1); + 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; - return (-1); + return -1; } msg = htonl(i_errno); if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) { i_errno = IECTRLWRITE; - return (-1); + return -1; } msg = htonl(errno); if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) { i_errno = IECTRLWRITE; - return (-1); + return -1; } - return (-1); + return -1; } FD_SET(s, &test->read_set); test->max_fd = (s > test->max_fd) ? s : test->max_fd; @@ -714,12 +740,12 @@ iperf_exchange_parameters(struct iperf_test * test) test->state = CREATE_STREAMS; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } } - return (0); + return 0; } /*************************************************************/ @@ -1073,7 +1099,7 @@ iperf_new_test() test = (struct iperf_test *) malloc(sizeof(struct iperf_test)); if (!test) { i_errno = IENEWTEST; - return (NULL); + return NULL; } /* initialize everything to zero */ memset(test, 0, sizeof(struct iperf_test)); @@ -1081,7 +1107,7 @@ iperf_new_test() test->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings)); memset(test->settings, 0, sizeof(struct iperf_settings)); - return (test); + return test; } /**************************************************************************/ @@ -1116,11 +1142,11 @@ iperf_defaults(struct iperf_test * testp) struct protocol *tcp, *udp; tcp = (struct protocol *) malloc(sizeof(struct protocol)); if (!tcp) - return (-1); + return -1; memset(tcp, 0, sizeof(struct protocol)); udp = (struct protocol *) malloc(sizeof(struct protocol)); if (!udp) - return (-1); + return -1; memset(udp, 0, sizeof(struct protocol)); tcp->id = Ptcp; @@ -1150,7 +1176,7 @@ iperf_defaults(struct iperf_test * testp) testp->on_connect = iperf_on_connect; testp->on_test_finish = iperf_on_test_finish; - return (0); + return 0; } @@ -1171,9 +1197,12 @@ iperf_free_test(struct iperf_test * test) free(test->server_hostname); free(test->bind_address); free(test->settings); - free_timer(test->timer); - free_timer(test->stats_timer); - free_timer(test->reporter_timer); + if (test->timer != NULL) + tmr_cancel(test->timer); + if (test->stats_timer != NULL) + tmr_cancel(test->stats_timer); + if (test->reporter_timer != NULL) + tmr_cancel(test->reporter_timer); /* Free protocol list */ while (!SLIST_EMPTY(&test->protocols)) { @@ -1201,12 +1230,18 @@ iperf_reset_test(struct iperf_test *test) SLIST_REMOVE_HEAD(&test->streams, streams); iperf_free_stream(sp); } - free_timer(test->timer); - free_timer(test->stats_timer); - free_timer(test->reporter_timer); - test->timer = NULL; - test->stats_timer = NULL; - test->reporter_timer = NULL; + if (test->timer != NULL) { + tmr_cancel(test->timer); + test->timer = NULL; + } + if (test->stats_timer != NULL) { + tmr_cancel(test->stats_timer); + test->stats_timer = NULL; + } + if (test->reporter_timer != NULL) { + tmr_cancel(test->reporter_timer); + test->reporter_timer = NULL; + } SLIST_INIT(&test->streams); @@ -1303,6 +1338,10 @@ iperf_print_intermediate(struct iperf_test *test) print_interval_results(test, sp); /* sum up all streams */ irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); + if (irp == NULL) { + printf("iperf_print_intermediate Error: interval_results is NULL \n"); + return; + } bytes += irp->bytes_transferred; if (test->protocol->id == Ptcp && has_tcpinfo_retransmits()) retransmits += irp->this_retrans; @@ -1330,7 +1369,7 @@ iperf_print_intermediate(struct iperf_test *test) } static void -iperf_print_results (struct iperf_test *test) +iperf_print_results(struct iperf_test *test) { long retransmits = 0, total_retransmits = 0; @@ -1344,6 +1383,8 @@ iperf_print_results (struct iperf_test *test) /* print final summary for all intervals */ + if (test->verbose) + printf("Test Complete. Summary Results:\n"); if (test->protocol->id == Ptcp) if (has_tcpinfo_retransmits()) fputs(report_bw_retrans_header, stdout); @@ -1464,7 +1505,7 @@ print_interval_results(struct iperf_test * test, struct iperf_stream * sp) 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"); + printf("print_interval_results Error: interval_results is NULL \n"); return; } /* First stream? */ @@ -1508,7 +1549,8 @@ iperf_free_stream(struct iperf_stream * sp) free(irp); } free(sp->result); - free(sp->send_timer); + if (sp->send_timer != NULL) + tmr_cancel(sp->send_timer); free(sp); } @@ -1522,7 +1564,7 @@ iperf_new_stream(struct iperf_test *test, int s) sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream)); if (!sp) { i_errno = IECREATESTREAM; - return (NULL); + return NULL; } memset(sp, 0, sizeof(struct iperf_stream)); @@ -1533,11 +1575,11 @@ iperf_new_stream(struct iperf_test *test, int s) if (!sp->buffer) { i_errno = IECREATESTREAM; - return (NULL); + return NULL; } if (!sp->result) { i_errno = IECREATESTREAM; - return (NULL); + return NULL; } memset(sp->result, 0, sizeof(struct iperf_stream_result)); @@ -1556,10 +1598,10 @@ iperf_new_stream(struct iperf_test *test, int s) /* Initialize stream */ if (iperf_init_stream(sp, test) < 0) - return (NULL); + return NULL; iperf_add_stream(test, sp); - return (sp); + return sp; } /**************************************************************************/ @@ -1572,12 +1614,12 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) len = sizeof(struct sockaddr_storage); if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) { i_errno = IEINITSTREAM; - return (-1); + return -1; } len = sizeof(struct sockaddr_storage); if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) { i_errno = IEINITSTREAM; - return (-1); + return -1; } /* Set IP TOS */ if ((opt = test->settings->tos)) { @@ -1585,21 +1627,21 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test) #ifdef IPV6_TCLASS if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) { i_errno = IESETCOS; - return (-1); + return -1; } #else i_errno = IESETCOS; - return (-1); + return -1; #endif } else { if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) { i_errno = IESETTOS; - return (-1); + return -1; } } } - return (0); + return 0; } /**************************************************************************/ diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index c065b1d..b90480f 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -33,7 +33,7 @@ iperf_create_streams(struct iperf_test *test) for (i = 0; i < test->num_streams; ++i) { if ((s = test->protocol->connect(test)) < 0) - return (-1); + return -1; FD_SET(s, &test->read_set); FD_SET(s, &test->write_set); @@ -41,14 +41,14 @@ iperf_create_streams(struct iperf_test *test) sp = iperf_new_stream(test, s); if (!sp) - return (-1); + return -1; /* Perform the new stream callback */ if (test->on_new_stream) test->on_new_stream(sp); } - return (0); + return 0; } int @@ -59,36 +59,36 @@ iperf_handle_message_client(struct iperf_test *test) if ((rval = read(test->ctrl_sck, &test->state, sizeof(char))) <= 0) { if (rval == 0) { i_errno = IECTRLCLOSE; - return (-1); + return -1; } else { i_errno = IERECVMESSAGE; - return (-1); + return -1; } } switch (test->state) { case PARAM_EXCHANGE: if (iperf_exchange_parameters(test) < 0) { - return (-1); + return -1; } if (test->on_connect) test->on_connect(test); break; case CREATE_STREAMS: if (iperf_create_streams(test) < 0) { - return (-1); + return -1; } break; case TEST_START: if (iperf_init_test(test) < 0) { - return (-1); + return -1; } break; case TEST_RUNNING: break; case EXCHANGE_RESULTS: if (iperf_exchange_results(test) < 0) { - return (-1); + return -1; } break; case DISPLAY_RESULTS: @@ -100,28 +100,28 @@ iperf_handle_message_client(struct iperf_test *test) break; case SERVER_TERMINATE: i_errno = IESERVERTERM; - return (-1); + return -1; case ACCESS_DENIED: i_errno = IEACCESSDENIED; - return (-1); + return -1; case SERVER_ERROR: if (Nread(test->ctrl_sck, &i_errno, sizeof(i_errno), Ptcp) < 0) { i_errno = IECTRLREAD; - return (-1); + return -1; } i_errno = ntohl(i_errno); if (Nread(test->ctrl_sck, &perr, sizeof(perr), Ptcp) < 0) { i_errno = IECTRLREAD; - return (-1); + return -1; } errno = ntohl(perr); - return (-1); + return -1; default: i_errno = IEMESSAGE; - return (-1); + return -1; } - return (0); + return 0; } @@ -139,19 +139,19 @@ iperf_connect(struct iperf_test *test) test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->server_hostname, test->server_port); if (test->ctrl_sck < 0) { i_errno = IECONNECT; - return (-1); + return -1; } if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IESENDCOOKIE; - return (-1); + return -1; } FD_SET(test->ctrl_sck, &test->read_set); FD_SET(test->ctrl_sck, &test->write_set); test->max_fd = (test->ctrl_sck > test->max_fd) ? test->ctrl_sck : test->max_fd; - return (0); + return 0; } @@ -171,10 +171,10 @@ iperf_client_end(struct iperf_test *test) test->state = IPERF_DONE; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } - return (0); + return 0; } @@ -183,32 +183,31 @@ iperf_run_client(struct iperf_test * test) { int result; fd_set temp_read_set, temp_write_set; - struct timeval tv; - time_t sec, usec; + struct timeval now; /* Start the client and connect to the server */ if (iperf_connect(test) < 0) { - return (-1); + return -1; } // Begin calculating CPU utilization cpu_util(NULL); + (void) gettimeofday(&now, NULL); while (test->state != IPERF_DONE) { 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, &temp_read_set, &temp_write_set, NULL, &tv); + result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, tmr_timeout(&now)); if (result < 0 && errno != EINTR) { i_errno = IESELECT; - return (-1); - } else if (result > 0) { + return -1; + } + if (result > 0) { if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { if (iperf_handle_message_client(test) < 0) { - return (-1); + return -1; } FD_CLR(test->ctrl_sck, &temp_read_set); } @@ -217,46 +216,32 @@ iperf_run_client(struct iperf_test * test) if (test->reverse) { // Reverse mode. Client receives. if (iperf_recv(test) < 0) { - return (-1); + return -1; } } else { // Regular mode. Client sends. if (iperf_send(test) < 0) { - return (-1); + return -1; } } - /* Perform callbacks */ - if (timer_expired(test->stats_timer)) { - test->stats_callback(test); - sec = (time_t) test->stats_interval; - usec = (test->stats_interval - sec) * SEC_TO_US; - if (update_timer(test->stats_timer, sec, usec) < 0) { - return (-1); - } - } - if (timer_expired(test->reporter_timer)) { - test->reporter_callback(test); - sec = (time_t) test->reporter_interval; - usec = (test->reporter_interval - sec) * SEC_TO_US; - if (update_timer(test->reporter_timer, sec, usec) < 0) { - return (-1); - } - } + /* Run the timers. */ + (void) gettimeofday(&now, NULL); + tmr_run(&now); /* Send TEST_END if all data has been sent or timer expired */ - if (all_data_sent(test) || timer_expired(test->timer)) { + if (all_data_sent(test) || test->done) { 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; - return (-1); + return -1; } } } } } - return (0); + return 0; } diff --git a/src/iperf_error.c b/src/iperf_error.c index 1528c8b..fad4534 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -232,7 +232,7 @@ iperf_strerror(int i_errno) strncat(errstr, strerror(errno), len); } - return (errstr); + return errstr; } void diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index 0c73c9c..cd301d3 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -49,7 +49,7 @@ iperf_server_listen(struct iperf_test *test) { if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { i_errno = IELISTEN; - return (-1); + return -1; } printf("-----------------------------------------------------------\n"); @@ -101,14 +101,14 @@ iperf_accept(struct iperf_test *test) len = sizeof(addr); if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { i_errno = IEACCEPT; - return (-1); + return -1; } if (test->ctrl_sck == -1) { /* Server free, accept new client */ if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IERECVCOOKIE; - return (-1); + return -1; } FD_SET(s, &test->read_set); @@ -119,10 +119,10 @@ iperf_accept(struct iperf_test *test) test->state = PARAM_EXCHANGE; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } if (iperf_exchange_parameters(test) < 0) { - return (-1); + return -1; } if (test->on_connect) { test->on_connect(test); @@ -131,16 +131,16 @@ iperf_accept(struct iperf_test *test) // XXX: Do we even need to receive cookie if we're just going to deny anyways? if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IERECVCOOKIE; - return (-1); + return -1; } if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } close(s); } - return (0); + return 0; } @@ -157,10 +157,10 @@ iperf_handle_message_server(struct iperf_test *test) fprintf(stderr, "The client has unexpectedly closed the connection.\n"); i_errno = IECTRLCLOSE; test->state = IPERF_DONE; - return (0); + return 0; } else { i_errno = IERECVMESSAGE; - return (-1); + return -1; } } @@ -178,14 +178,14 @@ iperf_handle_message_server(struct iperf_test *test) test->state = EXCHANGE_RESULTS; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } if (iperf_exchange_results(test) < 0) - return (-1); + return -1; test->state = DISPLAY_RESULTS; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } if (test->on_test_finish) test->on_test_finish(test); @@ -207,10 +207,10 @@ iperf_handle_message_server(struct iperf_test *test) break; default: i_errno = IEMESSAGE; - return (-1); + return -1; } - return (0); + return 0; } /* XXX: This function is not used anymore */ @@ -227,12 +227,18 @@ iperf_test_reset(struct iperf_test *test) SLIST_REMOVE_HEAD(&test->streams, streams); iperf_free_stream(sp); } - free_timer(test->timer); - free_timer(test->stats_timer); - free_timer(test->reporter_timer); - test->timer = NULL; - test->stats_timer = NULL; - test->reporter_timer = NULL; + if (test->timer != NULL) { + tmr_cancel(test->timer); + test->timer = NULL; + } + if (test->stats_timer != NULL) { + tmr_cancel(test->stats_timer); + test->stats_timer = NULL; + } + if (test->reporter_timer != NULL) { + tmr_cancel(test->reporter_timer); + test->reporter_timer = NULL; + } SLIST_INIT(&test->streams); @@ -269,12 +275,11 @@ iperf_run_server(struct iperf_test *test) int result, s, streams_accepted; fd_set temp_read_set, temp_write_set; struct iperf_stream *sp; - struct timeval tv; - time_t sec, usec; + struct timeval now; // Open socket and listen if (iperf_server_listen(test) < 0) { - return (-1); + return -1; } // Begin calculating CPU utilization @@ -283,29 +288,29 @@ iperf_run_server(struct iperf_test *test) test->state = IPERF_START; streams_accepted = 0; + (void) gettimeofday(&now, NULL); while (test->state != IPERF_DONE) { 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, &temp_read_set, &temp_write_set, NULL, &tv); + result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, tmr_timeout(&now)); if (result < 0 && errno != EINTR) { i_errno = IESELECT; - return (-1); - } else if (result > 0) { + return -1; + } + if (result > 0) { if (FD_ISSET(test->listener, &temp_read_set)) { if (test->state != CREATE_STREAMS) { if (iperf_accept(test) < 0) { - return (-1); + return -1; } FD_CLR(test->listener, &temp_read_set); } } if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { if (iperf_handle_message_server(test) < 0) - return (-1); + return -1; FD_CLR(test->ctrl_sck, &temp_read_set); } @@ -313,12 +318,12 @@ iperf_run_server(struct iperf_test *test) if (FD_ISSET(test->prot_listener, &temp_read_set)) { if ((s = test->protocol->accept(test)) < 0) - return (-1); + return -1; if (!is_closed(s)) { sp = iperf_new_stream(test, s); if (!sp) - return (-1); + return -1; FD_SET(s, &test->read_set); FD_SET(s, &test->write_set); @@ -341,7 +346,7 @@ iperf_run_server(struct iperf_test *test) close(test->listener); if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { i_errno = IELISTEN; - return (-1); + return -1; } test->listener = s; test->max_fd = (s > test->max_fd ? s : test->max_fd); @@ -352,14 +357,14 @@ iperf_run_server(struct iperf_test *test) test->state = TEST_START; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } if (iperf_init_test(test) < 0) - return (-1); + return -1; test->state = TEST_RUNNING; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } } } @@ -368,28 +373,16 @@ iperf_run_server(struct iperf_test *test) if (test->reverse) { // Reverse mode. Server sends. if (iperf_send(test) < 0) - return (-1); + return -1; } else { // Regular mode. Server receives. if (iperf_recv(test) < 0) - return (-1); + return -1; } - /* Perform callbacks */ - if (timer_expired(test->stats_timer)) { - test->stats_callback(test); - sec = (time_t) test->stats_interval; - usec = (test->stats_interval - sec) * SEC_TO_US; - if (update_timer(test->stats_timer, sec, usec) < 0) - return (-1); - } - if (timer_expired(test->reporter_timer)) { - test->reporter_callback(test); - sec = (time_t) test->reporter_interval; - usec = (test->reporter_interval - sec) * SEC_TO_US; - if (update_timer(test->reporter_timer, sec, usec) < 0) - return (-1); - } + /* Run the timers. */ + (void) gettimeofday(&now, NULL); + tmr_run(&now); } } } @@ -398,5 +391,5 @@ iperf_run_server(struct iperf_test *test) close(test->ctrl_sck); close(test->listener); - return (0); + return 0; } diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index 891c989..7f65642 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -39,13 +39,13 @@ iperf_tcp_recv(struct iperf_stream *sp) result = Nread(sp->socket, sp->buffer, size, Ptcp); if (result < 0) { - return (-1); + return -1; } sp->result->bytes_received += result; sp->result->bytes_received_this_interval += result; - return (result); + return result; } @@ -62,13 +62,13 @@ iperf_tcp_send(struct iperf_stream *sp) result = Nwrite(sp->socket, sp->buffer, size, Ptcp); if (result < 0) { - return (-1); + return -1; } sp->result->bytes_sent += result; sp->result->bytes_sent_this_interval += result; - return (result); + return result; } @@ -88,23 +88,23 @@ iperf_tcp_accept(struct iperf_test * test) len = sizeof(addr); if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IERECVCOOKIE; - return (-1); + return -1; } if (strcmp(test->cookie, cookie) != 0) { if (Nwrite(s, &rbuf, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } close(s); } - return (s); + return s; } @@ -125,36 +125,36 @@ iperf_tcp_listen(struct iperf_test *test) close(s); if ((s = socket(test->settings->domain, SOCK_STREAM, 0)) < 0) { i_errno = IESTREAMLISTEN; - return (-1); + return -1; } if (test->no_delay) { opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { i_errno = IESETNODELAY; - return (-1); + return -1; } } // XXX: Setting MSS is very buggy! if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { i_errno = IESETMSS; - return (-1); + return -1; } } if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { i_errno = IESETBUF; - return (-1); + return -1; } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { i_errno = IESETBUF; - return (-1); + return -1; } } opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { i_errno = IEREUSEADDR; - return (-1); + return -1; } snprintf(portstr, 6, "%d", test->server_port); @@ -165,26 +165,26 @@ iperf_tcp_listen(struct iperf_test *test) // XXX: Check getaddrinfo for errors! if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) { i_errno = IESTREAMLISTEN; - return (-1); + return -1; } if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { close(s); i_errno = IESTREAMLISTEN; - return (-1); + return -1; } freeaddrinfo(res); if (listen(s, 5) < 0) { i_errno = IESTREAMLISTEN; - return (-1); + return -1; } test->listener = s; } - return (s); + return s; } @@ -201,7 +201,7 @@ iperf_tcp_connect(struct iperf_test *test) if ((s = socket(test->settings->domain, SOCK_STREAM, 0)) < 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } if (test->bind_address) { @@ -211,12 +211,12 @@ iperf_tcp_connect(struct iperf_test *test) // XXX: Check getaddrinfo for errors! if (getaddrinfo(test->bind_address, NULL, &hints, &res) != 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } freeaddrinfo(res); @@ -227,23 +227,23 @@ iperf_tcp_connect(struct iperf_test *test) opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { i_errno = IESETNODELAY; - return (-1); + return -1; } } if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { i_errno = IESETMSS; - return (-1); + return -1; } } if ((opt = test->settings->socket_bufsize)) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { i_errno = IESETBUF; - return (-1); + return -1; } if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { i_errno = IESETBUF; - return (-1); + return -1; } } @@ -254,12 +254,12 @@ iperf_tcp_connect(struct iperf_test *test) // XXX: Check getaddrinfo for errors! if (getaddrinfo(test->server_hostname, portstr, &hints, &res) != 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } freeaddrinfo(res); @@ -267,9 +267,9 @@ iperf_tcp_connect(struct iperf_test *test) /* Send cookie for verification */ if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IESENDCOOKIE; - return (-1); + return -1; } - return (s); + return s; } diff --git a/src/iperf_udp.c b/src/iperf_udp.c index 733cc1d..f744907 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -44,7 +44,7 @@ iperf_udp_recv(struct iperf_stream *sp) result = Nread(sp->socket, sp->buffer, size, Pudp); if (result < 0) { - return (-1); + return -1; } sp->result->bytes_received += result; @@ -82,7 +82,21 @@ iperf_udp_recv(struct iperf_stream *sp) // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] sp->jitter += (d - sp->jitter) / 16.0; - return (result); + return result; +} + + +static void +send_timer_proc(TimerClientData client_data, struct timeval* nowP) +{ + struct iperf_stream *sp = client_data.p; + + /* All we do here is set a flag saying that this UDP stream may be sent + ** to. The actual sending gets done in iperf_udp_send(), which then + ** resets the flag and makes a new adjusted timer. + */ + sp->send_timer = NULL; + sp->udp_green_light = 1; } @@ -95,18 +109,13 @@ iperf_udp_send(struct iperf_stream *sp) { ssize_t result = 0; int64_t dtargus; - int64_t adjustus = 0; + int64_t adjustus; uint64_t sec, usec, pcount; int size = sp->settings->blksize; struct timeval before, after; + TimerClientData cd; - if (timer_expired(sp->send_timer)) { - - dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; - dtargus /= sp->settings->rate; - - assert(dtargus != 0); - + if (sp->udp_green_light) { gettimeofday(&before, 0); ++sp->packet_count; @@ -121,26 +130,31 @@ iperf_udp_send(struct iperf_stream *sp) result = Nwrite(sp->socket, sp->buffer, size, Pudp); if (result < 0) - return (-1); + return -1; sp->result->bytes_sent += result; sp->result->bytes_sent_this_interval += result; - gettimeofday(&after, 0); - - adjustus = dtargus; - adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; - adjustus += (before.tv_usec - after.tv_usec); - - if (adjustus > 0) { - dtargus = adjustus; - } - - if (update_timer(sp->send_timer, 0, dtargus) < 0) - return (-1); + if (sp->settings->rate != 0) { + gettimeofday(&after, 0); + dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; + dtargus /= sp->settings->rate; + assert(dtargus != 0); + adjustus = dtargus; + adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; + adjustus += (before.tv_usec - after.tv_usec); + if (adjustus > 0) { + dtargus = adjustus; + } + cd.p = sp; + sp->udp_green_light = 0; + sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, dtargus, 0); + if (sp->send_timer == NULL) + return -1; + } } - return (result); + return result; } @@ -163,18 +177,18 @@ iperf_udp_accept(struct iperf_test *test) len = sizeof sa_peer; if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { i_errno = IESTREAMACCEPT; - return (-1); + return -1; } if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { i_errno = IESTREAMACCEPT; - return (-1); + return -1; } test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); if (test->prot_listener < 0) { i_errno = IESTREAMLISTEN; - return (-1); + return -1; } FD_SET(test->prot_listener, &test->read_set); @@ -183,10 +197,10 @@ iperf_udp_accept(struct iperf_test *test) /* Let the client know we're ready "accept" another UDP "stream" */ if (write(s, &buf, sizeof(buf)) < 0) { i_errno = IESTREAMWRITE; - return (-1); + return -1; } - return (s); + return s; } @@ -201,10 +215,10 @@ iperf_udp_listen(struct iperf_test *test) if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { i_errno = IESTREAMLISTEN; - return (-1); + return -1; } - return (s); + return s; } @@ -219,23 +233,23 @@ iperf_udp_connect(struct iperf_test *test) if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->server_hostname, test->server_port)) < 0) { i_errno = IESTREAMCONNECT; - return (-1); + return -1; } /* Write to the UDP stream to give the server this stream's credentials */ if (write(s, &buf, sizeof(buf)) < 0) { // XXX: Should this be changed to IESTREAMCONNECT? i_errno = IESTREAMWRITE; - return (-1); + return -1; } /* Wait until the server confirms the client UDP write */ // XXX: Should this read be TCP instead? if (read(s, &buf, sizeof(buf)) < 0) { i_errno = IESTREAMREAD; - return (-1); + return -1; } - return (s); + return s; } @@ -248,19 +262,27 @@ iperf_udp_init(struct iperf_test *test) { int64_t dtargus; struct iperf_stream *sp; + TimerClientData cd; - /* Calculate the send delay needed to hit target bandwidth (-b) */ - dtargus = (int64_t) test->settings->blksize * SEC_TO_US * 8; - dtargus /= test->settings->rate; + if (test->settings->rate == 0) { + SLIST_FOREACH(sp, &test->streams, streams) { + sp->udp_green_light = 1; + } + } else { + /* Calculate the send delay needed to hit target bandwidth (-b) */ + dtargus = (int64_t) test->settings->blksize * SEC_TO_US * 8; + dtargus /= test->settings->rate; - assert(dtargus != 0); + assert(dtargus != 0); -// for (sp = test->streams; sp; sp = sp->next) { - SLIST_FOREACH(sp, &test->streams, streams) { - sp->send_timer = new_timer(dtargus / SEC_TO_US, dtargus % SEC_TO_US); - if (sp->send_timer == NULL) - return (-1); + SLIST_FOREACH(sp, &test->streams, streams) { + cd.p = sp; + sp->udp_green_light = 0; + sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, dtargus, 0); + if (sp->send_timer == NULL) + return -1; + } } - return (0); + return 0; } diff --git a/src/iperf_util.c b/src/iperf_util.c index bfbc939..1795d03 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -78,9 +78,9 @@ is_closed(int fd) if (select(fd+1, &readset, NULL, NULL, &tv) < 0) { if (errno == EBADF) - return (1); + return 1; } - return (0); + return 0; } @@ -114,7 +114,7 @@ timeval_diff(struct timeval * tv0, struct timeval * tv1) time1 = time1 - time2; if (time1 < 0) time1 = -time1; - return (time1); + return time1; } @@ -149,7 +149,7 @@ delay(int us) tv.tv_sec = 0; tv.tv_usec = us; (void) select(1, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv); - return (1); + return 1; } #endif diff --git a/src/main.c b/src/main.c index 808b1c9..a8bb24d 100644 --- a/src/main.c +++ b/src/main.c @@ -87,7 +87,7 @@ main(int argc, char **argv) test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; - return (-1); + return -1; } } exit(1); @@ -109,7 +109,7 @@ main(int argc, char **argv) printf("\niperf Done.\n"); - return (0); + return 0; } /**************************************************************************/ @@ -137,6 +137,6 @@ iperf_run(struct iperf_test * test) break; } - return (0); + return 0; } diff --git a/src/net.c b/src/net.c index bf98daf..4b7f695 100644 --- a/src/net.c +++ b/src/net.c @@ -37,7 +37,7 @@ netdial(int domain, int proto, char *local, char *server, int port) s = socket(domain, proto, 0); if (s < 0) { - return (-1); + return -1; } if (local) { @@ -47,10 +47,10 @@ netdial(int domain, int proto, char *local, char *server, int port) // XXX: Check getaddrinfo for errors! if (getaddrinfo(local, NULL, &hints, &res) != 0) - return (-1); + return -1; if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) - return (-1); + return -1; freeaddrinfo(res); } @@ -61,17 +61,17 @@ netdial(int domain, int proto, char *local, char *server, int port) // XXX: Check getaddrinfo for errors! if (getaddrinfo(server, NULL, &hints, &res) != 0) - return (-1); + return -1; ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(port); if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) { - return (-1); + return -1; } freeaddrinfo(res); - return (s); + return s; } /***************************************************************/ @@ -85,7 +85,7 @@ netannounce(int domain, int proto, char *local, int port) s = socket(domain, proto, 0); if (s < 0) { - return (-1); + return -1; } opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); @@ -97,22 +97,22 @@ netannounce(int domain, int proto, char *local, int port) hints.ai_flags = AI_PASSIVE; // XXX: Check getaddrinfo for errors! if (getaddrinfo(local, portstr, &hints, &res) != 0) - return (-1); + return -1; if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { close(s); - return (-1); + return -1; } freeaddrinfo(res); if (proto == SOCK_STREAM) { if (listen(s, 5) < 0) { - return (-1); + return -1; } } - return (s); + return s; } @@ -131,14 +131,14 @@ Nread(int fd, void *buf, int count, int prot) if (errno == EINTR) n = 0; else - return (-1); + return -1; } else if (n == 0) break; nleft -= n; buf += n; } - return (count - nleft); + return count - nleft; } @@ -166,7 +166,7 @@ Nwrite(int fd, void *buf, int count, int prot) delay(18000); // XXX: Fixme! n = 0; } else { - return (-1); + return -1; } } nleft -= n; @@ -178,13 +178,13 @@ Nwrite(int fd, void *buf, int count, int prot) if (errno == EINTR) n = 0; else - return (-1); + return -1; } nleft -= n; buf += n; } } - return (count); + return count; } /*************************************************************************/ diff --git a/src/t_timer.c b/src/t_timer.c index 47ca18b..936fec0 100644 --- a/src/t_timer.c +++ b/src/t_timer.c @@ -14,25 +14,42 @@ #include "timer.h" + +static int flag; + + +static void +timer_proc( TimerClientData client_data, struct timeval* nowP ) +{ + flag = 1; +} + + int main(int argc, char **argv) { - struct timer *tp; - tp = new_timer(3, 0); + struct Timer *tp; + + flag = 0; + tp = tmr_create((struct timeval*) 0, timer_proc, JunkClientData, 3000000, 0); sleep(2); - if (tp->expired(tp)) + tmr_run((struct timeval*) 0); + if (flag) { printf("timer should not have expired\n"); exit(-1); } sleep(1); - if (!tp->expired(tp)) + tmr_run((struct timeval*) 0); + if (!flag) { printf("timer should have expired\n"); exit(-2); } + + tmr_destroy(); exit(0); } diff --git a/src/timer.c b/src/timer.c index bc78485..eb1e7ed 100644 --- a/src/timer.c +++ b/src/timer.c @@ -5,104 +5,239 @@ * * This code is distributed under a BSD style license, see the LICENSE file * for complete information. + * + * Based on timers.c by Jef Poskanzer. Used with permission. */ -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include "timer.h" -#include "iperf_api.h" -int -timer_expired(struct timer * tp) +static Timer* timers = NULL; +static Timer* free_timers = NULL; + +TimerClientData JunkClientData; + + + +/* This is an efficiency tweak. All the routines that need to know the +** current time get passed a pointer to a struct timeval. If it's non-NULL +** it gets used, otherwise we do our own gettimeofday() to fill it in. +** This lets the caller avoid extraneous gettimeofday()s when efficiency +** is needed, and not bother with the extra code when efficiency doesn't +** matter too much. +*/ +static void +getnow( struct timeval* nowP, struct timeval* nowP2 ) { - if (tp == NULL) - return 0; + if ( nowP != NULL ) + *nowP2 = *nowP; + else + (void) gettimeofday( nowP2, NULL ); +} + +static void +list_add( Timer* t ) +{ + Timer* t2; + Timer* t2prev; + + if ( timers == NULL ) { + /* The list is empty. */ + timers = t; + t->prev = t->next = NULL; + } else { + if ( t->time.tv_sec < timers->time.tv_sec || + ( t->time.tv_sec == timers->time.tv_sec && + t->time.tv_usec < timers->time.tv_usec ) ) { + /* The new timer goes at the head of the list. */ + t->prev = NULL; + t->next = timers; + timers->prev = t; + timers = t; + } else { + /* Walk the list to find the insertion point. */ + for ( t2prev = timers, t2 = timers->next; t2 != NULL; + t2prev = t2, t2 = t2->next ) { + if ( t->time.tv_sec < t2->time.tv_sec || + ( t->time.tv_sec == t2->time.tv_sec && + t->time.tv_usec < t2->time.tv_usec ) ) { + /* Found it. */ + t2prev->next = t; + t->prev = t2prev; + t->next = t2; + t2->prev = t; + return; + } + } + /* Oops, got to the end of the list. Add to tail. */ + t2prev->next = t; + t->prev = t2prev; + t->next = NULL; + } + } +} + + +static void +list_remove( Timer* t ) +{ + if ( t->prev == NULL ) + timers = t->next; + else + t->prev->next = t->next; + if ( t->next != NULL ) + t->next->prev = t->prev; +} + + +static void +list_resort( Timer* t ) +{ + /* Remove the timer from the list. */ + list_remove( t ); + /* And add it back in, sorted correctly. */ + list_add( t ); +} + + +static void +add_usecs( struct timeval* t, int64_t usecs ) +{ + t->tv_sec += usecs / 1000000L; + t->tv_usec += usecs % 1000000L; + if ( t->tv_usec >= 1000000L ) { + t->tv_sec += t->tv_usec / 1000000L; + t->tv_usec %= 1000000L; + } +} + + +Timer* +tmr_create( + struct timeval* nowP, TimerProc* timer_proc, TimerClientData client_data, + int64_t usecs, int periodic ) +{ struct timeval now; - int64_t end = 0, current = 0; + Timer* t; - gettimeofday(&now, NULL); + getnow( nowP, &now ); - end += tp->end.tv_sec * 1000000; - end += tp->end.tv_usec; + if ( free_timers != NULL ) { + t = free_timers; + free_timers = t->next; + } else { + t = (Timer*) malloc( sizeof(Timer) ); + if ( t == NULL ) + return NULL; + } - current += now.tv_sec * 1000000; - current += now.tv_usec; + t->timer_proc = timer_proc; + t->client_data = client_data; + t->usecs = usecs; + t->periodic = periodic; + t->time = now; + add_usecs( &t->time, usecs ); + /* Add the new timer to the active list. */ + list_add( t ); - return current > end; + return t; } -int -update_timer(struct timer * tp, time_t sec, suseconds_t usec) + +struct timeval* +tmr_timeout( struct timeval* nowP ) { - if (gettimeofday(&tp->begin, NULL) < 0) { - i_errno = IEUPDATETIMER; - return (-1); - } + struct timeval now; + int64_t usecs; + static struct timeval timeout; - tp->end.tv_sec = tp->begin.tv_sec + (time_t) sec; - tp->end.tv_usec = tp->begin.tv_usec + (time_t) usec; - - tp->expired = timer_expired; - return (0); + getnow( nowP, &now ); + /* Since the list is sorted, we only need to look at the first timer. */ + if ( timers == NULL ) + return NULL; + usecs = ( timers->time.tv_sec - now.tv_sec ) * 1000000L + + ( timers->time.tv_usec - now.tv_usec ); + if ( usecs <= 0 ) + usecs = 0; + timeout.tv_sec = usecs / 1000000L; + timeout.tv_usec = usecs % 1000000L; + return &timeout; } -struct timer * -new_timer(time_t sec, suseconds_t usec) -{ - struct timer *tp = NULL; - tp = (struct timer *) calloc(1, sizeof(struct timer)); - if (tp == NULL) { - i_errno = IENEWTIMER; - return (NULL); - } - - if (gettimeofday(&tp->begin, NULL) < 0) { - i_errno = IENEWTIMER; - return (NULL); - } - - tp->end.tv_sec = tp->begin.tv_sec + (time_t) sec; - tp->end.tv_usec = tp->begin.tv_usec + (time_t) usec; - - tp->expired = timer_expired; - - return tp; -} void -free_timer(struct timer * tp) -{ - free(tp); -} - - -int64_t -timer_remaining(struct timer * tp) +tmr_run( struct timeval* nowP ) { struct timeval now; - long int end_time = 0, current_time = 0, diff = 0; + Timer* t; + Timer* next; - gettimeofday(&now, NULL); - - end_time += tp->end.tv_sec * 1000000; - end_time += tp->end.tv_usec; - - current_time += now.tv_sec * 1000000; - current_time += now.tv_usec; - - diff = end_time - current_time; - if (diff > 0) - return diff; - else - return 0; + getnow( nowP, &now ); + for ( t = timers; t != NULL; t = next ) { + next = t->next; + /* Since the list is sorted, as soon as we find a timer + ** that isn't ready yet, we are done. + */ + if ( t->time.tv_sec > now.tv_sec || + ( t->time.tv_sec == now.tv_sec && + t->time.tv_usec > now.tv_usec ) ) + break; + (t->timer_proc)( t->client_data, &now ); + if ( t->periodic ) { + /* Reschedule. */ + add_usecs( &t->time, t->usecs ); + list_resort( t ); + } else + tmr_cancel( t ); + } +} + + +void +tmr_reset( struct timeval* nowP, Timer* t ) +{ + struct timeval now; + + getnow( nowP, &now ); + t->time = now; + add_usecs( &t->time, t->usecs ); + list_resort( t ); +} + + +void +tmr_cancel( Timer* t ) +{ + /* Remove it from the active list. */ + list_remove( t ); + /* And put it on the free list. */ + t->next = free_timers; + free_timers = t; + t->prev = NULL; +} + + +void +tmr_cleanup( void ) +{ + Timer* t; + + while ( free_timers != NULL ) { + t = free_timers; + free_timers = t->next; + free( (void*) t ); + } +} + + +void +tmr_destroy( void ) +{ + while ( timers != NULL ) + tmr_cancel( timers ); + tmr_cleanup(); } diff --git a/src/timer.h b/src/timer.h index f154261..0d50d60 100644 --- a/src/timer.h +++ b/src/timer.h @@ -5,28 +5,75 @@ * * This code is distributed under a BSD style license, see the LICENSE file * for complete information. + * + * Based on timers.h by Jef Poskanzer. Used with permission. */ #ifndef __TIMER_H #define __TIMER_H -#include #include -struct timer { - struct timeval begin; - struct timeval end; - int (*expired)(struct timer *timer); -}; +/* TimerClientData is an opaque value that tags along with a timer. The +** client can use it for whatever, and it gets passed to the callback when +** the timer triggers. +*/ +typedef union +{ + void* p; + int i; + long l; +} TimerClientData; -struct timer *new_timer(time_t sec, suseconds_t usec); +extern TimerClientData JunkClientData; /* for use when you don't care */ -int update_timer(struct timer *tp, time_t sec, suseconds_t usec); +/* The TimerProc gets called when the timer expires. It gets passed +** the TimerClientData associated with the timer, and a timeval in case +** it wants to schedule another timer. +*/ +typedef void TimerProc( TimerClientData client_data, struct timeval* nowP ); -int64_t timer_remaining(struct timer *tp); +/* The Timer struct. */ +typedef struct TimerStruct +{ + TimerProc* timer_proc; + TimerClientData client_data; + int64_t usecs; + int periodic; + struct timeval time; + struct TimerStruct* prev; + struct TimerStruct* next; + int hash; +} Timer; -void free_timer(struct timer *tp); +/* Set up a timer, either periodic or one-shot. Returns (Timer*) 0 on errors. */ +extern Timer* tmr_create( + struct timeval* nowP, TimerProc* timer_proc, TimerClientData client_data, + int64_t usecs, int periodic ); -int timer_expired(struct timer *); +/* Returns a timeout indicating how long until the next timer triggers. You +** can just put the call to this routine right in your select(). Returns +** (struct timeval*) 0 if no timers are pending. +*/ +extern struct timeval* tmr_timeout( struct timeval* nowP ); -#endif +/* Run the list of timers. Your main program needs to call this every so often, +** or as indicated by tmr_timeout(). +*/ +extern void tmr_run( struct timeval* nowP ); + +/* Reset the clock on a timer, to current time plus the original timeout. */ +extern void tmr_reset( struct timeval* nowP, Timer* timer ); + +/* Deschedule a timer. Note that non-periodic timers are automatically +** descheduled when they run, so you don't have to call this on them. +*/ +extern void tmr_cancel( Timer* timer ); + +/* Clean up the timers package, freeing any unused storage. */ +extern void tmr_cleanup( void ); + +/* Cancel all timers and free storage, usually in preparation for exitting. */ +extern void tmr_destroy( void ); + +#endif /* __TIMER_H */