Converted the results exchange to use JSON.

This commit is contained in:
jef 2012-10-18 10:47:27 -07:00
parent 10d202a998
commit 23481e7953
5 changed files with 219 additions and 179 deletions

View File

@ -36,7 +36,7 @@ libiperf_a_SOURCES = \
# Specify the sources and various flags for the iperf binary
iperf3_SOURCES = main.c
iperf3_CFLAGS = -g -Wall
iperf3_LDADD = libiperf.a
iperf3_LDADD = libiperf.a -lm
iperf3_LDFLAGS =
# Specify the sources and various flags for the profiled iperf binary. This

View File

@ -268,7 +268,7 @@ libiperf_a_SOURCES = \
# Specify the sources and various flags for the iperf binary
iperf3_SOURCES = main.c
iperf3_CFLAGS = -g -Wall
iperf3_LDADD = libiperf.a
iperf3_LDADD = libiperf.a -lm
iperf3_LDFLAGS =
# Specify the sources and various flags for the profiled iperf binary. This

View File

@ -158,8 +158,8 @@ static const char *parse_number( cJSON *item, const char *num )
/* Put it together: number = +/- number.fraction * 10^+/- exponent */
n = sign * n * pow( 10.0, ( scale + subscale * signsubscale ) );
item->valuedouble = n;
item->valueint = (int) n;
item->valuefloat = n;
item->valueint = n;
item->type = cJSON_Number;
return num;
}
@ -169,7 +169,7 @@ static const char *parse_number( cJSON *item, const char *num )
static char *print_number( cJSON *item )
{
char *str;
double d = item->valuedouble;
double d = item->valuefloat;
if ( fabs( ( (double) item->valueint ) - d ) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN ) {
str = (char*) cJSON_malloc( 21 ); /* 2^64+1 can be represented in 21 chars. */
if ( str )
@ -899,13 +899,24 @@ cJSON *cJSON_CreateBool( int b )
return item;
}
cJSON *cJSON_CreateNumber( double num )
cJSON *cJSON_CreateInt( long long num )
{
cJSON *item = cJSON_New_Item();
if ( item ) {
item->type = cJSON_Number;
item->valuedouble = num;
item->valueint = (int) num;
item->valuefloat = num;
item->valueint = num;
}
return item;
}
cJSON *cJSON_CreateFloat( double num )
{
cJSON *item = cJSON_New_Item();
if ( item ) {
item->type = cJSON_Number;
item->valuefloat = num;
item->valueint = num;
}
return item;
}
@ -939,12 +950,12 @@ cJSON *cJSON_CreateObject( void )
/* Create Arrays. */
cJSON *cJSON_CreateIntArray( int *numbers,int count )
cJSON *cJSON_CreateIntArray( long long *numbers, int count )
{
int i;
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
for ( i = 0; a && i < count; ++i ) {
n = cJSON_CreateNumber( numbers[i] );
n = cJSON_CreateInt( numbers[i] );
if ( ! i )
a->child = n;
else
@ -954,27 +965,12 @@ cJSON *cJSON_CreateIntArray( int *numbers,int count )
return a;
}
cJSON *cJSON_CreateFloatArray( float *numbers, int count )
cJSON *cJSON_CreateFloatArray( double *numbers, int count )
{
int i;
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
for ( i = 0; a && i < count; ++i ) {
n = cJSON_CreateNumber( numbers[i] );
if ( ! i )
a->child = n;
else
suffix_object( p, n );
p = n;
}
return a;
}
cJSON *cJSON_CreateDoubleArray( double *numbers, int count )
{
int i;
cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
for ( i = 0; a && i < count; ++i ) {
n = cJSON_CreateNumber( numbers[i] );
n = cJSON_CreateFloat( numbers[i] );
if ( ! i )
a->child = n;
else

View File

@ -47,8 +47,8 @@ typedef struct cJSON {
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
long long valueint; /* The item's number, if type==cJSON_Number */
double valuefloat; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
@ -86,15 +86,15 @@ extern cJSON *cJSON_CreateNull( void );
extern cJSON *cJSON_CreateTrue( void );
extern cJSON *cJSON_CreateFalse( void );
extern cJSON *cJSON_CreateBool( int b );
extern cJSON *cJSON_CreateNumber( double num );
extern cJSON *cJSON_CreateInt( long long num );
extern cJSON *cJSON_CreateFloat( double num );
extern cJSON *cJSON_CreateString( const char *string );
extern cJSON *cJSON_CreateArray( void );
extern cJSON *cJSON_CreateObject( void );
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray( int *numbers,int count );
extern cJSON *cJSON_CreateFloatArray( float *numbers, int count );
extern cJSON *cJSON_CreateDoubleArray( double *numbers, int count );
extern cJSON *cJSON_CreateIntArray( long long *numbers,int count );
extern cJSON *cJSON_CreateFloatArray( double *numbers, int count );
extern cJSON *cJSON_CreateStringArray( const char **strings, int count );
/* Append item to the specified array/object. */
@ -117,7 +117,8 @@ extern void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON
#define cJSON_AddNullToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateNull() )
#define cJSON_AddTrueToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateTrue() )
#define cJSON_AddFalseToObject( object, name ) cJSON_AddItemToObject( object, name, cJSON_CreateFalse() )
#define cJSON_AddNumberToObject( object, name, n ) cJSON_AddItemToObject( object, name, cJSON_CreateNumber( n ) )
#define cJSON_AddIntToObject( object, name, n ) cJSON_AddItemToObject( object, name, cJSON_CreateInt( n ) )
#define cJSON_AddFloatToObject( object, name, n ) cJSON_AddItemToObject( object, name, cJSON_CreateFloat( n ) )
#define cJSON_AddStringToObject( object, name, s ) cJSON_AddItemToObject( object, name, cJSON_CreateString( s ) )
#ifdef __cplusplus

View File

@ -36,6 +36,7 @@
#include "iperf_tcp.h"
#include "timer.h"
#include "cjson.h"
#include "units.h"
#include "tcp_window_size.h"
#include "iperf_util.h"
@ -45,12 +46,10 @@ jmp_buf env; /* to handle longjmp on signal */
/* Forwards. */
static int format_results(struct iperf_test *test, char **resultsP, unsigned int *sizeP);
/* XXX There are actually a whole bunch of routines declared in iperf_api.h
** that should really be static and declared as forwards. parse_results()
** is just the first one I ran across.
*/
static int parse_results(struct iperf_test *test, char *results);
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 cJSON *JSON_read(int fd);
/*************************** Print usage functions ****************************/
@ -893,175 +892,219 @@ iperf_exchange_parameters(struct iperf_test * test)
int
iperf_exchange_results(struct iperf_test *test)
{
unsigned int hsize, nsize;
char *results;
if (test->role == 'c') {
/* Prepare results string and send to server */
if ( format_results(test, &results, &hsize) < 0)
return (-1);
nsize = htonl(hsize);
if (Nwrite(test->ctrl_sck, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IESENDRESULTS;
return (-1);
}
if (Nwrite(test->ctrl_sck, results, hsize, Ptcp) < 0) {
i_errno = IESENDRESULTS;
return (-1);
}
free(results);
/* Get server results string */
if (Nread(test->ctrl_sck, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IERECVRESULTS;
return (-1);
}
hsize = ntohl(nsize);
results = (char *) malloc(hsize * sizeof(char));
if (results == NULL) {
i_errno = IERECVRESULTS;
return (-1);
}
if (Nread(test->ctrl_sck, results, hsize, Ptcp) < 0) {
i_errno = IERECVRESULTS;
return (-1);
}
// XXX: The only error this sets is IESTREAMID, which may never be reached. Consider making void.
if (parse_results(test, results) < 0)
return (-1);
free(results);
/* Send results to server. */
if (send_results(test) < 0)
return -1;
/* Get server results. */
if (get_results(test) < 0)
return -1;
} else {
/* Get client results string */
if (Nread(test->ctrl_sck, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IERECVRESULTS;
return (-1);
}
hsize = ntohl(nsize);
results = (char *) malloc(hsize * sizeof(char));
if (results == NULL) {
i_errno = IERECVRESULTS;
return (-1);
}
if (Nread(test->ctrl_sck, results, hsize, Ptcp) < 0) {
i_errno = IERECVRESULTS;
return (-1);
}
// XXX: Same issue as with client
if (parse_results(test, results) < 0)
return (-1);
free(results);
/* Prepare results string and send to client */
if ( format_results(test, &results, &hsize) < 0)
return (-1);
nsize = htonl(hsize);
if (Nwrite(test->ctrl_sck, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IESENDRESULTS;
return (-1);
}
if (Nwrite(test->ctrl_sck, results, hsize, Ptcp) < 0) {
i_errno = IESENDRESULTS;
return (-1);
}
free(results);
/* Get client results. */
if (get_results(test) < 0)
return -1;
/* Send results to client. */
if (send_results(test) < 0)
return -1;
}
return (0);
return 0;
}
/*************************************************************/
static int
format_results(struct iperf_test *test, char **resultsP, unsigned int *sizeP)
send_results(struct iperf_test *test)
{
char buf[128];
int r = 0;
cJSON *j;
cJSON *j_streams;
struct iperf_stream *sp;
cJSON *j_stream;
iperf_size_t bytes_transferred;
*resultsP = NULL;
*sizeP = 0;
snprintf(buf, 128, "-C %f\n", test->cpu_util);
*sizeP += strlen(buf);
if ((*resultsP = malloc((*sizeP)+1)) == NULL) {
j = cJSON_CreateObject();
if (j == NULL) {
i_errno = IEPACKAGERESULTS;
return (-1);
}
**resultsP = '\0';
strncat(*resultsP, buf, (*sizeP)+1);
SLIST_FOREACH(sp, &test->streams, streams) {
if (test->role == 'c')
bytes_transferred = (test->reverse ? sp->result->bytes_received : sp->result->bytes_sent);
else
bytes_transferred = (test->reverse ? sp->result->bytes_sent : sp->result->bytes_received);
snprintf(buf, 128, "%d:%llu,%lf,%d,%d\n", sp->id, bytes_transferred,sp->jitter,
sp->cnt_error, sp->packet_count);
*sizeP += strlen(buf);
if ((*resultsP = realloc(*resultsP, (*sizeP)+1)) == NULL) {
r = -1;
} else {
cJSON_AddFloatToObject(j, "cpu_util", test->cpu_util);
j_streams = cJSON_CreateArray();
if (j_streams == NULL) {
i_errno = IEPACKAGERESULTS;
return (-1);
r = -1;
} else {
cJSON_AddItemToObject(j, "streams", j_streams);
SLIST_FOREACH(sp, &test->streams, streams) {
j_stream = cJSON_CreateObject();
if (j_stream == NULL) {
i_errno = IEPACKAGERESULTS;
r = -1;
} else {
cJSON_AddItemToArray(j_streams, j_stream);
if (test->role == 'c')
bytes_transferred = (test->reverse ? sp->result->bytes_received : sp->result->bytes_sent);
else
bytes_transferred = (test->reverse ? sp->result->bytes_sent : sp->result->bytes_received);
cJSON_AddIntToObject(j_stream, "id", sp->id);
cJSON_AddIntToObject(j_stream, "bytes", bytes_transferred);
cJSON_AddFloatToObject(j_stream, "jitter", sp->jitter);
cJSON_AddIntToObject(j_stream, "errors", sp->cnt_error);
cJSON_AddIntToObject(j_stream, "packets", sp->packet_count);
}
}
if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
i_errno = IESENDRESULTS;
r = -1;
}
}
/*
if (sp == SLIST_FIRST(&test->streams))
**resultsP = '\0';
*/
strncat(*resultsP, buf, (*sizeP)+1);
cJSON_Delete(j);
}
(*sizeP)++;
return (0);
return r;
}
/*************************************************************/
static int
parse_results(struct iperf_test *test, char *results)
get_results(struct iperf_test *test)
{
int r = 0;
cJSON *j;
cJSON *j_cpu_util;
cJSON *j_streams;
int n, i;
cJSON *j_stream;
cJSON *j_id;
cJSON *j_bytes;
cJSON *j_jitter;
cJSON *j_errors;
cJSON *j_packets;
int sid, cerror, pcount;
double jitter;
char *strp;
char *tok;
iperf_size_t bytes_transferred;
struct iperf_stream *sp;
/* Isolate the first line */
strp = strchr(results, '\n');
*strp = '\0';
strp++;
for (tok = strtok(results, " "); tok; tok = strtok(NULL, " ")) {
if (strcmp(tok, "-C") == 0) {
test->remote_cpu_util = atof(strtok(NULL, " "));
}
j = JSON_read(test->ctrl_sck);
if (j == NULL) {
i_errno = IERECVRESULTS;
r = -1;
} else {
j_cpu_util = cJSON_GetObjectItem(j, "cpu_util");
if (j_cpu_util == NULL) {
i_errno = IERECVRESULTS;
r = -1;
} else {
test->remote_cpu_util = j_cpu_util->valuefloat;
j_streams = cJSON_GetObjectItem(j, "streams");
if (j_streams == NULL) {
i_errno = IERECVRESULTS;
r = -1;
} else {
n = cJSON_GetArraySize(j_streams);
for (i=0; i<n; ++i) {
j_stream = cJSON_GetArrayItem(j_streams, i);
if (j_stream == NULL) {
i_errno = IERECVRESULTS;
r = -1;
} else {
j_id = cJSON_GetObjectItem(j_stream, "id");
j_bytes = cJSON_GetObjectItem(j_stream, "bytes");
j_jitter = cJSON_GetObjectItem(j_stream, "jitter");
j_errors = cJSON_GetObjectItem(j_stream, "errors");
j_packets = cJSON_GetObjectItem(j_stream, "packets");
if (j_id == NULL || j_bytes == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {
i_errno = IERECVRESULTS;
r = -1;
} else {
sid = j_id->valueint;
bytes_transferred = j_bytes->valueint;
jitter = j_jitter->valuefloat;
cerror = j_errors->valueint;
pcount = j_packets->valueint;
SLIST_FOREACH(sp, &test->streams, streams)
if (sp->id == sid) break;
if (sp == NULL) {
i_errno = IESTREAMID;
r = -1;
} else {
if ((test->role == 'c' && !test->reverse) || (test->role == 's' && test->reverse)) {
sp->jitter = jitter;
sp->cnt_error = cerror;
sp->packet_count = pcount;
sp->result->bytes_received = bytes_transferred;
} else
sp->result->bytes_sent = bytes_transferred;
}
}
}
}
}
}
cJSON_Delete(j);
}
for (; *strp; strp = strchr(strp, '\n')+1) {
sscanf(strp, "%d:%llu,%lf,%d,%d\n", &sid, &bytes_transferred, &jitter,
&cerror, &pcount);
SLIST_FOREACH(sp, &test->streams, streams)
if (sp->id == sid) break;
if (sp == NULL) {
i_errno = IESTREAMID;
return (-1);
}
if ((test->role == 'c' && !test->reverse) || (test->role == 's' && test->reverse)) {
sp->jitter = jitter;
sp->cnt_error = cerror;
sp->packet_count = pcount;
sp->result->bytes_received = bytes_transferred;
} else
sp->result->bytes_sent = bytes_transferred;
}
return (0);
return r;
}
/*************************************************************/
static int
JSON_write(int fd, cJSON *json)
{
unsigned int hsize, nsize;
char *str;
int r = 0;
str = cJSON_PrintUnformatted(json);
if (str == NULL) {
i_errno = IESENDRESULTS;
r = -1;
} else {
hsize = strlen(str);
nsize = htonl(hsize);
if (Nwrite(fd, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IESENDRESULTS;
r = -1;
} else {
if (Nwrite(fd, str, hsize, Ptcp) < 0) {
i_errno = IESENDRESULTS;
r = -1;
}
}
free(str);
}
return r;
}
/*************************************************************/
static cJSON *
JSON_read(int fd)
{
unsigned int hsize, nsize;
char *str;
cJSON *json = NULL;
if (Nread(fd, &nsize, sizeof(nsize), Ptcp) < 0) {
i_errno = IERECVRESULTS;
} else {
hsize = ntohl(nsize);
str = (char *) malloc((hsize+1) * sizeof(char)); /* +1 for EOS */
if (str == NULL) {
i_errno = IERECVRESULTS;
} else {
if (Nread(fd, str, hsize, Ptcp) < 0) {
i_errno = IERECVRESULTS;
} else {
str[hsize] = '\0'; /* add the EOS */
json = cJSON_Parse(str);
if (json == NULL) {
i_errno = IERECVRESULTS;
}
}
}
free(str);
}
return json;
}
/*************************************************************/
/**