lots of code restructuring

This commit is contained in:
Brian Tierney 2009-11-02 22:43:19 +00:00
parent da54a271ad
commit a951c98062
16 changed files with 1647 additions and 1221 deletions

View File

@ -1,5 +1,5 @@
CFLAGS=-g -Wall
OBJS=main.o iperf_api.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 uuid.o tcp_info.o locale.o
LDFLAGS=
UNAME=$(shell uname)
@ -10,7 +10,7 @@ endif
all: iperf
iperf: $(OBJS)
$(CC) $(LDFLAGS) -o iperf3 $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o iperf3 $(OBJS)
profile: iperf
$(CC) -pg -o iperf-profile $(OBJS)

View File

@ -1,2 +1,181 @@
/*
Copyright (c) 2009, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from the U.S. Dept. of Energy). All rights reserved.
*/
#ifndef IPERF_H
#define IPERF_H
typedef uint64_t iperf_size_t;
struct iperf_interval_results
{
iperf_size_t bytes_transferred;
struct timeval interval_time;
float interval_duration;
#if defined(linux) || defined(__FreeBSD__)
struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) results here for
* Linux and FreeBSD stored here */
#else
char *tcpInfo; /* just a placeholder */
#endif
struct iperf_interval_results *next;
void *custom_data;
};
struct iperf_stream_result
{
iperf_size_t bytes_received;
iperf_size_t bytes_sent;
struct timeval start_time;
struct timeval end_time;
struct iperf_interval_results *interval_results;
void *data;
};
struct iperf_settings
{
int socket_bufsize; /* window size for TCP */
int blksize; /* size of read/writes (-l) */
uint64_t rate; /* target data rate, UDP only */
int mss; /* for TCP MSS */
int ttl;
int tos;
iperf_size_t bytes; /* -n option */
char unit_format; /* -f */
/* XXX: not sure about this design: everything else is this struct is static state,
but the last 2 are dymanic state. Should they be in iperf_stream instead? */
int state; /* This is state of a stream/test */
char cookie[37]; /* XXX: why 37? This should be a constant
* -blt */
};
struct iperf_stream
{
/* configurable members */
int local_port;
int remote_port;
/* XXX: I think settings should be one per test, not one per stream -blt */
struct iperf_settings *settings; /* pointer to structure settings */
/* non configurable members */
struct iperf_stream_result *result; /* structure pointer to result */
int socket;
struct timer *send_timer;
char *buffer; /* data to send */
/*
* for udp measurements - This can be a structure outside stream, and
* stream can have a pointer to this
*/
int packet_count;
int stream_id; /* stream identity */
double jitter;
double prev_transit;
int outoforder_packets;
int cnt_error;
uint64_t target;
struct sockaddr_storage local_addr;
struct sockaddr_storage remote_addr;
int (*rcv) (struct iperf_stream * stream);
int (*snd) (struct iperf_stream * stream);
int (*update_stats) (struct iperf_stream * stream);
struct iperf_stream *next;
void *data;
};
struct iperf_test
{
char role; /* c' lient or 's' erver */
int protocol;
char *server_hostname; /* -c option */
int server_port;
int duration; /* total duration of test (-t flag) */
int listener_sock_tcp;
int listener_sock_udp;
/* boolen variables for Options */
int daemon; /* -D option */
int no_delay; /* -N option */
int print_mss; /* -m option */
int domain; /* -V option */
/* Select related parameters */
int max_fd;
fd_set read_set;
fd_set temp_set;
fd_set write_set;
int (*accept) (struct iperf_test *);
struct iperf_stream *(*new_stream) (struct iperf_test *);
int stats_interval; /* time interval to gather stats (-i) */
void *(*stats_callback) (struct iperf_test *); /* callback function
* pointer for stats */
int reporter_interval;/* time interval for reporter */
char *(*reporter_callback) (struct iperf_test *); /* callback function
* pointer for reporter */
int reporter_fd; /* file descriptor for reporter */
int num_streams; /* total streams in the test (-P) */
int tcp_info; /* display getsockopt(TCP_INFO) results */
struct iperf_stream *streams; /* pointer to list of struct stream */
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;
int stream_id;
int blksize;
int recv_window;
int send_window;
int mss;
char format;
char cookie[37]; /* size 37 makes total size 64 */
};
enum
{
/* default settings */
Ptcp = SOCK_STREAM,
Pudp = SOCK_DGRAM,
PORT = 5001, /* default port to listen on */
uS_TO_NS = 1000,
SEC_TO_US = 1000000,
RATE = 1024 * 1024, /* 1 Mbps */
DURATION = 5, /* seconds */
DEFAULT_UDP_BLKSIZE = 1450, /* 1 packet per ethernet frame, IPV6 too */
DEFAULT_TCP_BLKSIZE = 128 * 1024, /* default read/write block size */
/* other useful constants */
TEST_START = 1,
TEST_RUNNING = 2,
RESULT_REQUEST = 3,
RESULT_RESPOND = 4,
TEST_END = 5,
STREAM_BEGIN = 6,
STREAM_RUNNING = 7,
STREAM_END = 8,
ALL_STREAMS_END = 9,
PARAM_EXCHANGE = 10,
ACCESS_DENIED = -1,
};
#define SEC_TO_NS 1000000000 /* too big for enum on some platforms */
#endif /* IPERF_API_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2004, The Regents of the University of California, through
Copyright (c) 2009, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from the U.S. Dept. of Energy). All rights reserved.
*/
@ -8,171 +8,7 @@
#ifndef IPERF_API_H
#define IPERF_API_H
typedef uint64_t iperf_size_t;
struct iperf_interval_results
{
iperf_size_t bytes_transferred;
struct timeval interval_time;
float interval_duration;
#if defined(linux) || defined(__FreeBSD__)
struct tcp_info tcpInfo; /* getsockopt(TCP_INFO) results here for
* Linux and FreeBSD stored here */
#else
char *tcpInfo; /* just a placeholder */
#endif
struct iperf_interval_results *next;
void *custom_data;
};
struct iperf_stream_result
{
iperf_size_t bytes_received;
iperf_size_t bytes_sent;
struct timeval start_time;
struct timeval end_time;
struct iperf_interval_results *interval_results;
void *data;
};
struct iperf_settings
{
int socket_bufsize; /* window size for TCP */
int blksize; /* size of read/writes (-l) */
uint64_t rate; /* target data rate, UDP only */
int mss; /* for TCP MSS */
int ttl;
int tos;
iperf_size_t bytes; /* -n option */
char unit_format; /* -f */
int state; /* This is state of a stream/test */
char cookie[37]; /* XXX: why 37? This should be a constant
* -blt */
};
struct iperf_stream
{
/* configurable members */
int local_port;
int remote_port;
struct iperf_settings *settings; /* pointer to structure settings */
int protocol; /* TCP or UDP */
/* non configurable members */
struct iperf_stream_result *result; /* structure pointer to result */
int socket;
struct timer *send_timer;
char *buffer; /* data to send */
/*
* for udp measurements - This can be a structure outside stream, and
* stream can have a pointer to this
*/
int packet_count;
int stream_id; /* stream identity */
double jitter;
double prev_transit;
int outoforder_packets;
int cnt_error;
uint64_t target;
struct sockaddr_storage local_addr;
struct sockaddr_storage remote_addr;
int (*rcv) (struct iperf_stream * stream);
int (*snd) (struct iperf_stream * stream);
int (*update_stats) (struct iperf_stream * stream);
struct iperf_stream *next;
void *data;
};
struct iperf_test
{
char role; /* c' lient or 's' erver */
int protocol;
char *server_hostname; /* -c option */
int server_port;
int duration; /* total duration of test (-t flag) */
int listener_sock_tcp;
int listener_sock_udp;
/* boolen variables for Options */
int daemon; /* -D option */
int no_delay; /* -N option */
int print_mss; /* -m option */
int domain; /* -V option */
/* Select related parameters */
int max_fd;
fd_set read_set;
fd_set temp_set;
fd_set write_set;
int (*accept) (struct iperf_test *);
struct iperf_stream *(*new_stream) (struct iperf_test *);
int stats_interval; /* time interval to gather stats (-i) */
void *(*stats_callback) (struct iperf_test *); /* callback function
* pointer for stats */
int reporter_interval;/* time interval for reporter */
char *(*reporter_callback) (struct iperf_test *); /* callback function
* pointer for reporter */
int reporter_fd; /* file descriptor for reporter */
int num_streams; /* total streams in the test (-P) */
int tcp_info; /* display getsockopt(TCP_INFO) results */
struct iperf_stream *streams; /* pointer to list of struct stream */
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;
int stream_id;
int blksize;
int recv_window;
int send_window;
int mss;
char format;
char cookie[37]; /* size 37 makes total size 64 */
};
enum
{
/* default settings */
Ptcp = SOCK_STREAM,
Pudp = SOCK_DGRAM,
PORT = 5001, /* default port to listen on */
uS_TO_NS = 1000,
SEC_TO_US = 1000000,
RATE = 1024 * 1024, /* 1 Mbps */
DURATION = 5, /* seconds */
DEFAULT_UDP_BLKSIZE = 1450, /* 1 packet per ethernet frame, IPV6 too */
DEFAULT_TCP_BLKSIZE = 128 * 1024, /* default read/write block size */
/* other useful constants */
TEST_START = 1,
TEST_RUNNING = 2,
RESULT_REQUEST = 3,
RESULT_RESPOND = 4,
TEST_END = 5,
STREAM_BEGIN = 6,
STREAM_RUNNING = 7,
STREAM_END = 8,
ALL_STREAMS_END = 9,
PARAM_EXCHANGE = 10,
ACCESS_DENIED = -1,
};
#define SEC_TO_NS 1000000000 /* too big for enum on some platforms */
#include "iperf.h"
/**
* exchange_parameters - handles the param_Exchange part for client
@ -213,20 +49,6 @@ void send_result_to_client(struct iperf_stream * sp);
*/
void receive_result_from_server(struct iperf_test * test);
/**
* getsock_tcp_mss - Returns the MSS size for TCP
*
*/
int getsock_tcp_mss(int inSock);
/**
* set_socket_options - used for setsockopt()
*
*
*/
int set_socket_options(struct iperf_stream * sp, struct iperf_test * test);
/**
* connect_msg -- displays connection message
* denoting senfer/receiver details
@ -244,56 +66,6 @@ void connect_msg(struct iperf_stream * sp);
void Display(struct iperf_test * test);
/**
* iperf_tcp_accept -- accepts a new TCP connection
* on tcp_listener_socket for TCP data and param/result
* exchange messages
*returns 0 on success
*
*/
int iperf_tcp_accept(struct iperf_test * test);
/**
* iperf_udp_accept -- accepts a new UDP connection
* on udp_listener_socket
*returns 0 on success
*
*/
int iperf_udp_accept(struct iperf_test * test);
/**
* iperf_tcp_recv -- receives the data for TCP
* and the Param/result message exchange
*returns state of packet received
*
*/
int iperf_tcp_recv(struct iperf_stream * sp);
/**
* iperf_udp_recv -- receives the client data for UDP
*
*returns state of packet received
*
*/
int iperf_udp_recv(struct iperf_stream * sp);
/**
* iperf_tcp_send -- sends the client data for TCP
* and the Param/result message exchanges
* returns: bytes sent
*
*/
int iperf_tcp_send(struct iperf_stream * sp);
/**
* iperf_udp_send -- sends the client data for UDP
*
* returns: bytes sent
*
*/
int iperf_udp_send(struct iperf_stream * sp);
/**
* iperf_stats_callback -- handles the statistic gathering
*
@ -332,14 +104,6 @@ void iperf_run_server(struct iperf_test * test);
*/
void iperf_run_client(struct iperf_test * test);
/**
* iperf_run -- runs the test either as client or server
*
* returns status
*
*/
int iperf_run(struct iperf_test * test);
/**
* iperf_new_test -- return a new iperf_test with default values
*
@ -372,7 +136,6 @@ void iperf_free_test(struct iperf_test * testp);
*/
struct iperf_stream *iperf_new_stream(struct iperf_test * testp);
struct iperf_stream *iperf_new_tcp_stream(struct iperf_test * testp);
struct iperf_stream *iperf_new_udp_stream(struct iperf_test * testp);
/**

243
src/iperf_server_api.c Normal file
View File

@ -0,0 +1,243 @@
/*
* Copyright (c) 2009, The Regents of the University of California, through
* Lawrence Berkeley National Laboratory (subject to receipt of any required
* approvals from the U.S. Dept. of Energy). All rights reserved.
*/
/* iperf_server_api.c: Functions to be used by an iperf server
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdint.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include <signal.h>
#include <setjmp.h>
#include "iperf.h"
#include "iperf_server_api.h"
#include "iperf_api.h"
#include "iperf_udp.h"
#include "iperf_tcp.h"
#include "timer.h"
#include "net.h"
#include "units.h"
#include "tcp_window_size.h"
#include "uuid.h"
#include "locale.h"
/*********************************************************************/
/**
* param_received - handles the param_Exchange part for server
* returns state on success, -1 on failure
*
*/
int
param_received(struct iperf_stream * sp, struct param_exchange * param)
{
int result;
char *buf = (char *) malloc(sizeof(struct param_exchange));
if (sp->settings->cookie[0] == '\0' ||
(strncmp(param->cookie, sp->settings->cookie, 37) == 0))
{
strncpy(sp->settings->cookie, param->cookie, 37);
sp->settings->blksize = param->blksize;
sp->settings->socket_bufsize = param->recv_window;
sp->settings->unit_format = param->format;
printf("Got params from client: block size = %d, recv_window = %d cookie = %s\n",
sp->settings->blksize, sp->settings->socket_bufsize, sp->settings->cookie);
param->state = TEST_START;
buf[0] = TEST_START;
} else
{
fprintf(stderr, "Connection from new client denied\n");
param->state = ACCESS_DENIED;
buf[0] = ACCESS_DENIED;
}
free(buf);
printf("param_received: Sending message back to client \n");
result = send(sp->socket, buf, sizeof(struct param_exchange), 0);
if (result < 0)
perror("param_received: Error sending param ack to client");
return param->state;
}
/*************************************************************/
/**
* send_result_to_client - sends result string from server to client
*/
void
send_result_to_client(struct iperf_stream * sp)
{
int result;
int size = sp->settings->blksize;
char *buf = (char *) malloc(size);
if (!buf)
{
perror("malloc: unable to allocate transmit buffer");
}
/* adding the string terminator to the message */
buf[strlen((char *) sp->data)] = '\0';
memcpy(buf, sp->data, strlen((char *) sp->data));
printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data));
result = send(sp->socket, buf, size, 0);
printf("RESULT SENT TO CLIENT\n");
free(buf);
}
/**************************************************************************/
void
iperf_run_server(struct iperf_test * test)
{
struct timeval tv;
struct iperf_stream *np, *sp;
int j, result, message;
char *results_string = NULL;
FD_ZERO(&test->read_set);
FD_SET(test->listener_sock_tcp, &test->read_set);
FD_SET(test->listener_sock_udp, &test->read_set);
test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp;
test->num_streams = 0;
test->default_settings->state = TEST_RUNNING;
printf("iperf_run_server: Waiting for client connect.... \n");
while (test->default_settings->state != TEST_END)
{
memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set));
tv.tv_sec = 15;
tv.tv_usec = 0;
/* using select to check on multiple descriptors. */
result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv);
if (result == 0)
{
//printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec);
continue;
} else if (result < 0 && errno != EINTR)
{
printf("Error in select(): %s\n", strerror(errno));
exit(0);
} else if (result > 0)
{
/* Accept a new TCP connection */
if (FD_ISSET(test->listener_sock_tcp, &test->temp_set))
{
test->protocol = Ptcp;
test->accept = iperf_tcp_accept;
test->new_stream = iperf_new_tcp_stream;
test->accept(test);
test->default_settings->state = TEST_RUNNING;
FD_CLR(test->listener_sock_tcp, &test->temp_set);
}
/* Accept a new UDP connection */
else if (FD_ISSET(test->listener_sock_udp, &test->temp_set))
{
test->protocol = Pudp;
test->accept = iperf_udp_accept;
test->new_stream = iperf_new_udp_stream;
test->accept(test);
test->default_settings->state = TEST_RUNNING;
FD_CLR(test->listener_sock_udp, &test->temp_set);
}
/* Process the sockets for read operation */
for (j = 0; j < test->max_fd + 1; j++)
{
if (FD_ISSET(j, &test->temp_set))
{
/* find the correct stream - possibly time consuming */
np = find_stream_by_socket(test, j);
message = np->rcv(np); /* get data from client using receiver callback */
//printf ("iperf_run_server: iperf_tcp_recv returned %d \n", message);
np->settings->state = message;
if (message == PARAM_EXCHANGE)
{
/* copy the received settings into test */
memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings));
}
if (message == ACCESS_DENIED) /* this might get set by PARAM_EXCHANGE */
{
/* XXX: test this! */
close(np->socket);
FD_CLR(np->socket, &test->read_set);
iperf_free_stream(test, np);
}
if (message == STREAM_END)
{
/*
* XXX: should I expect one of these per stream. If
* so, only timestamp the 1st one??
*/
gettimeofday(&np->result->end_time, NULL);
}
if (message == RESULT_REQUEST)
{
np->settings->state = RESULT_RESPOND;
results_string = test->reporter_callback(test);
np->data = results_string;
send_result_to_client(np);
}
if (message == ALL_STREAMS_END)
{
/* print server results */
results_string = test->reporter_callback(test);
puts(results_string); /* send to stdio */
}
if (message == TEST_END)
{
/* FREE ALL STREAMS */
np = test->streams;
do
{
sp = np;
close(sp->socket);
FD_CLR(sp->socket, &test->read_set);
np = sp->next;
iperf_free_stream(test, sp);
} while (np != NULL);
printf("TEST_END\n\n");
test->default_settings->state = TEST_END;
/* reset cookie with client is finished */
memset(test->default_settings->cookie, '\0', 37);
}
} /* end if (FD_ISSET(j, &temp_set)) */
} /* end for (j=0;...) */
} /* end else (result>0) */
} /* end while */
}

