Added support for UDP mode (-b mode not yet supported). Added htonll/ntohll functions. Cleaned up code.

This commit is contained in:
sethdelliott 2010-07-14 23:24:58 +00:00
parent b0b16b86cc
commit 8556db5d08
9 changed files with 216 additions and 245 deletions

View File

@ -1,5 +1,5 @@
CFLAGS=-g -Wall
OBJS=main.o iperf_api.o iperf_server_api.o iperf_tcp.o iperf_udp.o timer.o net.o tcp_window_size.o units.o uuid.o tcp_info.o locale.o
OBJS=main.o iperf_api.o iperf_server_api.o iperf_tcp.o iperf_udp.o timer.o net.o tcp_window_size.o units.o iperf_util.o tcp_info.o locale.o
LDFLAGS=
UNAME=$(shell uname)

View File

@ -80,7 +80,6 @@ struct iperf_stream
* stream can have a pointer to this
*/
int packet_count;
uint64_t stream_id; /* stream identity for UDP mode */
double jitter;
double prev_transit;
int outoforder_packets;
@ -108,16 +107,9 @@ struct iperf_test
int server_port;
int duration; /* total duration of test (-t flag) */
/* The following two members should be replaced by a single TCP control socket */
int listener_sock_tcp;
int listener_sock_udp;
int ctrl_sck;
// Server is the only one that needs these
int listener_tcp;
int listener_udp;
int prot_listener;
/* boolen variables for Options */
int daemon; /* -D option */
@ -166,14 +158,6 @@ struct iperf_test
struct iperf_settings *default_settings;
};
struct udp_datagram
{
int state;
int stream_id;
int packet_count;
struct timeval sent_time;
};
struct param_exchange
{
int state;

View File

@ -300,6 +300,7 @@ parse_parameters(struct iperf_test *test)
break;
case 'u':
test->protocol = Pudp;
test->new_stream = iperf_new_udp_stream;
break;
case 'P':
test->num_streams = atoi(optarg);
@ -343,9 +344,9 @@ iperf_exchange_parameters(struct iperf_test * test)
printf(" cookie: %s\n", test->default_settings->cookie);
if (test->protocol == Pudp) {
test->prot_listener = netannounce(test->protocol, NULL, test->server_port);
FD_SET(test->prot_listener, &test->read_set);
test->max_fd = (test->prot_listener > test->max_fd) ? test->prot_listener : test->max_fd;
test->listener_udp = netannounce(test->protocol, NULL, test->server_port);
FD_SET(test->listener_udp, &test->read_set);
test->max_fd = (test->listener_udp > test->max_fd) ? test->listener_udp : test->max_fd;
}
// Send the control message to create streams and start the test
@ -652,7 +653,7 @@ int
iperf_create_streams(struct iperf_test *test)
{
struct iperf_stream *sp;
int i, s;
int i, s, buf;
for (i = 0; i < test->num_streams; ++i) {
s = netdial(test->protocol, test->server_hostname, test->server_port);
@ -666,6 +667,15 @@ iperf_create_streams(struct iperf_test *test)
perror("Nwrite COOKIE\n");
return -1;
}
} else {
if (write(s, &buf, sizeof(i)) < 0) {
perror("write data");
return -1;
}
if (read(s, &buf, sizeof(i)) < 0) {
perror("read data");
return -1;
}
}
FD_SET(s, &test->read_set);
@ -746,7 +756,7 @@ iperf_connect(struct iperf_test *test)
get_uuid(test->default_settings->cookie);
/* Create and connect the control channel */
test->ctrl_sck = netdial(test->protocol, test->server_hostname, test->server_port);
test->ctrl_sck = netdial(Ptcp, test->server_hostname, test->server_port);
if (test->ctrl_sck < 0) {
return -1;
}
@ -841,7 +851,7 @@ iperf_reporter_callback(struct iperf_test * test)
struct iperf_stream *sp = NULL;
iperf_size_t bytes = 0, bytes_sent = 0, bytes_received = 0;
iperf_size_t total_sent = 0, total_received = 0;
double start_time, end_time;
double start_time, end_time, avg_jitter;
struct iperf_interval_results *ip = NULL;
switch (test->state) {
@ -892,6 +902,7 @@ iperf_reporter_callback(struct iperf_test * test)
if (test->protocol == Pudp) {
total_packets += sp->packet_count;
lost_packets += sp->cnt_error;
avg_jitter += sp->jitter;
}
if (bytes_sent > 0) {
@ -939,10 +950,12 @@ iperf_reporter_callback(struct iperf_test * test)
printf(" Total received\n");
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
} else {
printf(report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, sp->jitter,
avg_jitter /= test->num_streams;
printf(report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, avg_jitter,
lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets));
}
// XXX: Why is this here?
if ((test->print_mss != 0) && (test->role == 'c')) {
printf("The TCP maximum segment size mss = %d\n", getsock_tcp_mss(sp->socket));
}
@ -1020,6 +1033,19 @@ iperf_new_stream(struct iperf_test *testp)
sp->buffer = (char *) malloc(testp->default_settings->blksize);
sp->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings));
sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
if (!sp->buffer) {
perror("Malloc sp->buffer");
return NULL;
}
if (!sp->settings) {
perror("Malloc sp->settings");
return NULL;
}
if (!sp->result) {
perror("Malloc sp->result");
return NULL;
}
/* Make a per stream copy of default_settings in each stream structure */
// XXX: These settings need to be moved to the test struct
@ -1032,9 +1058,6 @@ iperf_new_stream(struct iperf_test *testp)
sp->socket = -1;
// XXX: Not entirely sure what this does
sp->stream_id = (uint64_t) sp;
// XXX: Some of this code is needed, even though everything is already zero.
sp->packet_count = 0;
sp->jitter = 0.0;
@ -1154,7 +1177,7 @@ iperf_run_client(struct iperf_test * test)
fprintf(stderr, "Exiting...\n");
test->state = CLIENT_TERMINATE;
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
fprintf(stderr, "Unable to send CLIENT_TERMINATE message to serer\n");
fprintf(stderr, "Unable to send CLIENT_TERMINATE message to server\n");
}
exit(1);
}

