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.cpp902
1 files changed, 902 insertions, 0 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp
new file mode 100644
index 00000000000..1c74ec036ad
--- /dev/null
+++ b/cpp/src/Ice/Network.cpp
@@ -0,0 +1,902 @@
+// **********************************************************************
+//
+// Copyright (c) 2001
+// MutableRealms, Inc.
+// Huntsville, AL, USA
+//
+// All Rights Reserved
+//
+// **********************************************************************
+
+#include <Ice/Network.h>
+#include <Ice/LocalException.h>
+#include <sstream>
+
+using namespace std;
+using namespace Ice;
+using namespace IceInternal;
+
+bool
+IceInternal::interrupted()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAEINTR)
+ return true;
+#else
+ if (errno == EINTR ||
+ errno == EPROTO)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::acceptInterrupted()
+{
+ if (interrupted())
+ return true;
+
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAECONNABORTED ||
+ error == WSAECONNRESET ||
+ error == WSAETIMEDOUT)
+ return true;
+#else
+ if (errno == ECONNABORTED ||
+ errno == ECONNRESET ||
+ errno == ETIMEDOUT)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::noBuffers()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAENOBUFS ||
+ error == WSAEFAULT)
+ return true;
+#else
+ if (errno == ENOBUFS)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::wouldBlock()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAEWOULDBLOCK)
+ return true;
+#else
+ if (errno == EAGAIN ||
+ errno == EWOULDBLOCK)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::connectFailed()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAECONNREFUSED ||
+ error == WSAETIMEDOUT ||
+ error == WSAENETUNREACH ||
+ error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAECONNABORTED)
+ return true;
+#else
+ if (errno == ECONNREFUSED ||
+ errno == ETIMEDOUT ||
+ errno == ENETUNREACH ||
+ errno == ECONNRESET ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::connectInProgress()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAEWOULDBLOCK)
+ return true;
+#else
+ if (errno == EINPROGRESS)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::connectionLost()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAECONNABORTED)
+ return true;
+#else
+ if (errno == ECONNRESET ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED)
+ return true;
+#endif
+ else
+ return false;
+}
+
+bool
+IceInternal::notConnected()
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ if (error == WSAENOTCONN)
+ return true;
+#else
+ if (errno == ENOTCONN)
+ return true;
+#endif
+ else
+ return false;
+}
+
+int
+IceInternal::createSocket(bool udp)
+{
+ int fd;
+
+ if (udp)
+ fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ else
+ fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (fd == INVALID_SOCKET)
+ throw SocketException(__FILE__, __LINE__);
+
+ setBlock(fd, false);
+
+ if (!udp)
+ {
+ setTcpNoDelay(fd);
+ setKeepAlive(fd);
+ }
+
+ return fd;
+}
+
+void
+IceInternal::closeSocket(int fd)
+{
+#ifdef WIN32
+ int error = WSAGetLastError();
+ closesocket(fd);
+ WSASetLastError(error);
+#else
+ int error = errno;
+ close(fd);
+ errno = error;
+#endif
+}
+
+void
+IceInternal::setBlock(int fd, bool block)
+{
+ if (block)
+ {
+#ifdef WIN32
+ unsigned long arg = 0;
+ ioctlsocket(fd, FIONBIO, &arg);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ flags &= ~O_NONBLOCK;
+ fcntl(fd, F_SETFL, flags);
+#endif
+ }
+ else
+ {
+#ifdef WIN32
+ unsigned long arg = 1;
+ ioctlsocket(fd, FIONBIO, &arg);
+#else
+ int flags = fcntl(fd, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(fd, F_SETFL, flags);
+#endif
+ }
+}
+
+void
+IceInternal::setTcpNoDelay(int fd)
+{
+ int flag = 1;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int)) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+}
+
+void
+IceInternal::setKeepAlive(int fd)
+{
+ int flag = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, sizeof(int)) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+}
+
+void
+IceInternal::setSendBufferSize(int fd, int sz)
+{
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&sz, sizeof(int)) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+}
+
+void
+IceInternal::doBind(int fd, struct sockaddr_in& addr)
+{
+#ifndef WIN32
+ int flag = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(int)) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+#endif
+
+ if (bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ socklen_t len = sizeof(addr);
+ int ret = getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len);
+ assert(ret != SOCKET_ERROR);
+}
+
+void
+IceInternal::doListen(int fd, int backlog)
+{
+repeatListen:
+ if (::listen(fd, backlog) == SOCKET_ERROR)
+ {
+ if (interrupted())
+ goto repeatListen;
+
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+}
+
+void
+IceInternal::doConnect(int fd, struct sockaddr_in& addr, int timeout)
+{
+#ifdef WIN32
+ //
+ // Set larger send buffer size to avoid performance problems on
+ // WIN32
+ //
+ setSendBufferSize(fd, 64 * 1024);
+#endif
+
+repeatConnect:
+ if (::connect(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR)
+ {
+ if (interrupted())
+ goto repeatConnect;
+
+ if (connectInProgress())
+ {
+ repeatSelect:
+ int ret;
+ fd_set wFdSet;
+ FD_ZERO(&wFdSet);
+ FD_SET(fd, &wFdSet);
+#ifdef WIN32
+ //
+ // WIN32 notifies about connection failures
+ // through the exception filedescriptors
+ //
+ fd_set xFdSet;
+ FD_ZERO(&xFdSet);
+ FD_SET(fd, &xFdSet);
+#endif
+ if (timeout >= 0)
+ {
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
+#ifdef WIN32
+ ret = ::select(fd + 1, 0, &wFdSet, &xFdSet, &tv);
+#else
+ ret = ::select(fd + 1, 0, &wFdSet, 0, &tv);
+#endif
+ }
+ else
+ {
+#ifdef WIN32
+ ret = ::select(fd + 1, 0, &wFdSet, &xFdSet, 0);
+#else
+ ret = ::select(fd + 1, 0, &wFdSet, 0, 0);
+#endif
+ }
+
+ if (ret == 0)
+ {
+ closeSocket(fd);
+ throw ConnectTimeoutException(__FILE__, __LINE__);
+ }
+ else if (ret == SOCKET_ERROR)
+ {
+ if (interrupted())
+ goto repeatSelect;
+
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+#ifdef WIN32
+ //
+ // Strange windows bug: The following call to Sleep() is
+ // necessary, otherwise no error is reported through
+ // getsockopt.
+ //
+ Sleep(0);
+#endif
+ socklen_t len = sizeof(socklen_t);
+ int val;
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&val), &len) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ if (val > 0)
+ {
+ closeSocket(fd);
+#ifdef WIN32
+ WSASetLastError(val);
+#else
+ errno = val;
+#endif
+ if (connectFailed())
+ throw ConnectFailedException(__FILE__, __LINE__);
+ else
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ return;
+ }
+
+ closeSocket(fd);
+ if (connectFailed())
+ throw ConnectFailedException(__FILE__, __LINE__);
+ else
+ throw SocketException(__FILE__, __LINE__);
+ }
+}
+
+int
+IceInternal::doAccept(int fd, int timeout)
+{
+ int ret;
+
+repeatAccept:
+ if ((ret = ::accept(fd, 0, 0)) == INVALID_SOCKET)
+ {
+ if (acceptInterrupted())
+ goto repeatAccept;
+
+ if (wouldBlock())
+ {
+ repeatSelect:
+ int ret;
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(fd, &fdSet);
+ if (timeout >= 0)
+ {
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
+ ret = ::select(fd + 1, 0, &fdSet, 0, &tv);
+ }
+ else
+ {
+ ret = ::select(fd + 1, 0, &fdSet, 0, 0);
+ }
+
+ if (ret == SOCKET_ERROR)
+ {
+ if (interrupted())
+ goto repeatSelect;
+
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ if (ret == 0)
+ throw TimeoutException(__FILE__, __LINE__);
+
+ goto repeatAccept;
+ }
+
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ setTcpNoDelay(ret);
+ setKeepAlive(ret);
+
+#ifdef WIN32
+ //
+ // Set larger send buffer size to avoid performance problems on
+ // WIN32
+ //
+ setSendBufferSize(ret, 64 * 1024);
+#endif
+
+ return ret;
+}
+
+static JTCMutex getHostByNameMutex;
+
+void
+IceInternal::getAddress(const char* host, int port, struct sockaddr_in& addr)
+{
+ 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);
+
+ if (addr.sin_addr.s_addr == INADDR_NONE)
+ {
+ JTCSyncT<JTCMutex> sync(getHostByNameMutex);
+
+ struct hostent* entry;
+ int retry = 5; // TODO: Should be configurable
+
+ do
+ {
+ entry = gethostbyname(host);
+ }
+#ifdef WIN32
+ while (!entry && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
+#else
+ while (!entry && h_errno == TRY_AGAIN && --retry >= 0);
+#endif
+
+ if (!entry)
+ throw DNSException(__FILE__, __LINE__);
+
+ memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
+ }
+}
+
+void
+IceInternal::getLocalAddress(int port, struct sockaddr_in& addr)
+{
+ char host[1024 + 1];
+ if (gethostname(host, 1024) == -1)
+ throw SystemException(__FILE__, __LINE__);
+
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ {
+ JTCSyncT<JTCMutex> sync(getHostByNameMutex);
+
+ struct hostent* entry;
+ int retry = 5; // TODO: Should be configurable
+
+ do
+ {
+ entry = gethostbyname(host);
+ }
+#ifdef WIN32
+ while (!entry && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
+#else
+ while (!entry && h_errno == TRY_AGAIN && --retry >= 0);
+#endif
+
+ if (!entry)
+ throw DNSException(__FILE__, __LINE__);
+
+ memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
+ }
+}
+
+string
+IceInternal::getLocalHost(bool numeric)
+{
+ char host[1024 + 1];
+ if (gethostname(host, 1024) == -1)
+ throw SystemException(__FILE__, __LINE__);
+
+ {
+ JTCSyncT<JTCMutex> sync(getHostByNameMutex);
+
+ struct hostent* entry;
+ int retry = 5; // TODO: Should be configurable
+
+ do
+ entry = gethostbyname(host);
+#ifdef WIN32
+ while (!entry && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
+#else
+ while (!entry && h_errno == TRY_AGAIN && --retry >= 0);
+#endif
+
+ if (!entry)
+ throw DNSException(__FILE__, __LINE__);
+
+ if (numeric)
+ {
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ memcpy(&addr.sin_addr, entry->h_addr, entry->h_length);
+ return string(inet_ntoa(addr.sin_addr));
+ }
+ else
+ return string(entry->h_name);
+ }
+}
+
+void
+IceInternal::createPipe(int fds[2])
+{
+#ifdef WIN32
+
+ int fd = createSocket(false);
+
+ 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);
+
+ doBind(fd, addr);
+ doListen(fd, 1);
+
+ try
+ {
+ fds[0] = createSocket(false);
+ }
+ catch(...)
+ {
+ closeSocket(fd);
+ throw;
+ }
+
+ try
+ {
+ doConnect(fds[0], addr, -1);
+ fds[1] = doAccept(fd, -1);
+ }
+ catch(...)
+ {
+ closeSocket(fd);
+ closeSocket(fds[0]);
+ throw;
+ }
+
+ closeSocket(fd);
+
+#else
+
+ if (::pipe(fds) != 0)
+ throw SystemException(__FILE__, __LINE__);
+
+#endif
+}
+
+#ifdef WIN32
+
+const char*
+IceInternal::errorToString(int error)
+{
+ switch (error)
+ {
+ case WSAEINTR:
+ return "WSAEINTR";
+
+ case WSAEBADF:
+ return "WSAEBADF";
+
+ case WSAEACCES:
+ return "WSAEACCES";
+
+ case WSAEFAULT:
+ return "WSAEFAULT";
+
+ case WSAEINVAL:
+ return "WSAEINVAL";
+
+ case WSAEMFILE:
+ return "WSAEMFILE";
+
+ case WSAEWOULDBLOCK:
+ return "WSAEWOULDBLOCK";
+
+ case WSAEINPROGRESS:
+ return "WSAEINPROGRESS";
+
+ case WSAEALREADY:
+ return "WSAEALREADY";
+
+ case WSAENOTSOCK:
+ return "WSAENOTSOCK";
+
+ case WSAEDESTADDRREQ:
+ return "WSAEDESTADDRREQ";
+
+ case WSAEMSGSIZE:
+ return "WSAEMSGSIZE";
+
+ case WSAEPROTOTYPE:
+ return "WSAEPROTOTYPE";
+
+ case WSAENOPROTOOPT:
+ return "WSAENOPROTOOPT";
+
+ case WSAEPROTONOSUPPORT:
+ return "WSAEPROTONOSUPPORT";
+
+ case WSAESOCKTNOSUPPORT:
+ return "WSAESOCKTNOSUPPORT";
+
+ case WSAEOPNOTSUPP:
+ return "WSAEOPNOTSUPP";
+
+ case WSAEPFNOSUPPORT:
+ return "WSAEPFNOSUPPORT";
+
+ case WSAEAFNOSUPPORT:
+ return "WSAEAFNOSUPPORT";
+
+ case WSAEADDRINUSE:
+ return "WSAEADDRINUSE";
+
+ case WSAEADDRNOTAVAIL:
+ return "WSAEADDRNOTAVAIL";
+
+ case WSAENETDOWN:
+ return "WSAENETDOWN";
+
+ case WSAENETUNREACH:
+ return "WSAENETUNREACH";
+
+ case WSAENETRESET:
+ return "WSAENETRESET";
+
+ case WSAECONNABORTED:
+ return "WSAECONNABORTED";
+
+ case WSAECONNRESET:
+ return "WSAECONNRESET";
+
+ case WSAENOBUFS:
+ return "WSAENOBUFS";
+
+ case WSAEISCONN:
+ return "WSAEISCONN";
+
+ case WSAENOTCONN:
+ return "WSAENOTCONN";
+
+ case WSAESHUTDOWN:
+ return "WSAESHUTDOWN";
+
+ case WSAETOOMANYREFS:
+ return "WSAETOOMANYREFS";
+
+ case WSAETIMEDOUT:
+ return "WSAETIMEDOUT";
+
+ case WSAECONNREFUSED:
+ return "WSAECONNREFUSED";
+
+ case WSAELOOP:
+ return "WSAELOOP";
+
+ case WSAENAMETOOLONG:
+ return "WSAENAMETOOLONG";
+
+ case WSAEHOSTDOWN:
+ return "WSAEHOSTDOWN";
+
+ case WSAEHOSTUNREACH:
+ return "WSAEHOSTUNREACH";
+
+ case WSAENOTEMPTY:
+ return "WSAENOTEMPTY";
+
+ case WSAEPROCLIM:
+ return "WSAEPROCLIM";
+
+ case WSAEUSERS:
+ return "WSAEUSERS";
+
+ case WSAEDQUOT:
+ return "WSAEDQUOT";
+
+ case WSAESTALE:
+ return "WSAESTALE";
+
+ case WSAEREMOTE:
+ return "WSAEREMOTE";
+
+ case WSAEDISCON:
+ return "WSAEDISCON";
+
+ case WSASYSNOTREADY:
+ return "WSASYSNOTREADY";
+
+ case WSAVERNOTSUPPORTED:
+ return "WSAVERNOTSUPPORTED";
+
+ case WSANOTINITIALISED:
+ return "WSANOTINITIALISED";
+
+ case WSAHOST_NOT_FOUND:
+ return "WSAHOST_NOT_FOUND";
+
+ case WSATRY_AGAIN:
+ return "WSATRY_AGAIN";
+
+ case WSANO_RECOVERY:
+ return "WSANO_RECOVERY";
+
+ case WSANO_DATA:
+ return "WSANO_DATA";
+
+ default:
+ return "unknown error";
+ }
+}
+
+const char*
+IceInternal::errorToStringDNS(int error)
+{
+ return errorToString(error);
+}
+
+#else
+
+const char*
+IceInternal::errorToString(int error)
+{
+ return strerror(error);
+}
+
+const char*
+IceInternal::errorToStringDNS(int error)
+{
+ switch (error)
+ {
+ case NETDB_SUCCESS:
+ return "no problem";
+
+ case NETDB_INTERNAL:
+ return "internal problem";
+
+ case HOST_NOT_FOUND:
+ return "no such host is known";
+
+ case TRY_AGAIN:
+ return "temporary error, try again";
+
+ case NO_RECOVERY:
+ return "unexpected server failure";
+
+ case NO_DATA:
+ return "name has no IP address";
+
+ default:
+ return "unknown error";
+ }
+}
+
+#endif
+
+const char*
+IceInternal::lastErrorToString()
+{
+#ifdef WIN32
+ return errorToString(WSAGetLastError());
+#else
+ return errorToString(errno);
+#endif
+}
+
+const char*
+IceInternal::lastErrorToStringDNS()
+{
+#ifdef WIN32
+ return errorToStringDNS(WSAGetLastError());
+#else
+ return errorToStringDNS(h_errno);
+#endif
+}
+
+static JTCMutex inetNtoaMutex;
+
+std::string
+IceInternal::fdToString(int fd)
+{
+ socklen_t localLen = sizeof(struct sockaddr_in);
+ struct sockaddr_in localAddr;
+ if (getsockname(fd, reinterpret_cast<struct sockaddr*>(&localAddr), &localLen) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+
+ bool peerNotConnected = false;
+ socklen_t remoteLen = sizeof(struct sockaddr_in);
+ struct sockaddr_in remoteAddr;
+ if (getpeername(fd, reinterpret_cast<struct sockaddr*>(&remoteAddr), &remoteLen) == SOCKET_ERROR)
+ {
+ if (notConnected())
+ {
+ peerNotConnected = true;
+ }
+ else
+ {
+ closeSocket(fd);
+ throw SocketException(__FILE__, __LINE__);
+ }
+ }
+
+ ostringstream s;
+
+ {
+ JTCSyncT<JTCMutex> sync(inetNtoaMutex);
+
+ s << "local address = " << inet_ntoa(localAddr.sin_addr) << ':' << ntohs(localAddr.sin_port);
+ if (peerNotConnected)
+ {
+ s << "\nremote address = <not connected>";
+ }
+ else
+ {
+ s << "\nremote address = " << inet_ntoa(remoteAddr.sin_addr) << ':' << ntohs(remoteAddr.sin_port);
+ }
+ }
+
+ return s.str();
+}
+
+std::string
+IceInternal::addrToString(const struct sockaddr_in& addr)
+{
+ JTCSyncT<JTCMutex> sync(inetNtoaMutex);
+ ostringstream s;
+ s << inet_ntoa(addr.sin_addr) << ':' << ntohs(addr.sin_port);
+ return s.str();
+}