version 1.1.1.2, 2021/03/17 00:36:46
|
version 1.1.1.3, 2023/09/27 11:14:54
|
Line 33
|
Line 33
|
#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 <netinet/tcp.h> |
|
#include <assert.h> |
#include <assert.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <string.h> |
#include <string.h> |
Line 61
|
Line 60
|
#include <poll.h> |
#include <poll.h> |
#endif /* HAVE_POLL_H */ |
#endif /* HAVE_POLL_H */ |
|
|
|
#include "iperf.h" |
#include "iperf_util.h" |
#include "iperf_util.h" |
#include "net.h" |
#include "net.h" |
#include "timer.h" |
#include "timer.h" |
|
|
|
static int nread_read_timeout = 10; |
|
static int nread_overall_timeout = 30; |
|
|
/* |
/* |
* Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this |
* 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 |
* by including "iperf.h", but net.c lives "below" this layer. Clearly the |
Line 119 timeout_connect(int s, const struct sockaddr *name, so
|
Line 122 timeout_connect(int s, const struct sockaddr *name, so
|
* Copyright: http://swtch.com/libtask/COPYRIGHT |
* Copyright: http://swtch.com/libtask/COPYRIGHT |
*/ |
*/ |
|
|
/* make connection to server */ | /* create a socket */ |
int |
int |
netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout) | create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out) |
{ |
{ |
struct addrinfo hints, *local_res, *server_res; | struct addrinfo hints, *local_res = NULL, *server_res = NULL; |
int s, saved_errno; |
int s, saved_errno; |
|
char portstr[6]; |
|
|
if (local) { |
if (local) { |
memset(&hints, 0, sizeof(hints)); |
memset(&hints, 0, sizeof(hints)); |
Line 137 netdial(int domain, int proto, const char *local, int
|
Line 141 netdial(int domain, int proto, const char *local, int
|
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 ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0) | snprintf(portstr, sizeof(portstr), "%d", port); |
| if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) { |
| if (local) |
| freeaddrinfo(local_res); |
return -1; |
return -1; |
|
} |
|
|
s = socket(server_res->ai_family, proto, 0); |
s = socket(server_res->ai_family, proto, 0); |
if (s < 0) { |
if (s < 0) { |
Line 148 netdial(int domain, int proto, const char *local, int
|
Line 156 netdial(int domain, int proto, const char *local, int
|
return -1; |
return -1; |
} |
} |
|
|
|
if (bind_dev) { |
|
#if defined(HAVE_SO_BINDTODEVICE) |
|
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, |
|
bind_dev, IFNAMSIZ) < 0) |
|
#endif // HAVE_SO_BINDTODEVICE |
|
{ |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(local_res); |
|
freeaddrinfo(server_res); |
|
errno = saved_errno; |
|
return -1; |
|
} |
|
} |
|
|
/* Bind the local address if given a name (with or without --cport) */ |
/* Bind the local address if given a name (with or without --cport) */ |
if (local) { |
if (local) { |
if (local_port) { |
if (local_port) { |
Line 189 netdial(int domain, int proto, const char *local, int
|
Line 212 netdial(int domain, int proto, const char *local, int
|
} |
} |
/* Unknown protocol */ |
/* Unknown protocol */ |
else { |
else { |
|
close(s); |
|
freeaddrinfo(server_res); |
errno = EAFNOSUPPORT; |
errno = EAFNOSUPPORT; |
return -1; |
return -1; |
} |
} |
Line 202 netdial(int domain, int proto, const char *local, int
|
Line 227 netdial(int domain, int proto, const char *local, int
|
} |
} |
} |
} |
|
|
((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port); | *server_res_out = server_res; |
| return s; |
| } |
| |
| /* make connection to server */ |
| int |
| netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout) |
| { |
| struct addrinfo *server_res = NULL; |
| int s, saved_errno; |
| |
| s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res); |
| if (s < 0) { |
| return -1; |
| } |
| |
if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { |
if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) { |
saved_errno = errno; |
saved_errno = errno; |
close(s); |
close(s); |
Line 218 netdial(int domain, int proto, const char *local, int
|
Line 258 netdial(int domain, int proto, const char *local, int
|
/***************************************************************/ |
/***************************************************************/ |
|
|
int |
int |
netannounce(int domain, int proto, const char *local, int port) | netannounce(int domain, int proto, const char *local, const char *bind_dev, int port) |
{ |
{ |
struct addrinfo hints, *res; |
struct addrinfo hints, *res; |
char portstr[6]; |
char portstr[6]; |
Line 226 netannounce(int domain, int proto, const char *local,
|
Line 266 netannounce(int domain, int proto, const char *local,
|
|
|
snprintf(portstr, 6, "%d", port); |
snprintf(portstr, 6, "%d", port); |
memset(&hints, 0, sizeof(hints)); |
memset(&hints, 0, sizeof(hints)); |
/* | /* |
* If binding to the wildcard address with no explicit address |
* If binding to the wildcard address with no explicit address |
* family specified, then force us to get an AF_INET6 socket. On |
* family specified, then force us to get an AF_INET6 socket. On |
* CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family, |
* CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family, |
Line 247 netannounce(int domain, int proto, const char *local,
|
Line 287 netannounce(int domain, int proto, const char *local,
|
hints.ai_socktype = proto; |
hints.ai_socktype = proto; |
hints.ai_flags = AI_PASSIVE; |
hints.ai_flags = AI_PASSIVE; |
if ((gerror = 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); |
if (s < 0) { |
if (s < 0) { |
Line 255 netannounce(int domain, int proto, const char *local,
|
Line 295 netannounce(int domain, int proto, const char *local,
|
return -1; |
return -1; |
} |
} |
|
|
|
if (bind_dev) { |
|
#if defined(HAVE_SO_BINDTODEVICE) |
|
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, |
|
bind_dev, IFNAMSIZ) < 0) |
|
#endif // HAVE_SO_BINDTODEVICE |
|
{ |
|
saved_errno = errno; |
|
close(s); |
|
freeaddrinfo(res); |
|
errno = saved_errno; |
|
return -1; |
|
} |
|
} |
|
|
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; |
saved_errno = errno; |
close(s); |
close(s); |
Line 278 netannounce(int domain, int proto, const char *local,
|
Line 332 netannounce(int domain, int proto, const char *local,
|
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 298 netannounce(int domain, int proto, const char *local,
|
Line 352 netannounce(int domain, int proto, const char *local,
|
} |
} |
|
|
freeaddrinfo(res); |
freeaddrinfo(res); |
| |
if (proto == SOCK_STREAM) { |
if (proto == SOCK_STREAM) { |
if (listen(s, INT_MAX) < 0) { |
if (listen(s, INT_MAX) < 0) { |
saved_errno = errno; |
saved_errno = errno; |
Line 321 Nread(int fd, char *buf, size_t count, int prot)
|
Line 375 Nread(int fd, char *buf, size_t count, int prot)
|
{ |
{ |
register ssize_t r; |
register ssize_t r; |
register size_t nleft = count; |
register size_t nleft = count; |
|
struct iperf_time ftimeout = { 0, 0 }; |
|
|
|
fd_set rfdset; |
|
struct timeval timeout = { nread_read_timeout, 0 }; |
|
|
|
/* |
|
* fd might not be ready for reading on entry. Check for this |
|
* (with timeout) first. |
|
* |
|
* This check could go inside the while() loop below, except we're |
|
* currently considering whether it might make sense to support a |
|
* codepath that bypassese this check, for situations where we |
|
* already know that fd has data on it (for example if we'd gotten |
|
* to here as the result of a select() call. |
|
*/ |
|
{ |
|
FD_ZERO(&rfdset); |
|
FD_SET(fd, &rfdset); |
|
r = select(fd + 1, &rfdset, NULL, NULL, &timeout); |
|
if (r < 0) { |
|
return NET_HARDERROR; |
|
} |
|
if (r == 0) { |
|
return 0; |
|
} |
|
} |
|
|
while (nleft > 0) { |
while (nleft > 0) { |
r = read(fd, buf, nleft); |
r = read(fd, buf, nleft); |
if (r < 0) { |
if (r < 0) { |
Line 334 Nread(int fd, char *buf, size_t count, int prot)
|
Line 414 Nread(int fd, char *buf, size_t count, int prot)
|
|
|
nleft -= r; |
nleft -= r; |
buf += r; |
buf += r; |
|
|
|
/* |
|
* We need some more bytes but don't want to wait around |
|
* forever for them. In the case of partial results, we need |
|
* to be able to read some bytes every nread_timeout seconds. |
|
*/ |
|
if (nleft > 0) { |
|
struct iperf_time now; |
|
|
|
/* |
|
* Also, we have an approximate upper limit for the total time |
|
* that a Nread call is supposed to take. We trade off accuracy |
|
* of this timeout for a hopefully lower performance impact. |
|
*/ |
|
iperf_time_now(&now); |
|
if (ftimeout.secs == 0) { |
|
ftimeout = now; |
|
iperf_time_add_usecs(&ftimeout, nread_overall_timeout * 1000000L); |
|
} |
|
if (iperf_time_compare(&ftimeout, &now) < 0) { |
|
break; |
|
} |
|
|
|
FD_ZERO(&rfdset); |
|
FD_SET(fd, &rfdset); |
|
r = select(fd + 1, &rfdset, NULL, NULL, &timeout); |
|
if (r < 0) { |
|
return NET_HARDERROR; |
|
} |
|
if (r == 0) { |
|
break; |
|
} |
|
} |
} |
} |
return count - nleft; |
return count - nleft; |
} |
} |
Line 394 has_sendfile(void)
|
Line 507 has_sendfile(void)
|
int |
int |
Nsendfile(int fromfd, int tofd, const char *buf, size_t count) |
Nsendfile(int fromfd, int tofd, const char *buf, size_t count) |
{ |
{ |
off_t offset; |
|
#if defined(HAVE_SENDFILE) |
#if defined(HAVE_SENDFILE) |
|
off_t offset; |
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) |
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)) |
off_t sent; |
off_t sent; |
#endif |
#endif |