@@ -102,6 +102,7 @@ static int diskfile_recv(struct iperf_stream *sp);
102
102
static int JSON_write (int fd , cJSON * json );
103
103
static void print_interval_results (struct iperf_test * test , struct iperf_stream * sp , cJSON * json_interval_streams );
104
104
static cJSON * JSON_read (int fd );
105
+ static int JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj );
105
106
106
107
107
108
/*************************** Print usage functions ****************************/
@@ -326,6 +327,12 @@ iperf_get_test_json_output_string(struct iperf_test *ipt)
326
327
return ipt -> json_output_string ;
327
328
}
328
329
330
+ int
331
+ iperf_get_test_json_stream (struct iperf_test * ipt )
332
+ {
333
+ return ipt -> json_stream ;
334
+ }
335
+
329
336
int
330
337
iperf_get_test_zerocopy (struct iperf_test * ipt )
331
338
{
@@ -682,6 +689,12 @@ iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
682
689
ipt -> json_output = json_output ;
683
690
}
684
691
692
+ void
693
+ iperf_set_test_json_stream (struct iperf_test * ipt , int json_stream )
694
+ {
695
+ ipt -> json_stream = json_stream ;
696
+ }
697
+
685
698
int
686
699
iperf_has_zerocopy ( void )
687
700
{
@@ -892,8 +905,12 @@ iperf_on_test_start(struct iperf_test *test)
892
905
iperf_printf (test , test_start_time , test -> protocol -> name , test -> num_streams , test -> settings -> blksize , test -> omit , test -> duration , test -> settings -> tos );
893
906
}
894
907
}
908
+ if (test -> json_stream ) {
909
+ JSONStream_Output (test , "start" , test -> json_start );
910
+ }
895
911
}
896
912
913
+
897
914
/* This converts an IPv6 string address from IPv4-mapped format into regular
898
915
** old IPv4 format, which is easier on the eyes of network veterans.
899
916
**
@@ -1058,6 +1075,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1058
1075
{"one-off" , no_argument , NULL , '1' },
1059
1076
{"verbose" , no_argument , NULL , 'V' },
1060
1077
{"json" , no_argument , NULL , 'J' },
1078
+ {"json-stream" , no_argument , NULL , OPT_JSON_STREAM },
1061
1079
{"version" , no_argument , NULL , 'v' },
1062
1080
{"server" , no_argument , NULL , 's' },
1063
1081
{"client" , required_argument , NULL , 'c' },
@@ -1207,6 +1225,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1207
1225
case 'J' :
1208
1226
test -> json_output = 1 ;
1209
1227
break ;
1228
+ case OPT_JSON_STREAM :
1229
+ test -> json_output = 1 ;
1230
+ test -> json_stream = 1 ;
1231
+ break ;
1210
1232
case 'v' :
1211
1233
printf ("%s (cJSON %s)\n%s\n%s\n" , version , cJSON_Version (), get_system_info (),
1212
1234
get_optional_features ());
@@ -2736,6 +2758,29 @@ JSON_read(int fd)
2736
2758
return json ;
2737
2759
}
2738
2760
2761
+ /*************************************************************/
2762
+ /**
2763
+ * JSONStream_Output - outputs an obj as event without distrubing it
2764
+ */
2765
+
2766
+ static int
2767
+ JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj )
2768
+ {
2769
+ cJSON * event = cJSON_CreateObject ();
2770
+ if (!event )
2771
+ return -1 ;
2772
+ cJSON_AddStringToObject (event , "event" , event_name );
2773
+ cJSON_AddItemReferenceToObject (event , "data" , obj );
2774
+ char * str = cJSON_PrintUnformatted (event );
2775
+ if (str == NULL )
2776
+ return -1 ;
2777
+ fprintf (test -> outfile , "%s\n" , str );
2778
+ iflush (test );
2779
+ cJSON_free (str );
2780
+ cJSON_Delete (event );
2781
+ return 0 ;
2782
+ }
2783
+
2739
2784
/*************************************************************/
2740
2785
/**
2741
2786
* add_to_interval_list -- adds new interval to the interval_list
@@ -3400,6 +3445,7 @@ iperf_print_intermediate(struct iperf_test *test)
3400
3445
3401
3446
int lower_mode , upper_mode ;
3402
3447
int current_mode ;
3448
+ int discard_json ;
3403
3449
3404
3450
/*
3405
3451
* Due to timing oddities, there can be cases, especially on the
@@ -3445,11 +3491,20 @@ iperf_print_intermediate(struct iperf_test *test)
3445
3491
return ;
3446
3492
}
3447
3493
3494
+ /*
3495
+ * When we use streamed json, we don't actually need to keep the interval
3496
+ * results around unless we're the server and the client requested the server output.
3497
+ *
3498
+ * This avoids unneeded memory build up for long sessions.
3499
+ */
3500
+ discard_json = test -> json_stream == 1 && !(test -> role == 's' && test -> get_server_output );
3501
+
3448
3502
if (test -> json_output ) {
3449
3503
json_interval = cJSON_CreateObject ();
3450
3504
if (json_interval == NULL )
3451
3505
return ;
3452
- cJSON_AddItemToArray (test -> json_intervals , json_interval );
3506
+ if (!discard_json )
3507
+ cJSON_AddItemToArray (test -> json_intervals , json_interval );
3453
3508
json_interval_streams = cJSON_CreateArray ();
3454
3509
if (json_interval_streams == NULL )
3455
3510
return ;
@@ -3600,6 +3655,11 @@ iperf_print_intermediate(struct iperf_test *test)
3600
3655
}
3601
3656
}
3602
3657
}
3658
+
3659
+ if (test -> json_stream )
3660
+ JSONStream_Output (test , "interval" , json_interval );
3661
+ if (discard_json )
3662
+ cJSON_Delete (json_interval );
3603
3663
}
3604
3664
3605
3665
/**
@@ -4830,7 +4890,35 @@ iperf_json_finish(struct iperf_test *test)
4830
4890
cJSON_Delete (test -> json_top );
4831
4891
test -> json_top = NULL ;
4832
4892
}
4833
- test -> json_start = test -> json_connected = test -> json_intervals = test -> json_server_output = test -> json_end = NULL ;
4893
+ // Get ASCII rendering of JSON structure. Then make our
4894
+ // own copy of it and return the storage that cJSON allocated
4895
+ // on our behalf. We keep our own copy around.
4896
+ char * str = cJSON_Print (test -> json_top );
4897
+ if (str == NULL )
4898
+ return -1 ;
4899
+ test -> json_output_string = strdup (str );
4900
+ cJSON_free (str );
4901
+ if (test -> json_output_string == NULL )
4902
+ return -1 ;
4903
+ if (test -> json_stream ) {
4904
+ cJSON * error = cJSON_GetObjectItem (test -> json_top , "error" );
4905
+ if (error ) {
4906
+ JSONStream_Output (test , "error" , error );
4907
+ }
4908
+ if (test -> json_server_output ) {
4909
+ JSONStream_Output (test , "server_output_json" , test -> json_server_output );
4910
+ }
4911
+ if (test -> server_output_text ) {
4912
+ JSONStream_Output (test , "server_output_text" , cJSON_CreateString (test -> server_output_text ));
4913
+ }
4914
+ JSONStream_Output (test , "end" , test -> json_end );
4915
+ }
4916
+ else {
4917
+ fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4918
+ iflush (test );
4919
+ }
4920
+ cJSON_Delete (test -> json_top );
4921
+ test -> json_top = test -> json_start = test -> json_connected = test -> json_intervals = test -> json_server_output = test -> json_end = NULL ;
4834
4922
return 0 ;
4835
4923
}
4836
4924
0 commit comments