From 8a0b5a5d18280828056093fd21737e4936d35e17 Mon Sep 17 00:00:00 2001 From: sethdelliott Date: Thu, 22 Jul 2010 18:57:08 +0000 Subject: [PATCH] Added support for adding new protocols. Slightly modified iperf_error() --- src/iperf.h | 18 ++++ src/iperf_api.c | 208 +++++++++++++++------------------------- src/iperf_error.c | 3 + src/iperf_error.h | 17 ++-- src/iperf_server_api.c | 46 ++++++--- src/iperf_tcp.c | 210 ++++++++++++++++++++++++++++++----------- src/iperf_tcp.h | 12 ++- src/iperf_udp.c | 135 ++++++++++++++++++-------- src/iperf_udp.h | 19 ++-- src/iperf_util.c | 63 +++++++++++-- src/iperf_util.h | 9 +- src/main.c | 1 + src/net.c | 4 +- 13 files changed, 476 insertions(+), 269 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index d4c3221..5f438e9 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -12,6 +12,7 @@ #include #include #include +#include typedef uint64_t iperf_size_t; @@ -100,6 +101,20 @@ struct iperf_stream 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 { char role; /* c' lient or 's' erver */ @@ -112,6 +127,7 @@ struct iperf_test int ctrl_sck; int listener_tcp; int listener_udp; + int prot_listener; /* boolen variables for Options */ int daemon; /* -D option */ @@ -149,6 +165,8 @@ struct iperf_test struct iperf_stream *streams; /* pointer to list of struct stream */ struct iperf_settings *default_settings; + + SLIST_HEAD(slisthead, protocol) protocols; }; enum diff --git a/src/iperf_api.c b/src/iperf_api.c index a275174..6beadc8 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -344,24 +345,18 @@ iperf_recv(struct iperf_test *test) int iperf_init_test(struct iperf_test *test) { - char *prot; struct iperf_stream *sp; + struct protocol *prot; int64_t dtargus; - if (test->protocol == Pudp) { - prot = "UDP"; - 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); + SLIST_FOREACH(prot, &test->protocols, protocols) { + if (test->protocol == prot->id) { + if (prot->init) { + if (prot->init(test) < 0) + return (-1); + } + break; } - } else { - prot = "TCP"; } /* Set timers */ @@ -369,10 +364,10 @@ iperf_init_test(struct iperf_test *test) test->timer = new_timer(test->duration, 0); if (test->timer == NULL) 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); } 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); } @@ -554,9 +549,12 @@ parse_parameters(struct iperf_test *test) int iperf_exchange_parameters(struct iperf_test * test) { + int s; + struct protocol *prot; +/* int s, opt, len; struct sockaddr_in sa; - +*/ if (test->role == 'c') { if (package_parameters(test) < 0) @@ -568,64 +566,17 @@ iperf_exchange_parameters(struct iperf_test * test) printf(" cookie: %s\n", test->default_settings->cookie); - if (test->protocol == Pudp) { - if ((test->listener_udp = netannounce(test->protocol, NULL, test->server_port)) < 0) { - i_errno = IELISTEN; - 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); - } - + SLIST_FOREACH(prot, &test->protocols, protocols) { + if (prot->id == test->protocol) + break; } + 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 test->state = CREATE_STREAMS; 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->server_port = PORT; testp->ctrl_sck = -1; + testp->prot_listener = -1; testp->new_stream = iperf_new_tcp_stream; testp->stats_callback = iperf_stats_callback; @@ -933,6 +885,39 @@ iperf_defaults(struct iperf_test * testp) testp->default_settings->mss = 0; testp->default_settings->bytes = 0; 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 iperf_create_streams(struct iperf_test *test) { + int i, s; + struct protocol *prot; struct iperf_stream *sp; - struct sockaddr_in sa; - struct hostent *hent; - int i, s, buf, opt; 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) { - opt = 1; - if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { - 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); - } + SLIST_FOREACH(prot, &test->protocols, protocols) { + if (prot->id == test->protocol) + break; } - if (test->protocol == Ptcp) { - if (Nwrite(s, test->default_settings->cookie, COOKIE_SIZE, Ptcp) < 0) { - 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); - } - } + if ((s = prot->connect(test)) < 0) + return (-1); FD_SET(s, &test->read_set); FD_SET(s, &test->write_set); @@ -1021,7 +955,7 @@ iperf_create_streams(struct iperf_test *test) connect_msg(sp); } - return 0; + return (0); } int @@ -1112,11 +1046,21 @@ iperf_connect(struct iperf_test *test) void iperf_free_test(struct iperf_test * test) { + struct protocol *prot; + free(test->default_settings); free_timer(test->timer); free_timer(test->stats_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->accept = NULL; test->stats_callback = NULL; diff --git a/src/iperf_error.c b/src/iperf_error.c index 1fa27a9..60a3af2 100644 --- a/src/iperf_error.c +++ b/src/iperf_error.c @@ -131,6 +131,9 @@ iperf_strerror(int i_errno) case IEINITSTREAM: snprintf(errstr, len, "unable to initialize stream"); break; + case IESTREAMLISTEN: + snprintf(errstr, len, "unable to start stream listener"); + break; case IESTREAMCONNECT: snprintf(errstr, len, "unable to connect stream"); break; diff --git a/src/iperf_error.h b/src/iperf_error.h index 3e79568..35976ce 100644 --- a/src/iperf_error.h +++ b/src/iperf_error.h @@ -56,16 +56,17 @@ enum { /* Stream errors */ IECREATESTREAM = 36, // Unable to create a new stream (check herror/perror) IEINITSTREAM = 37, // Unable to initialize stream (check herror/perror) - IESTREAMCONNECT = 38, // Unable to connect stream (check herror/perror) - IESTREAMACCEPT = 39, // Unable to accepte stream connection (check perror) - IESTREAMWRITE = 40, // Unable to write to stream socket (check perror) - IESTREAMREAD = 41, // Unable to read from stream (check perror) - IESTREAMCLOSE = 42, // Stream has closed unexpectedly - IESTREAMID = 43, // Stream has invalid ID + IESTREAMLISTEN = 38, // Unable to start stream listener (check perror) + IESTREAMCONNECT = 39, // Unable to connect stream (check herror/perror) + IESTREAMACCEPT = 40, // Unable to accepte stream connection (check perror) + IESTREAMWRITE = 41, // Unable to write to stream socket (check perror) + IESTREAMREAD = 42, // Unable to read from stream (check perror) + IESTREAMCLOSE = 43, // Stream has closed unexpectedly + IESTREAMID = 44, // Stream has invalid ID /* Timer errors */ - IENEWTIMER = 44, // Unable to create new timer (check perror) - IEUPDATETIMER = 45, // Unable to update timer (check perror) + IENEWTIMER = 45, // Unable to create new timer (check perror) + IEUPDATETIMER = 46, // Unable to update timer (check perror) }; #endif diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index a73481c..034115c 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include "iperf_udp.h" #include "iperf_tcp.h" #include "iperf_error.h" +#include "iperf_util.h" #include "timer.h" #include "net.h" #include "units.h" @@ -322,6 +324,8 @@ iperf_run_server(struct iperf_test *test) { int result, s; fd_set temp_read_set, temp_write_set; + struct iperf_stream *sp; + struct protocol *prot; struct timeval tv; // Open socket and listen @@ -372,26 +376,37 @@ iperf_run_server(struct iperf_test *test) } if (test->state == CREATE_STREAMS) { - if (test->protocol == Ptcp) { - if (FD_ISSET(test->listener_tcp, &temp_read_set)) { - if (iperf_accept_tcp_stream(test) < 0) { - return (-1); - } - FD_CLR(test->listener_tcp, &temp_read_set); + if (FD_ISSET(test->prot_listener, &temp_read_set)) { + + SLIST_FOREACH(prot, &test->protocols, protocols) { + if (prot->id == test->protocol) + break; } - } else { - if (FD_ISSET(test->listener_udp, &temp_read_set)) { - if (iperf_udp_accept(test) < 0) { + + if ((s = prot->accept(test)) < 0) + return (-1); + + if (!is_closed(s)) { + sp = test->new_stream(test); + if (!sp) return (-1); - } - FD_CLR(test->listener_udp, &temp_read_set); + sp->socket = s; + 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->protocol == Pudp) { - FD_CLR(test->listener_udp, &test->read_set); - close(test->listener_udp); - test->listener_udp = -1; + if (test->protocol != Ptcp) { + FD_CLR(test->prot_listener, &test->read_set); + close(test->prot_listener); } else if (test->protocol == Ptcp) { if (test->no_delay || test->default_settings->mss) { 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); } } + test->prot_listener = -1; test->state = TEST_START; if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c index d015d2c..5edc0e7 100644 --- a/src/iperf_tcp.c +++ b/src/iperf_tcp.c @@ -5,6 +5,7 @@ * approvals from the U.S. Dept. of Energy). All rights reserved. */ +// XXX: Surely we do not need all these headers! #include #include #include @@ -30,6 +31,7 @@ #include "iperf.h" #include "iperf_api.h" +#include "iperf_error.h" #include "iperf_server_api.h" #include "iperf_tcp.h" #include "timer.h" @@ -38,50 +40,36 @@ #include "iperf_util.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 */ -/**************************************************************************/ -/** - * iperf_tcp_recv -- receives the data for TCP - * and the Param/result message exchange - *returns state of packet received +/* iperf_tcp_recv * + * receives the data for TCP */ - int iperf_tcp_recv(struct iperf_stream * sp) { int result = 0; 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); -#endif + if (result < 0) { return (-1); } + sp->result->bytes_received += result; sp->result->bytes_received_this_interval += result; - return result; + return (result); } -/**************************************************************************/ -/** - * iperf_tcp_send -- sends the client data for TCP - * and the Param/result message exchanges - * returns: bytes sent +/* iperf_tcp_send * + * sends the data for TCP */ int iperf_tcp_send(struct iperf_stream * sp) @@ -89,11 +77,8 @@ iperf_tcp_send(struct iperf_stream * sp) int result; 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); -#endif + if (result < 0) { return (-1); } @@ -101,9 +86,11 @@ iperf_tcp_send(struct iperf_stream * sp) sp->result->bytes_sent += result; sp->result->bytes_sent_this_interval += result; - return result; + return (result); } + +// XXX: This function is now deprecated /**************************************************************************/ struct iperf_stream * 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->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; } -/**************************************************************************/ -/** XXX: This function is not currently in use! - * iperf_tcp_accept -- accepts a new TCP connection - * on tcp_listener_socket for TCP data and param/result - * exchange messages - * returns 0 on success +/* iperf_tcp_accept * + * accept a new TCP stream connection */ - int iperf_tcp_accept(struct iperf_test * test) { + int s; + int rbuf = ACCESS_DENIED; + char cookie[COOKIE_SIZE]; socklen_t len; struct sockaddr_in addr; - int peersock; - struct iperf_stream *sp; len = sizeof(addr); - 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)); - return -1; + if ((s = accept(test->listener_tcp, (struct sockaddr *) &addr, &len)) < 0) { + i_errno = IESTREAMCONNECT; + return (-1); } - // XXX: This doesn't fit our API model! - sp = test->new_stream(test); - sp->socket = peersock; - iperf_init_stream(sp, test); - iperf_add_stream(test, sp); + if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { + i_errno = IERECVCOOKIE; + return (-1); + } - FD_SET(peersock, &test->read_set); /* add new socket to master set */ - FD_SET(peersock, &test->write_set); - test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd; + if (strcmp(test->default_settings->cookie, cookie) != 0) { + if (Nwrite(s, &rbuf, sizeof(char), Ptcp) < 0) { + i_errno = IESENDMESSAGE; + return (-1); + } + close(s); + } - connect_msg(sp); /* print connect message */ - - return 0; + return (s); } +/* 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); +} + diff --git a/src/iperf_tcp.h b/src/iperf_tcp.h index cc66b5c..d5fe7fb 100644 --- a/src/iperf_tcp.h +++ b/src/iperf_tcp.h @@ -14,7 +14,7 @@ *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 @@ -22,7 +22,7 @@ int iperf_tcp_accept(struct iperf_test * test); *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 * */ -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); diff --git a/src/iperf_udp.c b/src/iperf_udp.c index a175a0a..56728a3 100644 --- a/src/iperf_udp.c +++ b/src/iperf_udp.c @@ -10,6 +10,7 @@ * NOTE: not yet finished / working */ +// XXX: Do we really need all these headers? #include #include #include @@ -42,15 +43,10 @@ #include "locale.h" -/**************************************************************************/ - -/** - * iperf_udp_recv -- receives the client data for UDP - * - *returns state of packet received +/* iperf_udp_recv * + * receives the data for UDP */ - int iperf_udp_recv(struct iperf_stream *sp) { @@ -60,17 +56,12 @@ iperf_udp_recv(struct iperf_stream *sp) double transit = 0, d = 0; 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); -#endif if (result < 0) { return (-1); } + sp->result->bytes_received += 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] sp->jitter += (d - sp->jitter) / 16.0; - return result; + return (result); } -/**************************************************************************/ +/* iperf_udp_send + * + * sends the data for UDP + */ int 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+8, &pcount, sizeof(pcount)); -#ifdef USE_SEND - result = send(sp->socket, sp->buffer, size, 0); -#else result = Nwrite(sp->socket, sp->buffer, size, Pudp); -#endif if (result < 0) return (-1); @@ -165,10 +155,11 @@ iperf_udp_send(struct iperf_stream *sp) return (-1); } - return result; + return (result); } /**************************************************************************/ +// XXX: This function is deprecated struct iperf_stream * iperf_new_udp_stream(struct iperf_test * testp) { @@ -186,14 +177,10 @@ iperf_new_udp_stream(struct iperf_test * testp) /**************************************************************************/ -/** - * iperf_udp_accept -- accepts a new UDP connection - * on udp_listener_socket - *returns 0 on success +/* iperf_udp_accept * + * accepts a new UDP connection */ - - int iperf_udp_accept(struct iperf_test *test) { @@ -203,10 +190,10 @@ iperf_udp_accept(struct iperf_test *test) socklen_t len; int sz, s; - s = test->listener_udp; + s = test->prot_listener; 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; return (-1); } @@ -215,7 +202,7 @@ iperf_udp_accept(struct iperf_test *test) i_errno = IESTREAMACCEPT; return (-1); } - +/* sp = test->new_stream(test); if (!sp) return (-1); @@ -226,25 +213,97 @@ iperf_udp_accept(struct iperf_test *test) 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) { - i_errno = IELISTEN; + test->prot_listener = netannounce(Pudp, NULL, test->server_port); + if (test->prot_listener < 0) { + i_errno = IESTREAMLISTEN; 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->prot_listener, &test->read_set); + 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" */ - if (write(sp->socket, &buf, sizeof(buf)) < 0) { + if (write(s, &buf, sizeof(buf)) < 0) { i_errno = IESTREAMWRITE; return (-1); } - connect_msg(sp); - test->streams_accepted++; + return (s); +} + + +/* 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); } - diff --git a/src/iperf_udp.h b/src/iperf_udp.h index 8490a9e..2b95992 100644 --- a/src/iperf_udp.h +++ b/src/iperf_udp.h @@ -5,8 +5,8 @@ approvals from the U.S. Dept. of Energy). All rights reserved. */ -#ifndef IPERF_UDP_H -#define IPERF_UDP_H +#ifndef __IPERF_UDP_H +#define __IPERF_UDP_H /** @@ -15,7 +15,7 @@ *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 * */ -int iperf_udp_recv(struct iperf_stream * sp); +int iperf_udp_recv(struct iperf_stream *); /** * iperf_udp_send -- sends the client data for UDP @@ -32,7 +32,7 @@ int iperf_udp_recv(struct iperf_stream * sp); * 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 * */ -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); diff --git a/src/iperf_util.c b/src/iperf_util.c index a0a2785..84f285d 100644 --- a/src/iperf_util.c +++ b/src/iperf_util.c @@ -1,8 +1,24 @@ -#include "config.h" +/* iperf_util.c + * + * Iperf utility functions + * + */ #include #include -#include +#include +#include +#include + +#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) #warning DOING SOMETHING @@ -14,14 +30,15 @@ #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 get_uuid(char *temp) @@ -45,3 +62,31 @@ get_uuid(char *temp) // Otherwise use rpc_string_free (?) 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); +} diff --git a/src/iperf_util.h b/src/iperf_util.h index 4b5db7f..ed22017 100644 --- a/src/iperf_util.h +++ b/src/iperf_util.h @@ -1,3 +1,8 @@ +#ifndef __IPERF_UTIL_H +#define __IPERF_UTIL_H -void -get_uuid(char *); +void get_uuid(char *); + +int is_closed(int); + +#endif diff --git a/src/main.c b/src/main.c index 5560ce5..f8ac855 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/net.c b/src/net.c index 3e60b81..2c9964e 100644 --- a/src/net.c +++ b/src/net.c @@ -45,13 +45,15 @@ netdial(int proto, char *client, int port) if (connect(s, (struct sockaddr *) & sa, sizeof sa) < 0 && errno != EINPROGRESS) { return (-1); } - + +/* XXX: Consider deleting sn = sizeof sa; // XXX: Is there a reason to call getpeername() if none of the return values are used? if (getpeername(s, (struct sockaddr *) & sa, &sn) < 0) { return (-1); } +*/ return (s); }