2009-11-02 22:43:19 +00:00
|
|
|
/*
|
2016-05-26 09:47:48 -07:00
|
|
|
* iperf, Copyright (c) 2014, 2016, The Regents of the University of
|
2014-09-29 14:00:46 -07:00
|
|
|
* California, through Lawrence Berkeley National Laboratory (subject
|
|
|
|
* to receipt of any required approvals from the U.S. Dept. of
|
|
|
|
* Energy). All rights reserved.
|
2011-04-20 20:33:09 +00:00
|
|
|
*
|
2014-09-29 14:00:46 -07:00
|
|
|
* If you have questions about your rights to use or distribute this
|
|
|
|
* software, please contact Berkeley Lab's Technology Transfer
|
|
|
|
* Department at TTD@lbl.gov.
|
|
|
|
*
|
|
|
|
* NOTICE. This software is owned by the U.S. Department of Energy.
|
|
|
|
* As such, the U.S. Government has been granted for itself and others
|
|
|
|
* acting on its behalf a paid-up, nonexclusive, irrevocable,
|
|
|
|
* worldwide license in the Software to reproduce, prepare derivative
|
|
|
|
* works, and perform publicly and display publicly. Beginning five
|
|
|
|
* (5) years after the date permission to assert copyright is obtained
|
|
|
|
* from the U.S. Department of Energy, and subject to any subsequent
|
|
|
|
* five (5) year renewals, the U.S. Government is granted for itself
|
|
|
|
* and others acting on its behalf a paid-up, nonexclusive,
|
|
|
|
* irrevocable, worldwide license in the Software to reproduce,
|
|
|
|
* prepare derivative works, distribute copies to the public, perform
|
|
|
|
* publicly and display publicly, and to permit others to do so.
|
|
|
|
*
|
|
|
|
* This code is distributed under a BSD style license, see the LICENSE
|
|
|
|
* file for complete information.
|
2009-11-02 22:43:19 +00:00
|
|
|
*/
|
2014-04-14 13:33:33 -07:00
|
|
|
#include "iperf_config.h"
|
2009-11-02 22:43:19 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <sys/time.h>
|
2010-07-22 23:26:38 +00:00
|
|
|
#include <sys/select.h>
|
2009-11-02 22:43:19 +00:00
|
|
|
|
|
|
|
#include "iperf.h"
|
|
|
|
#include "iperf_api.h"
|
|
|
|
#include "iperf_tcp.h"
|
|
|
|
#include "net.h"
|
|
|
|
|
2014-04-10 11:20:36 -07:00
|
|
|
#if defined(HAVE_FLOWLABEL)
|
2013-12-12 09:21:36 -08:00
|
|
|
#include "flowlabel.h"
|
2014-04-10 11:20:36 -07:00
|
|
|
#endif /* HAVE_FLOWLABEL */
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
/* iperf_tcp_recv
|
2009-11-02 22:43:19 +00:00
|
|
|
*
|
2010-07-22 18:57:08 +00:00
|
|
|
* receives the data for TCP
|
2009-11-02 22:43:19 +00:00
|
|
|
*/
|
|
|
|
int
|
2010-07-22 23:26:38 +00:00
|
|
|
iperf_tcp_recv(struct iperf_stream *sp)
|
2009-11-02 22:43:19 +00:00
|
|
|
{
|
2013-02-22 15:54:05 -08:00
|
|
|
int r;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
|
2010-07-22 18:57:08 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2010-07-22 18:57:08 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
sp->result->bytes_received += r;
|
|
|
|
sp->result->bytes_received_this_interval += r;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
return r;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
/* iperf_tcp_send
|
2009-11-02 22:43:19 +00:00
|
|
|
*
|
2010-07-22 18:57:08 +00:00
|
|
|
* sends the data for TCP
|
2009-11-02 22:43:19 +00:00
|
|
|
*/
|
|
|
|
int
|
2010-07-22 23:26:38 +00:00
|
|
|
iperf_tcp_send(struct iperf_stream *sp)
|
2009-11-02 22:43:19 +00:00
|
|
|
{
|
2013-02-22 15:54:05 -08:00
|
|
|
int r;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2013-03-04 15:55:16 -08:00
|
|
|
if (sp->test->zerocopy)
|
|
|
|
r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);
|
|
|
|
else
|
|
|
|
r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
|
2010-07-22 18:57:08 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2009-11-02 23:56:55 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
sp->result->bytes_sent += r;
|
|
|
|
sp->result->bytes_sent_this_interval += r;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2013-02-22 15:54:05 -08:00
|
|
|
return r;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
|
|
|
|
/* iperf_tcp_accept
|
2009-11-02 22:43:19 +00:00
|
|
|
*
|
2010-07-22 18:57:08 +00:00
|
|
|
* accept a new TCP stream connection
|
2009-11-02 22:43:19 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
iperf_tcp_accept(struct iperf_test * test)
|
|
|
|
{
|
2010-07-22 18:57:08 +00:00
|
|
|
int s;
|
2013-08-16 13:19:42 -07:00
|
|
|
signed char rbuf = ACCESS_DENIED;
|
2010-07-22 18:57:08 +00:00
|
|
|
char cookie[COOKIE_SIZE];
|
2009-11-02 22:43:19 +00:00
|
|
|
socklen_t len;
|
2013-05-02 15:28:30 -07:00
|
|
|
struct sockaddr_storage addr;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
|
|
|
len = sizeof(addr);
|
2010-07-22 23:26:38 +00:00
|
|
|
if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESTREAMCONNECT;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-06-21 15:08:47 +00:00
|
|
|
}
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
|
|
|
|
i_errno = IERECVCOOKIE;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2010-07-23 18:39:14 +00:00
|
|
|
if (strcmp(test->cookie, cookie) != 0) {
|
2013-11-06 11:05:46 -08:00
|
|
|
if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESENDMESSAGE;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
close(s);
|
|
|
|
}
|
|
|
|
|
2012-12-11 22:29:26 -08:00
|
|
|
return s;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* iperf_tcp_listen
|
|
|
|
*
|
|
|
|
* start up a listener for TCP stream connections
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
iperf_tcp_listen(struct iperf_test *test)
|
|
|
|
{
|
2010-07-27 17:32:21 +00:00
|
|
|
struct addrinfo hints, *res;
|
|
|
|
char portstr[6];
|
2013-03-29 17:49:27 -07:00
|
|
|
int s, opt;
|
2013-12-13 19:57:52 -08:00
|
|
|
int saved_errno;
|
2013-03-29 17:49:27 -07:00
|
|
|
|
2010-07-22 23:26:38 +00:00
|
|
|
s = test->listener;
|
2010-07-22 18:57:08 +00:00
|
|
|
|
2014-08-01 16:24:14 -07:00
|
|
|
/*
|
|
|
|
* If certain parameters are specified (such as socket buffer
|
|
|
|
* size), then throw away the listening socket (the one for which
|
|
|
|
* we just accepted the control connection) and recreate it with
|
|
|
|
* those parameters. That way, when new data connections are
|
|
|
|
* set, they'll have all the correct parameters in place.
|
|
|
|
*
|
|
|
|
* It's not clear whether this is a requirement or a convenience.
|
|
|
|
*/
|
2010-08-02 22:45:53 +00:00
|
|
|
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
|
2010-07-22 18:57:08 +00:00
|
|
|
FD_CLR(s, &test->read_set);
|
|
|
|
close(s);
|
2013-03-29 17:49:27 -07:00
|
|
|
|
|
|
|
snprintf(portstr, 6, "%d", test->server_port);
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
2014-08-01 16:24:14 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If binding to the wildcard address with no explicit address
|
|
|
|
* family specified, then force us to get an AF_INET6 socket.
|
|
|
|
* More details in the comments in netanounce().
|
|
|
|
*/
|
|
|
|
if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
|
|
|
|
hints.ai_family = AF_INET6;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
hints.ai_family = test->settings->domain;
|
|
|
|
}
|
2013-03-29 17:49:27 -07:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESTREAMLISTEN;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
2013-03-29 17:49:27 -07:00
|
|
|
|
|
|
|
if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
|
2013-11-09 14:23:36 -08:00
|
|
|
freeaddrinfo(res);
|
2013-03-29 17:49:27 -07:00
|
|
|
i_errno = IESTREAMLISTEN;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
if (test->no_delay) {
|
|
|
|
opt = 1;
|
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESETNODELAY;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// XXX: Setting MSS is very buggy!
|
2010-07-23 18:39:14 +00:00
|
|
|
if ((opt = test->settings->mss)) {
|
2010-07-22 18:57:08 +00:00
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESETMSS;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-02 22:45:53 +00:00
|
|
|
if ((opt = test->settings->socket_bufsize)) {
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-08-02 22:45:53 +00:00
|
|
|
i_errno = IESETBUF;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-08-02 22:45:53 +00:00
|
|
|
}
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-08-02 22:45:53 +00:00
|
|
|
i_errno = IESETBUF;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-08-02 22:45:53 +00:00
|
|
|
}
|
|
|
|
}
|
2014-03-06 15:11:25 -08:00
|
|
|
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);
|
|
|
|
}
|
2016-05-26 09:47:48 -07:00
|
|
|
#if defined(HAVE_SO_MAX_PACING_RATE)
|
|
|
|
/* If socket pacing is available and not disabled, try it. */
|
|
|
|
if (! test->no_fq_socket_pacing) {
|
|
|
|
/* Convert bits per second to bytes per second */
|
|
|
|
unsigned int rate = test->settings->rate / 8;
|
|
|
|
if (rate > 0) {
|
|
|
|
if (test->debug) {
|
|
|
|
printf("Setting fair-queue socket pacing to %u\n", rate);
|
|
|
|
}
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
|
|
|
|
warning("Unable to set socket pacing, using application pacing instead");
|
|
|
|
test->no_fq_socket_pacing = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SO_MAX_PACING_RATE */
|
2010-07-22 18:57:08 +00:00
|
|
|
opt = 1;
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IEREUSEADDR;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
2014-08-01 16:24:14 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we got an IPv6 socket, figure out if it shoudl accept IPv4
|
|
|
|
* connections as well. See documentation in netannounce() for
|
|
|
|
* more details.
|
|
|
|
*/
|
2014-06-16 08:32:18 -07:00
|
|
|
#if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
|
2014-08-01 16:24:14 -07:00
|
|
|
if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
|
2013-03-29 17:49:27 -07:00
|
|
|
if (test->settings->domain == AF_UNSPEC)
|
|
|
|
opt = 0;
|
2014-08-01 16:24:14 -07:00
|
|
|
else
|
2013-03-29 17:49:27 -07:00
|
|
|
opt = 1;
|
2014-02-04 15:05:39 -08:00
|
|
|
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
|
|
(char *) &opt, sizeof(opt)) < 0) {
|
|
|
|
saved_errno = errno;
|
|
|
|
close(s);
|
|
|
|
freeaddrinfo(res);
|
|
|
|
errno = saved_errno;
|
|
|
|
i_errno = IEV6ONLY;
|
|
|
|
return -1;
|
|
|
|
}
|
2013-03-29 17:49:27 -07:00
|
|
|
}
|
2014-07-21 10:34:06 -07:00
|
|
|
#endif /* IPV6_V6ONLY */
|
2010-06-23 19:13:37 +00:00
|
|
|
|
2010-07-27 17:32:21 +00:00
|
|
|
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
close(s);
|
2013-11-09 14:23:36 -08:00
|
|
|
freeaddrinfo(res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESTREAMLISTEN;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
2010-06-21 15:08:47 +00:00
|
|
|
|
2010-07-27 17:32:21 +00:00
|
|
|
freeaddrinfo(res);
|
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
if (listen(s, 5) < 0) {
|
|
|
|
i_errno = IESTREAMLISTEN;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2010-07-22 23:26:38 +00:00
|
|
|
test->listener = s;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 22:29:26 -08:00
|
|
|
return s;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
/* iperf_tcp_connect
|
|
|
|
*
|
|
|
|
* connect to a TCP stream listener
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
iperf_tcp_connect(struct iperf_test *test)
|
|
|
|
{
|
2013-03-29 17:49:27 -07:00
|
|
|
struct addrinfo hints, *local_res, *server_res;
|
2010-07-27 17:32:21 +00:00
|
|
|
char portstr[6];
|
2013-03-29 17:49:27 -07:00
|
|
|
int s, opt;
|
2016-11-23 11:05:47 -08:00
|
|
|
socklen_t optlen;
|
2013-12-13 19:57:52 -08:00
|
|
|
int saved_errno;
|
2010-07-26 21:30:34 +00:00
|
|
|
|
|
|
|
if (test->bind_address) {
|
2010-07-27 17:32:21 +00:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
2010-07-27 20:27:34 +00:00
|
|
|
hints.ai_family = test->settings->domain;
|
2010-07-27 17:32:21 +00:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
2013-03-29 17:49:27 -07:00
|
|
|
if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
|
2010-07-26 21:30:34 +00:00
|
|
|
i_errno = IESTREAMCONNECT;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-26 21:30:34 +00:00
|
|
|
}
|
2013-03-29 17:49:27 -07:00
|
|
|
}
|
2010-07-26 21:30:34 +00:00
|
|
|
|
2013-03-29 17:49:27 -07:00
|
|
|
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) {
|
2013-11-09 14:23:36 -08:00
|
|
|
if (test->bind_address)
|
|
|
|
freeaddrinfo(local_res);
|
2013-03-29 17:49:27 -07:00
|
|
|
i_errno = IESTREAMCONNECT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
|
2013-11-09 14:23:36 -08:00
|
|
|
if (test->bind_address)
|
|
|
|
freeaddrinfo(local_res);
|
|
|
|
freeaddrinfo(server_res);
|
2013-03-29 17:49:27 -07:00
|
|
|
i_errno = IESTREAMCONNECT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (test->bind_address) {
|
2014-09-09 16:31:57 -07:00
|
|
|
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;
|
|
|
|
|
2013-03-29 17:49:27 -07:00
|
|
|
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(local_res);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-26 21:30:34 +00:00
|
|
|
i_errno = IESTREAMCONNECT;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-26 21:30:34 +00:00
|
|
|
}
|
2013-03-29 17:49:27 -07:00
|
|
|
freeaddrinfo(local_res);
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 22:45:53 +00:00
|
|
|
/* Set socket options */
|
2010-07-22 18:57:08 +00:00
|
|
|
if (test->no_delay) {
|
|
|
|
opt = 1;
|
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESETNODELAY;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
2010-07-23 18:39:14 +00:00
|
|
|
if ((opt = test->settings->mss)) {
|
2010-07-22 18:57:08 +00:00
|
|
|
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESETMSS;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
}
|
2010-08-02 22:45:53 +00:00
|
|
|
if ((opt = test->settings->socket_bufsize)) {
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-08-02 22:45:53 +00:00
|
|
|
i_errno = IESETBUF;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-08-02 22:45:53 +00:00
|
|
|
}
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-08-02 22:45:53 +00:00
|
|
|
i_errno = IESETBUF;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-08-02 22:45:53 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-23 11:05:47 -08:00
|
|
|
|
|
|
|
/* Read back and verify the sender socket buffer size */
|
|
|
|
optlen = sizeof(opt);
|
|
|
|
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
|
|
|
|
saved_errno = errno;
|
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
|
|
|
errno = saved_errno;
|
|
|
|
i_errno = IESETBUF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (test->settings->socket_bufsize && test->settings->socket_bufsize != opt) {
|
|
|
|
i_errno = IESETBUF2;
|
|
|
|
return -1;
|
|
|
|
}
|
2014-03-06 15:11:25 -08:00
|
|
|
if (test->debug) {
|
|
|
|
printf("SO_SNDBUF is %u\n", opt);
|
|
|
|
}
|
2016-11-23 11:05:47 -08:00
|
|
|
|
|
|
|
/* Read back and verify the receiver socket buffer size */
|
|
|
|
optlen = sizeof(opt);
|
|
|
|
if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, &optlen) < 0) {
|
|
|
|
saved_errno = errno;
|
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
|
|
|
errno = saved_errno;
|
|
|
|
i_errno = IESETBUF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (test->settings->socket_bufsize && test->settings->socket_bufsize != opt) {
|
|
|
|
i_errno = IESETBUF2;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (test->debug) {
|
|
|
|
printf("SO_RCVBUF is %u\n", opt);
|
|
|
|
}
|
|
|
|
|
2014-04-10 11:20:36 -07:00
|
|
|
#if defined(HAVE_FLOWLABEL)
|
2013-06-03 13:12:43 -07:00
|
|
|
if (test->settings->flowlabel) {
|
|
|
|
if (server_res->ai_addr->sa_family != AF_INET6) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2013-06-03 13:12:43 -07:00
|
|
|
i_errno = IESETFLOW;
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
struct sockaddr_in6* sa6P = (struct sockaddr_in6*) server_res->ai_addr;
|
2013-12-12 09:21:36 -08:00
|
|
|
char freq_buf[sizeof(struct in6_flowlabel_req)];
|
|
|
|
struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
|
|
|
|
int freq_len = sizeof(*freq);
|
|
|
|
|
|
|
|
memset(freq, 0, sizeof(*freq));
|
|
|
|
freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
|
|
|
|
freq->flr_action = IPV6_FL_A_GET;
|
|
|
|
freq->flr_flags = IPV6_FL_F_CREATE;
|
|
|
|
freq->flr_share = IPV6_FL_F_CREATE | IPV6_FL_S_EXCL;
|
|
|
|
memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
|
|
|
|
|
|
|
|
if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-12-12 09:21:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2013-12-12 09:21:36 -08:00
|
|
|
i_errno = IESETFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
sa6P->sin6_flowinfo = freq->flr_label;
|
|
|
|
|
|
|
|
opt = 1;
|
|
|
|
if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-12-12 09:21:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2013-12-12 09:21:36 -08:00
|
|
|
i_errno = IESETFLOW;
|
|
|
|
return -1;
|
|
|
|
}
|
2013-06-03 13:12:43 -07:00
|
|
|
}
|
|
|
|
}
|
2014-04-10 11:20:36 -07:00
|
|
|
#endif /* HAVE_FLOWLABEL */
|
2010-07-22 18:57:08 +00:00
|
|
|
|
2016-05-26 09:47:48 -07:00
|
|
|
#if defined(HAVE_SO_MAX_PACING_RATE)
|
|
|
|
/* If socket pacing is available and not disabled, try it. */
|
|
|
|
if (! test->no_fq_socket_pacing) {
|
|
|
|
/* Convert bits per second to bytes per second */
|
|
|
|
unsigned int rate = test->settings->rate / 8;
|
|
|
|
if (rate > 0) {
|
|
|
|
if (test->debug) {
|
|
|
|
printf("Socket pacing set to %u\n", rate);
|
|
|
|
}
|
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
|
|
|
|
warning("Unable to set socket pacing, using application pacing instead");
|
|
|
|
test->no_fq_socket_pacing = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SO_MAX_PACING_RATE */
|
|
|
|
|
2013-03-29 17:49:27 -07:00
|
|
|
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
|
|
|
freeaddrinfo(server_res);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESTREAMCONNECT;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 17:49:27 -07:00
|
|
|
freeaddrinfo(server_res);
|
2010-07-27 17:32:21 +00:00
|
|
|
|
2010-07-22 18:57:08 +00:00
|
|
|
/* Send cookie for verification */
|
2010-07-23 18:39:14 +00:00
|
|
|
if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
|
2013-12-13 19:57:52 -08:00
|
|
|
saved_errno = errno;
|
2013-11-09 14:23:36 -08:00
|
|
|
close(s);
|
2013-12-13 19:57:52 -08:00
|
|
|
errno = saved_errno;
|
2010-07-22 18:57:08 +00:00
|
|
|
i_errno = IESENDCOOKIE;
|
2012-12-11 22:29:26 -08:00
|
|
|
return -1;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 22:29:26 -08:00
|
|
|
return s;
|
2010-07-22 18:57:08 +00:00
|
|
|
}
|