@@ -102,6 +102,7 @@ static int diskfile_recv(struct iperf_stream *sp);
102102static int JSON_write (int fd , cJSON * json );
103103static void print_interval_results (struct iperf_test * test , struct iperf_stream * sp , cJSON * json_interval_streams );
104104static cJSON * JSON_read (int fd );
105+ static int JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj );
105106
106107
107108/*************************** Print usage functions ****************************/
@@ -314,6 +315,12 @@ iperf_get_test_json_output_string(struct iperf_test *ipt)
314315 return ipt -> json_output_string ;
315316}
316317
318+ int
319+ iperf_get_test_json_stream (struct iperf_test * ipt )
320+ {
321+ return ipt -> json_stream ;
322+ }
323+
317324int
318325iperf_get_test_zerocopy (struct iperf_test * ipt )
319326{
@@ -622,6 +629,12 @@ iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
622629 ipt -> json_output = json_output ;
623630}
624631
632+ void
633+ iperf_set_test_json_stream (struct iperf_test * ipt , int json_stream )
634+ {
635+ ipt -> json_stream = json_stream ;
636+ }
637+
625638int
626639iperf_has_zerocopy ( void )
627640{
@@ -827,8 +840,12 @@ iperf_on_test_start(struct iperf_test *test)
827840 iperf_printf (test , test_start_time , test -> protocol -> name , test -> num_streams , test -> settings -> blksize , test -> omit , test -> duration , test -> settings -> tos );
828841 }
829842 }
843+ if (test -> json_stream ) {
844+ JSONStream_Output (test , "start" , test -> json_start );
845+ }
830846}
831847
848+
832849/* This converts an IPv6 string address from IPv4-mapped format into regular
833850** old IPv4 format, which is easier on the eyes of network veterans.
834851**
@@ -938,6 +955,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
938955 {"one-off" , no_argument , NULL , '1' },
939956 {"verbose" , no_argument , NULL , 'V' },
940957 {"json" , no_argument , NULL , 'J' },
958+ {"json-stream" , no_argument , NULL , OPT_JSON_STREAM },
941959 {"version" , no_argument , NULL , 'v' },
942960 {"server" , no_argument , NULL , 's' },
943961 {"client" , required_argument , NULL , 'c' },
@@ -1084,6 +1102,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
10841102 case 'J' :
10851103 test -> json_output = 1 ;
10861104 break ;
1105+ case OPT_JSON_STREAM :
1106+ test -> json_output = 1 ;
1107+ test -> json_stream = 1 ;
1108+ break ;
10871109 case 'v' :
10881110 printf ("%s (cJSON %s)\n%s\n%s\n" , version , cJSON_Version (), get_system_info (),
10891111 get_optional_features ());
@@ -2495,6 +2517,29 @@ JSON_read(int fd)
24952517 return json ;
24962518}
24972519
2520+ /*************************************************************/
2521+ /**
2522+ * JSONStream_Output - outputs an obj as event without distrubing it
2523+ */
2524+
2525+ static int
2526+ JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj )
2527+ {
2528+ cJSON * event = cJSON_CreateObject ();
2529+ if (!event )
2530+ return -1 ;
2531+ cJSON_AddStringToObject (event , "event" , event_name );
2532+ cJSON_AddItemReferenceToObject (event , "data" , obj );
2533+ char * str = cJSON_PrintUnformatted (event );
2534+ if (str == NULL )
2535+ return -1 ;
2536+ fprintf (test -> outfile , "%s\n" , str );
2537+ iflush (test );
2538+ cJSON_free (str );
2539+ cJSON_Delete (event );
2540+ return 0 ;
2541+ }
2542+
24982543/*************************************************************/
24992544/**
25002545 * add_to_interval_list -- adds new interval to the interval_list
@@ -3131,6 +3176,7 @@ iperf_print_intermediate(struct iperf_test *test)
31313176
31323177 int lower_mode , upper_mode ;
31333178 int current_mode ;
3179+ int discard_json ;
31343180
31353181 /*
31363182 * Due to timing oddities, there can be cases, especially on the
@@ -3176,11 +3222,20 @@ iperf_print_intermediate(struct iperf_test *test)
31763222 return ;
31773223 }
31783224
3225+ /*
3226+ * When we use streamed json, we don't actually need to keep the interval
3227+ * results around unless we're the server and the client requested the server output.
3228+ *
3229+ * This avoids unneeded memory build up for long sessions.
3230+ */
3231+ discard_json = test -> json_stream == 1 && !(test -> role == 's' && test -> get_server_output );
3232+
31793233 if (test -> json_output ) {
31803234 json_interval = cJSON_CreateObject ();
31813235 if (json_interval == NULL )
31823236 return ;
3183- cJSON_AddItemToArray (test -> json_intervals , json_interval );
3237+ if (!discard_json )
3238+ cJSON_AddItemToArray (test -> json_intervals , json_interval );
31843239 json_interval_streams = cJSON_CreateArray ();
31853240 if (json_interval_streams == NULL )
31863241 return ;
@@ -3313,6 +3368,11 @@ iperf_print_intermediate(struct iperf_test *test)
33133368 }
33143369 }
33153370 }
3371+
3372+ if (test -> json_stream )
3373+ JSONStream_Output (test , "interval" , json_interval );
3374+ if (discard_json )
3375+ cJSON_Delete (json_interval );
33163376}
33173377
33183378/**
@@ -4443,8 +4503,23 @@ iperf_json_finish(struct iperf_test *test)
44434503 cJSON_free (str );
44444504 if (test -> json_output_string == NULL )
44454505 return -1 ;
4446- fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4447- iflush (test );
4506+ if (test -> json_stream ) {
4507+ cJSON * error = cJSON_GetObjectItem (test -> json_top , "error" );
4508+ if (error ) {
4509+ JSONStream_Output (test , "error" , error );
4510+ }
4511+ if (test -> json_server_output ) {
4512+ JSONStream_Output (test , "server_output_json" , test -> json_server_output );
4513+ }
4514+ if (test -> server_output_text ) {
4515+ JSONStream_Output (test , "server_output_text" , cJSON_CreateString (test -> server_output_text ));
4516+ }
4517+ JSONStream_Output (test , "end" , test -> json_end );
4518+ }
4519+ else {
4520+ fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4521+ iflush (test );
4522+ }
44484523 cJSON_Delete (test -> json_top );
44494524 test -> json_top = test -> json_start = test -> json_connected = test -> json_intervals = test -> json_server_output = test -> json_end = NULL ;
44504525 return 0 ;
0 commit comments