lots of code restructuring
Этот коммит содержится в:
родитель
da54a271ad
Коммит
a951c98062
@ -1,5 +1,5 @@
|
|||||||
CFLAGS=-g -Wall
|
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=
|
LDFLAGS=
|
||||||
|
|
||||||
UNAME=$(shell uname)
|
UNAME=$(shell uname)
|
||||||
@ -10,7 +10,7 @@ endif
|
|||||||
all: iperf
|
all: iperf
|
||||||
|
|
||||||
iperf: $(OBJS)
|
iperf: $(OBJS)
|
||||||
$(CC) $(LDFLAGS) -o iperf3 $(OBJS)
|
$(CC) $(CFLAGS) $(LDFLAGS) -o iperf3 $(OBJS)
|
||||||
|
|
||||||
profile: iperf
|
profile: iperf
|
||||||
$(CC) -pg -o iperf-profile $(OBJS)
|
$(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;
|
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 */
|
||||||
|
|
||||||
|
1331
src/iperf_api.c
1331
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
|
Lawrence Berkeley National Laboratory (subject to receipt of any required
|
||||||
approvals from the U.S. Dept. of Energy). All rights reserved.
|
approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||||
*/
|
*/
|
||||||
@ -8,171 +8,7 @@
|
|||||||
#ifndef IPERF_API_H
|
#ifndef IPERF_API_H
|
||||||
#define IPERF_API_H
|
#define IPERF_API_H
|
||||||
|
|
||||||
typedef uint64_t iperf_size_t;
|
#include "iperf.h"
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* exchange_parameters - handles the param_Exchange part for client
|
* 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);
|
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
|
* connect_msg -- displays connection message
|
||||||
* denoting senfer/receiver details
|
* denoting senfer/receiver details
|
||||||
@ -244,56 +66,6 @@ void connect_msg(struct iperf_stream * sp);
|
|||||||
void Display(struct iperf_test * test);
|
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
|
* 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);
|
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
|
* 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_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);
|
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)
|
#if defined(linux)
|
||||||
const char report_tcpInfo[] =
|
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
|
#endif
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
const char report_tcpInfo[] =
|
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.
|
* (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?
|
* 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. )
|
* 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
|
* much better/standard error handling throughout
|
||||||
* better packaging/makefile, README, LICENCE, etc files
|
* better packaging/makefile, README, LICENCE, etc files
|
||||||
* cleanup/fix/test UDP mode
|
* cleanup/fix/test UDP mode
|
||||||
@ -43,10 +45,13 @@
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "iperf.h"
|
||||||
#include "iperf_api.h"
|
#include "iperf_api.h"
|
||||||
|
#include "iperf_server_api.h"
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
#include "locale.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");
|
//printf("in main: calling iperf_init_test \n");
|
||||||
if (test->role == 'c')
|
if (test->role == 'c')
|
||||||
@ -204,3 +214,27 @@ main(int argc, char **argv)
|
|||||||
printf("\niperf Done.\n");
|
printf("\niperf Done.\n");
|
||||||
exit(0);
|
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/types.h>
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
@ -52,6 +55,8 @@ netdial(int proto, char *client, int port)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
|
||||||
int
|
int
|
||||||
netannounce(int proto, char *local, int port)
|
netannounce(int proto, char *local, int port)
|
||||||
{
|
{
|
||||||
@ -163,3 +168,97 @@ mread(int fd, char *bufp, int n)
|
|||||||
|
|
||||||
return ((int) count);
|
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 Nwrite(int fd, char *buf, int count, int prot);
|
||||||
int mread(int fd, char *bufp, int n);
|
int mread(int fd, char *bufp, int n);
|
||||||
int Nread(int fd, char *buf, int count, int prot);
|
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");
|
perror("getsockopt");
|
||||||
}
|
}
|
||||||
memcpy(&rp->tcpInfo, &tcpInfo, sizeof(tcpInfo));
|
memcpy(&rp->tcpInfo, &tcpInfo, sizeof(tcpInfo));
|
||||||
|
/* for debugging
|
||||||
printf(" got TCP_INFO: %d, %d, %d, %d\n", rp->tcpInfo.tcpi_snd_cwnd,
|
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);
|
rp->tcpInfo.tcpi_snd_ssthresh, rp->tcpInfo.tcpi_rcv_space, rp->tcpInfo.tcpi_rtt);
|
||||||
|
*/
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
return;
|
return;
|
||||||
@ -59,7 +61,7 @@ print_tcpinfo(struct iperf_interval_results *r)
|
|||||||
#if defined(linux)
|
#if defined(linux)
|
||||||
printf(report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_snd_ssthresh,
|
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_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
|
#endif
|
||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
printf(report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_rcv_space,
|
printf(report_tcpInfo, r->tcpInfo.tcpi_snd_cwnd, r->tcpInfo.tcpi_rcv_space,
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "iperf.h"
|
#include "iperf.h"
|
||||||
|
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user