diff options
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/Ice/Network.cpp | 117 | ||||
-rw-r--r-- | cpp/src/Ice/Network.h | 6 | ||||
-rw-r--r-- | cpp/src/Ice/TcpTransceiver.cpp | 13 | ||||
-rw-r--r-- | cpp/src/Ice/TcpTransceiver.h | 3 |
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 }; } |