Dual-stack operation - IPv4 and IP46 in the same server.
Also added -4 flag to force IPv4.
Этот коммит содержится в:
родитель
5bafe6e6cf
Коммит
a6b3f26be1
@ -142,7 +142,6 @@ struct iperf_test
|
||||
int no_delay; /* -N option */
|
||||
int output_format; /* -O option */
|
||||
int reverse; /* -R option */
|
||||
int v6domain; /* -6 option */
|
||||
int verbose; /* -V option - verbose mode */
|
||||
int json_output; /* -J option - JSON output */
|
||||
int zerocopy; /* -Z option - use sendfile */
|
||||
|
@ -86,8 +86,11 @@ set TCP maximum segment size (MTU - 40 bytes)
|
||||
.BR -N ", " --no-delay " "
|
||||
set TCP no delay, disabling Nagle's Algorithm
|
||||
.TP
|
||||
.BR -4 ", " --version4 " "
|
||||
only use IPv4
|
||||
.TP
|
||||
.BR -6 ", " --version6 " "
|
||||
use IPv6
|
||||
only use IPv6
|
||||
.TP
|
||||
.BR -S ", " --tos " \fIn\fR"
|
||||
set the IP 'type of service'
|
||||
|
@ -327,7 +327,7 @@ iperf_on_connect(struct iperf_test *test)
|
||||
struct sockaddr_in *sa_inP;
|
||||
struct sockaddr_in6 *sa_in6P;
|
||||
socklen_t len;
|
||||
int domain, opt;
|
||||
int opt;
|
||||
|
||||
if (test->role == 'c') {
|
||||
if (test->json_output)
|
||||
@ -335,12 +335,11 @@ iperf_on_connect(struct iperf_test *test)
|
||||
else
|
||||
printf("Connecting to host %s, port %d\n", test->server_hostname, test->server_port);
|
||||
} else {
|
||||
domain = test->settings->domain;
|
||||
len = sizeof(sa);
|
||||
getpeername(test->ctrl_sck, (struct sockaddr *) &sa, &len);
|
||||
if (domain == AF_INET) {
|
||||
if (getsockdomain(test->ctrl_sck) == AF_INET) {
|
||||
sa_inP = (struct sockaddr_in *) &sa;
|
||||
inet_ntop(domain, &sa_inP->sin_addr, ipr, sizeof(ipr));
|
||||
inet_ntop(AF_INET, &sa_inP->sin_addr, ipr, sizeof(ipr));
|
||||
port = ntohs(sa_inP->sin_port);
|
||||
if (test->json_output)
|
||||
cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
|
||||
@ -348,7 +347,7 @@ iperf_on_connect(struct iperf_test *test)
|
||||
printf("Accepted connection from %s, port %d\n", ipr, port);
|
||||
} else {
|
||||
sa_in6P = (struct sockaddr_in6 *) &sa;
|
||||
inet_ntop(domain, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
|
||||
inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
|
||||
port = ntohs(sa_in6P->sin6_port);
|
||||
if (test->json_output)
|
||||
cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
|
||||
@ -434,7 +433,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
|
||||
blksize = 0;
|
||||
server_flag = client_flag = 0;
|
||||
while ((ch = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N6S:Zh", longopts, NULL)) != -1) {
|
||||
while ((ch = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N46S:Zh", longopts, NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
test->server_port = atoi(optarg);
|
||||
@ -546,6 +545,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
test->no_delay = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case '4':
|
||||
test->settings->domain = AF_INET;
|
||||
break;
|
||||
case '6':
|
||||
test->settings->domain = AF_INET6;
|
||||
break;
|
||||
@ -1113,16 +1115,16 @@ void
|
||||
connect_msg(struct iperf_stream *sp)
|
||||
{
|
||||
char ipl[INET6_ADDRSTRLEN], ipr[INET6_ADDRSTRLEN];
|
||||
int lport, rport, domain = sp->settings->domain;
|
||||
int lport, rport;
|
||||
|
||||
if (domain == AF_INET) {
|
||||
inet_ntop(domain, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
|
||||
inet_ntop(domain, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
|
||||
if (getsockdomain(sp->socket) == AF_INET) {
|
||||
inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
|
||||
inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
|
||||
lport = ntohs(((struct sockaddr_in *) &sp->local_addr)->sin_port);
|
||||
rport = ntohs(((struct sockaddr_in *) &sp->remote_addr)->sin_port);
|
||||
} else {
|
||||
inet_ntop(domain, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
|
||||
inet_ntop(domain, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
|
||||
inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
|
||||
inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
|
||||
lport = ntohs(((struct sockaddr_in6 *) &sp->local_addr)->sin6_port);
|
||||
rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
|
||||
}
|
||||
@ -1171,7 +1173,7 @@ iperf_defaults(struct iperf_test *testp)
|
||||
testp->reporter_interval = 0;
|
||||
testp->num_streams = 1;
|
||||
|
||||
testp->settings->domain = AF_INET;
|
||||
testp->settings->domain = AF_UNSPEC;
|
||||
testp->settings->unit_format = 'a';
|
||||
testp->settings->socket_bufsize = 0; /* use autotuning */
|
||||
testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
|
||||
@ -1768,7 +1770,7 @@ iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
|
||||
}
|
||||
/* Set IP TOS */
|
||||
if ((opt = test->settings->tos)) {
|
||||
if (test->settings->domain == AF_INET6) {
|
||||
if (getsockdomain(sp->socket) == AF_INET6) {
|
||||
#ifdef IPV6_TCLASS
|
||||
if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
|
||||
i_errno = IESETCOS;
|
||||
|
@ -114,18 +114,31 @@ iperf_tcp_accept(struct iperf_test * test)
|
||||
int
|
||||
iperf_tcp_listen(struct iperf_test *test)
|
||||
{
|
||||
int s, opt;
|
||||
struct addrinfo hints, *res;
|
||||
char portstr[6];
|
||||
int s, opt;
|
||||
|
||||
s = test->listener;
|
||||
|
||||
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
|
||||
FD_CLR(s, &test->read_set);
|
||||
close(s);
|
||||
if ((s = socket(test->settings->domain, SOCK_STREAM, 0)) < 0) {
|
||||
|
||||
snprintf(portstr, 6, "%d", test->server_port);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = (test->settings->domain == AF_UNSPEC ? AF_INET6 : test->settings->domain);
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
|
||||
i_errno = IESTREAMLISTEN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
|
||||
i_errno = IESTREAMLISTEN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (test->no_delay) {
|
||||
opt = 1;
|
||||
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
|
||||
@ -155,17 +168,13 @@ iperf_tcp_listen(struct iperf_test *test)
|
||||
i_errno = IEREUSEADDR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(portstr, 6, "%d", test->server_port);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = test->settings->domain;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
|
||||
i_errno = IESTREAMLISTEN;
|
||||
return -1;
|
||||
}
|
||||
if (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET6) {
|
||||
if (test->settings->domain == AF_UNSPEC)
|
||||
opt = 0;
|
||||
else if (test->settings->domain == AF_INET6)
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
|
||||
close(s);
|
||||
@ -194,31 +203,40 @@ iperf_tcp_listen(struct iperf_test *test)
|
||||
int
|
||||
iperf_tcp_connect(struct iperf_test *test)
|
||||
{
|
||||
int s, opt;
|
||||
struct addrinfo hints, *res;
|
||||
struct addrinfo hints, *local_res, *server_res;
|
||||
char portstr[6];
|
||||
|
||||
if ((s = socket(test->settings->domain, SOCK_STREAM, 0)) < 0) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
int s, opt;
|
||||
|
||||
if (test->bind_address) {
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = test->settings->domain;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(test->bind_address, NULL, &hints, &res) != 0) {
|
||||
if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
|
||||
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) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (test->bind_address) {
|
||||
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
freeaddrinfo(local_res);
|
||||
}
|
||||
|
||||
/* Set socket options */
|
||||
@ -246,22 +264,12 @@ iperf_tcp_connect(struct iperf_test *test)
|
||||
}
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = test->settings->domain;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
snprintf(portstr, 6, "%d", test->server_port);
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(test->server_hostname, portstr, &hints, &res) != 0) {
|
||||
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) {
|
||||
i_errno = IESTREAMCONNECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
freeaddrinfo(server_res);
|
||||
|
||||
/* Send cookie for verification */
|
||||
if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
|
||||
|
@ -94,7 +94,8 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
|
||||
" -B, --bind <host> bind to a specific interface or multicast address\n"
|
||||
" -M, --set-mss # set TCP maximum segment size (MTU - 40 bytes)\n"
|
||||
" -N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n"
|
||||
" -6, --version6 use IPv6\n"
|
||||
" -4, --version4 only use IPv4\n"
|
||||
" -6, --version6 only use IPv6\n"
|
||||
" -S, --tos N set the IP 'type of service'\n"
|
||||
" -Z, --zerocopy use a 'zero copy' method of sending data\n"
|
||||
|
||||
|
74
src/net.c
74
src/net.c
@ -44,45 +44,38 @@
|
||||
int
|
||||
netdial(int domain, int proto, char *local, char *server, int port)
|
||||
{
|
||||
struct addrinfo hints, *local_res, *server_res;
|
||||
int s;
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
s = socket(domain, proto, 0);
|
||||
if (s < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (local) {
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = domain;
|
||||
hints.ai_socktype = proto;
|
||||
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(local, NULL, &hints, &res) != 0)
|
||||
if (getaddrinfo(local, NULL, &hints, &local_res) != 0)
|
||||
return -1;
|
||||
|
||||
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0)
|
||||
return -1;
|
||||
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = domain;
|
||||
hints.ai_socktype = proto;
|
||||
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(server, NULL, &hints, &res) != 0)
|
||||
if (getaddrinfo(server, NULL, &hints, &server_res) != 0)
|
||||
return -1;
|
||||
|
||||
((struct sockaddr_in *) res->ai_addr)->sin_port = htons(port);
|
||||
|
||||
if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) {
|
||||
s = socket(server_res->ai_family, proto, 0);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
|
||||
if (local) {
|
||||
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0)
|
||||
return -1;
|
||||
freeaddrinfo(local_res);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);
|
||||
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS)
|
||||
return -1;
|
||||
|
||||
freeaddrinfo(server_res);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -91,26 +84,32 @@ netdial(int domain, int proto, char *local, char *server, int port)
|
||||
int
|
||||
netannounce(int domain, int proto, char *local, int port)
|
||||
{
|
||||
int s, opt;
|
||||
struct addrinfo hints, *res;
|
||||
char portstr[6];
|
||||
|
||||
s = socket(domain, proto, 0);
|
||||
if (s < 0) {
|
||||
return -1;
|
||||
}
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
|
||||
int s, opt;
|
||||
|
||||
snprintf(portstr, 6, "%d", port);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = domain;
|
||||
hints.ai_family = (domain == AF_UNSPEC ? AF_INET6 : domain);
|
||||
hints.ai_socktype = proto;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
// XXX: Check getaddrinfo for errors!
|
||||
if (getaddrinfo(local, portstr, &hints, &res) != 0)
|
||||
return -1;
|
||||
|
||||
s = socket(res->ai_family, proto, 0);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt));
|
||||
if (domain == AF_UNSPEC || domain == AF_INET6) {
|
||||
if (domain == AF_UNSPEC)
|
||||
opt = 0;
|
||||
else if (domain == AF_INET6)
|
||||
opt = 1;
|
||||
setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
|
||||
close(s);
|
||||
return -1;
|
||||
@ -357,3 +356,16 @@ setnonblocking(int fd, int nonblocking)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
int
|
||||
getsockdomain(int sock)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
socklen_t len;
|
||||
|
||||
if (getsockname(sock, &sa, &len) < 0)
|
||||
return -1;
|
||||
return sa.sa_family;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ int Nsendfile(int fromfd, int tofd, const char *buf, size_t count) /* __attribut
|
||||
int getsock_tcp_mss(int inSock);
|
||||
int set_tcp_options(int sock, int no_delay, int mss);
|
||||
int setnonblocking(int fd, int nonblocking);
|
||||
int getsockdomain(int sock);
|
||||
|
||||
#define NET_SOFTERROR -1
|
||||
#define NET_HARDERROR -2
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user