summaryrefslogtreecommitdiff
path: root/cppe/src/IceE/Network.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cppe/src/IceE/Network.cpp')
-rw-r--r--cppe/src/IceE/Network.cpp1150
1 files changed, 1150 insertions, 0 deletions
diff --git a/cppe/src/IceE/Network.cpp b/cppe/src/IceE/Network.cpp
new file mode 100644
index 00000000000..b866cc922bf
--- /dev/null
+++ b/cppe/src/IceE/Network.cpp
@@ -0,0 +1,1150 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceE/Network.h>
+#include <IceE/LocalException.h>
+#include <IceE/SafeStdio.h>
+
+using namespace std;
+using namespace IceE;
+using namespace IceEInternal;
+
+#ifdef __sun
+# define INADDR_NONE (unsigned long)-1
+#endif
+
+bool
+IceEInternal::interrupted()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEINTR;
+#else
+# ifdef EPROTO
+ return errno == EINTR || errno == EPROTO;
+# else
+ return errno == EINTR;
+# endif
+#endif
+}
+
+bool
+IceEInternal::noBuffers()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAENOBUFS ||
+ error == WSAEFAULT;
+#else
+ return errno == ENOBUFS;
+#endif
+}
+
+bool
+IceEInternal::wouldBlock()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEWOULDBLOCK;
+#else
+ return errno == EAGAIN || errno == EWOULDBLOCK;
+#endif
+}
+
+bool
+IceEInternal::connectFailed()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAECONNREFUSED ||
+ error == WSAETIMEDOUT ||
+ error == WSAENETUNREACH ||
+ error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAECONNABORTED;
+#else
+ return errno == ECONNREFUSED ||
+ errno == ETIMEDOUT ||
+ errno == ENETUNREACH ||
+ errno == ECONNRESET ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED;
+#endif
+}
+
+bool
+IceEInternal::connectionRefused()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAECONNREFUSED;
+#else
+ return errno == ECONNREFUSED;
+#endif
+}
+
+bool
+IceEInternal::connectInProgress()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEWOULDBLOCK;
+#else
+ return errno == EINPROGRESS;
+#endif
+}
+
+bool
+IceEInternal::connectionLost()
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ return error == WSAECONNRESET ||
+ error == WSAESHUTDOWN ||
+ error == WSAENOTCONN ||
+ error == WSAECONNABORTED;
+#else
+ return errno == ECONNRESET ||
+ errno == ENOTCONN ||
+ errno == ESHUTDOWN ||
+ errno == ECONNABORTED ||
+ errno == EPIPE;
+#endif
+}
+
+bool
+IceEInternal::notConnected()
+{
+#ifdef _WIN32
+ return WSAGetLastError() == WSAENOTCONN;
+#else
+ return errno == ENOTCONN;
+#endif
+}
+
+SOCKET
+IceEInternal::createSocket()
+{
+ SOCKET fd;
+
+ fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(fd == INVALID_SOCKET)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) && !defined(_WIN32_WCE)
+ //
+ // Temporary work-around!
+ // Make this socket non-inheritable, so that IcePack-launched servers
+ // do not inherit it.
+ //
+ if(!SetHandleInformation(reinterpret_cast<HANDLE>(fd), HANDLE_FLAG_INHERIT, 0))
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+#endif
+
+ setTcpNoDelay(fd);
+ setKeepAlive(fd);
+
+ return fd;
+}
+
+void
+IceEInternal::closeSocket(SOCKET fd)
+{
+#ifdef _WIN32
+ int error = WSAGetLastError();
+ if(closesocket(fd) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ WSASetLastError(error);
+#else
+ int error = errno;
+ if(close(fd) == SOCKET_ERROR)
+ {
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ errno = error;
+#endif
+}
+
+void
+IceEInternal::shutdownSocketWrite(SOCKET fd)
+{
+ if(shutdown(fd, SHUT_WR) == SOCKET_ERROR)
+ {
+ //
+ // Ignore errors indicating that we are shutdown already.
+ //
+#if defined(_WIN32)
+ int error = WSAGetLastError();
+ if(error == WSAENOTCONN)
+ {
+ return;
+ }
+#elif defined(__APPLE__)
+ if(errno == ENOTCONN || errno == EINVAL)
+ {
+ return;
+ }
+#else
+ if(errno == ENOTCONN)
+ {
+ return;
+ }
+#endif
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+IceEInternal::shutdownSocketReadWrite(SOCKET fd)
+{
+ if(shutdown(fd, SHUT_RDWR) == SOCKET_ERROR)
+ {
+ //
+ // Ignore errors indicating that we are shutdown already.
+ //
+#if defined(_WIN32)
+ int error = WSAGetLastError();
+ if(error == WSAENOTCONN)
+ {
+ return;
+ }
+#elif defined(__APPLE__)
+ if(errno == ENOTCONN || errno == EINVAL)
+ {
+ return;
+ }
+#else
+ if(errno == ENOTCONN)
+ {
+ return;
+ }
+#endif
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+IceEInternal::setBlock(SOCKET 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
+IceEInternal::setTcpNoDelay(SOCKET fd)
+{
+ int flag = 1;
+ if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+IceEInternal::setKeepAlive(SOCKET fd)
+{
+ int flag = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+IceEInternal::setSendBufferSize(SOCKET fd, int sz)
+{
+ if(setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&sz, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+void
+IceEInternal::doBind(SOCKET fd, struct sockaddr_in& addr)
+{
+#ifndef _WIN32
+ int flag = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, int(sizeof(int))) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+#endif
+
+ if(bind(fd, reinterpret_cast<struct sockaddr*>(&addr), int(sizeof(addr))) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ socklen_t len = static_cast<socklen_t>(sizeof(addr));
+#ifdef NDEBUG
+ getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len);
+#else
+ int ret = getsockname(fd, reinterpret_cast<struct sockaddr*>(&addr), &len);
+ assert(ret != SOCKET_ERROR);
+#endif
+}
+
+
+void
+IceEInternal::doConnect(SOCKET 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
+
+ //
+ // Under WinCE its not possible to find out the connection failure
+ // reason with SO_ERROR, so its necessary to use the WSAEVENT
+ // mechanism.
+ //
+#ifdef _WIN32_WCE
+ WSAEVENT event = WSACreateEvent();
+ if(event == 0)
+ {
+ closeSocket(fd);
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = WSAGetLastError();
+ throw ex;
+ }
+
+ if(WSAEventSelect(fd, event, FD_CONNECT) == SOCKET_ERROR)
+ {
+ int error = WSAGetLastError();
+
+ WSACloseEvent(event);
+ closeSocket(fd);
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = error;
+ throw ex;
+ }
+#endif
+
+repeatConnect:
+ if(::connect(fd, reinterpret_cast<struct sockaddr*>(&addr), int(sizeof(addr))) == SOCKET_ERROR)
+ {
+ if(interrupted())
+ {
+ goto repeatConnect;
+ }
+
+ int val;
+ if(connectInProgress())
+ {
+#ifdef _WIN32_WCE
+ WSAEVENT events[1];
+ events[0] = event;
+ long tout = (timeout >= 0) ? timeout : WSA_INFINITE;
+ DWORD rc = WSAWaitForMultipleEvents(1, events, FALSE, tout, FALSE);
+ if(rc == WSA_WAIT_FAILED)
+ {
+ int error = WSAGetLastError();
+
+ WSACloseEvent(event);
+ closeSocket(fd);
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = error;
+ throw ex;
+ }
+
+ if(rc == WSA_WAIT_TIMEOUT)
+ {
+ WSACloseEvent(event);
+ closeSocket(fd);
+
+ assert(timeout >= 0);
+ throw ConnectTimeoutException(__FILE__, __LINE__);
+ }
+ assert(rc == WSA_WAIT_EVENT_0);
+
+ WSANETWORKEVENTS nevents;
+ if(WSAEnumNetworkEvents(fd, event, &nevents) == SOCKET_ERROR)
+ {
+ int error = WSAGetLastError();
+ WSACloseEvent(event);
+ closeSocket(fd);
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = error;
+ throw ex;
+ }
+
+ //
+ // Now we close the event, because we're finished and
+ // this code be repeated.
+ //
+ WSACloseEvent(event);
+
+ assert(nevents.lNetworkEvents & FD_CONNECT);
+ val = nevents.iErrorCode[FD_CONNECT_BIT];
+#else
+ 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;
+ }
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+#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 = static_cast<socklen_t>(sizeof(int));
+ if(getsockopt(fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&val), &len) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+#endif // _WIN32_WCE
+
+ if(val > 0)
+ {
+ closeSocket(fd);
+#ifdef _WIN32
+ WSASetLastError(val);
+#else
+ errno = val;
+#endif
+ 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;
+ }
+ }
+
+ return;
+ }
+
+ closeSocket(fd);
+ 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
+IceEInternal::getAddress(const string& 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.c_str());
+
+ if(addr.sin_addr.s_addr == INADDR_NONE)
+ {
+#ifdef _WIN32
+
+ //
+ // Windows XP has getaddrinfo(), but we don't want to require XP to run IceE.
+ //
+
+ //
+ // 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
+
+ struct addrinfo* info = 0;
+ int retry = 5;
+
+ struct addrinfo hints = { 0 };
+ hints.ai_family = PF_INET;
+
+ 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;
+ }
+
+ assert(info->ai_family == PF_INET);
+ struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(info->ai_addr);
+
+ addr.sin_addr.s_addr = sin->sin_addr.s_addr;
+ freeaddrinfo(info);
+
+#endif
+ }
+}
+
+string
+IceEInternal::getLocalHost(bool numeric)
+{
+ char host[1024 + 1];
+ if(gethostname(host, 1024) == SOCKET_ERROR)
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+
+#ifdef _WIN32
+
+ //
+ // Windows XP has getaddrinfo(), but we don't want to require XP to run IceE.
+ //
+
+ //
+ // gethostbyname() is thread safe on Windows, with a separate hostent per thread
+ //
+ struct hostent* entry;
+ int retry = 5;
+ do
+ {
+ entry = gethostbyname(host);
+ }
+ while(entry == 0 && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0);
+
+ if(entry == 0)
+ {
+ DNSException ex(__FILE__, __LINE__);
+ ex.error = WSAGetLastError();
+ ex.host = host;
+ throw ex;
+ }
+
+ 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);
+ }
+
+#else
+
+ struct addrinfo* info = 0;
+ int retry = 5;
+
+ struct addrinfo hints = { 0 };
+ hints.ai_family = PF_INET;
+
+ int rs = 0;
+ do
+ {
+ rs = getaddrinfo(host, 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;
+ }
+
+ string result;
+ if(numeric)
+ {
+ assert(info->ai_family == PF_INET);
+ struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(info->ai_addr);
+ result = inet_ntoa(sin->sin_addr);
+ }
+ else
+ {
+ result = info->ai_canonname;
+ }
+ freeaddrinfo(info);
+ return result;
+
+#endif
+}
+
+bool
+IceEInternal::compareAddress(const struct sockaddr_in& addr1, const struct sockaddr_in& addr2)
+{
+ return (addr1.sin_family == addr2.sin_family) &&
+ (addr1.sin_port == addr2.sin_port) &&
+ (addr1.sin_addr.s_addr == addr2.sin_addr.s_addr);
+}
+
+#ifdef _WIN32
+
+string
+IceEInternal::errorToString(int error)
+{
+ if(error < WSABASEERR)
+ {
+ LPVOID lpMsgBuf = 0;
+ DWORD ok = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR)&lpMsgBuf,
+ 0,
+ NULL);
+ if(ok)
+ {
+ LPCTSTR msg = (LPCTSTR)lpMsgBuf;
+ assert(msg && strlen((const char*)msg) > 0);
+ string result = (const char*)msg;
+ LocalFree(lpMsgBuf);
+ return result;
+ }
+ }
+
+ 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 socket error";
+ }
+}
+
+string
+IceEInternal::errorToStringDNS(int error)
+{
+ return errorToString(error);
+}
+
+#else
+
+string
+IceEInternal::errorToString(int error)
+{
+ return strerror(error);
+}
+
+string
+IceEInternal::errorToStringDNS(int error)
+{
+ return gai_strerror(error);
+}
+
+#endif
+
+string
+IceEInternal::lastErrorToString()
+{
+#ifdef _WIN32
+ return errorToString(WSAGetLastError());
+#else
+ return errorToString(errno);
+#endif
+}
+
+std::string
+IceEInternal::fdToString(SOCKET fd)
+{
+ if(fd == INVALID_SOCKET)
+ {
+ return "<closed>";
+ }
+
+ socklen_t localLen = static_cast<socklen_t>(sizeof(struct sockaddr_in));
+ struct sockaddr_in localAddr;
+ if(getsockname(fd, reinterpret_cast<struct sockaddr*>(&localAddr), &localLen) == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ bool peerNotConnected = false;
+ socklen_t remoteLen = static_cast<socklen_t>(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);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+
+ string s;
+ s += "local address = ";
+ s += inet_ntoa(localAddr.sin_addr);
+ s += ":";
+
+ s += IceE::printfToString("%d", ntohs(localAddr.sin_port));
+ if(peerNotConnected)
+ {
+ s += "\nremote address = <not connected>";
+ }
+ else
+ {
+ s += "\nremote address = ";
+ s += inet_ntoa(remoteAddr.sin_addr);
+ s += ":";
+ s += IceE::printfToString("%d", ntohs(remoteAddr.sin_port));
+ }
+ return s;
+}
+
+std::string
+IceEInternal::addrToString(const struct sockaddr_in& addr)
+{
+ //
+ // inet_ntoa uses thread-specific data on Windows, Linux, Solaris
+ // and HP-UX
+ //
+ string s;
+ s += inet_ntoa(addr.sin_addr);
+ s += ":";
+ s += IceE::printfToString("%d", ntohs(addr.sin_port));
+ return s;
+}
+
+#ifndef ICEE_PURE_CLIENT
+
+bool
+IceEInternal::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
+}
+
+SOCKET
+IceEInternal::doAccept(SOCKET fd, int timeout)
+{
+ int ret;
+
+repeatAccept:
+ if((ret = ::accept(fd, 0, 0)) == INVALID_SOCKET)
+ {
+ if(acceptInterrupted())
+ {
+ goto repeatAccept;
+ }
+
+ if(wouldBlock())
+ {
+ repeatSelect:
+ int rs;
+ 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;
+ rs = ::select(fd + 1, &fdSet, 0, 0, &tv);
+ }
+ else
+ {
+ rs = ::select(fd + 1, &fdSet, 0, 0, 0);
+ }
+
+ if(rs == SOCKET_ERROR)
+ {
+ if(interrupted())
+ {
+ goto repeatSelect;
+ }
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ if(rs == 0)
+ {
+ throw TimeoutException(__FILE__, __LINE__);
+ }
+
+ goto repeatAccept;
+ }
+
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+
+ setTcpNoDelay(ret);
+ setKeepAlive(ret);
+
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) && !defined(_WIN32_WCE)
+ //
+ // Temporary work-around!
+ // Make this socket non-inheritable, so that IcePack-launched servers
+ // do not inherit it.
+ //
+ if(!SetHandleInformation(reinterpret_cast<HANDLE>(ret), HANDLE_FLAG_INHERIT, 0))
+ {
+ SyscallException ex(__FILE__, __LINE__);
+ ex.error = getSystemErrno();
+ throw ex;
+ }
+#endif
+
+#ifdef _WIN32
+ //
+ // Set larger send buffer size to avoid performance problems on
+ // WIN32.
+ //
+ setSendBufferSize(ret, 64 * 1024);
+#endif
+
+ return ret;
+}
+
+void
+IceEInternal::doListen(SOCKET fd, int backlog)
+{
+repeatListen:
+ if(::listen(fd, backlog) == SOCKET_ERROR)
+ {
+ if(interrupted())
+ {
+ goto repeatListen;
+ }
+
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+}
+
+#endif