IPEndpointI.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
abstract class IPEndpointI extends EndpointI {
protected IPEndpointI(
ProtocolInstance instance,
String host,
int port,
InetSocketAddress sourceAddr,
String connectionId) {
_instance = instance;
_host = host;
_normalizedHost = normalizeHost(host);
_port = port;
_sourceAddr = sourceAddr;
_connectionId = connectionId;
}
protected IPEndpointI(ProtocolInstance instance) {
this(instance, null, 0, null, "");
}
protected IPEndpointI(ProtocolInstance instance, InputStream s) {
this(instance, s.readString(), s.readInt(), null, "");
}
@Override
public short type() {
return _instance.type();
}
@Override
public String protocol() {
return _instance.protocol();
}
@Override
public boolean secure() {
return _instance.secure();
}
@Override
public String connectionId() {
return _connectionId;
}
@Override
public EndpointI connectionId(String connectionId) {
if (connectionId.equals(_connectionId)) {
return this;
} else {
return createEndpoint(_host, _port, connectionId);
}
}
@Override
public void connectors_async(EndpointI_connectors callback) {
_instance.resolve(_host, _port, this, callback);
}
@Override
public List<EndpointI> expandHost() {
// If this endpoint has an empty host (wildcard address), don't expand, just return this
// endpoint.
if (_host.isEmpty()) {
return Collections.singletonList(this);
}
List<InetSocketAddress> addresses =
Network.getAddresses(
_host, _port, _instance.protocolSupport(), _instance.preferIPv6(), true);
var result = new ArrayList<EndpointI>(addresses.size());
for (InetSocketAddress addr : addresses) {
String host = addr.getAddress().getHostAddress();
result.add(createEndpoint(host, addr.getPort(), _connectionId));
}
return result;
}
@Override
public boolean isLoopbackOrMulticast() {
if (_host.isEmpty()) {
return false;
} else {
try {
var address = InetAddress.getByName(_host);
return address.isLoopbackAddress() || address.isMulticastAddress();
} catch (UnknownHostException ex) {
return false;
}
}
}
@Override
public boolean equivalent(EndpointI endpoint) {
if (!(endpoint instanceof IPEndpointI)) {
return false;
}
IPEndpointI ipEndpointI = (IPEndpointI) endpoint;
return ipEndpointI.type() == type()
&& ipEndpointI._normalizedHost.equals(_normalizedHost)
&& ipEndpointI._port == _port;
}
public List<Connector> connectors(
List<InetSocketAddress> addresses, NetworkProxy proxy) {
List<Connector> connectors = new ArrayList<>();
for (InetSocketAddress p : addresses) {
connectors.add(createConnector(p, proxy));
}
return connectors;
}
@Override
public int hashCode() {
int h = 5381;
h = HashUtil.hashAdd(h, type());
h = HashUtil.hashAdd(h, _host);
h = HashUtil.hashAdd(h, _port);
h = HashUtil.hashAdd(h, _connectionId);
if (_sourceAddr != null) {
h = HashUtil.hashAdd(h, _sourceAddr.getAddress().getHostAddress());
}
return h;
}
@Override
public String options() {
//
// WARNING: Certain features, such as proxy validation in Glacier2,
// depend on the format of proxy strings. Changes to toString() and
// methods called to generate parts of the reference string could break these features.
// Please review for all features that depend on the
// format of proxyToString() before changing this and related code.
//
String s = "";
if (_host != null && !_host.isEmpty()) {
s += " -h ";
boolean addQuote = _host.indexOf(':') != -1;
if (addQuote) {
s += '"';
}
s += _host;
if (addQuote) {
s += '"';
}
}
s += " -p " + _port;
if (_sourceAddr != null) {
String sourceAddr = _sourceAddr.getAddress().getHostAddress();
s += " --sourceAddress ";
boolean addQuote = sourceAddr.indexOf(':') != -1;
if (addQuote) {
s += "\"";
}
s += sourceAddr;
if (addQuote) {
s += "\"";
}
}
return s;
}
@Override
public int compareTo(EndpointI obj) {
if (!(obj instanceof IPEndpointI)) {
return type() < obj.type() ? -1 : 1;
}
IPEndpointI p = (IPEndpointI) obj;
if (this == p) {
return 0;
}
int v = _host.compareTo(p._host);
if (v != 0) {
return v;
}
if (_port < p._port) {
return -1;
} else if (p._port < _port) {
return 1;
}
int rc = Network.compareAddress(_sourceAddr, p._sourceAddr);
if (rc != 0) {
return rc;
}
return _connectionId.compareTo(p._connectionId);
}
@Override
public void streamWriteImpl(OutputStream s) {
s.writeString(_host);
s.writeInt(_port);
}
void initWithOptions(ArrayList<String> args, boolean oaEndpoint) {
super.initWithOptions(args);
if (_host == null || _host.isEmpty()) {
_host = _instance.defaultHost();
_normalizedHost = normalizeHost(_host);
} else if ("*".equals(_host)) {
if (oaEndpoint) {
_host = "";
_normalizedHost = "";
} else {
throw new ParseException(
"'-h *' not valid for proxy endpoint '" + toString() + "'");
}
}
if (_host == null) {
_host = "";
_normalizedHost = "";
}
if (_sourceAddr == null) {
if (!oaEndpoint) {
_sourceAddr = _instance.defaultSourceAddress();
}
} else if (oaEndpoint) {
throw new ParseException(
"'--sourceAddress' not valid for object adapter endpoint '" + toString() + "'");
}
}
@Override
protected boolean checkOption(String option, String argument, String endpoint) {
if ("-h".equals(option)) {
if (argument == null) {
throw new ParseException(
"no argument provided for -h option in endpoint '" + endpoint + "'");
}
_host = argument;
_normalizedHost = normalizeHost(argument);
} else if ("-p".equals(option)) {
if (argument == null) {
throw new ParseException(
"no argument provided for -p option in endpoint '" + endpoint + "'");
}
try {
_port = Integer.parseInt(argument);
} catch (NumberFormatException ex) {
throw new ParseException(
"invalid port value '" + argument + "' in endpoint '" + endpoint + "'", ex);
}
if (_port < 0 || _port > 65535) {
throw new ParseException(
"port value '"
+ argument
+ "' out of range in endpoint '"
+ endpoint
+ "'");
}
} else if ("--sourceAddress".equals(option)) {
if (argument == null) {
throw new ParseException(
"no argument provided for --sourceAddress option in endpoint '"
+ endpoint
+ "'");
}
_sourceAddr = Network.getNumericAddress(argument);
if (_sourceAddr == null) {
throw new ParseException(
"invalid IP address provided for --sourceAddress option in endpoint '"
+ endpoint
+ "'");
}
} else {
return false;
}
return true;
}
private String normalizeHost(String host) {
if (host != null && host.contains(":")) {
// Could be an IPv6 address that we need to normalize.
try {
var address = InetAddress.getByName(host);
host = address.getHostAddress(); // normalized host
} catch (UnknownHostException ex) {
// Ignore - don't normalize host.
}
}
return host;
}
protected abstract Connector createConnector(
InetSocketAddress addr, NetworkProxy proxy);
protected abstract IPEndpointI createEndpoint(String host, int port, String connectionId);
protected final ProtocolInstance _instance;
protected String _host;
protected int _port;
protected InetSocketAddress _sourceAddr;
protected final String _connectionId;
// Set when we set _host; used by the implementation of equivalent.
private String _normalizedHost;
}