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-2020, 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 123 iperf_udp_recv(struct iperf_stream *sp)
|
Line 123 iperf_udp_recv(struct iperf_stream *sp)
|
sent_time.usecs = usec; |
sent_time.usecs = usec; |
} |
} |
|
|
if (sp->test->debug) | if (sp->test->debug_level >= DEBUG_LEVEL_DEBUG) |
fprintf(stderr, "pcount %" PRIu64 " packet_count %d\n", pcount, sp->packet_count); | fprintf(stderr, "pcount %" PRIu64 " packet_count %" PRIu64 "\n", pcount, sp->packet_count); |
|
|
/* |
/* |
* Try to handle out of order packets. The way we do this |
* Try to handle out of order packets. The way we do this |
Line 150 iperf_udp_recv(struct iperf_stream *sp)
|
Line 150 iperf_udp_recv(struct iperf_stream *sp)
|
sp->packet_count = pcount; |
sp->packet_count = pcount; |
} else { |
} else { |
|
|
/* | /* |
* Sequence number went backward (or was stationary?!?). |
* Sequence number went backward (or was stationary?!?). |
* This counts as an out-of-order packet. |
* This counts as an out-of-order packet. |
*/ |
*/ |
Line 164 iperf_udp_recv(struct iperf_stream *sp)
|
Line 164 iperf_udp_recv(struct iperf_stream *sp)
|
*/ |
*/ |
if (sp->cnt_error > 0) |
if (sp->cnt_error > 0) |
sp->cnt_error--; |
sp->cnt_error--; |
| |
/* Log the out-of-order packet */ |
/* Log the out-of-order packet */ |
if (sp->test->debug) | if (sp->test->debug) |
fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", pcount, sp->packet_count + 1, sp->socket); | fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %" PRIu64 " on stream %d", pcount, sp->packet_count + 1, sp->socket); |
} |
} |
|
|
/* |
/* |
Line 228 iperf_udp_send(struct iperf_stream *sp)
|
Line 228 iperf_udp_send(struct iperf_stream *sp)
|
sec = htonl(before.secs); |
sec = htonl(before.secs); |
usec = htonl(before.usecs); |
usec = htonl(before.usecs); |
pcount = htobe64(sp->packet_count); |
pcount = htobe64(sp->packet_count); |
| |
memcpy(sp->buffer, &sec, sizeof(sec)); |
memcpy(sp->buffer, &sec, sizeof(sec)); |
memcpy(sp->buffer+4, &usec, sizeof(usec)); |
memcpy(sp->buffer+4, &usec, sizeof(usec)); |
memcpy(sp->buffer+8, &pcount, sizeof(pcount)); |
memcpy(sp->buffer+8, &pcount, sizeof(pcount)); |
| |
} |
} |
else { |
else { |
|
|
Line 241 iperf_udp_send(struct iperf_stream *sp)
|
Line 241 iperf_udp_send(struct iperf_stream *sp)
|
sec = htonl(before.secs); |
sec = htonl(before.secs); |
usec = htonl(before.usecs); |
usec = htonl(before.usecs); |
pcount = htonl(sp->packet_count); |
pcount = htonl(sp->packet_count); |
| |
memcpy(sp->buffer, &sec, sizeof(sec)); |
memcpy(sp->buffer, &sec, sizeof(sec)); |
memcpy(sp->buffer+4, &usec, sizeof(usec)); |
memcpy(sp->buffer+4, &usec, sizeof(usec)); |
memcpy(sp->buffer+8, &pcount, sizeof(pcount)); |
memcpy(sp->buffer+8, &pcount, sizeof(pcount)); |
| |
} |
} |
|
|
r = Nwrite(sp->socket, sp->buffer, size, Pudp); |
r = Nwrite(sp->socket, sp->buffer, size, Pudp); |
|
|
if (r < 0) | if (r <= 0) { |
return r; | --sp->packet_count; /* Don't count messages that no data was sent from them. |
| * Allows "resending" a massage with the same numbering */ |
| if (r < 0) { |
| if (r == NET_SOFTERROR && sp->test->debug_level >= DEBUG_LEVEL_INFO) |
| printf("UDP send failed on NET_SOFTERROR. errno=%s\n", strerror(errno)); |
| return 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, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); |
|
|
return r; |
return r; |
Line 291 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
Line 298 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
*/ |
*/ |
int opt; |
int opt; |
socklen_t optlen; |
socklen_t optlen; |
| |
if ((opt = test->settings->socket_bufsize)) { |
if ((opt = test->settings->socket_bufsize)) { |
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { |
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { |
i_errno = IESETBUF; |
i_errno = IESETBUF; |
Line 317 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
Line 324 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
return -1; |
return -1; |
} |
} |
if (test->settings->blksize > sndbuf_actual) { |
if (test->settings->blksize > sndbuf_actual) { |
char str[80]; | char str[WARN_STR_LEN]; |
snprintf(str, sizeof(str), |
snprintf(str, sizeof(str), |
"Block size %d > sending socket buffer size %d", |
"Block size %d > sending socket buffer size %d", |
test->settings->blksize, sndbuf_actual); |
test->settings->blksize, sndbuf_actual); |
Line 339 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
Line 346 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
return -1; |
return -1; |
} |
} |
if (test->settings->blksize > rcvbuf_actual) { |
if (test->settings->blksize > rcvbuf_actual) { |
char str[80]; | char str[WARN_STR_LEN]; |
snprintf(str, sizeof(str), |
snprintf(str, sizeof(str), |
"Block size %d > receiving socket buffer size %d", |
"Block size %d > receiving socket buffer size %d", |
test->settings->blksize, rcvbuf_actual); |
test->settings->blksize, rcvbuf_actual); |
Line 348 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
Line 355 iperf_udp_buffercheck(struct iperf_test *test, int s)
|
} |
} |
|
|
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); |
} |
} |
|
} |
|
|
return rc; |
return rc; |
} |
} |
Line 365 int
|
Line 383 int
|
iperf_udp_accept(struct iperf_test *test) |
iperf_udp_accept(struct iperf_test *test) |
{ |
{ |
struct sockaddr_storage sa_peer; |
struct sockaddr_storage sa_peer; |
int buf; | unsigned int buf; |
socklen_t len; |
socklen_t len; |
int sz, s; |
int sz, s; |
int rc; |
int rc; |
Line 403 iperf_udp_accept(struct iperf_test *test)
|
Line 421 iperf_udp_accept(struct iperf_test *test)
|
*/ |
*/ |
if (rc > 0) { |
if (rc > 0) { |
if (test->settings->socket_bufsize == 0) { |
if (test->settings->socket_bufsize == 0) { |
|
char str[WARN_STR_LEN]; |
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
printf("Increasing socket buffer size to %d\n", | snprintf(str, sizeof(str), "Increasing socket buffer size to %d", |
bufsize); | bufsize); |
| warning(str); |
test->settings->socket_bufsize = bufsize; |
test->settings->socket_bufsize = bufsize; |
rc = iperf_udp_buffercheck(test, s); |
rc = iperf_udp_buffercheck(test, s); |
if (rc < 0) |
if (rc < 0) |
return rc; |
return rc; |
} |
} |
} |
} |
| |
#if defined(HAVE_SO_MAX_PACING_RATE) |
#if defined(HAVE_SO_MAX_PACING_RATE) |
/* If socket pacing is specified, try it. */ |
/* If socket pacing is specified, try it. */ |
if (test->settings->fqrate) { |
if (test->settings->fqrate) { |
Line 440 iperf_udp_accept(struct iperf_test *test)
|
Line 460 iperf_udp_accept(struct iperf_test *test)
|
/* |
/* |
* Create a new "listening" socket to replace the one we were using before. |
* Create a new "listening" socket to replace the one we were using before. |
*/ |
*/ |
test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); | test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port); |
if (test->prot_listener < 0) { |
if (test->prot_listener < 0) { |
i_errno = IESTREAMLISTEN; |
i_errno = IESTREAMLISTEN; |
return -1; |
return -1; |
Line 450 iperf_udp_accept(struct iperf_test *test)
|
Line 470 iperf_udp_accept(struct iperf_test *test)
|
test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd; |
test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd; |
|
|
/* Let the client know we're ready "accept" another UDP "stream" */ |
/* Let the client know we're ready "accept" another UDP "stream" */ |
buf = 987654321; /* any content will work here */ | buf = UDP_CONNECT_REPLY; |
if (write(s, &buf, sizeof(buf)) < 0) { |
if (write(s, &buf, sizeof(buf)) < 0) { |
i_errno = IESTREAMWRITE; |
i_errno = IESTREAMWRITE; |
return -1; |
return -1; |
Line 472 iperf_udp_listen(struct iperf_test *test)
|
Line 492 iperf_udp_listen(struct iperf_test *test)
|
{ |
{ |
int s; |
int s; |
|
|
if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { | if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port)) < 0) { |
i_errno = IESTREAMLISTEN; |
i_errno = IESTREAMLISTEN; |
return -1; |
return -1; |
} |
} |
Line 492 iperf_udp_listen(struct iperf_test *test)
|
Line 512 iperf_udp_listen(struct iperf_test *test)
|
int |
int |
iperf_udp_connect(struct iperf_test *test) |
iperf_udp_connect(struct iperf_test *test) |
{ |
{ |
int s, buf, sz; | int s, sz; |
| unsigned int buf; |
#ifdef SO_RCVTIMEO |
#ifdef SO_RCVTIMEO |
struct timeval tv; |
struct timeval tv; |
#endif |
#endif |
int rc; |
int rc; |
|
int i, max_len_wait_for_reply; |
|
|
/* Create and bind our local socket. */ |
/* Create and bind our local socket. */ |
if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { | if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) { |
i_errno = IESTREAMCONNECT; |
i_errno = IESTREAMCONNECT; |
return -1; |
return -1; |
} |
} |
Line 515 iperf_udp_connect(struct iperf_test *test)
|
Line 537 iperf_udp_connect(struct iperf_test *test)
|
*/ |
*/ |
if (rc > 0) { |
if (rc > 0) { |
if (test->settings->socket_bufsize == 0) { |
if (test->settings->socket_bufsize == 0) { |
|
char str[WARN_STR_LEN]; |
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
printf("Increasing socket buffer size to %d\n", | snprintf(str, sizeof(str), "Increasing socket buffer size to %d", |
bufsize); | bufsize); |
| warning(str); |
test->settings->socket_bufsize = bufsize; |
test->settings->socket_bufsize = bufsize; |
rc = iperf_udp_buffercheck(test, s); |
rc = iperf_udp_buffercheck(test, s); |
if (rc < 0) |
if (rc < 0) |
return rc; |
return rc; |
} |
} |
} |
} |
| |
#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 available and not disabled, try it. */ |
if (test->settings->fqrate) { |
if (test->settings->fqrate) { |
Line 549 iperf_udp_connect(struct iperf_test *test)
|
Line 573 iperf_udp_connect(struct iperf_test *test)
|
} |
} |
} |
} |
|
|
|
/* Set common socket options */ |
|
iperf_common_sockopts(test, s); |
|
|
#ifdef SO_RCVTIMEO |
#ifdef SO_RCVTIMEO |
/* 30 sec timeout for a case when there is a network problem. */ |
/* 30 sec timeout for a case when there is a network problem. */ |
tv.tv_sec = 30; |
tv.tv_sec = 30; |
Line 560 iperf_udp_connect(struct iperf_test *test)
|
Line 587 iperf_udp_connect(struct iperf_test *test)
|
* Write a datagram to the UDP stream to let the server know we're here. |
* Write a datagram to the UDP stream to let the server know we're here. |
* The server learns our address by obtaining its peer's address. |
* The server learns our address by obtaining its peer's address. |
*/ |
*/ |
buf = 123456789; /* this can be pretty much anything */ | buf = UDP_CONNECT_MSG; |
| if (test->debug) { |
| printf("Sending Connect message to Socket %d\n", s); |
| } |
if (write(s, &buf, sizeof(buf)) < 0) { |
if (write(s, &buf, sizeof(buf)) < 0) { |
// XXX: Should this be changed to IESTREAMCONNECT? | // XXX: Should this be changed to IESTREAMCONNECT? |
i_errno = IESTREAMWRITE; |
i_errno = IESTREAMWRITE; |
return -1; |
return -1; |
} |
} |
|
|
/* |
/* |
* Wait until the server replies back to us. | * Wait until the server replies back to us with the "accept" response. |
*/ |
*/ |
if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) { | i = 0; |
| max_len_wait_for_reply = sizeof(buf); |
| if (test->reverse) /* In reverse mode allow few packets to have the "accept" response - to handle out of order packets */ |
| max_len_wait_for_reply += MAX_REVERSE_OUT_OF_ORDER_PACKETS * test->settings->blksize; |
| do { |
| if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) { |
| i_errno = IESTREAMREAD; |
| return -1; |
| } |
| if (test->debug) { |
| printf("Connect received for Socket %d, sz=%d, buf=%x, i=%d, max_len_wait_for_reply=%d\n", s, sz, buf, i, max_len_wait_for_reply); |
| } |
| i += sz; |
| } while (buf != UDP_CONNECT_REPLY && buf != LEGACY_UDP_CONNECT_REPLY && i < max_len_wait_for_reply); |
| |
| if (buf != UDP_CONNECT_REPLY && buf != LEGACY_UDP_CONNECT_REPLY) { |
i_errno = IESTREAMREAD; |
i_errno = IESTREAMREAD; |
return -1; |
return -1; |
} |
} |