View File

@ -62,7 +62,7 @@ iperf_server_listen(struct iperf_test *test)
// This needs to be changed to reflect if client has different window size
// make sure we got what we asked for
/* XXX: This needs to be moved to the stream listener
if ((x = get_tcp_windowsize(test->listener_sock_tcp, SO_RCVBUF)) < 0) {
if ((x = get_tcp_windowsize(test->listener_tcp, SO_RCVBUF)) < 0) {
// Needs to set some sort of error number/message
perror("SO_RCVBUF");
return -1;
@ -312,9 +312,9 @@ iperf_test_reset(struct iperf_test *test)
test->server_hostname = NULL;
test->ctrl_sck = -1;
test->prot_listener = 0;
test->bytes_sent = 0;
test->new_stream = iperf_new_tcp_stream;
test->reverse = 0;
test->no_delay = 0;
@ -336,7 +336,6 @@ int
iperf_run_server(struct iperf_test *test)
{
int result;
int streams_accepted;
fd_set temp_read_set, temp_write_set;
struct timeval tv;
@ -401,7 +400,7 @@ iperf_run_server(struct iperf_test *test)
}
} else {
if (FD_ISSET(test->listener_udp, &temp_read_set)) {
if (iperf_accept_udp_stream(test) < 0) {
if (iperf_udp_accept(test) < 0) {
fprintf(stderr, "iperf_accept_udp_stream: an error occurred.\n");
exit(1);
}
@ -409,6 +408,11 @@ iperf_run_server(struct iperf_test *test)
}
}
if (test->streams_accepted == test->num_streams) {
if (test->protocol == Pudp) {
FD_CLR(test->listener_udp, &test->read_set);
close(test->listener_udp);
test->listener_udp = -1;
}
test->state = TEST_START;
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
perror("Nwrite TEST_START");

View File

@ -105,7 +105,7 @@ iperf_tcp_send(struct iperf_stream * sp)
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result < 0)
perror("Write error");
perror("Nwrite error");
sp->result->bytes_sent += result;
sp->result->bytes_sent_this_interval += result;
@ -152,7 +152,7 @@ iperf_tcp_accept(struct iperf_test * test)
struct iperf_stream *sp;
len = sizeof(addr);
peersock = accept(test->prot_listener, (struct sockaddr *) & addr, &len);
peersock = accept(test->listener_tcp, (struct sockaddr *) & addr, &len);
if (peersock < 0) {
// XXX: Needs to implement better error handling
printf("Error in accept(): %s\n", strerror(errno));

View File

@ -51,177 +51,138 @@
*/
int
iperf_udp_recv(struct iperf_stream * sp)
iperf_udp_recv(struct iperf_stream *sp)
{
int result, message;
int result;
int size = sp->settings->blksize;
int sec, usec, pcount;
double transit = 0, d = 0;
struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
struct timeval arrival_time;
struct timeval sent_time, arrival_time;
printf("in iperf_udp_recv: reading %d bytes \n", size);
if (!sp->buffer)
{
fprintf(stderr, "receive buffer not allocated \n");
exit(0);
// XXX: Is this necessary? We've already checked the buffer to see if it's allocated.
if (!sp->buffer) {
fprintf(stderr, "receive buffer not allocated \n");
exit(0);
}
#ifdef USE_SEND
do
{
result = recv(sp->socket, sp->buffer, size, 0);
do {
result = recv(sp->socket, sp->buffer, size, 0);
} while (result == -1 && errno == EINTR);
#else
result = Nread(sp->socket, sp->buffer, size, Pudp);
#endif
/* interprete the type of message in packet */
if (result > 0)
{
message = udp->state;
if (result < 0) {
perror("Nread udp result");
return (-1);
}
if (message != 7)
{
//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
sp->result->bytes_received += result;
sp->result->bytes_received_this_interval += result;
memcpy(&sec, sp->buffer, sizeof(sec));
memcpy(&usec, sp->buffer+4, sizeof(usec));
memcpy(&pcount, sp->buffer+8, sizeof(pcount));
sec = ntohl(sec);
usec = ntohl(usec);
pcount = ntohl(pcount);
sent_time.tv_sec = sec;
sent_time.tv_usec = usec;
/* Out of order packets */
if (pcount >= sp->packet_count + 1) {
if (pcount > sp->packet_count + 1) {
sp->cnt_error += (pcount - 1) - sp->packet_count;
}
sp->packet_count = pcount;
} else {
sp->outoforder_packets++;
printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket);
}
if (message == STREAM_RUNNING && (sp->stream_id == udp->stream_id))
{
sp->result->bytes_received += result;
if (udp->packet_count == sp->packet_count + 1)
sp->packet_count++;
/* jitter measurement */
if (gettimeofday(&arrival_time, NULL) < 0)
{
perror("gettimeofday");
}
transit = timeval_diff(&udp->sent_time, &arrival_time);
d = transit - sp->prev_transit;
if (d < 0)
d = -d;
sp->prev_transit = transit;
sp->jitter += (d - sp->jitter) / 16.0;
/* OUT OF ORDER PACKETS */
if (udp->packet_count != sp->packet_count)
{
if (udp->packet_count < sp->packet_count + 1)
{
sp->outoforder_packets++;
printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
} else
sp->cnt_error += udp->packet_count - sp->packet_count;
}
/* store the latest packet id */
if (udp->packet_count > sp->packet_count)
sp->packet_count = udp->packet_count;
//printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
/* jitter measurement */
if (gettimeofday(&arrival_time, NULL) < 0) {
perror("gettimeofday");
}
return message;
transit = timeval_diff(&sent_time, &arrival_time);
d = transit - sp->prev_transit;
if (d < 0)
d = -d;
sp->prev_transit = transit;
// XXX: This is NOT the way to calculate jitter
// J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
sp->jitter += (d - sp->jitter) / 16.0;
return result;
}
/**************************************************************************/
int
iperf_udp_send(struct iperf_stream * sp)
iperf_udp_send(struct iperf_stream *sp)
{
int result = 0;
struct timeval before, after;
ssize_t result = 0;
int64_t dtargus;
int64_t adjustus = 0;
uint64_t sec, usec, pcount;
int size = sp->settings->blksize;
struct timeval before, after;
//printf("in iperf_udp_send \n");
/*
* the || part ensures that last packet is sent to server - the
* STREAM_END MESSAGE
*/
if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END)
{
int size = sp->settings->blksize;
// if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END) {
/* this is for udp packet/jitter/lost packet measurements */
struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
struct param_exchange *param = NULL;
/*
dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
dtargus /= sp->settings->rate;
dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
dtargus /= sp->settings->rate;
assert(dtargus != 0);
*/
if (gettimeofday(&before, 0) < 0)
perror("gettimeofday");
++sp->packet_count;
sec = htonl(before.tv_sec);
usec = htonl(before.tv_usec);
pcount = htonl(sp->packet_count);
assert(dtargus != 0);
memcpy(sp->buffer, &sec, sizeof(sec));
memcpy(sp->buffer+4, &usec, sizeof(usec));
memcpy(sp->buffer+8, &pcount, sizeof(pcount));
switch (sp->settings->state)
{
case STREAM_BEGIN:
udp->state = STREAM_BEGIN;
udp->stream_id = (uint64_t) sp;
/* udp->packet_count = ++sp->packet_count; */
break;
case STREAM_END:
udp->state = STREAM_END;
udp->stream_id = (uint64_t) sp;
break;
case RESULT_REQUEST:
udp->state = RESULT_REQUEST;
udp->stream_id = (uint64_t) sp;
break;
case ALL_STREAMS_END:
udp->state = ALL_STREAMS_END;
break;
case STREAM_RUNNING:
udp->state = STREAM_RUNNING;
udp->stream_id = (uint64_t) sp;
udp->packet_count = ++sp->packet_count;
break;
}
if (sp->settings->state == STREAM_BEGIN)
{
sp->settings->state = STREAM_RUNNING;
}
if (gettimeofday(&before, 0) < 0)
perror("gettimeofday");
udp->sent_time = before;
printf("iperf_udp_send: writing %d bytes \n", size);
#ifdef USE_SEND
result = send(sp->socket, sp->buffer, size, 0);
result = send(sp->socket, sp->buffer, size, 0);
#else
result = Nwrite(sp->socket, sp->buffer, size, Pudp);
result = Nwrite(sp->socket, sp->buffer, size, Pudp);
#endif
if (gettimeofday(&after, 0) < 0)
perror("gettimeofday");
if (result < 0)
perror("Nwrite udp error");
/*
* CHECK: Packet length and ID if(sp->settings->state ==
* STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP =
* %d\n",sp->settings->state, sp->packet_count, sp->socket);
*/
sp->result->bytes_sent += result;
sp->result->bytes_sent_this_interval += result;
/*
if (gettimeofday(&after, 0) < 0)
perror("gettimeofday");
if (sp->settings->state == STREAM_RUNNING)
sp->result->bytes_sent += result;
//
// CHECK: Packet length and ID if(sp->settings->state ==
// STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP =
// %d\n",sp->settings->state, sp->packet_count, sp->socket);
//
adjustus = dtargus;
adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
adjustus += (before.tv_usec - after.tv_usec);
if (adjustus > 0)
{
dtargus = adjustus;
}
/* RESET THE TIMER */
update_timer(sp->send_timer, 0, dtargus);
param = NULL;
adjustus = dtargus;
adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
adjustus += (before.tv_usec - after.tv_usec);
} /* timer_expired_micro */
if (adjustus > 0) {
dtargus = adjustus;
}
// RESET THE TIMER
update_timer(sp->send_timer, 0, dtargus);
// } // timer_expired_micro
*/
return result;
}
@ -232,10 +193,9 @@ iperf_new_udp_stream(struct iperf_test * testp)
struct iperf_stream *sp;
sp = (struct iperf_stream *) iperf_new_stream(testp);
if (!sp)
{
perror("malloc");
return (NULL);
if (!sp) {
perror("malloc");
return (NULL);
}
sp->rcv = iperf_udp_recv;
sp->snd = iperf_udp_send;
@ -254,70 +214,53 @@ iperf_new_udp_stream(struct iperf_test * testp)
int
iperf_udp_accept(struct iperf_test * test)
iperf_udp_accept(struct iperf_test *test)
{
struct iperf_stream *sp;
struct sockaddr_in sa_peer;
char *buf;
int buf;
socklen_t len;
int sz;
int sz, s;
buf = (char *) malloc(test->default_settings->blksize);
struct udp_datagram *udp = (struct udp_datagram *) buf;
s = test->listener_udp;
len = sizeof sa_peer;
sz = recvfrom(test->listener_sock_udp, buf, test->default_settings->blksize, 0, (struct sockaddr *) & sa_peer, &len);
if (!sz)
return -1;
if (connect(test->listener_sock_udp, (struct sockaddr *) & sa_peer, len) < 0)
{
perror("iperf_udp_accept: connect error");
exit(-1); /* XXX: for debugging */
return -1;
if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
perror("recvfrom in udp accept");
return (-1);
}
if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
perror("iperf_udp_accept: connect error");
return -1;
}
sp = test->new_stream(test);
sp->socket = test->listener_sock_udp;
setnonblocking(sp->socket);
if (!sp)
return (-1);
sp->socket = s;
iperf_init_stream(sp, test);
iperf_add_stream(test, sp);
FD_SET(s, &test->read_set);
FD_SET(s, &test->write_set);
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
test->listener_udp = netannounce(Pudp, NULL, test->server_port);
if (test->listener_udp < 0)
return -1;
test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port);
if (test->listener_sock_udp < 0)
return -1;
FD_SET(test->listener_udp, &test->read_set);
test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd;
FD_SET(test->listener_sock_udp, &test->read_set);
test->max_fd = (test->max_fd < test->listener_sock_udp) ? test->listener_sock_udp : test->max_fd;
if (test->default_settings->state != RESULT_REQUEST)
connect_msg(sp);
printf("iperf_udp_accept: 1st UDP data packet for socket %d has arrived \n", sp->socket);
sp->stream_id = udp->stream_id;
sp->result->bytes_received += sz;
/* Count OUT OF ORDER PACKETS */
if (udp->packet_count != 0)
{
if (udp->packet_count < sp->packet_count + 1)
sp->outoforder_packets++;
else
sp->cnt_error += udp->packet_count - sp->packet_count;
/* Let the client know we're ready "accept" another UDP "stream" */
if (write(sp->socket, &buf, sizeof(buf)) < 0) {
perror("write listen message");
return -1;
}
/* store the latest packet id */
if (udp->packet_count > sp->packet_count)
sp->packet_count = udp->packet_count;
//printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
connect_msg(sp);
test->streams_accepted++;
free(buf);
return 0;
}

View File

@ -229,13 +229,6 @@ main(int argc, char **argv)
optind = 0;
/* exit until this is done.... */
if (test->protocol == Pudp) {
printf("UDP mode not yet supported. Exiting. \n");
iperf_free_test(test);
return 0;
}
if (iperf_run(test) < 0) {
fprintf(stderr, "An error occurred. Exiting...\n");
return -1;

View File

@ -18,6 +18,7 @@
*/
/* make connection to server */
// XXX: Change client to server?
int
netdial(int proto, char *client, int port)
{
@ -49,13 +50,14 @@ netdial(int proto, char *client, int port)
}
sn = sizeof sa;
if (getpeername(s, (struct sockaddr *) & sa, &sn) >= 0) {
return (s);
// XXX: Is there a reason to call getpeername() if none of the return values are used?
if (getpeername(s, (struct sockaddr *) & sa, &sn) < 0) {
perror("getpeername error");
return (-1);
}
perror("getpeername error");
return (-1);
return (s);
}
/***************************************************************/
@ -100,28 +102,20 @@ netannounce(int proto, char *local, int port)
int
Nread(int fd, void *buf, int count, int prot)
{
struct sockaddr from;
socklen_t len = sizeof(from);
register int n;
register int nleft = count;
if (prot == SOCK_DGRAM) {
// XXX: Does recvfrom guarantee all count bytes are sent at once?
fprintf(stderr, "READING UDP DATA IN Nread SOCK_DGRAM\n");
n = recvfrom(fd, buf, count, 0, &from, &len);
} else {
while (nleft > 0) {
if ((n = read(fd, buf, nleft)) < 0) {
if (errno == EINTR)
n = 0;
else
return (-1);
} else if (n == 0)
break;
nleft -= n;
buf += n;
}
while (nleft > 0) {
if ((n = read(fd, buf, nleft)) < 0) {
if (errno == EINTR)
n = 0;
else
return (-1);
} else if (n == 0)
break;
nleft -= n;
buf += n;
}
return (count - nleft);
}

View File

@ -9,5 +9,35 @@ int getsock_tcp_mss(int);
int set_tcp_options(int, int, int);
int setnonblocking(int);
unsigned long long htonll(unsigned long long);
unsigned long long ntohll(unsigned long long);
/* XXX: Need a better check for byte order */
#if BYTE_ORDER == BIG_ENDIAN
#define HTONLL(n) (n)
#define NTOHLL(n) (n)
#else
#define HTONLL(n) ((((unsigned long long)(n) & 0xFF) << 56) | \
(((unsigned long long)(n) & 0xFF00) << 40) | \
(((unsigned long long)(n) & 0xFF0000) << 24) | \
(((unsigned long long)(n) & 0xFF000000) << 8) | \
(((unsigned long long)(n) & 0xFF00000000) >> 8) | \
(((unsigned long long)(n) & 0xFF0000000000) >> 24) | \
(((unsigned long long)(n) & 0xFF000000000000) >> 40) | \
(((unsigned long long)(n) & 0xFF00000000000000) >> 56))
#define NTOHLL(n) ((((unsigned long long)(n) & 0xFF) << 56) | \
(((unsigned long long)(n) & 0xFF00) << 40) | \
(((unsigned long long)(n) & 0xFF0000) << 24) | \
(((unsigned long long)(n) & 0xFF000000) << 8) | \
(((unsigned long long)(n) & 0xFF00000000) >> 8) | \
(((unsigned long long)(n) & 0xFF0000000000) >> 24) | \
(((unsigned long long)(n) & 0xFF000000000000) >> 40) | \
(((unsigned long long)(n) & 0xFF00000000000000) >> 56))
#endif
#define htonll(n) HTONLL(n)
#define ntohll(n) NTOHLL(n)
#endif