summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Ice/Network.cpp117
-rw-r--r--cpp/src/Ice/Network.h6
-rw-r--r--cpp/src/Ice/TcpTransceiver.cpp13
-rw-r--r--cpp/src/Ice/TcpTransceiver.h3
4 files changed, 139 insertions, 0 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp
index 00eba6393ca..6c3f9126bc9 100644
--- a/cpp/src/Ice/Network.cpp
+++ b/cpp/src/Ice/Network.cpp
@@ -7,9 +7,21 @@
//
// **********************************************************************
+#ifdef _WIN32
+//
+// Prevents windows.h from including winsock.h
+//
+# define WIN32_LEAN_AND_MEAN 1
+#endif
+
#include <Ice/Network.h>
#include <Ice/LocalException.h>
+#ifdef _WIN32
+# include <winsock2.h>
+#endif
+
+
using namespace std;
using namespace Ice;
using namespace IceInternal;
@@ -1193,3 +1205,108 @@ IceInternal::addrToString(const struct sockaddr_in& addr)
s << inet_ntoa(addr.sin_addr) << ':' << ntohs(addr.sin_port);
return s.str();
}
+
+#ifdef _WIN32
+
+vector<struct sockaddr_in>
+IceInternal::getLocalAddresses()
+{
+ vector<struct sockaddr_in> result;
+ try
+ {
+ SOCKET fd = createSocket(false);
+
+ vector<unsigned char> buffer;
+ buffer.resize(1024);
+ unsigned long len = 0;
+ DWORD rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, &buffer[0], buffer.size(), &len, 0, 0);
+ if(rs == SOCKET_ERROR)
+ {
+ //
+ // If the buffer wasn't big enough, resize it to the
+ // required length and try again.
+ //
+ if(getSocketErrno() == WSAEFAULT)
+ {
+ buffer.resize(len);
+ rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, &buffer[0], buffer.size(), &len, 0, 0);
+ }
+
+ if(rs == SOCKET_ERROR)
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+
+ //
+ // Add the local interface addresses.
+ //
+ SOCKET_ADDRESS_LIST* addrs = reinterpret_cast<SOCKET_ADDRESS_LIST*>(&buffer[0]);
+ for (int i = 0; i < addrs->iAddressCount; ++i)
+ {
+ result.push_back(*reinterpret_cast<struct sockaddr_in*>(addrs->Address[i].lpSockaddr));
+ }
+
+ //
+ // Add the loopback interface address.
+ //
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(0);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ result.push_back(addr);
+
+ closeSocket(fd);
+ }
+ catch(const Ice::LocalException&)
+ {
+ //
+ // TODO: Warning?
+ //
+ }
+ return result;
+}
+
+bool
+IceInternal::isLocalAddress(const struct sockaddr_in& addr)
+{
+ struct sockaddr_in addr0 = addr;
+ addr0.sin_port = htons(0); // Local interface addresses have the port set to 0.
+ vector<struct sockaddr_in> localAddrs = getLocalAddresses();
+ for(vector<struct sockaddr_in>::const_iterator p = localAddrs.begin(); p != localAddrs.end(); ++p)
+ {
+ if(compareAddress(addr0, *p))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+IceInternal::isPeerLocal(SOCKET fd)
+{
+ 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())
+ {
+ return false;
+ }
+ else
+ {
+ closeSocket(fd);
+ SocketException ex(__FILE__, __LINE__);
+ ex.error = getSocketErrno();
+ throw ex;
+ }
+ }
+ return isLocalAddress(remoteAddr);
+}
+
+#endif
diff --git a/cpp/src/Ice/Network.h b/cpp/src/Ice/Network.h
index def423750e9..9d536aacdd7 100644
--- a/cpp/src/Ice/Network.h
+++ b/cpp/src/Ice/Network.h
@@ -111,6 +111,12 @@ ICE_PROTOCOL_API std::string lastErrorToString();
ICE_PROTOCOL_API std::string fdToString(SOCKET);
ICE_PROTOCOL_API std::string addrToString(const struct sockaddr_in&);
+#ifdef _WIN32
+ICE_PROTOCOL_API std::vector<struct sockaddr_in> getLocalAddresses();
+ICE_PROTOCOL_API bool isLocalAddress(const struct sockaddr_in&);
+ICE_PROTOCOL_API bool isPeerLocal(SOCKET);
+#endif
+
}
#endif
diff --git a/cpp/src/Ice/TcpTransceiver.cpp b/cpp/src/Ice/TcpTransceiver.cpp
index bfe6cee14d0..6586aee2201 100644
--- a/cpp/src/Ice/TcpTransceiver.cpp
+++ b/cpp/src/Ice/TcpTransceiver.cpp
@@ -81,6 +81,16 @@ IceInternal::TcpTransceiver::write(Buffer& buf, int timeout)
Buffer::Container::difference_type packetSize =
static_cast<Buffer::Container::difference_type>(buf.b.end() - buf.i);
+#ifdef _WIN32
+ //
+ // Limit packet size to avoid performance problems on WIN32
+ //
+ if(_isPeerLocal && packetSize > 64 * 1024)
+ {
+ packetSize = 64 * 1024;
+ }
+#endif
+
while(buf.i != buf.b.end())
{
assert(_fd != INVALID_SOCKET);
@@ -322,6 +332,9 @@ IceInternal::TcpTransceiver::TcpTransceiver(const InstancePtr& instance, SOCKET
_stats(instance->stats()),
_fd(fd),
_desc(fdToString(fd))
+#ifdef _WIN32
+ , _isPeerLocal(isPeerLocal(fd))
+#endif
{
FD_ZERO(&_rFdSet);
FD_ZERO(&_wFdSet);
diff --git a/cpp/src/Ice/TcpTransceiver.h b/cpp/src/Ice/TcpTransceiver.h
index 14b6930f4cf..e9e9a870500 100644
--- a/cpp/src/Ice/TcpTransceiver.h
+++ b/cpp/src/Ice/TcpTransceiver.h
@@ -51,6 +51,9 @@ private:
fd_set _wFdSet;
const std::string _desc;
+#ifdef _WIN32
+ const bool _isPeerLocal;
+#endif
};
}