diff options
Diffstat (limited to 'cpp/src/Ice/Network.cpp')
-rw-r--r-- | cpp/src/Ice/Network.cpp | 244 |
1 files changed, 185 insertions, 59 deletions
diff --git a/cpp/src/Ice/Network.cpp b/cpp/src/Ice/Network.cpp index 749b5683e27..36adc5b70fe 100644 --- a/cpp/src/Ice/Network.cpp +++ b/cpp/src/Ice/Network.cpp @@ -11,10 +11,18 @@ // The following is required on HP-UX in order to bring in // the definition for the ip_mreq structure. // -#ifdef __hpux -#undef _XOPEN_SOURCE_EXTENDED -#define _XOPEN_SOURCE -#include <netinet/in.h> +#if defined(__hpux) +# undef _XOPEN_SOURCE_EXTENDED +# define _XOPEN_SOURCE +# include <netinet/in.h> +#endif + +// +// 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) +# define _WIN32_WINNT 0x0501 #endif #include <IceUtil/StringUtil.h> @@ -26,15 +34,15 @@ #if defined(_WIN32) # include <winsock2.h> # include <ws2tcpip.h> -#elif defined(__linux) || defined(__APPLE__) || defined(__FreeBSD__) +# include <iphlpapi.h> +#else # include <ifaddrs.h> # include <net/if.h> -#else # include <sys/ioctl.h> -# include <net/if.h> -# ifdef __sun -# include <sys/sockio.h> -# endif +#endif + +#ifdef __sun +# include <sys/sockio.h> #endif using namespace std; @@ -68,7 +76,7 @@ getLocalAddresses(ProtocolSupport protocol) vector<unsigned char> buffer; buffer.resize(1024); unsigned long len = 0; - DWORD rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, + DWORD rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, &buffer[0], static_cast<DWORD>(buffer.size()), &len, 0, 0); if(rs == SOCKET_ERROR) @@ -80,7 +88,7 @@ getLocalAddresses(ProtocolSupport protocol) if(getSocketErrno() == WSAEFAULT) { buffer.resize(len); - rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, + rs = WSAIoctl(fd, SIO_ADDRESS_LIST_QUERY, 0, 0, &buffer[0], static_cast<DWORD>(buffer.size()), &len, 0, 0); } @@ -94,7 +102,7 @@ getLocalAddresses(ProtocolSupport protocol) } } - // + // // Add the local interface addresses. // SOCKET_ADDRESS_LIST* addrs = reinterpret_cast<SOCKET_ADDRESS_LIST*>(&buffer[0]); @@ -161,7 +169,7 @@ getLocalAddresses(ProtocolSupport protocol) } } } - + curr = curr->ifa_next; } @@ -195,7 +203,7 @@ getLocalAddresses(ProtocolSupport protocol) int bufsize = numaddrs * static_cast<int>(sizeof(struct ifreq)); ifc.ifc_len = bufsize; ifc.ifc_buf = (char*)malloc(bufsize); - + int rs = ioctl(fd, cmd, &ifc); if(rs == SOCKET_ERROR) { @@ -216,7 +224,7 @@ getLocalAddresses(ProtocolSupport protocol) { old_ifc_len = ifc.ifc_len; } - + numaddrs += 10; free(ifc.ifc_buf); } @@ -262,11 +270,11 @@ getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, Prot // We now use getaddrinfo() on Windows. // // #ifdef _WIN32 - + // // // // Windows XP has getaddrinfo(), but we don't want to require XP to run Ice. // // - + // // // // gethostbyname() is thread safe on Windows, with a separate hostent per thread // // @@ -277,7 +285,7 @@ getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, Prot // entry = gethostbyname(host.c_str()); // } // while(entry == 0 && WSAGetLastError() == WSATRY_AGAIN && --retry >= 0); - + // if(entry == 0) // { // DNSException ex(__FILE__, __LINE__); @@ -293,7 +301,7 @@ getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, Prot memset(&addr, 0, sizeof(struct sockaddr_storage)); struct addrinfo* info = 0; int retry = 5; - + struct addrinfo hints = { 0 }; if(server) @@ -301,7 +309,7 @@ getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, Prot // // If host is empty, getaddrinfo will return the wildcard // address instead of the loopack address. - // + // hints.ai_flags |= AI_PASSIVE; } @@ -327,11 +335,11 @@ getAddressImpl(const string& host, int port, struct sockaddr_storage& addr, Prot } else { - rs = getaddrinfo(host.c_str(), 0, &hints, &info); + rs = getaddrinfo(host.c_str(), 0, &hints, &info); } } while(info == 0 && rs == EAI_AGAIN && --retry >= 0); - + if(rs != 0) { DNSException ex(__FILE__, __LINE__); @@ -389,6 +397,86 @@ isWildcard(const string& host, ProtocolSupport protocol) return false; } +int +getInterfaceIndex(const string& name) +{ + int index = 0; +#ifdef _WIN32 + IP_ADAPTER_ADDRESSES addrs; + ULONG buflen = 0; + if(::GetAdaptersAddresses(AF_INET6, 0, 0, &addrs, &buflen) == ERROR_BUFFER_OVERFLOW) + { + PIP_ADAPTER_ADDRESSES paddrs; + char* buf = new char[buflen]; + paddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buf); + if(::GetAdaptersAddresses(AF_INET6, 0, 0, paddrs, &buflen) == NO_ERROR) + { + while(paddrs) + { + if(IceUtil::wstringToString(paddrs->FriendlyName) == name) + { + index = paddrs->Ipv6IfIndex; + break; + } + paddrs = paddrs->Next; + } + } + delete[] buf; + } +#else + index = if_nametoindex(name.c_str()); +#endif + + return index; +} + +struct in_addr +getInterfaceAddress(const string& name) +{ + struct in_addr addr; + addr.s_addr = INADDR_ANY; +#ifdef _WIN32 + IP_ADAPTER_ADDRESSES addrs; + ULONG buflen = 0; + if(::GetAdaptersAddresses(AF_INET, 0, 0, &addrs, &buflen) == ERROR_BUFFER_OVERFLOW) + { + PIP_ADAPTER_ADDRESSES paddrs; + char* buf = new char[buflen]; + paddrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buf); + if(::GetAdaptersAddresses(AF_INET, 0, 0, paddrs, &buflen) == NO_ERROR) + { + while(paddrs) + { + if(IceUtil::wstringToString(paddrs->FriendlyName) == name) + { + struct sockaddr_in addrin; + memcpy(&addrin, paddrs->FirstUnicastAddress->Address.lpSockaddr, + paddrs->FirstUnicastAddress->Address.iSockaddrLength); + addr = addrin.sin_addr; + break; + } + paddrs = paddrs->Next; + } + } + delete[] buf; + } +#else + ifreq if_address; + strcpy(if_address.ifr_name, name.c_str()); + + SOCKET fd = createSocket(false, AF_INET); + int rc = ioctl(fd, SIOCGIFADDR, &if_address); + closeSocketNoThrow(fd); + + if(rc != SOCKET_ERROR) + { + addr = reinterpret_cast<struct sockaddr_in*>(&if_address.ifr_addr)->sin_addr; + } +#endif + + return addr; +} + } int @@ -609,7 +697,7 @@ IceInternal::closeSocketNoThrow(SOCKET fd) errno = error; #endif } - + void IceInternal::shutdownSocketWrite(SOCKET fd) { @@ -645,7 +733,7 @@ IceInternal::shutdownSocketWrite(SOCKET fd) throw ex; } } - + void IceInternal::shutdownSocketReadWrite(SOCKET fd) { @@ -682,7 +770,7 @@ IceInternal::shutdownSocketReadWrite(SOCKET fd) throw ex; } } - + void IceInternal::setBlock(SOCKET fd, bool block) { @@ -746,7 +834,7 @@ IceInternal::setTcpNoDelay(SOCKET fd) throw ex; } } - + void IceInternal::setKeepAlive(SOCKET fd) { @@ -825,9 +913,16 @@ IceInternal::setMcastGroup(SOCKET fd, const struct sockaddr_storage& group, cons mreq.imr_interface.s_addr = INADDR_ANY; if(interface.size() > 0) { - struct sockaddr_storage addr; - getAddressForServer(interface, 0, addr, EnableIPv4); - mreq.imr_interface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr; + // + // First see if it is the interface name. If not check if IP Address. + // + mreq.imr_interface = getInterfaceAddress(interface); + if(mreq.imr_interface.s_addr == INADDR_ANY) + { + struct sockaddr_storage addr; + getAddressForServer(interface, 0, addr, EnableIPv4); + mreq.imr_interface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr; + } } rc = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, int(sizeof(mreq))); } @@ -835,13 +930,24 @@ 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; - istringstream p(interface); - if(!(p >> mreq.ipv6mr_interface) || !p.eof()) + mreq.ipv6mr_interface = 0; + if(interface.size() != 0) { - closeSocketNoThrow(fd); - SocketException ex(__FILE__, __LINE__); - ex.error = 0; - throw ex; + // + // First check if it is the interface name. If not check if index. + // + mreq.ipv6mr_interface = getInterfaceIndex(interface); + if(mreq.ipv6mr_interface == 0) + { + istringstream p(interface); + if(!(p >> mreq.ipv6mr_interface) || !p.eof()) + { + closeSocketNoThrow(fd); + SocketException ex(__FILE__, __LINE__); + ex.error = 0; + throw ex; + } + } } rc = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq, int(sizeof(mreq))); } @@ -860,14 +966,34 @@ IceInternal::setMcastInterface(SOCKET fd, const string& interface, bool IPv4) int rc; if(IPv4) { - struct sockaddr_storage addr; - getAddress(interface, 0, addr, EnableIPv4); - struct in_addr iface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr; + // + // First see if it is the interface name. If not check if IP Address. + // + struct in_addr iface = getInterfaceAddress(interface); + if(iface.s_addr == INADDR_ANY) + { + struct sockaddr_storage addr; + getAddressForServer(interface, 0, addr, EnableIPv4); + iface = reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr; + } rc = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char*)&iface, int(sizeof(iface))); } else { - int interfaceNum = atoi(interface.c_str()); + // + // First check if it is the interface name. If not check if index. + // + int interfaceNum = getInterfaceIndex(interface); + if(interfaceNum == 0) + { + istringstream p(interface); + if(!(p >> interfaceNum) || !p.eof()) + { + closeSocketNoThrow(fd); + SocketException ex(__FILE__, __LINE__); + ex.error = 0; + } + } rc = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&interfaceNum, int(sizeof(int))); } if(rc == SOCKET_ERROR) @@ -958,7 +1084,7 @@ repeatListen: { goto repeatListen; } - + closeSocketNoThrow(fd); SocketException ex(__FILE__, __LINE__); ex.error = getSocketErrno(); @@ -991,7 +1117,7 @@ repeatConnect: { goto repeatConnect; } - + if(connectInProgress()) { if(timeout == 0) @@ -1010,7 +1136,7 @@ repeatConnect: } return true; } - + closeSocketNoThrow(fd); if(connectionRefused()) { @@ -1097,7 +1223,7 @@ IceInternal::doFinishConnect(SOCKET fd, int timeout) { goto repeatSelect; } - + SocketException ex(__FILE__, __LINE__); ex.error = getSocketErrno(); throw ex; @@ -1121,7 +1247,7 @@ IceInternal::doFinishConnect(SOCKET fd, int timeout) ex.error = getSocketErrno(); throw ex; } - + if(val > 0) { #ifdef _WIN32 @@ -1209,27 +1335,27 @@ repeatAccept: pollFd[0].events = POLLIN; rs = ::poll(pollFd, 1, timeout); #endif - + 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; @@ -1262,7 +1388,7 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol // // // // Windows XP has getaddrinfo(), but we don't want to require XP to run Ice. // // - + // // // // gethostbyname() is thread safe on Windows, with a separate hostent per thread // // @@ -1274,7 +1400,7 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol // entry = gethostbyname(host.c_str()); // } // while(entry == 0 && h_errno == TRY_AGAIN && --retry >= 0); - + // if(entry == 0) // { // DNSException ex(__FILE__, __LINE__); @@ -1289,7 +1415,7 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol // memcpy(&addr.sin_addr, *p, entry->h_length); // result.push_back(addr); // p++; -// } +// } // #else @@ -1318,7 +1444,7 @@ IceInternal::getAddresses(const string& host, int port, ProtocolSupport protocol { hints.ai_flags = AI_NUMERICHOST; } - + int rs = 0; do { @@ -1435,7 +1561,7 @@ IceInternal::compareAddress(const struct sockaddr_storage& addr1, const struct s { return 1; } - + int res = memcmp(&addr1in->sin6_addr, &addr2in->sin6_addr, sizeof(struct in6_addr)); if(res < 0) { @@ -1457,7 +1583,7 @@ IceInternal::createPipe(SOCKET fds[2]) SOCKET fd = createSocket(false, AF_INET); setBlock(fd, true); - + struct sockaddr_storage addr; memset(&addr, 0, sizeof(addr)); @@ -1465,7 +1591,7 @@ IceInternal::createPipe(SOCKET fds[2]) addrin->sin_family = AF_INET; addrin->sin_port = htons(0); addrin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - + doBind(fd, addr); doListen(fd, 1); @@ -1694,10 +1820,10 @@ IceInternal::getHostsForEndpointExpand(const string& host, ProtocolSupport proto for(vector<struct sockaddr_storage>::const_iterator p = addrs.begin(); p != addrs.end(); ++p) { // - // NOTE: We don't publish link-local IPv6 addresses as these addresses can only + // 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 || + if(p->ss_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&reinterpret_cast<const struct sockaddr_in6*>(&(*p))->sin6_addr)) { hosts.push_back(inetAddrToString(*p)); |