Add -J flag to produce JSON output instead.

This commit is contained in:
Jef Poskanzer 2013-02-01 11:42:35 -08:00
parent 17666b94d9
commit 9bfb54c0cc
10 changed files with 440 additions and 151 deletions

View File

@ -17,6 +17,7 @@
#include <netinet/tcp.h>
#include "timer.h"
#include "queue.h"
#include "cjson.h"
typedef uint64_t iperf_size_t;
@ -64,8 +65,12 @@ struct iperf_settings
char unit_format; /* -f */
};
struct iperf_test;
struct iperf_stream
{
struct iperf_test* test;
/* configurable members */
int local_port;
int remote_port;
@ -104,8 +109,6 @@ struct iperf_stream
void *data;
};
struct iperf_test;
struct protocol {
int id;
char *name;
@ -140,6 +143,7 @@ struct iperf_test
int reverse; /* -R option */
int v6domain; /* -6 option */
int verbose; /* -V option - verbose mode */
int json_output; /* -J option - JSON output */
/* Select related parameters */
int max_fd;
@ -174,6 +178,12 @@ struct iperf_test
void (*on_test_start)(struct iperf_test *);
void (*on_connect)(struct iperf_test *);
void (*on_test_finish)(struct iperf_test *);
/* cJSON handles for use when in -J mode */\
cJSON *json_top;
cJSON *json_start;
cJSON *json_intervals;
cJSON *json_end;
};
/* default settings */

View File

@ -33,6 +33,9 @@ pause \fIn\fR seconds between periodic bandwidth reports
.BR -V ", " --verbose " "
give more detailed output
.TP
.BR -J ", " --json " "
output in JSON format
.TP
.BR -d ", " --debug " "
debug mode
.TP

View File

