Switched to using a new timer package, adapted from thttpd and http_load.

This commit is contained in:
Jef Poskanzer 2012-12-11 22:29:26 -08:00
parent 9673370f98
commit ec2d0670b8
15 changed files with 642 additions and 398 deletions

View File

@ -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();

View File

@ -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 );

View File

@ -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 */

View File

@ -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;
}
/**************************************************************************/

View File

@ -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;
}

View File

@ -232,7 +232,7 @@ iperf_strerror(int i_errno)
strncat(errstr, strerror(errno), len);
}
return (errstr);
return errstr;
}
void

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
/*************************************************************************/

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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 */