From 28699c5ecb0d0268bc511d93042b0318059bdce4 Mon Sep 17 00:00:00 2001 From: David Bar-On Date: Tue, 12 Apr 2022 09:51:07 +0300 Subject: [PATCH] Enhancement per issue 1311 - use same socket for both Bidir directions --- src/iperf.h | 1 + src/iperf_api.c | 21 +++++++++++++++++++-- src/iperf_api.h | 2 +- src/iperf_client_api.c | 32 +++++++++++++++++++++++--------- src/iperf_locale.c | 3 ++- src/iperf_server_api.c | 36 ++++++++++++++++++++++++++++-------- 6 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/iperf.h b/src/iperf.h index 3304b5e9b..8cf804c75 100644 --- a/src/iperf.h +++ b/src/iperf.h @@ -261,6 +261,7 @@ struct iperf_test { char role; /* 'c' lient or 's' erver */ enum iperf_mode mode; + int same_socket; /* --bidir option value - used if mode == BIDIRECTIONAL */ int sender_has_retransmits; int other_side_has_retransmits; /* used if mode == BIDIRECTIONAL */ struct protocol *protocol; diff --git a/src/iperf_api.c b/src/iperf_api.c index 7fa297cf5..694f54c11 100644 --- a/src/iperf_api.c +++ b/src/iperf_api.c @@ -748,6 +748,12 @@ iperf_set_test_bidirectional(struct iperf_test* ipt, int bidirectional) iperf_set_test_reverse(ipt, ipt->reverse); } +void +iperf_set_test_samesocket(struct iperf_test* ipt, int same_socket) +{ + ipt->same_socket = same_socket; +} + void iperf_set_test_no_delay(struct iperf_test* ipt, int no_delay) { @@ -1021,7 +1027,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) {"length", required_argument, NULL, 'l'}, {"parallel", required_argument, NULL, 'P'}, {"reverse", no_argument, NULL, 'R'}, - {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL}, + {"bidir", optional_argument, NULL, OPT_BIDIRECTIONAL}, {"window", required_argument, NULL, 'w'}, {"bind", required_argument, NULL, 'B'}, #if defined(HAVE_SO_BINDTODEVICE) @@ -1282,6 +1288,10 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) return -1; } iperf_set_test_bidirectional(test, 1); + if (optarg) { + if (atoi(optarg) == 1) + iperf_set_test_samesocket(test, 1); + } client_flag = 1; break; case 'w': @@ -2114,7 +2124,9 @@ send_parameters(struct iperf_test *test) if (test->reverse) cJSON_AddTrueToObject(j, "reverse"); if (test->bidirectional) - cJSON_AddTrueToObject(j, "bidirectional"); + cJSON_AddTrueToObject(j, "bidirectional"); + if (test->same_socket) + cJSON_AddTrueToObject(j, "same_socket"); if (test->settings->socket_bufsize) cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize); if (test->settings->blksize) @@ -2229,6 +2241,8 @@ get_parameters(struct iperf_test *test) iperf_set_test_reverse(test, 1); if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL) iperf_set_test_bidirectional(test, 1); + if ((j_p = cJSON_GetObjectItem(j, "same_socket")) != NULL) + iperf_set_test_samesocket(test, 1); if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL) test->settings->socket_bufsize = j_p->valueint; if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL) @@ -2760,6 +2774,8 @@ iperf_defaults(struct iperf_test *testp) testp->stats_interval = testp->reporter_interval = 1; testp->num_streams = 1; + testp->same_socket = 0; + testp->settings->domain = AF_UNSPEC; testp->settings->unit_format = 'a'; testp->settings->socket_bufsize = 0; /* use autotuning */ @@ -3022,6 +3038,7 @@ iperf_reset_test(struct iperf_test *test) test->remote_congestion_used = NULL; test->role = 's'; test->mode = RECEIVER; + test->same_socket = 0; test->sender_has_retransmits = 0; set_protocol(test, Ptcp); test->omit = OMIT; diff --git a/src/iperf_api.h b/src/iperf_api.h index fc128984b..8b467d874 100644 --- a/src/iperf_api.h +++ b/src/iperf_api.h @@ -322,7 +322,7 @@ extern jmp_buf env; /* Client routines. */ int iperf_run_client(struct iperf_test *); int iperf_connect(struct iperf_test *); -int iperf_create_streams(struct iperf_test *, int sender); +int iperf_create_streams(struct iperf_test *, int sender, int use_same_socket); int iperf_handle_message_client(struct iperf_test *); int iperf_client_end(struct iperf_test *); diff --git a/src/iperf_client_api.c b/src/iperf_client_api.c index 25d99ac23..7e523af81 100644 --- a/src/iperf_client_api.c +++ b/src/iperf_client_api.c @@ -52,7 +52,7 @@ #endif /* HAVE_TCP_CONGESTION */ int -iperf_create_streams(struct iperf_test *test, int sender) +iperf_create_streams(struct iperf_test *test, int sender, int use_same_socket) { if (NULL == test) { @@ -63,7 +63,7 @@ iperf_create_streams(struct iperf_test *test, int sender) #if defined(HAVE_TCP_CONGESTION) int saved_errno; #endif /* HAVE_TCP_CONGESTION */ - struct iperf_stream *sp; + struct iperf_stream *sp, *sp_same; int orig_bind_port = test->bind_port; for (i = 0; i < test->num_streams; ++i) { @@ -71,11 +71,22 @@ iperf_create_streams(struct iperf_test *test, int sender) test->bind_port = orig_bind_port; if (orig_bind_port) { test->bind_port += i; - // If Bidir make sure send and receive ports are different - if (!sender && test->mode == BIDIRECTIONAL) + // If Bidir using different sockets, make sure send and receive ports are different + if (!sender && test->mode == BIDIRECTIONAL && !test->same_socket) test->bind_port += test->num_streams; } - s = test->protocol->connect(test); + + if (!use_same_socket) + s = test->protocol->connect(test); + else { + // When using same socket for both directions - reuse already created sockets + if (i == 0) + sp_same = SLIST_FIRST(&test->streams); + else + sp_same = SLIST_NEXT(sp_same, streams); + s = sp_same->socket; + } + test->bind_port = orig_bind_port; if (s < 0) return -1; @@ -115,7 +126,10 @@ iperf_create_streams(struct iperf_test *test, int sender) } #endif /* HAVE_TCP_CONGESTION */ - if (sender) + if (test->same_socket) { + FD_SET(s, &test->write_set); + FD_SET(s, &test->read_set); + } else if (sender) FD_SET(s, &test->write_set); else FD_SET(s, &test->read_set); @@ -288,12 +302,12 @@ iperf_handle_message_client(struct iperf_test *test) case CREATE_STREAMS: if (test->mode == BIDIRECTIONAL) { - if (iperf_create_streams(test, 1) < 0) + if (iperf_create_streams(test, 1, 0) < 0) return -1; - if (iperf_create_streams(test, 0) < 0) + if (iperf_create_streams(test, 0, test->same_socket) < 0) return -1; } - else if (iperf_create_streams(test, test->mode) < 0) + else if (iperf_create_streams(test, test->mode, 0) < 0) return -1; break; case TEST_START: diff --git a/src/iperf_locale.c b/src/iperf_locale.c index 58a6d77f8..8bc10035b 100644 --- a/src/iperf_locale.c +++ b/src/iperf_locale.c @@ -167,8 +167,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n" " --cport bind to a specific client port (TCP and UDP, default: ephemeral port)\n" " -P, --parallel # number of parallel client streams to run\n" " -R, --reverse run in reverse mode (server sends, client receives)\n" - " --bidir run in bidirectional mode.\n" + " --bidir[=1] run in bidirectional mode.\n" " Client and server send and receive data.\n" + " (Optional option: 1 - use same socket for both directions.\n" " -w, --window #[KMG] set send/receive socket buffer sizes\n" " (indirectly sets TCP window size)\n" diff --git a/src/iperf_server_api.c b/src/iperf_server_api.c index f74cf519d..6930a2f21 100644 --- a/src/iperf_server_api.c +++ b/src/iperf_server_api.c @@ -424,7 +424,7 @@ iperf_run_server(struct iperf_test *test) int saved_errno; #endif /* HAVE_TCP_CONGESTION */ fd_set read_set, write_set; - struct iperf_stream *sp; + struct iperf_stream *sp1, *sp2; struct iperf_time now; struct iperf_time last_receive_time; struct iperf_time diff_time; @@ -652,22 +652,39 @@ iperf_run_server(struct iperf_test *test) if (rec_streams_accepted != streams_to_rec) { flag = 0; ++rec_streams_accepted; + if (test->same_socket) + ++send_streams_accepted; } else if (send_streams_accepted != streams_to_send) { flag = 1; ++send_streams_accepted; } if (flag != -1) { - sp = iperf_new_stream(test, s, flag); - if (!sp) { + sp1 = NULL; + sp2 = NULL; + + sp1 = iperf_new_stream(test, s, flag); + if (!sp1) { cleanup_server(test); return -1; } + if (test->same_socket) { + sp2 = iperf_new_stream(test, s, 1 - flag); + if (!sp2) { + cleanup_server(test); + return -1; + } + } - if (sp->sender) + if (test->same_socket) { FD_SET(s, &test->write_set); - else FD_SET(s, &test->read_set); + } else { + if (sp1->sender) + FD_SET(s, &test->write_set); + else + FD_SET(s, &test->read_set); + } if (s > test->max_fd) test->max_fd = s; @@ -678,12 +695,15 @@ iperf_run_server(struct iperf_test *test) * maintain interactivity with the control channel. */ if (test->protocol->id != Pudp || - !sp->sender) { + test->same_socket || !sp1->sender) { setnonblocking(s, 1); } - if (test->on_new_stream) - test->on_new_stream(sp); + if (test->on_new_stream) { + test->on_new_stream(sp1); + if (sp2 != NULL) + test->on_new_stream(sp2); + } flag = -1; }