summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/Network.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Ice/Network.cpp')
-rw-r--r--cpp/src/Ice/Network.cpp247
1 files changed, 119 insertions, 128 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp
index 31a9b4a7f09..ea50982f9f8 100644
--- a/cpp/src/Ice/Network.cpp
+++ b/cpp/src/Ice/Network.cpp
@@ -32,6 +32,7 @@
#include <Ice/LocalException.h>
#include <Ice/Properties.h> // For setTcpBufSize
#include <Ice/LoggerUtil.h> // For setTcpBufSize
+#include <IceUtil/Random.h>
#if defined(ICE_OS_WINRT)
# include <IceUtil/InputUtil.h>
@@ -68,6 +69,47 @@ namespace
{
#ifndef ICE_OS_WINRT
+struct AddressIsIPv6 : public unary_function<Address, bool>
+{
+public:
+
+ bool
+ operator()(const Address& ss) const
+ {
+ return ss.saStorage.ss_family == AF_INET6;
+ }
+};
+
+struct RandomNumberGenerator : public std::unary_function<ptrdiff_t, ptrdiff_t>
+{
+ ptrdiff_t operator()(ptrdiff_t d)
+ {
+ return IceUtilInternal::random(static_cast<int>(d));
+ }
+};
+
+void
+sortAddresses(vector<Address>& addrs, ProtocolSupport protocol, Ice::EndpointSelectionType selType, bool preferIPv6)
+{
+ if(selType == Ice::Random)
+ {
+ RandomNumberGenerator rng;
+ random_shuffle(addrs.begin(), addrs.end(), rng);
+ }
+
+ if(protocol == EnableBoth)
+ {
+ if(preferIPv6)
+ {
+ stable_partition(addrs.begin(), addrs.end(), AddressIsIPv6());
+ }
+ else
+ {
+ stable_partition(addrs.begin(), addrs.end(), not1(AddressIsIPv6()));
+ }
+ }
+}
+
void
setTcpNoDelay(SOCKET fd)
{
@@ -147,122 +189,6 @@ createSocketImpl(bool udp, int family)
}
#endif
-#ifdef ICE_OS_WINRT
-Address
-getAddressImpl(const string& host, int port, ProtocolSupport, bool server)
-{
- Address addr;
- ostringstream os;
- os << port;
- addr.port = ref new String(IceUtil::stringToWstring(os.str()).c_str());
- if(host.empty())
- {
- if(server)
- {
- addr.host = nullptr; // Equivalent of inaddr_any, see doBind implementation.
- }
- else
- {
- addr.host = ref new HostName("localhost");
- }
- }
- else
- {
- addr.host = ref new HostName(ref new String(IceUtil::stringToWstring(host).c_str()));
- }
- return addr;
-}
-#else
-Address
-getAddressImpl(const string& host, int port, ProtocolSupport protocol, bool server)
-{
- Address addr;
- memset(&addr.saStorage, 0, sizeof(sockaddr_storage));
-
- //
- // We don't use getaddrinfo when host is empty as it's not portable (some old Linux
- // versions don't support it).
- //
- if(host.empty())
- {
- if(protocol == EnableIPv6)
- {
- addr.saIn6.sin6_family = AF_INET6;
- addr.saIn6.sin6_port = htons(port);
- addr.saIn6.sin6_addr = server ? in6addr_any : in6addr_loopback;
- }
- else
- {
- addr.saIn.sin_family = AF_INET;
- addr.saIn.sin_port = htons(port);
- addr.saIn.sin_addr.s_addr = server ? htonl(INADDR_ANY) : htonl(INADDR_LOOPBACK);
- }
- return addr;
- }
-
- struct addrinfo* info = 0;
- int retry = 5;
-
- struct addrinfo hints = { 0 };
-
- if(server)
- {
- //
- // If host is empty, getaddrinfo will return the wildcard
- // address instead of the loopack address.
- //
- hints.ai_flags |= AI_PASSIVE;
- }
-
- if(protocol == EnableIPv4)
- {
- hints.ai_family = PF_INET;
- }
- else if(protocol == EnableIPv6)
- {
- hints.ai_family = PF_INET6;
- }
- else
- {
- hints.ai_family = PF_UNSPEC;
- }
-
- int rs = 0;
- do
- {
- rs = getaddrinfo(host.c_str(), 0, &hints, &info);
- }
- while(info == 0 && rs == EAI_AGAIN && --retry >= 0);
-
- if(rs != 0)
- {
- DNSException ex(__FILE__, __LINE__);
- ex.error = rs;
- ex.host = host;
- throw ex;
- }
-
- memcpy(&addr.saStorage, info->ai_addr, info->ai_addrlen);
- if(info->ai_family == PF_INET)
- {
- addr.saIn.sin_port = htons(port);
- }
- else if(info->ai_family == PF_INET6)
- {
- addr.saIn6.sin6_port = htons(port);
- }
- else // Unknown address family.
- {
- freeaddrinfo(info);
- DNSException ex(__FILE__, __LINE__);
- ex.host = host;
- throw ex;
- }
- freeaddrinfo(info);
- return addr;
-}
-#endif
-
#ifndef ICE_OS_WINRT
vector<Address>
getLocalAddresses(ProtocolSupport protocol)
@@ -502,7 +428,7 @@ isWildcard(const string& host, ProtocolSupport protocol)
{
try
{
- Address addr = getAddressImpl(host, 0, protocol, false);
+ Address addr = getAddressForServer(host, 0, protocol, true);
if(addr.saStorage.ss_family == AF_INET)
{
if(addr.saIn.sin_addr.s_addr == INADDR_ANY)
@@ -647,7 +573,7 @@ IceInternal::errorToStringDNS(int error)
#ifdef ICE_OS_WINRT
vector<Address>
-IceInternal::getAddresses(const string& host, int port, ProtocolSupport, bool)
+IceInternal::getAddresses(const string& host, int port, ProtocolSupport, Ice::EndpointSelectionType, bool, bool)
{
vector<Address> result;
Address addr;
@@ -660,7 +586,8 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport, bool)
}
#else
vector<Address>
-IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol, bool blocking)
+IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol, Ice::EndpointSelectionType selType,
+ bool preferIPv6, bool blocking)
{
vector<Address> result;
Address addr;
@@ -687,6 +614,7 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol
addr.saIn.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
result.push_back(addr);
}
+ sortAddresses(result, protocol, selType, preferIPv6);
return result;
}
@@ -768,12 +696,13 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol
freeaddrinfo(info);
- if(result.size() == 0)
+ if(result.empty())
{
DNSException ex(__FILE__, __LINE__);
ex.host = host;
throw ex;
}
+ sortAddresses(result, protocol, selType, preferIPv6);
return result;
}
#endif
@@ -793,17 +722,53 @@ IceInternal::getProtocolSupport(const Address& addr)
}
#endif
+#ifdef ICE_OS_WINRT
Address
-IceInternal::getAddressForServer(const string& host, int port, ProtocolSupport protocol)
+IceInternal::getAddressForServer(const string& host, int port, ProtocolSupport, bool)
{
- return getAddressImpl(host, port, protocol, true);
+ Address addr;
+ ostringstream os;
+ os << port;
+ addr.port = ref new String(IceUtil::stringToWstring(os.str()).c_str());
+ if(host.empty())
+ {
+ addr.host = nullptr; // Equivalent of inaddr_any, see doBind implementation.
+ }
+ else
+ {
+ addr.host = ref new HostName(ref new String(IceUtil::stringToWstring(host).c_str()));
+ }
+ return addr;
}
-
+#else
Address
-IceInternal::getAddress(const string& host, int port, ProtocolSupport protocol)
+IceInternal::getAddressForServer(const string& host, int port, ProtocolSupport protocol, bool preferIPv6)
{
- return getAddressImpl(host, port, protocol, false);
+ //
+ // We don't use getaddrinfo when host is empty as it's not portable (some old Linux
+ // versions don't support it).
+ //
+ if(host.empty())
+ {
+ Address addr;
+ memset(&addr.saStorage, 0, sizeof(sockaddr_storage));
+ if(protocol != EnableIPv4)
+ {
+ addr.saIn6.sin6_family = AF_INET6;
+ addr.saIn6.sin6_port = htons(port);
+ addr.saIn6.sin6_addr = in6addr_any;
+ }
+ else
+ {
+ addr.saIn.sin_family = AF_INET;
+ addr.saIn.sin_port = htons(port);
+ addr.saIn.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ return addr;
+ }
+ return getAddresses(host, port, protocol, Ice::Ordered, preferIPv6, true)[0];
}
+#endif
int
IceInternal::compareAddress(const Address& addr1, const Address& addr2)
@@ -885,6 +850,32 @@ IceInternal::createSocket(bool udp, const Address& addr)
}
#endif
+#ifndef ICE_OS_WINRT
+SOCKET
+IceInternal::createServerSocket(bool udp, const Address& addr, ProtocolSupport protocol)
+{
+ SOCKET fd = createSocket(udp, addr);
+ if(addr.saStorage.ss_family == AF_INET6 && protocol != EnableIPv4)
+ {
+ int flag = protocol == EnableIPv6 ? 1 : 0;
+ if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+ return fd;
+}
+#else
+SOCKET
+IceInternal::createServerSocket(bool udp, const Address& addr, ProtocolSupport)
+{
+ return createSocket(udp, addr);
+}
+#endif
+
void
IceInternal::closeSocketNoThrow(SOCKET fd)
{
@@ -1109,7 +1100,7 @@ vector<string>
IceInternal::getHostsForEndpointExpand(const string& host, ProtocolSupport protocolSupport, bool includeLoopback)
{
vector<string> hosts;
- if(host.empty() || isWildcard(host, protocolSupport))
+ if(isWildcard(host, protocolSupport))
{
vector<Address> addrs = getLocalAddresses(protocolSupport);
for(vector<Address>::const_iterator p = addrs.begin(); p != addrs.end(); ++p)
@@ -1471,7 +1462,7 @@ IceInternal::setMcastGroup(SOCKET fd, const Address& group, const string& intf)
mreq.imr_interface = getInterfaceAddress(intf);
if(mreq.imr_interface.s_addr == INADDR_ANY)
{
- Address addr = getAddressForServer(intf, 0, EnableIPv4);
+ Address addr = getAddressForServer(intf, 0, EnableIPv4, false);
mreq.imr_interface = addr.saIn.sin_addr;
}
}
@@ -1546,7 +1537,7 @@ IceInternal::setMcastInterface(SOCKET fd, const string& intf, const Address& add
struct in_addr iface = getInterfaceAddress(intf);
if(iface.s_addr == INADDR_ANY)
{
- Address addr = getAddressForServer(intf, 0, EnableIPv4);
+ Address addr = getAddressForServer(intf, 0, EnableIPv4, false);
iface = addr.saIn.sin_addr;
}
rc = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, int(sizeof(iface)));