version 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 30
|
Line 30
|
#include <errno.h> |
#include <errno.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <assert.h> |
#include <assert.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> |
Line 45
|
Line 46
|
#include "iperf_udp.h" |
#include "iperf_udp.h" |
#include "timer.h" |
#include "timer.h" |
#include "net.h" |
#include "net.h" |
|
#include "cjson.h" |
#include "portable_endian.h" |
#include "portable_endian.h" |
|
|
|
#if defined(HAVE_INTTYPES_H) |
|
# include <inttypes.h> |
|
#else |
|
# ifndef PRIu64 |
|
# if sizeof(long) == 8 |
|
# define PRIu64 "lu" |
|
# else |
|
# define PRIu64 "llu" |
|
# endif |
|
# endif |
|
#endif |
|
|
/* iperf_udp_recv |
/* iperf_udp_recv |
* |
* |
* receives the data for UDP |
* receives the data for UDP |
Line 58 iperf_udp_recv(struct iperf_stream *sp)
|
Line 72 iperf_udp_recv(struct iperf_stream *sp)
|
uint64_t pcount; |
uint64_t pcount; |
int r; |
int r; |
int size = sp->settings->blksize; |
int size = sp->settings->blksize; |
|
int first_packet = 0; |
double transit = 0, d = 0; |
double transit = 0, d = 0; |
struct timeval sent_time, arrival_time; | struct iperf_time sent_time, arrival_time, temp_time; |
|
|
r = Nread(sp->socket, sp->buffer, size, Pudp); |
r = Nread(sp->socket, sp->buffer, size, Pudp); |
|
|
Line 71 iperf_udp_recv(struct iperf_stream *sp)
|
Line 86 iperf_udp_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) { |
|
|
if (sp->test->udp_counters_64bit) { | /* |
memcpy(&sec, sp->buffer, sizeof(sec)); | * For jitter computation below, it's important to know if this |
memcpy(&usec, sp->buffer+4, sizeof(usec)); | * packet is the first packet received. |
memcpy(&pcount, sp->buffer+8, sizeof(pcount)); | */ |
sec = ntohl(sec); | if (sp->result->bytes_received == 0) { |
usec = ntohl(usec); | first_packet = 1; |
pcount = be64toh(pcount); | } |
sent_time.tv_sec = sec; | |
sent_time.tv_usec = usec; | |
} | |
else { | |
uint32_t pc; | |
memcpy(&sec, sp->buffer, sizeof(sec)); | |
memcpy(&usec, sp->buffer+4, sizeof(usec)); | |
memcpy(&pc, sp->buffer+8, sizeof(pc)); | |
sec = ntohl(sec); | |
usec = ntohl(usec); | |
pcount = ntohl(pc); | |
sent_time.tv_sec = sec; | |
sent_time.tv_usec = usec; | |
} | |
|
|
/* Out of order packets */ | sp->result->bytes_received += r; |
if (pcount >= sp->packet_count + 1) { | sp->result->bytes_received_this_interval += r; |
if (pcount > sp->packet_count + 1) { | |
sp->cnt_error += (pcount - 1) - sp->packet_count; | |
} | |
sp->packet_count = pcount; | |
} else { | |
sp->outoforder_packets++; | |
iperf_err(sp->test, "OUT OF ORDER - incoming packet = %zu and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket); | |
} | |
|
|
/* jitter measurement */ | /* Dig the various counters out of the incoming UDP packet */ |
gettimeofday(&arrival_time, NULL); | if (sp->test->udp_counters_64bit) { |
| memcpy(&sec, sp->buffer, sizeof(sec)); |
| memcpy(&usec, sp->buffer+4, sizeof(usec)); |
| memcpy(&pcount, sp->buffer+8, sizeof(pcount)); |
| sec = ntohl(sec); |
| usec = ntohl(usec); |
| pcount = be64toh(pcount); |
| sent_time.secs = sec; |
| sent_time.usecs = usec; |
| } |
| else { |
| uint32_t pc; |
| memcpy(&sec, sp->buffer, sizeof(sec)); |
| memcpy(&usec, sp->buffer+4, sizeof(usec)); |
| memcpy(&pc, sp->buffer+8, sizeof(pc)); |
| sec = ntohl(sec); |
| usec = ntohl(usec); |
| pcount = ntohl(pc); |
| sent_time.secs = sec; |
| sent_time.usecs = usec; |
| } |
|
|
transit = timeval_diff(&sent_time, &arrival_time); | if (sp->test->debug_level >= DEBUG_LEVEL_DEBUG) |
d = transit - sp->prev_transit; | fprintf(stderr, "pcount %" PRIu64 " packet_count %" PRIu64 "\n", pcount, sp->packet_count); |
if (d < 0) | |
d = -d; | |
sp->prev_transit = transit; | |
// XXX: This is NOT the way to calculate jitter | |
// J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] | |
sp->jitter += (d - sp->jitter) / 16.0; | |
|
|
if (sp->test->debug) { | /* |
fprintf(stderr, "packet_count %d\n", sp->packet_count); | * Try to handle out of order packets. The way we do this |
| * uses a constant amount of storage but might not be |
| * correct in all cases. In particular we seem to have the |
| * assumption that packets can't be duplicated in the network, |
| * because duplicate packets will possibly cause some problems here. |
| * |
| * First figure out if the sequence numbers are going forward. |
| * Note that pcount is the sequence number read from the packet, |
| * and sp->packet_count is the highest sequence number seen so |
| * far (so we're expecting to see the packet with sequence number |
| * sp->packet_count + 1 arrive next). |
| */ |
| if (pcount >= sp->packet_count + 1) { |
| |
| /* Forward, but is there a gap in sequence numbers? */ |
| if (pcount > sp->packet_count + 1) { |
| /* There's a gap so count that as a loss. */ |
| sp->cnt_error += (pcount - 1) - sp->packet_count; |
| } |
| /* Update the highest sequence number seen so far. */ |
| sp->packet_count = pcount; |
| } else { |
| |
| /* |
| * Sequence number went backward (or was stationary?!?). |
| * This counts as an out-of-order packet. |
| */ |
| sp->outoforder_packets++; |
| |
| /* |
| * If we have lost packets, then the fact that we are now |
| * seeing an out-of-order packet offsets a prior sequence |
| * number gap that was counted as a loss. So we can take |
| * away a loss. |
| */ |
| if (sp->cnt_error > 0) |
| sp->cnt_error--; |
| |
| /* Log the out-of-order packet */ |
| if (sp->test->debug) |
| fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %" PRIu64 " on stream %d", pcount, sp->packet_count + 1, sp->socket); |
| } |
| |
| /* |
| * jitter measurement |
| * |
| * This computation is based on RFC 1889 (specifically |
| * sections 6.3.1 and A.8). |
| * |
| * Note that synchronized clocks are not required since |
| * the source packet delta times are known. Also this |
| * computation does not require knowing the round-trip |
| * time. |
| */ |
| iperf_time_now(&arrival_time); |
| |
| iperf_time_diff(&arrival_time, &sent_time, &temp_time); |
| transit = iperf_time_in_secs(&temp_time); |
| |
| /* Hack to handle the first packet by initializing prev_transit. */ |
| if (first_packet) |
| sp->prev_transit = transit; |
| |
| d = transit - sp->prev_transit; |
| if (d < 0) |
| d = -d; |
| sp->prev_transit = transit; |
| sp->jitter += (d - sp->jitter) / 16.0; |
} |
} |
|
else { |
|
if (sp->test->debug) |
|
printf("Late receive, state = %d\n", sp->test->state); |
|
} |
|
|
return r; |
return r; |
} |
} |
Line 136 iperf_udp_send(struct iperf_stream *sp)
|
Line 214 iperf_udp_send(struct iperf_stream *sp)
|
{ |
{ |
int r; |
int r; |
int size = sp->settings->blksize; |
int size = sp->settings->blksize; |
struct timeval before; | struct iperf_time before; |
|
|
gettimeofday(&before, 0); | iperf_time_now(&before); |
|
|
++sp->packet_count; |
++sp->packet_count; |
|
|
Line 147 iperf_udp_send(struct iperf_stream *sp)
|
Line 225 iperf_udp_send(struct iperf_stream *sp)
|
uint32_t sec, usec; |
uint32_t sec, usec; |
uint64_t pcount; |
uint64_t pcount; |
|
|
sec = htonl(before.tv_sec); | sec = htonl(before.secs); |
usec = htonl(before.tv_usec); | 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 { |
|
|
uint32_t sec, usec, pcount; |
uint32_t sec, usec, pcount; |
|
|
sec = htonl(before.tv_sec); | sec = htonl(before.secs); |
usec = htonl(before.tv_usec); | 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_level >= DEBUG_LEVEL_DEBUG) |
|
printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent); |
|
|
return r; |
return r; |
} |
} |
|
|
Line 194 iperf_udp_send(struct iperf_stream *sp)
|
Line 282 iperf_udp_send(struct iperf_stream *sp)
|
*/ |
*/ |
|
|
/* |
/* |
|
* Set and verify socket buffer sizes. |
|
* Return 0 if no error, -1 if an error, +1 if socket buffers are |
|
* potentially too small to hold a message. |
|
*/ |
|
int |
|
iperf_udp_buffercheck(struct iperf_test *test, int s) |
|
{ |
|
int rc = 0; |
|
int sndbuf_actual, rcvbuf_actual; |
|
|
|
/* |
|
* Set socket buffer size if requested. Do this for both sending and |
|
* receiving so that we can cover both normal and --reverse operation. |
|
*/ |
|
int opt; |
|
socklen_t optlen; |
|
|
|
if ((opt = test->settings->socket_bufsize)) { |
|
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { |
|
i_errno = IESETBUF; |
|
return -1; |
|
} |
|
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { |
|
i_errno = IESETBUF; |
|
return -1; |
|
} |
|
} |
|
|
|
/* Read back and verify the sender socket buffer size */ |
|
optlen = sizeof(sndbuf_actual); |
|
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) { |
|
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; |
|
} |
|
if (test->settings->blksize > sndbuf_actual) { |
|
char str[WARN_STR_LEN]; |
|
snprintf(str, sizeof(str), |
|
"Block size %d > sending socket buffer size %d", |
|
test->settings->blksize, sndbuf_actual); |
|
warning(str); |
|
rc = 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) { |
|
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->settings->blksize > rcvbuf_actual) { |
|
char str[WARN_STR_LEN]; |
|
snprintf(str, sizeof(str), |
|
"Block size %d > receiving socket buffer size %d", |
|
test->settings->blksize, rcvbuf_actual); |
|
warning(str); |
|
rc = 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); |
|
} |
|
} |
|
|
|
return rc; |
|
} |
|
|
|
/* |
* iperf_udp_accept |
* iperf_udp_accept |
* |
* |
* Accepts a new UDP "connection" |
* Accepts a new UDP "connection" |
Line 202 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; |
|
|
/* |
/* |
* Get the current outstanding socket. This socket will be used to handle |
* Get the current outstanding socket. This socket will be used to handle |
Line 228 iperf_udp_accept(struct iperf_test *test)
|
Line 410 iperf_udp_accept(struct iperf_test *test)
|
return -1; |
return -1; |
} |
} |
|
|
|
/* Check and set socket buffer sizes */ |
|
rc = iperf_udp_buffercheck(test, s); |
|
if (rc < 0) |
|
/* error */ |
|
return rc; |
/* |
/* |
* Set socket buffer size if requested. Do this for both sending and | * If the socket buffer was too small, but it was the default |
* receiving so that we can cover both normal and --reverse operation. | * size, then try explicitly setting it to something larger. |
*/ |
*/ |
int opt; | if (rc > 0) { |
if ((opt = test->settings->socket_bufsize)) { | if (test->settings->socket_bufsize == 0) { |
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { | char str[WARN_STR_LEN]; |
i_errno = IESETBUF; | int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
return -1; | snprintf(str, sizeof(str), "Increasing socket buffer size to %d", |
} | bufsize); |
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { | warning(str); |
i_errno = IESETBUF; | test->settings->socket_bufsize = bufsize; |
return -1; | rc = iperf_udp_buffercheck(test, s); |
} | if (rc < 0) |
| 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 specified, try 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); |
|
} |
|
} |
|
} |
|
|
/* |
/* |
* 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 274 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 296 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 316 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 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)) < 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; |
} |
} |
|
|
|
/* Check and set socket buffer sizes */ |
|
rc = iperf_udp_buffercheck(test, s); |
|
if (rc < 0) |
|
/* error */ |
|
return rc; |
/* |
/* |
* Set socket buffer size if requested. Do this for both sending and | * If the socket buffer was too small, but it was the default |
* receiving so that we can cover both normal and --reverse operation. | * size, then try explicitly setting it to something larger. |
*/ |
*/ |
int opt; | if (rc > 0) { |
if ((opt = test->settings->socket_bufsize)) { | if (test->settings->socket_bufsize == 0) { |
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) { | char str[WARN_STR_LEN]; |
i_errno = IESETBUF; | int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA; |
return -1; | snprintf(str, sizeof(str), "Increasing socket buffer size to %d", |
} | bufsize); |
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) { | warning(str); |
i_errno = IESETBUF; | test->settings->socket_bufsize = bufsize; |
return -1; | rc = iperf_udp_buffercheck(test, s); |
} | if (rc < 0) |
| 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->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); |
|
} |
|
} |
|
} |
|
|
|
/* 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 371 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; |
} |
} |