Added support for adding new protocols. Slightly modified iperf_error()
Этот коммит содержится в:
родитель
b60a49dd37
Коммит
8a0b5a5d18
18
src/iperf.h
18
src/iperf.h
@ -12,6 +12,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
typedef uint64_t iperf_size_t;
|
typedef uint64_t iperf_size_t;
|
||||||
|
|
||||||
@ -100,6 +101,20 @@ struct iperf_stream
|
|||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct iperf_test;
|
||||||
|
|
||||||
|
struct protocol {
|
||||||
|
int id;
|
||||||
|
char *name;
|
||||||
|
int (*accept)(struct iperf_test *);
|
||||||
|
int (*listen)(struct iperf_test *);
|
||||||
|
int (*connect)(struct iperf_test *);
|
||||||
|
int (*send)(struct iperf_stream *);
|
||||||
|
int (*recv)(struct iperf_stream *);
|
||||||
|
int (*init)(struct iperf_test *);
|
||||||
|
SLIST_ENTRY(protocol) protocols;
|
||||||
|
};
|
||||||
|
|
||||||
struct iperf_test
|
struct iperf_test
|
||||||
{
|
{
|
||||||
char role; /* c' lient or 's' erver */
|
char role; /* c' lient or 's' erver */
|
||||||
@ -112,6 +127,7 @@ struct iperf_test
|
|||||||
int ctrl_sck;
|
int ctrl_sck;
|
||||||
int listener_tcp;
|
int listener_tcp;
|
||||||
int listener_udp;
|
int listener_udp;
|
||||||
|
int prot_listener;
|
||||||
|
|
||||||
/* boolen variables for Options */
|
/* boolen variables for Options */
|
||||||
int daemon; /* -D option */
|
int daemon; /* -D option */
|
||||||
@ -149,6 +165,8 @@ struct iperf_test
|
|||||||
|
|
||||||
struct iperf_stream *streams; /* pointer to list of struct stream */
|
struct iperf_stream *streams; /* pointer to list of struct stream */
|
||||||
struct iperf_settings *default_settings;
|
struct iperf_settings *default_settings;
|
||||||
|
|
||||||
|
SLIST_HEAD(slisthead, protocol) protocols;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
208
src/iperf_api.c
208
src/iperf_api.c
@ -14,6 +14,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -344,24 +345,18 @@ iperf_recv(struct iperf_test *test)
|
|||||||
int
|
int
|
||||||
iperf_init_test(struct iperf_test *test)
|
iperf_init_test(struct iperf_test *test)
|
||||||
{
|
{
|
||||||
char *prot;
|
|
||||||
struct iperf_stream *sp;
|
struct iperf_stream *sp;
|
||||||
|
struct protocol *prot;
|
||||||
int64_t dtargus;
|
int64_t dtargus;
|
||||||
|
|
||||||
if (test->protocol == Pudp) {
|
SLIST_FOREACH(prot, &test->protocols, protocols) {
|
||||||
prot = "UDP";
|
if (test->protocol == prot->id) {
|
||||||
dtargus = (int64_t) test->default_settings->blksize * SEC_TO_US * 8;
|
if (prot->init) {
|
||||||
dtargus /= test->default_settings->rate;
|
if (prot->init(test) < 0)
|
||||||
|
return (-1);
|
||||||
assert(dtargus != 0);
|
}
|
||||||
|
break;
|
||||||
for (sp = test->streams; sp; sp = sp->next) {
|
|
||||||
sp->send_timer = new_timer(dtargus / SEC_TO_US, dtargus % SEC_TO_US);
|
|
||||||
if (sp->send_timer == NULL)
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
prot = "TCP";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set timers */
|
/* Set timers */
|
||||||
@ -369,10 +364,10 @@ iperf_init_test(struct iperf_test *test)
|
|||||||
test->timer = new_timer(test->duration, 0);
|
test->timer = new_timer(test->duration, 0);
|
||||||
if (test->timer == NULL)
|
if (test->timer == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
printf(test_start_time, prot, test->num_streams, test->default_settings->blksize,
|
printf(test_start_time, prot->name, test->num_streams, test->default_settings->blksize,
|
||||||
test->duration);
|
test->duration);
|
||||||
} else {
|
} else {
|
||||||
printf(test_start_bytes, prot, test->num_streams, test->default_settings->blksize,
|
printf(test_start_bytes, prot->name, test->num_streams, test->default_settings->blksize,
|
||||||
test->default_settings->bytes);
|
test->default_settings->bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,9 +549,12 @@ parse_parameters(struct iperf_test *test)
|
|||||||
int
|
int
|
||||||
iperf_exchange_parameters(struct iperf_test * test)
|
iperf_exchange_parameters(struct iperf_test * test)
|
||||||
{
|
{
|
||||||
|
int s;
|
||||||
|
struct protocol *prot;
|
||||||
|
/*
|
||||||
int s, opt, len;
|
int s, opt, len;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
|
*/
|
||||||
if (test->role == 'c') {
|
if (test->role == 'c') {
|
||||||
|
|
||||||
if (package_parameters(test) < 0)
|
if (package_parameters(test) < 0)
|
||||||
@ -568,64 +566,17 @@ iperf_exchange_parameters(struct iperf_test * test)
|
|||||||
|
|
||||||
printf(" cookie: %s\n", test->default_settings->cookie);
|
printf(" cookie: %s\n", test->default_settings->cookie);
|
||||||
|
|
||||||
if (test->protocol == Pudp) {
|
SLIST_FOREACH(prot, &test->protocols, protocols) {
|
||||||
if ((test->listener_udp = netannounce(test->protocol, NULL, test->server_port)) < 0) {
|
if (prot->id == test->protocol)
|
||||||
i_errno = IELISTEN;
|
break;
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
FD_SET(test->listener_udp, &test->read_set);
|
|
||||||
test->max_fd = (test->listener_udp > test->max_fd) ? test->listener_udp : test->max_fd;
|
|
||||||
} else if (test->protocol == Ptcp) {
|
|
||||||
if (test->no_delay || test->default_settings->mss) {
|
|
||||||
FD_CLR(test->listener_tcp, &test->read_set);
|
|
||||||
close(test->listener_tcp);
|
|
||||||
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
||||||
i_errno = IELISTEN;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
if (test->no_delay) {
|
|
||||||
opt = 1;
|
|
||||||
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
|
||||||
i_errno = IESETNODELAY;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
printf(" TCP NODELAY: on\n");
|
|
||||||
}
|
|
||||||
// XXX: Setting MSS is very buggy!
|
|
||||||
if ((opt = test->default_settings->mss)) {
|
|
||||||
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
|
||||||
i_errno = IESETMSS;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
printf(" TCP MSS: %d\n", opt);
|
|
||||||
}
|
|
||||||
opt = 1;
|
|
||||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
|
||||||
i_errno = IEREUSEADDR;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
|
||||||
sa.sin_family = AF_INET;
|
|
||||||
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
sa.sin_port = htons(test->server_port);
|
|
||||||
if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
|
|
||||||
close(s);
|
|
||||||
i_errno = IELISTEN;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(s, 5) < 0) {
|
|
||||||
i_errno = IELISTEN;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
test->listener_tcp = s;
|
|
||||||
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
|
||||||
FD_SET(test->listener_tcp, &test->read_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((s = prot->listen(test)) < 0)
|
||||||
|
return (-1);
|
||||||
|
FD_SET(s, &test->read_set);
|
||||||
|
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
||||||
|
test->prot_listener = s;
|
||||||
|
|
||||||
// Send the control message to create streams and start the test
|
// Send the control message to create streams and start the test
|
||||||
test->state = CREATE_STREAMS;
|
test->state = CREATE_STREAMS;
|
||||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||||
@ -916,6 +867,7 @@ iperf_defaults(struct iperf_test * testp)
|
|||||||
testp->duration = DURATION;
|
testp->duration = DURATION;
|
||||||
testp->server_port = PORT;
|
testp->server_port = PORT;
|
||||||
testp->ctrl_sck = -1;
|
testp->ctrl_sck = -1;
|
||||||
|
testp->prot_listener = -1;
|
||||||
|
|
||||||
testp->new_stream = iperf_new_tcp_stream;
|
testp->new_stream = iperf_new_tcp_stream;
|
||||||
testp->stats_callback = iperf_stats_callback;
|
testp->stats_callback = iperf_stats_callback;
|
||||||
@ -933,6 +885,39 @@ iperf_defaults(struct iperf_test * testp)
|
|||||||
testp->default_settings->mss = 0;
|
testp->default_settings->mss = 0;
|
||||||
testp->default_settings->bytes = 0;
|
testp->default_settings->bytes = 0;
|
||||||
memset(testp->default_settings->cookie, 0, COOKIE_SIZE);
|
memset(testp->default_settings->cookie, 0, COOKIE_SIZE);
|
||||||
|
|
||||||
|
/* Set up protocol list */
|
||||||
|
SLIST_INIT(&testp->protocols);
|
||||||
|
|
||||||
|
struct protocol *tcp, *udp;
|
||||||
|
tcp = (struct protocol *) malloc(sizeof(struct protocol));
|
||||||
|
if (!tcp)
|
||||||
|
return (-1);
|
||||||
|
memset(tcp, 0, sizeof(struct protocol));
|
||||||
|
udp = (struct protocol *) malloc(sizeof(struct protocol));
|
||||||
|
if (!udp)
|
||||||
|
return (-1);
|
||||||
|
memset(udp, 0, sizeof(struct protocol));
|
||||||
|
|
||||||
|
tcp->id = Ptcp;
|
||||||
|
tcp->name = "TCP";
|
||||||
|
tcp->accept = iperf_tcp_accept;
|
||||||
|
tcp->listen = iperf_tcp_listen;
|
||||||
|
tcp->connect = iperf_tcp_connect;
|
||||||
|
tcp->send = iperf_tcp_send;
|
||||||
|
tcp->recv = iperf_tcp_recv;
|
||||||
|
tcp->init = NULL;
|
||||||
|
SLIST_INSERT_HEAD(&testp->protocols, tcp, protocols);
|
||||||
|
|
||||||
|
udp->id = Pudp;
|
||||||
|
udp->name = "UDP";
|
||||||
|
udp->accept = iperf_udp_accept;
|
||||||
|
udp->listen = iperf_udp_listen;
|
||||||
|
udp->connect = iperf_udp_connect;
|
||||||
|
udp->send = iperf_udp_send;
|
||||||
|
udp->recv = iperf_udp_recv;
|
||||||
|
udp->init = iperf_udp_init;
|
||||||
|
SLIST_INSERT_AFTER(tcp, udp, protocols);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
@ -940,70 +925,19 @@ iperf_defaults(struct iperf_test * testp)
|
|||||||
int
|
int
|
||||||
iperf_create_streams(struct iperf_test *test)
|
iperf_create_streams(struct iperf_test *test)
|
||||||
{
|
{
|
||||||
|
int i, s;
|
||||||
|
struct protocol *prot;
|
||||||
struct iperf_stream *sp;
|
struct iperf_stream *sp;
|
||||||
struct sockaddr_in sa;
|
|
||||||
struct hostent *hent;
|
|
||||||
int i, s, buf, opt;
|
|
||||||
|
|
||||||
for (i = 0; i < test->num_streams; ++i) {
|
for (i = 0; i < test->num_streams; ++i) {
|
||||||
if (test->protocol == Ptcp && (test->no_delay || test->default_settings->mss)) {
|
|
||||||
if ((hent = gethostbyname(test->server_hostname)) == 0) {
|
|
||||||
i_errno = IECREATESTREAM;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
||||||
i_errno = IECREATESTREAM;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
|
||||||
sa.sin_family = AF_INET;
|
|
||||||
memcpy(&sa.sin_addr.s_addr, hent->h_addr, sizeof(sa.sin_addr.s_addr));
|
|
||||||
sa.sin_port = htons(test->server_port);
|
|
||||||
|
|
||||||
if (test->no_delay) {
|
SLIST_FOREACH(prot, &test->protocols, protocols) {
|
||||||
opt = 1;
|
if (prot->id == test->protocol)
|
||||||
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
break;
|
||||||
i_errno = IECREATESTREAM;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt = test->default_settings->mss) {
|
|
||||||
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
|
||||||
i_errno = IECREATESTREAM;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0 && errno != EINPROGRESS) {
|
|
||||||
i_errno = IESTREAMCONNECT;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s = netdial(test->protocol, test->server_hostname, test->server_port);
|
|
||||||
if (s < 0) {
|
|
||||||
i_errno = IESTREAMCONNECT;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test->protocol == Ptcp) {
|
if ((s = prot->connect(test)) < 0)
|
||||||
if (Nwrite(s, test->default_settings->cookie, COOKIE_SIZE, Ptcp) < 0) {
|
return (-1);
|
||||||
i_errno = IESENDCOOKIE;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Write to the UDP stream to give the server this stream's credentials */
|
|
||||||
if (write(s, &buf, sizeof(i)) < 0) {
|
|
||||||
// XXX: Should this be changed to IESTREAMCONNECT?
|
|
||||||
i_errno = IESTREAMWRITE;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
/* Wait until the server confirms the client UDP write */
|
|
||||||
// XXX: Should this read be TCP instead?
|
|
||||||
if (read(s, &buf, sizeof(i)) < 0) {
|
|
||||||
i_errno = IESTREAMREAD;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_SET(s, &test->read_set);
|
FD_SET(s, &test->read_set);
|
||||||
FD_SET(s, &test->write_set);
|
FD_SET(s, &test->write_set);
|
||||||
@ -1021,7 +955,7 @@ iperf_create_streams(struct iperf_test *test)
|
|||||||
connect_msg(sp);
|
connect_msg(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1112,11 +1046,21 @@ iperf_connect(struct iperf_test *test)
|
|||||||
void
|
void
|
||||||
iperf_free_test(struct iperf_test * test)
|
iperf_free_test(struct iperf_test * test)
|
||||||
{
|
{
|
||||||
|
struct protocol *prot;
|
||||||
|
|
||||||
free(test->default_settings);
|
free(test->default_settings);
|
||||||
free_timer(test->timer);
|
free_timer(test->timer);
|
||||||
free_timer(test->stats_timer);
|
free_timer(test->stats_timer);
|
||||||
free_timer(test->reporter_timer);
|
free_timer(test->reporter_timer);
|
||||||
|
|
||||||
|
/* Free protocol list */
|
||||||
|
while (!SLIST_EMPTY(&test->protocols)) {
|
||||||
|
prot = SLIST_FIRST(&test->protocols);
|
||||||
|
SLIST_REMOVE_HEAD(&test->protocols, protocols);
|
||||||
|
free(prot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: Why are we setting these values to NULL? */
|
||||||
test->streams = NULL;
|
test->streams = NULL;
|
||||||
test->accept = NULL;
|
test->accept = NULL;
|
||||||
test->stats_callback = NULL;
|
test->stats_callback = NULL;
|
||||||
|
@ -131,6 +131,9 @@ iperf_strerror(int i_errno)
|
|||||||
case IEINITSTREAM:
|
case IEINITSTREAM:
|
||||||
snprintf(errstr, len, "unable to initialize stream");
|
snprintf(errstr, len, "unable to initialize stream");
|
||||||
break;
|
break;
|
||||||
|
case IESTREAMLISTEN:
|
||||||
|
snprintf(errstr, len, "unable to start stream listener");
|
||||||
|
break;
|
||||||
case IESTREAMCONNECT:
|
case IESTREAMCONNECT:
|
||||||
snprintf(errstr, len, "unable to connect stream");
|
snprintf(errstr, len, "unable to connect stream");
|
||||||
break;
|
break;
|
||||||
|
@ -56,16 +56,17 @@ enum {
|
|||||||
/* Stream errors */
|
/* Stream errors */
|
||||||
IECREATESTREAM = 36, // Unable to create a new stream (check herror/perror)
|
IECREATESTREAM = 36, // Unable to create a new stream (check herror/perror)
|
||||||
IEINITSTREAM = 37, // Unable to initialize stream (check herror/perror)
|
IEINITSTREAM = 37, // Unable to initialize stream (check herror/perror)
|
||||||
IESTREAMCONNECT = 38, // Unable to connect stream (check herror/perror)
|
IESTREAMLISTEN = 38, // Unable to start stream listener (check perror)
|
||||||
IESTREAMACCEPT = 39, // Unable to accepte stream connection (check perror)
|
IESTREAMCONNECT = 39, // Unable to connect stream (check herror/perror)
|
||||||
IESTREAMWRITE = 40, // Unable to write to stream socket (check perror)
|
IESTREAMACCEPT = 40, // Unable to accepte stream connection (check perror)
|
||||||
IESTREAMREAD = 41, // Unable to read from stream (check perror)
|
IESTREAMWRITE = 41, // Unable to write to stream socket (check perror)
|
||||||
IESTREAMCLOSE = 42, // Stream has closed unexpectedly
|
IESTREAMREAD = 42, // Unable to read from stream (check perror)
|
||||||
IESTREAMID = 43, // Stream has invalid ID
|
IESTREAMCLOSE = 43, // Stream has closed unexpectedly
|
||||||
|
IESTREAMID = 44, // Stream has invalid ID
|
||||||
|
|
||||||
/* Timer errors */
|
/* Timer errors */
|
||||||
IENEWTIMER = 44, // Unable to create new timer (check perror)
|
IENEWTIMER = 45, // Unable to create new timer (check perror)
|
||||||
IEUPDATETIMER = 45, // Unable to update timer (check perror)
|
IEUPDATETIMER = 46, // Unable to update timer (check perror)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@ -36,6 +37,7 @@
|
|||||||
#include "iperf_udp.h"
|
#include "iperf_udp.h"
|
||||||
#include "iperf_tcp.h"
|
#include "iperf_tcp.h"
|
||||||
#include "iperf_error.h"
|
#include "iperf_error.h"
|
||||||
|
#include "iperf_util.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
@ -322,6 +324,8 @@ iperf_run_server(struct iperf_test *test)
|
|||||||
{
|
{
|
||||||
int result, s;
|
int result, s;
|
||||||
fd_set temp_read_set, temp_write_set;
|
fd_set temp_read_set, temp_write_set;
|
||||||
|
struct iperf_stream *sp;
|
||||||
|
struct protocol *prot;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
// Open socket and listen
|
// Open socket and listen
|
||||||
@ -372,26 +376,37 @@ iperf_run_server(struct iperf_test *test)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (test->state == CREATE_STREAMS) {
|
if (test->state == CREATE_STREAMS) {
|
||||||
if (test->protocol == Ptcp) {
|
if (FD_ISSET(test->prot_listener, &temp_read_set)) {
|
||||||
if (FD_ISSET(test->listener_tcp, &temp_read_set)) {
|
|
||||||
if (iperf_accept_tcp_stream(test) < 0) {
|
SLIST_FOREACH(prot, &test->protocols, protocols) {
|
||||||
return (-1);
|
if (prot->id == test->protocol)
|
||||||
}
|
break;
|
||||||
FD_CLR(test->listener_tcp, &temp_read_set);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (FD_ISSET(test->listener_udp, &temp_read_set)) {
|
if ((s = prot->accept(test)) < 0)
|
||||||
if (iperf_udp_accept(test) < 0) {
|
return (-1);
|
||||||
|
|
||||||
|
if (!is_closed(s)) {
|
||||||
|
sp = test->new_stream(test);
|
||||||
|
if (!sp)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
sp->socket = s;
|
||||||
FD_CLR(test->listener_udp, &temp_read_set);
|
if (iperf_init_stream(sp, test) < 0)
|
||||||
|
return (-1);
|
||||||
|
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->streams_accepted++;
|
||||||
|
connect_msg(sp);
|
||||||
}
|
}
|
||||||
|
FD_CLR(test->prot_listener, &temp_read_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test->streams_accepted == test->num_streams) {
|
if (test->streams_accepted == test->num_streams) {
|
||||||
if (test->protocol == Pudp) {
|
if (test->protocol != Ptcp) {
|
||||||
FD_CLR(test->listener_udp, &test->read_set);
|
FD_CLR(test->prot_listener, &test->read_set);
|
||||||
close(test->listener_udp);
|
close(test->prot_listener);
|
||||||
test->listener_udp = -1;
|
|
||||||
} else if (test->protocol == Ptcp) {
|
} else if (test->protocol == Ptcp) {
|
||||||
if (test->no_delay || test->default_settings->mss) {
|
if (test->no_delay || test->default_settings->mss) {
|
||||||
FD_CLR(test->listener_tcp, &test->read_set);
|
FD_CLR(test->listener_tcp, &test->read_set);
|
||||||
@ -405,6 +420,7 @@ iperf_run_server(struct iperf_test *test)
|
|||||||
FD_SET(test->listener_tcp, &test->read_set);
|
FD_SET(test->listener_tcp, &test->read_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
test->prot_listener = -1;
|
||||||
test->state = TEST_START;
|
test->state = TEST_START;
|
||||||
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) {
|
||||||
i_errno = IESENDMESSAGE;
|
i_errno = IESENDMESSAGE;
|
||||||
|
210
src/iperf_tcp.c
210
src/iperf_tcp.c
@ -5,6 +5,7 @@
|
|||||||
* approvals from the U.S. Dept. of Energy). All rights reserved.
|
* approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// XXX: Surely we do not need all these headers!
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -30,6 +31,7 @@
|
|||||||
|
|
||||||
#include "iperf.h"
|
#include "iperf.h"
|
||||||
#include "iperf_api.h"
|
#include "iperf_api.h"
|
||||||
|
#include "iperf_error.h"
|
||||||
#include "iperf_server_api.h"
|
#include "iperf_server_api.h"
|
||||||
#include "iperf_tcp.h"
|
#include "iperf_tcp.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
@ -38,50 +40,36 @@
|
|||||||
#include "iperf_util.h"
|
#include "iperf_util.h"
|
||||||
#include "locale.h"
|
#include "locale.h"
|
||||||
|
|
||||||
|
// XXX: Does this belong here? We should probably declare this in iperf_api.c then put an extern in the header
|
||||||
jmp_buf env; /* to handle longjmp on signal */
|
jmp_buf env; /* to handle longjmp on signal */
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/* iperf_tcp_recv
|
||||||
* iperf_tcp_recv -- receives the data for TCP
|
|
||||||
* and the Param/result message exchange
|
|
||||||
*returns state of packet received
|
|
||||||
*
|
*
|
||||||
|
* receives the data for TCP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
iperf_tcp_recv(struct iperf_stream * sp)
|
iperf_tcp_recv(struct iperf_stream * sp)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int size = sp->settings->blksize;
|
int 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 {
|
|
||||||
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
|
|
||||||
} while (result == -1 && errno == EINTR);
|
|
||||||
#else
|
|
||||||
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
||||||
#endif
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp->result->bytes_received += result;
|
sp->result->bytes_received += result;
|
||||||
sp->result->bytes_received_this_interval += result;
|
sp->result->bytes_received_this_interval += result;
|
||||||
|
|
||||||
return result;
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/* iperf_tcp_send
|
||||||
* iperf_tcp_send -- sends the client data for TCP
|
|
||||||
* and the Param/result message exchanges
|
|
||||||
* returns: bytes sent
|
|
||||||
*
|
*
|
||||||
|
* sends the data for TCP
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
iperf_tcp_send(struct iperf_stream * sp)
|
iperf_tcp_send(struct iperf_stream * sp)
|
||||||
@ -89,11 +77,8 @@ iperf_tcp_send(struct iperf_stream * sp)
|
|||||||
int result;
|
int result;
|
||||||
int size = sp->settings->blksize;
|
int size = sp->settings->blksize;
|
||||||
|
|
||||||
#ifdef USE_SEND
|
|
||||||
result = send(sp->socket, sp->buffer, size, 0);
|
|
||||||
#else
|
|
||||||
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
|
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
|
||||||
#endif
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -101,9 +86,11 @@ iperf_tcp_send(struct iperf_stream * sp)
|
|||||||
sp->result->bytes_sent += result;
|
sp->result->bytes_sent += result;
|
||||||
sp->result->bytes_sent_this_interval += result;
|
sp->result->bytes_sent_this_interval += result;
|
||||||
|
|
||||||
return result;
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// XXX: This function is now deprecated
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
struct iperf_stream *
|
struct iperf_stream *
|
||||||
iperf_new_tcp_stream(struct iperf_test * testp)
|
iperf_new_tcp_stream(struct iperf_test * testp)
|
||||||
@ -117,51 +104,164 @@ iperf_new_tcp_stream(struct iperf_test * testp)
|
|||||||
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
|
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
|
||||||
sp->snd = iperf_tcp_send; /* pointer to send function */
|
sp->snd = iperf_tcp_send; /* pointer to send function */
|
||||||
|
|
||||||
/* XXX: not yet written... (what is this supposed to do? ) */
|
|
||||||
//sp->update_stats = iperf_tcp_update_stats;
|
|
||||||
|
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
/** XXX: This function is not currently in use!
|
/* iperf_tcp_accept
|
||||||
* iperf_tcp_accept -- accepts a new TCP connection
|
|
||||||
* on tcp_listener_socket for TCP data and param/result
|
|
||||||
* exchange messages
|
|
||||||
* returns 0 on success
|
|
||||||
*
|
*
|
||||||
|
* accept a new TCP stream connection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
iperf_tcp_accept(struct iperf_test * test)
|
iperf_tcp_accept(struct iperf_test * test)
|
||||||
{
|
{
|
||||||
|
int s;
|
||||||
|
int rbuf = ACCESS_DENIED;
|
||||||
|
char cookie[COOKIE_SIZE];
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
int peersock;
|
|
||||||
struct iperf_stream *sp;
|
|
||||||
|
|
||||||
len = sizeof(addr);
|
len = sizeof(addr);
|
||||||
peersock = accept(test->listener_tcp, (struct sockaddr *) & addr, &len);
|
if ((s = accept(test->listener_tcp, (struct sockaddr *) &addr, &len)) < 0) {
|
||||||
if (peersock < 0) {
|
i_errno = IESTREAMCONNECT;
|
||||||
// XXX: Needs to implement better error handling
|
return (-1);
|
||||||
printf("Error in accept(): %s\n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: This doesn't fit our API model!
|
if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
|
||||||
sp = test->new_stream(test);
|
i_errno = IERECVCOOKIE;
|
||||||
sp->socket = peersock;
|
return (-1);
|
||||||
iperf_init_stream(sp, test);
|
}
|
||||||
iperf_add_stream(test, sp);
|
|
||||||
|
|
||||||
FD_SET(peersock, &test->read_set); /* add new socket to master set */
|
if (strcmp(test->default_settings->cookie, cookie) != 0) {
|
||||||
FD_SET(peersock, &test->write_set);
|
if (Nwrite(s, &rbuf, sizeof(char), Ptcp) < 0) {
|
||||||
test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd;
|
i_errno = IESENDMESSAGE;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
|
|
||||||
connect_msg(sp); /* print connect message */
|
return (s);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* iperf_tcp_listen
|
||||||
|
*
|
||||||
|
* start up a listener for TCP stream connections
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iperf_tcp_listen(struct iperf_test *test)
|
||||||
|
{
|
||||||
|
int s, opt;
|
||||||
|
struct sockaddr_in sa;
|
||||||
|
s = test->listener_tcp;
|
||||||
|
|
||||||
|
if (test->no_delay || test->default_settings->mss) {
|
||||||
|
FD_CLR(s, &test->read_set);
|
||||||
|
close(s);
|
||||||
|
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
i_errno = IESTREAMLISTEN;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (test->no_delay) {
|
||||||
|
opt = 1;
|
||||||
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
||||||
|
i_errno = IESETNODELAY;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
printf(" TCP NODELAY: on\n");
|
||||||
|
}
|
||||||
|
// XXX: Setting MSS is very buggy!
|
||||||
|
if ((opt = test->default_settings->mss)) {
|
||||||
|
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
||||||
|
i_errno = IESETMSS;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
printf(" TCP MSS: %d\n", opt);
|
||||||
|
}
|
||||||
|
opt = 1;
|
||||||
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
||||||
|
i_errno = IEREUSEADDR;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sin_family = AF_INET;
|
||||||
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
sa.sin_port = htons(test->server_port);
|
||||||
|
|
||||||
|
if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
|
||||||
|
close(s);
|
||||||
|
i_errno = IESTREAMLISTEN;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(s, 5) < 0) {
|
||||||
|
i_errno = IESTREAMLISTEN;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test->listener_tcp = s;
|
||||||
|
/*
|
||||||
|
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
||||||
|
FD_SET(test->listener_tcp, &test->read_set);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* iperf_tcp_connect
|
||||||
|
*
|
||||||
|
* connect to a TCP stream listener
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iperf_tcp_connect(struct iperf_test *test)
|
||||||
|
{
|
||||||
|
int s, opt;
|
||||||
|
struct sockaddr_in sa;
|
||||||
|
struct hostent *hent;
|
||||||
|
|
||||||
|
if ((hent = gethostbyname(test->server_hostname)) == 0) {
|
||||||
|
i_errno = IESTREAMCONNECT;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
i_errno = IESTREAMCONNECT;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sin_family = AF_INET;
|
||||||
|
memcpy(&sa.sin_addr.s_addr, hent->h_addr, sizeof(sa.sin_addr.s_addr));
|
||||||
|
sa.sin_port = htons(test->server_port);
|
||||||
|
|
||||||
|
/* Set TCP options */
|
||||||
|
if (test->no_delay) {
|
||||||
|
opt = 1;
|
||||||
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
||||||
|
i_errno = IESETNODELAY;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt = test->default_settings->mss) {
|
||||||
|
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
||||||
|
i_errno = IESETMSS;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0 && errno != EINPROGRESS) {
|
||||||
|
i_errno = IESTREAMCONNECT;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send cookie for verification */
|
||||||
|
if (Nwrite(s, test->default_settings->cookie, COOKIE_SIZE, Ptcp) < 0) {
|
||||||
|
i_errno = IESENDCOOKIE;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*returns 0 on success
|
*returns 0 on success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_tcp_accept(struct iperf_test * test);
|
int iperf_tcp_accept(struct iperf_test *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iperf_tcp_recv -- receives the data for TCP
|
* iperf_tcp_recv -- receives the data for TCP
|
||||||
@ -22,7 +22,7 @@ int iperf_tcp_accept(struct iperf_test * test);
|
|||||||
*returns state of packet received
|
*returns state of packet received
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_tcp_recv(struct iperf_stream * sp);
|
int iperf_tcp_recv(struct iperf_stream *);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,7 +31,13 @@ int iperf_tcp_recv(struct iperf_stream * sp);
|
|||||||
* returns: bytes sent
|
* returns: bytes sent
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_tcp_send(struct iperf_stream * sp);
|
int iperf_tcp_send(struct iperf_stream *);
|
||||||
|
|
||||||
|
|
||||||
|
int iperf_tcp_listen(struct iperf_test *);
|
||||||
|
|
||||||
|
int iperf_tcp_connect(struct iperf_test *);
|
||||||
|
|
||||||
|
|
||||||
struct iperf_stream *iperf_new_tcp_stream(struct iperf_test * testp);
|
struct iperf_stream *iperf_new_tcp_stream(struct iperf_test * testp);
|
||||||
|
|
||||||
|
135
src/iperf_udp.c
135
src/iperf_udp.c
@ -10,6 +10,7 @@
|
|||||||
* NOTE: not yet finished / working
|
* NOTE: not yet finished / working
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// XXX: Do we really need all these headers?
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -42,15 +43,10 @@
|
|||||||
#include "locale.h"
|
#include "locale.h"
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/* iperf_udp_recv
|
||||||
|
|
||||||
/**
|
|
||||||
* iperf_udp_recv -- receives the client data for UDP
|
|
||||||
*
|
|
||||||
*returns state of packet received
|
|
||||||
*
|
*
|
||||||
|
* receives the data for UDP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
iperf_udp_recv(struct iperf_stream *sp)
|
iperf_udp_recv(struct iperf_stream *sp)
|
||||||
{
|
{
|
||||||
@ -60,17 +56,12 @@ iperf_udp_recv(struct iperf_stream *sp)
|
|||||||
double transit = 0, d = 0;
|
double transit = 0, d = 0;
|
||||||
struct timeval sent_time, arrival_time;
|
struct timeval sent_time, arrival_time;
|
||||||
|
|
||||||
#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);
|
result = Nread(sp->socket, sp->buffer, size, Pudp);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp->result->bytes_received += result;
|
sp->result->bytes_received += result;
|
||||||
sp->result->bytes_received_this_interval += result;
|
sp->result->bytes_received_this_interval += result;
|
||||||
|
|
||||||
@ -106,11 +97,14 @@ iperf_udp_recv(struct iperf_stream *sp)
|
|||||||
// J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
|
// J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
|
||||||
sp->jitter += (d - sp->jitter) / 16.0;
|
sp->jitter += (d - sp->jitter) / 16.0;
|
||||||
|
|
||||||
return result;
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/* iperf_udp_send
|
||||||
|
*
|
||||||
|
* sends the data for UDP
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
iperf_udp_send(struct iperf_stream *sp)
|
iperf_udp_send(struct iperf_stream *sp)
|
||||||
{
|
{
|
||||||
@ -139,11 +133,7 @@ iperf_udp_send(struct iperf_stream *sp)
|
|||||||
memcpy(sp->buffer+4, &usec, sizeof(usec));
|
memcpy(sp->buffer+4, &usec, sizeof(usec));
|
||||||
memcpy(sp->buffer+8, &pcount, sizeof(pcount));
|
memcpy(sp->buffer+8, &pcount, sizeof(pcount));
|
||||||
|
|
||||||
#ifdef USE_SEND
|
|
||||||
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 (result < 0)
|
if (result < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -165,10 +155,11 @@ iperf_udp_send(struct iperf_stream *sp)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
// XXX: This function is deprecated
|
||||||
struct iperf_stream *
|
struct iperf_stream *
|
||||||
iperf_new_udp_stream(struct iperf_test * testp)
|
iperf_new_udp_stream(struct iperf_test * testp)
|
||||||
{
|
{
|
||||||
@ -186,14 +177,10 @@ iperf_new_udp_stream(struct iperf_test * testp)
|
|||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
/**
|
/* iperf_udp_accept
|
||||||
* iperf_udp_accept -- accepts a new UDP connection
|
|
||||||
* on udp_listener_socket
|
|
||||||
*returns 0 on success
|
|
||||||
*
|
*
|
||||||
|
* accepts a new UDP connection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iperf_udp_accept(struct iperf_test *test)
|
iperf_udp_accept(struct iperf_test *test)
|
||||||
{
|
{
|
||||||
@ -203,10 +190,10 @@ iperf_udp_accept(struct iperf_test *test)
|
|||||||
socklen_t len;
|
socklen_t len;
|
||||||
int sz, s;
|
int sz, s;
|
||||||
|
|
||||||
s = test->listener_udp;
|
s = test->prot_listener;
|
||||||
|
|
||||||
len = sizeof sa_peer;
|
len = sizeof sa_peer;
|
||||||
if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
|
if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
|
||||||
i_errno = IESTREAMACCEPT;
|
i_errno = IESTREAMACCEPT;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
@ -215,7 +202,7 @@ iperf_udp_accept(struct iperf_test *test)
|
|||||||
i_errno = IESTREAMACCEPT;
|
i_errno = IESTREAMACCEPT;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
sp = test->new_stream(test);
|
sp = test->new_stream(test);
|
||||||
if (!sp)
|
if (!sp)
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -226,25 +213,97 @@ iperf_udp_accept(struct iperf_test *test)
|
|||||||
FD_SET(s, &test->read_set);
|
FD_SET(s, &test->read_set);
|
||||||
FD_SET(s, &test->write_set);
|
FD_SET(s, &test->write_set);
|
||||||
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
test->max_fd = (s > test->max_fd) ? s : test->max_fd;
|
||||||
|
*/
|
||||||
|
|
||||||
test->listener_udp = netannounce(Pudp, NULL, test->server_port);
|
test->prot_listener = netannounce(Pudp, NULL, test->server_port);
|
||||||
if (test->listener_udp < 0) {
|
if (test->prot_listener < 0) {
|
||||||
i_errno = IELISTEN;
|
i_errno = IESTREAMLISTEN;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_SET(test->listener_udp, &test->read_set);
|
FD_SET(test->prot_listener, &test->read_set);
|
||||||
test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd;
|
test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
|
||||||
|
|
||||||
/* Let the client know we're ready "accept" another UDP "stream" */
|
/* Let the client know we're ready "accept" another UDP "stream" */
|
||||||
if (write(sp->socket, &buf, sizeof(buf)) < 0) {
|
if (write(s, &buf, sizeof(buf)) < 0) {
|
||||||
i_errno = IESTREAMWRITE;
|
i_errno = IESTREAMWRITE;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect_msg(sp);
|
return (s);
|
||||||
test->streams_accepted++;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* iperf_udp_listen
|
||||||
|
*
|
||||||
|
* start up a listener for UDP stream connections
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iperf_udp_listen(struct iperf_test *test)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if ((s = netannounce(Pudp, NULL, test->server_port)) < 0) {
|
||||||
|
i_errno = IESTREAMLISTEN;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* iperf_udp_connect
|
||||||
|
*
|
||||||
|
* connect to a TCP stream listener
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iperf_udp_connect(struct iperf_test *test)
|
||||||
|
{
|
||||||
|
int s, buf;
|
||||||
|
|
||||||
|
if ((s = netdial(Pudp, test->server_hostname, test->server_port)) < 0) {
|
||||||
|
i_errno = IESTREAMCONNECT;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
/* 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 (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* iperf_udp_init
|
||||||
|
*
|
||||||
|
* initializer for UDP streams in TEST_START
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iperf_udp_init(struct iperf_test *test)
|
||||||
|
{
|
||||||
|
int64_t dtargus;
|
||||||
|
struct iperf_stream *sp;
|
||||||
|
|
||||||
|
/* Calculate the send delay needed to hit target bandwidth (-b) */
|
||||||
|
dtargus = (int64_t) test->default_settings->blksize * SEC_TO_US * 8;
|
||||||
|
dtargus /= test->default_settings->rate;
|
||||||
|
|
||||||
|
assert(dtargus != 0);
|
||||||
|
|
||||||
|
for (sp = test->streams; sp; sp = sp->next) {
|
||||||
|
sp->send_timer = new_timer(dtargus / SEC_TO_US, dtargus % SEC_TO_US);
|
||||||
|
if (sp->send_timer == NULL)
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
approvals from the U.S. Dept. of Energy). All rights reserved.
|
approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IPERF_UDP_H
|
#ifndef __IPERF_UDP_H
|
||||||
#define IPERF_UDP_H
|
#define __IPERF_UDP_H
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,7 +15,7 @@
|
|||||||
*returns 0 on success
|
*returns 0 on success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_udp_accept(struct iperf_test * test);
|
int iperf_udp_accept(struct iperf_test *);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,7 +24,7 @@ int iperf_udp_accept(struct iperf_test * test);
|
|||||||
*returns state of packet received
|
*returns state of packet received
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_udp_recv(struct iperf_stream * sp);
|
int iperf_udp_recv(struct iperf_stream *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iperf_udp_send -- sends the client data for UDP
|
* iperf_udp_send -- sends the client data for UDP
|
||||||
@ -32,7 +32,7 @@ int iperf_udp_recv(struct iperf_stream * sp);
|
|||||||
* returns: bytes sent
|
* returns: bytes sent
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_udp_send(struct iperf_stream * sp);
|
int iperf_udp_send(struct iperf_stream *);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +41,14 @@ int iperf_udp_send(struct iperf_stream * sp);
|
|||||||
*returns 0 on success
|
*returns 0 on success
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int iperf_udp_accept(struct iperf_test * test);
|
int iperf_udp_accept(struct iperf_test *);
|
||||||
|
|
||||||
|
|
||||||
|
int iperf_udp_listen(struct iperf_test *);
|
||||||
|
|
||||||
|
int iperf_udp_connect(struct iperf_test *);
|
||||||
|
|
||||||
|
int iperf_udp_init(struct iperf_test *);
|
||||||
|
|
||||||
struct iperf_stream *iperf_new_udp_stream(struct iperf_test * testp);
|
struct iperf_stream *iperf_new_udp_stream(struct iperf_test * testp);
|
||||||
|
|
||||||
|
@ -1,8 +1,24 @@
|
|||||||
#include "config.h"
|
/* iperf_util.c
|
||||||
|
*
|
||||||
|
* Iperf utility functions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include<string.h>
|
#include <string.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
/* XXX: this code is not portable: not all versions of linux install libuuidgen
|
||||||
|
* by default
|
||||||
|
*
|
||||||
|
* if not installed, may need to do something like this:
|
||||||
|
* yum install libuuid-devel
|
||||||
|
* apt-get install uuid-dev
|
||||||
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_UUID_H)
|
#if defined(HAVE_UUID_H)
|
||||||
#warning DOING SOMETHING
|
#warning DOING SOMETHING
|
||||||
@ -14,14 +30,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* XXX: this code is not portable: not all versions of linux install libuuidgen
|
|
||||||
* by default
|
|
||||||
*
|
|
||||||
* if not installed, may need to do something like this:
|
|
||||||
* yum install libuuid-devel
|
|
||||||
* apt-get install uuid-dev
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
/* get_uuid
|
||||||
|
*
|
||||||
|
* Generate and return a UUID string
|
||||||
|
*
|
||||||
|
* Iperf uses this function to create test "cookies" which
|
||||||
|
* server as unique test identifiers. These cookies are also
|
||||||
|
* used for the authentication of stream connections.
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
get_uuid(char *temp)
|
get_uuid(char *temp)
|
||||||
@ -45,3 +62,31 @@ get_uuid(char *temp)
|
|||||||
// Otherwise use rpc_string_free (?)
|
// Otherwise use rpc_string_free (?)
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* is_closed
|
||||||
|
*
|
||||||
|
* Test if the file descriptor fd is closed.
|
||||||
|
*
|
||||||
|
* Iperf uses this function to test whether a TCP stream socket
|
||||||
|
* is closed, because accepting and denying an invalid connection
|
||||||
|
* in iperf_tcp_accept is not considered an error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
is_closed(int fd)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set readset;
|
||||||
|
|
||||||
|
FD_ZERO(&readset);
|
||||||
|
FD_SET(fd, &readset);
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select(fd+1, &readset, NULL, NULL, &tv) < 0) {
|
||||||
|
if (errno == EBADF)
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
#ifndef __IPERF_UTIL_H
|
||||||
|
#define __IPERF_UTIL_H
|
||||||
|
|
||||||
void
|
void get_uuid(char *);
|
||||||
get_uuid(char *);
|
|
||||||
|
int is_closed(int);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
@ -45,13 +45,15 @@ netdial(int proto, char *client, int port)
|
|||||||
if (connect(s, (struct sockaddr *) & sa, sizeof sa) < 0 && errno != EINPROGRESS) {
|
if (connect(s, (struct sockaddr *) & sa, sizeof sa) < 0 && errno != EINPROGRESS) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX: Consider deleting
|
||||||
sn = sizeof sa;
|
sn = sizeof sa;
|
||||||
|
|
||||||
// XXX: Is there a reason to call getpeername() if none of the return values are used?
|
// XXX: Is there a reason to call getpeername() if none of the return values are used?
|
||||||
if (getpeername(s, (struct sockaddr *) & sa, &sn) < 0) {
|
if (getpeername(s, (struct sockaddr *) & sa, &sn) < 0) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
Загрузка…
Ссылка в новой задаче
Block a user