version 1.1.1.2, 2021/03/17 00:36:46
|
version 1.1.1.3, 2023/09/27 11:14:54
|
Line 1
|
Line 1
|
/* |
/* |
* iperf, Copyright (c) 2014-2019, 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 76 iperf_tcp_recv(struct iperf_stream *sp)
|
Line 76 iperf_tcp_recv(struct iperf_stream *sp)
|
} |
} |
|
|
|
|
/* iperf_tcp_send | /* iperf_tcp_send |
* |
* |
* sends the data for TCP |
* sends the data for TCP |
*/ |
*/ |
Line 85 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) | if (sp->test->debug_level >= DEBUG_LEVEL_DEBUG) |
printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); | 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 129 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 270 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 278 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 310 iperf_tcp_listen(struct iperf_test *test)
|
Line 314 iperf_tcp_listen(struct iperf_test *test)
|
|
|
test->listener = s; |
test->listener = s; |
} |
} |
| |
/* Read back and verify the sender socket buffer size */ |
/* Read back and verify the sender socket buffer size */ |
optlen = sizeof(sndbuf_actual); |
optlen = sizeof(sndbuf_actual); |
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { |
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { |
Line 365 iperf_tcp_listen(struct iperf_test *test)
|
Line 369 iperf_tcp_listen(struct iperf_test *test)
|
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; |
socklen_t optlen; |
int saved_errno; |
int saved_errno; |
int rcvbuf_actual, sndbuf_actual; |
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 ((gerror = 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 ((gerror = 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; |
|
} |
|
|
|
/* |
|
* Various ways to bind the local end of the connection. |
|
* 1. --bind (with or without --cport). |
|
*/ |
|
if (test->bind_address) { |
|
struct sockaddr_in *lcladdr; |
|
lcladdr = (struct sockaddr_in *)local_res->ai_addr; |
|
lcladdr->sin_port = htons(test->bind_port); |
|
|
|
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); |
|
} |
|
/* --cport, no --bind */ |
|
else if (test->bind_port) { |
|
size_t addrlen; |
|
struct sockaddr_storage lcl; |
|
|
|
/* IPv4 */ |
|
if (server_res->ai_family == AF_INET) { |
|
struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl; |
|
lcladdr->sin_family = AF_INET; |
|
lcladdr->sin_port = htons(test->bind_port); |
|
lcladdr->sin_addr.s_addr = INADDR_ANY; |
|
addrlen = sizeof(struct sockaddr_in); |
|
} |
|
/* IPv6 */ |
|
else if (server_res->ai_family == AF_INET6) { |
|
struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl; |
|
lcladdr->sin6_family = AF_INET6; |
|
lcladdr->sin6_port = htons(test->bind_port); |
|
lcladdr->sin6_addr = in6addr_any; |
|
addrlen = sizeof(struct sockaddr_in6); |
|
} |
|
/* Unknown protocol */ |
|
else { |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(server_res); |
|
errno = saved_errno; |
|
i_errno = IEPROTOCOL; |
|
return -1; |
|
} |
|
|
|
if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(server_res); |
|
errno = saved_errno; |
|
i_errno = IESTREAMCONNECT; |
|
return -1; |
|
} |
|
} |
|
|
|
/* Set socket options */ |
/* Set socket options */ |
if (test->no_delay) { |
if (test->no_delay) { |
opt = 1; |
opt = 1; |
Line 502 iperf_tcp_connect(struct iperf_test *test)
|
Line 421 iperf_tcp_connect(struct iperf_test *test)
|
return -1; |
return -1; |
} |
} |
} |
} |
|
#if defined(HAVE_TCP_USER_TIMEOUT) |
|
if ((opt = test->settings->snd_timeout)) { |
|
if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) { |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(server_res); |
|
errno = saved_errno; |
|
i_errno = IESETUSERTIMEOUT; |
|
return -1; |
|
} |
|
} |
|
#endif /* HAVE_TCP_USER_TIMEOUT */ |
|
|
/* Read back and verify the sender socket buffer size */ |
/* Read back and verify the sender socket buffer size */ |
optlen = sizeof(sndbuf_actual); |
optlen = sizeof(sndbuf_actual); |
Line 540 iperf_tcp_connect(struct iperf_test *test)
|
Line 471 iperf_tcp_connect(struct iperf_test *test)
|
} |
} |
|
|
if (test->json_output) { |
if (test->json_output) { |
cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize); | 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_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); |
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) { |
Line 585 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 */ |
Line 613 iperf_tcp_connect(struct iperf_test *test)
|
Line 555 iperf_tcp_connect(struct iperf_test *test)
|
} |
} |
} |
} |
} |
} |
|
|
|
/* 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; |