@@ -103,6 +103,7 @@ static int diskfile_recv(struct iperf_stream *sp);
103
103
static int JSON_write (int fd , cJSON * json );
104
104
static void print_interval_results (struct iperf_test * test , struct iperf_stream * sp , cJSON * json_interval_streams );
105
105
static cJSON * JSON_read (int fd );
106
+ static int JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj );
106
107
107
108
108
109
/*************************** Print usage functions ****************************/
@@ -315,6 +316,12 @@ iperf_get_test_json_output_string(struct iperf_test *ipt)
315
316
return ipt -> json_output_string ;
316
317
}
317
318
319
+ int
320
+ iperf_get_test_json_stream (struct iperf_test * ipt )
321
+ {
322
+ return ipt -> json_stream ;
323
+ }
324
+
318
325
int
319
326
iperf_get_test_zerocopy (struct iperf_test * ipt )
320
327
{
@@ -599,6 +606,12 @@ iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
599
606
ipt -> json_output = json_output ;
600
607
}
601
608
609
+ void
610
+ iperf_set_test_json_stream (struct iperf_test * ipt , int json_stream )
611
+ {
612
+ ipt -> json_stream = json_stream ;
613
+ }
614
+
602
615
int
603
616
iperf_has_zerocopy ( void )
604
617
{
@@ -779,8 +792,12 @@ iperf_on_test_start(struct iperf_test *test)
779
792
iperf_printf (test , test_start_time , test -> protocol -> name , test -> num_streams , test -> settings -> blksize , test -> omit , test -> duration , test -> settings -> tos );
780
793
}
781
794
}
795
+ if (test -> json_stream ) {
796
+ JSONStream_Output (test , "start" , test -> json_start );
797
+ }
782
798
}
783
799
800
+
784
801
/* This converts an IPv6 string address from IPv4-mapped format into regular
785
802
** old IPv4 format, which is easier on the eyes of network veterans.
786
803
**
@@ -890,6 +907,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
890
907
{"one-off" , no_argument , NULL , '1' },
891
908
{"verbose" , no_argument , NULL , 'V' },
892
909
{"json" , no_argument , NULL , 'J' },
910
+ {"json-stream" , no_argument , NULL , OPT_JSON_STREAM },
893
911
{"version" , no_argument , NULL , 'v' },
894
912
{"server" , no_argument , NULL , 's' },
895
913
{"client" , required_argument , NULL , 'c' },
@@ -1030,6 +1048,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1030
1048
case 'J' :
1031
1049
test -> json_output = 1 ;
1032
1050
break ;
1051
+ case OPT_JSON_STREAM :
1052
+ test -> json_output = 1 ;
1053
+ test -> json_stream = 1 ;
1054
+ break ;
1033
1055
case 'v' :
1034
1056
printf ("%s (cJSON %s)\n%s\n%s\n" , version , cJSON_Version (), get_system_info (),
1035
1057
get_optional_features ());
@@ -2404,6 +2426,29 @@ JSON_read(int fd)
2404
2426
return json ;
2405
2427
}
2406
2428
2429
+ /*************************************************************/
2430
+ /**
2431
+ * JSONStream_Output - outputs an obj as event without distrubing it
2432
+ */
2433
+
2434
+ static int
2435
+ JSONStream_Output (struct iperf_test * test , const char * event_name , cJSON * obj )
2436
+ {
2437
+ cJSON * event = cJSON_CreateObject ();
2438
+ if (!event )
2439
+ return -1 ;
2440
+ cJSON_AddStringToObject (event , "event" , event_name );
2441
+ cJSON_AddItemReferenceToObject (event , "data" , obj );
2442
+ char * str = cJSON_PrintUnformatted (event );
2443
+ if (str == NULL )
2444
+ return -1 ;
2445
+ fprintf (test -> outfile , "%s\n" , str );
2446
+ iflush (test );
2447
+ cJSON_free (str );
2448
+ cJSON_Delete (event );
2449
+ return 0 ;
2450
+ }
2451
+
2407
2452
/*************************************************************/
2408
2453
/**
2409
2454
* add_to_interval_list -- adds new interval to the interval_list
@@ -3031,6 +3076,7 @@ iperf_print_intermediate(struct iperf_test *test)
3031
3076
3032
3077
int lower_mode , upper_mode ;
3033
3078
int current_mode ;
3079
+ int discard_json ;
3034
3080
3035
3081
/*
3036
3082
* Due to timing oddities, there can be cases, especially on the
@@ -3076,11 +3122,20 @@ iperf_print_intermediate(struct iperf_test *test)
3076
3122
return ;
3077
3123
}
3078
3124
3125
+ /*
3126
+ * When we use streamed json, we don't actually need to keep the interval
3127
+ * results around unless we're the server and the client requested the server output.
3128
+ *
3129
+ * This avoids unneeded memory build up for long sessions.
3130
+ */
3131
+ discard_json = test -> json_stream == 1 && !(test -> role == 's' && test -> get_server_output );
3132
+
3079
3133
if (test -> json_output ) {
3080
3134
json_interval = cJSON_CreateObject ();
3081
3135
if (json_interval == NULL )
3082
3136
return ;
3083
- cJSON_AddItemToArray (test -> json_intervals , json_interval );
3137
+ if (!discard_json )
3138
+ cJSON_AddItemToArray (test -> json_intervals , json_interval );
3084
3139
json_interval_streams = cJSON_CreateArray ();
3085
3140
if (json_interval_streams == NULL )
3086
3141
return ;
@@ -3213,6 +3268,11 @@ iperf_print_intermediate(struct iperf_test *test)
3213
3268
}
3214
3269
}
3215
3270
}
3271
+
3272
+ if (test -> json_stream )
3273
+ JSONStream_Output (test , "interval" , json_interval );
3274
+ if (discard_json )
3275
+ cJSON_Delete (json_interval );
3216
3276
}
3217
3277
3218
3278
/**
@@ -4282,8 +4342,23 @@ iperf_json_finish(struct iperf_test *test)
4282
4342
cJSON_free (str );
4283
4343
if (test -> json_output_string == NULL )
4284
4344
return -1 ;
4285
- fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4286
- iflush (test );
4345
+ if (test -> json_stream ) {
4346
+ cJSON * error = cJSON_GetObjectItem (test -> json_top , "error" );
4347
+ if (error ) {
4348
+ JSONStream_Output (test , "error" , error );
4349
+ }
4350
+ if (test -> json_server_output ) {
4351
+ JSONStream_Output (test , "server_output_json" , test -> json_server_output );
4352
+ }
4353
+ if (test -> server_output_text ) {
4354
+ JSONStream_Output (test , "server_output_text" , cJSON_CreateString (test -> server_output_text ));
4355
+ }
4356
+ JSONStream_Output (test , "end" , test -> json_end );
4357
+ }
4358
+ else {
4359
+ fprintf (test -> outfile , "%s\n" , test -> json_output_string );
4360
+ iflush (test );
4361
+ }
4287
4362
cJSON_Delete (test -> json_top );
4288
4363
test -> json_top = test -> json_start = test -> json_connected = test -> json_intervals = test -> json_server_output = test -> json_end = NULL ;
4289
4364
return 0 ;
0 commit comments