diff options
Diffstat (limited to 'src/javax/jmdns/impl/HostInfo.java')
-rwxr-xr-x | src/javax/jmdns/impl/HostInfo.java | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/src/javax/jmdns/impl/HostInfo.java b/src/javax/jmdns/impl/HostInfo.java new file mode 100755 index 0000000..1f9650e --- /dev/null +++ b/src/javax/jmdns/impl/HostInfo.java @@ -0,0 +1,431 @@ +// Copyright 2003-2005 Arthur van Hoff, Rick Blair +// Licensed under Apache License version 2.0 +// Original license LGPL + +package javax.jmdns.impl; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.jmdns.NetworkTopologyDiscovery; +import javax.jmdns.impl.constants.DNSConstants; +import javax.jmdns.impl.constants.DNSRecordClass; +import javax.jmdns.impl.constants.DNSRecordType; +import javax.jmdns.impl.constants.DNSState; +import javax.jmdns.impl.tasks.DNSTask; + +/** + * HostInfo information on the local host to be able to cope with change of addresses. + * + * @author Pierre Frisch, Werner Randelshofer + */ +public class HostInfo implements DNSStatefulObject { + private static Logger logger = Logger.getLogger(HostInfo.class.getName()); + + protected String _name; + + protected InetAddress _address; + + protected NetworkInterface _interfaze; + + private final HostInfoState _state; + + private final static class HostInfoState extends DNSStatefulObject.DefaultImplementation { + + private static final long serialVersionUID = -8191476803620402088L; + + /** + * @param dns + */ + public HostInfoState(JmDNSImpl dns) { + super(); + this.setDns(dns); + } + + } + + /** + * @param address + * IP address to bind + * @param dns + * JmDNS instance + * @param jmdnsName + * JmDNS name + * @return new HostInfo + */ + public static HostInfo newHostInfo(InetAddress address, JmDNSImpl dns, String jmdnsName) { + HostInfo localhost = null; + String aName = ""; + InetAddress addr = address; + try { + if (addr == null) { + String ip = System.getProperty("net.mdns.interface"); + if (ip != null) { + addr = InetAddress.getByName(ip); + } else { + addr = InetAddress.getLocalHost(); + if (addr.isLoopbackAddress()) { + // Find local address that isn't a loopback address + InetAddress[] addresses = NetworkTopologyDiscovery.Factory.getInstance().getInetAddresses(); + if (addresses.length > 0) { + addr = addresses[0]; + } + } + } + aName = addr.getHostName(); + if (addr.isLoopbackAddress()) { + logger.warning("Could not find any address beside the loopback."); + } + } else { + aName = addr.getHostName(); + } + if (aName.contains("in-addr.arpa") || (aName.equals(addr.getHostAddress()))) { + aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : addr.getHostAddress()); + } + } catch (final IOException e) { + logger.log(Level.WARNING, "Could not intialize the host network interface on " + address + "because of an error: " + e.getMessage(), e); + // This is only used for running unit test on Debian / Ubuntu + addr = loopbackAddress(); + aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : "computer"); + } + // A host name with "." is illegal. so strip off everything and append .local. + aName = aName.replace('.', '-'); + aName += ".local."; + localhost = new HostInfo(addr, aName, dns); + return localhost; + } + + private static InetAddress loopbackAddress() { + try { + return InetAddress.getByName(null); + } catch (UnknownHostException exception) { + return null; + } + } + + /** + * This is used to create a unique name for the host name. + */ + private int hostNameCount; + + private HostInfo(final InetAddress address, final String name, final JmDNSImpl dns) { + super(); + this._state = new HostInfoState(dns); + this._address = address; + this._name = name; + if (address != null) { + try { + _interfaze = NetworkInterface.getByInetAddress(address); + } catch (Exception exception) { + logger.log(Level.SEVERE, "LocalHostInfo() exception ", exception); + } + } + } + + public String getName() { + return _name; + } + + public InetAddress getInetAddress() { + return _address; + } + + Inet4Address getInet4Address() { + if (this.getInetAddress() instanceof Inet4Address) { + return (Inet4Address) _address; + } + return null; + } + + Inet6Address getInet6Address() { + if (this.getInetAddress() instanceof Inet6Address) { + return (Inet6Address) _address; + } + return null; + } + + public NetworkInterface getInterface() { + return _interfaze; + } + + public boolean conflictWithRecord(DNSRecord.Address record) { + DNSRecord.Address hostAddress = this.getDNSAddressRecord(record.getRecordType(), record.isUnique(), DNSConstants.DNS_TTL); + if (hostAddress != null) { + return hostAddress.sameType(record) && hostAddress.sameName(record) && (!hostAddress.sameValue(record)); + } + return false; + } + + synchronized String incrementHostName() { + hostNameCount++; + int plocal = _name.indexOf(".local."); + int punder = _name.lastIndexOf('-'); + _name = _name.substring(0, (punder == -1 ? plocal : punder)) + "-" + hostNameCount + ".local."; + return _name; + } + + boolean shouldIgnorePacket(DatagramPacket packet) { + boolean result = false; + if (this.getInetAddress() != null) { + InetAddress from = packet.getAddress(); + if (from != null) { + if (from.isLinkLocalAddress() && (!this.getInetAddress().isLinkLocalAddress())) { + // Ignore linklocal packets on regular interfaces, unless this is + // also a linklocal interface. This is to avoid duplicates. This is + // a terrible hack caused by the lack of an API to get the address + // of the interface on which the packet was received. + result = true; + } + if (from.isLoopbackAddress() && (!this.getInetAddress().isLoopbackAddress())) { + // Ignore loopback packets on a regular interface unless this is also a loopback interface. + result = true; + } + } + } + return result; + } + + DNSRecord.Address getDNSAddressRecord(DNSRecordType type, boolean unique, int ttl) { + switch (type) { + case TYPE_A: + return this.getDNS4AddressRecord(unique, ttl); + case TYPE_A6: + case TYPE_AAAA: + return this.getDNS6AddressRecord(unique, ttl); + default: + } + return null; + } + + private DNSRecord.Address getDNS4AddressRecord(boolean unique, int ttl) { + if ((this.getInetAddress() instanceof Inet4Address) || ((this.getInetAddress() instanceof Inet6Address) && (((Inet6Address) this.getInetAddress()).isIPv4CompatibleAddress()))) { + return new DNSRecord.IPv4Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress()); + } + return null; + } + + private DNSRecord.Address getDNS6AddressRecord(boolean unique, int ttl) { + if (this.getInetAddress() instanceof Inet6Address) { + return new DNSRecord.IPv6Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress()); + } + return null; + } + + DNSRecord.Pointer getDNSReverseAddressRecord(DNSRecordType type, boolean unique, int ttl) { + switch (type) { + case TYPE_A: + return this.getDNS4ReverseAddressRecord(unique, ttl); + case TYPE_A6: + case TYPE_AAAA: + return this.getDNS6ReverseAddressRecord(unique, ttl); + default: + } + return null; + } + + private DNSRecord.Pointer getDNS4ReverseAddressRecord(boolean unique, int ttl) { + if (this.getInetAddress() instanceof Inet4Address) { + return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".in-addr.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName()); + } + if ((this.getInetAddress() instanceof Inet6Address) && (((Inet6Address) this.getInetAddress()).isIPv4CompatibleAddress())) { + byte[] rawAddress = this.getInetAddress().getAddress(); + String address = (rawAddress[12] & 0xff) + "." + (rawAddress[13] & 0xff) + "." + (rawAddress[14] & 0xff) + "." + (rawAddress[15] & 0xff); + return new DNSRecord.Pointer(address + ".in-addr.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName()); + } + return null; + } + + private DNSRecord.Pointer getDNS6ReverseAddressRecord(boolean unique, int ttl) { + if (this.getInetAddress() instanceof Inet6Address) { + return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".ip6.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName()); + } + return null; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(1024); + buf.append("local host info["); + buf.append(getName() != null ? getName() : "no name"); + buf.append(", "); + buf.append(getInterface() != null ? getInterface().getDisplayName() : "???"); + buf.append(":"); + buf.append(getInetAddress() != null ? getInetAddress().getHostAddress() : "no address"); + buf.append(", "); + buf.append(_state); + buf.append("]"); + return buf.toString(); + } + + public Collection<DNSRecord> answers(boolean unique, int ttl) { + List<DNSRecord> list = new ArrayList<DNSRecord>(); + DNSRecord answer = this.getDNS4AddressRecord(unique, ttl); + if (answer != null) { + list.add(answer); + } + answer = this.getDNS6AddressRecord(unique, ttl); + if (answer != null) { + list.add(answer); + } + return list; + } + + /** + * {@inheritDoc} + */ + @Override + public JmDNSImpl getDns() { + return this._state.getDns(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean advanceState(DNSTask task) { + return this._state.advanceState(task); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeAssociationWithTask(DNSTask task) { + this._state.removeAssociationWithTask(task); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean revertState() { + return this._state.revertState(); + } + + /** + * {@inheritDoc} + */ + @Override + public void associateWithTask(DNSTask task, DNSState state) { + this._state.associateWithTask(task, state); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAssociatedWithTask(DNSTask task, DNSState state) { + return this._state.isAssociatedWithTask(task, state); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean cancelState() { + return this._state.cancelState(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean closeState() { + return this._state.closeState(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean recoverState() { + return this._state.recoverState(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isProbing() { + return this._state.isProbing(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAnnouncing() { + return this._state.isAnnouncing(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAnnounced() { + return this._state.isAnnounced(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isCanceling() { + return this._state.isCanceling(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isCanceled() { + return this._state.isCanceled(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isClosing() { + return this._state.isClosing(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isClosed() { + return this._state.isClosed(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean waitForAnnounced(long timeout) { + return _state.waitForAnnounced(timeout); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean waitForCanceled(long timeout) { + if (_address == null) { + // No need to wait this was never announced. + return true; + } + return _state.waitForCanceled(timeout); + } + +} |