@ -14,6 +14,7 @@
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdarg.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/socket.h>
@ -51,6 +52,7 @@ static int get_parameters(struct iperf_test *test);
static int send_results(struct iperf_test *test);
static int get_results(struct iperf_test *test);
static int JSON_write(int fd, cJSON *json);
static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams);
static cJSON *JSON_read(int fd);
@ -79,73 +81,73 @@ void warning(char *str)
/************** Getter routines for some fields inside iperf_test *************/
int
iperf_get_control_socket( struct iperf_test* ipt )
iperf_get_control_socket(struct iperf_test *ipt)
{
return ipt->ctrl_sck;
}
int
iperf_get_test_duration( struct iperf_test* ipt )
iperf_get_test_duration(struct iperf_test *ipt)
{
return ipt->duration;
}
uint64_t
iperf_get_test_rate( struct iperf_test* ipt )
iperf_get_test_rate(struct iperf_test *ipt)
{
return ipt->settings->rate;
}
char
iperf_get_test_role( struct iperf_test* ipt )
iperf_get_test_role(struct iperf_test *ipt)
{
return ipt->role;
}
int
iperf_get_test_blksize( struct iperf_test* ipt )
iperf_get_test_blksize(struct iperf_test *ipt)
{
return ipt->settings->blksize;
}
int
iperf_get_test_socket_bufsize( struct iperf_test* ipt )
iperf_get_test_socket_bufsize(struct iperf_test *ipt)
{
return ipt->settings->socket_bufsize;
}
double
iperf_get_test_reporter_interval( struct iperf_test* ipt )
iperf_get_test_reporter_interval(struct iperf_test *ipt)
{
return ipt->reporter_interval;
}
double
iperf_get_test_stats_interval( struct iperf_test* ipt )
iperf_get_test_stats_interval(struct iperf_test *ipt)
{
return ipt->stats_interval;
}
int
iperf_get_test_num_streams( struct iperf_test* ipt )
iperf_get_test_num_streams(struct iperf_test *ipt)
{
return ipt->num_streams;
}
int
iperf_get_test_server_port( struct iperf_test* ipt )
iperf_get_test_server_port(struct iperf_test *ipt)
{
return ipt->server_port;
}
char*
iperf_get_test_server_hostname( struct iperf_test* ipt )
iperf_get_test_server_hostname(struct iperf_test *ipt)
{
return ipt->server_hostname;
}
int
iperf_get_test_protocol_id( struct iperf_test* ipt )
iperf_get_test_protocol_id(struct iperf_test *ipt)
{
return ipt->protocol->id;
}
@ -153,73 +155,73 @@ iperf_get_test_protocol_id( struct iperf_test* ipt )
/************** Setter routines for some fields inside iperf_test *************/
void
iperf_set_control_socket( struct iperf_test* ipt, int ctrl_sck )
iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
{
ipt->ctrl_sck = ctrl_sck;
}
void
iperf_set_test_duration( struct iperf_test* ipt, int duration )
iperf_set_test_duration(struct iperf_test *ipt, int duration)
{
ipt->duration = duration;
}
void
iperf_set_test_reporter_interval( struct iperf_test* ipt, double reporter_interval )
iperf_set_test_reporter_interval(struct iperf_test *ipt, double reporter_interval)
{
ipt->reporter_interval = reporter_interval;
}
void
iperf_set_test_stats_interval( struct iperf_test* ipt, double stats_interval )
iperf_set_test_stats_interval(struct iperf_test *ipt, double stats_interval)
{
ipt->stats_interval = stats_interval;
}
void
iperf_set_test_state( struct iperf_test* ipt, char state )
iperf_set_test_state(struct iperf_test *ipt, char state)
{
ipt->state = state;
}
void
iperf_set_test_blksize( struct iperf_test* ipt, int blksize )
iperf_set_test_blksize(struct iperf_test *ipt, int blksize)
{
ipt->settings->blksize = blksize;
}
void
iperf_set_test_rate( struct iperf_test* ipt, uint64_t rate )
iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
{
ipt->settings->rate = rate;
}
void
iperf_set_test_server_port( struct iperf_test* ipt, int server_port )
iperf_set_test_server_port(struct iperf_test *ipt, int server_port)
{
ipt->server_port = server_port;
}
void
iperf_set_test_socket_bufsize( struct iperf_test* ipt, int socket_bufsize )
iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)
{
ipt->settings->socket_bufsize = socket_bufsize;
}
void
iperf_set_test_num_streams( struct iperf_test* ipt, int num_streams )
iperf_set_test_num_streams(struct iperf_test *ipt, int num_streams)
{
ipt->num_streams = num_streams;
}
void
iperf_set_test_role( struct iperf_test* ipt, char role )
iperf_set_test_role(struct iperf_test *ipt, char role)
{
ipt->role = role;
}
void
iperf_set_test_server_hostname( struct iperf_test* ipt, char* server_hostname )
iperf_set_test_server_hostname(struct iperf_test *ipt, char *server_hostname)
{
ipt->server_hostname = server_hostname;
}
@ -271,14 +273,18 @@ iperf_on_new_stream(struct iperf_stream *sp)
void
iperf_on_test_start(struct iperf_test *test)
{
if (test->verbose) {
if (test->settings->bytes) {
printf(test_start_bytes, test->protocol->name, test->num_streams,
test->settings->blksize, test->settings->bytes);
} else {
printf(test_start_time, test->protocol->name, test->num_streams,
test->settings->blksize, test->duration);
}
if (test->json_output) {
if (test->settings->bytes)
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d bytes: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->settings->bytes));
else
cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d duration: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->duration));
} else {
if (test->verbose) {
if (test->settings->bytes)
printf(test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->settings->bytes);
else
printf(test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->duration);
}
}
}
@ -286,31 +292,55 @@ void
iperf_on_connect(struct iperf_test *test)
{
char ipr[INET6_ADDRSTRLEN];
struct sockaddr_storage temp;
int port;
struct sockaddr_storage sa;
struct sockaddr_in *sa_inP;
struct sockaddr_in6 *sa_in6P;
socklen_t len;
int domain, opt;
if (test->role == 'c') {
printf("Connecting to host %s, port %d\n", test->server_hostname,
test->server_port);
if (test->json_output)
cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s port: %d", test->server_hostname, (int64_t) test->server_port));
else
printf("Connecting to host %s, port %d\n", test->server_hostname, test->server_port);
} else {
domain = test->settings->domain;
len = sizeof(temp);
getpeername(test->ctrl_sck, (struct sockaddr *) &temp, &len);
len = sizeof(sa);
getpeername(test->ctrl_sck, (struct sockaddr *) &sa, &len);
if (domain == AF_INET) {
inet_ntop(domain, &((struct sockaddr_in *) &temp)->sin_addr, ipr, sizeof(ipr));
printf("Accepted connection from %s, port %d\n", ipr, ntohs(((struct sockaddr_in *) &temp)->sin_port));
sa_inP = (struct sockaddr_in *) &sa;
inet_ntop(domain, &sa_inP->sin_addr, ipr, sizeof(ipr));
port = ntohs(sa_inP->sin_port);
if (test->json_output)
cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
else
printf("Accepted connection from %s, port %d\n", ipr, port);
} else {
inet_ntop(domain, &((struct sockaddr_in6 *) &temp)->sin6_addr, ipr, sizeof(ipr));
printf("Accepted connection from %s, port %d\n", ipr, ntohs(((struct sockaddr_in6 *) &temp)->sin6_port));
sa_in6P = (struct sockaddr_in6 *) &sa;
inet_ntop(domain, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
port = ntohs(sa_in6P->sin6_port);
if (test->json_output)
cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
else
printf("Accepted connection from %s, port %d\n", ipr, port);
}
}
if (test->verbose) {
if (test->json_output) {
cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
if (test->protocol->id == SOCK_STREAM)
cJSON_AddIntToObject(test->json_start, "tcp_mss", test->settings->mss);
else {
len = sizeof(opt);
getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
cJSON_AddIntToObject(test->json_start, "tcp_mss_default", opt);
}
} else if (test->verbose) {
printf(" Cookie: %s\n", test->cookie);
if (test->protocol->id == SOCK_STREAM) {
if (test->settings->mss) {
if (test->settings->mss)
printf(" TCP MSS: %d\n", test->settings->mss);
} else {
else {
len = sizeof(opt);
getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
printf(" TCP MSS: %d (default)\n", opt);
@ -338,6 +368,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
{"interval", required_argument, NULL, 'i'},
{"daemon", no_argument, NULL, 'D'},
{"verbose", no_argument, NULL, 'V'},
{"json", no_argument, NULL, 'J'},
{"debug", no_argument, NULL, 'd'},
{"version", no_argument, NULL, 'v'},
{"server", no_argument, NULL, 's'},
@ -370,7 +401,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
int blksize;
blksize = 0;
while ((ch = getopt_long(argc, argv, "p:f:i:DVdvsc:ub:t:n:l:P:Rw:B:M:N6S:h", longopts, NULL)) != -1) {
while ((ch = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N6S:h", longopts, NULL)) != -1) {
switch (ch) {
case 'p':
test->server_port = atoi(optarg);
@ -398,6 +429,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
case 'V':
test->verbose = 1;
break;
case 'J':
test->json_output = 1;
break;
case 'd':
test->debug = 1;
break;
@ -555,16 +589,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
i_errno = IENOROLE;
return -1;
}
if (test->verbose) {
fputs(version, stdout);
system("uname -a");
}
return 0;
}
int
all_data_sent(struct iperf_test * test)
all_data_sent(struct iperf_test *test)
{
if (test->settings->bytes > 0) {
if (test->bytes_sent >= (test->num_streams * test->settings->bytes)) {
@ -616,7 +646,7 @@ iperf_recv(struct iperf_test *test, fd_set *read_setP)
}
static void
test_timer_proc(TimerClientData client_data, struct timeval* nowP)
test_timer_proc(TimerClientData client_data, struct timeval *nowP)
{
struct iperf_test *test = client_data.p;
@ -625,7 +655,7 @@ test_timer_proc(TimerClientData client_data, struct timeval* nowP)
}
static void
stats_timer_proc(TimerClientData client_data, struct timeval* nowP)
stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
{
struct iperf_test *test = client_data.p;
@ -635,7 +665,7 @@ stats_timer_proc(TimerClientData client_data, struct timeval* nowP)
}
static void
reporter_timer_proc(TimerClientData client_data, struct timeval* nowP)
reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
{
struct iperf_test *test = client_data.p;
@ -698,7 +728,7 @@ iperf_init_test(struct iperf_test *test)
*/
int
iperf_exchange_parameters(struct iperf_test * test)
iperf_exchange_parameters(struct iperf_test *test)
{
int s, msg;
char state;
@ -1083,8 +1113,10 @@ connect_msg(struct iperf_stream *sp)
rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
}
printf("[%3d] local %s port %d connected to %s port %d\n",
sp->socket, ipl, lport, ipr, rport);
if (sp->test->json_output)
cJSON_AddItemToObject(sp->test->json_start, "connected", iperf_json_printf("socket: %d local_host: %s local_port: %d remote_host: %s remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport));
else
printf("[%3d] local %s port %d connected to %s port %d\n", sp->socket, ipl, lport, ipr, rport);
}
@ -1111,7 +1143,7 @@ iperf_new_test()
/**************************************************************************/
int
iperf_defaults(struct iperf_test * testp)
iperf_defaults(struct iperf_test *testp)
{
testp->duration = DURATION;
testp->server_port = PORT;
@ -1181,7 +1213,7 @@ iperf_defaults(struct iperf_test * testp)
/**************************************************************************/
void
iperf_free_test(struct iperf_test * test)
iperf_free_test(struct iperf_test *test)
{
struct protocol *prot;
struct iperf_stream *sp;
@ -1280,7 +1312,7 @@ iperf_reset_test(struct iperf_test *test)
void
iperf_stats_callback(struct iperf_test * test)
iperf_stats_callback(struct iperf_test *test)
{
struct iperf_stream *sp;
struct iperf_stream_result *rp = NULL;
@ -1330,15 +1362,32 @@ iperf_print_intermediate(struct iperf_test *test)
struct iperf_stream *sp = NULL;
struct iperf_interval_results *irp;
iperf_size_t bytes = 0;
double bandwidth;
long retransmits = 0;
double start_time, end_time;
cJSON *json_interval;
cJSON *json_interval_streams;
if (test->json_output) {
json_interval = cJSON_CreateObject();
if (json_interval == NULL)
return;
cJSON_AddItemToArray(test->json_intervals, json_interval);
json_interval_streams = cJSON_CreateArray();
if (json_interval_streams == NULL)
return;
cJSON_AddItemToObject(json_interval, "streams", json_interval_streams);
} else {
json_interval = NULL;
json_interval_streams = NULL;
}
SLIST_FOREACH(sp, &test->streams, streams) {
print_interval_results(test, sp);
print_interval_results(test, sp, json_interval_streams);
/* sum up all streams */
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
if (irp == NULL) {
printf("iperf_print_intermediate Error: interval_results is NULL \n");
fprintf(stderr, "iperf_print_intermediate Error: interval_results is NULL\n");
return;
}
bytes += irp->bytes_transferred;
@ -1354,16 +1403,23 @@ iperf_print_intermediate(struct iperf_test *test)
sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */
unit_snprintf(ubuf, UNIT_LEN, (double) (bytes), 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) (bytes / irp->interval_duration),
test->settings->unit_format);
unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
bandwidth = (double) bytes / (double) irp->interval_duration;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
start_time = timeval_diff(&sp->result->start_time,&irp->interval_start_time);
end_time = timeval_diff(&sp->result->start_time,&irp->interval_end_time);
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits())
printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits);
else
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits()) {
if (test->json_output)
cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits));
else
printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits);
} else {
if (test->json_output)
cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8));
else
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
}
}
}
@ -1371,6 +1427,8 @@ static void
iperf_print_results(struct iperf_test *test)
{
cJSON *json_summary_streams;
cJSON *json_summary_stream;
long retransmits = 0, total_retransmits = 0;
int total_packets = 0, lost_packets = 0;
char ubuf[UNIT_LEN];
@ -1378,25 +1436,40 @@ iperf_print_results(struct iperf_test *test)
struct iperf_stream *sp = NULL;
iperf_size_t bytes_sent, total_sent = 0;
iperf_size_t bytes_received, total_received = 0;
double start_time, end_time, avg_jitter;
double start_time, end_time, avg_jitter, loss_percent;
double bandwidth, out_of_order_percent;
/* print final summary for all intervals */
if (test->verbose)
printf("Test Complete. Summary Results:\n");
if (test->protocol->id == Ptcp)
if (has_tcpinfo_retransmits())
fputs(report_bw_retrans_header, stdout);
if (test->json_output) {
json_summary_streams = cJSON_CreateArray();
if (json_summary_streams == NULL)
return;
cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);
} else {
if (test->verbose)
printf("Test Complete. Summary Results:\n");
if (test->protocol->id == Ptcp)
if (has_tcpinfo_retransmits())
fputs(report_bw_retrans_header, stdout);
else
fputs(report_bw_header, stdout);
else
fputs(report_bw_header, stdout);
else
fputs(report_bw_udp_header, stdout);
fputs(report_bw_udp_header, stdout);
}
start_time = 0.;
sp = SLIST_FIRST(&test->streams);
end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time);
avg_jitter = 0;
SLIST_FOREACH(sp, &test->streams, streams) {
if (test->json_output) {
json_summary_stream = cJSON_CreateObject();
if (json_summary_stream == NULL)
return;
cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
}
bytes_sent = sp->result->bytes_sent;
bytes_received = sp->result->bytes_received;
total_sent += bytes_sent;
@ -1414,56 +1487,91 @@ iperf_print_results(struct iperf_test *test)
}
if (bytes_sent > 0) {
unit_snprintf(ubuf, UNIT_LEN, (double) (bytes_sent), 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_sent / end_time), test->settings->unit_format);
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
bandwidth = (double) bytes_sent / (double) end_time;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
if (test->protocol->id == Ptcp) {
fputs(" Sent\n", stdout);
if (has_tcpinfo_retransmits())
printf(report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, retransmits);
else
printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
if (!test->json_output)
fputs(" Sent\n", stdout);
if (has_tcpinfo_retransmits()) {
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "sent", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) retransmits));
else
printf(report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, retransmits);
} else {
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "sent", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8));
else
printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
}
} else {
printf(report_bw_udp_format, sp->socket, start_time,
end_time, ubuf, nbuf, sp->jitter * 1000, sp->cnt_error,
sp->packet_count, (double) (100.0 * sp->cnt_error / sp->packet_count));
if (test->role == 'c') {
printf(report_datagrams, sp->socket, sp->packet_count);
}
if (sp->outoforder_packets > 0)
printf(report_sum_outoforder, start_time, end_time, sp->cnt_error);
out_of_order_percent = 100.0 * sp->cnt_error / sp->packet_count;
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f outoforder: %d packets: %d percent: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) sp->cnt_error, (int64_t) sp->packet_count, out_of_order_percent));
else {
printf(report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, sp->cnt_error, sp->packet_count, out_of_order_percent);
if (test->role == 'c')
printf(report_datagrams, sp->socket, sp->packet_count);
if (sp->outoforder_packets > 0)
printf(report_sum_outoforder, start_time, end_time, sp->cnt_error);
}
}
}
if (bytes_received > 0) {
unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) (bytes_received / end_time), test->settings->unit_format);
bandwidth = (double) bytes_received / (double) end_time;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
if (test->protocol->id == Ptcp) {
printf(" Received\n");
printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
if (!test->json_output)
printf(" Received\n");
if (test->json_output)
cJSON_AddItemToObject(json_summary_stream, "received", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8));
else
printf(report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf);
}
}
}
if (test->num_streams > 1) {
unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) total_sent / end_time, test->settings->unit_format);
bandwidth = (double) total_sent / (double) end_time;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
if (test->protocol->id == Ptcp) {
printf(" Total sent\n");
if (has_tcpinfo_retransmits())
printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits);
if (!test->json_output)
printf(" Total sent\n");
if (has_tcpinfo_retransmits()) {
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits));
else
printf(report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits);
} else {
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8));
else
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
}
unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
bandwidth = (double) total_received / (double) end_time;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
if (!test->json_output)
printf(" Total received\n");
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_received, bandwidth * 8));
else
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) (total_received / end_time), test->settings->unit_format);
printf(" Total received\n");
printf(report_sum_bw_format, start_time, end_time, ubuf, nbuf);
} else {
avg_jitter /= test->num_streams;
printf(report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter,
lost_packets, total_packets, (double) (100.0 * lost_packets / total_packets));
loss_percent = 100.0 * lost_packets / total_packets;
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d total_packets: %d loss_percent: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, avg_jitter, (int64_t) lost_packets, (int64_t) total_packets, loss_percent));
else
printf(report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter, lost_packets, total_packets, loss_percent);
}
}
if (test->verbose) {
if (test->json_output)
cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host: %f remote: %f", (double) test->cpu_util, (double) test->remote_cpu_util));
else if (test->verbose) {
printf("Host CPU Utilization: %.1f%%\n", test->cpu_util);
printf("Remote CPU Utilization: %.1f%%\n", test->remote_cpu_util);
}
@ -1477,7 +1585,7 @@ iperf_print_results(struct iperf_test *test)
*/
void
iperf_reporter_callback(struct iperf_test * test)
iperf_reporter_callback(struct iperf_test *test)
{
switch (test->state) {
case TEST_RUNNING:
@ -1494,50 +1602,60 @@ iperf_reporter_callback(struct iperf_test * test)
}
/**************************************************************************/
void
print_interval_results(struct iperf_test * test, struct iperf_stream * sp)
static void
print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams)
{
char ubuf[UNIT_LEN];
char nbuf[UNIT_LEN];
double st = 0., et = 0.;
struct iperf_interval_results *irp = NULL;
double bandwidth;
irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
if (irp == NULL) {
printf("print_interval_results Error: interval_results is NULL \n");
fprintf(stderr, "print_interval_results Error: interval_results is NULL \n");
return;
}
/* First stream? */
if (sp == SLIST_FIRST(&test->streams)) {
/* It it's the first interval, print the header;
** else if there's more than one stream, print the separator;
** else nothing.
*/
if (timeval_equals(&sp->result->start_time, &irp->interval_start_time))
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits())
fputs(report_bw_retrans_header, stdout);
else
fputs(report_bw_header, stdout);
else if (test->num_streams > 1)
fputs(report_bw_separator, stdout);
if (!test->json_output) {
/* First stream? */
if (sp == SLIST_FIRST(&test->streams)) {
/* It it's the first interval, print the header;
** else if there's more than one stream, print the separator;
** else nothing.
*/
if (timeval_equals(&sp->result->start_time, &irp->interval_start_time))
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits())
fputs(report_bw_retrans_header, stdout);
else
fputs(report_bw_header, stdout);
else if (test->num_streams > 1)
fputs(report_bw_separator, stdout);
}
}
unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
unit_snprintf(nbuf, UNIT_LEN, (double) (irp->bytes_transferred / irp->interval_duration),
test->settings->unit_format);
bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
st = timeval_diff(&sp->result->start_time,&irp->interval_start_time);
et = timeval_diff(&sp->result->start_time,&irp->interval_end_time);
st = timeval_diff(&sp->result->start_time, &irp->interval_start_time);
et = timeval_diff(&sp->result->start_time, &irp->interval_end_time);
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits())
printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->this_retrans);
else
printf(report_bw_format, sp->socket, st, et, ubuf, nbuf);
if (test->protocol->id == Ptcp && has_tcpinfo_retransmits()) {
if (test->json_output)
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->this_retrans));
else
printf(report_bw_retrans_format, sp->socket, st, et, ubuf, nbuf, irp->this_retrans);
} else {
if (test->json_output)
cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8));
else
printf(report_bw_format, sp->socket, st, et, ubuf, nbuf);
}
}
/**************************************************************************/
void
iperf_free_stream(struct iperf_stream * sp)
iperf_free_stream(struct iperf_stream *sp)
{
struct iperf_interval_results *irp, *nirp;
@ -1568,6 +1686,7 @@ iperf_new_stream(struct iperf_test *test, int s)
memset(sp, 0, sizeof(struct iperf_stream));
sp->test = test;
sp->buffer = (char *) malloc(test->settings->blksize);
sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
sp->settings = test->settings;
@ -1645,7 +1764,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
/**************************************************************************/
void
iperf_add_stream(struct iperf_test * test, struct iperf_stream * sp)
iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp)
{
int i;
struct iperf_stream *n, *prev;
@ -1670,3 +1789,117 @@ sig_handler(int sig)
{
longjmp(env, 1);
}
int
iperf_json_start(struct iperf_test *test)
{
test->json_top = cJSON_CreateObject();
if (test->json_top == NULL)
return -1;
test->json_start = cJSON_CreateObject();
if (test->json_start == NULL)
return -1;
cJSON_AddItemToObject(test->json_top, "start", test->json_start);
test->json_intervals = cJSON_CreateArray();
if (test->json_intervals == NULL)
return -1;
cJSON_AddItemToObject(test->json_top, "intervals", test->json_intervals);
test->json_end = cJSON_CreateObject();
if (test->json_end == NULL)
return -1;
cJSON_AddItemToObject(test->json_top, "end", test->json_end);
return 0;
}
int
iperf_json_finish(struct iperf_test *test)
{
char *str;
str = cJSON_Print(test->json_top);
if (str == NULL)
return -1;
fputs(str, stdout);
putchar('\n');
free(str);
cJSON_Delete(test->json_top);
test->json_top = test->json_start = test->json_intervals = test->json_end = NULL;
return 0;
}
/* Helper routine for building cJSON objects in a printf-like manner.
**
** Sample call:
** j = iperf_json_printf("foo: %b bar: %d bletch: %f eep: %s", b, i, f, s);
**
** The four formatting characters and the types they expect are:
** %b boolean int
** %d integer int64_t
** %f floating point double
** %s string char *
** If the values you're passing in are not these exact types, you must
** cast them, there is no automatic type coercion/widening here.
**
** The colons mark the end of field names, and blanks are ignored.
**
** This routine is not particularly robust, but it's not part of the API,
** it's just for internal iperf3 use.
**
** It currently lives in iperf_api.c, rather than iperf_util.c, because
** putting it in iperf_util.c would mean adding -lm to more executables,
** because the cJSON package uses libm/floor(). If I get around to fixing
** that, then this routine can move.
*/
cJSON*
iperf_json_printf(const char *format, ...)
{
cJSON* o;
va_list argp;
const char *cp;
char name[100];
char* np;
cJSON* j;
o = cJSON_CreateObject();
if (o == NULL)
return NULL;
va_start(argp, format);
np = name;
for (cp = format; *cp != '\0'; ++cp) {
switch (*cp) {
case ' ':
break;
case ':':
*np = '\0';
break;
case '%':
++cp;
switch (*cp) {
case 'b':
j = cJSON_CreateBool(va_arg(argp, int));
break;
case 'd':
j = cJSON_CreateInt(va_arg(argp, int64_t));
break;
case 'f':
j = cJSON_CreateFloat(va_arg(argp, double));
break;
case 's':
j = cJSON_CreateString(va_arg(argp, char *));
break;
default:
return NULL;
}
if (j == NULL)
return NULL;
cJSON_AddItemToObject(o, name, j);
np = name;
break;
default:
*np++ = *cp;
break;
}
}
va_end(argp);
return o;
}

View File

@ -156,7 +156,6 @@ long get_tcpinfo_total_retransmits(struct iperf_interval_results *irp);
void print_tcpinfo(struct iperf_test *test);
void build_tcpinfo_message(struct iperf_interval_results *r, char *message);
void print_interval_results(struct iperf_test * test, struct iperf_stream *sp);
int iperf_send(struct iperf_test *, fd_set *);
int iperf_recv(struct iperf_test *, fd_set *);
void sig_handler(int);
@ -193,6 +192,11 @@ int iperf_accept(struct iperf_test *);
int iperf_handle_message_server(struct iperf_test *);
void iperf_test_reset(struct iperf_test *);
/* JSON output routines. */
int iperf_json_start(struct iperf_test *);
int iperf_json_finish(struct iperf_test *);
cJSON* iperf_json_printf(const char *format, ...);
/* Error routines. */
void iperf_error(char *);
char *iperf_strerror(int);

View File

@ -52,8 +52,10 @@ iperf_server_listen(struct iperf_test *test)
return -1;
}
printf("-----------------------------------------------------------\n");
printf("Server listening on %d\n", test->server_port);
if (!test->json_output) {
printf("-----------------------------------------------------------\n");
printf("Server listening on %d\n", test->server_port);
}
// This needs to be changed to reflect if client has different window size
// make sure we got what we asked for
@ -73,13 +75,16 @@ iperf_server_listen(struct iperf_test *test)
if (test->protocol->id == Ptcp) {
if (test->settings->socket_bufsize > 0) {
unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
printf("TCP window size: %s\n", ubuf);
if (test->json_output)
printf("TCP window size: %s\n", ubuf);
} else {
printf("Using TCP Autotuning\n");
if (test->json_output)
printf("Using TCP Autotuning\n");
}
}
*/
printf("-----------------------------------------------------------\n");
if (!test->json_output)
printf("-----------------------------------------------------------\n");
FD_ZERO(&test->read_set);
FD_ZERO(&test->write_set);

