|
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, 2016, 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 24
|
Line 24
|
| * This code is distributed under a BSD style license, see the LICENSE |
* This code is distributed under a BSD style license, see the LICENSE |
| * file for complete information. |
* file for complete information. |
| */ |
*/ |
| #include "iperf_config.h" |
|
| |
|
| #include <stdio.h> |
#include <stdio.h> |
| #include <stdlib.h> |
#include <stdlib.h> |
| #include <string.h> |
#include <string.h> |
| #include <errno.h> |
#include <errno.h> |
| #include <unistd.h> |
#include <unistd.h> |
| |
#include <arpa/inet.h> |
| #include <sys/socket.h> |
#include <sys/socket.h> |
| #include <sys/types.h> |
#include <sys/types.h> |
| #include <netinet/in.h> |
#include <netinet/in.h> |
| #include <netdb.h> |
#include <netdb.h> |
| #include <netinet/tcp.h> |
|
| #include <sys/time.h> |
#include <sys/time.h> |
| #include <sys/select.h> |
#include <sys/select.h> |
| |
#include <limits.h> |
| |
|
| #include "iperf.h" |
#include "iperf.h" |
| #include "iperf_api.h" |
#include "iperf_api.h" |
| #include "iperf_tcp.h" |
#include "iperf_tcp.h" |
| #include "net.h" |
#include "net.h" |
| |
#include "cjson.h" |
| |
|
| #if defined(HAVE_FLOWLABEL) |
#if defined(HAVE_FLOWLABEL) |
| #include "flowlabel.h" |
#include "flowlabel.h" |
|
Line 62 iperf_tcp_recv(struct iperf_stream *sp)
|
Line 62 iperf_tcp_recv(struct iperf_stream *sp)
|
| if (r < 0) |
if (r < 0) |
| return r; |
return r; |
| |
|
| sp->result->bytes_received += r; | /* Only count bytes received while we're in the correct state. */ |
| sp->result->bytes_received_this_interval += r; | if (sp->test->state == TEST_RUNNING) { |
| | sp->result->bytes_received += r; |
| | sp->result->bytes_received_this_interval += r; |
| | } |
| | else { |
| | if (sp->test->debug) |
| | printf("Late receive, state = %d\n", sp->test->state); |
| | } |
| |
|
| return r; |
return r; |
| } |
} |
| |
|
| |
|
| /* iperf_tcp_send | /* iperf_tcp_send |
| * |
* |
| * sends the data for TCP |
* sends the data for TCP |
| */ |
*/ |
|
Line 78 iperf_tcp_send(struct iperf_stream *sp)
|
Line 85 iperf_tcp_send(struct iperf_stream *sp)
|
| { |
{ |
| int r; |
int r; |
| |
|
| |
if (!sp->pending_size) |
| |
sp->pending_size = sp->settings->blksize; |
| |
|
| if (sp->test->zerocopy) |
if (sp->test->zerocopy) |
| r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize); | r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->pending_size); |
| else |
else |
| r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp); | r = Nwrite(sp->socket, sp->buffer, sp->pending_size, Ptcp); |
| |
|
| if (r < 0) |
if (r < 0) |
| return r; |
return r; |
| |
|
| |
sp->pending_size -= r; |
| sp->result->bytes_sent += r; |
sp->result->bytes_sent += r; |
| sp->result->bytes_sent_this_interval += r; |
sp->result->bytes_sent_this_interval += r; |
| |
|
| |
if (sp->test->debug_level >= DEBUG_LEVEL_DEBUG) |
| |
printf("sent %d bytes of %d, pending %d, total %" PRIu64 "\n", |
| |
r, sp->settings->blksize, sp->pending_size, sp->result->bytes_sent); |
| |
|
| return r; |
return r; |
| } |
} |
| |
|
|
Line 119 iperf_tcp_accept(struct iperf_test * test)
|
Line 134 iperf_tcp_accept(struct iperf_test * test)
|
| |
|
| if (strcmp(test->cookie, cookie) != 0) { |
if (strcmp(test->cookie, cookie) != 0) { |
| if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { |
if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { |
| i_errno = IESENDMESSAGE; | iperf_err(test, "failed to send access denied from busy server to new connecting client, errno = %d\n", errno); |
| return -1; | |
| } |
} |
| close(s); |
close(s); |
| } |
} |
|
Line 136 iperf_tcp_accept(struct iperf_test * test)
|
Line 150 iperf_tcp_accept(struct iperf_test * test)
|
| int |
int |
| iperf_tcp_listen(struct iperf_test *test) |
iperf_tcp_listen(struct iperf_test *test) |
| { |
{ |
| struct addrinfo hints, *res; |
|
| char portstr[6]; |
|
| int s, opt; |
int s, opt; |
| |
socklen_t optlen; |
| int saved_errno; |
int saved_errno; |
| |
int rcvbuf_actual, sndbuf_actual; |
| |
|
| s = test->listener; |
s = test->listener; |
| |
|
|
Line 153 iperf_tcp_listen(struct iperf_test *test)
|
Line 167 iperf_tcp_listen(struct iperf_test *test)
|
| * It's not clear whether this is a requirement or a convenience. |
* It's not clear whether this is a requirement or a convenience. |
| */ |
*/ |
| if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { |
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { |
| |
struct addrinfo hints, *res; |
| |
char portstr[6]; |
| |
|
| FD_CLR(s, &test->read_set); |
FD_CLR(s, &test->read_set); |
| close(s); |
close(s); |
| |
|
|
Line 172 iperf_tcp_listen(struct iperf_test *test)
|
Line 189 iperf_tcp_listen(struct iperf_test *test)
|
| } |
} |
| hints.ai_socktype = SOCK_STREAM; |
hints.ai_socktype = SOCK_STREAM; |
| hints.ai_flags = AI_PASSIVE; |
hints.ai_flags = AI_PASSIVE; |
| if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) { | if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) { |
| i_errno = IESTREAMLISTEN; |
i_errno = IESTREAMLISTEN; |
| return -1; |
return -1; |
| } |
} |
|
Line 223 iperf_tcp_listen(struct iperf_test *test)
|
Line 240 iperf_tcp_listen(struct iperf_test *test)
|
| return -1; |
return -1; |
| } |
} |
| } |
} |
| if (test->debug) { |
|
| socklen_t optlen = sizeof(opt); |
|
| if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) { |
|
| saved_errno = errno; |
|
| close(s); |
|
| freeaddrinfo(res); |
|
| errno = saved_errno; |
|
| i_errno = IESETBUF; |
|
| return -1; |
|
| } |
|
| printf("SO_SNDBUF is %u\n", opt); |
|
| } |
|
| #if defined(HAVE_TCP_CONGESTION) |
|
| if (test->congestion) { |
|
| if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { |
|
| close(s); |
|
| freeaddrinfo(res); |
|
| i_errno = IESETCONGESTION; |
|
| return -1; |
|
| } |
|
| } |
|
| #endif /* HAVE_TCP_CONGESTION */ |
|
| #if defined(HAVE_SO_MAX_PACING_RATE) |
#if defined(HAVE_SO_MAX_PACING_RATE) |
| /* If socket pacing is available and not disabled, try it. */ | /* If fq socket pacing is specified, enable it. */ |
| if (! test->no_fq_socket_pacing) { | if (test->settings->fqrate) { |
| /* Convert bits per second to bytes per second */ |
/* Convert bits per second to bytes per second */ |
| unsigned int rate = test->settings->rate / 8; | unsigned int fqrate = test->settings->fqrate / 8; |
| if (rate > 0) { | if (fqrate > 0) { |
| if (test->debug) { |
if (test->debug) { |
| printf("Setting fair-queue socket pacing to %u\n", rate); | printf("Setting fair-queue socket pacing to %u\n", fqrate); |
| } |
} |
| if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) { | if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { |
| warning("Unable to set socket pacing, using application pacing instead"); | warning("Unable to set socket pacing"); |
| test->no_fq_socket_pacing = 1; | |
| } |
} |
| } |
} |
| } |
} |
| #endif /* HAVE_SO_MAX_PACING_RATE */ |
#endif /* HAVE_SO_MAX_PACING_RATE */ |
| |
{ |
| |
unsigned int rate = test->settings->rate / 8; |
| |
if (rate > 0) { |
| |
if (test->debug) { |
| |
printf("Setting application pacing to %u\n", rate); |
| |
} |
| |
} |
| |
} |
| opt = 1; |
opt = 1; |
| if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { |
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { |
| saved_errno = errno; |
saved_errno = errno; |
|
Line 272 iperf_tcp_listen(struct iperf_test *test)
|
Line 274 iperf_tcp_listen(struct iperf_test *test)
|
| } |
} |
| |
|
| /* |
/* |
| * If we got an IPv6 socket, figure out if it shoudl accept IPv4 | * If we got an IPv6 socket, figure out if it should accept IPv4 |
| * connections as well. See documentation in netannounce() for |
* connections as well. See documentation in netannounce() for |
| * more details. |
* more details. |
| */ |
*/ |
|
Line 280 iperf_tcp_listen(struct iperf_test *test)
|
Line 282 iperf_tcp_listen(struct iperf_test *test)
|
| if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) { |
if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) { |
| if (test->settings->domain == AF_UNSPEC) |
if (test->settings->domain == AF_UNSPEC) |
| opt = 0; |
opt = 0; |
| else | else |
| opt = 1; |
opt = 1; |
| if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, | if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, |
| (char *) &opt, sizeof(opt)) < 0) { |
(char *) &opt, sizeof(opt)) < 0) { |
| saved_errno = errno; |
saved_errno = errno; |
| close(s); |
close(s); |
|
Line 305 iperf_tcp_listen(struct iperf_test *test)
|
Line 307 iperf_tcp_listen(struct iperf_test *test)
|
| |
|
| freeaddrinfo(res); |
freeaddrinfo(res); |
| |
|
| if (listen(s, 5) < 0) { | if (listen(s, INT_MAX) < 0) { |
| i_errno = IESTREAMLISTEN; |
i_errno = IESTREAMLISTEN; |
| return -1; |
return -1; |
| } |
} |
| |
|
| test->listener = s; |
test->listener = s; |
| } |
} |
| | |
| | /* Read back and verify the sender socket buffer size */ |
| | optlen = sizeof(sndbuf_actual); |
| | if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { |
| | saved_errno = errno; |
| | close(s); |
| | errno = saved_errno; |
| | i_errno = IESETBUF; |
| | return -1; |
| | } |
| | if (test->debug) { |
| | printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize); |
| | } |
| | if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) { |
| | i_errno = IESETBUF2; |
| | return -1; |
| | } |
| | |
| | /* Read back and verify the receiver socket buffer size */ |
| | optlen = sizeof(rcvbuf_actual); |
| | if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) { |
| | saved_errno = errno; |
| | close(s); |
| | errno = saved_errno; |
| | i_errno = IESETBUF; |
| | return -1; |
| | } |
| | if (test->debug) { |
| | printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize); |
| | } |
| | if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) { |
| | i_errno = IESETBUF2; |
| | return -1; |
| | } |
| | |
| | if (test->json_output) { |
| | cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize); |
| | cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual); |
| | cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual); |
| | } |
| | |
| return s; |
return s; |
| } |
} |
| |
|
|
Line 320 iperf_tcp_listen(struct iperf_test *test)
|
Line 362 iperf_tcp_listen(struct iperf_test *test)
|
| /* iperf_tcp_connect |
/* iperf_tcp_connect |
| * |
* |
| * connect to a TCP stream listener |
* connect to a TCP stream listener |
| |
* This function is roughly similar to netdial(), and may indeed have |
| |
* been derived from it at some point, but it sets many TCP-specific |
| |
* options between socket creation and connection. |
| */ |
*/ |
| int |
int |
| iperf_tcp_connect(struct iperf_test *test) |
iperf_tcp_connect(struct iperf_test *test) |
| { |
{ |
| struct addrinfo hints, *local_res, *server_res; | struct addrinfo *server_res; |
| char portstr[6]; | |
| int s, opt; |
int s, opt; |
| |
socklen_t optlen; |
| int saved_errno; |
int saved_errno; |
| |
int rcvbuf_actual, sndbuf_actual; |
| |
|
| if (test->bind_address) { | s = create_socket(test->settings->domain, SOCK_STREAM, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, &server_res); |
| memset(&hints, 0, sizeof(hints)); | if (s < 0) { |
| hints.ai_family = test->settings->domain; | i_errno = IESTREAMCONNECT; |
| hints.ai_socktype = SOCK_STREAM; | return -1; |
| if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) { | |
| i_errno = IESTREAMCONNECT; | |
| return -1; | |
| } | |
| } |
} |
| |
|
| memset(&hints, 0, sizeof(hints)); |
|
| hints.ai_family = test->settings->domain; |
|
| hints.ai_socktype = SOCK_STREAM; |
|
| snprintf(portstr, sizeof(portstr), "%d", test->server_port); |
|
| if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) { |
|
| if (test->bind_address) |
|
| freeaddrinfo(local_res); |
|
| i_errno = IESTREAMCONNECT; |
|
| return -1; |
|
| } |
|
| |
|
| if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) { |
|
| if (test->bind_address) |
|
| freeaddrinfo(local_res); |
|
| freeaddrinfo(server_res); |
|
| i_errno = IESTREAMCONNECT; |
|
| return -1; |
|
| } |
|
| |
|
| if (test->bind_address) { |
|
| struct sockaddr_in *lcladdr; |
|
| lcladdr = (struct sockaddr_in *)local_res->ai_addr; |
|
| lcladdr->sin_port = htons(test->bind_port); |
|
| local_res->ai_addr = (struct sockaddr *)lcladdr; |
|
| |
|
| if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { |
|
| saved_errno = errno; |
|
| close(s); |
|
| freeaddrinfo(local_res); |
|
| freeaddrinfo(server_res); |
|
| errno = saved_errno; |
|
| i_errno = IESTREAMCONNECT; |
|
| return -1; |
|
| } |
|
| freeaddrinfo(local_res); |
|
| } |
|
| |
|
| /* Set socket options */ |
/* Set socket options */ |
| if (test->no_delay) { |
if (test->no_delay) { |
| opt = 1; |
opt = 1; |
|
Line 416 iperf_tcp_connect(struct iperf_test *test)
|
Line 421 iperf_tcp_connect(struct iperf_test *test)
|
| return -1; |
return -1; |
| } |
} |
| } |
} |
| if (test->debug) { | #if defined(HAVE_TCP_USER_TIMEOUT) |
| socklen_t optlen = sizeof(opt); | if ((opt = test->settings->snd_timeout)) { |
| if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) { | if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) { |
| saved_errno = errno; |
saved_errno = errno; |
| close(s); |
close(s); |
| freeaddrinfo(server_res); |
freeaddrinfo(server_res); |
| errno = saved_errno; |
errno = saved_errno; |
| i_errno = IESETBUF; | i_errno = IESETUSERTIMEOUT; |
| return -1; | return -1; |
| } | } |
| printf("SO_SNDBUF is %u\n", opt); | |
| } |
} |
| |
#endif /* HAVE_TCP_USER_TIMEOUT */ |
| |
|
| |
/* Read back and verify the sender socket buffer size */ |
| |
optlen = sizeof(sndbuf_actual); |
| |
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { |
| |
saved_errno = errno; |
| |
close(s); |
| |
freeaddrinfo(server_res); |
| |
errno = saved_errno; |
| |
i_errno = IESETBUF; |
| |
return -1; |
| |
} |
| |
if (test->debug) { |
| |
printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize); |
| |
} |
| |
if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) { |
| |
i_errno = IESETBUF2; |
| |
return -1; |
| |
} |
| |
|
| |
/* Read back and verify the receiver socket buffer size */ |
| |
optlen = sizeof(rcvbuf_actual); |
| |
if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) { |
| |
saved_errno = errno; |
| |
close(s); |
| |
freeaddrinfo(server_res); |
| |
errno = saved_errno; |
| |
i_errno = IESETBUF; |
| |
return -1; |
| |
} |
| |
if (test->debug) { |
| |
printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize); |
| |
} |
| |
if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) { |
| |
i_errno = IESETBUF2; |
| |
return -1; |
| |
} |
| |
|
| |
if (test->json_output) { |
| |
cJSON *sock_bufsize_item = cJSON_GetObjectItem(test->json_start, "sock_bufsize"); |
| |
if (sock_bufsize_item == NULL) { |
| |
cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize); |
| |
} |
| |
|
| |
cJSON *sndbuf_actual_item = cJSON_GetObjectItem(test->json_start, "sndbuf_actual"); |
| |
if (sndbuf_actual_item == NULL) { |
| |
cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual); |
| |
} |
| |
|
| |
cJSON *rcvbuf_actual_item = cJSON_GetObjectItem(test->json_start, "rcvbuf_actual"); |
| |
if (rcvbuf_actual_item == NULL) { |
| |
cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual); |
| |
} |
| |
} |
| |
|
| #if defined(HAVE_FLOWLABEL) |
#if defined(HAVE_FLOWLABEL) |
| if (test->settings->flowlabel) { |
if (test->settings->flowlabel) { |
| if (server_res->ai_addr->sa_family != AF_INET6) { |
if (server_res->ai_addr->sa_family != AF_INET6) { |
|
Line 447 iperf_tcp_connect(struct iperf_test *test)
|
Line 506 iperf_tcp_connect(struct iperf_test *test)
|
| freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL); |
freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL); |
| freq->flr_action = IPV6_FL_A_GET; |
freq->flr_action = IPV6_FL_A_GET; |
| freq->flr_flags = IPV6_FL_F_CREATE; |
freq->flr_flags = IPV6_FL_F_CREATE; |
| freq->flr_share = IPV6_FL_F_CREATE | IPV6_FL_S_EXCL; | freq->flr_share = IPV6_FL_S_ANY; |
| memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16); |
memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16); |
| |
|
| if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) { |
if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) { |
|
Line 468 iperf_tcp_connect(struct iperf_test *test)
|
Line 527 iperf_tcp_connect(struct iperf_test *test)
|
| errno = saved_errno; |
errno = saved_errno; |
| i_errno = IESETFLOW; |
i_errno = IESETFLOW; |
| return -1; |
return -1; |
| } | } |
| } |
} |
| } |
} |
| #endif /* HAVE_FLOWLABEL */ |
#endif /* HAVE_FLOWLABEL */ |
| |
|
| #if defined(HAVE_TCP_CONGESTION) |
|
| if (test->congestion) { |
|
| if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) { |
|
| close(s); |
|
| freeaddrinfo(server_res); |
|
| i_errno = IESETCONGESTION; |
|
| return -1; |
|
| } |
|
| } |
|
| #endif /* HAVE_TCP_CONGESTION */ |
|
| |
|
| #if defined(HAVE_SO_MAX_PACING_RATE) |
#if defined(HAVE_SO_MAX_PACING_RATE) |
| /* If socket pacing is available and not disabled, try it. */ | /* If socket pacing is specified try to enable it. */ |
| if (! test->no_fq_socket_pacing) { | if (test->settings->fqrate) { |
| /* Convert bits per second to bytes per second */ |
/* Convert bits per second to bytes per second */ |
| unsigned int rate = test->settings->rate / 8; | unsigned int fqrate = test->settings->fqrate / 8; |
| if (rate > 0) { | if (fqrate > 0) { |
| if (test->debug) { |
if (test->debug) { |
| printf("Socket pacing set to %u\n", rate); | printf("Setting fair-queue socket pacing to %u\n", fqrate); |
| } |
} |
| if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) { | if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) { |
| warning("Unable to set socket pacing, using application pacing instead"); | warning("Unable to set socket pacing"); |
| test->no_fq_socket_pacing = 1; | |
| } |
} |
| } |
} |
| } |
} |
| #endif /* HAVE_SO_MAX_PACING_RATE */ |
#endif /* HAVE_SO_MAX_PACING_RATE */ |
| |
{ |
| |
unsigned int rate = test->settings->rate / 8; |
| |
if (rate > 0) { |
| |
if (test->debug) { |
| |
printf("Setting application pacing to %u\n", rate); |
| |
} |
| |
} |
| |
} |
| |
|
| |
/* Set common socket options */ |
| |
iperf_common_sockopts(test, s); |
| |
|
| if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { |
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) { |
| saved_errno = errno; |
saved_errno = errno; |