version 1.1.1.1, 2016/10/18 13:28:18
|
version 1.1.1.2, 2021/03/17 00:36:46
|
Line 1
|
Line 1
|
/* |
/* |
* iperf, Copyright (c) 2014, 2015, The Regents of the University of | * iperf, Copyright (c) 2014-2020 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) |
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"); | iperf_printf(test, "-----------------------------------------------------------\n"); |
iprintf(test, "Server listening on %d\n", test->server_port); | iperf_printf(test, "Server listening on %d\n", test->server_port); |
| iperf_printf(test, "-----------------------------------------------------------\n"); |
| if (test->forceflush) |
| iflush(test); |
} |
} |
|
|
// 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->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); |
FD_SET(test->listener, &test->read_set); |
FD_SET(test->listener, &test->read_set); |
Line 246 iperf_handle_message_server(struct iperf_test *test)
|
Line 223 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->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 255 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 268 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 308 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; |
|
|
Line 371 server_omit_timer_proc(TimerClientData client_data, st
|
Line 316 server_omit_timer_proc(TimerClientData client_data, st
|
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 328 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; |
} |
} |
Line 409 create_server_omit_timer(struct iperf_test * test)
|
Line 354 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) { |
|
FD_CLR(sp->socket, &test->read_set); |
|
FD_CLR(sp->socket, &test->write_set); |
|
close(sp->socket); |
|
} |
|
|
/* Close open test sockets */ |
/* Close open test sockets */ |
close(test->ctrl_sck); | if (test->ctrl_sck) { |
close(test->listener); | close(test->ctrl_sck); |
| } |
| if (test->listener) { |
| close(test->listener); |
| } |
|
|
/* 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 384 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 timeval* timeout; |
struct timeval* timeout; |
|
int flag; |
|
|
|
if (test->logfile) |
|
if (iperf_open_logfile(test) < 0) |
|
return -1; |
|
|
if (test->affinity != -1) |
if (test->affinity != -1) |
if (iperf_setaffinity(test, test->affinity) != 0) |
if (iperf_setaffinity(test, test->affinity) != 0) |
return -2; |
return -2; |
Line 450 iperf_run_server(struct iperf_test *test)
|
Line 426 iperf_run_server(struct iperf_test *test)
|
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); |
} |
} |
|
|
Line 465 iperf_run_server(struct iperf_test *test)
|
Line 441 iperf_run_server(struct iperf_test *test)
|
cpu_util(NULL); |
cpu_util(NULL); |
|
|
test->state = IPERF_START; |
test->state = IPERF_START; |
streams_accepted = 0; | send_streams_accepted = 0; |
| rec_streams_accepted = 0; |
|
|
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); |
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; |
Line 488 iperf_run_server(struct iperf_test *test)
|
Line 473 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 506 iperf_run_server(struct iperf_test *test)
|
Line 503 iperf_run_server(struct iperf_test *test)
|
return -1; |
return -1; |
} |
} |
|
|
if (!is_closed(s)) { | #if defined(HAVE_TCP_CONGESTION) |
sp = iperf_new_stream(test, s); | if (test->protocol->id == Ptcp) { |
if (!sp) { | if (test->congestion) { |
cleanup_server(test); | if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { |
return -1; | /* |
| * 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]; |
|
if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) { |
|
saved_errno = errno; |
|
close(s); |
|
cleanup_server(test); |
|
errno = saved_errno; |
|
i_errno = IESETCONGESTION; |
|
return -1; |
|
} |
|
test->congestion_used = strdup(ca); |
|
if (test->debug) { |
|
printf("Congestion algorithm is %s\n", test->congestion_used); |
|
} |
|
} |
|
} |
|
#endif /* HAVE_TCP_CONGESTION */ |
|
|
if (test->sender) | if (!is_closed(s)) { |
FD_SET(s, &test->write_set); | |
else | |
FD_SET(s, &test->read_set); | |
if (s > test->max_fd) test->max_fd = s; | |
|
|
/* | if (rec_streams_accepted != streams_to_rec) { |
* If the protocol isn't UDP, or even if it is but | flag = 0; |
* we're the receiver, set nonblocking sockets. | ++rec_streams_accepted; |
* We need this to allow a server receiver to | } else if (send_streams_accepted != streams_to_send) { |
* maintain interactivity with the control channel. | flag = 1; |
*/ | ++send_streams_accepted; |
if (test->protocol->id != Pudp || | } |
!test->sender) { | |
setnonblocking(s, 1); | |
} | |
|
|
streams_accepted++; | if (flag != -1) { |
if (test->on_new_stream) | sp = iperf_new_stream(test, s, flag); |
test->on_new_stream(sp); | 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); |
Line 545 iperf_run_server(struct iperf_test *test)
|
Line 601 iperf_run_server(struct iperf_test *test)
|
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; |
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->server_port)) < 0) { |
cleanup_server(test); |
cleanup_server(test); |
i_errno = IELISTEN; |
i_errno = IELISTEN; |
Line 556 iperf_run_server(struct iperf_test *test)
|
Line 613 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) { |
|
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; |
|
} |
|
|
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 640 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 653 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 675 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); |
} |
} |
} |
} |