|
|
| 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; |
| } | } |