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.cpp933
1 files changed, 594 insertions, 339 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp
index 0bd0fa8bd4a..db66ebc4441 100644
--- a/cpp/src/Ice/Network.cpp
+++ b/cpp/src/Ice/Network.cpp
@@ -28,6 +28,7 @@
# include <ws2tcpip.h>
#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__)
# include <ifaddrs.h>
+# include <net/if.h>
#else
# include <sys/ioctl.h>
# include <net/if.h>
@@ -44,17 +45,350 @@ using namespace IceInternal;
# define INADDR_NONE (in_addr_t)0xffffffff
#endif
-static IceUtil::StaticMutex inetMutex = ICE_STATIC_MUTEX_INITIALIZER;
+namespace
+{
-string
-IceInternal::inetAddrToString(const struct in_addr& in)
+vector<struct sockaddr_storage>
+getLocalAddresses(ProtocolSupport protocol)
+{
+ vector<struct sockaddr_storage> result;
+
+#if defined(_WIN32)
+ try
+ {
+ for(int i = 0; i < 2; i++)
+ {
+ if((i == 0 && protocol == EnableIPv6) || (i == 1 && protocol == EnableIPv4))
+ {
+ continue;
+ }
+
+ SOCKET fd = createSocket(false, i == 0 ? AF_INET : AF_INET6);
+
+ vector<unsigned char> buffer;
+ buffer.resize(1024);
+ unsigned long len = 0;
+ DWORD rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0,
+ &buffer[0], static_cast<DWORD>(buffer.size()),
+ &len, 0, 0);
+ if(rs == SOCKET_ERROR)
+ {
+ //
+ // If the buffer wasn't big enough, resize it to the
+ // required length and try again.
+ //
+ if(getSocketErrno() == WSAEFAULT)
+ {
+ buffer.resize(len);
+ rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0,
+ &buffer[0], static_cast<DWORD>(buffer.size()),
+ &len, 0, 0);
+ }
+
+ if(rs == SOCKET_ERROR)
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+
+ //
+ // Add the local interface addresses.
+ //
+ SOCKET_ADDRESS_LIST* addrs = reinterpret_cast<SOCKET_ADDRESS_LIST*>(&buffer[0]);
+ for (int i = 0; i < addrs->iAddressCount; ++i)
+ {
+ sockaddr_storage addr;
+ memcpy(&addr, addrs->Address[i].lpSockaddr, addrs->Address[i].iSockaddrLength);
+ if(addr.ss_family == AF_INET && protocol != EnableIPv6)
+ {
+ if(reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr != 0)
+ {
+ result.push_back(addr);
+ }
+ }
+ else if(addr.ss_family == AF_INET6 && protocol != EnableIPv4)
+ {
+ struct in6_addr* inaddr6 = &reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr;
+ if(!IN6_IS_ADDR_UNSPECIFIED(inaddr6) && !IN6_IS_ADDR_LOOPBACK(inaddr6))
+ {
+ result.push_back(addr);
+ }
+ }
+ }
+
+ closeSocket(fd);
+ }
+ }
+ catch(const Ice::LocalException&)
+ {
+ //
+ // TODO: Warning?
+ //
+ }
+#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__)
+ struct ifaddrs* ifap;
+ if(::getifaddrs(&ifap) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ struct ifaddrs* curr = ifap;
+ while(curr != 0)
+ {
+ if(curr->ifa_addr && !(curr->ifa_flags & IFF_LOOPBACK)) // Don't include loopback interface addresses
+ {
+ if(curr->ifa_addr->sa_family == AF_INET && protocol != EnableIPv6)
+ {
+ sockaddr_storage addr;
+ memcpy(&addr, curr->ifa_addr, sizeof(sockaddr_in));
+ if(reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr != 0)
+ {
+ result.push_back(addr);
+ }
+ }
+ else if(curr->ifa_addr->sa_family == AF_INET6 && protocol != EnableIPv4)
+ {
+ sockaddr_storage addr;
+ memcpy(&addr, curr->ifa_addr, sizeof(sockaddr_in6));
+ if(!IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr))
+ {
+ result.push_back(*reinterpret_cast<struct sockaddr_storage*>(curr->ifa_addr));
+ }
+ }
+ }
+
+ curr = curr->ifa_next;
+ }
+
+ ::freeifaddrs(ifap);
+#else
+ for(int i = 0; i < 2; i++)
+ {
+ if((i == 0 && protocol == EnableIPv6) || (i == 1 && protocol == EnableIPv4))
+ {
+ continue;
+ }
+ SOCKET fd = createSocket(false, i == 0 ? AF_INET : AF_INET6);
+
+#ifdef _AIX
+ int cmd = CSIOCGIFCONF;
+#else
+ int cmd = SIOCGIFCONF;
+#endif
+ struct ifconf ifc;
+ int numaddrs = 10;
+ int old_ifc_len = 0;
+
+ //
+ // Need to call ioctl multiple times since we do not know up front
+ // how many addresses there will be, and thus how large a buffer we need.
+ // We keep increasing the buffer size until subsequent calls return
+ // the same length, meaning we have all the addresses.
+ //
+ while(true)
+ {
+ int bufsize = numaddrs * static_cast<int>(sizeof(struct ifreq));
+ ifc.ifc_len = bufsize;
+ ifc.ifc_buf = (char*)malloc(bufsize);
+
+ int rs = ioctl(fd, cmd, &ifc);
+ if(rs == SOCKET_ERROR)
+ {
+ free(ifc.ifc_buf);
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ else if(ifc.ifc_len == old_ifc_len)
+ {
+ //
+ // Returned same length twice in a row, finished.
+ //
+ break;
+ }
+ else
+ {
+ old_ifc_len = ifc.ifc_len;
+ }
+
+ numaddrs += 10;
+ free(ifc.ifc_buf);
+ }
+ closeSocket(fd);
+
+ numaddrs = ifc.ifc_len / static_cast<int>(sizeof(struct ifreq));
+ struct ifreq* ifr = ifc.ifc_req;
+ for(int i = 0; i < numaddrs; ++i)
+ {
+ if(!(ifr[i].ifr_flags & IFF_LOOPBACK)) // Don't include loopback interface addresses
+ {
+ if(ifr[i].ifr_addr.sa_family == AF_INET && protocol != EnableIPv6)
+ {
+ sockaddr_storage addr;
+ memcpy(&addr, &ifr[i].ifr_addr, sizeof(sockaddr_in));
+ if(reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr != 0)
+ {
+ result.push_back(addr);
+ }
+ }
+ else if(ifr[i].ifr_addr.sa_family == AF_INET6 && protocol != EnableIPv4)
+ {
+ sockaddr_storage addr;
+ memcpy(&addr, &ifr[i].ifr_addr, sizeof(sockaddr_in6));
+ if(!IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr))
+ {
+ result.push_back(*reinterpret_cast<struct sockaddr_storage*>(curr->ifa_addr));
+ }
+ }
+ }
+ }
+ free(ifc.ifc_buf);
+ }
+#endif
+
+ return result;
+}
+
+void
+getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, ProtocolSupport protocol, bool server)
{
//
- // inet_ntoa uses static memory on some platforms so we protect
- // access and make a copy.
+ // We now use getaddrinfo() on Windows.
//
- IceUtil::StaticMutex::Lock lock(inetMutex);
- return string(inet_ntoa(in));
+// #ifdef _WIN32
+
+// //
+// // Windows XP has getaddrinfo(), but we don't want to require XP to run Ice.
+// //
+
+// //
+// // gethostbyname() is thread safe on Windows, with a separate hostent per thread
+// //
+// struct hostent* entry;
+// int retry = 5;
+// do
+// {
+// entry = gethostbyname(host.c_str());
+// }
+// while(entry == 0 && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
+
+// if(entry == 0)
+// {
+// DNSException ex(__FILE__, __LINE__);
+
+// ex.error = WSAGetLastError();
+// ex.host = host;
+// throw ex;
+// }
+// memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
+
+// #else
+
+ memset(&addr, 0, sizeof(struct sockaddr_storage));
+ 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
+ {
+ if(host.empty())
+ {
+ rs = getaddrinfo(0, "0", &hints, &info);
+ }
+ else
+ {
+ 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, info->ai_addr, info->ai_addrlen);
+ if(info->ai_family != PF_INET)
+ {
+ reinterpret_cast<sockaddr_in*>(&addr)->sin_port = htons(port);
+ }
+ else if(info->ai_family != AF_INET6)
+ {
+ reinterpret_cast<sockaddr_in6*>(&addr)->sin6_port = htons(port);
+ }
+ else // Unknown address family.
+ {
+ freeaddrinfo(info);
+ DNSException ex(__FILE__, __LINE__);
+ ex.host = host;
+ throw ex;
+ }
+ freeaddrinfo(info);
+}
+
+bool
+isWildcard(const string& host, ProtocolSupport protocol)
+{
+ try
+ {
+ sockaddr_storage addr;
+ getAddressImpl(host, 0, addr, protocol, false);
+ if(addr.ss_family == AF_INET)
+ {
+ struct sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
+ if(addrin->sin_addr.s_addr == INADDR_ANY)
+ {
+ return true;
+ }
+ }
+ else if(addr.ss_family)
+ {
+ struct sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
+ if(IN6_IS_ADDR_UNSPECIFIED(&addrin6->sin6_addr))
+ {
+ return true;
+ }
+ }
+ }
+ catch(const DNSException&)
+ {
+ }
+ return false;
+}
+
}
int
@@ -209,17 +543,17 @@ IceInternal::recvTruncated()
}
SOCKET
-IceInternal::createSocket(bool udp)
+IceInternal::createSocket(bool udp, int family)
{
SOCKET fd;
if(udp)
{
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
}
else
{
- fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
}
if(fd == INVALID_SOCKET)
@@ -533,9 +867,19 @@ IceInternal::setReuseAddress(SOCKET fd, bool reuse)
}
void
-IceInternal::doBind(SOCKET fd, struct sockaddr_in& addr)
+IceInternal::doBind(SOCKET fd, struct sockaddr_storage& addr)
{
- if(bind(fd, reinterpret_cast<struct sockaddr*>(&addr), int(sizeof(addr))) == SOCKET_ERROR)
+ int size;
+ if(addr.ss_family == AF_INET)
+ {
+ size = sizeof(sockaddr_in);
+ }
+ else if(addr.ss_family == AF_INET6)
+ {
+ size = sizeof(sockaddr_in6);
+ }
+
+ if(bind(fd, reinterpret_cast<struct sockaddr*>(&addr), size) == SOCKET_ERROR)
{
closeSocketNoThrow(fd);
SocketException ex(__FILE__, __LINE__);
@@ -571,10 +915,20 @@ repeatListen:
}
bool
-IceInternal::doConnect(SOCKET fd, struct sockaddr_in& addr, int timeout)
+IceInternal::doConnect(SOCKET fd, struct sockaddr_storage& addr, int timeout)
{
repeatConnect:
- if(::connect(fd, reinterpret_cast<struct sockaddr*>(&addr), int(sizeof(addr))) == SOCKET_ERROR)
+ int size;
+ if(addr.ss_family == AF_INET)
+ {
+ size = sizeof(sockaddr_in);
+ }
+ else if(addr.ss_family == AF_INET6)
+ {
+ size = sizeof(sockaddr_in6);
+ }
+
+ if(::connect(fd, reinterpret_cast<struct sockaddr*>(&addr), size) == SOCKET_ERROR)
{
if(interrupted())
{
@@ -627,7 +981,7 @@ repeatConnect:
// a server which was just deactivated if the client socket re-uses the same ephemeral
// port as the server).
//
- struct sockaddr_in localAddr;
+ struct sockaddr_storage localAddr;
fdToLocalAddress(fd, localAddr);
if(compareAddress(addr, localAddr) == 0)
{
@@ -744,9 +1098,9 @@ IceInternal::doFinishConnect(SOCKET fd, int timeout)
// a server which was just deactivated if the client socket re-uses the same ephemeral
// port as the server).
//
- struct sockaddr_in localAddr;
+ struct sockaddr_storage localAddr;
fdToLocalAddress(fd, localAddr);
- struct sockaddr_in remoteAddr;
+ struct sockaddr_storage remoteAddr;
if(fdToRemoteAddress(fd, remoteAddr) && compareAddress(remoteAddr, localAddr) == 0)
{
ConnectionRefusedException ex(__FILE__, __LINE__);
@@ -830,20 +1184,24 @@ repeatAccept:
}
void
-IceInternal::getAddress(const string& host, int port, struct sockaddr_in& addr)
+IceInternal::getAddressForServer(const string& host, int port, struct sockaddr_storage& addr, ProtocolSupport protocol)
{
- memset(&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = inet_addr(host.c_str());
+ getAddressImpl(host, port, addr, protocol, true);
+}
- if(addr.sin_addr.s_addr == INADDR_NONE)
- {
- //
- // We now use getaddrinfo() on Windows.
- //
-// #ifdef _WIN32
+void
+IceInternal::getAddress(const string& host, int port, struct sockaddr_storage& addr, ProtocolSupport protocol)
+{
+ getAddressImpl(host, port, addr, protocol, false);
+}
+vector<struct sockaddr_storage>
+IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol, bool blocking)
+{
+ //
+ // We now use getaddrinfo() on Windows.
+ //
+// #ifdef _WIN32
// //
// // Windows XP has getaddrinfo(), but we don't want to require XP to run Ice.
// //
@@ -851,83 +1209,185 @@ IceInternal::getAddress(const string& host, int port, struct sockaddr_in& addr)
// //
// // gethostbyname() is thread safe on Windows, with a separate hostent per thread
// //
-// struct hostent* entry;
+// struct hostent* entry = 0;
// int retry = 5;
+
// do
// {
// entry = gethostbyname(host.c_str());
// }
-// while(entry == 0 && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
-
+// while(entry == 0 && h_errno == TRY_AGAIN && --retry >= 0);
+
// if(entry == 0)
// {
// DNSException ex(__FILE__, __LINE__);
-
-// ex.error = WSAGetLastError();
+// ex.error = h_errno;
// ex.host = host;
// throw ex;
// }
-// memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
+
+// char** p = entry->h_addr_list;
+// while(*p)
+// {
+// memcpy(&addr.sin_addr, *p, entry->h_length);
+// result.push_back(addr);
+// p++;
+// }
// #else
- struct addrinfo* info = 0;
- int retry = 5;
+ vector<struct sockaddr_storage> result;
+ struct sockaddr_storage addr;
+ memset(&addr, 0, sizeof(struct sockaddr_storage));
+
+ struct addrinfo* info = 0;
+ int retry = 5;
- struct addrinfo hints = { 0 };
+ struct addrinfo hints = { 0 };
+ 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
+ if(!blocking)
+ {
+ hints.ai_flags = AI_NUMERICHOST;
+ }
+
+ int rs = 0;
+ do
+ {
+ if(host.empty())
{
- rs = getaddrinfo(host.c_str(), 0, &hints, &info);
+ rs = getaddrinfo(0, "0", &hints, &info); // Get the address of the loopback interface
}
- while(info == 0 && rs == EAI_AGAIN && --retry >= 0);
-
- if(rs != 0)
+ else
{
- DNSException ex(__FILE__, __LINE__);
- ex.error = rs;
- ex.host = host;
- throw ex;
+ rs = getaddrinfo(host.c_str(), 0, &hints, &info);
}
+ }
+ while(info == 0 && rs == EAI_AGAIN && --retry >= 0);
- assert(info->ai_family == PF_INET);
- struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(info->ai_addr);
+ if(!blocking && rs == EAI_NONAME)
+ {
+ return result; // Empty result indicates that a blocking lookup is necessary.
+ }
+ else if(rs != 0)
+ {
+ DNSException ex(__FILE__, __LINE__);
+ ex.error = rs;
+ ex.host = host;
+ throw ex;
+ }
- addr.sin_addr.s_addr = sin->sin_addr.s_addr;
- freeaddrinfo(info);
+ struct addrinfo* p;
+ for(p = info; p != NULL; p = p->ai_next)
+ {
+ memcpy(&addr, p->ai_addr, p->ai_addrlen);
+ if(p->ai_family == PF_INET)
+ {
+ struct sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
+ addrin->sin_port = htons(port);
+ if(addrin->sin_addr.s_addr == 0)
+ {
+ continue;
+ }
+ }
+ else if(p->ai_family == PF_INET6)
+ {
+ struct sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
+ addrin6->sin6_port = htons(port);
+ if(IN6_IS_ADDR_UNSPECIFIED(&addrin6->sin6_addr))
+ {
+ continue;
+ }
+ }
+
+ bool found = false;
+ for(unsigned int i = 0; i < result.size(); ++i)
+ {
+ if(compareAddress(result[i], addr) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ result.push_back(addr);
+ }
}
+
+ freeaddrinfo(info);
+ return result;
}
int
-IceInternal::compareAddress(const struct sockaddr_in& addr1, const struct sockaddr_in& addr2)
+IceInternal::compareAddress(const struct sockaddr_storage& addr1, const struct sockaddr_storage& addr2)
{
- if(addr1.sin_family < addr2.sin_family)
+ if(addr1.ss_family < addr2.ss_family)
{
return -1;
}
- else if(addr2.sin_family < addr1.sin_family)
+ else if(addr2.ss_family < addr1.ss_family)
{
return 1;
}
- if(addr1.sin_port < addr2.sin_port)
+ if(addr1.ss_family == AF_INET)
{
- return -1;
- }
- else if(addr2.sin_port < addr1.sin_port)
- {
- return 1;
- }
+ const struct sockaddr_in* addr1in = reinterpret_cast<const sockaddr_in*>(&addr1);
+ const struct sockaddr_in* addr2in = reinterpret_cast<const sockaddr_in*>(&addr2);
- if(addr1.sin_addr.s_addr < addr2.sin_addr.s_addr)
- {
- return -1;
+ if(addr1in->sin_port < addr2in->sin_port)
+ {
+ return -1;
+ }
+ else if(addr2in->sin_port < addr1in->sin_port)
+ {
+ return 1;
+ }
+
+ if(addr1in->sin_addr.s_addr < addr2in->sin_addr.s_addr)
+ {
+ return -1;
+ }
+ else if(addr2in->sin_addr.s_addr < addr1in->sin_addr.s_addr)
+ {
+ return 1;
+ }
}
- else if(addr2.sin_addr.s_addr < addr1.sin_addr.s_addr)
+ else
{
- return 1;
+ const struct sockaddr_in6* addr1in = reinterpret_cast<const sockaddr_in6*>(&addr1);
+ const struct sockaddr_in6* addr2in = reinterpret_cast<const sockaddr_in6*>(&addr2);
+
+ if(addr1in->sin6_port < addr2in->sin6_port)
+ {
+ return -1;
+ }
+ else if(addr2in->sin6_port < addr1in->sin6_port)
+ {
+ return 1;
+ }
+
+ int res = memcmp(&addr1in->sin6_addr, &addr2in->sin6_addr, sizeof(struct in6_addr));
+ if(res < 0)
+ {
+ return -1;
+ }
+ else if(res > 0)
+ {
+ return 1;
+ }
}
return 0;
@@ -938,21 +1398,23 @@ IceInternal::createPipe(SOCKET fds[2])
{
#ifdef _WIN32
- SOCKET fd = createSocket(false);
+ SOCKET fd = createSocket(false, AF_INET);
setBlock(fd, true);
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(0);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ struct sockaddr_in* addrin = reinterpret_cast<struct sockaddr_in*>(&addr);
+ addrin->sin_family = AF_INET;
+ addrin->sin_port = htons(0);
+ addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
doBind(fd, addr);
doListen(fd, 1);
try
{
- fds[0] = createSocket(false);
+ fds[0] = createSocket(false, AF_INET);
}
catch(...)
{
@@ -1268,17 +1730,17 @@ IceInternal::fdToString(SOCKET fd)
return "<closed>";
}
- struct sockaddr_in localAddr;
+ struct sockaddr_storage localAddr;
fdToLocalAddress(fd, localAddr);
- struct sockaddr_in remoteAddr;
+ struct sockaddr_storage remoteAddr;
bool peerConnected = fdToRemoteAddress(fd, remoteAddr);
return addressesToString(localAddr, remoteAddr, peerConnected);
};
std::string
-IceInternal::addressesToString(const struct sockaddr_in& localAddr, const struct sockaddr_in& remoteAddr,
+IceInternal::addressesToString(const struct sockaddr_storage& localAddr, const struct sockaddr_storage& remoteAddr,
bool peerConnected)
{
ostringstream s;
@@ -1295,9 +1757,9 @@ IceInternal::addressesToString(const struct sockaddr_in& localAddr, const struct
}
void
-IceInternal::fdToLocalAddress(SOCKET fd, struct sockaddr_in& addr)
+IceInternal::fdToLocalAddress(SOCKET fd, struct sockaddr_storage& addr)
{
- socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
+ socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
if(getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
{
closeSocketNoThrow(fd);
@@ -1308,9 +1770,9 @@ IceInternal::fdToLocalAddress(SOCKET fd, struct sockaddr_in& addr)
}
bool
-IceInternal::fdToRemoteAddress(SOCKET fd, struct sockaddr_in& addr)
+IceInternal::fdToRemoteAddress(SOCKET fd, struct sockaddr_storage& addr)
{
- socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_in));
+ socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
if(getpeername(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
{
if(notConnected())
@@ -1330,296 +1792,89 @@ IceInternal::fdToRemoteAddress(SOCKET fd, struct sockaddr_in& addr)
}
string
-IceInternal::addrToString(const struct sockaddr_in& addr)
+IceInternal::inetAddrToString(const struct sockaddr_storage& ss)
+{
+ int size;
+ if(ss.ss_family == AF_INET)
+ {
+ size = sizeof(sockaddr_in);
+ }
+ else if(ss.ss_family == AF_INET6)
+ {
+ size = sizeof(sockaddr_in6);
+ }
+
+ char namebuf[1024];
+ namebuf[0] = '\0';
+ getnameinfo(reinterpret_cast<const struct sockaddr *>(&ss), size, namebuf, sizeof(namebuf), 0, 0, NI_NUMERICHOST);
+ return string(namebuf);
+}
+
+string
+IceInternal::addrToString(const struct sockaddr_storage& addr)
{
ostringstream s;
- s << inetAddrToString(addr.sin_addr) << ':' << ntohs(addr.sin_port);
+ string port;
+ s << inetAddrToString(addr) << ':';
+ if(addr.ss_family == AF_INET)
+ {
+ const struct sockaddr_in* addrin = reinterpret_cast<const sockaddr_in*>(&addr);
+ s << ntohs(addrin->sin_port);
+ }
+ else
+ {
+ const struct sockaddr_in6* addrin = reinterpret_cast<const sockaddr_in6*>(&addr);
+ s << ntohs(addrin->sin6_port);
+ }
return s.str();
}
-vector<struct sockaddr_in>
-IceInternal::getAddresses(const string& host, int port, bool blocking)
+int
+IceInternal::getPort(const struct sockaddr_storage& addr)
{
- vector<struct sockaddr_in> result;
-
- if(host == "0.0.0.0")
+ if(addr.ss_family == AF_INET)
{
- vector<string> hosts = getLocalHosts();
- for(unsigned int i = 0; i < hosts.size(); ++i)
- {
- struct sockaddr_in addr;
- getAddress(hosts[i], port, addr);
- result.push_back(addr);
- }
+ return ntohs(reinterpret_cast<const sockaddr_in*>(&addr)->sin_port);
}
else
{
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(struct sockaddr_in));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
-
- //
- // We now use getaddrinfo() on Windows.
- //
-// #ifdef _WIN32
-
-// //
-// // Windows XP has getaddrinfo(), but we don't want to require XP to run Ice.
-// //
-
-// //
-// // gethostbyname() is thread safe on Windows, with a separate hostent per thread
-// //
-// struct hostent* entry = 0;
-// int retry = 5;
-
-// do
-// {
-// entry = gethostbyname(host.c_str());
-// }
-// while(entry == 0 && h_errno == TRY_AGAIN && --retry >= 0);
-
-// if(entry == 0)
-// {
-// DNSException ex(__FILE__, __LINE__);
-// ex.error = h_errno;
-// ex.host = host;
-// throw ex;
-// }
-
-// char** p = entry->h_addr_list;
-// while(*p)
-// {
-// memcpy(&addr.sin_addr, *p, entry->h_length);
-// result.push_back(addr);
-// p++;
-// }
-
-// #else
-
- struct addrinfo* info = 0;
- int retry = 5;
-
- struct addrinfo hints = { 0 };
- hints.ai_family = PF_INET;
- if(!blocking)
- {
- hints.ai_flags = AI_NUMERICHOST;
- }
-
- int rs = 0;
- do
- {
- rs = getaddrinfo(host.c_str(), 0, &hints, &info);
- }
- while(info == 0 && rs == EAI_AGAIN && --retry >= 0);
-
- if(!blocking && rs == EAI_NONAME)
- {
- return result; // Empty result indicates that a blocking lookup is necessary.
- }
- else if(rs != 0)
- {
- DNSException ex(__FILE__, __LINE__);
- ex.error = rs;
- ex.host = host;
- throw ex;
- }
-
- struct addrinfo* p;
- for(p = info; p != NULL; p = p->ai_next)
- {
- assert(p->ai_family == PF_INET);
- struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(p->ai_addr);
- if(sin->sin_addr.s_addr != 0)
- {
- addr.sin_addr.s_addr = sin->sin_addr.s_addr;
-
- bool found = false;
- for(unsigned int i = 0; i < result.size(); ++i)
- {
- if(compareAddress(result[i], addr) == 0)
- {
- found = true;
- break;
- }
- }
- if(!found)
- {
- result.push_back(addr);
- }
- }
- }
-
- freeaddrinfo(info);
-
-//#endif
+ return ntohs(reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port);
}
-
- return result;
}
vector<string>
-IceInternal::getLocalHosts()
+IceInternal::getHostsForEndpointExpand(const string& host, ProtocolSupport protocolSupport)
{
- vector<string> result;
-
-#if defined(_WIN32)
- try
+ vector<string> hosts;
+ if(host.empty() || isWildcard(host, protocolSupport))
{
- SOCKET fd = createSocket(false);
-
- vector<unsigned char> buffer;
- buffer.resize(1024);
- unsigned long len = 0;
- DWORD rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0,
- &buffer[0], static_cast<DWORD>(buffer.size()),
- &len, 0, 0);
- if(rs == SOCKET_ERROR)
+ vector<struct sockaddr_storage> addrs = getLocalAddresses(protocolSupport);
+ for(vector<struct sockaddr_storage>::const_iterator p = addrs.begin(); p != addrs.end(); ++p)
{
//
- // If the buffer wasn't big enough, resize it to the
- // required length and try again.
+ // NOTE: We don't publish link-local IPv6 addresses as these addresses can only
+ // be accessed in general with a scope-id.
//
- if(getSocketErrno() == WSAEFAULT)
+ if(p->ss_family != AF_INET6 ||
+ !IN6_IS_ADDR_LINKLOCAL(&reinterpret_cast<const struct sockaddr_in6*>(&(*p))->sin6_addr))
{
- buffer.resize(len);
- rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0,
- &buffer[0], static_cast<DWORD>(buffer.size()),
- &len, 0, 0);
+ hosts.push_back(inetAddrToString(*p));
}
-
- if(rs == SOCKET_ERROR)
- {
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- }
-
- //
- // Add the local interface addresses.
- //
- SOCKET_ADDRESS_LIST* addrs = reinterpret_cast<SOCKET_ADDRESS_LIST*>(&buffer[0]);
- for (int i = 0; i < addrs->iAddressCount; ++i)
- {
- result.push_back(
- inetAddrToString(reinterpret_cast<struct sockaddr_in*>(addrs->Address[i].lpSockaddr)->sin_addr));
}
- //
- // Add the loopback interface address.
- //
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(0);
- addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- result.push_back(inetAddrToString(addr.sin_addr));
-
- closeSocket(fd);
- }
- catch(const Ice::LocalException&)
- {
- //
- // TODO: Warning?
- //
- }
-#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__)
- struct ifaddrs* ifap;
- if(::getifaddrs(&ifap) == SOCKET_ERROR)
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- struct ifaddrs* curr = ifap;
- while(curr != 0)
- {
- if(curr->ifa_addr && curr->ifa_addr->sa_family == AF_INET)
+ if(hosts.empty())
{
- struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(curr->ifa_addr);
- if(addr->sin_addr.s_addr != 0)
+ if(protocolSupport != EnableIPv6)
{
- result.push_back(inetAddrToString((*addr).sin_addr));
+ hosts.push_back("127.0.0.1");
}
- }
-
- curr = curr->ifa_next;
- }
-
- ::freeifaddrs(ifap);
-#else
- SOCKET fd = createSocket(false);
-
-#ifdef _AIX
- int cmd = CSIOCGIFCONF;
-#else
- int cmd = SIOCGIFCONF;
-#endif
- struct ifconf ifc;
- int numaddrs = 10;
- int old_ifc_len = 0;
-
- //
- // Need to call ioctl multiple times since we do not know up front
- // how many addresses there will be, and thus how large a buffer we need.
- // We keep increasing the buffer size until subsequent calls return
- // the same length, meaning we have all the addresses.
- //
- while(true)
- {
- int bufsize = numaddrs * static_cast<int>(sizeof(struct ifreq));
- ifc.ifc_len = bufsize;
- ifc.ifc_buf = (char*)malloc(bufsize);
-
- int rs = ioctl(fd, cmd, &ifc);
- if(rs == SOCKET_ERROR)
- {
- free(ifc.ifc_buf);
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else if(ifc.ifc_len == old_ifc_len)
- {
- //
- // Returned same length twice in a row, finished.
- //
- break;
- }
- else
- {
- old_ifc_len = ifc.ifc_len;
- }
-
- numaddrs += 10;
- free(ifc.ifc_buf);
- }
-
- numaddrs = ifc.ifc_len / static_cast<int>(sizeof(struct ifreq));
- struct ifreq* ifr = ifc.ifc_req;
- for(int i = 0; i < numaddrs; ++i)
- {
- if(ifr[i].ifr_addr.sa_family == AF_INET)
- {
- struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(&ifr[i].ifr_addr);
- if(addr->sin_addr.s_addr != 0)
+ if(protocolSupport != EnableIPv4)
{
- result.push_back(inetAddrToString((*addr).sin_addr));
+ hosts.push_back("0:0:0:0:0:0:0:1");
}
}
}
-
- free(ifc.ifc_buf);
- closeSocket(fd);
-#endif
-
- return result;
+ return hosts; // An empty host list indicates to just use the given host.
}
void