Network.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.io.IOException;
import java.net.ConnectException;
import java.net.DatagramSocket;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* @hidden Public because it's used by IceDiscovery and IceLocatorDiscovery.
*/
public final class Network {
// ProtocolSupport
public static final int EnableIPv4 = 0;
public static final int EnableIPv6 = 1;
public static final int EnableBoth = 2;
private static Pattern IPV4_PATTERN;
private static Pattern IPV6_PATTERN;
private static final String ipv4Pattern =
"(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])";
private static final String ipv6Pattern =
"(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-"
+ "fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1"
+ ",4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,"
+ "4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-"
+ "F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
+ "\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}"
+ "[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))";
static {
try {
IPV4_PATTERN =
Pattern.compile(
ipv4Pattern, Pattern.CASE_INSENSITIVE);
IPV6_PATTERN =
Pattern.compile(
ipv6Pattern, Pattern.CASE_INSENSITIVE);
} catch (PatternSyntaxException ex) {
assert false;
}
}
public static boolean isNumericAddress(String ipAddress) {
Matcher ipv4 = IPV4_PATTERN.matcher(ipAddress);
if (ipv4.matches()) {
return true;
}
Matcher ipv6 = IPV6_PATTERN.matcher(ipAddress);
return ipv6.matches();
}
public static boolean connectionRefused(ConnectException ex) {
//
// The JDK raises a generic ConnectException when the server
// actively refuses a connection. Unfortunately, our only choice is to search the exception
// message for distinguishing phrases.
//
String msg = ex.getMessage();
if (msg != null) {
msg = msg.toLowerCase();
return msg.indexOf("connection refused") != -1;
}
return false;
}
public static boolean isIPv6Supported() {
try {
Socket socket = new Socket();
socket.bind(new InetSocketAddress(InetAddress.getByName("::1"), 0));
socket.close();
return true;
} catch (IOException ex) {
return false;
}
}
public static SocketChannel createTcpSocket() {
try {
SocketChannel fd = SocketChannel.open();
Socket socket = fd.socket();
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
return fd;
} catch (IOException ex) {
throw new SocketException(ex);
}
}
public static ServerSocketChannel createTcpServerSocket() {
try {
ServerSocketChannel fd = ServerSocketChannel.open();
// It's not possible to set TCP_NODELAY or KEEP_ALIVE on a server socket in Java
//
// java.net.Socket socket = fd.socket();
// socket.setTcpNoDelay(true); socket.setKeepAlive(true);
return fd;
} catch (IOException ex) {
throw new SocketException(ex);
}
}
public static DatagramChannel createUdpSocket(
InetSocketAddress addr) {
try {
if (addr.getAddress().isMulticastAddress()) {
var familyStr =
addr.getAddress() instanceof Inet6Address ? "INET6" : "INET";
var family = StandardProtocolFamily.valueOf(familyStr);
return DatagramChannel.open(family);
} else {
return DatagramChannel.open();
}
} catch (IOException ex) {
throw new SocketException(ex);
}
}
public static void closeSocketNoThrow(SelectableChannel fd) {
try {
fd.close();
} catch (IOException ex) {
// Ignore
}
}
public static NetworkInterface getInterface(String intf) {
NetworkInterface iface;
try {
iface = NetworkInterface.getByName(intf);
if (iface != null) {
return iface;
}
} catch (Exception ex) {}
try {
iface =
NetworkInterface.getByInetAddress(
InetAddress.getByName(intf));
if (iface != null) {
return iface;
}
} catch (Exception ex) {}
throw new IllegalArgumentException("couldn't find interface `" + intf + "'");
}
public static void setMcastInterface(DatagramChannel fd, String intf) {
try {
fd.setOption(StandardSocketOptions.IP_MULTICAST_IF, getInterface(intf));
} catch (Exception ex) {
throw new SocketException(ex);
}
}
public static void setMcastGroup(
MulticastSocket fd, InetSocketAddress group, String intf) {
try {
Set<NetworkInterface> interfaces = new HashSet<>();
for (String address : getInterfacesForMulticast(intf, getProtocolSupport(group))) {
NetworkInterface intf2 = getInterface(address);
if (!interfaces.contains(intf2)) {
interfaces.add(intf2);
fd.joinGroup(group, intf2);
}
}
} catch (Exception ex) {
throw new SocketException(ex);
}
}
public static void setMcastGroup(
DatagramChannel fd, InetSocketAddress group, String intf) {
try {
Set<NetworkInterface> interfaces = new HashSet<>();
for (String address : getInterfacesForMulticast(intf, getProtocolSupport(group))) {
NetworkInterface intf2 = getInterface(address);
if (!interfaces.contains(intf2)) {
interfaces.add(intf2);
fd.join(group.getAddress(), intf2);
}
}
} catch (Exception ex) {
throw new SocketException(ex);
}
}
public static void setMcastTtl(DatagramChannel fd, int ttl) {
try {
fd.setOption(StandardSocketOptions.IP_MULTICAST_TTL, ttl);
} catch (Exception ex) {
throw new SocketException(ex);
}
}
public static void setBlock(SelectableChannel fd, boolean block) {
try {
fd.configureBlocking(block);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static void setReuseAddress(DatagramChannel fd, boolean reuse) {
try {
fd.socket().setReuseAddress(reuse);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static void setReuseAddress(ServerSocketChannel fd, boolean reuse) {
try {
fd.socket().setReuseAddress(reuse);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static InetSocketAddress doBind(
ServerSocketChannel fd,
InetSocketAddress addr,
int backlog) {
try {
ServerSocket sock = fd.socket();
sock.bind(addr, backlog);
return (InetSocketAddress) sock.getLocalSocketAddress();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static InetSocketAddress doBind(
DatagramChannel fd, InetSocketAddress addr) {
try {
DatagramSocket sock = fd.socket();
sock.bind(addr);
return (InetSocketAddress) sock.getLocalSocketAddress();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static SocketChannel doAccept(
ServerSocketChannel socketChannel) {
SocketChannel fd = null;
while (true) {
try {
fd = socketChannel.accept();
break;
} catch (IOException ex) {
throw new SocketException(ex);
}
}
try {
Socket socket = fd.socket();
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
} catch (IOException ex) {
throw new SocketException(ex);
}
return fd;
}
public static boolean doConnect(
SocketChannel fd,
InetSocketAddress addr,
InetSocketAddress sourceAddr) {
if (sourceAddr != null) {
try {
fd.bind(sourceAddr);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
try {
if (!fd.connect(addr)) {
return false;
}
} catch (ConnectException ex) {
closeSocketNoThrow(fd);
if (connectionRefused(ex)) {
throw new ConnectionRefusedException(ex);
} else {
throw new ConnectFailedException(ex);
}
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
} catch (java.lang.SecurityException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
if ("Linux".equals(System.getProperty("os.name"))) {
//
// Prevent self connect (self connect happens on Linux when a client tries to connect to
// a server which was just deactivated if the client socket re-uses the same ephemeral
// port as the server).
//
if (addr.equals(fd.socket().getLocalSocketAddress())) {
closeSocketNoThrow(fd);
throw new ConnectionRefusedException();
}
}
return true;
}
public static void doFinishConnect(SocketChannel fd) {
//
// Note: we don't close the socket if there's an exception. It's the responsibility of the
// caller to do so.
//
try {
if (!fd.finishConnect()) {
throw new ConnectFailedException();
}
if ("Linux".equals(System.getProperty("os.name"))) {
//
// Prevent self connect (self connect happens on Linux when a client tries to
// connect to a server which was just deactivated if the client socket re-uses the
// same ephemeral port as the server).
//
SocketAddress addr = fd.socket().getRemoteSocketAddress();
if (addr != null && addr.equals(fd.socket().getLocalSocketAddress())) {
throw new ConnectionRefusedException();
}
}
} catch (ConnectException ex) {
if (connectionRefused(ex)) {
throw new ConnectionRefusedException(ex);
} else {
throw new ConnectFailedException(ex);
}
} catch (IOException ex) {
throw new SocketException(ex);
}
}
public static void doConnect(
DatagramChannel fd,
InetSocketAddress addr,
InetSocketAddress sourceAddr) {
if (sourceAddr != null) {
doBind(fd, sourceAddr);
}
try {
fd.connect(addr);
} catch (ConnectException ex) {
closeSocketNoThrow(fd);
if (connectionRefused(ex)) {
throw new ConnectionRefusedException(ex);
} else {
throw new ConnectFailedException(ex);
}
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static void setSendBufferSize(SocketChannel fd, int size) {
try {
Socket socket = fd.socket();
socket.setSendBufferSize(size);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static int getSendBufferSize(SocketChannel fd) {
int size;
try {
Socket socket = fd.socket();
size = socket.getSendBufferSize();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
return size;
}
public static void setRecvBufferSize(SocketChannel fd, int size) {
try {
Socket socket = fd.socket();
socket.setReceiveBufferSize(size);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static int getRecvBufferSize(SocketChannel fd) {
int size;
try {
Socket socket = fd.socket();
size = socket.getReceiveBufferSize();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
return size;
}
public static void setRecvBufferSize(ServerSocketChannel fd, int size) {
try {
ServerSocket socket = fd.socket();
socket.setReceiveBufferSize(size);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static int getRecvBufferSize(ServerSocketChannel fd) {
int size;
try {
ServerSocket socket = fd.socket();
size = socket.getReceiveBufferSize();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
return size;
}
public static void setSendBufferSize(DatagramChannel fd, int size) {
try {
DatagramSocket socket = fd.socket();
socket.setSendBufferSize(size);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static int getSendBufferSize(DatagramChannel fd) {
int size;
try {
DatagramSocket socket = fd.socket();
size = socket.getSendBufferSize();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
return size;
}
public static void setRecvBufferSize(DatagramChannel fd, int size) {
try {
DatagramSocket socket = fd.socket();
socket.setReceiveBufferSize(size);
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
}
public static int getRecvBufferSize(DatagramChannel fd) {
int size;
try {
DatagramSocket socket = fd.socket();
size = socket.getReceiveBufferSize();
} catch (IOException ex) {
closeSocketNoThrow(fd);
throw new SocketException(ex);
}
return size;
}
public static int getProtocolSupport(InetSocketAddress addr) {
return addr.getAddress().getAddress().length == 4 ? Network.EnableIPv4 : Network.EnableIPv6;
}
public static InetSocketAddress getAddressForServer(
String host, int port, int protocol, boolean preferIPv6) {
if (host == null || host.isEmpty()) {
try {
if (protocol != EnableIPv4) {
return new InetSocketAddress(
InetAddress.getByName("::0"), port);
} else {
return new InetSocketAddress(
InetAddress.getByName("0.0.0.0"), port);
}
} catch (UnknownHostException ex) {
assert false;
return null;
} catch (java.lang.SecurityException ex) {
throw new SocketException(ex);
}
}
return getAddresses(host, port, protocol, preferIPv6, true).get(0);
}
public static int compareAddress(
InetSocketAddress addr1, InetSocketAddress addr2) {
if (addr1 == null) {
return addr2 == null ? 0 : -1;
} else if (addr2 == null) {
return 1;
}
int v = Integer.compare(addr1.getPort(), addr2.getPort());
if (v != 0) {
return v;
}
byte[] larr = addr1.getAddress().getAddress();
byte[] rarr = addr2.getAddress().getAddress();
v = larr.length - rarr.length;
if (v != 0) {
return v;
}
return Arrays.compare(larr, rarr);
}
public static List<InetSocketAddress> getAddresses(
String host, int port, int protocol, boolean preferIPv6, boolean blocking) {
if (!blocking) {
if (!isNumericAddress(host)) {
return null; // Can't get the address without blocking.
}
List<InetSocketAddress> addrs = new ArrayList<>();
try {
addrs.add(
new InetSocketAddress(InetAddress.getByName(host), port));
} catch (UnknownHostException ex) {
assert false;
}
return addrs;
}
List<InetSocketAddress> addresses = new ArrayList<>();
try {
InetAddress[] addrs;
if (host == null || host.isEmpty()) {
addrs = getLoopbackAddresses(protocol);
} else {
addrs = InetAddress.getAllByName(host);
}
for (InetAddress addr : addrs) {
if (protocol == EnableBoth || isValidAddr(addr, protocol)) {
addresses.add(new InetSocketAddress(addr, port));
}
}
if (protocol == EnableBoth) {
if (preferIPv6) {
Collections.sort(addresses, _preferIPv6Comparator);
} else {
Collections.sort(addresses, _preferIPv4Comparator);
}
}
} catch (UnknownHostException ex) {
throw new DNSException(host, ex);
} catch (java.lang.SecurityException ex) {
throw new SocketException(ex);
}
//
// No Inet4Address/Inet6Address available.
//
if (addresses.isEmpty()) {
throw new DNSException(host);
}
return addresses;
}
// Only used for multicast.
private static ArrayList<InetAddress> getLocalAddresses(int protocol) {
ArrayList<InetAddress> result = new ArrayList<>();
try {
Enumeration<NetworkInterface> ifaces =
NetworkInterface.getNetworkInterfaces();
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> addrs = iface.getInetAddresses();
while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement();
if (!result.contains(addr)
&& (protocol == EnableBoth || isValidAddr(addr, protocol))) {
result.add(addr);
break;
}
}
}
} catch (java.net.SocketException ex) {
throw new SocketException(ex);
} catch (java.lang.SecurityException ex) {
throw new SocketException(ex);
}
return result;
}
public static List<String> getInterfacesForMulticast(String intf, int protocolSupport) {
ArrayList<String> interfaces = new ArrayList<>();
if (isWildcard(intf)) {
for (InetAddress addr : getLocalAddresses(protocolSupport)) {
interfaces.add(addr.getHostAddress());
}
}
if (interfaces.isEmpty()) {
interfaces.add(intf);
}
return interfaces;
}
public static void setTcpBufSize(
SocketChannel socket, ProtocolInstance instance) {
//
// By default, on Windows we use a 128KB buffer size. On Unix platforms, we use the system
// defaults.
//
int dfltBufSize = 0;
if (System.getProperty("os.name").startsWith("Windows")) {
dfltBufSize = 128 * 1024;
}
int rcvSize =
instance.properties().getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize);
int sndSize =
instance.properties().getPropertyAsIntWithDefault("Ice.TCP.SndSize", dfltBufSize);
setTcpBufSize(socket, rcvSize, sndSize, instance);
}
public static void setTcpBufSize(
SocketChannel socket,
int rcvSize,
int sndSize,
ProtocolInstance instance) {
if (rcvSize > 0) {
//
// Try to set the buffer size. The kernel will silently adjust the size to an acceptable
// value. Then read the size back to get the size that was actually set.
//
setRecvBufferSize(socket, rcvSize);
int size = getRecvBufferSize(socket);
if (size < rcvSize) {
// Warn if the size that was set is less than the requested size and we have not
// already warned.
BufSizeWarnInfo winfo = instance.getBufSizeWarn(TCPEndpointType.value);
if (!winfo.rcvWarn || rcvSize != winfo.rcvSize) {
instance.logger()
.warning(
"TCP receive buffer size: requested size of "
+ rcvSize
+ " adjusted to "
+ size);
instance.setRcvBufSizeWarn(TCPEndpointType.value, rcvSize);
}
}
}
if (sndSize > 0) {
//
// Try to set the buffer size. The kernel will silently adjust the size to an acceptable
// value. Then read the size back to get the size that was actually set.
//
setSendBufferSize(socket, sndSize);
int size = getSendBufferSize(socket);
if (size < sndSize) {
// Warn if the size that was set is less than the requested size and we have not
// already warned.
BufSizeWarnInfo winfo = instance.getBufSizeWarn(TCPEndpointType.value);
if (!winfo.sndWarn || sndSize != winfo.sndSize) {
instance.logger()
.warning(
"TCP send buffer size: requested size of "
+ sndSize
+ " adjusted to "
+ size);
instance.setSndBufSizeWarn(TCPEndpointType.value, sndSize);
}
}
}
}
public static void setTcpBufSize(
ServerSocketChannel socket, ProtocolInstance instance) {
//
// By default, on Windows we use a 128KB buffer size. On Unix platforms, we use the system
// defaults.
//
int dfltBufSize = 0;
if (System.getProperty("os.name").startsWith("Windows")) {
dfltBufSize = 128 * 1024;
}
//
// Get property for buffer size.
//
int sizeRequested =
instance.properties().getPropertyAsIntWithDefault("Ice.TCP.RcvSize", dfltBufSize);
if (sizeRequested > 0) {
//
// Try to set the buffer size. The kernel will silently adjust the size to an acceptable
// value. Then read the size back to get the size that was actually set.
//
setRecvBufferSize(socket, sizeRequested);
int size = getRecvBufferSize(socket);
if (size < sizeRequested) {
// Warn if the size that was set is less than the requested size and we have not
// already warned.
BufSizeWarnInfo winfo = instance.getBufSizeWarn(TCPEndpointType.value);
if (!winfo.rcvWarn || sizeRequested != winfo.rcvSize) {
instance.logger()
.warning(
"TCP receive buffer size: requested size of "
+ sizeRequested
+ " adjusted to "
+ size);
instance.setRcvBufSizeWarn(TCPEndpointType.value, sizeRequested);
}
}
}
}
public static String fdToString(
SelectableChannel fd,
NetworkProxy proxy,
InetSocketAddress target) {
if (fd == null) {
return "<closed>";
}
InetAddress localAddr = null, remoteAddr = null;
int localPort = -1, remotePort = -1;
if (fd instanceof SocketChannel) {
Socket socket = ((SocketChannel) fd).socket();
localAddr = socket.getLocalAddress();
localPort = socket.getLocalPort();
remoteAddr = socket.getInetAddress();
remotePort = socket.getPort();
} else if (fd instanceof DatagramChannel) {
DatagramSocket socket = ((DatagramChannel) fd).socket();
localAddr = socket.getLocalAddress();
localPort = socket.getLocalPort();
remoteAddr = socket.getInetAddress();
remotePort = socket.getPort();
} else {
assert false;
}
return addressesToString(localAddr, localPort, remoteAddr, remotePort, proxy, target);
}
public static String fdToString(SelectableChannel fd) {
if (fd == null) {
return "<closed>";
}
InetAddress localAddr = null, remoteAddr = null;
int localPort = -1, remotePort = -1;
if (fd instanceof SocketChannel) {
Socket socket = ((SocketChannel) fd).socket();
localAddr = socket.getLocalAddress();
localPort = socket.getLocalPort();
remoteAddr = socket.getInetAddress();
remotePort = socket.getPort();
} else if (fd instanceof DatagramChannel) {
DatagramSocket socket = ((DatagramChannel) fd).socket();
localAddr = socket.getLocalAddress();
localPort = socket.getLocalPort();
remoteAddr = socket.getInetAddress();
remotePort = socket.getPort();
} else {
assert false;
}
return addressesToString(localAddr, localPort, remoteAddr, remotePort);
}
public static String addressesToString(
InetAddress localAddr,
int localPort,
InetAddress remoteAddr,
int remotePort,
NetworkProxy proxy,
InetSocketAddress target) {
StringBuilder s = new StringBuilder(128);
s.append("local address = ");
s.append(addrToString(localAddr, localPort));
if (proxy != null) {
if (remoteAddr == null) {
InetSocketAddress addr = proxy.getAddress();
remoteAddr = addr.getAddress();
remotePort = addr.getPort();
}
s.append("\n");
s.append(proxy.getName());
s.append(" proxy address = ");
s.append(addrToString(remoteAddr, remotePort));
s.append("\nremote address = ");
s.append(addrToString(target.getAddress(), target.getPort()));
} else {
if (remoteAddr == null && target != null) {
remoteAddr = target.getAddress();
remotePort = target.getPort();
}
if (remoteAddr == null) {
s.append("\nremote address = <not connected>");
} else {
s.append("\nremote address = ");
s.append(addrToString(remoteAddr, remotePort));
}
}
return s.toString();
}
public static String addressesToString(
InetAddress localAddr,
int localPort,
InetAddress remoteAddr,
int remotePort) {
return addressesToString(localAddr, localPort, remoteAddr, remotePort, null, null);
}
public static String addrToString(InetSocketAddress addr) {
StringBuilder s = new StringBuilder(128);
s.append(addr.getAddress().getHostAddress());
s.append(':');
s.append(addr.getPort());
return s.toString();
}
private static boolean isValidAddr(InetAddress addr, int protocol) {
byte[] bytes = null;
if (addr != null) {
bytes = addr.getAddress();
}
return bytes != null
&& ((bytes.length == 16 && protocol == EnableIPv6)
|| (bytes.length == 4 && protocol == EnableIPv4));
}
public static String addrToString(InetAddress addr, int port) {
StringBuffer s = new StringBuffer();
//
// In early Android releases, sockets don't correctly report their address and port
// information.
//
if (addr == null || addr.isAnyLocalAddress()) {
s.append("<not available>");
} else {
s.append(addr.getHostAddress());
}
if (port > 0) {
s.append(':');
s.append(port);
}
return s.toString();
}
private static InetAddress[] getLoopbackAddresses(int protocol) {
try {
InetAddress[] addrs = new InetAddress[protocol == EnableBoth ? 2 : 1];
int i = 0;
if (protocol != EnableIPv6) {
addrs[i++] = InetAddress.getByName("127.0.0.1");
}
if (protocol != EnableIPv4) {
addrs[i++] = InetAddress.getByName("::1");
}
return addrs;
} catch (UnknownHostException ex) {
assert false;
return null;
} catch (java.lang.SecurityException ex) {
throw new SocketException(ex);
}
}
public static InetSocketAddress getNumericAddress(String address) {
InetSocketAddress addr = null;
if (!address.isEmpty() && isNumericAddress(address)) {
try {
addr = new InetSocketAddress(InetAddress.getByName(address), 0);
} catch (UnknownHostException ex) {}
}
return addr;
}
private static boolean isWildcard(String host) {
if (host == null || host.isEmpty()) {
return true;
}
try {
return InetAddress.getByName(host).isAnyLocalAddress();
} catch (UnknownHostException ex) {} catch (java.lang.SecurityException ex) {
throw new SocketException(ex);
}
return false;
}
static class IPAddressComparator implements Comparator<InetSocketAddress> {
IPAddressComparator(boolean ipv6) {
_ipv6 = ipv6;
}
@Override
public int compare(InetSocketAddress lhs, InetSocketAddress rhs) {
if (lhs.getAddress().getAddress().length < rhs.getAddress().getAddress().length) {
return _ipv6 ? 1 : -1;
} else if (lhs.getAddress().getAddress().length
> rhs.getAddress().getAddress().length) {
return _ipv6 ? -1 : 1;
} else {
return 0;
}
}
private final boolean _ipv6;
}
private static final IPAddressComparator _preferIPv4Comparator = new IPAddressComparator(false);
private static final IPAddressComparator _preferIPv6Comparator = new IPAddressComparator(true);
private Network() {}
}