diff --git a/src/Makefile b/src/Makefile index 6c62d4c..8582616 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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) diff --git a/src/iperf.h b/src/iperf.h index 872736b..08556f2 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -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 */ + diff --git a/src/iperf_api.c b/src/iperf_api.c index d7c85ef..a7bc770 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -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. */ @@ -28,7 +28,10 @@ #include #include +#include "iperf.h" #include "iperf_api.h" +#include "iperf_udp.h" +#include "iperf_tcp.h" #include "timer.h" #include "net.h" #include "units.h" @@ -36,46 +39,59 @@ #include "uuid.h" #include "locale.h" -jmp_buf env; /* to handle longjmp on signal */ +jmp_buf env; /* to handle longjmp on signal */ /*************************************************************/ + +/* check to see if client has sent the requested number of bytes to the server yet +*/ + +/* XXX: should probably just compute this as we go and store it in the iperf_test structure -blt */ int -all_data_sent(struct iperf_test *test) +all_data_sent(struct iperf_test * test) { if (test->default_settings->bytes == 0) return 0; - else { - uint64_t total_bytes = 0; + else + { + uint64_t total_bytes = 0; struct iperf_stream *sp; sp = test->streams; - while (sp) { + while (sp) + { total_bytes += sp->result->bytes_sent; sp = sp->next; } - if (total_bytes >= (test->num_streams * test->default_settings->bytes)) { + if (total_bytes >= (test->num_streams * test->default_settings->bytes)) + { return 1; - } - else + } else return 0; } } /*********************************************************/ + +/** + * exchange_parameters - handles the param_Exchange part for client + * + */ + void -exchange_parameters(struct iperf_test *test) +exchange_parameters(struct iperf_test * test) { - int result; + int result; struct iperf_stream *sp; struct param_exchange *param; //printf("in exchange_parameters \n"); sp = test->streams; sp->settings->state = PARAM_EXCHANGE; - param = (struct param_exchange *)sp->buffer; + param = (struct param_exchange *) sp->buffer; get_uuid(test->default_settings->cookie); strncpy(param->cookie, test->default_settings->cookie, 37); @@ -88,7 +104,7 @@ exchange_parameters(struct iperf_test *test) param->send_window = test->default_settings->socket_bufsize; param->format = test->default_settings->unit_format; - printf(" sending exchange params: size = %d \n", (int)sizeof(struct param_exchange)); + printf(" sending exchange params: size = %d \n", (int) sizeof(struct param_exchange)); /* XXX: can we use iperf_tcp_send for this? that would be cleaner */ result = send(sp->socket, sp->buffer, sizeof(struct param_exchange), 0); if (result < 0) @@ -97,83 +113,46 @@ exchange_parameters(struct iperf_test *test) //printf("result = %d state = %d, error = %d \n", result, sp->buffer[0], errno); /* get answer back from server */ - do { - //printf("exchange_parameters: reading result from server .. \n"); + do + { + printf("exchange_parameters: reading result from server .. \n"); result = recv(sp->socket, sp->buffer, sizeof(struct param_exchange), 0); } while (result == -1 && errno == EINTR); if (result < 0) perror("Error getting exchange params ack from server"); - if (result > 0 && sp->buffer[0] == ACCESS_DENIED) { + if (result > 0 && sp->buffer[0] == ACCESS_DENIED) + { fprintf(stderr, "Busy server Detected. Try again later. Exiting.\n"); exit(-1); } return; } -/*********************************************************************/ -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); - result = send(sp->socket, buf, sizeof(struct param_exchange), 0); - if (result < 0) - perror("Error sending param ack to client"); - return param->state; -} - /*************************************************************/ -void -setnonblocking(int sock) -{ - int opts; +/** + * add_interval_list -- adds new interval to the interval_list + * + */ - opts = (opts | O_NONBLOCK); - if (fcntl(sock, F_SETFL, opts) < 0) { - perror("fcntl(F_SETFL)"); - exit(EXIT_FAILURE); - } - return; -} - -/*************************************************************/ void -add_interval_list(struct iperf_stream_result *rp, struct iperf_interval_results temp) +add_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results temp) { struct iperf_interval_results *n; - struct iperf_interval_results *ip = (struct iperf_interval_results *)malloc(sizeof(struct iperf_interval_results)); + struct iperf_interval_results *ip = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results)); ip->bytes_transferred = temp.bytes_transferred; ip->interval_duration = temp.interval_duration; ip->tcpInfo = temp.tcpInfo; - //printf("add_interval_list: Mbytes = %d, duration = %f \n", (int)(ip->bytes_transferred / 1000000), ip->interval_duration); + //printf("add_interval_list: Mbytes = %d, duration = %f \n", (int) (ip->bytes_transferred / 1000000), ip->interval_duration); - if (!rp->interval_results) { + if (!rp->interval_results) + { rp->interval_results = ip; - } - else { + } else + { n = rp->interval_results; while (n->next) n = n->next; @@ -187,13 +166,14 @@ add_interval_list(struct iperf_stream_result *rp, struct iperf_interval_results /* for debugging only */ void -display_interval_list(struct iperf_stream_result *rp, int tflag) +display_interval_list(struct iperf_stream_result * rp, int tflag) { struct iperf_interval_results *n; n = rp->interval_results; - while (n) { + while (n) + { printf("Interval = %f\tBytes transferred = %llu\n", n->interval_duration, n->bytes_transferred); if (tflag) print_tcpinfo(n); @@ -201,44 +181,26 @@ display_interval_list(struct iperf_stream_result *rp, int tflag) } } -/*************************************************************/ -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)); - - result = send(sp->socket, buf, size, 0); - printf("RESULT SENT TO CLIENT\n"); - - free(buf); -} - /************************************************************/ + +/** + * receive_result_from_server - Receives result from server + */ + void -receive_result_from_server(struct iperf_test *test) +receive_result_from_server(struct iperf_test * test) { - int result; + int result; struct iperf_stream *sp; - int size = 0; - char *buf = NULL; + int size = 0; + char *buf = NULL; printf("in receive_result_from_server \n"); sp = test->streams; size = sp->settings->blksize; /* XXX: Is blksize really what we * want to use for the results? */ - buf = (char *)malloc(size); + buf = (char *) malloc(size); printf("receive_result_from_server: send ALL_STREAMS_END to server \n"); sp->settings->state = ALL_STREAMS_END; @@ -251,7 +213,8 @@ receive_result_from_server(struct iperf_test *test) /* receive from server */ printf("reading results (size=%d) back from server \n", size); - do { + do + { result = recv(sp->socket, buf, size, 0); } while (result == -1 && errno == EINTR); printf("Got size of results from server: %d \n", result); @@ -259,107 +222,62 @@ receive_result_from_server(struct iperf_test *test) printf(server_reporting, sp->socket); puts(buf); /* prints results */ -} + printf("receive_result_from_server: send TEST_END to server \n"); + sp->settings->state = TEST_END; + sp->snd(sp); /* send message to server */ -/*************************************************************************/ -int -getsock_tcp_mss(int inSock) -{ - int mss = 0; - - int rc; - socklen_t len; - - assert(inSock >= 0); - - /* query for mss */ - len = sizeof(mss); - rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len); - - return mss; } /*************************************************************/ -int -set_socket_options(struct iperf_stream *sp, struct iperf_test *tp) -{ - socklen_t len; +/** + * connect_msg -- displays connection message + * denoting sender/receiver details + * + */ - if (tp->no_delay == 1) { - int no_delay = 1; - - len = sizeof(no_delay); - int rc = setsockopt(sp->socket, IPPROTO_TCP, TCP_NODELAY, - (char *)&no_delay, len); - - if (rc == -1) { - perror("TCP_NODELAY"); - return -1; - } - } -#ifdef TCP_MAXSEG - if (tp->default_settings->mss > 0) { - int rc; - int new_mss; - - len = sizeof(new_mss); - - assert(sp->socket != -1); - - /* set */ - new_mss = tp->default_settings->mss; - len = sizeof(new_mss); - rc = setsockopt(sp->socket, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len); - if (rc == -1) { - perror("setsockopt"); - return -1; - } - /* verify results */ - rc = getsockopt(sp->socket, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len); - if (new_mss != tp->default_settings->mss) { - perror("setsockopt value mismatch"); - return -1; - } - } -#endif - return 0; -} - -/*************************************************************/ void -connect_msg(struct iperf_stream *sp) +connect_msg(struct iperf_stream * sp) { - char ipl [512], ipr[512]; + char ipl[512], ipr[512]; - inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)&sp->local_addr)->sin_addr), (void *)ipl, sizeof(ipl)); - inet_ntop(AF_INET, (void *)(&((struct sockaddr_in *)&sp->remote_addr)->sin_addr), (void *)ipr, sizeof(ipr)); + inet_ntop(AF_INET, (void *) (&((struct sockaddr_in *) & sp->local_addr)->sin_addr), (void *) ipl, sizeof(ipl)); + inet_ntop(AF_INET, (void *) (&((struct sockaddr_in *) & sp->remote_addr)->sin_addr), (void *) ipr, sizeof(ipr)); printf("[%3d] local %s port %d connected to %s port %d\n", sp->socket, - ipl, ntohs(((struct sockaddr_in *)&sp->local_addr)->sin_port), - ipr, ntohs(((struct sockaddr_in *)&sp->remote_addr)->sin_port)); + ipl, ntohs(((struct sockaddr_in *) & sp->local_addr)->sin_port), + ipr, ntohs(((struct sockaddr_in *) & sp->remote_addr)->sin_port)); } /*************************************************************/ +/** + * Display -- Displays results for test + * Mainly for DEBUG purpose + * + */ + void -Display(struct iperf_test *test) +Display(struct iperf_test * test) { struct iperf_stream *n; n = test->streams; - int count = 1; + int count = 1; printf("===============DISPLAY==================\n"); - while (1) { - if (n) { + while (1) + { + if (n) + { if (test->role == 'c') - printf("position-%d\tsp=%d\tsocket=%d\tbytes sent=%llu\n", count++, (int)n, n->socket, n->result->bytes_sent); + printf("position-%d\tsp=%d\tsocket=%d\tbytes sent=%llu\n", count++, (int) n, n->socket, n->result->bytes_sent); else - printf("position-%d\tsp=%d\tsocket=%d\tbytes received=%llu\n", count++, (int)n, n->socket, n->result->bytes_received); + printf("position-%d\tsp=%d\tsocket=%d\tbytes received=%llu\n", count++, (int) n, n->socket, n->result->bytes_received); - if (n->next == NULL) { + if (n->next == NULL) + { printf("=================END====================\n"); fflush(stdout); break; @@ -370,355 +288,22 @@ Display(struct iperf_test *test) } /**************************************************************************/ -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; - 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); - do { /* XXX: is the do/while really needed? */ - //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); - 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); - message = param_received(sp, param); - - 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 { /* XXX: is the do/while really needed? */ - 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; -} - -/**************************************************************************/ -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_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("number bytes sent so far = %d \n", (int)sp->result->bytes_sent); - - return result; -} - -/**************************************************************************/ -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_test * iperf_new_test() { struct iperf_test *testp; - testp = (struct iperf_test *)malloc(sizeof(struct iperf_test)); - if (!testp) { + testp = (struct iperf_test *) malloc(sizeof(struct iperf_test)); + if (!testp) + { perror("malloc"); return (NULL); } /* initialise everything to zero */ memset(testp, 0, sizeof(struct iperf_test)); - testp->default_settings = (struct iperf_settings *)malloc(sizeof(struct iperf_settings)); + testp->default_settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings)); memset(testp->default_settings, 0, sizeof(struct iperf_settings)); /* return an empty iperf_test* with memory alloted. */ @@ -727,7 +312,7 @@ iperf_new_test() /**************************************************************************/ void -iperf_defaults(struct iperf_test *testp) +iperf_defaults(struct iperf_test * testp) { testp->protocol = Ptcp; testp->role = 's'; @@ -755,27 +340,29 @@ iperf_defaults(struct iperf_test *testp) /**************************************************************************/ void -iperf_init_test(struct iperf_test *test) +iperf_init_test(struct iperf_test * test) { - char ubuf [UNIT_LEN]; + char ubuf[UNIT_LEN]; struct iperf_stream *sp; - int i , s = 0; + int i, s = 0; - if (test->role == 's') { /* server */ - if (test->protocol == Pudp) { + if (test->role == 's') + { /* server */ + if (test->protocol == Pudp) + { test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port); if (test->listener_sock_udp < 0) exit(0); } - /* always create TCP connection for control messages */ test->listener_sock_tcp = netannounce(Ptcp, NULL, test->server_port); if (test->listener_sock_tcp < 0) exit(0); - if (test->protocol == Ptcp) { - if (set_tcp_windowsize(test->listener_sock_tcp, test->default_settings->socket_bufsize, SO_RCVBUF) < 0) - perror("unable to set TCP window"); + if (test->protocol == Ptcp) + { + if (set_tcp_windowsize(test->listener_sock_tcp, test->default_settings->socket_bufsize, SO_RCVBUF) < 0) + perror("unable to set TCP window"); } /* XXX: why do we do this?? -blt */ //setnonblocking(test->listener_sock_tcp); @@ -783,34 +370,41 @@ iperf_init_test(struct iperf_test *test) printf("-----------------------------------------------------------\n"); printf("Server listening on %d\n", test->server_port); - int x; + int x; /* make sure we got what we asked for */ if ((x = get_tcp_windowsize(test->listener_sock_tcp, SO_RCVBUF)) < 0) perror("SO_RCVBUF"); - if (test->protocol == Ptcp) { + if (test->protocol == Ptcp) + { { - if (test->default_settings->socket_bufsize > 0) { - unit_snprintf(ubuf, UNIT_LEN, (double)x, 'A'); + if (test->default_settings->socket_bufsize > 0) + { + unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); printf("TCP window size: %s\n", ubuf); - } - else { + } else + { printf("Using TCP Autotuning \n"); } } } printf("-----------------------------------------------------------\n"); - } - else if (test->role == 'c') { /* Client */ + } else if (test->role == 'c') + { /* Client */ FD_ZERO(&test->write_set); FD_SET(s, &test->write_set); - /* XXX: I think we need to create a TCP control socket here too for UDP mode -blt */ - for (i = 0; i < test->num_streams; i++) { + /* + * XXX: I think we need to create a TCP control socket here too for + * UDP mode -blt + */ + for (i = 0; i < test->num_streams; i++) + { s = netdial(test->protocol, test->server_hostname, test->server_port); - if (s < 0) { + if (s < 0) + { fprintf(stderr, "netdial failed\n"); exit(0); } @@ -823,14 +417,14 @@ iperf_init_test(struct iperf_test *test) iperf_add_stream(test, sp); if (test->default_settings->state != RESULT_REQUEST) - connect_msg(sp); /* XXX: what is this ?? */ + connect_msg(sp);/* XXX: what is this ?? */ } } } /**************************************************************************/ void -iperf_free_test(struct iperf_test *test) +iperf_free_test(struct iperf_test * test) { free(test->default_settings); @@ -846,21 +440,32 @@ iperf_free_test(struct iperf_test *test) } /**************************************************************************/ -void * -iperf_stats_callback(struct iperf_test *test) + +/** + * iperf_stats_callback -- handles the statistic gathering for both the client and server + * + *returns void * + * + */ + + +void * +iperf_stats_callback(struct iperf_test * test) { - iperf_size_t cumulative_bytes = 0; - int i; + iperf_size_t cumulative_bytes = 0; + int i; struct iperf_stream *sp = test->streams; struct iperf_stream_result *rp = test->streams->result; struct iperf_interval_results *ip, temp; //printf("in stats_callback: num_streams = %d \n", test->num_streams); - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { rp = sp->result; - if (!rp->interval_results) { + if (!rp->interval_results) + { if (test->role == 'c') temp.bytes_transferred = rp->bytes_sent; else @@ -872,10 +477,11 @@ iperf_stats_callback(struct iperf_test *test) gettimeofday(&sp->result->end_time, NULL); add_interval_list(rp, temp); - } - else { + } else + { ip = sp->result->interval_results; - while (1) { + while (1) + { cumulative_bytes += ip->bytes_transferred; if (ip->next != NULL) ip = ip->next; @@ -907,30 +513,28 @@ iperf_stats_callback(struct iperf_test *test) } /**************************************************************************/ -/* - * XXX: this routine is confusing, and should be cleaned up and/or better - * commented -blt + +/** + * iperf_reporter_callback -- handles the report printing + * + *returns report + * */ -char * -iperf_reporter_callback(struct iperf_test *test) + +char * +iperf_reporter_callback(struct iperf_test * test) { - int count = 0, total_packets = 0, lost_packets = 0; - char ubuf [UNIT_LEN]; - char nbuf [UNIT_LEN]; + int total_packets = 0, lost_packets = 0, curr_state = 0; + char ubuf[UNIT_LEN]; + char nbuf[UNIT_LEN]; struct iperf_stream *sp = test->streams; - iperf_size_t bytes = 0; - double start_time, end_time; - char *message = (char *)malloc(500); + iperf_size_t bytes = 0; + double start_time, end_time; + char *message = (char *) malloc(500); - //printf("in iperf_reporter_callback \n"); - /* used to determine the length of reporter buffer */ - while (sp) { - count++; - sp = sp->next; - } - char *message_final = (char *)malloc((count + 1) * (strlen(report_bw_jitter_loss_header) - + strlen(report_bw_jitter_loss_format) + strlen(report_sum_bw_jitter_loss_format))); + char *message_final = (char *) malloc(test->num_streams * (strlen(report_bw_jitter_loss_header) + + strlen(report_bw_jitter_loss_format) + strlen(report_sum_bw_jitter_loss_format))); memset(message_final, 0, strlen(message_final)); @@ -938,35 +542,43 @@ iperf_reporter_callback(struct iperf_test *test) struct iperf_interval_results *ip_prev = ip; sp = test->streams; + curr_state = sp->settings->state; + printf("in iperf_reporter_callback: state = %d \n", curr_state); - if (test->default_settings->state == TEST_RUNNING) { - while (sp) { /* for each stream */ + if (curr_state == TEST_RUNNING) + { + /* print interval results */ + while (sp) + { /* for each stream */ ip = sp->result->interval_results; - while (ip->next != NULL) { + while (ip->next != NULL) + { ip_prev = ip; ip = ip->next; } bytes += ip->bytes_transferred; - unit_snprintf(ubuf, UNIT_LEN, (double)(ip->bytes_transferred), 'A'); + unit_snprintf(ubuf, UNIT_LEN, (double) (ip->bytes_transferred), 'A'); - if (test->streams->result->interval_results->next != NULL) { + if (test->streams->result->interval_results->next != NULL) + { unit_snprintf(nbuf, UNIT_LEN, - (double)(ip->bytes_transferred / (ip->interval_duration - ip_prev->interval_duration)), + (double) (ip->bytes_transferred / (ip->interval_duration - ip_prev->interval_duration)), test->default_settings->unit_format); sprintf(message, report_bw_format, sp->socket, ip_prev->interval_duration, ip->interval_duration, ubuf, nbuf); - } - else { + } else + { sprintf(message, report_bw_header); strcat(message_final, message); - unit_snprintf(nbuf, UNIT_LEN, (double)(ip->bytes_transferred / ip->interval_duration), test->default_settings->unit_format); + unit_snprintf(nbuf, UNIT_LEN, (double) (ip->bytes_transferred / ip->interval_duration), test->default_settings->unit_format); sprintf(message, report_bw_format, sp->socket, 0.0, ip->interval_duration, ubuf, nbuf); } strcat(message_final, message); - if (test->tcp_info) { + if (test->tcp_info) + { build_tcpinfo_message(ip, message); strcat(message_final, message); } @@ -974,97 +586,106 @@ iperf_reporter_callback(struct iperf_test *test) } - if (test->num_streams > 1) { - unit_snprintf(ubuf, UNIT_LEN, (double)(bytes), 'A'); + if (test->num_streams > 1) + { + unit_snprintf(ubuf, UNIT_LEN, (double) (bytes), 'A'); - if (test->streams->result->interval_results->next != NULL) { - unit_snprintf(nbuf, UNIT_LEN, (double)(bytes / (ip->interval_duration - ip_prev->interval_duration)), + if (test->streams->result->interval_results->next != NULL) + { + unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / (ip->interval_duration - ip_prev->interval_duration)), test->default_settings->unit_format); sprintf(message, report_sum_bw_format, ip_prev->interval_duration, ip->interval_duration, ubuf, nbuf); - } - else { - unit_snprintf(nbuf, UNIT_LEN, (double)(bytes / ip->interval_duration), test->default_settings->unit_format); + } else + { + unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / ip->interval_duration), test->default_settings->unit_format); sprintf(message, report_sum_bw_format, 0.0, ip->interval_duration, ubuf, nbuf); } strcat(message_final, message); - if (test->tcp_info) { + if (test->tcp_info) + { build_tcpinfo_message(ip, message); strcat(message_final, message); } free(message); } } - if (test->default_settings->state == RESULT_REQUEST) { + /* if TEST_RUNNING */ + else if (curr_state == ALL_STREAMS_END || curr_state == RESULT_REQUEST) + { sp = test->streams; - while (sp) { - if (sp->settings->state == STREAM_END) { - if (test->role == 'c') - bytes += sp->result->bytes_sent; - else - bytes += sp->result->bytes_received; + while (sp) + { + if (test->role == 'c') + bytes += sp->result->bytes_sent; + else + bytes += sp->result->bytes_received; - if (test->protocol == Pudp) { - total_packets += sp->packet_count; - lost_packets += sp->cnt_error; - } - start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); - end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); - - if (test->role == 'c') { - unit_snprintf(ubuf, UNIT_LEN, (double)(sp->result->bytes_sent), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)(sp->result->bytes_sent / end_time), test->default_settings->unit_format); - - } - else { - unit_snprintf(ubuf, UNIT_LEN, (double)(sp->result->bytes_received), 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)(sp->result->bytes_received / end_time), test->default_settings->unit_format); - } - - if (test->protocol == Ptcp) { - sprintf(message, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); - strcat(message_final, message); - } - else { - sprintf(message, report_bw_jitter_loss_format, sp->socket, start_time, - end_time, ubuf, nbuf, sp->jitter * 1000, sp->cnt_error, sp->packet_count, (double)(100.0 * sp->cnt_error / sp->packet_count)); - strcat(message_final, message); - - if (test->role == 'c') { - sprintf(message, report_datagrams, sp->socket, sp->packet_count); - strcat(message_final, message); - } - if (sp->outoforder_packets > 0) - printf(report_sum_outoforder, start_time, end_time, sp->cnt_error); - } - /* - * XXX: do we need to do something with any TCP_INFO results - * here too? - */ + if (test->protocol == Pudp) + { + total_packets += sp->packet_count; + lost_packets += sp->cnt_error; } + start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); + end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); + + if (test->role == 'c') + { + unit_snprintf(ubuf, UNIT_LEN, (double) (sp->result->bytes_sent), 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) (sp->result->bytes_sent / end_time), test->default_settings->unit_format); + + } else + { + unit_snprintf(ubuf, UNIT_LEN, (double) (sp->result->bytes_received), 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) (sp->result->bytes_received / end_time), test->default_settings->unit_format); + } + + if (test->protocol == Ptcp) + { + sprintf(message, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf); + strcat(message_final, message); + } else + { /* UDP mode */ + sprintf(message, report_bw_jitter_loss_format, sp->socket, start_time, + end_time, ubuf, nbuf, sp->jitter * 1000, sp->cnt_error, sp->packet_count, (double) (100.0 * sp->cnt_error / sp->packet_count)); + strcat(message_final, message); + + if (test->role == 'c') + { + sprintf(message, report_datagrams, sp->socket, sp->packet_count); + strcat(message_final, message); + } + if (sp->outoforder_packets > 0) + printf(report_sum_outoforder, start_time, end_time, sp->cnt_error); + } + /* + * XXX: we need to do something with any TCP_INFO results here + */ sp = sp->next; } - - sp = test->streams; + sp = test->streams; /* reset to first socket */ start_time = timeval_diff(&sp->result->start_time, &sp->result->start_time); end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time); - unit_snprintf(ubuf, UNIT_LEN, (double)bytes, 'A'); - unit_snprintf(nbuf, UNIT_LEN, (double)bytes / end_time, test->default_settings->unit_format); + unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A'); + unit_snprintf(nbuf, UNIT_LEN, (double) bytes / end_time, test->default_settings->unit_format); - if ((test->role == 'c' && test->num_streams > 1) || (test->role == 's')) { - if (test->protocol == Ptcp) { + if ((test->role == 'c' && test->num_streams > 1) || (test->role == 's')) + { + if (test->protocol == Ptcp) + { sprintf(message, report_sum_bw_format, start_time, end_time, ubuf, nbuf); strcat(message_final, message); - } - else { - sprintf(message, report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, sp->jitter, lost_packets, total_packets, (double)(100.0 * lost_packets / total_packets)); + } else + { + sprintf(message, report_sum_bw_jitter_loss_format, start_time, end_time, ubuf, nbuf, sp->jitter, lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets)); strcat(message_final, message); } - if ((test->print_mss != 0) && (test->role == 'c')) { + if ((test->print_mss != 0) && (test->role == 'c')) + { sprintf(message, "\nThe TCP maximum segment size mss = %d \n", getsock_tcp_mss(sp->socket)); strcat(message_final, message); } @@ -1076,24 +697,28 @@ iperf_reporter_callback(struct iperf_test *test) /**************************************************************************/ void -iperf_free_stream(struct iperf_test *test, struct iperf_stream *sp) +iperf_free_stream(struct iperf_test * test, struct iperf_stream * sp) { struct iperf_stream *prev, *start; prev = test->streams; start = test->streams; - if (test->streams->socket == sp->socket) { + if (test->streams->socket == sp->socket) + { test->streams = test->streams->next; - } - else { + } else + { start = test->streams->next; - while (1) { - if (start->socket == sp->socket) { + while (1) + { + if (start->socket == sp->socket) + { prev->next = sp->next; break; } - if (start->next != NULL) { + if (start->next != NULL) + { start = start->next; prev = prev->next; } @@ -1109,22 +734,23 @@ iperf_free_stream(struct iperf_test *test, struct iperf_stream *sp) /**************************************************************************/ struct iperf_stream * -iperf_new_stream(struct iperf_test *testp) +iperf_new_stream(struct iperf_test * testp) { - int i = 0; + int i = 0; struct iperf_stream *sp; - sp = (struct iperf_stream *)malloc(sizeof(struct iperf_stream)); - if (!sp) { + sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream)); + if (!sp) + { perror("malloc"); return (NULL); } memset(sp, 0, sizeof(struct iperf_stream)); - sp->buffer = (char *)malloc(testp->default_settings->blksize); - sp->settings = (struct iperf_settings *)malloc(sizeof(struct iperf_settings)); + sp->buffer = (char *) malloc(testp->default_settings->blksize); + sp->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings)); memcpy(sp->settings, testp->default_settings, sizeof(struct iperf_settings)); - sp->result = (struct iperf_stream_result *)malloc(sizeof(struct iperf_stream_result)); + sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result)); /* fill in buffer with random stuff */ /* XXX: probably better to use something truely random here */ @@ -1134,7 +760,7 @@ iperf_new_stream(struct iperf_test *testp) sp->socket = -1; sp->packet_count = 0; - sp->stream_id = (int)sp; + sp->stream_id = (int) sp; sp->jitter = 0.0; sp->prev_transit = 0.0; sp->outoforder_packets = 0; @@ -1151,181 +777,46 @@ iperf_new_stream(struct iperf_test *testp) return sp; } -/**************************************************************************/ -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; -} - -/**************************************************************************/ -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; -} - -/**************************************************************************/ -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; -} - -/**************************************************************************/ -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); /* XXX: ??? */ - - return 0; - } -} - /**************************************************************************/ void -iperf_init_stream(struct iperf_stream *sp, struct iperf_test *testp) +iperf_init_stream(struct iperf_stream * sp, struct iperf_test * testp) { - socklen_t len; + socklen_t len; len = sizeof(struct sockaddr_in); - sp->protocol = testp->protocol; - - if (getsockname(sp->socket, (struct sockaddr *)&sp->local_addr, &len) < 0) { + if (getsockname(sp->socket, (struct sockaddr *) & sp->local_addr, &len) < 0) + { perror("getsockname"); } - if (getpeername(sp->socket, (struct sockaddr *)&sp->remote_addr, &len) < 0) { + if (getpeername(sp->socket, (struct sockaddr *) & sp->remote_addr, &len) < 0) + { perror("getpeername"); } //printf("in init_stream: calling set_tcp_windowsize: %d \n", testp->default_settings->socket_bufsize); - if (testp->protocol == Ptcp) { - if (set_tcp_windowsize(sp->socket, testp->default_settings->socket_bufsize, - testp->role == 's' ? SO_RCVBUF : SO_SNDBUF) < 0) + if (testp->protocol == Ptcp) + { + if (set_tcp_windowsize(sp->socket, testp->default_settings->socket_bufsize, + testp->role == 's' ? SO_RCVBUF : SO_SNDBUF) < 0) fprintf(stderr, "unable to set window size\n"); - set_socket_options(sp, testp); /* set other options (TCP_NODELAY, - * MSS, etc.) */ - } + /* set TCP_NODELAY and TCP_MAXSEG if requested */ + set_tcp_options(sp->socket, testp->no_delay, testp->default_settings->mss); + } } /**************************************************************************/ int -iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) +iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp) { struct iperf_stream *n; - if (!test->streams) { + if (!test->streams) + { test->streams = sp; return 1; - } - else { + } else + { n = test->streams; while (n->next) n = n->next; @@ -1337,14 +828,23 @@ iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp) } /**************************************************************************/ + +/** + * find_stream_by_socket -- finds the stream based on socket ID + * + *returns stream + * + */ + struct iperf_stream * -find_stream_by_socket(struct iperf_test *test, int sock) +find_stream_by_socket(struct iperf_test * test, int sock) { struct iperf_stream *n; n = test->streams; - while (1) { + while (1) + { if (n->socket == sock) break; @@ -1357,130 +857,6 @@ find_stream_by_socket(struct iperf_test *test, int sock) return n; } -/**************************************************************************/ -void -iperf_run_server(struct iperf_test *test) -{ - struct timeval tv; - struct iperf_stream *np, *sp; - int j , result, message; - char *read = 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; - - 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); - - if (message == PARAM_EXCHANGE || message == ACCESS_DENIED) { - /* copy the received settings into test */ - if (message != ACCESS_DENIED) - memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings)); - - close(np->socket); - FD_CLR(np->socket, &test->read_set); - iperf_free_stream(test, np); - } - if (message == STREAM_END) { - np->settings->state = STREAM_END; - gettimeofday(&np->result->end_time, NULL); - } - if (message == RESULT_REQUEST) { - np->settings->state = RESULT_RESPOND; - np->data = read; - send_result_to_client(np); - /* 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; - } - if (message == ALL_STREAMS_END) { - /* - * sometimes the server is not getting the STREAM_END - * message, hence changing the state of all but last - * stream forcefully - */ - np = test->streams; - while (np->next) { - if (np->settings->state == STREAM_BEGIN) { - np->settings->state = STREAM_END; - gettimeofday(&np->result->end_time, NULL); - } - np = np->next; - } - - /* This is necessary to preserve reporting format */ - test->protocol = test->streams->protocol; - - test->default_settings->state = RESULT_REQUEST; - read = test->reporter_callback(test); - puts(read); - - /* reset cookie with client is finished */ - memset(test->default_settings->cookie, '\0', 37); - - /* printf("REPORTER CALL + ALL_STREAMS_END\n"); */ - } - } /* end if (FD_ISSET(j, &temp_set)) */ - } /* end for (j=0;...) */ - - } /* end else (result>0) */ - } /* end while */ - -} /**************************************************************************/ void @@ -1491,16 +867,16 @@ catcher(int sig) /**************************************************************************/ void -iperf_run_client(struct iperf_test *test) +iperf_run_client(struct iperf_test * test) { - int i , result = 0; + int i, result = 0; struct iperf_stream *sp, *np; - struct timer *timer, *stats_interval, *reporter_interval; - char *read = NULL; - char *prot = NULL; - int64_t delayus, adjustus, dtargus; - struct timeval tv; - int ret = 0; + struct timer *timer, *stats_interval, *reporter_interval; + char *result_string = NULL; + char *prot = NULL; + int64_t delayus, adjustus, dtargus; + struct timeval tv; + int ret = 0; struct sigaction sact; printf("in iperf_run_client \n"); @@ -1512,7 +888,8 @@ iperf_run_client(struct iperf_test *test) sact.sa_handler = catcher; sigaction(SIGINT, &sact, NULL); - if (test->protocol == Pudp) { + if (test->protocol == Pudp) + { dtargus = (int64_t) (test->default_settings->blksize) * SEC_TO_US * 8; dtargus /= test->default_settings->rate; @@ -1523,7 +900,8 @@ iperf_run_client(struct iperf_test *test) printf("iperf_run_client: adjustus: %lld, delayus: %lld \n", adjustus, delayus); sp = test->streams; - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { sp->send_timer = new_timer(0, dtargus); sp = sp->next; } @@ -1540,19 +918,20 @@ iperf_run_client(struct iperf_test *test) if (test->reporter_interval != 0) reporter_interval = new_timer(test->reporter_interval, 0); - if (test->protocol == Pudp) + if (test->protocol == Pudp) prot = "UDP"; else prot = "TCP"; if (test->default_settings->bytes == 0) printf("Starting Test: protocol: %s, %d streams, %d byte blocks, %d second test \n", - prot, test->num_streams, test->default_settings->blksize, test->duration); + prot, test->num_streams, test->default_settings->blksize, test->duration); else printf("Starting Test: protocol: %s, %d streams, %d byte blocks, %d bytes to send\n", - prot, test->num_streams, test->default_settings->blksize, (int)test->default_settings->bytes); + prot, test->num_streams, test->default_settings->blksize, (int) test->default_settings->bytes); /* send data till the timer expires or bytes sent */ - while (!all_data_sent(test) && !timer->expired(timer)) { + while (!all_data_sent(test) && !timer->expired(timer)) + { #ifdef NEED_THIS /* not sure what this was for, so removed * -blt */ @@ -1564,7 +943,9 @@ iperf_run_client(struct iperf_test *test) #endif sp = test->streams; - for (i = 0; i < test->num_streams; i++) { + for (i = 0; i < test->num_streams; i++) + { + //printf("sending data to stream %d \n", i); result += sp->snd(sp); if (sp->next == NULL) @@ -1573,31 +954,33 @@ iperf_run_client(struct iperf_test *test) } - if ((test->stats_interval != 0) && stats_interval->expired(stats_interval)) { + if ((test->stats_interval != 0) && stats_interval->expired(stats_interval)) + { test->stats_callback(test); update_timer(stats_interval, test->stats_interval, 0); } - if ((test->reporter_interval != 0) && reporter_interval->expired(reporter_interval)) { - read = test->reporter_callback(test); - puts(read); + if ((test->reporter_interval != 0) && reporter_interval->expired(reporter_interval)) + { + result_string = test->reporter_callback(test); + puts(result_string); update_timer(reporter_interval, test->reporter_interval, 0); } /* detecting Ctrl+C */ if (setjmp(env)) break; - } /* while outer timer */ - - /* for last interval */ + } /* while outer timer */ + /* show last interval if necessary */ test->stats_callback(test); - read = test->reporter_callback(test); - puts(read); + result_string = test->reporter_callback(test); + puts(result_string); + printf("Test Complete. \n"); - /* sending STREAM_END packets */ - sp = test->streams; - np = sp; - do { + /* send STREAM_END packets */ + np = test->streams; + do + { sp = np; sp->settings->state = STREAM_END; sp->snd(sp); @@ -1605,19 +988,32 @@ iperf_run_client(struct iperf_test *test) } while (np); //printf("Done Sending STREAM_END. \n"); + /* send ALL_STREAMS_END packet to 1st socket */ + sp = test->streams; + sp->settings->state = ALL_STREAMS_END; + sp->snd(sp); + //printf("Done Sending ALL_STREAMS_END. \n"); + + /* show and final summary */ + test->stats_callback(test); + result_string = test->reporter_callback(test); + puts(result_string); + + /* Requesting for result from Server */ test->default_settings->state = RESULT_REQUEST; //receive_result_from_server(test); /* XXX: currently broken! */ - //read = test->reporter_callback(test); + //result_string = test->reporter_callback(test); //printf("Summary results as measured by the server: \n"); - //puts(read); + //puts(result_string); //printf("Done getting/printing results. \n"); /* Deleting all streams - CAN CHANGE FREE_STREAM FN */ sp = test->streams; np = sp; - do { + do + { sp = np; close(sp->socket); np = sp->next; @@ -1631,24 +1027,3 @@ iperf_run_client(struct iperf_test *test) free_timer(timer); } -/**************************************************************************/ -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"); -} diff --git a/src/iperf_api.h b/src/iperf_api.h index a10b604..387c68f 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -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); /** diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c new file mode 100644 index 0000000..5150727 --- /dev/null +++ b/src/iperf_server_api.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ + +} + diff --git a/src/iperf_server_api.h b/src/iperf_server_api.h new file mode 100644 index 0000000..3908a7e --- /dev/null +++ b/src/iperf_server_api.h @@ -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); + diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c new file mode 100644 index 0000000..331bc71 --- /dev/null +++ b/src/iperf_tcp.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } +} + + diff --git a/src/iperf_tcp.h b/src/iperf_tcp.h new file mode 100644 index 0000000..cc66b5c --- /dev/null +++ b/src/iperf_tcp.h @@ -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 */ + diff --git a/src/iperf_udp.c b/src/iperf_udp.c new file mode 100644 index 0000000..e7b8c72 --- /dev/null +++ b/src/iperf_udp.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/src/iperf_udp.h b/src/iperf_udp.h new file mode 100644 index 0000000..8490a9e --- /dev/null +++ b/src/iperf_udp.h @@ -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 */ + diff --git a/src/locale.c b/src/locale.c index 37c6f2b..1f26584 100755 --- a/src/locale.c +++ b/src/locale.c @@ -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[] = diff --git a/src/main.c b/src/main.c index 0c24904..4ea310d 100644 --- a/src/main.c +++ b/src/main.c @@ -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 +#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"); +} + diff --git a/src/net.c b/src/net.c index 5813fa8..43c5523 100644 --- a/src/net.c +++ b/src/net.c @@ -4,8 +4,11 @@ #include #include #include +#include +#include #include #include +#include #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; +} + diff --git a/src/net.h b/src/net.h index 6643d3c..6afd558 100644 --- a/src/net.h +++ b/src/net.h @@ -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); + + + diff --git a/src/tcp_info.c b/src/tcp_info.c index 936bb8c..1c2187e 100644 --- a/src/tcp_info.c +++ b/src/tcp_info.c @@ -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, diff --git a/src/units.c b/src/units.c index ece84eb..13b3da3 100644 --- a/src/units.c +++ b/src/units.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include "iperf.h"