5
src/iperf_server_api.h Normal file
View File

@ -0,0 +1,5 @@
int param_received(struct iperf_stream * sp, struct param_exchange * param);
void send_result_to_client(struct iperf_stream * sp);
void iperf_run_server(struct iperf_test * test);

307
src/iperf_tcp.c Normal file
View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2009, The Regents of the University of California, through
* Lawrence Berkeley National Laboratory (subject to receipt of any required
* approvals from the U.S. Dept. of Energy). All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdint.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include <signal.h>
#include <setjmp.h>
#include "iperf.h"
#include "iperf_api.h"
#include "iperf_tcp.h"
#include "timer.h"
#include "net.h"
#include "tcp_window_size.h"
#include "uuid.h"
#include "locale.h"
jmp_buf env; /* to handle longjmp on signal */
/**************************************************************************/
/**
* iperf_tcp_recv -- receives the data for TCP
* and the Param/result message exchange
*returns state of packet received
*
*/
int
iperf_tcp_recv(struct iperf_stream * sp)
{
int result, message;
char ch;
int size = sp->settings->blksize;
char *final_message = NULL;
errno = 0;
struct param_exchange *param = (struct param_exchange *) sp->buffer;
if (!sp->buffer)
{
fprintf(stderr, "receive buffer not allocated \n");
return -1;
}
/* get the 1st byte: then based on that, decide how much to read */
if ((result = recv(sp->socket, &ch, sizeof(int), MSG_PEEK)) != sizeof(int))
{
if (result == 0)
printf("Client Disconnected. \n");
else
perror("iperf_tcp_recv: recv error: MSG_PEEK");
return -1;
}
message = (int) ch;
sp->settings->state = message;
if (message != 7) /* tell me about non STREAM_RUNNING messages
* for debugging */
printf("iperf_tcp_recv: got message type %d \n", message);
switch (message)
{
case PARAM_EXCHANGE:
size = sizeof(struct param_exchange);
#ifdef USE_RECV
do
{
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
} while (result == -1 && errno == EINTR);
#else
result = Nread(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result == -1)
{
perror("iperf_tcp_recv: recv error");
return -1;
}
//printf("iperf_tcp_recv: recv returned %d bytes \n", result);
//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
result = param_received(sp, param); /* handle PARAM_EXCHANGE and
* send result to client */
break;
case TEST_START:
case STREAM_BEGIN:
case STREAM_RUNNING:
case STREAM_END:
size = sp->settings->blksize;
#ifdef USE_RECV
/*
* NOTE: Nwrite/Nread seems to be 10-15% faster than send/recv for
* localhost on OSX. More testing needed on other OSes to be sure.
*/
do
{
printf("iperf_tcp_recv: Calling recv: expecting %d bytes \n", size);
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
} while (result == -1 && errno == EINTR);
#else
result = Nread(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result == -1)
{
perror("Read error");
return -1;
}
//printf("iperf_tcp_recv: recv returned %d bytes \n", result);
sp->result->bytes_received += result;
break;
case ALL_STREAMS_END:
size = sizeof(struct param_exchange);
result = Nread(sp->socket, sp->buffer, size, Ptcp);
/* XXX: is there anything that should be done at the point ? */
break;
case RESULT_REQUEST:
/* XXX: not working yet */
//final_message = iperf_reporter_callback(test);
final_message = "final server results string will go here \n";
memcpy(sp->buffer, final_message, strlen(final_message));
result = send(sp->socket, sp->buffer, sp->settings->blksize, 0);
if (result < 0)
perror("Error sending results back to client");
break;
default:
printf("unexpected state encountered: %d \n", message);
return -1;
}
return message;
}
/**************************************************************************/
/**
* iperf_tcp_send -- sends the client data for TCP
* and the Param/result message exchanges
* returns: bytes sent
*
*/
int
iperf_tcp_send(struct iperf_stream * sp)
{
int result;
int size = sp->settings->blksize;
struct param_exchange *param = (struct param_exchange *) sp->buffer;
if (!sp->buffer)
{
perror("transmit buffer not allocated");
return -1;
}
strncpy(param->cookie, sp->settings->cookie, 37);
switch (sp->settings->state)
{
case PARAM_EXCHANGE:
param->state = PARAM_EXCHANGE;
size = sizeof(struct param_exchange);
break;
case STREAM_BEGIN:
param->state = STREAM_BEGIN;
size = sp->settings->blksize;
break;
case STREAM_END:
param->state = STREAM_END;
size = sp->settings->blksize; /* XXX: this might not be right, will
* the last block always be full
* size? */
break;
case RESULT_REQUEST:
param->state = RESULT_REQUEST;
size = sizeof(struct param_exchange);
break;
case ALL_STREAMS_END:
param->state = ALL_STREAMS_END;
size = sizeof(struct param_exchange);
break;
case STREAM_RUNNING:
param->state = STREAM_RUNNING;
size = sp->settings->blksize;
break;
default:
printf("State of the stream can't be determined\n");
break;
}
//printf(" in iperf_tcp_send, message type = %d (total = %d bytes) \n", param->state, size);
#ifdef USE_SEND
result = send(sp->socket, sp->buffer, size, 0);
#else
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result < 0)
perror("Write error");
//printf(" iperf_tcp_send: %d bytes sent \n", result);
/* change state after 1st send */
if (sp->settings->state == STREAM_BEGIN)
sp->settings->state = STREAM_RUNNING;
if (sp->buffer[0] != STREAM_END)
/*
* XXX: check/fix this. Maybe only want to increment the size with
* STREAM_BEGIN and STREAM_RUNNING?
*/
sp->result->bytes_sent += size;
//printf("iperf_tcp_send: number bytes sent so far = %u \n", (uint64_t) sp->result->bytes_sent);
return result;
}
/**************************************************************************/
struct iperf_stream *
iperf_new_tcp_stream(struct iperf_test * testp)
{
struct iperf_stream *sp;
sp = (struct iperf_stream *) iperf_new_stream(testp);
if (!sp)
{
perror("malloc");
return (NULL);
}
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
sp->snd = iperf_tcp_send; /* pointer to send function */
/* XXX: not yet written... */
//sp->update_stats = iperf_tcp_update_stats;
return sp;
}
/**************************************************************************/
/**
* iperf_tcp_accept -- accepts a new TCP connection
* on tcp_listener_socket for TCP data and param/result
* exchange messages
* returns 0 on success
*
*/
int
iperf_tcp_accept(struct iperf_test * test)
{
socklen_t len;
struct sockaddr_in addr;
int peersock;
struct iperf_stream *sp;
len = sizeof(addr);
peersock = accept(test->listener_sock_tcp, (struct sockaddr *) & addr, &len);
if (peersock < 0)
{
printf("Error in accept(): %s\n", strerror(errno));
return -1;
} else
{
sp = test->new_stream(test);
setnonblocking(peersock);
FD_SET(peersock, &test->read_set);
test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd;
sp->socket = peersock;
//printf("in iperf_tcp_accept: tcp_windowsize: %d \n", test->default_settings->socket_bufsize);
iperf_init_stream(sp, test);
iperf_add_stream(test, sp);
if (test->default_settings->state != RESULT_REQUEST)
connect_msg(sp); /* print connect message */
return 0;
}
}

