version 1.1.1.1, 2016/10/18 13:28:18
|
version 1.1.1.2, 2021/03/17 00:36:46
|
Line 1
|
Line 1
|
/* |
/* |
* iperf, Copyright (c) 2014, 2015, The Regents of the University of | * iperf, Copyright (c) 2014-2019, 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 29
|
Line 29
|
#include <stdio.h> |
#include <stdio.h> |
#include <unistd.h> |
#include <unistd.h> |
#include <errno.h> |
#include <errno.h> |
|
#include <arpa/inet.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/errno.h> |
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netinet/tcp.h> |
#include <netinet/tcp.h> |
#include <assert.h> |
#include <assert.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <string.h> |
#include <string.h> |
#include <sys/fcntl.h> | #include <fcntl.h> |
| #include <limits.h> |
|
|
#ifdef HAVE_SENDFILE |
#ifdef HAVE_SENDFILE |
#ifdef linux |
#ifdef linux |
Line 56
|
Line 57
|
#endif |
#endif |
#endif /* HAVE_SENDFILE */ |
#endif /* HAVE_SENDFILE */ |
|
|
|
#ifdef HAVE_POLL_H |
|
#include <poll.h> |
|
#endif /* HAVE_POLL_H */ |
|
|
#include "iperf_util.h" |
#include "iperf_util.h" |
#include "net.h" |
#include "net.h" |
#include "timer.h" |
#include "timer.h" |
|
|
|
/* |
|
* Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this |
|
* by including "iperf.h", but net.c lives "below" this layer. Clearly the |
|
* presence of this declaration is a sign we need to revisit this layering. |
|
*/ |
|
extern int gerror; |
|
|
|
/* |
|
* timeout_connect adapted from netcat, via OpenBSD and FreeBSD |
|
* Copyright (c) 2001 Eric Jackson <ericj@monkey.org> |
|
*/ |
|
int |
|
timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, |
|
int timeout) |
|
{ |
|
struct pollfd pfd; |
|
socklen_t optlen; |
|
int flags, optval; |
|
int ret; |
|
|
|
flags = 0; |
|
if (timeout != -1) { |
|
flags = fcntl(s, F_GETFL, 0); |
|
if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) |
|
return -1; |
|
} |
|
|
|
if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) { |
|
pfd.fd = s; |
|
pfd.events = POLLOUT; |
|
if ((ret = poll(&pfd, 1, timeout)) == 1) { |
|
optlen = sizeof(optval); |
|
if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR, |
|
&optval, &optlen)) == 0) { |
|
errno = optval; |
|
ret = optval == 0 ? 0 : -1; |
|
} |
|
} else if (ret == 0) { |
|
errno = ETIMEDOUT; |
|
ret = -1; |
|
} else |
|
ret = -1; |
|
} |
|
|
|
if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1) |
|
ret = -1; |
|
|
|
return (ret); |
|
} |
|
|
/* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ |
/* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ |
* Copyright: http://swtch.com/libtask/COPYRIGHT |
* Copyright: http://swtch.com/libtask/COPYRIGHT |
*/ |
*/ |
|
|
/* make connection to server */ |
/* make connection to server */ |
int |
int |
netdial(int domain, int proto, char *local, int local_port, char *server, int port) | netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout) |
{ |
{ |
struct addrinfo hints, *local_res, *server_res; |
struct addrinfo hints, *local_res, *server_res; |
int s; | int s, saved_errno; |
|
|
if (local) { |
if (local) { |
memset(&hints, 0, sizeof(hints)); |
memset(&hints, 0, sizeof(hints)); |
hints.ai_family = domain; |
hints.ai_family = domain; |
hints.ai_socktype = proto; |
hints.ai_socktype = proto; |
if (getaddrinfo(local, NULL, &hints, &local_res) != 0) | if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0) |
return -1; |
return -1; |
} |
} |
|
|
memset(&hints, 0, sizeof(hints)); |
memset(&hints, 0, sizeof(hints)); |
hints.ai_family = domain; |
hints.ai_family = domain; |
hints.ai_socktype = proto; |
hints.ai_socktype = proto; |
if (getaddrinfo(server, NULL, &hints, &server_res) != 0) | if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0) |
return -1; |
return -1; |
|
|
s = socket(server_res->ai_family, proto, 0); |
s = socket(server_res->ai_family, proto, 0); |
Line 93 netdial(int domain, int proto, char *local, int local_
|
Line 148 netdial(int domain, int proto, char *local, int local_
|
return -1; |
return -1; |
} |
} |
|
|
|
/* Bind the local address if given a name (with or without --cport) */ |
if (local) { |
if (local) { |
if (local_port) { |
if (local_port) { |
struct sockaddr_in *lcladdr; |
struct sockaddr_in *lcladdr; |
lcladdr = (struct sockaddr_in *)local_res->ai_addr; |
lcladdr = (struct sockaddr_in *)local_res->ai_addr; |
lcladdr->sin_port = htons(local_port); |
lcladdr->sin_port = htons(local_port); |
local_res->ai_addr = (struct sockaddr *)lcladdr; |
|
} |
} |
|
|
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { |
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) { |
|
saved_errno = errno; |
close(s); |
close(s); |
freeaddrinfo(local_res); |
freeaddrinfo(local_res); |
freeaddrinfo(server_res); |
freeaddrinfo(server_res); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
freeaddrinfo(local_res); |
freeaddrinfo(local_res); |
} |
} |
|
/* No local name, but --cport given */ |
|
else if (local_port) { |
|
size_t addrlen; |
|
struct sockaddr_storage lcl; |
|
|
|
/* IPv4 */ |
|
if (server_res->ai_family == AF_INET) { |
|
struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl; |
|
lcladdr->sin_family = AF_INET; |
|
lcladdr->sin_port = htons(local_port); |
|
lcladdr->sin_addr.s_addr = INADDR_ANY; |
|
addrlen = sizeof(struct sockaddr_in); |
|
} |
|
/* IPv6 */ |
|
else if (server_res->ai_family == AF_INET6) { |
|
struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl; |
|
lcladdr->sin6_family = AF_INET6; |
|
lcladdr->sin6_port = htons(local_port); |
|
lcladdr->sin6_addr = in6addr_any; |
|
addrlen = sizeof(struct sockaddr_in6); |
|
} |
|
/* Unknown protocol */ |
|
else { |
|
errno = EAFNOSUPPORT; |
|
return -1; |
|
} |
|
|
|
if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) { |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(server_res); |
|
errno = saved_errno; |
|
return -1; |
|
} |
|
} |
|
|
((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); |
((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) { | if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { |
| saved_errno = errno; |
close(s); |
close(s); |
freeaddrinfo(server_res); |
freeaddrinfo(server_res); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
|
|
Line 124 netdial(int domain, int proto, char *local, int local_
|
Line 218 netdial(int domain, int proto, char *local, int local_
|
/***************************************************************/ |
/***************************************************************/ |
|
|
int |
int |
netannounce(int domain, int proto, char *local, int port) | netannounce(int domain, int proto, const char *local, int port) |
{ |
{ |
struct addrinfo hints, *res; |
struct addrinfo hints, *res; |
char portstr[6]; |
char portstr[6]; |
int s, opt; | int s, opt, saved_errno; |
|
|
snprintf(portstr, 6, "%d", port); |
snprintf(portstr, 6, "%d", port); |
memset(&hints, 0, sizeof(hints)); |
memset(&hints, 0, sizeof(hints)); |
Line 152 netannounce(int domain, int proto, char *local, int po
|
Line 246 netannounce(int domain, int proto, char *local, int po
|
} |
} |
hints.ai_socktype = proto; |
hints.ai_socktype = proto; |
hints.ai_flags = AI_PASSIVE; |
hints.ai_flags = AI_PASSIVE; |
if (getaddrinfo(local, portstr, &hints, &res) != 0) | if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0) |
return -1; |
return -1; |
|
|
s = socket(res->ai_family, proto, 0); |
s = socket(res->ai_family, proto, 0); |
Line 164 netannounce(int domain, int proto, char *local, int po
|
Line 258 netannounce(int domain, int proto, char *local, int po
|
opt = 1; |
opt = 1; |
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
(char *) &opt, sizeof(opt)) < 0) { |
(char *) &opt, sizeof(opt)) < 0) { |
|
saved_errno = errno; |
close(s); |
close(s); |
freeaddrinfo(res); |
freeaddrinfo(res); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
/* |
/* |
Line 184 netannounce(int domain, int proto, char *local, int po
|
Line 280 netannounce(int domain, int proto, char *local, int po
|
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; |
close(s); |
close(s); |
freeaddrinfo(res); |
freeaddrinfo(res); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
} |
} |
#endif /* IPV6_V6ONLY */ |
#endif /* IPV6_V6ONLY */ |
|
|
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { |
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { |
|
saved_errno = errno; |
close(s); |
close(s); |
freeaddrinfo(res); |
freeaddrinfo(res); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
|
|
freeaddrinfo(res); |
freeaddrinfo(res); |
|
|
if (proto == SOCK_STREAM) { |
if (proto == SOCK_STREAM) { |
if (listen(s, 5) < 0) { | if (listen(s, INT_MAX) < 0) { |
| saved_errno = errno; |
close(s); |
close(s); |
|
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
} |
} |
Line 351 Nsendfile(int fromfd, int tofd, const char *buf, size_
|
Line 453 Nsendfile(int fromfd, int tofd, const char *buf, size_
|
} |
} |
|
|
/*************************************************************************/ |
/*************************************************************************/ |
|
|
/** |
|
* getsock_tcp_mss - Returns the MSS size for TCP |
|
* |
|
*/ |
|
|
|
int |
|
getsock_tcp_mss(int inSock) |
|
{ |
|
int mss = 0; |
|
|
|
int rc; |
|
socklen_t len; |
|
|
|
assert(inSock >= 0); /* print error and exit if this is not true */ |
|
|
|
/* query for mss */ |
|
len = sizeof(mss); |
|
rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len); |
|
if (rc == -1) { |
|
perror("getsockopt TCP_MAXSEG"); |
|
return -1; |
|
} |
|
|
|
return mss; |
|
} |
|
|
|
|
|
|
|
/*************************************************************/ |
|
|
|
/* sets TCP_NODELAY and TCP_MAXSEG if requested */ |
|
// XXX: This function is not being used. |
|
|
|
int |
|
set_tcp_options(int sock, int no_delay, int mss) |
|
{ |
|
socklen_t len; |
|
int rc; |
|
int new_mss; |
|
|
|
if (no_delay == 1) { |
|
len = sizeof(no_delay); |
|
rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len); |
|
if (rc == -1) { |
|
perror("setsockopt TCP_NODELAY"); |
|
return -1; |
|
} |
|
} |
|
#ifdef TCP_MAXSEG |
|
if (mss > 0) { |
|
len = sizeof(new_mss); |
|
assert(sock != -1); |
|
|
|
/* set */ |
|
new_mss = mss; |
|
len = sizeof(new_mss); |
|
rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len); |
|
if (rc == -1) { |
|
perror("setsockopt TCP_MAXSEG"); |
|
return -1; |
|
} |
|
/* verify results */ |
|
rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len); |
|
if (rc == -1) { |
|
perror("getsockopt TCP_MAXSEG"); |
|
return -1; |
|
} |
|
if (new_mss != mss) { |
|
perror("setsockopt value mismatch"); |
|
return -1; |
|
} |
|
} |
|
#endif |
|
return 0; |
|
} |
|
|
|
/****************************************************************************/ |
|
|
|
int |
int |
setnonblocking(int fd, int nonblocking) |
setnonblocking(int fd, int nonblocking) |