version 1.1.1.1, 2016/10/18 13:28:18
|
version 1.1.1.3, 2023/09/27 11:14:54
|
Line 1
|
Line 1
|
/* |
/* |
* iperf, Copyright (c) 2014, 2015, 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 40
|
Line 40
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <pthread.h> |
|
#ifdef HAVE_STDINT_H |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#include <stdint.h> |
#endif |
#endif |
#include <netinet/tcp.h> |
|
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/resource.h> |
#include <sys/resource.h> |
#include <sched.h> |
#include <sched.h> |
Line 56
|
Line 54
|
#include "iperf_tcp.h" |
#include "iperf_tcp.h" |
#include "iperf_util.h" |
#include "iperf_util.h" |
#include "timer.h" |
#include "timer.h" |
|
#include "iperf_time.h" |
#include "net.h" |
#include "net.h" |
#include "units.h" |
#include "units.h" |
#include "tcp_window_size.h" |
|
#include "iperf_util.h" |
#include "iperf_util.h" |
#include "iperf_locale.h" |
#include "iperf_locale.h" |
|
|
|
#if defined(HAVE_TCP_CONGESTION) |
|
#if !defined(TCP_CA_NAME_MAX) |
|
#define TCP_CA_NAME_MAX 16 |
|
#endif /* TCP_CA_NAME_MAX */ |
|
#endif /* HAVE_TCP_CONGESTION */ |
|
|
int |
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 84 iperf_server_listen(struct iperf_test *test)
|
Line 87 iperf_server_listen(struct iperf_test *test)
|
} |
} |
|
|
if (!test->json_output) { |
if (!test->json_output) { |
iprintf(test, "-----------------------------------------------------------\n"); | if (test->server_last_run_rc != 2) |
iprintf(test, "Server listening on %d\n", test->server_port); | test->server_test_number +=1; |
} | if (test->debug || test->server_last_run_rc != 2) { |
| iperf_printf(test, "-----------------------------------------------------------\n"); |
// This needs to be changed to reflect if client has different window size | iperf_printf(test, "Server listening on %d (test #%d)\n", test->server_port, test->server_test_number); |
// make sure we got what we asked for | iperf_printf(test, "-----------------------------------------------------------\n"); |
/* XXX: This needs to be moved to the stream listener | if (test->forceflush) |
if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { | iflush(test); |
// Needs to set some sort of error number/message | |
perror("SO_RCVBUF"); | |
return -1; | |
} | |
*/ | |
| |
// XXX: This code needs to be moved to after parameter exhange | |
/* | |
char ubuf[UNIT_LEN]; | |
int x; | |
| |
if (test->protocol->id == Ptcp) { | |
if (test->settings->socket_bufsize > 0) { | |
unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); | |
if (!test->json_output) | |
iprintf(test, report_window, ubuf); | |
} else { | |
if (!test->json_output) | |
iprintf(test, "%s", report_autotune); | |
} |
} |
} |
} |
*/ |
|
if (!test->json_output) |
|
iprintf(test, "-----------------------------------------------------------\n"); |
|
|
|
FD_ZERO(&test->read_set); |
FD_ZERO(&test->read_set); |
FD_ZERO(&test->write_set); |
FD_ZERO(&test->write_set); |
Line 142 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 153 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 246 iperf_handle_message_server(struct iperf_test *test)
|
Line 254 iperf_handle_message_server(struct iperf_test *test)
|
return 0; |
return 0; |
} |
} |
|
|
/* XXX: This function is not used anymore */ | static void |
void | server_timer_proc(TimerClientData client_data, struct iperf_time *nowP) |
iperf_test_reset(struct iperf_test *test) | |
{ |
{ |
|
struct iperf_test *test = client_data.p; |
struct iperf_stream *sp; |
struct iperf_stream *sp; |
|
|
close(test->ctrl_sck); | test->timer = NULL; |
| if (test->done) |
| return; |
| test->done = 1; |
/* Free streams */ |
/* Free streams */ |
while (!SLIST_EMPTY(&test->streams)) { |
while (!SLIST_EMPTY(&test->streams)) { |
sp = SLIST_FIRST(&test->streams); |
sp = SLIST_FIRST(&test->streams); |
SLIST_REMOVE_HEAD(&test->streams, streams); |
SLIST_REMOVE_HEAD(&test->streams, streams); |
|
close(sp->socket); |
iperf_free_stream(sp); |
iperf_free_stream(sp); |
} |
} |
if (test->timer != NULL) { | close(test->ctrl_sck); |
tmr_cancel(test->timer); | |
test->timer = NULL; | |
} | |
if (test->stats_timer != NULL) { | |
tmr_cancel(test->stats_timer); | |
test->stats_timer = NULL; | |
} | |
if (test->reporter_timer != NULL) { | |
tmr_cancel(test->reporter_timer); | |
test->reporter_timer = NULL; | |
} | |
test->done = 0; | |
| |
SLIST_INIT(&test->streams); | |
| |
test->role = 's'; | |
set_protocol(test, Ptcp); | |
test->omit = OMIT; | |
test->duration = DURATION; | |
test->diskfile_name = (char*) 0; | |
test->affinity = -1; | |
test->server_affinity = -1; | |
test->title = NULL; | |
test->congestion = NULL; | |
test->state = 0; | |
test->server_hostname = NULL; | |
| |
test->ctrl_sck = -1; |
test->ctrl_sck = -1; |
test->prot_listener = -1; |
|
|
|
test->bytes_sent = 0; |
|
|
|
test->reverse = 0; |
|
test->sender = 0; |
|
test->sender_has_retransmits = 0; |
|
test->no_delay = 0; |
|
|
|
FD_ZERO(&test->read_set); |
|
FD_ZERO(&test->write_set); |
|
FD_SET(test->listener, &test->read_set); |
|
test->max_fd = test->listener; |
|
|
|
test->num_streams = 1; |
|
test->settings->socket_bufsize = 0; |
|
test->settings->blksize = DEFAULT_TCP_BLKSIZE; |
|
test->settings->rate = 0; |
|
test->settings->mss = 0; |
|
memset(test->cookie, 0, COOKIE_SIZE); |
|
} |
} |
|
|
static void |
static void |
server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP) | server_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP) |
{ |
{ |
struct iperf_test *test = client_data.p; |
struct iperf_test *test = client_data.p; |
|
|
Line 323 server_stats_timer_proc(TimerClientData client_data, s
|
Line 287 server_stats_timer_proc(TimerClientData client_data, s
|
} |
} |
|
|
static void |
static void |
server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) | server_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP) |
{ |
{ |
struct iperf_test *test = client_data.p; |
struct iperf_test *test = client_data.p; |
|
|
Line 336 server_reporter_timer_proc(TimerClientData client_data
|
Line 300 server_reporter_timer_proc(TimerClientData client_data
|
static int |
static int |
create_server_timers(struct iperf_test * test) |
create_server_timers(struct iperf_test * test) |
{ |
{ |
struct timeval now; | struct iperf_time now; |
TimerClientData cd; |
TimerClientData cd; |
|
int max_rtt = 4; /* seconds */ |
|
int state_transitions = 10; /* number of state transitions in iperf3 */ |
|
int grace_period = max_rtt * state_transitions; |
|
|
if (gettimeofday(&now, NULL) < 0) { | if (iperf_time_now(&now) < 0) { |
i_errno = IEINITTEST; |
i_errno = IEINITTEST; |
return -1; |
return -1; |
} |
} |
cd.p = test; |
cd.p = test; |
|
test->timer = test->stats_timer = test->reporter_timer = NULL; |
|
if (test->duration != 0 ) { |
|
test->done = 0; |
|
test->timer = tmr_create(&now, server_timer_proc, cd, (test->duration + test->omit + grace_period) * SEC_TO_US, 0); |
|
if (test->timer == NULL) { |
|
i_errno = IEINITTEST; |
|
return -1; |
|
} |
|
} |
|
|
test->stats_timer = test->reporter_timer = NULL; |
test->stats_timer = test->reporter_timer = NULL; |
if (test->stats_interval != 0) { |
if (test->stats_interval != 0) { |
test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); |
test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); |
Line 363 create_server_timers(struct iperf_test * test)
|
Line 340 create_server_timers(struct iperf_test * test)
|
} |
} |
|
|
static void |
static void |
server_omit_timer_proc(TimerClientData client_data, struct timeval *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; |
test->omitting = 0; |
test->omitting = 0; |
iperf_reset_stats(test); |
iperf_reset_stats(test); |
if (test->verbose && !test->json_output && test->reporter_interval == 0) |
if (test->verbose && !test->json_output && test->reporter_interval == 0) |
iprintf(test, "%s", report_omit_done); | iperf_printf(test, "%s", report_omit_done); |
|
|
/* Reset the timers. */ |
/* Reset the timers. */ |
if (test->stats_timer != NULL) |
if (test->stats_timer != NULL) |
Line 383 server_omit_timer_proc(TimerClientData client_data, st
|
Line 360 server_omit_timer_proc(TimerClientData client_data, st
|
static int |
static int |
create_server_omit_timer(struct iperf_test * test) |
create_server_omit_timer(struct iperf_test * test) |
{ |
{ |
struct timeval 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; |
test->omitting = 0; |
test->omitting = 0; |
} else { |
} else { |
if (gettimeofday(&now, NULL) < 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 409 create_server_omit_timer(struct iperf_test * test)
|
Line 386 create_server_omit_timer(struct iperf_test * test)
|
static void |
static void |
cleanup_server(struct iperf_test *test) |
cleanup_server(struct iperf_test *test) |
{ |
{ |
|
struct iperf_stream *sp; |
|
|
|
/* Close open streams */ |
|
SLIST_FOREACH(sp, &test->streams, streams) { |
|
if (sp->socket > -1) { |
|
FD_CLR(sp->socket, &test->read_set); |
|
FD_CLR(sp->socket, &test->write_set); |
|
close(sp->socket); |
|
sp->socket = -1; |
|
} |
|
} |
|
|
/* Close open test sockets */ |
/* Close open test sockets */ |
close(test->ctrl_sck); | if (test->ctrl_sck > -1) { |
close(test->listener); | close(test->ctrl_sck); |
| test->ctrl_sck = -1; |
| } |
| if (test->listener > -1) { |
| 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 426 cleanup_server(struct iperf_test *test)
|
Line 425 cleanup_server(struct iperf_test *test)
|
tmr_cancel(test->omit_timer); |
tmr_cancel(test->omit_timer); |
test->omit_timer = NULL; |
test->omit_timer = NULL; |
} |
} |
|
if (test->congestion_used != NULL) { |
|
free(test->congestion_used); |
|
test->congestion_used = NULL; |
|
} |
|
if (test->timer != NULL) { |
|
tmr_cancel(test->timer); |
|
test->timer = NULL; |
|
} |
} |
} |
|
|
|
|
int |
int |
iperf_run_server(struct iperf_test *test) |
iperf_run_server(struct iperf_test *test) |
{ |
{ |
int result, s, streams_accepted; | int result, s; |
| int send_streams_accepted, rec_streams_accepted; |
| int streams_to_send = 0, streams_to_rec = 0; |
| #if defined(HAVE_TCP_CONGESTION) |
| int saved_errno; |
| #endif /* HAVE_TCP_CONGESTION */ |
fd_set read_set, write_set; |
fd_set read_set, write_set; |
struct iperf_stream *sp; |
struct iperf_stream *sp; |
struct timeval 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; |
|
int64_t t_usecs; |
|
int64_t timeout_us; |
|
int64_t rcv_timeout_us; |
|
|
if (test->affinity != -1) | if (test->logfile) |
if (iperf_setaffinity(test, test->affinity) != 0) | if (iperf_open_logfile(test) < 0) |
| return -2; |
| |
| if (test->affinity != -1) |
| 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)); |
cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); |
cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); |
} else if (test->verbose) { |
} else if (test->verbose) { |
iprintf(test, "%s\n", version); | iperf_printf(test, "%s\n", version); |
iprintf(test, "%s", ""); | iperf_printf(test, "%s", ""); |
iprintf(test, "%s\n", get_system_info()); | iperf_printf(test, "%s\n", get_system_info()); |
iflush(test); |
iflush(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; |
streams_accepted = 0; | send_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) { |
|
|
|
// Check if average transfer rate was exceeded (condition set in the callback routines) |
|
if (test->bitrate_limit_exceeded) { |
|
cleanup_server(test); |
|
i_errno = IETOTALRATE; |
|
return -1; |
|
} |
|
|
memcpy(&read_set, &test->read_set, sizeof(fd_set)); |
memcpy(&read_set, &test->read_set, sizeof(fd_set)); |
memcpy(&write_set, &test->write_set, sizeof(fd_set)); |
memcpy(&write_set, &test->write_set, sizeof(fd_set)); |
|
|
(void) gettimeofday(&now, NULL); | iperf_time_now(&now); |
timeout = tmr_timeout(&now); |
timeout = tmr_timeout(&now); |
|
|
|
// 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); |
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 488 iperf_run_server(struct iperf_test *test)
|
Line 584 iperf_run_server(struct iperf_test *test)
|
return -1; |
return -1; |
} |
} |
FD_CLR(test->listener, &read_set); |
FD_CLR(test->listener, &read_set); |
|
|
|
// Set streams number |
|
if (test->mode == BIDIRECTIONAL) { |
|
streams_to_send = test->num_streams; |
|
streams_to_rec = test->num_streams; |
|
} else if (test->mode == RECEIVER) { |
|
streams_to_rec = test->num_streams; |
|
streams_to_send = 0; |
|
} else { |
|
streams_to_send = test->num_streams; |
|
streams_to_rec = 0; |
|
} |
} |
} |
} |
} |
if (FD_ISSET(test->ctrl_sck, &read_set)) { |
if (FD_ISSET(test->ctrl_sck, &read_set)) { |
Line 495 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 (!is_closed(s)) { |
sp = iperf_new_stream(test, s); |
|
if (!sp) { |
|
cleanup_server(test); |
|
return -1; |
|
} |
|
|
|
if (test->sender) | #if defined(HAVE_TCP_USER_TIMEOUT) |
FD_SET(s, &test->write_set); | if (test->protocol->id == Ptcp) { |
else | int opt; |
FD_SET(s, &test->read_set); | if ((opt = test->settings->snd_timeout)) { |
if (s > test->max_fd) test->max_fd = s; | 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 the protocol isn't UDP, or even if it is but | if (test->protocol->id == Ptcp) { |
* we're the receiver, set nonblocking sockets. | if (test->congestion) { |
* We need this to allow a server receiver to | if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { |
* maintain interactivity with the control channel. | /* |
*/ | * ENOENT means we tried to set the |
if (test->protocol->id != Pudp || | * congestion algorithm but the algorithm |
!test->sender) { | * specified doesn't exist. This can happen |
setnonblocking(s, 1); | * if the client and server have different |
| * congestion algorithms available. In this |
| * case, print a warning, but otherwise |
| * continue. |
| */ |
| if (errno == ENOENT) { |
| warning("TCP congestion control algorithm not supported"); |
| } |
| else { |
| saved_errno = errno; |
| close(s); |
| cleanup_server(test); |
| errno = saved_errno; |
| i_errno = IESETCONGESTION; |
| return -1; |
| } |
| } |
} |
} |
|
{ |
|
socklen_t len = TCP_CA_NAME_MAX; |
|
char ca[TCP_CA_NAME_MAX + 1]; |
|
int rc; |
|
rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len); |
|
if (rc < 0 && test->congestion) { |
|
saved_errno = errno; |
|
close(s); |
|
cleanup_server(test); |
|
errno = saved_errno; |
|
i_errno = IESETCONGESTION; |
|
return -1; |
|
} |
|
/* |
|
* 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) { |
|
printf("Congestion algorithm is %s\n", test->congestion_used); |
|
} |
|
} |
|
} |
|
#endif /* HAVE_TCP_CONGESTION */ |
|
|
streams_accepted++; | if (rec_streams_accepted != streams_to_rec) { |
if (test->on_new_stream) | flag = 0; |
test->on_new_stream(sp); | ++rec_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) { |
| cleanup_server(test); |
| return -1; |
| } |
| |
| if (sp->sender) |
| FD_SET(s, &test->write_set); |
| else |
| FD_SET(s, &test->read_set); |
| |
| if (s > test->max_fd) test->max_fd = s; |
| |
| /* |
| * If the protocol isn't UDP, or even if it is but |
| * we're the receiver, set nonblocking sockets. |
| * We need this to allow a server receiver to |
| * maintain interactivity with the control channel. |
| */ |
| if (test->protocol->id != Pudp || |
| !sp->sender) { |
| setnonblocking(s, 1); |
| } |
| |
| if (test->on_new_stream) |
| test->on_new_stream(sp); |
| |
| flag = -1; |
| } |
} |
} |
FD_CLR(test->prot_listener, &read_set); |
FD_CLR(test->prot_listener, &read_set); |
} |
} |
|
|
if (streams_accepted == test->num_streams) { | |
| if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { |
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); |
if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { | test->listener = -1; |
| 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 556 iperf_run_server(struct iperf_test *test)
|
Line 763 iperf_run_server(struct iperf_test *test)
|
} |
} |
} |
} |
test->prot_listener = -1; |
test->prot_listener = -1; |
|
|
|
/* 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); |
|
if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) { |
|
if (iperf_get_verbose(test)) |
|
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); |
|
i_errno = IETOTALRATE; |
|
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 572 iperf_run_server(struct iperf_test *test)
|
Line 794 iperf_run_server(struct iperf_test *test)
|
cleanup_server(test); |
cleanup_server(test); |
return -1; |
return -1; |
} |
} |
if (test->reverse) | if (test->mode != RECEIVER) |
if (iperf_create_send_timers(test) < 0) { |
if (iperf_create_send_timers(test) < 0) { |
cleanup_server(test); |
cleanup_server(test); |
return -1; |
return -1; |
Line 585 iperf_run_server(struct iperf_test *test)
|
Line 807 iperf_run_server(struct iperf_test *test)
|
} |
} |
|
|
if (test->state == TEST_RUNNING) { |
if (test->state == TEST_RUNNING) { |
if (test->reverse) { | if (test->mode == BIDIRECTIONAL) { |
| if (iperf_recv(test, &read_set) < 0) { |
| cleanup_server(test); |
| return -1; |
| } |
| if (iperf_send(test, &write_set) < 0) { |
| cleanup_server(test); |
| return -1; |
| } |
| } else if (test->mode == SENDER) { |
// Reverse mode. Server sends. |
// Reverse mode. Server sends. |
if (iperf_send(test, &write_set) < 0) { |
if (iperf_send(test, &write_set) < 0) { |
cleanup_server(test); |
cleanup_server(test); |
Line 598 iperf_run_server(struct iperf_test *test)
|
Line 829 iperf_run_server(struct iperf_test *test)
|
return -1; |
return -1; |
} |
} |
} |
} |
} | } |
} |
} |
|
|
if (result == 0 || |
if (result == 0 || |
(timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { |
(timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { |
/* Run the timers. */ |
/* Run the timers. */ |
(void) gettimeofday(&now, NULL); | iperf_time_now(&now); |
tmr_run(&now); |
tmr_run(&now); |
} |
} |
} |
} |
|
|
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; |
|
|