|
|
@@ -399,125 +399,122 @@ int TcpSocket::getSockPort(int sock) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly, |
|
|
|
int sock, bool close_) : closeFd(close_) |
|
|
|
static int bindIPv6 (const char *listenaddr, |
|
|
|
int port, |
|
|
|
bool localhostOnly) |
|
|
|
{ |
|
|
|
if (sock != -1) { |
|
|
|
fd = sock; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
bool use_ipv6; |
|
|
|
int af; |
|
|
|
#ifdef HAVE_GETADDRINFO |
|
|
|
use_ipv6 = true; |
|
|
|
af = AF_INET6; |
|
|
|
struct sockaddr_in6 addr6; |
|
|
|
socklen_t sa_len; |
|
|
|
int fd; |
|
|
|
|
|
|
|
if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) |
|
|
|
return -1; |
|
|
|
|
|
|
|
#ifdef IPV6_V6ONLY |
|
|
|
// - We made an IPv6-capable socket, and we need it to do IPv4 too |
|
|
|
int opt = 0; |
|
|
|
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof(opt)); |
|
|
|
#else |
|
|
|
use_ipv6 = false; |
|
|
|
af = AF_INET; |
|
|
|
vlog.error("IPV6_V6ONLY support is missing. " |
|
|
|
"IPv4 clients may not be able to connect."); |
|
|
|
#endif |
|
|
|
|
|
|
|
initSockets(); |
|
|
|
if ((fd = socket(af, SOCK_STREAM, 0)) < 0) { |
|
|
|
// - Socket creation failed |
|
|
|
if (use_ipv6) { |
|
|
|
// - Trying to make an IPv6-capable socket failed - try again, IPv4-only |
|
|
|
use_ipv6 = false; |
|
|
|
af = AF_INET; |
|
|
|
fd = socket(af, SOCK_STREAM, 0); |
|
|
|
memset(&addr6, 0, (sa_len = sizeof(addr6))); |
|
|
|
addr6.sin6_family = AF_INET6; |
|
|
|
addr6.sin6_port = htons(port); |
|
|
|
|
|
|
|
if (localhostOnly) |
|
|
|
addr6.sin6_addr = in6addr_loopback; |
|
|
|
else if (listenaddr != NULL) { |
|
|
|
#ifdef HAVE_INET_PTON |
|
|
|
if (inet_pton(AF_INET6, listenaddr, &addr6.sin6_addr) != 1) { |
|
|
|
closesocket(fd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (fd < 0) |
|
|
|
throw SocketException("unable to create listening socket", errorNumber); |
|
|
|
} else { |
|
|
|
// - Socket creation succeeded |
|
|
|
if (use_ipv6) { |
|
|
|
#ifdef IPV6_V6ONLY |
|
|
|
// - We made an IPv6-capable socket, and we need it to do IPv4 too |
|
|
|
int opt = 0; |
|
|
|
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof(opt)); |
|
|
|
#else |
|
|
|
vlog.error("IPV6_V6ONLY support is missing. " |
|
|
|
"IPv4 clients may not be able to connect."); |
|
|
|
// Unable to parse without inet_pton |
|
|
|
closesocket(fd); |
|
|
|
return -1; |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef WIN32 |
|
|
|
// - By default, close the socket on exec() |
|
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC); |
|
|
|
|
|
|
|
int one = 1; |
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, |
|
|
|
(char *)&one, sizeof(one)) < 0) { |
|
|
|
int e = errorNumber; |
|
|
|
if (bind(fd, (struct sockaddr *) &addr6, sa_len) == -1) { |
|
|
|
closesocket(fd); |
|
|
|
throw SocketException("unable to create listening socket", e); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// - Bind it to the desired port |
|
|
|
return fd; |
|
|
|
#else |
|
|
|
return -1; |
|
|
|
#endif /* HAVE_GETADDRINFO */ |
|
|
|
} |
|
|
|
|
|
|
|
static int bindIPv4 (const char *listenaddr, |
|
|
|
int port, |
|
|
|
bool localhostOnly) |
|
|
|
{ |
|
|
|
struct sockaddr_in addr; |
|
|
|
#ifdef HAVE_GETADDRINFO |
|
|
|
struct sockaddr_in6 addr6; |
|
|
|
#endif |
|
|
|
struct sockaddr *sa; |
|
|
|
int sa_len; |
|
|
|
socklen_t sa_len; |
|
|
|
int fd; |
|
|
|
|
|
|
|
#ifdef HAVE_GETADDRINFO |
|
|
|
if (use_ipv6) { |
|
|
|
memset(&addr6, 0, (sa_len = sizeof(addr6))); |
|
|
|
addr6.sin6_family = af; |
|
|
|
addr6.sin6_port = htons(port); |
|
|
|
|
|
|
|
if (localhostOnly) |
|
|
|
addr6.sin6_addr = in6addr_loopback; |
|
|
|
else if (listenaddr != NULL) { |
|
|
|
#ifdef HAVE_INET_PTON |
|
|
|
if (inet_pton(AF_INET6, listenaddr, &addr6.sin6_addr) != 1) |
|
|
|
use_ipv6 = false; |
|
|
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) |
|
|
|
return -1; |
|
|
|
|
|
|
|
memset(&addr, 0, (sa_len = sizeof(addr))); |
|
|
|
addr.sin_family = AF_INET; |
|
|
|
addr.sin_port = htons(port); |
|
|
|
|
|
|
|
if (localhostOnly) |
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
|
|
|
else if (listenaddr != NULL) { |
|
|
|
#ifdef HAVE_INET_ATON |
|
|
|
if (inet_aton(listenaddr, &addr.sin_addr) == 0) |
|
|
|
#else |
|
|
|
// Unable to parse without inet_pton |
|
|
|
use_ipv6 = false; |
|
|
|
/* Some systems (e.g. Windows) do not have inet_aton, sigh */ |
|
|
|
if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE) |
|
|
|
#endif |
|
|
|
} |
|
|
|
{ |
|
|
|
closesocket(fd); |
|
|
|
throw Exception("invalid network interface address: %s", listenaddr); |
|
|
|
} |
|
|
|
} else |
|
|
|
/* Bind to 0.0.0.0 by default. */ |
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY); |
|
|
|
|
|
|
|
if (use_ipv6) |
|
|
|
sa = (struct sockaddr *)&addr6; |
|
|
|
if (bind(fd, (struct sockaddr *) &addr, sa_len) == -1) { |
|
|
|
closesocket(fd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
if (!use_ipv6) { |
|
|
|
memset(&addr, 0, (sa_len = sizeof(addr))); |
|
|
|
addr.sin_family = af; |
|
|
|
addr.sin_port = htons(port); |
|
|
|
return fd; |
|
|
|
} |
|
|
|
|
|
|
|
if (localhostOnly) { |
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
|
|
|
} else if (listenaddr != NULL) { |
|
|
|
#ifdef HAVE_INET_ATON |
|
|
|
if (inet_aton(listenaddr, &addr.sin_addr) == 0) |
|
|
|
#else |
|
|
|
/* Some systems (e.g. Windows) do not have inet_aton, sigh */ |
|
|
|
if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE) |
|
|
|
#endif |
|
|
|
{ |
|
|
|
closesocket(fd); |
|
|
|
throw Exception("invalid network interface address: %s", listenaddr); |
|
|
|
} |
|
|
|
} else |
|
|
|
/* Bind to 0.0.0.0 by default. */ |
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY); |
|
|
|
|
|
|
|
sa = (struct sockaddr *)&addr; |
|
|
|
TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly, |
|
|
|
int sock, bool close_) : closeFd(close_) |
|
|
|
{ |
|
|
|
if (sock != -1) { |
|
|
|
fd = sock; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
addr.sin_port = htons(port); |
|
|
|
if (bind(fd, sa, sa_len) < 0) { |
|
|
|
initSockets(); |
|
|
|
if ((fd = bindIPv6 (listenaddr, port, localhostOnly)) < 0) |
|
|
|
if ((fd = bindIPv4 (listenaddr, port, localhostOnly)) < 0) |
|
|
|
throw SocketException("unable to create listening socket", errorNumber); |
|
|
|
|
|
|
|
#ifndef WIN32 |
|
|
|
// - By default, close the socket on exec() |
|
|
|
fcntl(fd, F_SETFD, FD_CLOEXEC); |
|
|
|
|
|
|
|
int one = 1; |
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, |
|
|
|
(char *)&one, sizeof(one)) < 0) { |
|
|
|
int e = errorNumber; |
|
|
|
closesocket(fd); |
|
|
|
throw SocketException("unable to bind listening socket", e); |
|
|
|
throw SocketException("unable to create listening socket", e); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// - Set it to be a listening socket |
|
|
|
if (listen(fd, 5) < 0) { |