Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement per issue 1311 - use same socket for both Bidir directions #1321

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/iperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
21 changes: 19 additions & 2 deletions src/iperf_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/iperf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);

Expand Down
32 changes: 23 additions & 9 deletions src/iperf_client_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -63,19 +63,30 @@ 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) {

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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion src/iperf_locale.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" --cport <port> 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"

Expand Down
36 changes: 28 additions & 8 deletions src/iperf_server_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down