version 1.1.1.2, 2021/03/17 00:36:46
|
version 1.1.1.3, 2023/09/27 11:14:54
|
Line 1
|
Line 1
|
/* |
/* |
* iperf, Copyright (c) 2014-2020 The Regents of the University of | * iperf, Copyright (c) 2014-2022 The Regents of the University of |
* California, through Lawrence Berkeley National Laboratory (subject |
* California, through Lawrence Berkeley National Laboratory (subject |
* to receipt of any required approvals from the U.S. Dept. of |
* to receipt of any required approvals from the U.S. Dept. of |
* Energy). All rights reserved. |
* Energy). All rights reserved. |
Line 70 int
|
Line 70 int
|
iperf_server_listen(struct iperf_test *test) |
iperf_server_listen(struct iperf_test *test) |
{ |
{ |
retry: |
retry: |
if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { | if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { |
if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { |
if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { |
/* If we get "Address family not supported by protocol", that |
/* If we get "Address family not supported by protocol", that |
** probably means we were compiled with IPv6 but the running |
** probably means we were compiled with IPv6 but the running |
Line 87 iperf_server_listen(struct iperf_test *test)
|
Line 87 iperf_server_listen(struct iperf_test *test)
|
} |
} |
|
|
if (!test->json_output) { |
if (!test->json_output) { |
iperf_printf(test, "-----------------------------------------------------------\n"); | if (test->server_last_run_rc != 2) |
iperf_printf(test, "Server listening on %d\n", test->server_port); | test->server_test_number +=1; |
iperf_printf(test, "-----------------------------------------------------------\n"); | if (test->debug || test->server_last_run_rc != 2) { |
if (test->forceflush) | iperf_printf(test, "-----------------------------------------------------------\n"); |
iflush(test); | iperf_printf(test, "Server listening on %d (test #%d)\n", test->server_port, test->server_test_number); |
| iperf_printf(test, "-----------------------------------------------------------\n"); |
| if (test->forceflush) |
| iflush(test); |
| } |
} |
} |
|
|
FD_ZERO(&test->read_set); |
FD_ZERO(&test->read_set); |
Line 119 iperf_accept(struct iperf_test *test)
|
Line 123 iperf_accept(struct iperf_test *test)
|
if (test->ctrl_sck == -1) { |
if (test->ctrl_sck == -1) { |
/* Server free, accept new client */ |
/* Server free, accept new client */ |
test->ctrl_sck = s; |
test->ctrl_sck = s; |
if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { | // set TCP_NODELAY for lower latency on control messages |
| int flag = 1; |
| if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) { |
| i_errno = IESETNODELAY; |
| return -1; |
| } |
| |
| #if defined(HAVE_TCP_USER_TIMEOUT) |
| int opt; |
| if ((opt = test->settings->snd_timeout)) { |
| if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) { |
| i_errno = IESETUSERTIMEOUT; |
| return -1; |
| } |
| } |
| #endif /* HAVE_TCP_USER_TIMEOUT */ |
| |
| if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) != COOKIE_SIZE) { |
| /* |
| * Note this error covers both the case of a system error |
| * or the inability to read the correct amount of data |
| * (i.e. timed out). |
| */ |
i_errno = IERECVCOOKIE; |
i_errno = IERECVCOOKIE; |
return -1; |
return -1; |
} |
} |
Line 130 iperf_accept(struct iperf_test *test)
|
Line 156 iperf_accept(struct iperf_test *test)
|
return -1; |
return -1; |
if (iperf_exchange_parameters(test) < 0) |
if (iperf_exchange_parameters(test) < 0) |
return -1; |
return -1; |
if (test->server_affinity != -1) | if (test->server_affinity != -1) |
if (iperf_setaffinity(test, test->server_affinity) != 0) |
if (iperf_setaffinity(test, test->server_affinity) != 0) |
return -1; |
return -1; |
if (test->on_connect) |
if (test->on_connect) |
test->on_connect(test); |
test->on_connect(test); |
} else { |
} else { |
/* |
/* |
* Don't try to read from the socket. It could block an ongoing test. | * Don't try to read from the socket. It could block an ongoing test. |
* Just send ACCESS_DENIED. |
* Just send ACCESS_DENIED. |
|
* Also, if sending failed, don't return an error, as the request is not related |
|
* to the ongoing test, and returning an error will terminate the test. |
*/ |
*/ |
if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { |
if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { |
i_errno = IESENDMESSAGE; | if (test->debug) |
return -1; | printf("failed to send ACCESS_DENIED to an unsolicited connection request during active test\n"); |
| } else { |
| if (test->debug) |
| printf("successfully sent ACCESS_DENIED to an unsolicited connection request during active test\n"); |
} |
} |
close(s); |
close(s); |
} |
} |
Line 241 server_timer_proc(TimerClientData client_data, struct
|
Line 272 server_timer_proc(TimerClientData client_data, struct
|
iperf_free_stream(sp); |
iperf_free_stream(sp); |
} |
} |
close(test->ctrl_sck); |
close(test->ctrl_sck); |
|
test->ctrl_sck = -1; |
} |
} |
|
|
static void |
static void |
Line 309 create_server_timers(struct iperf_test * test)
|
Line 341 create_server_timers(struct iperf_test * test)
|
|
|
static void |
static void |
server_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP) |
server_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP) |
{ | { |
struct iperf_test *test = client_data.p; |
struct iperf_test *test = client_data.p; |
|
|
test->omit_timer = NULL; |
test->omit_timer = NULL; |
Line 329 static int
|
Line 361 static int
|
create_server_omit_timer(struct iperf_test * test) |
create_server_omit_timer(struct iperf_test * test) |
{ |
{ |
struct iperf_time now; |
struct iperf_time now; |
TimerClientData cd; | TimerClientData cd; |
|
|
if (test->omit == 0) { |
if (test->omit == 0) { |
test->omit_timer = NULL; |
test->omit_timer = NULL; |
Line 337 create_server_omit_timer(struct iperf_test * test)
|
Line 369 create_server_omit_timer(struct iperf_test * test)
|
} else { |
} else { |
if (iperf_time_now(&now) < 0) { |
if (iperf_time_now(&now) < 0) { |
i_errno = IEINITTEST; |
i_errno = IEINITTEST; |
return -1; | return -1; |
} |
} |
test->omitting = 1; |
test->omitting = 1; |
cd.p = test; |
cd.p = test; |
test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); | test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); |
if (test->omit_timer == NULL) { |
if (test->omit_timer == NULL) { |
i_errno = IEINITTEST; |
i_errno = IEINITTEST; |
return -1; |
return -1; |
Line 358 cleanup_server(struct iperf_test *test)
|
Line 390 cleanup_server(struct iperf_test *test)
|
|
|
/* Close open streams */ |
/* Close open streams */ |
SLIST_FOREACH(sp, &test->streams, streams) { |
SLIST_FOREACH(sp, &test->streams, streams) { |
FD_CLR(sp->socket, &test->read_set); | if (sp->socket > -1) { |
FD_CLR(sp->socket, &test->write_set); | FD_CLR(sp->socket, &test->read_set); |
close(sp->socket); | FD_CLR(sp->socket, &test->write_set); |
| close(sp->socket); |
| sp->socket = -1; |
| } |
} |
} |
|
|
/* Close open test sockets */ |
/* Close open test sockets */ |
if (test->ctrl_sck) { | if (test->ctrl_sck > -1) { |
close(test->ctrl_sck); |
close(test->ctrl_sck); |
|
test->ctrl_sck = -1; |
} |
} |
if (test->listener) { | if (test->listener > -1) { |
close(test->listener); |
close(test->listener); |
|
test->listener = -1; |
} |
} |
|
if (test->prot_listener > -1) { // May remain open if create socket failed |
|
close(test->prot_listener); |
|
test->prot_listener = -1; |
|
} |
|
|
/* Cancel any remaining timers. */ |
/* Cancel any remaining timers. */ |
if (test->stats_timer != NULL) { |
if (test->stats_timer != NULL) { |
Line 407 iperf_run_server(struct iperf_test *test)
|
Line 448 iperf_run_server(struct iperf_test *test)
|
fd_set read_set, write_set; |
fd_set read_set, write_set; |
struct iperf_stream *sp; |
struct iperf_stream *sp; |
struct iperf_time now; |
struct iperf_time now; |
|
struct iperf_time last_receive_time; |
|
struct iperf_time diff_time; |
struct timeval* timeout; |
struct timeval* timeout; |
|
struct timeval used_timeout; |
int flag; |
int flag; |
|
int64_t t_usecs; |
|
int64_t timeout_us; |
|
int64_t rcv_timeout_us; |
|
|
if (test->logfile) |
if (test->logfile) |
if (iperf_open_logfile(test) < 0) |
if (iperf_open_logfile(test) < 0) |
return -1; | return -2; |
|
|
if (test->affinity != -1) | if (test->affinity != -1) |
if (iperf_setaffinity(test, test->affinity) != 0) | if (iperf_setaffinity(test, test->affinity) != 0) { |
| cleanup_server(test); |
return -2; |
return -2; |
|
} |
|
|
if (test->json_output) |
if (test->json_output) |
if (iperf_json_start(test) < 0) | if (iperf_json_start(test) < 0) { |
| cleanup_server(test); |
return -2; |
return -2; |
|
} |
|
|
if (test->json_output) { |
if (test->json_output) { |
cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); |
cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); |
Line 434 iperf_run_server(struct iperf_test *test)
|
Line 485 iperf_run_server(struct iperf_test *test)
|
|
|
// Open socket and listen |
// Open socket and listen |
if (iperf_server_listen(test) < 0) { |
if (iperf_server_listen(test) < 0) { |
|
cleanup_server(test); |
return -2; |
return -2; |
} |
} |
|
|
// Begin calculating CPU utilization | iperf_time_now(&last_receive_time); // Initialize last time something was received |
cpu_util(NULL); | |
|
|
test->state = IPERF_START; |
test->state = IPERF_START; |
send_streams_accepted = 0; |
send_streams_accepted = 0; |
rec_streams_accepted = 0; |
rec_streams_accepted = 0; |
|
rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs; |
|
|
while (test->state != IPERF_DONE) { |
while (test->state != IPERF_DONE) { |
|
|
Line 450 iperf_run_server(struct iperf_test *test)
|
Line 502 iperf_run_server(struct iperf_test *test)
|
if (test->bitrate_limit_exceeded) { |
if (test->bitrate_limit_exceeded) { |
cleanup_server(test); |
cleanup_server(test); |
i_errno = IETOTALRATE; |
i_errno = IETOTALRATE; |
return -1; | return -1; |
} |
} |
|
|
memcpy(&read_set, &test->read_set, sizeof(fd_set)); |
memcpy(&read_set, &test->read_set, sizeof(fd_set)); |
Line 458 iperf_run_server(struct iperf_test *test)
|
Line 510 iperf_run_server(struct iperf_test *test)
|
|
|
iperf_time_now(&now); |
iperf_time_now(&now); |
timeout = tmr_timeout(&now); |
timeout = tmr_timeout(&now); |
result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); |
|
|
|
|
// Ensure select() will timeout to allow handling error cases that require server restart |
|
if (test->state == IPERF_START) { // In idle mode server may need to restart |
|
if (timeout == NULL && test->settings->idle_timeout > 0) { |
|
used_timeout.tv_sec = test->settings->idle_timeout; |
|
used_timeout.tv_usec = 0; |
|
timeout = &used_timeout; |
|
} |
|
} else if (test->mode != SENDER) { // In non-reverse active mode server ensures data is received |
|
timeout_us = -1; |
|
if (timeout != NULL) { |
|
used_timeout.tv_sec = timeout->tv_sec; |
|
used_timeout.tv_usec = timeout->tv_usec; |
|
timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec; |
|
} |
|
if (timeout_us < 0 || timeout_us > rcv_timeout_us) { |
|
used_timeout.tv_sec = test->settings->rcv_timeout.secs; |
|
used_timeout.tv_usec = test->settings->rcv_timeout.usecs; |
|
} |
|
timeout = &used_timeout; |
|
} |
|
|
|
result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); |
if (result < 0 && errno != EINTR) { |
if (result < 0 && errno != EINTR) { |
cleanup_server(test); | cleanup_server(test); |
i_errno = IESELECT; |
i_errno = IESELECT; |
return -1; |
return -1; |
|
} else if (result == 0) { |
|
// If nothing was received during the specified time (per state) |
|
// then probably something got stack either at the client, server or network, |
|
// and Test should be forced to end. |
|
iperf_time_now(&now); |
|
t_usecs = 0; |
|
if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) { |
|
t_usecs = iperf_time_in_usecs(&diff_time); |
|
if (test->state == IPERF_START) { |
|
if (test->settings->idle_timeout > 0 && t_usecs >= test->settings->idle_timeout * SEC_TO_US) { |
|
test->server_forced_idle_restarts_count += 1; |
|
if (test->debug) |
|
printf("Server restart (#%d) in idle state as no connection request was received for %d sec\n", |
|
test->server_forced_idle_restarts_count, test->settings->idle_timeout); |
|
cleanup_server(test); |
|
if ( iperf_get_test_one_off(test) ) { |
|
if (test->debug) |
|
printf("No connection request was received for %d sec in one-off mode; exiting.\n", |
|
test->settings->idle_timeout); |
|
exit(0); |
|
} |
|
|
|
return 2; |
|
} |
|
} |
|
else if (test->mode != SENDER && t_usecs > rcv_timeout_us) { |
|
test->server_forced_no_msg_restarts_count += 1; |
|
i_errno = IENOMSG; |
|
if (iperf_get_verbose(test)) |
|
iperf_err(test, "Server restart (#%d) during active test due to idle timeout for receiving data", |
|
test->server_forced_no_msg_restarts_count); |
|
cleanup_server(test); |
|
return -1; |
|
} |
|
|
|
} |
} |
} |
|
|
if (result > 0) { |
if (result > 0) { |
|
iperf_time_now(&last_receive_time); |
if (FD_ISSET(test->listener, &read_set)) { |
if (FD_ISSET(test->listener, &read_set)) { |
if (test->state != CREATE_STREAMS) { |
if (test->state != CREATE_STREAMS) { |
if (iperf_accept(test) < 0) { |
if (iperf_accept(test) < 0) { |
Line 492 iperf_run_server(struct iperf_test *test)
|
Line 603 iperf_run_server(struct iperf_test *test)
|
cleanup_server(test); |
cleanup_server(test); |
return -1; |
return -1; |
} |
} |
FD_CLR(test->ctrl_sck, &read_set); | FD_CLR(test->ctrl_sck, &read_set); |
} |
} |
|
|
if (test->state == CREATE_STREAMS) { |
if (test->state == CREATE_STREAMS) { |
if (FD_ISSET(test->prot_listener, &read_set)) { |
if (FD_ISSET(test->prot_listener, &read_set)) { |
| |
if ((s = test->protocol->accept(test)) < 0) { |
if ((s = test->protocol->accept(test)) < 0) { |
cleanup_server(test); |
cleanup_server(test); |
return -1; |
return -1; |
} |
} |
|
|
|
/* apply other common socket options */ |
|
if (iperf_common_sockopts(test, s) < 0) |
|
{ |
|
cleanup_server(test); |
|
return -1; |
|
} |
|
|
|
if (!is_closed(s)) { |
|
|
|
#if defined(HAVE_TCP_USER_TIMEOUT) |
|
if (test->protocol->id == Ptcp) { |
|
int opt; |
|
if ((opt = test->settings->snd_timeout)) { |
|
if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) { |
|
saved_errno = errno; |
|
close(s); |
|
cleanup_server(test); |
|
errno = saved_errno; |
|
i_errno = IESETUSERTIMEOUT; |
|
return -1; |
|
} |
|
} |
|
} |
|
#endif /* HAVE_TCP_USER_TIMEOUT */ |
|
|
#if defined(HAVE_TCP_CONGESTION) |
#if defined(HAVE_TCP_CONGESTION) |
if (test->protocol->id == Ptcp) { |
if (test->protocol->id == Ptcp) { |
if (test->congestion) { |
if (test->congestion) { |
Line 527 iperf_run_server(struct iperf_test *test)
|
Line 663 iperf_run_server(struct iperf_test *test)
|
i_errno = IESETCONGESTION; |
i_errno = IESETCONGESTION; |
return -1; |
return -1; |
} |
} |
} | } |
} |
} |
{ |
{ |
socklen_t len = TCP_CA_NAME_MAX; |
socklen_t len = TCP_CA_NAME_MAX; |
char ca[TCP_CA_NAME_MAX + 1]; |
char ca[TCP_CA_NAME_MAX + 1]; |
if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { | int rc; |
| rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len); |
| if (rc < 0 && test->congestion) { |
saved_errno = errno; |
saved_errno = errno; |
close(s); |
close(s); |
cleanup_server(test); |
cleanup_server(test); |
Line 540 iperf_run_server(struct iperf_test *test)
|
Line 678 iperf_run_server(struct iperf_test *test)
|
i_errno = IESETCONGESTION; |
i_errno = IESETCONGESTION; |
return -1; |
return -1; |
} |
} |
test->congestion_used = strdup(ca); | /* |
| * If not the first connection, discard prior |
| * congestion algorithm name so we don't leak |
| * duplicated strings. We probably don't need |
| * the old string anyway. |
| */ |
| if (test->congestion_used != NULL) { |
| free(test->congestion_used); |
| } |
| // Set actual used congestion alg, or set to unknown if could not get it |
| if (rc < 0) |
| test->congestion_used = strdup("unknown"); |
| else |
| test->congestion_used = strdup(ca); |
if (test->debug) { |
if (test->debug) { |
printf("Congestion algorithm is %s\n", test->congestion_used); |
printf("Congestion algorithm is %s\n", test->congestion_used); |
} |
} |
Line 548 iperf_run_server(struct iperf_test *test)
|
Line 699 iperf_run_server(struct iperf_test *test)
|
} |
} |
#endif /* HAVE_TCP_CONGESTION */ |
#endif /* HAVE_TCP_CONGESTION */ |
|
|
if (!is_closed(s)) { |
|
|
|
if (rec_streams_accepted != streams_to_rec) { |
if (rec_streams_accepted != streams_to_rec) { |
flag = 0; |
flag = 0; |
++rec_streams_accepted; |
++rec_streams_accepted; |
Line 597 iperf_run_server(struct iperf_test *test)
|
Line 746 iperf_run_server(struct iperf_test *test)
|
if (test->protocol->id != Ptcp) { |
if (test->protocol->id != Ptcp) { |
FD_CLR(test->prot_listener, &test->read_set); |
FD_CLR(test->prot_listener, &test->read_set); |
close(test->prot_listener); |
close(test->prot_listener); |
} else { | test->prot_listener = -1; |
| } else { |
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { |
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { |
FD_CLR(test->listener, &test->read_set); |
FD_CLR(test->listener, &test->read_set); |
close(test->listener); |
close(test->listener); |
test->listener = 0; | test->listener = -1; |
if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { | if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) { |
cleanup_server(test); |
cleanup_server(test); |
i_errno = IELISTEN; |
i_errno = IELISTEN; |
return -1; |
return -1; |
Line 617 iperf_run_server(struct iperf_test *test)
|
Line 767 iperf_run_server(struct iperf_test *test)
|
/* Ensure that total requested data rate is not above limit */ |
/* Ensure that total requested data rate is not above limit */ |
iperf_size_t total_requested_rate = test->num_streams * test->settings->rate * (test->mode == BIDIRECTIONAL? 2 : 1); |
iperf_size_t total_requested_rate = test->num_streams * test->settings->rate * (test->mode == BIDIRECTIONAL? 2 : 1); |
if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) { |
if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) { |
iperf_err(test, "Client total requested throughput rate of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", | if (iperf_get_verbose(test)) |
total_requested_rate, test->settings->bitrate_limit); | iperf_err(test, "Client total requested throughput rate of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", |
| total_requested_rate, test->settings->bitrate_limit); |
cleanup_server(test); |
cleanup_server(test); |
i_errno = IETOTALRATE; |
i_errno = IETOTALRATE; |
return -1; |
return -1; |
} |
} |
|
|
|
// Begin calculating CPU utilization |
|
cpu_util(NULL); |
|
|
if (iperf_set_send_state(test, TEST_START) != 0) { |
if (iperf_set_send_state(test, TEST_START) != 0) { |
cleanup_server(test); |
cleanup_server(test); |
return -1; |
return -1; |
Line 686 iperf_run_server(struct iperf_test *test)
|
Line 840 iperf_run_server(struct iperf_test *test)
|
} |
} |
} |
} |
|
|
cleanup_server(test); |
|
|
|
if (test->json_output) { |
if (test->json_output) { |
if (iperf_json_finish(test) < 0) |
if (iperf_json_finish(test) < 0) |
return -1; |
return -1; |
} | } |
|
|
iflush(test); |
iflush(test); |
|
cleanup_server(test); |
|
|
if (test->server_affinity != -1) | if (test->server_affinity != -1) |
if (iperf_clearaffinity(test) != 0) |
if (iperf_clearaffinity(test) != 0) |
return -1; |
return -1; |
|
|