39
src/iperf_tcp.h Normal file
View File

@ -0,0 +1,39 @@
/*
Copyright (c) 2009, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from the U.S. Dept. of Energy). All rights reserved.
*/
#ifndef IPERF_TCP_H
#define IPERF_TCP_H
/**
* iperf_tcp_accept -- accepts a new TCP connection
* on tcp_listener_socket for TCP data and param/result
* exchange messages
*returns 0 on success
*
*/
int iperf_tcp_accept(struct iperf_test * test);
/**
* iperf_tcp_recv -- receives the data for TCP
* and the Param/result message exchange
*returns state of packet received
*
*/
int iperf_tcp_recv(struct iperf_stream * sp);
/**
* iperf_tcp_send -- sends the client data for TCP
* and the Param/result message exchanges
* returns: bytes sent
*
*/
int iperf_tcp_send(struct iperf_stream * sp);
struct iperf_stream *iperf_new_tcp_stream(struct iperf_test * testp);
#endif /* IPERF_TCP_H */

322
src/iperf_udp.c Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 2009, The Regents of the University of California, through
* Lawrence Berkeley National Laboratory (subject to receipt of any required
* approvals from the U.S. Dept. of Energy). All rights reserved.
*/
/* iperf_udp.c: UDP specific routines for iperf
*
* NOTE: not yet finished / working
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <stdint.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include <signal.h>
#include <setjmp.h>
#include "iperf.h"
#include "iperf_api.h"
#include "iperf_udp.h"
#include "timer.h"
#include "net.h"
#include "locale.h"
/**************************************************************************/
/**
* iperf_udp_recv -- receives the client data for UDP
*
*returns state of packet received
*
*/
int
iperf_udp_recv(struct iperf_stream * sp)
{
int result, message;
int size = sp->settings->blksize;
double transit = 0, d = 0;
struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
struct timeval arrival_time;
printf("in iperf_udp_recv: reading %d bytes \n", size);
if (!sp->buffer)
{
fprintf(stderr, "receive buffer not allocated \n");
exit(0);
}
#ifdef USE_SEND
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 (message != 7)
{
//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
}
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);
}
return message;
}
/**************************************************************************/
int
iperf_udp_send(struct iperf_stream * sp)
{
int result = 0;
struct timeval before, after;
int64_t dtargus;
int64_t adjustus = 0;
//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;
/* 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;
assert(dtargus != 0);
switch (sp->settings->state)
{
case STREAM_BEGIN:
udp->state = STREAM_BEGIN;
udp->stream_id = (int) sp;
/* udp->packet_count = ++sp->packet_count; */
break;
case STREAM_END:
udp->state = STREAM_END;
udp->stream_id = (int) sp;
break;
case RESULT_REQUEST:
udp->state = RESULT_REQUEST;
udp->stream_id = (int) sp;
break;
case ALL_STREAMS_END:
udp->state = ALL_STREAMS_END;
break;
case STREAM_RUNNING:
udp->state = STREAM_RUNNING;
udp->stream_id = (int) 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);
#else
result = Nwrite(sp->socket, sp->buffer, size, Pudp);
#endif
if (gettimeofday(&after, 0) < 0)
perror("gettimeofday");
/*
* 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);
*/
if (sp->settings->state == STREAM_RUNNING)
sp->result->bytes_sent += result;
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;
} /* timer_expired_micro */
return result;
}
/**************************************************************************/
struct iperf_stream *
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);
}
sp->rcv = iperf_udp_recv;
sp->snd = iperf_udp_send;
return sp;
}
/**************************************************************************/
/**
* iperf_udp_accept -- accepts a new UDP connection
* on udp_listener_socket
*returns 0 on success
*
*/
int
iperf_udp_accept(struct iperf_test * test)
{
struct iperf_stream *sp;
struct sockaddr_in sa_peer;
char *buf;
socklen_t len;
int sz;
buf = (char *) malloc(test->default_settings->blksize);
struct udp_datagram *udp = (struct udp_datagram *) buf;
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("connect");
return -1;
}
sp = test->new_stream(test);
sp->socket = test->listener_sock_udp;
setnonblocking(sp->socket);
iperf_init_stream(sp, test);
iperf_add_stream(test, sp);
test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port);
if (test->listener_sock_udp < 0)
return -1;
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;
}
/* 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);
free(buf);
return 0;
}

50
src/iperf_udp.h Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright (c) 2009, The Regents of the University of California, through
Lawrence Berkeley National Laboratory (subject to receipt of any required
approvals from the U.S. Dept. of Energy). All rights reserved.
*/
#ifndef IPERF_UDP_H
#define IPERF_UDP_H
/**
* iperf_udp_accept -- accepts a new UDP connection
* on udp_listener_socket
*returns 0 on success
*
*/
int iperf_udp_accept(struct iperf_test * test);
/**
* iperf_udp_recv -- receives the client data for UDP
*
*returns state of packet received
*
*/
int iperf_udp_recv(struct iperf_stream * sp);
/**
* iperf_udp_send -- sends the client data for UDP
*
* returns: bytes sent
*
*/
int iperf_udp_send(struct iperf_stream * sp);
/**
* iperf_udp_accept -- accepts a new UDP connection
* on udp_listener_socket
*returns 0 on success
*
*/
int iperf_udp_accept(struct iperf_test * test);
struct iperf_stream *iperf_new_udp_stream(struct iperf_test * testp);
#endif /* IPERF_UDP_H */

