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.cpp2153
1 files changed, 1218 insertions, 935 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp
index 28a380779a8..ed730a8bb88 100644
--- a/cpp/src/Ice/Network.cpp
+++ b/cpp/src/Ice/Network.cpp
@@ -21,25 +21,28 @@
// The following is required for the Vista PSDK to bring in
// the definitions of the IN6_IS_ADDR_* macros.
//
-#if defined(_WIN32) && !defined(_WIN32_WINNT)
+#if defined(_WIN32) && !defined(_WIN32_WINNT) && WINAPI_FAMILY != 0x02
# define _WIN32_WINNT 0x0501
#endif
+#include <Ice/Network.h>
#include <IceUtil/StringUtil.h>
#include <IceUtil/Unicode.h>
-#include <Ice/Network.h>
#include <Ice/LocalException.h>
#include <Ice/Properties.h> // For setTcpBufSize
#include <Ice/LoggerUtil.h> // For setTcpBufSize
-#if defined(_WIN32)
-# include <winsock2.h>
-# include <ws2tcpip.h>
-# include <iphlpapi.h>
-# include <Mswsock.h>
+#if defined(ICE_OS_WINRT)
+# include <IceUtil/InputUtil.h>
+# include <ppltasks.h> // For Concurrency::task
+#elif defined(_WIN32)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <iphlpapi.h>
+# include <Mswsock.h>
#else
-# include <net/if.h>
-# include <sys/ioctl.h>
+# include <net/if.h>
+# include <sys/ioctl.h>
#endif
#if defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__)
@@ -52,6 +55,14 @@ using namespace std;
using namespace Ice;
using namespace IceInternal;
+#ifdef ICE_OS_WINRT
+using namespace Platform;
+using namespace Windows::Foundation;
+using namespace Windows::Storage::Streams;
+using namespace Windows::Networking;
+using namespace Windows::Networking::Sockets;
+#endif
+
#if defined(__sun) && !defined(__GNUC__)
# define INADDR_NONE (in_addr_t)0xffffffff
#endif
@@ -59,10 +70,195 @@ using namespace IceInternal;
namespace
{
-vector<struct sockaddr_storage>
+#ifndef ICE_OS_WINRT
+void
+setTcpNoDelay(SOCKET fd)
+{
+ int flag = 1;
+ if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+setKeepAlive(SOCKET fd)
+{
+ int flag = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+#endif
+
+SOCKET
+createSocketImpl(bool udp, int family)
+{
+#ifdef ICE_OS_WINRT
+ if(udp)
+ {
+ return ref new DatagramSocket();
+ }
+ else
+ {
+ StreamSocket^ socket = ref new StreamSocket();
+ socket->Control->KeepAlive = true;
+ socket->Control->NoDelay = true;
+ return socket;
+ }
+#else
+ SOCKET fd;
+
+ if(udp)
+ {
+ fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ }
+ else
+ {
+ fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ }
+
+ if(fd == INVALID_SOCKET)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ if(!udp)
+ {
+ setTcpNoDelay(fd);
+ setKeepAlive(fd);
+ }
+
+ return fd;
+#endif
+}
+
+Address
+getAddressImpl(const string& host, int port, ProtocolSupport protocol, bool server)
+{
+ Address addr;
+#ifdef ICE_OS_WINRT
+ 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()));
+ }
+#else
+ memset(&addr, 0, sizeof(Address));
+
+ //
+ // 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)
+ {
+ sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
+ addrin6->sin6_family = AF_INET6;
+ addrin6->sin6_port = htons(port);
+ addrin6->sin6_addr = server ? in6addr_any : in6addr_loopback;
+ }
+ else
+ {
+ sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
+ addrin->sin_family = AF_INET;
+ addrin->sin_port = htons(port);
+ addrin->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, 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 == PF_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);
+#endif
+ return addr;
+}
+
+#ifndef ICE_OS_WINRT
+vector<Address>
getLocalAddresses(ProtocolSupport protocol)
{
- vector<struct sockaddr_storage> result;
+ vector<Address> result;
#if defined(_WIN32)
try
@@ -74,7 +270,7 @@ getLocalAddresses(ProtocolSupport protocol)
continue;
}
- SOCKET fd = createSocket(false, i == 0 ? AF_INET : AF_INET6);
+ SOCKET fd = createSocketImpl(false, i == 0 ? AF_INET : AF_INET6);
vector<unsigned char> buffer;
buffer.resize(1024);
@@ -111,7 +307,7 @@ getLocalAddresses(ProtocolSupport protocol)
SOCKET_ADDRESS_LIST* addrs = reinterpret_cast<SOCKET_ADDRESS_LIST*>(&buffer[0]);
for (int i = 0; i < addrs->iAddressCount; ++i)
{
- sockaddr_storage addr;
+ Address addr;
memcpy(&addr, addrs->Address[i].lpSockaddr, addrs->Address[i].iSockaddrLength);
if(addr.ss_family == AF_INET && protocol != EnableIPv6)
{
@@ -155,7 +351,7 @@ getLocalAddresses(ProtocolSupport protocol)
{
if(curr->ifa_addr->sa_family == AF_INET && protocol != EnableIPv6)
{
- sockaddr_storage addr;
+ Address addr;
memcpy(&addr, curr->ifa_addr, sizeof(sockaddr_in));
if(reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr.s_addr != 0)
{
@@ -164,11 +360,11 @@ getLocalAddresses(ProtocolSupport protocol)
}
else if(curr->ifa_addr->sa_family == AF_INET6 && protocol != EnableIPv4)
{
- sockaddr_storage addr;
+ Address 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));
+ result.push_back(*reinterpret_cast<Address*>(curr->ifa_addr));
}
}
}
@@ -184,7 +380,7 @@ getLocalAddresses(ProtocolSupport protocol)
{
continue;
}
- SOCKET fd = createSocket(false, i == 0 ? AF_INET : AF_INET6);
+ SOCKET fd = createSocketImpl(false, i == 0 ? AF_INET : AF_INET6);
#ifdef _AIX
int cmd = CSIOCGIFCONF;
@@ -239,51 +435,51 @@ getLocalAddresses(ProtocolSupport protocol)
{
if(!(ifr[i].ifr_flags & IFF_LOOPBACK)) // Don't include loopback interface addresses
{
- //
- // On Solaris the above Loopback check does not always work so we double
- // check the address below. Solaris also returns duplicate entries that need
- // to be filtered out.
- //
+ //
+ // On Solaris the above Loopback check does not always work so we double
+ // check the address below. Solaris also returns duplicate entries that need
+ // to be filtered out.
+ //
if(ifr[i].ifr_addr.sa_family == AF_INET && protocol != EnableIPv6)
{
- sockaddr_storage addr;
+ Address addr;
memcpy(&addr, &ifr[i].ifr_addr, sizeof(sockaddr_in));
struct in_addr* inaddr = &reinterpret_cast<struct sockaddr_in*>(&addr)->sin_addr;
if(inaddr->s_addr != 0 && inaddr->s_addr != htonl(INADDR_LOOPBACK))
{
- unsigned int j;
- for(j = 0; j < result.size(); ++j)
- {
- if(compareAddress(addr, result[j]) == 0)
- {
- break;
- }
- }
- if(j == result.size())
- {
+ unsigned int j;
+ for(j = 0; j < result.size(); ++j)
+ {
+ if(compareAddress(addr, result[j]) == 0)
+ {
+ break;
+ }
+ }
+ if(j == result.size())
+ {
result.push_back(addr);
- }
+ }
}
}
else if(ifr[i].ifr_addr.sa_family == AF_INET6 && protocol != EnableIPv4)
{
- sockaddr_storage addr;
+ Address addr;
memcpy(&addr, &ifr[i].ifr_addr, sizeof(sockaddr_in6));
struct in6_addr* inaddr6 = &reinterpret_cast<struct sockaddr_in6*>(&addr)->sin6_addr;
if(!IN6_IS_ADDR_UNSPECIFIED(inaddr6) && !IN6_IS_ADDR_LOOPBACK(inaddr6))
{
- unsigned int j;
- for(j = 0; j < result.size(); ++j)
- {
- if(compareAddress(addr, result[j]) == 0)
- {
- break;
- }
- }
- if(j == result.size())
- {
+ unsigned int j;
+ for(j = 0; j < result.size(); ++j)
+ {
+ if(compareAddress(addr, result[j]) == 0)
+ {
+ break;
+ }
+ }
+ if(j == result.size())
+ {
result.push_back(addr);
- }
+ }
}
}
}
@@ -295,103 +491,12 @@ getLocalAddresses(ProtocolSupport protocol)
return result;
}
-struct sockaddr_storage
-getAddressImpl(const string& host, int port, ProtocolSupport protocol, bool server)
-{
- struct sockaddr_storage addr;
- memset(&addr, 0, sizeof(struct 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)
- {
- sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
- addrin6->sin6_family = AF_INET6;
- addrin6->sin6_port = htons(port);
- addrin6->sin6_addr = server ? in6addr_any : in6addr_loopback;
- }
- else
- {
- sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
- addrin->sin_family = AF_INET;
- addrin->sin_port = htons(port);
- addrin->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, 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 == PF_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);
- return addr;
-}
-
bool
isWildcard(const string& host, ProtocolSupport protocol)
{
try
{
- sockaddr_storage addr = getAddressImpl(host, 0, protocol, false);
+ Address addr = getAddressImpl(host, 0, protocol, false);
if(addr.ss_family == AF_INET)
{
struct sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
@@ -481,7 +586,7 @@ getInterfaceAddress(const string& name)
ifreq if_address;
strcpy(if_address.ifr_name, name.c_str());
- SOCKET fd = createSocket(false, AF_INET);
+ SOCKET fd = createSocketImpl(false, AF_INET);
int rc = ioctl(fd, SIOCGIFADDR, &if_address);
closeSocketNoThrow(fd);
@@ -494,6 +599,8 @@ getInterfaceAddress(const string& name)
return addr;
}
+#endif // #ifndef ICE_OS_WINRT
+
}
#ifdef ICE_USE_IOCP
@@ -504,317 +611,691 @@ IceInternal::AsyncInfo::AsyncInfo(SocketOperation s)
}
#endif
-int
-IceInternal::getSocketErrno()
+bool
+IceInternal::noMoreFds(int error)
{
-#ifdef _WIN32
- return WSAGetLastError();
+#if defined(ICE_OS_WINRT)
+ return error == (int)SocketErrorStatus::TooManyOpenFiles;
+#elif defined(_WIN32)
+ return error == WSAEMFILE;
#else
- return errno;
+ return error == EMFILE || error == ENFILE;
#endif
}
-bool
-IceInternal::interrupted()
+string
+IceInternal::errorToStringDNS(int error)
{
-#ifdef _WIN32
- return WSAGetLastError() == WSAEINTR;
+#if defined(ICE_OS_WINRT)
+ return "Host not found";
+#elif defined(_WIN32)
+ return IceUtilInternal::errorToString(error);
#else
-# ifdef EPROTO
- return errno == EINTR || errno == EPROTO;
-# else
- return errno == EINTR;
-# endif
+ return gai_strerror(error);
#endif
}
-bool
-IceInternal::acceptInterrupted()
+vector<Address>
+IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol, bool blocking)
{
- if(interrupted())
+ vector<Address> result;
+ Address addr;
+#ifdef ICE_OS_WINRT
+ addr.host = ref new HostName(host.empty() ? "localhost" : ref new String(IceUtil::stringToWstring(host).c_str()));
+ stringstream os;
+ os << port;
+ addr.port = ref new String(IceUtil::stringToWstring(os.str()).c_str());
+ result.push_back(addr);
+#else
+ memset(&addr, 0, sizeof(Address));
+
+ //
+ // 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())
{
- return true;
+ if(protocol != EnableIPv4)
+ {
+ sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
+ addrin6->sin6_family = AF_INET6;
+ addrin6->sin6_port = htons(port);
+ addrin6->sin6_addr = in6addr_loopback;
+ result.push_back(addr);
+ }
+ if(protocol != EnableIPv6)
+ {
+ sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
+ addrin->sin_family = AF_INET;
+ addrin->sin_port = htons(port);
+ addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ result.push_back(addr);
+ }
+ return result;
}
-#ifdef _WIN32
- int error = WSAGetLastError();
- return error == WSAECONNABORTED ||
- error == WSAECONNRESET ||
- error == WSAETIMEDOUT;
+ struct addrinfo* info = 0;
+ int retry = 5;
+
+ 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;
+ }
+
+ 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);
+
+ // In theory, getaddrinfo should only return EAI_NONAME if AI_NUMERICHOST is specified and the host name
+ // is not a IP address. However on some platforms (e.g. Mac OS X 10.4.x) EAI_NODATA is also returned so
+ // we also check for it.
+#ifdef EAI_NODATA
+ if(!blocking && (rs == EAI_NONAME || rs == EAI_NODATA))
#else
- return errno == ECONNABORTED ||
- errno == ECONNRESET ||
- errno == ETIMEDOUT;
+ if(!blocking && rs == EAI_NONAME)
+#endif
+ {
+ 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)
+ {
+ 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);
+ }
+ else if(p->ai_family == PF_INET6)
+ {
+ struct sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
+ addrin6->sin6_port = htons(port);
+ }
+
+ 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);
+
+ if(result.size() == 0)
+ {
+ DNSException ex(__FILE__, __LINE__);
+ ex.host = host;
+ throw ex;
+ }
#endif
+ return result;
}
-bool
-IceInternal::noBuffers()
+ProtocolSupport
+IceInternal::getProtocolSupport(const Address& addr)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- return error == WSAENOBUFS ||
- error == WSAEFAULT;
+#ifndef ICE_OS_WINRT
+ return addr.ss_family == AF_INET ? EnableIPv4 : EnableIPv6;
#else
- return errno == ENOBUFS;
+ return EnableIPv4;
#endif
}
-bool
-IceInternal::wouldBlock()
+Address
+IceInternal::getAddressForServer(const string& host, int port, ProtocolSupport protocol)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- return error == WSAEWOULDBLOCK || error == WSA_IO_PENDING || error == ERROR_IO_PENDING;
+ return getAddressImpl(host, port, protocol, true);
+}
+
+Address
+IceInternal::getAddress(const string& host, int port, ProtocolSupport protocol)
+{
+ return getAddressImpl(host, port, protocol, false);
+}
+
+int
+IceInternal::compareAddress(const Address& addr1, const Address& addr2)
+{
+#ifdef ICE_OS_WINRT
+ int o = String::CompareOrdinal(addr1.port, addr2.port);
+ if(o != 0)
+ {
+ return o;
+ }
+ return String::CompareOrdinal(addr1.host->RawName, addr2.host->RawName);
#else
- return errno == EAGAIN || errno == EWOULDBLOCK;
+ if(addr1.ss_family < addr2.ss_family)
+ {
+ return -1;
+ }
+ else if(addr2.ss_family < addr1.ss_family)
+ {
+ return 1;
+ }
+
+ if(addr1.ss_family == AF_INET)
+ {
+ const struct sockaddr_in* addr1in = reinterpret_cast<const sockaddr_in*>(&addr1);
+ const struct sockaddr_in* addr2in = reinterpret_cast<const sockaddr_in*>(&addr2);
+
+ 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
+ {
+ 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;
#endif
}
-bool
-IceInternal::connectFailed()
+SOCKET
+IceInternal::createSocket(bool udp, const Address& addr)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- return error == WSAECONNREFUSED ||
- error == WSAETIMEDOUT ||
- error == WSAENETUNREACH ||
- error == WSAEHOSTUNREACH ||
- error == WSAECONNRESET ||
- error == WSAESHUTDOWN ||
- error == WSAECONNABORTED;
+#ifdef ICE_OS_WINRT
+ return createSocketImpl(udp, 0);
#else
- return errno == ECONNREFUSED ||
- errno == ETIMEDOUT ||
- errno == ENETUNREACH ||
- errno == EHOSTUNREACH ||
- errno == ECONNRESET ||
- errno == ESHUTDOWN ||
- errno == ECONNABORTED;
+ return createSocketImpl(udp, addr.ss_family);
#endif
}
-bool
-IceInternal::connectionRefused()
+
+void
+IceInternal::closeSocketNoThrow(SOCKET fd)
{
-#ifdef _WIN32
+#if defined(ICE_OS_WINRT)
+ //
+ // NOTE: StreamSocket::Close or DatagramSocket::Close aren't
+ // exposed in C++, you have to delete the socket to close
+ // it. According some Microsoft samples, this is safe even if
+ // there are still references to the object...
+ //
+ //fd->Close();
+ delete fd;
+#elif defined(_WIN32)
int error = WSAGetLastError();
- return error == WSAECONNREFUSED || error == ERROR_CONNECTION_REFUSED;
+ closesocket(fd);
+ WSASetLastError(error);
#else
- return errno == ECONNREFUSED;
+ int error = errno;
+ close(fd);
+ errno = error;
#endif
}
-bool
-IceInternal::connectInProgress()
+void
+IceInternal::closeSocket(SOCKET fd)
{
-#ifdef _WIN32
+#if defined(ICE_OS_WINRT)
+ //
+ // NOTE: StreamSocket::Close or DatagramSocket::Close aren't
+ // exposed in C++, you have to delete the socket to close
+ // it. According some Microsoft samples, this is safe even if
+ // there are still references to the object...
+ //
+ //fd->Close();
+ delete fd;
+#elif defined(_WIN32)
int error = WSAGetLastError();
- return error == WSAEWOULDBLOCK || error == WSA_IO_PENDING || error == ERROR_IO_PENDING;
+ if(closesocket(fd) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ WSASetLastError(error);
#else
- return errno == EINPROGRESS;
+ int error = errno;
+ if(close(fd) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ errno = error;
#endif
}
-bool
-IceInternal::connectionLost()
+string
+IceInternal::addrToString(const Address& addr)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- return error == WSAECONNRESET ||
- error == WSAESHUTDOWN ||
- error == WSAENOTCONN ||
-#ifdef ICE_USE_IOCP
- error == ERROR_NETNAME_DELETED ||
-#endif
- error == WSAECONNABORTED;
+ ostringstream s;
+ s << inetAddrToString(addr) << ':' << getPort(addr);
+ return s.str();
+}
+
+void
+IceInternal::fdToLocalAddress(SOCKET fd, Address& addr)
+{
+#ifndef ICE_OS_WINRT
+ socklen_t len = static_cast<socklen_t>(sizeof(Address));
+ if(getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
#else
- return errno == ECONNRESET ||
- errno == ENOTCONN ||
- errno == ESHUTDOWN ||
- errno == ECONNABORTED ||
- errno == EPIPE;
+ StreamSocket^ stream = dynamic_cast<StreamSocket^>(fd);
+ if(stream)
+ {
+ addr.host = stream->Information->LocalAddress;
+ addr.port = stream->Information->LocalPort;
+ }
+ DatagramSocket^ datagram = dynamic_cast<DatagramSocket^>(fd);
+ if(datagram)
+ {
+ addr.host = datagram->Information->LocalAddress;
+ addr.port = datagram->Information->LocalPort;
+ }
#endif
}
bool
-IceInternal::notConnected()
+IceInternal::fdToRemoteAddress(SOCKET fd, Address& addr)
{
-#ifdef _WIN32
- return WSAGetLastError() == WSAENOTCONN;
-#elif defined(__APPLE__) || defined(__FreeBSD__)
- return errno == ENOTCONN || errno == EINVAL;
+#ifndef ICE_OS_WINRT
+ socklen_t len = static_cast<socklen_t>(sizeof(Address));
+ if(getpeername(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
+ {
+ if(notConnected())
+ {
+ return false;
+ }
+ else
+ {
+ closeSocketNoThrow(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+
+ return true;
#else
- return errno == ENOTCONN;
+ StreamSocket^ stream = dynamic_cast<StreamSocket^>(fd);
+ if(stream != nullptr)
+ {
+ addr.host = stream->Information->RemoteAddress;
+ addr.port = stream->Information->RemotePort;
+ }
+ DatagramSocket^ datagram = dynamic_cast<DatagramSocket^>(fd);
+ if(datagram != nullptr)
+ {
+ addr.host = datagram->Information->RemoteAddress;
+ addr.port = datagram->Information->RemotePort;
+ }
+ return addr.host != nullptr;
#endif
}
+
+std::string
+IceInternal::fdToString(SOCKET fd)
+{
+ if(fd == INVALID_SOCKET)
+ {
+ return "<closed>";
+ }
+
+ Address localAddr;
+ fdToLocalAddress(fd, localAddr);
+
+ Address remoteAddr;
+ bool peerConnected = fdToRemoteAddress(fd, remoteAddr);
+
+ return addressesToString(localAddr, remoteAddr, peerConnected);
+};
+
+void
+IceInternal::fdToAddressAndPort(SOCKET fd, string& localAddress, int& localPort, string& remoteAddress, int& remotePort)
+{
+ if(fd == INVALID_SOCKET)
+ {
+ localAddress.clear();
+ remoteAddress.clear();
+ localPort = -1;
+ remotePort = -1;
+ return;
+ }
+
+ Address localAddr;
+ fdToLocalAddress(fd, localAddr);
+ addrToAddressAndPort(localAddr, localAddress, localPort);
+
+ Address remoteAddr;
+ if(fdToRemoteAddress(fd, remoteAddr))
+ {
+ addrToAddressAndPort(remoteAddr, remoteAddress, remotePort);
+ }
+ else
+ {
+ remoteAddress.clear();
+ remotePort = -1;
+ }
+}
+
+void
+IceInternal::addrToAddressAndPort(const Address& addr, string& address, int& port)
+{
+ address = inetAddrToString(addr);
+ port = getPort(addr);
+}
+
+std::string
+IceInternal::addressesToString(const Address& localAddr, const Address& remoteAddr,
+ bool peerConnected)
+{
+ ostringstream s;
+ s << "local address = " << addrToString(localAddr);
+ if(peerConnected)
+ {
+ s << "\nremote address = " << addrToString(remoteAddr);
+ }
+ else
+ {
+ s << "\nremote address = <not connected>";
+ }
+ return s.str();
+}
+
bool
-IceInternal::recvTruncated()
+IceInternal::isAddressValid(const Address& addr)
{
-#ifdef _WIN32
- int err = WSAGetLastError();
- return err == WSAEMSGSIZE || err == ERROR_MORE_DATA;
+#ifndef ICE_OS_WINRT
+ return addr.ss_family != AF_UNSPEC;
#else
- // We don't get an error under Linux if a datagram is truncated.
- return false;
+ return addr.host != nullptr || addr.port != nullptr;
#endif
}
-bool
-IceInternal::noMoreFds(int error)
+vector<string>
+IceInternal::getHostsForEndpointExpand(const string& host, ProtocolSupport protocolSupport, bool includeLoopback)
{
-#ifdef _WIN32
- return error == WSAEMFILE;
+ vector<string> hosts;
+
+#ifndef ICE_OS_WINRT
+ if(host.empty() || isWildcard(host, protocolSupport))
+ {
+ vector<Address> addrs = getLocalAddresses(protocolSupport);
+ for(vector<Address>::const_iterator p = addrs.begin(); p != addrs.end(); ++p)
+ {
+ //
+ // NOTE: We don't publish link-local IPv6 addresses as these addresses can only
+ // be accessed in general with a scope-id.
+ //
+ if(p->ss_family != AF_INET6 ||
+ !IN6_IS_ADDR_LINKLOCAL(&reinterpret_cast<const struct sockaddr_in6*>(&(*p))->sin6_addr))
+ {
+ hosts.push_back(inetAddrToString(*p));
+ }
+ }
+
+ if(hosts.empty() || includeLoopback)
+ {
+ if(protocolSupport != EnableIPv6)
+ {
+ hosts.push_back("127.0.0.1");
+ }
+ if(protocolSupport != EnableIPv4)
+ {
+ hosts.push_back("0:0:0:0:0:0:0:1");
+ }
+ }
+ }
#else
- return error == EMFILE || error == ENFILE;
+ //
+ // No support for expanding wildcard addresses on WinRT
+ //
#endif
+ return hosts; // An empty host list indicates to just use the given host.
}
-SOCKET
-IceInternal::createSocket(bool udp, int family)
+string
+IceInternal::inetAddrToString(const Address& ss)
{
- SOCKET fd;
-
- if(udp)
+#ifndef ICE_OS_WINRT
+ int size = 0;
+ if(ss.ss_family == AF_INET)
{
- fd = socket(family, SOCK_DGRAM, IPPROTO_UDP);
+ size = sizeof(sockaddr_in);
+ }
+ else if(ss.ss_family == AF_INET6)
+ {
+ size = sizeof(sockaddr_in6);
}
else
{
- fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+ return "";
}
- if(fd == INVALID_SOCKET)
+ char namebuf[1024];
+ namebuf[0] = '\0';
+ getnameinfo(reinterpret_cast<const struct sockaddr *>(&ss), size, namebuf, sizeof(namebuf), 0, 0, NI_NUMERICHOST);
+ return string(namebuf);
+#else
+ if(ss.host == nullptr)
{
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
+ return "";
}
-
- if(!udp)
+ else
{
- setTcpNoDelay(fd);
- setKeepAlive(fd);
+ return IceUtil::wstringToString(ss.host->RawName->Data());
}
-
- return fd;
+#endif
}
-void
-IceInternal::closeSocket(SOCKET fd)
+int
+IceInternal::getPort(const Address& addr)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- if(closesocket(fd) == SOCKET_ERROR)
+#ifndef ICE_OS_WINRT
+ if(addr.ss_family == AF_INET)
{
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
+ return ntohs(reinterpret_cast<const sockaddr_in*>(&addr)->sin_port);
+ }
+ else if(addr.ss_family == AF_INET6)
+ {
+ return ntohs(reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port);
+ }
+ else
+ {
+ return -1;
}
- WSASetLastError(error);
#else
- int error = errno;
- if(close(fd) == SOCKET_ERROR)
+ IceUtil::Int64 port;
+ if(addr.port == nullptr || !IceUtilInternal::stringToInt64(IceUtil::wstringToString(addr.port->Data()), port))
{
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
+ return -1;
}
- errno = error;
+ return static_cast<int>(port);
#endif
}
void
-IceInternal::closeSocketNoThrow(SOCKET fd)
+IceInternal::setPort(Address& addr, int port)
{
-#ifdef _WIN32
- int error = WSAGetLastError();
- closesocket(fd);
- WSASetLastError(error);
+#ifndef ICE_OS_WINRT
+ if(addr.ss_family == AF_INET)
+ {
+ reinterpret_cast<sockaddr_in*>(&addr)->sin_port = htons(port);
+ }
+ else
+ {
+ assert(addr.ss_family == AF_INET6);
+ reinterpret_cast<sockaddr_in6*>(&addr)->sin6_port = htons(port);
+ }
#else
- int error = errno;
- close(fd);
- errno = error;
+ ostringstream os;
+ os << port;
+ addr.port = ref new String(IceUtil::stringToWstring(os.str()).c_str());
#endif
}
-void
-IceInternal::shutdownSocketWrite(SOCKET fd)
+bool
+IceInternal::isMulticast(const Address& addr)
{
- if(shutdown(fd, SHUT_WR) == SOCKET_ERROR)
+#ifndef ICE_OS_WINRT
+ if(addr.ss_family == AF_INET)
{
- //
- // Ignore errors indicating that we are shutdown already.
- //
-#if defined(_WIN32)
- int error = WSAGetLastError();
- //
- // Under Vista its possible to get a WSAECONNRESET. See
- // http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1739 for
- // some details.
- //
- if(error == WSAENOTCONN || error == WSAECONNRESET)
- {
- return;
- }
-#elif defined(__APPLE__) || defined(__FreeBSD__)
- if(errno == ENOTCONN || errno == EINVAL)
- {
- return;
- }
+ return IN_MULTICAST(ntohl(reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr.s_addr));
+ }
+ else if(addr.ss_family == AF_INET6)
+ {
+ return IN6_IS_ADDR_MULTICAST(&reinterpret_cast<const struct sockaddr_in6*>(&addr)->sin6_addr);
+ }
#else
- if(errno == ENOTCONN)
+ if(addr.host == nullptr)
+ {
+ return false;
+ }
+ string host = IceUtil::wstringToString(addr.host->RawName->Data());
+ string ip = IceUtilInternal::toUpper(host);
+ vector<string> tokens;
+ IceUtilInternal::splitString(ip, ".", tokens);
+ if(tokens.size() == 4)
+ {
+ IceUtil::Int64 j;
+ if(IceUtilInternal::stringToInt64(tokens[0], j))
{
- return;
+ if(j >= 233 && j <= 239)
+ {
+ return true;
+ }
}
-#endif
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
}
+ if(ip.find("::") != string::npos)
+ {
+ return ip.compare(0, 2, "FF") == 0;
+ }
+#endif
+ return false;
}
void
-IceInternal::shutdownSocketReadWrite(SOCKET fd)
+IceInternal::setTcpBufSize(SOCKET fd, const Ice::PropertiesPtr& properties, const Ice::LoggerPtr& logger)
{
- if(shutdown(fd, SHUT_RDWR) == SOCKET_ERROR)
+ assert(fd != INVALID_SOCKET);
+
+ //
+ // By default, on Windows we use a 128KB buffer size. On Unix
+ // platforms, we use the system defaults.
+ //
+#ifdef _WIN32
+ const int dfltBufSize = 128 * 1024;
+#else
+ const int dfltBufSize = 0;
+#endif
+ Int sizeRequested;
+
+ sizeRequested = properties->getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize);
+ if(sizeRequested > 0)
{
//
- // Ignore errors indicating that we are shutdown already.
- //
-#if defined(_WIN32)
- int error = WSAGetLastError();
- //
- // Under Vista its possible to get a WSAECONNRESET. See
- // http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1739 for
- // some details.
+ // Try to set the buffer size. The kernel will silently adjust
+ // the size to an acceptable value. Then read the size back to
+ // get the size that was actually set.
//
- if(error == WSAENOTCONN || error == WSAECONNRESET)
- {
- return;
- }
-#elif defined(__APPLE__) || defined(__FreeBSD__)
- if(errno == ENOTCONN || errno == EINVAL)
+ setRecvBufferSize(fd, sizeRequested);
+ int size = getRecvBufferSize(fd);
+ if(size > 0 && size < sizeRequested) // Warn if the size that was set is less than the requested size.
{
- return;
+ Ice::Warning out(logger);
+ out << "TCP receive buffer size: requested size of " << sizeRequested << " adjusted to " << size;
}
-#else
- if(errno == ENOTCONN)
+ }
+
+ sizeRequested = properties->getPropertyAsIntWithDefault("Ice.TCP.SndSize", dfltBufSize);
+ if(sizeRequested > 0)
+ {
+ //
+ // Try to set the buffer size. The kernel will silently adjust
+ // the size to an acceptable value. Then read the size back to
+ // get the size that was actually set.
+ //
+ setSendBufferSize(fd, sizeRequested);
+ int size = getSendBufferSize(fd);
+ if(size > 0 && size < sizeRequested) // Warn if the size that was set is less than the requested size.
{
- return;
+ Ice::Warning out(logger);
+ out << "TCP send buffer size: requested size of " << sizeRequested << " adjusted to " << size;
}
-#endif
-
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
}
}
void
IceInternal::setBlock(SOCKET fd, bool block)
{
+#ifndef ICE_OS_WINRT
if(block)
{
#ifdef _WIN32
@@ -861,37 +1342,13 @@ IceInternal::setBlock(SOCKET fd, bool block)
}
#endif
}
-}
-
-void
-IceInternal::setTcpNoDelay(SOCKET fd)
-{
- int flag = 1;
- if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
- {
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-}
-
-void
-IceInternal::setKeepAlive(SOCKET fd)
-{
- int flag = 1;
- if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
- {
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
+#endif
}
void
IceInternal::setSendBufferSize(SOCKET fd, int sz)
{
+#ifndef ICE_OS_WINRT
if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&sz, int(sizeof(int))) == SOCKET_ERROR)
{
closeSocketNoThrow(fd);
@@ -899,11 +1356,19 @@ IceInternal::setSendBufferSize(SOCKET fd, int sz)
ex.error = getSocketErrno();
throw ex;
}
+#else
+ StreamSocket^ stream = dynamic_cast<StreamSocket^>(fd);
+ if(stream != nullptr)
+ {
+ stream->Control->OutboundBufferSizeInBytes = sz;
+ }
+#endif
}
int
IceInternal::getSendBufferSize(SOCKET fd)
{
+#ifndef ICE_OS_WINRT
int sz;
socklen_t len = sizeof(sz);
if(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&sz, &len) == SOCKET_ERROR ||
@@ -915,11 +1380,20 @@ IceInternal::getSendBufferSize(SOCKET fd)
throw ex;
}
return sz;
+#else
+ StreamSocket^ stream = dynamic_cast<StreamSocket^>(fd);
+ if(stream != nullptr)
+ {
+ return stream->Control->OutboundBufferSizeInBytes;
+ }
+ return 0; // Not supported
+#endif
}
void
IceInternal::setRecvBufferSize(SOCKET fd, int sz)
{
+#ifndef ICE_OS_WINRT
if(setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&sz, int(sizeof(int))) == SOCKET_ERROR)
{
closeSocketNoThrow(fd);
@@ -927,11 +1401,13 @@ IceInternal::setRecvBufferSize(SOCKET fd, int sz)
ex.error = getSocketErrno();
throw ex;
}
+#endif
}
int
IceInternal::getRecvBufferSize(SOCKET fd)
{
+#ifndef ICE_OS_WINRT
int sz;
socklen_t len = sizeof(sz);
if(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&sz, &len) == SOCKET_ERROR ||
@@ -943,26 +1419,30 @@ IceInternal::getRecvBufferSize(SOCKET fd)
throw ex;
}
return sz;
+#else
+ return 0; // Not supported
+#endif
}
void
-IceInternal::setMcastGroup(SOCKET fd, const struct sockaddr_storage& group, const string& interface)
+IceInternal::setMcastGroup(SOCKET fd, const Address& group, const string& intf)
{
+#ifndef ICE_OS_WINRT
int rc;
if(group.ss_family == AF_INET)
{
struct ip_mreq mreq;
mreq.imr_multiaddr = reinterpret_cast<const struct sockaddr_in*>(&group)->sin_addr;
mreq.imr_interface.s_addr = INADDR_ANY;
- if(interface.size() > 0)
+ if(intf.size() > 0)
{
//
// First see if it is the interface name. If not check if IP Address.
//
- mreq.imr_interface = getInterfaceAddress(interface);
+ mreq.imr_interface = getInterfaceAddress(intf);
if(mreq.imr_interface.s_addr == INADDR_ANY)
{
- struct sockaddr_storage addr = getAddressForServer(interface, 0, EnableIPv4);
+ Address addr = getAddressForServer(intf, 0, EnableIPv4);
mreq.imr_interface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr;
}
}
@@ -973,15 +1453,15 @@ IceInternal::setMcastGroup(SOCKET fd, const struct sockaddr_storage& group, cons
struct ipv6_mreq mreq;
mreq.ipv6mr_multiaddr = reinterpret_cast<const struct sockaddr_in6*>(&group)->sin6_addr;
mreq.ipv6mr_interface = 0;
- if(interface.size() != 0)
+ if(intf.size() != 0)
{
//
// First check if it is the interface name. If not check if index.
//
- mreq.ipv6mr_interface = getInterfaceIndex(interface);
+ mreq.ipv6mr_interface = getInterfaceIndex(intf);
if(mreq.ipv6mr_interface == 0)
{
- istringstream p(interface);
+ istringstream p(intf);
if(!(p >> mreq.ipv6mr_interface) || !p.eof())
{
closeSocketNoThrow(fd);
@@ -1000,21 +1480,35 @@ IceInternal::setMcastGroup(SOCKET fd, const struct sockaddr_storage& group, cons
ex.error = getSocketErrno();
throw ex;
}
+#else
+ try
+ {
+ //
+ // NOTE: WinRT doesn't allow specyfing the interface.
+ //
+ safe_cast<DatagramSocket^>(fd)->JoinMulticastGroup(group.host);
+ }
+ catch(Platform::Exception^ pex)
+ {
+ throw SocketException(__FILE__, __LINE__, (int)SocketError::GetStatus(pex->HResult));
+ }
+#endif
}
void
-IceInternal::setMcastInterface(SOCKET fd, const string& interface, bool IPv4)
+IceInternal::setMcastInterface(SOCKET fd, const string& intf, const Address& addr)
{
+#ifndef ICE_OS_WINRT
int rc;
- if(IPv4)
+ if(addr.ss_family == AF_INET)
{
//
// First see if it is the interface name. If not check if IP Address.
//
- struct in_addr iface = getInterfaceAddress(interface);
+ struct in_addr iface = getInterfaceAddress(intf);
if(iface.s_addr == INADDR_ANY)
{
- struct sockaddr_storage addr = getAddressForServer(interface, 0, EnableIPv4);
+ Address addr = getAddressForServer(intf, 0, EnableIPv4);
iface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr;
}
rc = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, int(sizeof(iface)));
@@ -1024,10 +1518,10 @@ IceInternal::setMcastInterface(SOCKET fd, const string& interface, bool IPv4)
//
// First check if it is the interface name. If not check if index.
//
- int interfaceNum = getInterfaceIndex(interface);
+ int interfaceNum = getInterfaceIndex(intf);
if(interfaceNum == 0)
{
- istringstream p(interface);
+ istringstream p(intf);
if(!(p >> interfaceNum) || !p.eof())
{
closeSocketNoThrow(fd);
@@ -1044,13 +1538,15 @@ IceInternal::setMcastInterface(SOCKET fd, const string& interface, bool IPv4)
ex.error = getSocketErrno();
throw ex;
}
+#endif
}
void
-IceInternal::setMcastTtl(SOCKET fd, int ttl, bool IPv4)
+IceInternal::setMcastTtl(SOCKET fd, int ttl, const Address& addr)
{
+#ifndef ICE_OS_WINRT
int rc;
- if(IPv4)
+ if(addr.ss_family == AF_INET)
{
rc = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, int(sizeof(int)));
}
@@ -1065,11 +1561,13 @@ IceInternal::setMcastTtl(SOCKET fd, int ttl, bool IPv4)
ex.error = getSocketErrno();
throw ex;
}
+#endif
}
void
IceInternal::setReuseAddress(SOCKET fd, bool reuse)
{
+#ifndef ICE_OS_WINRT
int flag = reuse ? 1 : 0;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
{
@@ -1078,11 +1576,53 @@ IceInternal::setReuseAddress(SOCKET fd, bool reuse)
ex.error = getSocketErrno();
throw ex;
}
+#endif
}
-struct sockaddr_storage
-IceInternal::doBind(SOCKET fd, const struct sockaddr_storage& addr)
+Address
+IceInternal::doBind(SOCKET fd, const Address& addr)
{
+#ifdef ICE_OS_WINRT
+ Address local;
+ try
+ {
+ StreamSocketListener^ listener = dynamic_cast<StreamSocketListener^>(fd);
+ if(listener != nullptr)
+ {
+ if(addr.host == nullptr) // inaddr_any
+ {
+ concurrency::create_task(listener->BindServiceNameAsync(addr.port)).wait();
+ }
+ else
+ {
+ concurrency::create_task(listener->BindEndpointAsync(addr.host, addr.port)).wait();
+ }
+ local.host = addr.host;
+ local.port = listener->Information->LocalPort;
+ }
+
+ DatagramSocket^ datagram = dynamic_cast<DatagramSocket^>(fd);
+ if(datagram != nullptr)
+ {
+ if(addr.host == nullptr) // inaddr_any
+ {
+ concurrency::create_task(datagram->BindServiceNameAsync(addr.port)).wait();
+ }
+ else
+ {
+ concurrency::create_task(datagram->BindEndpointAsync(addr.host, addr.port)).wait();
+ }
+ local.host = datagram->Information->LocalAddress;
+ local.port = datagram->Information->LocalPort;
+ }
+ }
+ catch(Platform::Exception^ pex)
+ {
+ closeSocketNoThrow(fd);
+ checkErrorCode(__FILE__, __LINE__, pex->HResult);
+ }
+ return local;
+#else
int size;
if(addr.ss_family == AF_INET)
{
@@ -1106,7 +1646,7 @@ IceInternal::doBind(SOCKET fd, const struct sockaddr_storage& addr)
throw ex;
}
- struct sockaddr_storage local;
+ Address local;
socklen_t len = static_cast<socklen_t>(sizeof(local));
#ifdef NDEBUG
getsockname(fd, reinterpret_cast<struct sockaddr*>(&local), &len);
@@ -1115,6 +1655,166 @@ IceInternal::doBind(SOCKET fd, const struct sockaddr_storage& addr)
assert(ret != SOCKET_ERROR);
#endif
return local;
+#endif
+}
+
+#ifndef ICE_OS_WINRT
+
+int
+IceInternal::getSocketErrno()
+{
+#if defined(_WIN32)
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+bool
+IceInternal::interrupted()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEINTR;
+#else
+# ifdef EPROTO
+ return errno == EINTR || errno == EPROTO;
+# else
+ return errno == EINTR;
+# endif
+#endif
+}
+
+bool
+IceInternal::acceptInterrupted()
+{
+ if(interrupted())
+ {
+ return true;
+ }
+
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAECONNABORTED ||
+ error == WSAECONNRESET ||
+ error == WSAETIMEDOUT;
+#else
+ return errno == ECONNABORTED ||
+ errno == ECONNRESET ||
+ errno == ETIMEDOUT;
+#endif
+}
+
+bool
+IceInternal::noBuffers()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAENOBUFS ||
+ error == WSAEFAULT;
+#else
+ return errno == ENOBUFS;
+#endif
+}
+
+bool
+IceInternal::wouldBlock()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAEWOULDBLOCK || error == WSA_IO_PENDING || error == ERROR_IO_PENDING;
+#else
+ return errno == EAGAIN || errno == EWOULDBLOCK;
+#endif
+}
+
+bool
+IceInternal::connectFailed()
+{
+#if defined(_WIN32)
+ int error = WSAGetLastError();
+ return error == WSAECONNREFUSED ||
+ error == WSAETIMEDOUT ||
+ error == WSAENETUNREACH ||
+ error == WSAEHOSTUNREACH ||
+ error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAECONNABORTED;
+#else
+ return errno == ECONNREFUSED ||
+ errno == ETIMEDOUT ||
+ errno == ENETUNREACH ||
+ errno == EHOSTUNREACH ||
+ errno == ECONNRESET ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED;
+#endif
+}
+
+bool
+IceInternal::connectionRefused()
+{
+#if defined(_WIN32)
+ int error = WSAGetLastError();
+ return error == WSAECONNREFUSED || error == ERROR_CONNECTION_REFUSED;
+#else
+ return errno == ECONNREFUSED;
+#endif
+}
+
+bool
+IceInternal::connectionLost()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAENOTCONN ||
+# ifdef ICE_USE_IOCP
+ error == ERROR_NETNAME_DELETED ||
+# endif
+ error == WSAECONNABORTED;
+#else
+ return errno == ECONNRESET ||
+ errno == ENOTCONN ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED ||
+ errno == EPIPE;
+#endif
+}
+
+bool
+IceInternal::connectInProgress()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAEWOULDBLOCK || error == WSA_IO_PENDING || error == ERROR_IO_PENDING;
+#else
+ return errno == EINPROGRESS;
+#endif
+}
+
+bool
+IceInternal::notConnected()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAENOTCONN;
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+ return errno == ENOTCONN || errno == EINVAL;
+#else
+ return errno == ENOTCONN;
+#endif
+}
+
+bool
+IceInternal::recvTruncated()
+{
+#ifdef _WIN32
+ int err = WSAGetLastError();
+ return err == WSAEMSGSIZE || err == ERROR_MORE_DATA;
+#else
+ // We don't get an error under Linux if a datagram is truncated.
+ return false;
+#endif
}
void
@@ -1136,7 +1836,7 @@ repeatListen:
}
bool
-IceInternal::doConnect(SOCKET fd, const struct sockaddr_storage& addr)
+IceInternal::doConnect(SOCKET fd, const Address& addr)
{
repeatConnect:
int size;
@@ -1193,7 +1893,7 @@ repeatConnect:
// a server which was just deactivated if the client socket re-uses the same ephemeral
// port as the server).
//
- struct sockaddr_storage localAddr;
+ Address localAddr;
fdToLocalAddress(fd, localAddr);
if(compareAddress(addr, localAddr) == 0)
{
@@ -1218,7 +1918,7 @@ IceInternal::doFinishConnect(SOCKET fd)
// necessary, otherwise no error is reported through
// getsockopt.
//
-#ifdef _WIN32
+#if defined(_WIN32)
Sleep(0);
#endif
@@ -1230,10 +1930,10 @@ IceInternal::doFinishConnect(SOCKET fd)
ex.error = getSocketErrno();
throw ex;
}
-
+
if(val > 0)
{
-#ifdef _WIN32
+#if defined(_WIN32)
WSASetLastError(val);
#else
errno = val;
@@ -1264,9 +1964,9 @@ IceInternal::doFinishConnect(SOCKET fd)
// a server which was just deactivated if the client socket re-uses the same ephemeral
// port as the server).
//
- struct sockaddr_storage localAddr;
+ Address localAddr;
fdToLocalAddress(fd, localAddr);
- struct sockaddr_storage remoteAddr;
+ Address remoteAddr;
if(fdToRemoteAddress(fd, remoteAddr) && compareAddress(remoteAddr, localAddr) == 0)
{
ConnectionRefusedException ex(__FILE__, __LINE__);
@@ -1276,141 +1976,6 @@ IceInternal::doFinishConnect(SOCKET fd)
#endif
}
-#ifdef ICE_USE_IOCP
-void
-IceInternal::doConnectAsync(SOCKET fd, const struct sockaddr_storage& addr, AsyncInfo& info)
-{
- //
- // NOTE: It's the caller's responsability to close the socket upon
- // failure to connect. The socket isn't closed by this method.
- //
-
- struct sockaddr_storage bindAddr;
- memset(&bindAddr, 0, sizeof(bindAddr));
-
- int size;
- if(addr.ss_family == AF_INET)
- {
- size = sizeof(sockaddr_in);
-
- struct sockaddr_in* addrin = reinterpret_cast<struct sockaddr_in*>(&bindAddr);
- addrin->sin_family = AF_INET;
- addrin->sin_port = htons(0);
- addrin->sin_addr.s_addr = htonl(INADDR_ANY);
- }
- else if(addr.ss_family == AF_INET6)
- {
- size = sizeof(sockaddr_in6);
-
- struct sockaddr_in6* addrin = reinterpret_cast<struct sockaddr_in6*>(&bindAddr);
- addrin->sin6_family = AF_INET6;
- addrin->sin6_port = htons(0);
- addrin->sin6_addr = in6addr_any;
- }
- else
- {
- assert(false);
- size = 0; // Keep the compiler happy.
- }
-
- if(bind(fd, reinterpret_cast<const struct sockaddr*>(&bindAddr), size) == SOCKET_ERROR)
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- LPFN_CONNECTEX ConnectEx = NULL; // a pointer to the 'ConnectEx()' function
- GUID GuidConnectEx = WSAID_CONNECTEX; // The Guid
- DWORD dwBytes;
- if(WSAIoctl(fd,
- SIO_GET_EXTENSION_FUNCTION_POINTER,
- &GuidConnectEx,
- sizeof(GuidConnectEx),
- &ConnectEx,
- sizeof(ConnectEx),
- &dwBytes,
- NULL,
- NULL) == SOCKET_ERROR)
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- if(!ConnectEx(fd, reinterpret_cast<const struct sockaddr*>(&addr), size, 0, 0, 0,
-#if defined(_MSC_VER) && (_MSC_VER < 1300) // COMPILER FIX: VC60
- reinterpret_cast<LPOVERLAPPED>(&info)
-#else
- &info
-#endif
- ))
- {
- if(!connectInProgress())
- {
- if(connectionRefused())
- {
- ConnectionRefusedException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else if(connectFailed())
- {
- ConnectFailedException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- }
- }
-
-}
-
-void
-IceInternal::doFinishConnectAsync(SOCKET fd, AsyncInfo& info)
-{
- //
- // NOTE: It's the caller's responsability to close the socket upon
- // failure to connect. The socket isn't closed by this method.
- //
-
- if(info.count == SOCKET_ERROR)
- {
- WSASetLastError(info.error);
- if(connectionRefused())
- {
- ConnectionRefusedException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else if(connectFailed())
- {
- ConnectFailedException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- }
-
- if(setsockopt(fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR)
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-}
-#endif
-
SOCKET
IceInternal::doAccept(SOCKET fd)
{
@@ -1438,212 +2003,16 @@ repeatAccept:
return ret;
}
-struct sockaddr_storage
-IceInternal::getAddressForServer(const string& host, int port, ProtocolSupport protocol)
-{
- return getAddressImpl(host, port, protocol, true);
-}
-
-struct sockaddr_storage
-IceInternal::getAddress(const string& host, int port, ProtocolSupport protocol)
-{
- return getAddressImpl(host, port, protocol, false);
-}
-
-vector<struct sockaddr_storage>
-IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol, bool blocking)
-{
- vector<struct sockaddr_storage> result;
- struct sockaddr_storage addr;
- memset(&addr, 0, sizeof(struct 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 != EnableIPv4)
- {
- sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
- addrin6->sin6_family = AF_INET6;
- addrin6->sin6_port = htons(port);
- addrin6->sin6_addr = in6addr_loopback;
- result.push_back(addr);
- }
- if(protocol != EnableIPv6)
- {
- sockaddr_in* addrin = reinterpret_cast<sockaddr_in*>(&addr);
- addrin->sin_family = AF_INET;
- addrin->sin_port = htons(port);
- addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- result.push_back(addr);
- }
- return result;
- }
-
- struct addrinfo* info = 0;
- int retry = 5;
-
- 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;
- }
-
- 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);
-
- // In theory, getaddrinfo should only return EAI_NONAME if AI_NUMERICHOST is specified and the host name
- // is not a IP address. However on some platforms (e.g. Mac OS X 10.4.x) EAI_NODATA is also returned so
- // we also check for it.
-#ifdef EAI_NODATA
- if(!blocking && (rs == EAI_NONAME || rs == EAI_NODATA))
-#else
- if(!blocking && rs == EAI_NONAME)
-#endif
- {
- 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)
- {
- 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);
- }
- else if(p->ai_family == PF_INET6)
- {
- struct sockaddr_in6* addrin6 = reinterpret_cast<sockaddr_in6*>(&addr);
- addrin6->sin6_port = htons(port);
- }
-
- 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);
-
- if(result.size() == 0)
- {
- DNSException ex(__FILE__, __LINE__);
- ex.host = host;
- throw ex;
- }
-
- return result;
-}
-
-int
-IceInternal::compareAddress(const struct sockaddr_storage& addr1, const struct sockaddr_storage& addr2)
-{
- if(addr1.ss_family < addr2.ss_family)
- {
- return -1;
- }
- else if(addr2.ss_family < addr1.ss_family)
- {
- return 1;
- }
-
- if(addr1.ss_family == AF_INET)
- {
- const struct sockaddr_in* addr1in = reinterpret_cast<const sockaddr_in*>(&addr1);
- const struct sockaddr_in* addr2in = reinterpret_cast<const sockaddr_in*>(&addr2);
-
- 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
- {
- 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;
-}
void
IceInternal::createPipe(SOCKET fds[2])
{
#ifdef _WIN32
- SOCKET fd = createSocket(false, AF_INET);
+ SOCKET fd = createSocketImpl(false, AF_INET);
setBlock(fd, true);
- struct sockaddr_storage addr;
+ Address addr;
memset(&addr, 0, sizeof(addr));
struct sockaddr_in* addrin = reinterpret_cast<struct sockaddr_in*>(&addr);
@@ -1656,7 +2025,7 @@ IceInternal::createPipe(SOCKET fds[2])
try
{
- fds[0] = createSocket(false, AF_INET);
+ fds[0] = createSocketImpl(false, AF_INET);
}
catch(...)
{
@@ -1739,290 +2108,204 @@ IceInternal::createPipe(SOCKET fds[2])
#endif
}
-#ifdef _WIN32
-
-string
-IceInternal::errorToStringDNS(int error)
-{
- return IceUtilInternal::errorToString(error);
-}
-
-#else
+#else // ICE_OS_WINRT
-string
-IceInternal::errorToStringDNS(int error)
-{
- return gai_strerror(error);
-}
-
-#endif
-
-std::string
-IceInternal::fdToString(SOCKET fd)
+void
+IceInternal::checkConnectErrorCode(const char* file, int line, HRESULT herr, HostName^ host)
{
- if(fd == INVALID_SOCKET)
+ SocketErrorStatus error = SocketError::GetStatus(herr);
+ if(error == SocketErrorStatus::ConnectionRefused)
{
- return "<closed>";
+ ConnectionRefusedException ex(file, line);
+ ex.error = static_cast<int>(error);
+ throw ex;
}
-
- struct sockaddr_storage localAddr;
- fdToLocalAddress(fd, localAddr);
-
- struct sockaddr_storage remoteAddr;
- bool peerConnected = fdToRemoteAddress(fd, remoteAddr);
-
- return addressesToString(localAddr, remoteAddr, peerConnected);
-};
-
-void
-IceInternal::fdToAddressAndPort(SOCKET fd, string& localAddress, int& localPort, string& remoteAddress, int& remotePort)
-{
- if(fd == INVALID_SOCKET)
+ else if(error == SocketErrorStatus::NetworkDroppedConnectionOnReset ||
+ error == SocketErrorStatus::ConnectionTimedOut ||
+ error == SocketErrorStatus::NetworkIsUnreachable ||
+ error == SocketErrorStatus::UnreachableHost ||
+ error == SocketErrorStatus::ConnectionResetByPeer ||
+ error == SocketErrorStatus::SoftwareCausedConnectionAbort)
{
- localAddress.clear();
- remoteAddress.clear();
- localPort = -1;
- remotePort = -1;
- return;
+ ConnectFailedException ex(file, line);
+ ex.error = static_cast<int>(error);
+ throw ex;
}
-
- struct sockaddr_storage localAddr;
- fdToLocalAddress(fd, localAddr);
- addrToAddressAndPort(localAddr, localAddress, localPort);
-
- struct sockaddr_storage remoteAddr;
- if(fdToRemoteAddress(fd, remoteAddr))
+ else if(error == SocketErrorStatus::HostNotFound)
{
- addrToAddressAndPort(remoteAddr, remoteAddress, remotePort);
+ DNSException ex(file, line);
+ ex.error = static_cast<int>(error);
+ ex.host = IceUtil::wstringToString(host->RawName->Data());
+ throw ex;
}
else
{
- remoteAddress.clear();
- remotePort = -1;
+ SocketException ex(file, line);
+ ex.error = static_cast<int>(error);
+ throw ex;
}
}
void
-IceInternal::addrToAddressAndPort(const struct sockaddr_storage& addr, string& address, int& port)
-{
- address = inetAddrToString(addr);
- port = getPort(addr);
-}
-
-std::string
-IceInternal::addressesToString(const struct sockaddr_storage& localAddr, const struct sockaddr_storage& remoteAddr,
- bool peerConnected)
+IceInternal::checkErrorCode(const char* file, int line, HRESULT herr)
{
- ostringstream s;
- s << "local address = " << addrToString(localAddr);
- if(peerConnected)
+ SocketErrorStatus error = SocketError::GetStatus(herr);
+ if(error == SocketErrorStatus::NetworkDroppedConnectionOnReset ||
+ error == SocketErrorStatus::SoftwareCausedConnectionAbort ||
+ error == SocketErrorStatus::ConnectionResetByPeer)
{
- s << "\nremote address = " << addrToString(remoteAddr);
+ ConnectionLostException ex(file, line);
+ ex.error = static_cast<int>(error);
+ throw ex;
}
- else
+ else if(error == SocketErrorStatus::HostNotFound)
{
- s << "\nremote address = <not connected>";
+ DNSException ex(file, line);
+ ex.error = static_cast<int>(error);
+ throw ex;
}
- return s.str();
-}
-
-void
-IceInternal::fdToLocalAddress(SOCKET fd, struct sockaddr_storage& addr)
-{
- socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
- if(getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
+ else
{
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
+ SocketException ex(file, line);
+ ex.error = static_cast<int>(error);
throw ex;
}
}
-bool
-IceInternal::fdToRemoteAddress(SOCKET fd, struct sockaddr_storage& addr)
-{
- socklen_t len = static_cast<socklen_t>(sizeof(struct sockaddr_storage));
- if(getpeername(fd, reinterpret_cast<struct sockaddr*>(&addr), &len) == SOCKET_ERROR)
- {
- if(notConnected())
- {
- return false;
- }
- else
- {
- closeSocketNoThrow(fd);
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- }
- return true;
-}
+#endif
-string
-IceInternal::inetAddrToString(const struct sockaddr_storage& ss)
+#if defined(ICE_USE_IOCP)
+void
+IceInternal::doConnectAsync(SOCKET fd, const Address& addr, AsyncInfo& info)
{
- int size = 0;
- if(ss.ss_family == AF_INET)
- {
- size = sizeof(sockaddr_in);
- }
- else if(ss.ss_family == AF_INET6)
- {
- size = sizeof(sockaddr_in6);
- }
- else
- {
- return "";
- }
-
- char namebuf[1024];
- namebuf[0] = '\0';
- getnameinfo(reinterpret_cast<const struct sockaddr *>(&ss), size, namebuf, sizeof(namebuf), 0, 0, NI_NUMERICHOST);
- return string(namebuf);
-}
+ //
+ // NOTE: It's the caller's responsability to close the socket upon
+ // failure to connect. The socket isn't closed by this method.
+ //
-string
-IceInternal::addrToString(const struct sockaddr_storage& addr)
-{
- ostringstream s;
- string port;
- s << inetAddrToString(addr) << ':' << getPort(addr);
- return s.str();
-}
+ Address bindAddr;
+ memset(&bindAddr, 0, sizeof(bindAddr));
-bool
-IceInternal::isMulticast(const struct sockaddr_storage& addr)
-{
+ int size;
if(addr.ss_family == AF_INET)
{
- return IN_MULTICAST(ntohl(reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr.s_addr));
- }
- else if(addr.ss_family == AF_INET6)
- {
- return IN6_IS_ADDR_MULTICAST(&reinterpret_cast<const struct sockaddr_in6*>(&addr)->sin6_addr);
- }
- else
- {
- return false;
- }
-}
+ size = sizeof(sockaddr_in);
-int
-IceInternal::getPort(const struct sockaddr_storage& addr)
-{
- if(addr.ss_family == AF_INET)
- {
- return ntohs(reinterpret_cast<const sockaddr_in*>(&addr)->sin_port);
+ struct sockaddr_in* addrin = reinterpret_cast<struct sockaddr_in*>(&bindAddr);
+ addrin->sin_family = AF_INET;
+ addrin->sin_port = htons(0);
+ addrin->sin_addr.s_addr = htonl(INADDR_ANY);
}
else if(addr.ss_family == AF_INET6)
{
- return ntohs(reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port);
+ size = sizeof(sockaddr_in6);
+
+ struct sockaddr_in6* addrin = reinterpret_cast<struct sockaddr_in6*>(&bindAddr);
+ addrin->sin6_family = AF_INET6;
+ addrin->sin6_port = htons(0);
+ addrin->sin6_addr = in6addr_any;
}
else
{
- return -1;
+ assert(false);
+ size = 0; // Keep the compiler happy.
}
-}
-void
-IceInternal::setPort(struct sockaddr_storage& addr, int port)
-{
- if(addr.ss_family == AF_INET)
+ if(bind(fd, reinterpret_cast<const struct sockaddr*>(&bindAddr), size) == SOCKET_ERROR)
{
- reinterpret_cast<sockaddr_in*>(&addr)->sin_port = htons(port);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
- else
+
+ LPFN_CONNECTEX ConnectEx = NULL; // a pointer to the 'ConnectEx()' function
+ GUID GuidConnectEx = WSAID_CONNECTEX; // The Guid
+ DWORD dwBytes;
+ if(WSAIoctl(fd,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &GuidConnectEx,
+ sizeof(GuidConnectEx),
+ &ConnectEx,
+ sizeof(ConnectEx),
+ &dwBytes,
+ NULL,
+ NULL) == SOCKET_ERROR)
{
- assert(addr.ss_family == AF_INET6);
- reinterpret_cast<sockaddr_in6*>(&addr)->sin6_port = htons(port);
- }
-}
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
-vector<string>
-IceInternal::getHostsForEndpointExpand(const string& host, ProtocolSupport protocolSupport, bool includeLoopback)
-{
- vector<string> hosts;
- if(host.empty() || isWildcard(host, protocolSupport))
+ if(!ConnectEx(fd, reinterpret_cast<const struct sockaddr*>(&addr), size, 0, 0, 0,
+#if defined(_MSC_VER) && (_MSC_VER < 1300) // COMPILER FIX: VC60
+ reinterpret_cast<LPOVERLAPPED>(&info)
+#else
+ &info
+#endif
+ ))
{
- vector<struct sockaddr_storage> addrs = getLocalAddresses(protocolSupport);
- for(vector<struct sockaddr_storage>::const_iterator p = addrs.begin(); p != addrs.end(); ++p)
+ if(!connectInProgress())
{
- //
- // NOTE: We don't publish link-local IPv6 addresses as these addresses can only
- // be accessed in general with a scope-id.
- //
- if(p->ss_family != AF_INET6 ||
- !IN6_IS_ADDR_LINKLOCAL(&reinterpret_cast<const struct sockaddr_in6*>(&(*p))->sin6_addr))
+ if(connectionRefused())
{
- hosts.push_back(inetAddrToString(*p));
+ ConnectionRefusedException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
- }
-
- if(hosts.empty() || includeLoopback)
- {
- if(protocolSupport != EnableIPv6)
+ else if(connectFailed())
{
- hosts.push_back("127.0.0.1");
+ ConnectFailedException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
- if(protocolSupport != EnableIPv4)
+ else
{
- hosts.push_back("0:0:0:0:0:0:0:1");
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
}
}
- return hosts; // An empty host list indicates to just use the given host.
}
void
-IceInternal::setTcpBufSize(SOCKET fd, const Ice::PropertiesPtr& properties, const Ice::LoggerPtr& logger)
+IceInternal::doFinishConnectAsync(SOCKET fd, AsyncInfo& info)
{
- assert(fd != INVALID_SOCKET);
-
//
- // By default, on Windows we use a 128KB buffer size. On Unix
- // platforms, we use the system defaults.
+ // NOTE: It's the caller's responsability to close the socket upon
+ // failure to connect. The socket isn't closed by this method.
//
-#ifdef _WIN32
- const int dfltBufSize = 128 * 1024;
-#else
- const int dfltBufSize = 0;
-#endif
- Int sizeRequested;
- sizeRequested = properties->getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize);
- if(sizeRequested > 0)
+ if(info.count == SOCKET_ERROR)
{
- //
- // Try to set the buffer size. The kernel will silently adjust
- // the size to an acceptable value. Then read the size back to
- // get the size that was actually set.
- //
- setRecvBufferSize(fd, sizeRequested);
- int size = getRecvBufferSize(fd);
- if(size < sizeRequested) // Warn if the size that was set is less than the requested size.
+ WSASetLastError(info.error);
+ if(connectionRefused())
{
- Ice::Warning out(logger);
- out << "TCP receive buffer size: requested size of " << sizeRequested << " adjusted to " << size;
+ ConnectionRefusedException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ else if(connectFailed())
+ {
+ ConnectFailedException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ else
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
}
- sizeRequested = properties->getPropertyAsIntWithDefault("Ice.TCP.SndSize", dfltBufSize);
- if(sizeRequested > 0)
+ if(setsockopt(fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == SOCKET_ERROR)
{
- //
- // Try to set the buffer size. The kernel will silently adjust
- // the size to an acceptable value. Then read the size back to
- // get the size that was actually set.
- //
- setSendBufferSize(fd, sizeRequested);
- int size = getSendBufferSize(fd);
- if(size < sizeRequested) // Warn if the size that was set is less than the requested size.
- {
- Ice::Warning out(logger);
- out << "TCP send buffer size: requested size of " << sizeRequested << " adjusted to " << size;
- }
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
}
}
+#endif
+