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