View File

@ -226,7 +226,7 @@ const char reportCSV_peer[] =
#if defined(linux)
const char report_tcpInfo[] =
"event=TCP_Info CWND=%u RCV_WIND=%u SND_SSTHRESH=%u UNACKED=%u SACK=%u LOST=%u RETRANS=%u FACK=%u RTT=%u";
"event=TCP_Info CWND=%u RCV_WIND=%u SND_SSTHRESH=%u UNACKED=%u SACK=%u LOST=%u RETRANS=%u FACK=%u RTT=%u REORDERING=%u";
#endif
#if defined(__FreeBSD__)
const char report_tcpInfo[] =

View File

@ -13,6 +13,8 @@
* (and related to this, check, test, document 'state machine' aspect of this.
* eg: are TEST_START and TEST_END, and STREAM_END / ALL_STREAMS_END all required?
* is it an error to get these in a strange order? etc. )
* verify placment of all timing calls and total_bytes_sent computations
* break up into client/sever files and TCP/UDP files
* much better/standard error handling throughout
* better packaging/makefile, README, LICENCE, etc files
* cleanup/fix/test UDP mode
@ -43,10 +45,13 @@
#include <netinet/tcp.h>
#include "iperf.h"
#include "iperf_api.h"
#include "iperf_server_api.h"
#include "units.h"
#include "locale.h"
int iperf_run(struct iperf_test * test);
/**************************************************************************/
@ -186,6 +191,11 @@ main(int argc, char **argv)
}
}
/* untill this is done.... */
if (test->protocol == Pudp) {
printf("UDP mode not yet supported. Exiting. \n");
exit(0);
}
//printf("in main: calling iperf_init_test \n");
if (test->role == 'c')
@ -204,3 +214,27 @@ main(int argc, char **argv)
printf("\niperf Done.\n");
exit(0);
}
/**************************************************************************/
int
iperf_run(struct iperf_test * test)
{
test->default_settings->state = TEST_RUNNING;
switch (test->role)
{
case 's':
iperf_run_server(test);
return 0;
break;
case 'c':
iperf_run_client(test);
return 0;
break;
default:
return -1;
break;
}
printf("Done iperf_run. \n");
}

