@@ -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 ****************************/
@@ -320,6 +321,12 @@ iperf_get_test_json_output(struct iperf_test *ipt)
320
321
return ipt -> json_output ;
321
322
}
322
323
324
+ int
325
+ iperf_get_test_json_stream (struct iperf_test * ipt )
326
+ {
327
+ return ipt -> json_stream ;
328
+ }
329
+
323
330
char *
324
331
iperf_get_test_json_output_string (struct iperf_test * ipt )
325
332
{
@@ -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,6 +905,9 @@ 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
897
913
/* This converts an IPv6 string address from IPv4-mapped format into regular
@@ -1058,6 +1074,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1058
1074
{"one-off" , no_argument , NULL , '1' },
1059
1075
{"verbose" , no_argument , NULL , 'V' },
1060
1076
{"json" , no_argument , NULL , 'J' },
1077
+ {"json-stream" , no_argument , NULL , OPT_JSON_STREAM },
1061
1078
{"version" , no_argument , NULL , 'v' },
1062
1079
{"server" , no_argument , NULL , 's' },
1063
1080
{"client" , required_argument , NULL , 'c' },
@@ -1207,6 +1224,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1207
1224
case 'J' :
1208
1225
test -> json_output = 1 ;
1209
1226
break ;
1227
+ case OPT_JSON_STREAM :
1228
+ test -> json_output = 1 ;
1229
+ test -> json_stream = 1 ;
1230
+ break ;
1210
1231
case 'v' :
1211
1232
printf ("%s (cJSON %s)\n%s\n%s\n" , version , cJSON_Version (), get_system_info (),
1212
1233
get_optional_features ());
@@ -2736,6 +2757,29 @@ JSON_read(int fd)
2736
2757
return json ;
2737
2758
}
2738
2759
2760
+ /*************************************************************/
2761
+ /**
2762
+ * JSONStream_Output - outputs an obj as event without distrubing it
2763
+ */
2764
+
2765
+ static int
2766
+ JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj )
2767
+ {
2768
+ cJSON * event = cJSON_CreateObject ();
2769
+ if (!event )
2770
+ return -1 ;
2771
+ cJSON_AddStringToObject (event , "event" , event_name );
2772
+ cJSON_AddItemReferenceToObject (event , "data" , obj );
2773
+ char * str = cJSON_PrintUnformatted (event );
2774
+ if (str == NULL )
2775
+ return -1 ;
2776
+ fprintf (test -> outfile , "%s\n" , str );
2777
+ iflush (test );
2778
+ cJSON_free (str );
2779
+ cJSON_Delete (event );
2780
+ return 0 ;
2781
+ }
2782
+
2739
2783
/*************************************************************/
2740
2784
/**
2741
2785
* add_to_interval_list -- adds new interval to the interval_list
@@ -3400,6 +3444,7 @@ iperf_print_intermediate(struct iperf_test *test)
3400
3444
3401
3445
int lower_mode , upper_mode ;
3402
3446
int current_mode ;
3447
+ int discard_json ;
3403
3448
3404
3449
/*
3405
3450
* Due to timing oddities, there can be cases, especially on the
@@ -3445,12 +3490,21 @@ iperf_print_intermediate(struct iperf_test *test)
3445
3490
return ;
3446
3491
}
3447
3492
3493
+ /*
3494
+ * When we use streamed json, we don't actually need to keep the interval
3495
+ * results around unless we're the server and the client requested the server output.
3496
+ *
3497
+ * This avoids unneeded memory build up for long sessions.
3498
+ */
3499
+ discard_json = test -> json_stream == 1 && !(test -> role == 's' && test -> get_server_output );
3500
+
3448
3501
if (test -> json_output ) {
3449
3502
json_interval = cJSON_CreateObject ();
3450
3503
if (json_interval == NULL )
3451
3504
return ;
3452
- cJSON_AddItemToArray (test -> json_intervals , json_interval );
3453
- json_interval_streams = cJSON_CreateArray ();
3505
+ if (!discard_json )
3506
+ cJSON_AddItemToArray (test -> json_intervals , json_interval );
3507
+ json_interval_streams = cJSON_CreateArray ();
3454
3508
if (json_interval_streams == NULL )
3455
3509
return ;
3456
3510
cJSON_AddItemToObject (json_interval , "streams" , json_interval_streams );
@@ -3600,6 +3654,10 @@ iperf_print_intermediate(struct iperf_test *test)
3600
3654
}
3601
3655
}
3602
3656
}
3657
+ if (test -> json_stream )
3658
+ JSONStream_Output (test , "interval" , json_interval );
3659
+ if (discard_json )
3660
+ cJSON_Delete (json_interval );
3603
3661
}
3604
3662
3605
3663
/**
@@ -4811,14 +4869,29 @@ iperf_json_finish(struct iperf_test *test)
4811
4869
return -1 ;
4812
4870
}
4813
4871
4814
- if (pthread_mutex_lock (& (test -> print_mutex )) != 0 ) {
4815
- perror ("iperf_json_finish: pthread_mutex_lock" );
4816
- }
4817
- fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4818
- if (pthread_mutex_unlock (& (test -> print_mutex )) != 0 ) {
4819
- perror ("iperf_json_finish: pthread_mutex_unlock" );
4872
+ if (test -> json_stream ) {
4873
+ cJSON * error = cJSON_GetObjectItem (test -> json_top , "error" );
4874
+ if (error ) {
4875
+ JSONStream_Output (test , "error" , error );
4876
+ }
4877
+ if (test -> json_server_output ) {
4878
+ JSONStream_Output (test , "server_output_json" , test -> json_server_output );
4879
+ }
4880
+ if (test -> server_output_text ) {
4881
+ JSONStream_Output (test , "server_output_text" , cJSON_CreateString (test -> server_output_text ));
4882
+ }
4883
+ JSONStream_Output (test , "end" , test -> json_end );
4820
4884
}
4821
- iflush (test );
4885
+ else {
4886
+ if (pthread_mutex_lock (& (test -> print_mutex )) != 0 ) {
4887
+ perror ("iperf_json_finish: pthread_mutex_lock" );
4888
+ }
4889
+ fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4890
+ if (pthread_mutex_unlock (& (test -> print_mutex )) != 0 ) {
4891
+ perror ("iperf_json_finish: pthread_mutex_unlock" );
4892
+ }
4893
+ iflush (test );
4894
+ }
4822
4895
cJSON_Delete (test -> json_top );
4823
4896
test -> json_top = NULL ;
4824
4897
}
0 commit comments