lots of code restructuring
Этот коммит содержится в:
родитель
da54a271ad
Коммит
a951c98062
@ -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)
|
||||
|
179
src/iperf.h
179
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 */
|
||||
|
||||
|
1327
src/iperf_api.c
1327
src/iperf_api.c
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
241
src/iperf_api.h
241
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);
|
||||
|
||||
/**
|
||||
|
243
src/iperf_server_api.c
Обычный файл
243
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "iperf.h"
|
||||
#include "iperf_server_api.h"
|
||||
#include "iperf_api.h"
|
||||
#include "iperf_udp.h"
|
||||
#include "iperf_tcp.h"
|
||||
#include "timer.h"
|
||||
#include "net.h"
|
||||
#include "units.h"
|
||||
#include "tcp_window_size.h"
|
||||
#include "uuid.h"
|
||||
#include "locale.h"
|
||||
|
||||
/*********************************************************************/
|
||||
/**
|
||||
* param_received - handles the param_Exchange part for server
|
||||
* returns state on success, -1 on failure
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
param_received(struct iperf_stream * sp, struct param_exchange * param)
|
||||
{
|
||||
int result;
|
||||
char *buf = (char *) malloc(sizeof(struct param_exchange));
|
||||
|
||||
if (sp->settings->cookie[0] == '\0' ||
|
||||
(strncmp(param->cookie, sp->settings->cookie, 37) == 0))
|
||||
{
|
||||
strncpy(sp->settings->cookie, param->cookie, 37);
|
||||
sp->settings->blksize = param->blksize;
|
||||
sp->settings->socket_bufsize = param->recv_window;
|
||||
sp->settings->unit_format = param->format;
|
||||
printf("Got params from client: block size = %d, recv_window = %d cookie = %s\n",
|
||||
sp->settings->blksize, sp->settings->socket_bufsize, sp->settings->cookie);
|
||||
param->state = TEST_START;
|
||||
buf[0] = TEST_START;
|
||||
|
||||
} else
|
||||
{
|
||||
fprintf(stderr, "Connection from new client denied\n");
|
||||
param->state = ACCESS_DENIED;
|
||||
buf[0] = ACCESS_DENIED;
|
||||
}
|
||||
free(buf);
|
||||
printf("param_received: Sending message back to client \n");
|
||||
result = send(sp->socket, buf, sizeof(struct param_exchange), 0);
|
||||
if (result < 0)
|
||||
perror("param_received: Error sending param ack to client");
|
||||
return param->state;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
/**
|
||||
* send_result_to_client - sends result string from server to client
|
||||
*/
|
||||
|
||||
void
|
||||
send_result_to_client(struct iperf_stream * sp)
|
||||
{
|
||||
int result;
|
||||
int size = sp->settings->blksize;
|
||||
|
||||
char *buf = (char *) malloc(size);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
perror("malloc: unable to allocate transmit buffer");
|
||||
}
|
||||
/* adding the string terminator to the message */
|
||||
buf[strlen((char *) sp->data)] = '\0';
|
||||
|
||||
memcpy(buf, sp->data, strlen((char *) sp->data));
|
||||
|
||||
printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data));
|
||||
result = send(sp->socket, buf, size, 0);
|
||||
printf("RESULT SENT TO CLIENT\n");
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void
|
||||
iperf_run_server(struct iperf_test * test)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct iperf_stream *np, *sp;
|
||||
int j, result, message;
|
||||
char *results_string = NULL;
|
||||
|
||||
FD_ZERO(&test->read_set);
|
||||
FD_SET(test->listener_sock_tcp, &test->read_set);
|
||||
FD_SET(test->listener_sock_udp, &test->read_set);
|
||||
|
||||
test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp;
|
||||
|
||||
test->num_streams = 0;
|
||||
test->default_settings->state = TEST_RUNNING;
|
||||
|
||||
printf("iperf_run_server: Waiting for client connect.... \n");
|
||||
while (test->default_settings->state != TEST_END)
|
||||
{
|
||||
memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set));
|
||||
tv.tv_sec = 15;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
/* using select to check on multiple descriptors. */
|
||||
result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
//printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec);
|
||||
continue;
|
||||
} else if (result < 0 && errno != EINTR)
|
||||
{
|
||||
printf("Error in select(): %s\n", strerror(errno));
|
||||
exit(0);
|
||||
} else if (result > 0)
|
||||
{
|
||||
/* Accept a new TCP connection */
|
||||
if (FD_ISSET(test->listener_sock_tcp, &test->temp_set))
|
||||
{
|
||||
test->protocol = Ptcp;
|
||||
test->accept = iperf_tcp_accept;
|
||||
test->new_stream = iperf_new_tcp_stream;
|
||||
test->accept(test);
|
||||
test->default_settings->state = TEST_RUNNING;
|
||||
FD_CLR(test->listener_sock_tcp, &test->temp_set);
|
||||
}
|
||||
/* Accept a new UDP connection */
|
||||
else if (FD_ISSET(test->listener_sock_udp, &test->temp_set))
|
||||
{
|
||||
test->protocol = Pudp;
|
||||
test->accept = iperf_udp_accept;
|
||||
test->new_stream = iperf_new_udp_stream;
|
||||
test->accept(test);
|
||||
test->default_settings->state = TEST_RUNNING;
|
||||
FD_CLR(test->listener_sock_udp, &test->temp_set);
|
||||
}
|
||||
/* Process the sockets for read operation */
|
||||
for (j = 0; j < test->max_fd + 1; j++)
|
||||
{
|
||||
if (FD_ISSET(j, &test->temp_set))
|
||||
{
|
||||
/* find the correct stream - possibly time consuming */
|
||||
np = find_stream_by_socket(test, j);
|
||||
message = np->rcv(np); /* get data from client using receiver callback */
|
||||
//printf ("iperf_run_server: iperf_tcp_recv returned %d \n", message);
|
||||
np->settings->state = message;
|
||||
|
||||
if (message == PARAM_EXCHANGE)
|
||||
{
|
||||
/* copy the received settings into test */
|
||||
memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings));
|
||||
}
|
||||
if (message == ACCESS_DENIED) /* this might get set by PARAM_EXCHANGE */
|
||||
{
|
||||
/* XXX: test this! */
|
||||
close(np->socket);
|
||||
FD_CLR(np->socket, &test->read_set);
|
||||
iperf_free_stream(test, np);
|
||||
}
|
||||
if (message == STREAM_END)
|
||||
{
|
||||
/*
|
||||
* XXX: should I expect one of these per stream. If
|
||||
* so, only timestamp the 1st one??
|
||||
*/
|
||||
gettimeofday(&np->result->end_time, NULL);
|
||||
}
|
||||
if (message == RESULT_REQUEST)
|
||||
{
|
||||
np->settings->state = RESULT_RESPOND;
|
||||
results_string = test->reporter_callback(test);
|
||||
np->data = results_string;
|
||||
send_result_to_client(np);
|
||||
}
|
||||
if (message == ALL_STREAMS_END)
|
||||
{
|
||||
/* print server results */
|
||||
results_string = test->reporter_callback(test);
|
||||
puts(results_string); /* send to stdio */
|
||||
}
|
||||
if (message == TEST_END)
|
||||
{
|
||||
/* FREE ALL STREAMS */
|
||||
np = test->streams;
|
||||
do
|
||||
{
|
||||
sp = np;
|
||||
close(sp->socket);
|
||||
FD_CLR(sp->socket, &test->read_set);
|
||||
np = sp->next;
|
||||
iperf_free_stream(test, sp);
|
||||
} while (np != NULL);
|
||||
|
||||
printf("TEST_END\n\n");
|
||||
test->default_settings->state = TEST_END;
|
||||
/* reset cookie with client is finished */
|
||||
memset(test->default_settings->cookie, '\0', 37);
|
||||
|
||||
}
|
||||
} /* end if (FD_ISSET(j, &temp_set)) */
|
||||
} /* end for (j=0;...) */
|
||||
|
||||
} /* end else (result>0) */
|
||||
} /* end while */
|
||||
|
||||
}
|
||||
|
5
src/iperf_server_api.h
Обычный файл
5
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);
|
||||
|
307
src/iperf_tcp.c
Обычный файл
307
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "iperf.h"
|
||||
#include "iperf_api.h"
|
||||
#include "iperf_tcp.h"
|
||||
#include "timer.h"
|
||||
#include "net.h"
|
||||
#include "tcp_window_size.h"
|
||||
#include "uuid.h"
|
||||
#include "locale.h"
|
||||
|
||||
jmp_buf env; /* to handle longjmp on signal */
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* iperf_tcp_recv -- receives the data for TCP
|
||||
* and the Param/result message exchange
|
||||
*returns state of packet received
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
iperf_tcp_recv(struct iperf_stream * sp)
|
||||
{
|
||||
int result, message;
|
||||
char ch;
|
||||
int size = sp->settings->blksize;
|
||||
char *final_message = NULL;
|
||||
|
||||
errno = 0;
|
||||
|
||||
struct param_exchange *param = (struct param_exchange *) sp->buffer;
|
||||
|
||||
if (!sp->buffer)
|
||||
{
|
||||
fprintf(stderr, "receive buffer not allocated \n");
|
||||
return -1;
|
||||
}
|
||||
/* get the 1st byte: then based on that, decide how much to read */
|
||||
if ((result = recv(sp->socket, &ch, sizeof(int), MSG_PEEK)) != sizeof(int))
|
||||
{
|
||||
if (result == 0)
|
||||
printf("Client Disconnected. \n");
|
||||
else
|
||||
perror("iperf_tcp_recv: recv error: MSG_PEEK");
|
||||
return -1;
|
||||
}
|
||||
message = (int) ch;
|
||||
sp->settings->state = message;
|
||||
if (message != 7) /* tell me about non STREAM_RUNNING messages
|
||||
* for debugging */
|
||||
printf("iperf_tcp_recv: got message type %d \n", message);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case PARAM_EXCHANGE:
|
||||
size = sizeof(struct param_exchange);
|
||||
#ifdef USE_RECV
|
||||
do
|
||||
{
|
||||
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
|
||||
} while (result == -1 && errno == EINTR);
|
||||
#else
|
||||
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
||||
#endif
|
||||
if (result == -1)
|
||||
{
|
||||
perror("iperf_tcp_recv: recv error");
|
||||
return -1;
|
||||
}
|
||||
//printf("iperf_tcp_recv: recv returned %d bytes \n", result);
|
||||
//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
|
||||
result = param_received(sp, param); /* handle PARAM_EXCHANGE and
|
||||
* send result to client */
|
||||
|
||||
break;
|
||||
|
||||
case TEST_START:
|
||||
case STREAM_BEGIN:
|
||||
case STREAM_RUNNING:
|
||||
case STREAM_END:
|
||||
size = sp->settings->blksize;
|
||||
#ifdef USE_RECV
|
||||
/*
|
||||
* NOTE: Nwrite/Nread seems to be 10-15% faster than send/recv for
|
||||
* localhost on OSX. More testing needed on other OSes to be sure.
|
||||
*/
|
||||
do
|
||||
{
|
||||
printf("iperf_tcp_recv: Calling recv: expecting %d bytes \n", size);
|
||||
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
|
||||
|
||||
} while (result == -1 && errno == EINTR);
|
||||
#else
|
||||
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
||||
#endif
|
||||
if (result == -1)
|
||||
{
|
||||
perror("Read error");
|
||||
return -1;
|
||||
}
|
||||
//printf("iperf_tcp_recv: recv returned %d bytes \n", result);
|
||||
sp->result->bytes_received += result;
|
||||
break;
|
||||
case ALL_STREAMS_END:
|
||||
size = sizeof(struct param_exchange);
|
||||
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
||||
/* XXX: is there anything that should be done at the point ? */
|
||||
break;
|
||||
case RESULT_REQUEST:
|
||||
/* XXX: not working yet */
|
||||
//final_message = iperf_reporter_callback(test);
|
||||
final_message = "final server results string will go here \n";
|
||||
memcpy(sp->buffer, final_message, strlen(final_message));
|
||||
result = send(sp->socket, sp->buffer, sp->settings->blksize, 0);
|
||||
if (result < 0)
|
||||
perror("Error sending results back to client");
|
||||
|
||||
break;
|
||||
default:
|
||||
printf("unexpected state encountered: %d \n", message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* iperf_tcp_send -- sends the client data for TCP
|
||||
* and the Param/result message exchanges
|
||||
* returns: bytes sent
|
||||
*
|
||||
*/
|
||||
int
|
||||
iperf_tcp_send(struct iperf_stream * sp)
|
||||
{
|
||||
int result;
|
||||
int size = sp->settings->blksize;
|
||||
struct param_exchange *param = (struct param_exchange *) sp->buffer;
|
||||
|
||||
if (!sp->buffer)
|
||||
{
|
||||
perror("transmit buffer not allocated");
|
||||
return -1;
|
||||
}
|
||||
strncpy(param->cookie, sp->settings->cookie, 37);
|
||||
switch (sp->settings->state)
|
||||
{
|
||||
case PARAM_EXCHANGE:
|
||||
param->state = PARAM_EXCHANGE;
|
||||
size = sizeof(struct param_exchange);
|
||||
break;
|
||||
|
||||
case STREAM_BEGIN:
|
||||
param->state = STREAM_BEGIN;
|
||||
size = sp->settings->blksize;
|
||||
break;
|
||||
|
||||
case STREAM_END:
|
||||
param->state = STREAM_END;
|
||||
size = sp->settings->blksize; /* XXX: this might not be right, will
|
||||
* the last block always be full
|
||||
* size? */
|
||||
break;
|
||||
|
||||
case RESULT_REQUEST:
|
||||
param->state = RESULT_REQUEST;
|
||||
size = sizeof(struct param_exchange);
|
||||
break;
|
||||
|
||||
case ALL_STREAMS_END:
|
||||
param->state = ALL_STREAMS_END;
|
||||
size = sizeof(struct param_exchange);
|
||||
break;
|
||||
|
||||
case STREAM_RUNNING:
|
||||
param->state = STREAM_RUNNING;
|
||||
size = sp->settings->blksize;
|
||||
break;
|
||||
default:
|
||||
printf("State of the stream can't be determined\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//printf(" in iperf_tcp_send, message type = %d (total = %d bytes) \n", param->state, size);
|
||||
#ifdef USE_SEND
|
||||
result = send(sp->socket, sp->buffer, size, 0);
|
||||
#else
|
||||
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
|
||||
#endif
|
||||
if (result < 0)
|
||||
perror("Write error");
|
||||
//printf(" iperf_tcp_send: %d bytes sent \n", result);
|
||||
|
||||
/* change state after 1st send */
|
||||
if (sp->settings->state == STREAM_BEGIN)
|
||||
sp->settings->state = STREAM_RUNNING;
|
||||
|
||||
if (sp->buffer[0] != STREAM_END)
|
||||
/*
|
||||
* XXX: check/fix this. Maybe only want to increment the size with
|
||||
* STREAM_BEGIN and STREAM_RUNNING?
|
||||
*/
|
||||
sp->result->bytes_sent += size;
|
||||
|
||||
//printf("iperf_tcp_send: number bytes sent so far = %u \n", (uint64_t) sp->result->bytes_sent);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
struct iperf_stream *
|
||||
iperf_new_tcp_stream(struct iperf_test * testp)
|
||||
{
|
||||
struct iperf_stream *sp;
|
||||
|
||||
sp = (struct iperf_stream *) iperf_new_stream(testp);
|
||||
if (!sp)
|
||||
{
|
||||
perror("malloc");
|
||||
return (NULL);
|
||||
}
|
||||
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
|
||||
sp->snd = iperf_tcp_send; /* pointer to send function */
|
||||
|
||||
/* XXX: not yet written... */
|
||||
//sp->update_stats = iperf_tcp_update_stats;
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* iperf_tcp_accept -- accepts a new TCP connection
|
||||
* on tcp_listener_socket for TCP data and param/result
|
||||
* exchange messages
|
||||
* returns 0 on success
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
iperf_tcp_accept(struct iperf_test * test)
|
||||
{
|
||||
socklen_t len;
|
||||
struct sockaddr_in addr;
|
||||
int peersock;
|
||||
struct iperf_stream *sp;
|
||||
|
||||
len = sizeof(addr);
|
||||
peersock = accept(test->listener_sock_tcp, (struct sockaddr *) & addr, &len);
|
||||
if (peersock < 0)
|
||||
{
|
||||
printf("Error in accept(): %s\n", strerror(errno));
|
||||
return -1;
|
||||
} else
|
||||
{
|
||||
sp = test->new_stream(test);
|
||||
setnonblocking(peersock);
|
||||
|
||||
FD_SET(peersock, &test->read_set);
|
||||
test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd;
|
||||
|
||||
sp->socket = peersock;
|
||||
//printf("in iperf_tcp_accept: tcp_windowsize: %d \n", test->default_settings->socket_bufsize);
|
||||
iperf_init_stream(sp, test);
|
||||
iperf_add_stream(test, sp);
|
||||
|
||||
if (test->default_settings->state != RESULT_REQUEST)
|
||||
connect_msg(sp); /* print connect message */
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
39
src/iperf_tcp.h
Обычный файл
39
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 */
|
||||
|
322
src/iperf_udp.c
Обычный файл
322
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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "iperf.h"
|
||||
#include "iperf_api.h"
|
||||
#include "iperf_udp.h"
|
||||
#include "timer.h"
|
||||
#include "net.h"
|
||||
#include "locale.h"
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* iperf_udp_recv -- receives the client data for UDP
|
||||
*
|
||||
*returns state of packet received
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
iperf_udp_recv(struct iperf_stream * sp)
|
||||
{
|
||||
int result, message;
|
||||
int size = sp->settings->blksize;
|
||||
double transit = 0, d = 0;
|
||||
struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
|
||||
struct timeval arrival_time;
|
||||
|
||||
printf("in iperf_udp_recv: reading %d bytes \n", size);
|
||||
if (!sp->buffer)
|
||||
{
|
||||
fprintf(stderr, "receive buffer not allocated \n");
|
||||
exit(0);
|
||||
}
|
||||
#ifdef USE_SEND
|
||||
do
|
||||
{
|
||||
result = recv(sp->socket, sp->buffer, size, 0);
|
||||
|
||||
} while (result == -1 && errno == EINTR);
|
||||
#else
|
||||
result = Nread(sp->socket, sp->buffer, size, Pudp);
|
||||
#endif
|
||||
|
||||
/* interprete the type of message in packet */
|
||||
if (result > 0)
|
||||
{
|
||||
message = udp->state;
|
||||
}
|
||||
if (message != 7)
|
||||
{
|
||||
//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
|
||||
}
|
||||
if (message == STREAM_RUNNING && (sp->stream_id == udp->stream_id))
|
||||
{
|
||||
sp->result->bytes_received += result;
|
||||
if (udp->packet_count == sp->packet_count + 1)
|
||||
sp->packet_count++;
|
||||
|
||||
/* jitter measurement */
|
||||
if (gettimeofday(&arrival_time, NULL) < 0)
|
||||
{
|
||||
perror("gettimeofday");
|
||||
}
|
||||
transit = timeval_diff(&udp->sent_time, &arrival_time);
|
||||
d = transit - sp->prev_transit;
|
||||
if (d < 0)
|
||||
d = -d;
|
||||
sp->prev_transit = transit;
|
||||
sp->jitter += (d - sp->jitter) / 16.0;
|
||||
|
||||
|
||||
/* OUT OF ORDER PACKETS */
|
||||
if (udp->packet_count != sp->packet_count)
|
||||
{
|
||||
if (udp->packet_count < sp->packet_count + 1)
|
||||
{
|
||||
sp->outoforder_packets++;
|
||||
printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
|
||||
} else
|
||||
sp->cnt_error += udp->packet_count - sp->packet_count;
|
||||
}
|
||||
/* store the latest packet id */
|
||||
if (udp->packet_count > sp->packet_count)
|
||||
sp->packet_count = udp->packet_count;
|
||||
|
||||
//printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
|
||||
|
||||
}
|
||||
return message;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
int
|
||||
iperf_udp_send(struct iperf_stream * sp)
|
||||
{
|
||||
int result = 0;
|
||||
struct timeval before, after;
|
||||
int64_t dtargus;
|
||||
int64_t adjustus = 0;
|
||||
|
||||
//printf("in iperf_udp_send \n");
|
||||
/*
|
||||
* the || part ensures that last packet is sent to server - the
|
||||
* STREAM_END MESSAGE
|
||||
*/
|
||||
if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END)
|
||||
{
|
||||
int size = sp->settings->blksize;
|
||||
|
||||
/* this is for udp packet/jitter/lost packet measurements */
|
||||
struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
|
||||
struct param_exchange *param = NULL;
|
||||
|
||||
dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
|
||||
dtargus /= sp->settings->rate;
|
||||
|
||||
assert(dtargus != 0);
|
||||
|
||||
switch (sp->settings->state)
|
||||
{
|
||||
case STREAM_BEGIN:
|
||||
udp->state = STREAM_BEGIN;
|
||||
udp->stream_id = (int) sp;
|
||||
/* udp->packet_count = ++sp->packet_count; */
|
||||
break;
|
||||
|
||||
case STREAM_END:
|
||||
udp->state = STREAM_END;
|
||||
udp->stream_id = (int) sp;
|
||||
break;
|
||||
|
||||
case RESULT_REQUEST:
|
||||
udp->state = RESULT_REQUEST;
|
||||
udp->stream_id = (int) sp;
|
||||
break;
|
||||
|
||||
case ALL_STREAMS_END:
|
||||
udp->state = ALL_STREAMS_END;
|
||||
break;
|
||||
|
||||
case STREAM_RUNNING:
|
||||
udp->state = STREAM_RUNNING;
|
||||
udp->stream_id = (int) sp;
|
||||
udp->packet_count = ++sp->packet_count;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sp->settings->state == STREAM_BEGIN)
|
||||
{
|
||||
sp->settings->state = STREAM_RUNNING;
|
||||
}
|
||||
if (gettimeofday(&before, 0) < 0)
|
||||
perror("gettimeofday");
|
||||
|
||||
udp->sent_time = before;
|
||||
|
||||
printf("iperf_udp_send: writing %d bytes \n", size);
|
||||
#ifdef USE_SEND
|
||||
result = send(sp->socket, sp->buffer, size, 0);
|
||||
#else
|
||||
result = Nwrite(sp->socket, sp->buffer, size, Pudp);
|
||||
#endif
|
||||
|
||||
if (gettimeofday(&after, 0) < 0)
|
||||
perror("gettimeofday");
|
||||
|
||||
/*
|
||||
* CHECK: Packet length and ID if(sp->settings->state ==
|
||||
* STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP =
|
||||
* %d\n",sp->settings->state, sp->packet_count, sp->socket);
|
||||
*/
|
||||
|
||||
if (sp->settings->state == STREAM_RUNNING)
|
||||
sp->result->bytes_sent += result;
|
||||
|
||||
adjustus = dtargus;
|
||||
adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
|
||||
adjustus += (before.tv_usec - after.tv_usec);
|
||||
|
||||
if (adjustus > 0)
|
||||
{
|
||||
dtargus = adjustus;
|
||||
}
|
||||
/* RESET THE TIMER */
|
||||
update_timer(sp->send_timer, 0, dtargus);
|
||||
param = NULL;
|
||||
|
||||
} /* timer_expired_micro */
|
||||
return result;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
struct iperf_stream *
|
||||
iperf_new_udp_stream(struct iperf_test * testp)
|
||||
{
|
||||
struct iperf_stream *sp;
|
||||
|
||||
sp = (struct iperf_stream *) iperf_new_stream(testp);
|
||||
if (!sp)
|
||||
{
|
||||
perror("malloc");
|
||||
return (NULL);
|
||||
}
|
||||
sp->rcv = iperf_udp_recv;
|
||||
sp->snd = iperf_udp_send;
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* iperf_udp_accept -- accepts a new UDP connection
|
||||
* on udp_listener_socket
|
||||
*returns 0 on success
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
iperf_udp_accept(struct iperf_test * test)
|
||||
{
|
||||
|
||||
struct iperf_stream *sp;
|
||||
struct sockaddr_in sa_peer;
|
||||
char *buf;
|
||||
socklen_t len;
|
||||
int sz;
|
||||
|
||||
buf = (char *) malloc(test->default_settings->blksize);
|
||||
struct udp_datagram *udp = (struct udp_datagram *) buf;
|
||||
|
||||
len = sizeof sa_peer;
|
||||
|
||||
sz = recvfrom(test->listener_sock_udp, buf, test->default_settings->blksize, 0, (struct sockaddr *) & sa_peer, &len);
|
||||
|
||||
if (!sz)
|
||||
return -1;
|
||||
|
||||
if (connect(test->listener_sock_udp, (struct sockaddr *) & sa_peer, len) < 0)
|
||||
{
|
||||
perror("connect");
|
||||
return -1;
|
||||
}
|
||||
sp = test->new_stream(test);
|
||||
|
||||
sp->socket = test->listener_sock_udp;
|
||||
|
||||
setnonblocking(sp->socket);
|
||||
|
||||
iperf_init_stream(sp, test);
|
||||
iperf_add_stream(test, sp);
|
||||
|
||||
|
||||
test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port);
|
||||
if (test->listener_sock_udp < 0)
|
||||
return -1;
|
||||
|
||||
FD_SET(test->listener_sock_udp, &test->read_set);
|
||||
test->max_fd = (test->max_fd < test->listener_sock_udp) ? test->listener_sock_udp : test->max_fd;
|
||||
|
||||
if (test->default_settings->state != RESULT_REQUEST)
|
||||
connect_msg(sp);
|
||||
|
||||
printf("iperf_udp_accept: 1st UDP data packet for socket %d has arrived \n", sp->socket);
|
||||
sp->stream_id = udp->stream_id;
|
||||
sp->result->bytes_received += sz;
|
||||
|
||||
/* Count OUT OF ORDER PACKETS */
|
||||
if (udp->packet_count != 0)
|
||||
{
|
||||
if (udp->packet_count < sp->packet_count + 1)
|
||||
sp->outoforder_packets++;
|
||||
else
|
||||
sp->cnt_error += udp->packet_count - sp->packet_count;
|
||||
}
|
||||
/* store the latest packet id */
|
||||
if (udp->packet_count > sp->packet_count)
|
||||
sp->packet_count = udp->packet_count;
|
||||
|
||||
//printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
50
src/iperf_udp.h
Обычный файл
50
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 */
|
||||
|
@ -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[] =
|
||||
|
34
src/main.c
34
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 <netinet/tcp.h>
|
||||
|
||||
|
||||
#include "iperf.h"
|
||||
#include "iperf_api.h"
|
||||
#include "iperf_server_api.h"
|
||||
#include "units.h"
|
||||
#include "locale.h"
|
||||
|
||||
int iperf_run(struct iperf_test * test);
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
@ -186,6 +191,11 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* untill this is done.... */
|
||||
if (test->protocol == Pudp) {
|
||||
printf("UDP mode not yet supported. Exiting. \n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
//printf("in main: calling iperf_init_test \n");
|
||||
if (test->role == 'c')
|
||||
@ -204,3 +214,27 @@ main(int argc, char **argv)
|
||||
printf("\niperf Done.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
int
|
||||
iperf_run(struct iperf_test * test)
|
||||
{
|
||||
test->default_settings->state = TEST_RUNNING;
|
||||
|
||||
switch (test->role)
|
||||
{
|
||||
case 's':
|
||||
iperf_run_server(test);
|
||||
return 0;
|
||||
break;
|
||||
case 'c':
|
||||
iperf_run_client(test);
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
printf("Done iperf_run. \n");
|
||||
}
|
||||
|
||||
|
99
src/net.c
99
src/net.c
@ -4,8 +4,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <assert.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#include "net.h"
|
||||
#include "timer.h"
|
||||
@ -52,6 +55,8 @@ netdial(int proto, char *client, int port)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
|
||||
int
|
||||
netannounce(int proto, char *local, int port)
|
||||
{
|
||||
@ -163,3 +168,97 @@ mread(int fd, char *bufp, int n)
|
||||
|
||||
return ((int) count);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/**
|
||||
* getsock_tcp_mss - Returns the MSS size for TCP
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
getsock_tcp_mss(int inSock)
|
||||
{
|
||||
int mss = 0;
|
||||
|
||||
int rc;
|
||||
socklen_t len;
|
||||
|
||||
assert(inSock >= 0); /* print error and exit if this is not true */
|
||||
|
||||
/* query for mss */
|
||||
len = sizeof(mss);
|
||||
rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);
|
||||
|
||||
return mss;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
/* sets TCP_NODELAY and TCP_MAXSEG if requested */
|
||||
|
||||
int
|
||||
set_tcp_options(int sock, int no_delay, int mss)
|
||||
{
|
||||
|
||||
socklen_t len;
|
||||
|
||||
if (no_delay == 1) {
|
||||
int no_delay = 1;
|
||||
|
||||
len = sizeof(no_delay);
|
||||
int rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&no_delay, len);
|
||||
|
||||
if (rc == -1) {
|
||||
perror("TCP_NODELAY");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#ifdef TCP_MAXSEG
|
||||
if (mss > 0) {
|
||||
int rc;
|
||||
int new_mss;
|
||||
|
||||
len = sizeof(new_mss);
|
||||
|
||||
assert(sock != -1);
|
||||
|
||||
/* set */
|
||||
new_mss = mss;
|
||||
len = sizeof(new_mss);
|
||||
rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);
|
||||
if (rc == -1) {
|
||||
perror("setsockopt");
|
||||
return -1;
|
||||
}
|
||||
/* verify results */
|
||||
rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);
|
||||
if (new_mss != mss) {
|
||||
perror("setsockopt value mismatch");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int
|
||||
setnonblocking(int sock)
|
||||
{
|
||||
int opts;
|
||||
|
||||
opts = (opts | O_NONBLOCK);
|
||||
if (fcntl(sock, F_SETFL, opts) < 0)
|
||||
{
|
||||
perror("fcntl(F_SETFL)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -55,6 +55,8 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "iperf.h"
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user