View File

@ -4,8 +4,11 @@
#include <sys/types.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <netdb.h>
#include <string.h>
#include <sys/fcntl.h>
#include "net.h"
#include "timer.h"
@ -52,6 +55,8 @@ netdial(int proto, char *client, int port)
return (-1);
}
/***************************************************************/
int
netannounce(int proto, char *local, int port)
{
@ -163,3 +168,97 @@ mread(int fd, char *bufp, int n)
return ((int) count);
}
/*************************************************************************/
/**
* getsock_tcp_mss - Returns the MSS size for TCP
*
*/
int
getsock_tcp_mss(int inSock)
{
int mss = 0;
int rc;
socklen_t len;
assert(inSock >= 0); /* print error and exit if this is not true */
/* query for mss */
len = sizeof(mss);
rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
return mss;
}
/*************************************************************/
/* sets TCP_NODELAY and TCP_MAXSEG if requested */
int
set_tcp_options(int sock, int no_delay, int mss)
{
socklen_t len;
if (no_delay == 1) {
int no_delay = 1;
len = sizeof(no_delay);
int rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
(char *)&no_delay, len);
if (rc == -1) {
perror("TCP_NODELAY");
return -1;
}
}
#ifdef TCP_MAXSEG
if (mss > 0) {
int rc;
int new_mss;
len = sizeof(new_mss);
assert(sock != -1);
/* set */
new_mss = mss;
len = sizeof(new_mss);
rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
if (rc == -1) {
perror("setsockopt");
return -1;
}
/* verify results */
rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
if (new_mss != mss) {
perror("setsockopt value mismatch");
return -1;
}
}
#endif
return 0;
}
/****************************************************************************/
int
setnonblocking(int sock)
{
int opts;
opts = (opts | O_NONBLOCK);
if (fcntl(sock, F_SETFL, opts) < 0)
{
perror("fcntl(F_SETFL)");
return -1;
}
return 0;
}

