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.DataOutputStream;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.UnsupportedEncodingException;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet4Address;
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet6Address;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.InetAddress;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.UnknownHostException;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashMap;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Map;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level;
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceEvent;
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo;
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo.Fields;
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSOutgoing.MessageOutputStream;
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants;
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass;
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordType;
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DNS record
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Arthur van Hoff, Rick Blair, Werner Randelshofer, Pierre Frisch
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic abstract class DNSRecord extends DNSEntry {
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static Logger logger = Logger.getLogger(DNSRecord.class.getName());
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private int           _ttl;
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private long          _created;
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * This source is mainly for debugging purposes, should be the address that sent this record.
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private InetAddress   _source;
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Create a DNSRecord with a name, type, class, and ttl.
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    DNSRecord(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl) {
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super(name, type, recordClass, unique);
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ttl = ttl;
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._created = System.currentTimeMillis();
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.DNSEntry#equals(java.lang.Object)
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean equals(Object other) {
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (other instanceof DNSRecord) && super.equals(other) && sameValue((DNSRecord) other);
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * True if this record has the same value as some other record.
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    abstract boolean sameValue(DNSRecord other);
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * True if this record has the same type as some other record.
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    boolean sameType(DNSRecord other) {
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getRecordType() == other.getRecordType();
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Handles a query represented by this record.
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return Returns true if a conflict with one of the services registered with JmDNS or with the hostname occured.
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    abstract boolean handleQuery(JmDNSImpl dns, long expirationTime);
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Handles a response represented by this record.
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return Returns true if a conflict with one of the services registered with JmDNS or with the hostname occured.
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    abstract boolean handleResponse(JmDNSImpl dns);
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Adds this as an answer to the provided outgoing datagram.
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    abstract DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException;
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * True if this record is suppressed by the answers in a message.
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    boolean suppressedBy(DNSIncoming msg) {
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (DNSRecord answer : msg.getAllAnswers()) {
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (suppressedBy(answer)) {
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return true;
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (ArrayIndexOutOfBoundsException e) {
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            logger.log(Level.WARNING, "suppressedBy() message " + msg + " exception ", e);
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // msg.print(true);
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * True if this record would be suppressed by an answer. This is the case if this record would not have a significantly longer TTL.
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    boolean suppressedBy(DNSRecord other) {
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.equals(other) && (other._ttl > _ttl / 2)) {
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return false;
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Get the expiration time of this record.
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    long getExpirationTime(int percent) {
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // ttl is in seconds the constant 10 is 1000 ms / 100 %
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _created + (percent * _ttl * 10L);
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Get the remaining TTL for this record.
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    int getRemainingTTL(long now) {
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (int) Math.max(0, (getExpirationTime(100) - now) / 1000);
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.DNSEntry#isExpired(long)
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isExpired(long now) {
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return getExpirationTime(100) <= now;
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.impl.DNSEntry#isStale(long)
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isStale(long now) {
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return getExpirationTime(50) <= now;
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Reset the TTL of a record. This avoids having to update the entire record in the cache.
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void resetTTL(DNSRecord other) {
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _created = other._created;
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ttl = other._ttl;
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * When a record flushed we don't remove it immediately, but mark it for rapid decay.
1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void setWillExpireSoon(long now) {
1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _created = now;
1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ttl = DNSConstants.RECORD_EXPIRY_DELAY;
1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Write this record into an outgoing message.
1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    abstract void write(MessageOutputStream out);
1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class IPv4Address extends Address {
1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, addr);
1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        IPv4Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_A, recordClass, unique, ttl, rawAddress);
1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (_addr != null) {
1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                byte[] buffer = _addr.getAddress();
1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // If we have a type A records we should answer with a IPv4 address
1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (_addr instanceof Inet4Address) {
1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // All is good
1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // Get the last four bytes
1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    byte[] tempbuffer = buffer;
1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    buffer = new byte[4];
1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    System.arraycopy(tempbuffer, 12, buffer, 0, 4);
1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int length = buffer.length;
1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.writeBytes(buffer, 0, length);
1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent);
2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            info.addAddress((Inet4Address) _addr);
2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return info;
2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class IPv6Address extends Address {
2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, addr);
2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        IPv6Address(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_AAAA, recordClass, unique, ttl, rawAddress);
2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (_addr != null) {
2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                byte[] buffer = _addr.getAddress();
2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // If we have a type AAAA records we should answer with a IPv6 address
2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (_addr instanceof Inet4Address) {
2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    byte[] tempbuffer = buffer;
2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    buffer = new byte[16];
2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (int i = 0; i < 16; i++) {
2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (i < 11) {
2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            buffer[i] = tempbuffer[i - 12];
2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        } else {
2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            buffer[i] = 0;
2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int length = buffer.length;
2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.writeBytes(buffer, 0, length);
2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = (ServiceInfoImpl) super.getServiceInfo(persistent);
2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            info.addAddress((Inet6Address) _addr);
2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return info;
2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Address record.
2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static abstract class Address extends DNSRecord {
2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static Logger logger1 = Logger.getLogger(Address.class.getName());
2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress           _addr;
2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, InetAddress addr) {
2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, type, recordClass, unique, ttl);
2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._addr = addr;
2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique, int ttl, byte[] rawAddress) {
2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, type, recordClass, unique, ttl);
2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this._addr = InetAddress.getByAddress(rawAddress);
2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (UnknownHostException exception) {
2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.log(Level.WARNING, "Address() exception ", exception);
2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean same(DNSRecord other) {
2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof Address) ) {
2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return ((sameName(other)) && ((sameValue(other))));
2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameName(DNSRecord other) {
2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this.getName().equalsIgnoreCase(other.getName());
2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameValue(DNSRecord other) {
2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof Address) ) {
2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Address address = (Address) other;
2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((this.getAddress() == null) && (address.getAddress() != null)) {
3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this.getAddress().equals(address.getAddress());
3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSingleValued() {
3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress getAddress() {
3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return _addr;
3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * Creates a byte array representation of this record. This is needed for tie-break tests according to draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toByteArray(DataOutputStream dout) throws IOException {
3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toByteArray(dout);
3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            byte[] buffer = this.getAddress().getAddress();
3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (int i = 0; i < buffer.length; i++) {
3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                dout.writeByte(buffer[i]);
3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * Does the necessary actions, when this as a query.
3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleQuery(JmDNSImpl dns, long expirationTime) {
3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (dns.getLocalHost().conflictWithRecord(this)) {
3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                DNSRecord.Address localAddress = dns.getLocalHost().getDNSAddressRecord(this.getRecordType(), this.isUnique(), DNSConstants.DNS_TTL);
3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int comparison = this.compareTo(localAddress);
3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (comparison == 0) {
3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // the 2 records are identical this probably means we are seeing our own record.
3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // With multiple interfaces on a single computer it is possible to see our
3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // own records come in on different interfaces than the ones they were sent on.
3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // see section "10. Conflict Resolution" of mdns draft spec.
3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger1.finer("handleQuery() Ignoring an identical address query");
3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return false;
3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.finer("handleQuery() Conflicting query detected.");
3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // Tie breaker test
3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (dns.isProbing() && comparison > 0) {
3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // We lost the tie-break. We have to choose a different name.
3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getLocalHost().incrementHostName();
3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getCache().clear();
3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (ServiceInfo serviceInfo : dns.getServices().values()) {
3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo;
3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        info.revertState();
3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                dns.revertState();
3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return true;
3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * Does the necessary actions, when this as a response.
3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleResponse(JmDNSImpl dns) {
3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (dns.getLocalHost().conflictWithRecord(this)) {
3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.finer("handleResponse() Denial detected");
3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (dns.isProbing()) {
3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getLocalHost().incrementHostName();
3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getCache().clear();
3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (ServiceInfo serviceInfo : dns.getServices().values()) {
3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo;
3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        info.revertState();
3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                dns.revertState();
3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return true;
3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return out;
3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // info.setAddress(_addr); This is done in the sub class so we don't have to test for class type
3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return info;
3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceEvent getServiceEvent(JmDNSImpl dns) {
4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = this.getServiceInfo(false);
4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDns(dns);
4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toString(StringBuilder aLog) {
4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toString(aLog);
4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(" address: '" + (this.getAddress() != null ? this.getAddress().getHostAddress() : "null") + "'");
4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Pointer record.
4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class Pointer extends DNSRecord {
4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // private static Logger logger = Logger.getLogger(Pointer.class.getName());
4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final String _alias;
4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public Pointer(String name, DNSRecordClass recordClass, boolean unique, int ttl, String alias) {
4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_PTR, recordClass, unique, ttl);
4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._alias = alias;
4323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
4353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
4363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSEntry#isSameEntry(javax.jmdns.impl.DNSEntry)
4373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
4383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSameEntry(DNSEntry entry) {
4403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return super.isSameEntry(entry) && (entry instanceof Pointer) && this.sameValue((Pointer) entry);
4413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
4453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeName(_alias);
4463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameValue(DNSRecord other) {
4503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof Pointer) ) {
4513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
4523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
4533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Pointer pointer = (Pointer) other;
4543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((_alias == null) && (pointer._alias != null)) {
4553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
4563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
4573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return _alias.equals(pointer._alias);
4583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSingleValued() {
4623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
4633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleQuery(JmDNSImpl dns, long expirationTime) {
4673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // Nothing to do (?)
4683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // I think there is no possibility for conflicts for this record type?
4693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
4703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleResponse(JmDNSImpl dns) {
4743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // Nothing to do (?)
4753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // I think there is no possibility for conflicts for this record type?
4763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
4773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String getAlias() {
4803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return _alias;
4813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
4853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return out;
4863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
4893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
4903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
4913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
4923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
4933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
4943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (this.isServicesDiscoveryMetaQuery()) {
4953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // The service name is in the alias
4963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias());
4973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return new ServiceInfoImpl(map, 0, 0, 0, persistent, (byte[]) null);
4983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else if (this.isReverseLookup()) {
4993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
5003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else if (this.isDomainDiscoveryQuery()) {
5013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // FIXME [PJYF Nov 16 2010] We do not currently support domain discovery
5023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, (byte[]) null);
5033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(this.getAlias());
5053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            map.put(Fields.Subtype, this.getQualifiedNameMap().get(Fields.Subtype));
5063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceInfoImpl(map, 0, 0, 0, persistent, this.getAlias());
5073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
5103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
5113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
5123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
5133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceEvent getServiceEvent(JmDNSImpl dns) {
5153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = this.getServiceInfo(false);
5163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDns(dns);
5173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String domainName = info.getType();
5183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String serviceName = JmDNSImpl.toUnqualifiedName(domainName, this.getAlias());
5193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceEventImpl(dns, domainName, serviceName, info);
5203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
5233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
5243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
5253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
5263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toString(StringBuilder aLog) {
5283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toString(aLog);
5293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(" alias: '" + (_alias != null ? _alias.toString() : "null") + "'");
5303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public final static byte[] EMPTY_TXT = new byte[] { 0 };
5353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class Text extends DNSRecord {
5373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // private static Logger logger = Logger.getLogger(Text.class.getName());
5383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final byte[] _text;
5393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public Text(String name, DNSRecordClass recordClass, boolean unique, int ttl, byte text[]) {
5413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_TXT, recordClass, unique, ttl);
5423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._text = (text != null && text.length > 0 ? text : EMPTY_TXT);
5433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
5463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @return the text
5473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
5483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        byte[] getText() {
5493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this._text;
5503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
5543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeBytes(_text, 0, _text.length);
5553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameValue(DNSRecord other) {
5593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof Text) ) {
5603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
5613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Text txt = (Text) other;
5633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((_text == null) && (txt._text != null)) {
5643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
5653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (txt._text.length != _text.length) {
5673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
5683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (int i = _text.length; i-- > 0;) {
5703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (txt._text[i] != _text[i]) {
5713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return false;
5723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
5733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
5743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
5753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSingleValued() {
5793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
5803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleQuery(JmDNSImpl dns, long expirationTime) {
5843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // Nothing to do (?)
5853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // I think there is no possibility for conflicts for this record type?
5863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
5873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
5903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleResponse(JmDNSImpl dns) {
5913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // Nothing to do (?)
5923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // Shouldn't we care if we get a conflict at this level?
5933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            /*
5943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman             * ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); if (info != null) { if (! Arrays.equals(text,info.text)) { info.revertState(); return true; } }
5953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman             */
5963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
5973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
5983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
6013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return out;
6023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
6053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
6063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
6073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
6083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
6103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, _text);
6113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
6143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
6153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
6163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
6173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceEvent getServiceEvent(JmDNSImpl dns) {
6193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = this.getServiceInfo(false);
6203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDns(dns);
6213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
6223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
6253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
6263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
6273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
6283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toString(StringBuilder aLog) {
6303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toString(aLog);
6313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(" text: '" + ((_text.length > 20) ? new String(_text, 0, 17) + "..." : new String(_text)) + "'");
6323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
6373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Service record.
6383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class Service extends DNSRecord {
6403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static Logger logger1 = Logger.getLogger(Service.class.getName());
6413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final int     _priority;
6423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final int     _weight;
6433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final int     _port;
6443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final String  _server;
6453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public Service(String name, DNSRecordClass recordClass, boolean unique, int ttl, int priority, int weight, int port, String server) {
6473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_SRV, recordClass, unique, ttl);
6483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._priority = priority;
6493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._weight = weight;
6503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._port = port;
6513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._server = server;
6523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
6563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeShort(_priority);
6573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeShort(_weight);
6583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeShort(_port);
6593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (DNSIncoming.USE_DOMAIN_NAME_FORMAT_FOR_SRV_TARGET) {
6603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.writeName(_server);
6613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
6623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // [PJYF Nov 13 2010] Do we still need this? This looks really bad. All label are supposed to start by a length.
6633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.writeUTF(_server, 0, _server.length());
6643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // add a zero byte to the end just to be safe, this is the strange form
6663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // used by the BonjourConformanceTest
6673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.writeByte(0);
6683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
6693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
6723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toByteArray(DataOutputStream dout) throws IOException {
6733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toByteArray(dout);
6743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            dout.writeShort(_priority);
6753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            dout.writeShort(_weight);
6763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            dout.writeShort(_port);
6773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
6783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                dout.write(_server.getBytes("UTF-8"));
6793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (UnsupportedEncodingException exception) {
6803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                /* UTF-8 is always present */
6813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
6823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String getServer() {
6853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return _server;
6863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
6893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @return the priority
6903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
6913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public int getPriority() {
6923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this._priority;
6933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
6963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @return the weight
6973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
6983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public int getWeight() {
6993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this._weight;
7003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
7033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @return the port
7043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
7053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public int getPort() {
7063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return this._port;
7073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
7103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameValue(DNSRecord other) {
7113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof Service) ) {
7123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
7133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
7143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Service s = (Service) other;
7153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return (_priority == s._priority) && (_weight == s._weight) && (_port == s._port) && _server.equals(s._server);
7163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
7193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSingleValued() {
7203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
7213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
7243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleQuery(JmDNSImpl dns, long expirationTime) {
7253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
7263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (info != null && (info.isAnnouncing() || info.isAnnounced()) && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) {
7273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.finer("handleQuery() Conflicting probe detected from: " + getRecordSource());
7283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                DNSRecord.Service localService = new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns.getLocalHost().getName());
7293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // This block is useful for debugging race conditions when jmdns is responding to itself.
7313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                try {
7323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (dns.getInetAddress().equals(getRecordSource())) {
7333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        logger1.warning("Got conflicting probe from ourselves\n" + "incoming: " + this.toString() + "\n" + "local   : " + localService.toString());
7343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
7353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } catch (IOException e) {
7363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger1.log(Level.WARNING, "IOException", e);
7373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
7383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int comparison = this.compareTo(localService);
7403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (comparison == 0) {
7423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // the 2 records are identical this probably means we are seeing our own record.
7433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // With multiple interfaces on a single computer it is possible to see our
7443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // own records come in on different interfaces than the ones they were sent on.
7453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // see section "10. Conflict Resolution" of mdns draft spec.
7463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger1.finer("handleQuery() Ignoring a identical service query");
7473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return false;
7483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
7493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // Tie breaker test
7513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (info.isProbing() && comparison > 0) {
7523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // We lost the tie break
7533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    String oldName = info.getQualifiedName().toLowerCase();
7543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    info.setName(dns.incrementName(info.getName()));
7553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getServices().remove(oldName);
7563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getServices().put(info.getQualifiedName().toLowerCase(), info);
7573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger1.finer("handleQuery() Lost tie break: new unique name chosen:" + info.getName());
7583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // We revert the state to start probing again with the new name
7603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    info.revertState();
7613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
7623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // We won the tie break, so this conflicting probe should be ignored
7633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // See paragraph 3 of section 9.2 in mdns draft spec
7643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return false;
7653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
7663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return true;
7683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
7703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
7713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
7743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleResponse(JmDNSImpl dns) {
7753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
7763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (info != null && (_port != info.getPort() || !_server.equalsIgnoreCase(dns.getLocalHost().getName()))) {
7773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger1.finer("handleResponse() Denial detected");
7783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (info.isProbing()) {
7803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    String oldName = info.getQualifiedName().toLowerCase();
7813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    info.setName(dns.incrementName(info.getName()));
7823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getServices().remove(oldName);
7833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.getServices().put(info.getQualifiedName().toLowerCase(), info);
7843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger1.finer("handleResponse() New unique name chose:" + info.getName());
7853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
7873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                info.revertState();
7883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return true;
7893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
7903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
7913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
7943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
7953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfoImpl info = (ServiceInfoImpl) dns.getServices().get(this.getKey());
7963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (info != null) {
7973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (this._port == info.getPort() != _server.equals(dns.getLocalHost().getName())) {
7983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    return dns.addAnswer(in, addr, port, out, new DNSRecord.Service(info.getQualifiedName(), DNSRecordClass.CLASS_IN, DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, info.getPriority(), info.getWeight(), info.getPort(), dns
7993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            .getLocalHost().getName()));
8003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
8013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
8023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return out;
8033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
8083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
8113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceInfoImpl(this.getQualifiedNameMap(), _port, _weight, _priority, persistent, _server);
8123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
8173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceEvent getServiceEvent(JmDNSImpl dns) {
8203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = this.getServiceInfo(false);
8213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDns(dns);
8223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // String domainName = "";
8233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // String serviceName = this.getServer();
8243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // int index = serviceName.indexOf('.');
8253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // if (index > 0)
8263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // {
8273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // serviceName = this.getServer().substring(0, index);
8283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // if (index + 1 < this.getServer().length())
8293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // domainName = this.getServer().substring(index + 1);
8303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // }
8313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // return new ServiceEventImpl(dns, domainName, serviceName, info);
8323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
8333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
8393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toString(StringBuilder aLog) {
8423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toString(aLog);
8433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(" server: '" + _server + ":" + _port + "'");
8443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
8473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class HostInformation extends DNSRecord {
8493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String _os;
8503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String _cpu;
8513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
8533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param name
8543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param recordClass
8553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param unique
8563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param ttl
8573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param cpu
8583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param os
8593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public HostInformation(String name, DNSRecordClass recordClass, boolean unique, int ttl, String cpu, String os) {
8613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(name, DNSRecordType.TYPE_HINFO, recordClass, unique, ttl);
8623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _cpu = cpu;
8633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _os = os;
8643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#addAnswer(javax.jmdns.impl.JmDNSImpl, javax.jmdns.impl.DNSIncoming, java.net.InetAddress, int, javax.jmdns.impl.DNSOutgoing)
8693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        DNSOutgoing addAnswer(JmDNSImpl dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException {
8723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return out;
8733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#handleQuery(javax.jmdns.impl.JmDNSImpl, long)
8783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleQuery(JmDNSImpl dns, long expirationTime) {
8813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
8823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#handleResponse(javax.jmdns.impl.JmDNSImpl)
8873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean handleResponse(JmDNSImpl dns) {
8903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return false;
8913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
8943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
8953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#sameValue(javax.jmdns.impl.DNSRecord)
8963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
8973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
8983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        boolean sameValue(DNSRecord other) {
8993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (! (other instanceof HostInformation) ) {
9003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
9013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            HostInformation hinfo = (HostInformation) other;
9033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((_cpu == null) && (hinfo._cpu != null)) {
9043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
9053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((_os == null) && (hinfo._os != null)) {
9073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return false;
9083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return _cpu.equals(hinfo._cpu) && _os.equals(hinfo._os);
9103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
9133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
9143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#isSingleValued()
9153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
9163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
9173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public boolean isSingleValued() {
9183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
9193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
9223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
9233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#write(javax.jmdns.impl.DNSOutgoing)
9243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
9253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
9263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void write(MessageOutputStream out) {
9273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String hostInfo = _cpu + " " + _os;
9283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            out.writeUTF(hostInfo, 0, hostInfo.length());
9293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
9323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
9333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceInfo(boolean)
9343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
9353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
9363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfo getServiceInfo(boolean persistent) {
9373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Map<String, String> hinfo = new HashMap<String, String>(2);
9383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            hinfo.put("cpu", _cpu);
9393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            hinfo.put("os", _os);
9403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceInfoImpl(this.getQualifiedNameMap(), 0, 0, 0, persistent, hinfo);
9413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
9443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
9453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see javax.jmdns.impl.DNSRecord#getServiceEvent(javax.jmdns.impl.JmDNSImpl)
9463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
9473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
9483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceEvent getServiceEvent(JmDNSImpl dns) {
9493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = this.getServiceInfo(false);
9503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ((ServiceInfoImpl) info).setDns(dns);
9513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return new ServiceEventImpl(dns, info.getType(), info.getName(), info);
9523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
9553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
9563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
9573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
9583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
9593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void toString(StringBuilder aLog) {
9603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.toString(aLog);
9613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(" cpu: '" + _cpu + "' os: '" + _os + "'");
9623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Determine if a record can have multiple values in the cache.
9683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
9693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return <code>false</code> if this record can have multiple values in the cache, <code>true</code> otherwise.
9703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public abstract boolean isSingleValued();
9723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Return a service information associated with that record if appropriate.
9753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
9763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return service information
9773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfo getServiceInfo() {
9793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getServiceInfo(false);
9803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Return a service information associated with that record if appropriate.
9843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
9853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param persistent
9863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            if <code>true</code> ServiceListener.resolveService will be called whenever new new information is received.
9873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return service information
9883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public abstract ServiceInfo getServiceInfo(boolean persistent);
9903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Creates and return a service event for this record.
9933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
9943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param dns
9953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            DNS serviced by this event
9963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return service event
9973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public abstract ServiceEvent getServiceEvent(JmDNSImpl dns);
9993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setRecordSource(InetAddress source) {
10013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._source = source;
10023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress getRecordSource() {
10053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _source;
10063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
10093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
10103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see com.webobjects.discoveryservices.DNSRecord#toString(java.lang.StringBuilder)
10113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected void toString(StringBuilder aLog) {
10143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super.toString(aLog);
10153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        aLog.append(" ttl: '" + getRemainingTTL(System.currentTimeMillis()) + "/" + _ttl + "'");
10163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setTTL(int ttl) {
10193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ttl = ttl;
10203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int getTTL() {
10233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _ttl;
10243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}
1026