Switched to using a new timer package, adapted from thttpd and http_load.
Этот коммит содержится в:
родитель
9673370f98
Коммит
ec2d0670b8
@ -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();
|
||||
|
@ -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 );
|
||||
|
||||
|
11
src/iperf.h
11
src/iperf.h
@ -15,6 +15,7 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/tcp.h>
|
||||
#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 */
|
||||
|
226
src/iperf_api.c
226
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;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ iperf_strerror(int i_errno)
|
||||
strncat(errstr, strerror(errno), len);
|
||||
}
|
||||
|
||||
return (errstr);
|
||||
return errstr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
112
src/iperf_udp.c
112
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
32
src/net.c
32
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;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
@ -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);
|
||||
}
|
||||
|
285
src/timer.c
285
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
71
src/timer.h
71
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 <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
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 */
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user