View File

@ -3,5 +3,11 @@ int netannounce(int proto, char *local, int port);
int Nwrite(int fd, char *buf, int count, int prot);
int mread(int fd, char *bufp, int n);
int Nread(int fd, char *buf, int count, int prot);
int getsock_tcp_mss(int inSock);
int set_tcp_options(int sock, int no_delay, int mss);
int setnonblocking(int sock);

View File

@ -44,8 +44,10 @@ get_tcpinfo(struct iperf_test *test, struct iperf_interval_results *rp)
perror("getsockopt");
}
memcpy(&rp->tcpInfo, &tcpInfo, sizeof(tcpInfo));
/* for debugging
printf(" got TCP_INFO: %d, %d, %d, %d\n", rp->tcpInfo.tcpi_snd_cwnd,
rp->tcpInfo.tcpi_snd_ssthresh, rp->tcpInfo.tcpi_rcv_space, rp->tcpInfo.tcpi_rtt);
*/
return;
#else
return;
@ -59,7 +61,7 @@ print_tcpinfo(struct iperf_interval_results *r)
#if defined(linux)
printf(report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
r->tcpInfo.tcpi_rcv_ssthresh, r->tcpInfo.tcpi_unacked, r->tcpInfo.tcpi_sacked,
r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets);
r->tcpInfo.tcpi_lost, r->tcpInfo.tcpi_retrans, r->tcpInfo.tcpi_fackets, tcpi_reordering);
#endif
#if defined(__FreeBSD__)
printf(report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_rcv_space,

View File

@ -55,6 +55,8 @@
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "iperf.h"