--- embedaddon/iperf/src/iperf_server_api.c 2016/10/18 13:28:18 1.1.1.1 +++ embedaddon/iperf/src/iperf_server_api.c 2023/09/27 11:14:54 1.1.1.3 @@ -1,5 +1,5 @@ /* - * 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 * to receipt of any required approvals from the U.S. Dept. of * Energy). All rights reserved. @@ -40,11 +40,9 @@ #include #include #include -#include #ifdef HAVE_STDINT_H #include #endif -#include #include #include #include @@ -56,18 +54,23 @@ #include "iperf_tcp.h" #include "iperf_util.h" #include "timer.h" +#include "iperf_time.h" #include "net.h" #include "units.h" -#include "tcp_window_size.h" #include "iperf_util.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 iperf_server_listen(struct iperf_test *test) { 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 we get "Address family not supported by protocol", that ** probably means we were compiled with IPv6 but the running @@ -84,38 +87,16 @@ iperf_server_listen(struct iperf_test *test) } if (!test->json_output) { - iprintf(test, "-----------------------------------------------------------\n"); - iprintf(test, "Server listening on %d\n", test->server_port); - } - - // This needs to be changed to reflect if client has different window size - // make sure we got what we asked for - /* XXX: This needs to be moved to the stream listener - if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { - // 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->server_last_run_rc != 2) + test->server_test_number +=1; + if (test->debug || test->server_last_run_rc != 2) { + iperf_printf(test, "-----------------------------------------------------------\n"); + 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); } } - */ - if (!test->json_output) - iprintf(test, "-----------------------------------------------------------\n"); FD_ZERO(&test->read_set); FD_ZERO(&test->write_set); @@ -142,7 +123,29 @@ iperf_accept(struct iperf_test *test) if (test->ctrl_sck == -1) { /* Server free, accept new client */ 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; return -1; } @@ -153,19 +156,24 @@ iperf_accept(struct iperf_test *test) return -1; if (iperf_exchange_parameters(test) < 0) return -1; - if (test->server_affinity != -1) + if (test->server_affinity != -1) if (iperf_setaffinity(test, test->server_affinity) != 0) return -1; if (test->on_connect) test->on_connect(test); } 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. + * 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) { - i_errno = IESENDMESSAGE; - return -1; + if (test->debug) + 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); } @@ -246,73 +254,29 @@ iperf_handle_message_server(struct iperf_test *test) return 0; } -/* XXX: This function is not used anymore */ -void -iperf_test_reset(struct iperf_test *test) +static void +server_timer_proc(TimerClientData client_data, struct iperf_time *nowP) { + struct iperf_test *test = client_data.p; struct iperf_stream *sp; - close(test->ctrl_sck); - + test->timer = NULL; + if (test->done) + return; + test->done = 1; /* Free streams */ while (!SLIST_EMPTY(&test->streams)) { sp = SLIST_FIRST(&test->streams); SLIST_REMOVE_HEAD(&test->streams, streams); + close(sp->socket); iperf_free_stream(sp); } - if (test->timer != NULL) { - 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; - + close(test->ctrl_sck); 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 -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; @@ -323,7 +287,7 @@ server_stats_timer_proc(TimerClientData client_data, s } 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; @@ -336,14 +300,27 @@ server_reporter_timer_proc(TimerClientData client_data static int create_server_timers(struct iperf_test * test) { - struct timeval now; + struct iperf_time now; 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; return -1; } 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; if (test->stats_interval != 0) { test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); @@ -363,15 +340,15 @@ create_server_timers(struct iperf_test * test) } 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; test->omit_timer = NULL; test->omitting = 0; iperf_reset_stats(test); 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. */ if (test->stats_timer != NULL) @@ -383,20 +360,20 @@ server_omit_timer_proc(TimerClientData client_data, st static int create_server_omit_timer(struct iperf_test * test) { - struct timeval now; - TimerClientData cd; + struct iperf_time now; + TimerClientData cd; if (test->omit == 0) { test->omit_timer = NULL; test->omitting = 0; } else { - if (gettimeofday(&now, NULL) < 0) { + if (iperf_time_now(&now) < 0) { i_errno = IEINITTEST; - return -1; + return -1; } test->omitting = 1; 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) { i_errno = IEINITTEST; return -1; @@ -409,9 +386,31 @@ create_server_omit_timer(struct iperf_test * test) static void 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(test->ctrl_sck); - close(test->listener); + if (test->ctrl_sck > -1) { + 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. */ if (test->stats_timer != NULL) { @@ -426,61 +425,158 @@ cleanup_server(struct iperf_test *test) tmr_cancel(test->omit_timer); 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 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; 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 used_timeout; + int flag; + int64_t t_usecs; + int64_t timeout_us; + int64_t rcv_timeout_us; - if (test->affinity != -1) - if (iperf_setaffinity(test, test->affinity) != 0) + if (test->logfile) + if (iperf_open_logfile(test) < 0) + return -2; + + if (test->affinity != -1) + if (iperf_setaffinity(test, test->affinity) != 0) { + cleanup_server(test); return -2; + } if (test->json_output) - if (iperf_json_start(test) < 0) + if (iperf_json_start(test) < 0) { + cleanup_server(test); return -2; + } if (test->json_output) { cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); } else if (test->verbose) { - iprintf(test, "%s\n", version); - iprintf(test, "%s", ""); - iprintf(test, "%s\n", get_system_info()); + iperf_printf(test, "%s\n", version); + iperf_printf(test, "%s", ""); + iperf_printf(test, "%s\n", get_system_info()); iflush(test); } // Open socket and listen if (iperf_server_listen(test) < 0) { + cleanup_server(test); return -2; } - // Begin calculating CPU utilization - cpu_util(NULL); + iperf_time_now(&last_receive_time); // Initialize last time something was received 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) { + // 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(&write_set, &test->write_set, sizeof(fd_set)); - (void) gettimeofday(&now, NULL); + iperf_time_now(&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); if (result < 0 && errno != EINTR) { - cleanup_server(test); + cleanup_server(test); i_errno = IESELECT; 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) { + iperf_time_now(&last_receive_time); if (FD_ISSET(test->listener, &read_set)) { if (test->state != CREATE_STREAMS) { if (iperf_accept(test) < 0) { @@ -488,6 +584,18 @@ iperf_run_server(struct iperf_test *test) return -1; } 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)) { @@ -495,57 +603,156 @@ iperf_run_server(struct iperf_test *test) cleanup_server(test); return -1; } - FD_CLR(test->ctrl_sck, &read_set); + FD_CLR(test->ctrl_sck, &read_set); } if (test->state == CREATE_STREAMS) { if (FD_ISSET(test->prot_listener, &read_set)) { - + if ((s = test->protocol->accept(test)) < 0) { cleanup_server(test); return -1; } + /* apply other common socket options */ + if (iperf_common_sockopts(test, s) < 0) + { + cleanup_server(test); + return -1; + } + if (!is_closed(s)) { - sp = iperf_new_stream(test, s); - if (!sp) { - cleanup_server(test); - return -1; - } - if (test->sender) - FD_SET(s, &test->write_set); - else - FD_SET(s, &test->read_set); - if (s > test->max_fd) test->max_fd = 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 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 || - !test->sender) { - setnonblocking(s, 1); +#if defined(HAVE_TCP_CONGESTION) + if (test->protocol->id == Ptcp) { + if (test->congestion) { + if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { + /* + * ENOENT means we tried to set the + * congestion algorithm but the algorithm + * specified doesn't exist. This can happen + * 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 (test->on_new_stream) - test->on_new_stream(sp); + if (rec_streams_accepted != streams_to_rec) { + flag = 0; + ++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); } - if (streams_accepted == test->num_streams) { + + if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) { if (test->protocol->id != Ptcp) { FD_CLR(test->prot_listener, &test->read_set); close(test->prot_listener); - } else { + test->prot_listener = -1; + } else { if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { FD_CLR(test->listener, &test->read_set); 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); i_errno = IELISTEN; return -1; @@ -556,6 +763,21 @@ iperf_run_server(struct iperf_test *test) } } 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) { cleanup_server(test); return -1; @@ -572,7 +794,7 @@ iperf_run_server(struct iperf_test *test) cleanup_server(test); return -1; } - if (test->reverse) + if (test->mode != RECEIVER) if (iperf_create_send_timers(test) < 0) { cleanup_server(test); return -1; @@ -585,7 +807,16 @@ iperf_run_server(struct iperf_test *test) } 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. if (iperf_send(test, &write_set) < 0) { cleanup_server(test); @@ -598,27 +829,27 @@ iperf_run_server(struct iperf_test *test) return -1; } } - } + } } if (result == 0 || (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) { /* Run the timers. */ - (void) gettimeofday(&now, NULL); + iperf_time_now(&now); tmr_run(&now); } } - cleanup_server(test); if (test->json_output) { if (iperf_json_finish(test) < 0) return -1; - } + } iflush(test); + cleanup_server(test); - if (test->server_affinity != -1) + if (test->server_affinity != -1) if (iperf_clearaffinity(test) != 0) return -1;