13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Copyright 2003-2005 Arthur van Hoff, Rick Blair
23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0
33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Original license LGPL
43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl;
63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.DatagramPacket;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet4Address;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet6Address;
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.InetAddress;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.NetworkInterface;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.UnknownHostException;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.ArrayList;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collection;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.List;
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level;
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.NetworkTopologyDiscovery;
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants;
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass;
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordType;
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSState;
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.tasks.DNSTask;
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * HostInfo information on the local host to be able to cope with change of addresses.
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Pierre Frisch, Werner Randelshofer
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class HostInfo implements DNSStatefulObject {
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static Logger       logger = Logger.getLogger(HostInfo.class.getName());
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected String            _name;
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected InetAddress       _address;
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected NetworkInterface  _interfaze;
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final HostInfoState _state;
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final static class HostInfoState extends DNSStatefulObject.DefaultImplementation {
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static final long serialVersionUID = -8191476803620402088L;
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param dns
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public HostInfoState(JmDNSImpl dns) {
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super();
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this.setDns(dns);
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param address
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            IP address to bind
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param dns
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            JmDNS instance
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param jmdnsName
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            JmDNS name
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return new HostInfo
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static HostInfo newHostInfo(InetAddress address, JmDNSImpl dns, String jmdnsName) {
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        HostInfo localhost = null;
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String aName = "";
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress addr = address;
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (addr == null) {
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                String ip = System.getProperty("net.mdns.interface");
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (ip != null) {
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    addr = InetAddress.getByName(ip);
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    addr = InetAddress.getLocalHost();
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (addr.isLoopbackAddress()) {
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        // Find local address that isn't a loopback address
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        InetAddress[] addresses = NetworkTopologyDiscovery.Factory.getInstance().getInetAddresses();
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (addresses.length > 0) {
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            addr = addresses[0];
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aName = addr.getHostName();
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (addr.isLoopbackAddress()) {
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger.warning("Could not find any address beside the loopback.");
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aName = addr.getHostName();
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (aName.contains("in-addr.arpa") || (aName.equals(addr.getHostAddress()))) {
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : addr.getHostAddress());
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (final IOException e) {
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.log(Level.WARNING, "Could not intialize the host network interface on " + address + "because of an error: " + e.getMessage(), e);
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // This is only used for running unit test on Debian / Ubuntu
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            addr = loopbackAddress();
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : "computer");
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // A host name with "." is illegal. so strip off everything and append .local.
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        aName = aName.replace('.', '-');
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        aName += ".local.";
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        localhost = new HostInfo(addr, aName, dns);
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return localhost;
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static InetAddress loopbackAddress() {
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return InetAddress.getByName(null);
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (UnknownHostException exception) {
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return null;
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * This is used to create a unique name for the host name.
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private int hostNameCount;
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private HostInfo(final InetAddress address, final String name, final JmDNSImpl dns) {
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super();
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state = new HostInfoState(dns);
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._address = address;
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._name = name;
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (address != null) {
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                _interfaze = NetworkInterface.getByInetAddress(address);
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (Exception exception) {
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.log(Level.SEVERE, "LocalHostInfo() exception ", exception);
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getName() {
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _name;
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress getInetAddress() {
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _address;
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    Inet4Address getInet4Address() {
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() instanceof Inet4Address) {
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return (Inet4Address) _address;
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    Inet6Address getInet6Address() {
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() instanceof Inet6Address) {
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return (Inet6Address) _address;
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public NetworkInterface getInterface() {
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _interfaze;
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean conflictWithRecord(DNSRecord.Address record) {
1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSRecord.Address hostAddress = this.getDNSAddressRecord(record.getRecordType(), record.isUnique(), DNSConstants.DNS_TTL);
1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (hostAddress != null) {
1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return hostAddress.sameType(record) && hostAddress.sameName(record) && (!hostAddress.sameValue(record));
1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return false;
1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    synchronized String incrementHostName() {
1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        hostNameCount++;
1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        int plocal = _name.indexOf(".local.");
1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        int punder = _name.lastIndexOf('-');
1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _name = _name.substring(0, (punder == -1 ? plocal : punder)) + "-" + hostNameCount + ".local.";
1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _name;
1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    boolean shouldIgnorePacket(DatagramPacket packet) {
1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean result = false;
1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() != null) {
1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            InetAddress from = packet.getAddress();
1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (from != null) {
1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (from.isLinkLocalAddress() && (!this.getInetAddress().isLinkLocalAddress())) {
1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // Ignore linklocal packets on regular interfaces, unless this is
1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // also a linklocal interface. This is to avoid duplicates. This is
1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // a terrible hack caused by the lack of an API to get the address
1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // of the interface on which the packet was received.
1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    result = true;
1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (from.isLoopbackAddress() && (!this.getInetAddress().isLoopbackAddress())) {
1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // Ignore loopback packets on a regular interface unless this is also a loopback interface.
1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    result = true;
1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return result;
1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    DNSRecord.Address getDNSAddressRecord(DNSRecordType type, boolean unique, int ttl) {
1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        switch (type) {
2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_A:
2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return this.getDNS4AddressRecord(unique, ttl);
2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_A6:
2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_AAAA:
2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return this.getDNS6AddressRecord(unique, ttl);
2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            default:
2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private DNSRecord.Address getDNS4AddressRecord(boolean unique, int ttl) {
2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((this.getInetAddress() instanceof Inet4Address) || ((this.getInetAddress() instanceof Inet6Address) && (((Inet6Address) this.getInetAddress()).isIPv4CompatibleAddress()))) {
2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new DNSRecord.IPv4Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress());
2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private DNSRecord.Address getDNS6AddressRecord(boolean unique, int ttl) {
2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() instanceof Inet6Address) {
2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new DNSRecord.IPv6Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress());
2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    DNSRecord.Pointer getDNSReverseAddressRecord(DNSRecordType type, boolean unique, int ttl) {
2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        switch (type) {
2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_A:
2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return this.getDNS4ReverseAddressRecord(unique, ttl);
2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_A6:
2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            case TYPE_AAAA:
2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return this.getDNS6ReverseAddressRecord(unique, ttl);
2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            default:
2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private DNSRecord.Pointer getDNS4ReverseAddressRecord(boolean unique, int ttl) {
2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() instanceof Inet4Address) {
2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".in-addr.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName());
2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((this.getInetAddress() instanceof Inet6Address) && (((Inet6Address) this.getInetAddress()).isIPv4CompatibleAddress())) {
2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            byte[] rawAddress = this.getInetAddress().getAddress();
2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String address = (rawAddress[12] & 0xff) + "." + (rawAddress[13] & 0xff) + "." + (rawAddress[14] & 0xff) + "." + (rawAddress[15] & 0xff);
2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new DNSRecord.Pointer(address + ".in-addr.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName());
2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private DNSRecord.Pointer getDNS6ReverseAddressRecord(boolean unique, int ttl) {
2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getInetAddress() instanceof Inet6Address) {
2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".ip6.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName());
2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return null;
2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String toString() {
2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        StringBuilder buf = new StringBuilder(1024);
2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("local host info[");
2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(getName() != null ? getName() : "no name");
2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(", ");
2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(getInterface() != null ? getInterface().getDisplayName() : "???");
2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(":");
2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(getInetAddress() != null ? getInetAddress().getHostAddress() : "no address");
2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(", ");
2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(_state);
2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("]");
2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return buf.toString();
2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Collection<DNSRecord> answers(boolean unique, int ttl) {
2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        List<DNSRecord> list = new ArrayList<DNSRecord>();
2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSRecord answer = this.getDNS4AddressRecord(unique, ttl);
2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (answer != null) {
2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            list.add(answer);
2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        answer = this.getDNS6AddressRecord(unique, ttl);
2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (answer != null) {
2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            list.add(answer);
2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return list;
2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public JmDNSImpl getDns() {
2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.getDns();
2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean advanceState(DNSTask task) {
2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.advanceState(task);
2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void removeAssociationWithTask(DNSTask task) {
3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state.removeAssociationWithTask(task);
3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean revertState() {
3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.revertState();
3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void associateWithTask(DNSTask task, DNSState state) {
3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state.associateWithTask(task, state);
3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAssociatedWithTask(DNSTask task, DNSState state) {
3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isAssociatedWithTask(task, state);
3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean cancelState() {
3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.cancelState();
3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean closeState() {
3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.closeState();
3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean recoverState() {
3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.recoverState();
3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isProbing() {
3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isProbing();
3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAnnouncing() {
3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isAnnouncing();
3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAnnounced() {
3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isAnnounced();
3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isCanceling() {
3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isCanceling();
3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isCanceled() {
3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isCanceled();
3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isClosing() {
4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isClosing();
4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isClosed() {
4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isClosed();
4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean waitForAnnounced(long timeout) {
4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.waitForAnnounced(timeout);
4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean waitForCanceled(long timeout) {
4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (_address == null) {
4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // No need to wait this was never announced.
4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.waitForCanceled(timeout);
4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}
432