View File

@ -67,7 +67,7 @@ iperf_udp_recv(struct iperf_stream *sp)
sp->packet_count = pcount;
} else {
sp->outoforder_packets++;
printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket);
fprintf(stderr, "OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket);
}
/* jitter measurement */

View File

@ -67,10 +67,11 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
" -p, --port # server port to listen on/connect to\n"
" -f, --format [kmgKMG] format to report: Kbits, Mbits, KBytes, MBytes\n"
" -i, --interval # seconds between periodic bandwidth reports\n"
" -V, --verbose more verbose output\n"
" -V, --verbose more detailed output\n"
" -J, --json output in JSON format\n"
" -d, --debug debug mode\n"
" -v, --version print version information and quit\n"
" -h, --help print this message and quit\n"
" -v, --version show version information and quit\n"
" -h, --help show this message and quit\n"
"Server specific:\n"
" -s, --server run in server mode\n"
"Client specific:\n"
@ -110,7 +111,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
-y, --reportstyle C report as a Comma-Separated Values
#endif
const char version[] = "iperf version " IPERF_VERSION " (" IPERF_VERSION_DATE ") \n";
const char version[] = "iperf version " IPERF_VERSION " (" IPERF_VERSION_DATE ")";
/* -------------------------------------------------------------------
* settings

View File

@ -51,7 +51,7 @@ main(int argc, char **argv)
if (rc < 0) {
perror("setpriority:");
printf("setting priority to valid level\n");
fprintf(stderr, "setting priority to valid level\n");
rc = setpriority(PRIO_PROCESS, 0, 0);
}
@ -107,21 +107,45 @@ main(int argc, char **argv)
iperf_free_test(test);
printf("\niperf Done.\n");
return 0;
}
static char*
get_system_info(void)
{
FILE* fp;
static char buf[1000];
fp = popen("uname -a", "r");
if (fp == NULL)
return NULL;
fgets(buf, sizeof(buf), fp);
pclose(fp);
return buf;
}
/**************************************************************************/
int
iperf_run(struct iperf_test * test)
{
if (test->json_output)
if (iperf_json_start(test) < 0)
return -1;
if (test->json_output) {
cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
} else if (test->verbose) {
printf("%s\n", version);
system("uname -a");
}
switch (test->role) {
case 's':
for (;;) {
if (iperf_run_server(test) < 0) {
iperf_error("error");
printf("\n");
fprintf(stderr, "\n");
}
iperf_reset_test(test);
}
@ -137,5 +161,12 @@ iperf_run(struct iperf_test * test)
break;
}
if (test->json_output) {
if (iperf_json_finish(test) < 0)
return -1;
} else
printf("\niperf Done.\n");
return 0;
}

View File

@ -99,6 +99,7 @@ get_tcpinfo_total_retransmits(struct iperf_interval_results *irp)
#endif
}
#ifdef notdef
/*************************************************************/
//print_tcpinfo(struct iperf_interval_results *r)
void
@ -127,6 +128,7 @@ print_tcpinfo(struct iperf_test *test)
*/
#endif
}
#endif
/*************************************************************/

View File

@ -8,4 +8,4 @@
*/
#define IPERF_VERSION "3.0-BETA5"
#define IPERF_VERSION_DATE "13 Dec 2012"
#define IPERF_VERSION_DATE "01 Feb 2013"