diff --git a/activemq-core/pom.xml b/activemq-core/pom.xml index 9b6c1ff6bc..184e6b5772 100755 --- a/activemq-core/pom.xml +++ b/activemq-core/pom.xml @@ -38,6 +38,7 @@ javax.annotation*;resolution:=optional, javax.transaction*;resolution:=optional, javax.security*;resolution:=optional, + javax.jmdns*;resolution:=optional, org.codehaus.jettison*;resolution:=optional, org.apache.activeio*;resolution:=optional, org.apache.camel*;resolution:=optional, @@ -219,8 +220,8 @@ test - org.apache.activemq - activemq-jmdns_1.0 + javax.jmdns + jmdns true diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/JmDNSFactory.java b/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/JmDNSFactory.java index 6b2a369be9..08f61bca29 100644 --- a/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/JmDNSFactory.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/JmDNSFactory.java @@ -21,7 +21,7 @@ import java.net.InetAddress; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.activemq.jmdns.JmDNS; +import javax.jmdns.JmDNS; public final class JmDNSFactory { @@ -39,20 +39,14 @@ public final class JmDNSFactory { UsageTracker tracker = registry.get(address); if (tracker == null) { tracker = new UsageTracker(); - tracker.jmDNS = new JmDNS(address) { - public void close() { - if (onClose(address)) { - super.close(); - } - } - }; + tracker.jmDNS = JmDNS.create(address); registry.put(address, tracker); } tracker.count.incrementAndGet(); return tracker.jmDNS; } - static synchronized boolean onClose(InetAddress address) { + static synchronized boolean onClose(InetAddress address, JmDNS dns) { UsageTracker tracker = registry.get(address); if (tracker != null) { if (tracker.count.decrementAndGet() == 0) { diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/ZeroconfDiscoveryAgent.java b/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/ZeroconfDiscoveryAgent.java index ad032a1f4d..77fc9f3f9c 100755 --- a/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/ZeroconfDiscoveryAgent.java +++ b/activemq-core/src/main/java/org/apache/activemq/transport/discovery/zeroconf/ZeroconfDiscoveryAgent.java @@ -23,11 +23,10 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; - -import org.apache.activemq.jmdns.JmDNS; -import org.apache.activemq.jmdns.ServiceEvent; -import org.apache.activemq.jmdns.ServiceInfo; -import org.apache.activemq.jmdns.ServiceListener; +import javax.jmdns.JmDNS; +import javax.jmdns.ServiceEvent; +import javax.jmdns.ServiceInfo; +import javax.jmdns.ServiceListener; import org.apache.activemq.command.DiscoveryEvent; import org.apache.activemq.transport.discovery.DiscoveryAgent; @@ -46,7 +45,7 @@ import org.slf4j.LoggerFactory; public class ZeroconfDiscoveryAgent implements DiscoveryAgent, ServiceListener { private static final Logger LOG = LoggerFactory.getLogger(ZeroconfDiscoveryAgent.class); - private static final String TYPE_SUFFIX = "ActiveMQ-4."; + private static final String TYPE_SUFFIX = "ActiveMQ-5."; private JmDNS jmdns; private InetAddress localAddress; @@ -92,7 +91,11 @@ public class ZeroconfDiscoveryAgent implements DiscoveryAgent, ServiceListener { final JmDNS closeTarget = jmdns; Thread thread = new Thread() { public void run() { - closeTarget.close(); + try { + JmDNSFactory.onClose(getLocalAddress(), closeTarget); + } catch (IOException e) { + LOG.debug("Error closing JmDNS " + getLocalhost() + ". This exception will be ignored.", e); + } } }; @@ -200,7 +203,7 @@ public class ZeroconfDiscoveryAgent implements DiscoveryAgent, ServiceListener { if (LOG.isDebugEnabled()) { LOG.debug("Registering service type: " + type + " name: " + name + " details: " + map); } - return new ServiceInfo(type, name + "." + type, port, weight, priority, ""); + return ServiceInfo.create(type, name + "." + type, port, weight, priority, ""); } protected JmDNS createJmDNS() throws IOException { diff --git a/activemq-jmdns_1.0/pom.xml b/activemq-jmdns_1.0/pom.xml deleted file mode 100644 index cff60795ed..0000000000 --- a/activemq-jmdns_1.0/pom.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - activemq-parent - org.apache.activemq - 5.7-SNAPSHOT - - 4.0.0 - activemq-jmdns_1.0 - ActiveMQ :: jmdns 1.0 - - - The activemq-jmdns_1.0 source is derived from http://repo1.maven.org/maven2/jmdns/jmdns/1.0/jmdns-1.0-sources.jar - - Changes to apache activemq version: - - renamed package javax.jmdns to org.apache.activemq.jmdns - - removed classes with lgpl source headers, leaving only the org.apache.activemq.jmdns package. - - - - - - maven-surefire-plugin - - true - - - - - diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSCache.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSCache.java deleted file mode 100644 index 5b7cde07ca..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSCache.java +++ /dev/null @@ -1,270 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.logging.Logger; - -/** - * A table of DNS entries. This is a hash table which - * can handle multiple entries with the same name. - *

- * Storing multiple entries with the same name is implemented using a - * linked list of CacheNode's. - *

- * The current implementation of the API of DNSCache does expose the - * cache nodes to clients. Clients must explicitly deal with the nodes - * when iterating over entries in the cache. Here's how to iterate over - * all entries in the cache: - *

- * for (Iterator i=dnscache.iterator(); i.hasNext(); ) {
- *    for (DNSCache.CacheNode n = (DNSCache.CacheNode) i.next(); n != null; n.next()) {
- *       DNSEntry entry = n.getValue();
- *       ...do something with entry...
- *    }
- * }
- * 
- *

- * And here's how to iterate over all entries having a given name: - *

- * for (DNSCache.CacheNode n = (DNSCache.CacheNode) dnscache.find(name); n != null; n.next()) {
- *     DNSEntry entry = n.getValue();
- *     ...do something with entry...
- * }
- * 
- * - * @version %I%, %G% - * @author Arthur van Hoff, Werner Randelshofer, Rick Blair - */ -class DNSCache -{ - private static Logger logger = Logger.getLogger(DNSCache.class.toString()); - // Implementation note: - // We might completely hide the existence of CacheNode's in a future version - // of DNSCache. But this will require to implement two (inner) classes for - // the iterators that will be returned by method iterator() and - // method find(name). - // Since DNSCache is not a public class, it does not seem worth the effort - // to clean its API up that much. - - // [PJYF Oct 15 2004] This should implements Collections that would be amuch cleaner implementation - - /** - * The number of DNSEntry's in the cache. - */ - private int size; - - /** - * The hashtable used internally to store the entries of the cache. - * Keys are instances of String. The String contains an unqualified service - * name. - * Values are linked lists of CacheNode instances. - */ - private HashMap hashtable; - - /** - * Cache nodes are used to implement storage of multiple DNSEntry's of the - * same name in the cache. - */ - public static class CacheNode - { - private static Logger logger = Logger.getLogger(CacheNode.class.toString()); - private DNSEntry value; - private CacheNode next; - - public CacheNode(DNSEntry value) - { - this.value = value; - } - - public CacheNode next() - { - return next; - } - - public DNSEntry getValue() - { - return value; - } - } - - - /** - * Create a table with a given initial size. - */ - public DNSCache(final int size) - { - hashtable = new HashMap(size); - } - - /** - * Clears the cache. - */ - public synchronized void clear() - { - hashtable.clear(); - size = 0; - } - - /** - * Adds an entry to the table. - */ - public synchronized void add(final DNSEntry entry) - { - //logger.log("DNSCache.add("+entry.getName()+")"); - CacheNode newValue = new CacheNode(entry); - CacheNode node = (CacheNode) hashtable.get(entry.getName()); - if (node == null) - { - hashtable.put(entry.getName(), newValue); - } - else - { - newValue.next = node.next; - node.next = newValue; - } - size++; - } - - /** - * Remove a specific entry from the table. Returns true if the - * entry was found. - */ - public synchronized boolean remove(DNSEntry entry) - { - CacheNode node = (CacheNode) hashtable.get(entry.getName()); - if (node != null) - { - if (node.value == entry) - { - if (node.next == null) - { - hashtable.remove(entry.getName()); - } - else - { - hashtable.put(entry.getName(), node.next); - } - size--; - return true; - } - - CacheNode previous = node; - node = node.next; - while (node != null) - { - if (node.value == entry) - { - previous.next = node.next; - size--; - return true; - } - previous = node; - node = node.next; - } - ; - } - return false; - } - - /** - * Get a matching DNS entry from the table (using equals). - * Returns the entry that was found. - */ - public synchronized DNSEntry get(DNSEntry entry) - { - for (CacheNode node = find(entry.getName()); node != null; node = node.next) - { - if (node.value.equals(entry)) - { - return node.value; - } - } - return null; - } - - /** - * Get a matching DNS entry from the table. - */ - public synchronized DNSEntry get(String name, int type, int clazz) - { - for (CacheNode node = find(name); node != null; node = node.next) - { - if (node.value.type == type && node.value.clazz == clazz) - { - return node.value; - } - } - return null; - } - - /** - * Iterates over all cache nodes. - * The iterator returns instances of DNSCache.CacheNode. - * Each instance returned is the first node of a linked list. - * To retrieve all entries, one must iterate over this linked list. See - * code snippets in the header of the class. - */ - public Iterator iterator() - { - return Collections.unmodifiableCollection(hashtable.values()).iterator(); - } - - /** - * Iterate only over items with matching name. - * Returns an instance of DNSCache.CacheNode or null. - * If an instance is returned, it is the first node of a linked list. - * To retrieve all entries, one must iterate over this linked list. - */ - public synchronized CacheNode find(String name) - { - return (CacheNode) hashtable.get(name); - } - - /** - * List all entries for debugging. - */ - public synchronized void print() - { - for (Iterator i = iterator(); i.hasNext();) - { - for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) - { - System.out.println(n.value); - } - } - } - - public synchronized String toString() - { - StringBuffer aLog = new StringBuffer(); - aLog.append("\t---- cache ----"); - for (Iterator i = iterator(); i.hasNext();) - { - for (CacheNode n = (CacheNode) i.next(); n != null; n = n.next) - { - aLog.append("\n\t\t" + n.value); - } - } - return aLog.toString(); - } - -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSConstants.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSConstants.java deleted file mode 100644 index 21363e5d1b..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSConstants.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -/** - * DNS constants. - * - * @version %I%, %G% - * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer, Pierre Frisch, Rick Blair - */ -final class DNSConstants -{ - - // changed to final class - jeffs - final static String MDNS_GROUP = "224.0.0.251"; - final static String MDNS_GROUP_IPV6 = "FF02::FB"; - final static int MDNS_PORT = 5353; - final static int DNS_PORT = 53; - final static int DNS_TTL = 60 * 60; // default one hour TTL - // final static int DNS_TTL = 120 * 60; // two hour TTL (draft-cheshire-dnsext-multicastdns.txt ch 13) - - final static int MAX_MSG_TYPICAL = 1460; - final static int MAX_MSG_ABSOLUTE = 8972; - - final static int FLAGS_QR_MASK = 0x8000; // Query response mask - final static int FLAGS_QR_QUERY = 0x0000; // Query - final static int FLAGS_QR_RESPONSE = 0x8000; // Response - - final static int FLAGS_AA = 0x0400; // Authorative answer - final static int FLAGS_TC = 0x0200; // Truncated - final static int FLAGS_RD = 0x0100; // Recursion desired - final static int FLAGS_RA = 0x8000; // Recursion available - - final static int FLAGS_Z = 0x0040; // Zero - final static int FLAGS_AD = 0x0020; // Authentic data - final static int FLAGS_CD = 0x0010; // Checking disabled - - final static int CLASS_IN = 1; // Final Static Internet - final static int CLASS_CS = 2; // CSNET - final static int CLASS_CH = 3; // CHAOS - final static int CLASS_HS = 4; // Hesiod - final static int CLASS_NONE = 254; // Used in DNS UPDATE [RFC 2136] - final static int CLASS_ANY = 255; // Not a DNS class, but a DNS query class, meaning "all classes" - final static int CLASS_MASK = 0x7FFF; // Multicast DNS uses the bottom 15 bits to identify the record class... - final static int CLASS_UNIQUE = 0x8000; // ... and the top bit indicates that all other cached records are now invalid - - final static int TYPE_IGNORE = 0; // This is a hack to stop further processing - final static int TYPE_A = 1; // Address - final static int TYPE_NS = 2; // Name Server - final static int TYPE_MD = 3; // Mail Destination - final static int TYPE_MF = 4; // Mail Forwarder - final static int TYPE_CNAME = 5; // Canonical Name - final static int TYPE_SOA = 6; // Start of Authority - final static int TYPE_MB = 7; // Mailbox - final static int TYPE_MG = 8; // Mail Group - final static int TYPE_MR = 9; // Mail Rename - final static int TYPE_NULL = 10; // NULL RR - final static int TYPE_WKS = 11; // Well-known-service - final static int TYPE_PTR = 12; // Domain Name pofinal static inter - final static int TYPE_HINFO = 13; // Host information - final static int TYPE_MINFO = 14; // Mailbox information - final static int TYPE_MX = 15; // Mail exchanger - final static int TYPE_TXT = 16; // Arbitrary text string - final static int TYPE_RP = 17; // for Responsible Person [RFC1183] - final static int TYPE_AFSDB = 18; // for AFS Data Base location [RFC1183] - final static int TYPE_X25 = 19; // for X.25 PSDN address [RFC1183] - final static int TYPE_ISDN = 20; // for ISDN address [RFC1183] - final static int TYPE_RT = 21; // for Route Through [RFC1183] - final static int TYPE_NSAP = 22; // for NSAP address, NSAP style A record [RFC1706] - final static int TYPE_NSAP_PTR = 23; // - final static int TYPE_SIG = 24; // for security signature [RFC2931] - final static int TYPE_KEY = 25; // for security key [RFC2535] - final static int TYPE_PX = 26; // X.400 mail mapping information [RFC2163] - final static int TYPE_GPOS = 27; // Geographical Position [RFC1712] - final static int TYPE_AAAA = 28; // IP6 Address [Thomson] - final static int TYPE_LOC = 29; // Location Information [Vixie] - final static int TYPE_NXT = 30; // Next Domain - OBSOLETE [RFC2535, RFC3755] - final static int TYPE_EID = 31; // Endpoint Identifier [Patton] - final static int TYPE_NIMLOC = 32; // Nimrod Locator [Patton] - final static int TYPE_SRV = 33; // Server Selection [RFC2782] - final static int TYPE_ATMA = 34; // ATM Address [Dobrowski] - final static int TYPE_NAPTR = 35; // Naming Authority Pointer [RFC2168, RFC2915] - final static int TYPE_KX = 36; // Key Exchanger [RFC2230] - final static int TYPE_CERT = 37; // CERT [RFC2538] - final static int TYPE_A6 = 38; // A6 [RFC2874] - final static int TYPE_DNAME = 39; // DNAME [RFC2672] - final static int TYPE_SINK = 40; // SINK [Eastlake] - final static int TYPE_OPT = 41; // OPT [RFC2671] - final static int TYPE_APL = 42; // APL [RFC3123] - final static int TYPE_DS = 43; // Delegation Signer [RFC3658] - final static int TYPE_SSHFP = 44; // SSH Key Fingerprint [RFC-ietf-secsh-dns-05.txt] - final static int TYPE_RRSIG = 46; // RRSIG [RFC3755] - final static int TYPE_NSEC = 47; // NSEC [RFC3755] - final static int TYPE_DNSKEY = 48; // DNSKEY [RFC3755] - final static int TYPE_UINFO = 100; // [IANA-Reserved] - final static int TYPE_UID = 101; // [IANA-Reserved] - final static int TYPE_GID = 102; // [IANA-Reserved] - final static int TYPE_UNSPEC = 103; // [IANA-Reserved] - final static int TYPE_TKEY = 249; // Transaction Key [RFC2930] - final static int TYPE_TSIG = 250; // Transaction Signature [RFC2845] - final static int TYPE_IXFR = 251; // Incremental transfer [RFC1995] - final static int TYPE_AXFR = 252; // Transfer of an entire zone [RFC1035] - final static int TYPE_MAILA = 253; // Mailbox-related records (MB, MG or MR) [RFC1035] - final static int TYPE_MAILB = 254; // Mail agent RRs (Obsolete - see MX) [RFC1035] - final static int TYPE_ANY = 255; // Request for all records [RFC1035] - - //Time Intervals for various functions - - final static int SHARED_QUERY_TIME = 20; //milliseconds before send shared query - final static int QUERY_WAIT_INTERVAL = 225; //milliseconds between query loops. - final static int PROBE_WAIT_INTERVAL = 250; //milliseconds between probe loops. - final static int RESPONSE_MIN_WAIT_INTERVAL = 20; //minimal wait interval for response. - final static int RESPONSE_MAX_WAIT_INTERVAL = 115; //maximal wait interval for response - final static int PROBE_CONFLICT_INTERVAL = 1000; //milliseconds to wait after conflict. - final static int PROBE_THROTTLE_COUNT = 10; //After x tries go 1 time a sec. on probes. - final static int PROBE_THROTTLE_COUNT_INTERVAL = 5000; //We only increment the throttle count, if - // the previous increment is inside this interval. - final static int ANNOUNCE_WAIT_INTERVAL = 1000; //milliseconds between Announce loops. - final static int RECORD_REAPER_INTERVAL = 10000; //milliseconds between cache cleanups. - final static int KNOWN_ANSWER_TTL = 120; - final static int ANNOUNCED_RENEWAL_TTL_INTERVAL = DNS_TTL * 500; // 50% of the TTL in milliseconds -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSEntry.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSEntry.java deleted file mode 100644 index b0bc06be72..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSEntry.java +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.logging.Logger; - -/** - * DNS entry with a name, type, and class. This is the base - * class for questions and records. - * - * @version %I%, %G% - * @author Arthur van Hoff, Pierre Frisch, Rick Blair - */ -class DNSEntry -{ - private static Logger logger = Logger.getLogger(DNSEntry.class.toString()); - String key; - String name; - int type; - int clazz; - boolean unique; - - /** - * Create an entry. - */ - DNSEntry(String name, int type, int clazz) - { - this.key = name.toLowerCase(); - this.name = name; - this.type = type; - this.clazz = clazz & DNSConstants.CLASS_MASK; - this.unique = (clazz & DNSConstants.CLASS_UNIQUE) != 0; - } - - /** - * Check if two entries have exactly the same name, type, and class. - */ - public boolean equals(Object obj) - { - if (obj instanceof DNSEntry) - { - DNSEntry other = (DNSEntry) obj; - return name.equals(other.name) && type == other.type && clazz == other.clazz; - } - return false; - } - - public String getName() - { - return name; - } - - public int getType() - { - return type; - } - - /** - * Overriden, to return a value which is consistent with the value returned - * by equals(Object). - */ - public int hashCode() - { - return name.hashCode() + type + clazz; - } - - /** - * Get a string given a clazz. - */ - static String getClazz(int clazz) - { - switch (clazz & DNSConstants.CLASS_MASK) - { - case DNSConstants.CLASS_IN: - return "in"; - case DNSConstants.CLASS_CS: - return "cs"; - case DNSConstants.CLASS_CH: - return "ch"; - case DNSConstants.CLASS_HS: - return "hs"; - case DNSConstants.CLASS_NONE: - return "none"; - case DNSConstants.CLASS_ANY: - return "any"; - default: - return "?"; - } - } - - /** - * Get a string given a type. - */ - static String getType(int type) - { - switch (type) - { - case DNSConstants.TYPE_A: - return "a"; - case DNSConstants.TYPE_AAAA: - return "aaaa"; - case DNSConstants.TYPE_NS: - return "ns"; - case DNSConstants.TYPE_MD: - return "md"; - case DNSConstants.TYPE_MF: - return "mf"; - case DNSConstants.TYPE_CNAME: - return "cname"; - case DNSConstants.TYPE_SOA: - return "soa"; - case DNSConstants.TYPE_MB: - return "mb"; - case DNSConstants.TYPE_MG: - return "mg"; - case DNSConstants.TYPE_MR: - return "mr"; - case DNSConstants.TYPE_NULL: - return "null"; - case DNSConstants.TYPE_WKS: - return "wks"; - case DNSConstants.TYPE_PTR: - return "ptr"; - case DNSConstants.TYPE_HINFO: - return "hinfo"; - case DNSConstants.TYPE_MINFO: - return "minfo"; - case DNSConstants.TYPE_MX: - return "mx"; - case DNSConstants.TYPE_TXT: - return "txt"; - case DNSConstants.TYPE_SRV: - return "srv"; - case DNSConstants.TYPE_ANY: - return "any"; - default: - return "?"; - } - } - - public String toString(String hdr, String other) - { - return hdr + "[" + getType(type) + "," + getClazz(clazz) + (unique ? "-unique," : ",") + name + ((other != null) ? "," + other + "]" : "]"); - } -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSIncoming.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSIncoming.java deleted file mode 100644 index 90c18d90f4..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSIncoming.java +++ /dev/null @@ -1,478 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Parse an incoming DNS message into its components. - * - * @version %I%, %G% - * @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch - */ -final class DNSIncoming -{ - private static Logger logger = Logger.getLogger(DNSIncoming.class.toString()); - // Implementation note: This vector should be immutable. - // If a client of DNSIncoming changes the contents of this vector, - // we get undesired results. To fix this, we have to migrate to - // the Collections API of Java 1.2. i.e we replace Vector by List. - // final static Vector EMPTY = new Vector(); - - private DatagramPacket packet; - private int off; - private int len; - private byte data[]; - - int id; - private int flags; - private int numQuestions; - int numAnswers; - private int numAuthorities; - private int numAdditionals; - private long receivedTime; - - List questions; - List answers; - - /** - * Parse a message from a datagram packet. - */ - DNSIncoming(DatagramPacket packet) throws IOException - { - this.packet = packet; - this.data = packet.getData(); - this.len = packet.getLength(); - this.off = packet.getOffset(); - this.questions = Collections.EMPTY_LIST; - this.answers = Collections.EMPTY_LIST; - this.receivedTime = System.currentTimeMillis(); - - try - { - id = readUnsignedShort(); - flags = readUnsignedShort(); - numQuestions = readUnsignedShort(); - numAnswers = readUnsignedShort(); - numAuthorities = readUnsignedShort(); - numAdditionals = readUnsignedShort(); - - // parse questions - if (numQuestions > 0) - { - questions = Collections.synchronizedList(new ArrayList(numQuestions)); - for (int i = 0; i < numQuestions; i++) - { - DNSQuestion question = new DNSQuestion(readName(), readUnsignedShort(), readUnsignedShort()); - questions.add(question); - } - } - - // parse answers - int n = numAnswers + numAuthorities + numAdditionals; - if (n > 0) - { - answers = Collections.synchronizedList(new ArrayList(n)); - for (int i = 0; i < n; i++) - { - String domain = readName(); - int type = readUnsignedShort(); - int clazz = readUnsignedShort(); - int ttl = readInt(); - int len = readUnsignedShort(); - int end = off + len; - DNSRecord rec = null; - - switch (type) - { - case DNSConstants.TYPE_A: // IPv4 - case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested - rec = new DNSRecord.Address(domain, type, clazz, ttl, readBytes(off, len)); - break; - case DNSConstants.TYPE_CNAME: - case DNSConstants.TYPE_PTR: - rec = new DNSRecord.Pointer(domain, type, clazz, ttl, readName()); - break; - case DNSConstants.TYPE_TXT: - rec = new DNSRecord.Text(domain, type, clazz, ttl, readBytes(off, len)); - break; - case DNSConstants.TYPE_SRV: - rec = new DNSRecord.Service(domain, type, clazz, ttl, - readUnsignedShort(), readUnsignedShort(), readUnsignedShort(), readName()); - break; - case DNSConstants.TYPE_HINFO: - // Maybe we should do something with those - break; - default : - logger.finer("DNSIncoming() unknown type:" + type); - break; - } - - if (rec != null) - { - // Add a record, if we were able to create one. - answers.add(rec); - } - else - { - // Addjust the numbers for the skipped record - if (answers.size() < numAnswers) - { - numAnswers--; - } - else - { - if (answers.size() < numAnswers + numAuthorities) - { - numAuthorities--; - } - else - { - if (answers.size() < numAnswers + numAuthorities + numAdditionals) - { - numAdditionals--; - } - } - } - } - off = end; - } - } - } - catch (IOException e) - { - logger.log(Level.WARNING, "DNSIncoming() dump " + print(true) + "\n exception ", e); - throw e; - } - } - - /** - * Check if the message is a query. - */ - boolean isQuery() - { - return (flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY; - } - - /** - * Check if the message is truncated. - */ - boolean isTruncated() - { - return (flags & DNSConstants.FLAGS_TC) != 0; - } - - /** - * Check if the message is a response. - */ - boolean isResponse() - { - return (flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_RESPONSE; - } - - private int get(int off) throws IOException - { - if ((off < 0) || (off >= len)) - { - throw new IOException("parser error: offset=" + off); - } - return data[off] & 0xFF; - } - - private int readUnsignedShort() throws IOException - { - return (get(off++) << 8) + get(off++); - } - - private int readInt() throws IOException - { - return (readUnsignedShort() << 16) + readUnsignedShort(); - } - - private byte[] readBytes(int off, int len) throws IOException - { - byte bytes[] = new byte[len]; - System.arraycopy(data, off, bytes, 0, len); - return bytes; - } - - private void readUTF(StringBuffer buf, int off, int len) throws IOException - { - for (int end = off + len; off < end;) - { - int ch = get(off++); - switch (ch >> 4) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxxxxxx - break; - case 12: - case 13: - // 110x xxxx 10xx xxxx - ch = ((ch & 0x1F) << 6) | (get(off++) & 0x3F); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - ch = ((ch & 0x0f) << 12) | ((get(off++) & 0x3F) << 6) | (get(off++) & 0x3F); - break; - default: - // 10xx xxxx, 1111 xxxx - ch = ((ch & 0x3F) << 4) | (get(off++) & 0x0f); - break; - } - buf.append((char) ch); - } - } - - private String readName() throws IOException - { - StringBuffer buf = new StringBuffer(); - int off = this.off; - int next = -1; - int first = off; - - while (true) - { - int len = get(off++); - if (len == 0) - { - break; - } - switch (len & 0xC0) - { - case 0x00: - //buf.append("[" + off + "]"); - readUTF(buf, off, len); - off += len; - buf.append('.'); - break; - case 0xC0: - //buf.append("<" + (off - 1) + ">"); - if (next < 0) - { - next = off + 1; - } - off = ((len & 0x3F) << 8) | get(off++); - if (off >= first) - { - throw new IOException("bad domain name: possible circular name detected"); - } - first = off; - break; - default: - throw new IOException("bad domain name: '" + buf + "' at " + off); - } - } - this.off = (next >= 0) ? next : off; - return buf.toString(); - } - - /** - * Debugging. - */ - String print(boolean dump) - { - StringBuffer buf = new StringBuffer(); - buf.append(toString() + "\n"); - for (Iterator iterator = questions.iterator(); iterator.hasNext();) - { - buf.append(" ques:" + iterator.next() + "\n"); - } - int count = 0; - for (Iterator iterator = answers.iterator(); iterator.hasNext(); count++) - { - if (count < numAnswers) - { - buf.append(" answ:"); - } - else - { - if (count < numAnswers + numAuthorities) - { - buf.append(" auth:"); - } - else - { - buf.append(" addi:"); - } - } - buf.append(iterator.next() + "\n"); - } - if (dump) - { - for (int off = 0, len = packet.getLength(); off < len; off += 32) - { - int n = Math.min(32, len - off); - if (off < 10) - { - buf.append(' '); - } - if (off < 100) - { - buf.append(' '); - } - buf.append(off); - buf.append(':'); - for (int i = 0; i < n; i++) - { - if ((i % 8) == 0) - { - buf.append(' '); - } - buf.append(Integer.toHexString((data[off + i] & 0xF0) >> 4)); - buf.append(Integer.toHexString((data[off + i] & 0x0F) >> 0)); - } - buf.append("\n"); - buf.append(" "); - for (int i = 0; i < n; i++) - { - if ((i % 8) == 0) - { - buf.append(' '); - } - buf.append(' '); - int ch = data[off + i] & 0xFF; - buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.'); - } - buf.append("\n"); - - // limit message size - if (off + 32 >= 256) - { - buf.append("....\n"); - break; - } - } - } - return buf.toString(); - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append(isQuery() ? "dns[query," : "dns[response,"); - if (packet.getAddress() != null) - { - buf.append(packet.getAddress().getHostAddress()); - } - buf.append(':'); - buf.append(packet.getPort()); - buf.append(",len="); - buf.append(packet.getLength()); - buf.append(",id=0x"); - buf.append(Integer.toHexString(id)); - if (flags != 0) - { - buf.append(",flags=0x"); - buf.append(Integer.toHexString(flags)); - if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0) - { - buf.append(":r"); - } - if ((flags & DNSConstants.FLAGS_AA) != 0) - { - buf.append(":aa"); - } - if ((flags & DNSConstants.FLAGS_TC) != 0) - { - buf.append(":tc"); - } - } - if (numQuestions > 0) - { - buf.append(",questions="); - buf.append(numQuestions); - } - if (numAnswers > 0) - { - buf.append(",answers="); - buf.append(numAnswers); - } - if (numAuthorities > 0) - { - buf.append(",authorities="); - buf.append(numAuthorities); - } - if (numAdditionals > 0) - { - buf.append(",additionals="); - buf.append(numAdditionals); - } - buf.append("]"); - return buf.toString(); - } - - /** - * Appends answers to this Incoming. - * - * @throws IllegalArgumentException If not a query or if Truncated. - */ - void append(DNSIncoming that) - { - if (this.isQuery() && this.isTruncated() && that.isQuery()) - { - this.questions.addAll(that.questions); - this.numQuestions += that.numQuestions; - - if (Collections.EMPTY_LIST.equals(answers)) - { - answers = Collections.synchronizedList(new ArrayList()); - } - - if (that.numAnswers > 0) - { - this.answers.addAll(this.numAnswers, that.answers.subList(0, that.numAnswers)); - this.numAnswers += that.numAnswers; - } - if (that.numAuthorities > 0) - { - this.answers.addAll(this.numAnswers + this.numAuthorities, that.answers.subList(that.numAnswers, that.numAnswers + that.numAuthorities)); - this.numAuthorities += that.numAuthorities; - } - if (that.numAdditionals > 0) - { - this.answers.addAll(that.answers.subList(that.numAnswers + that.numAuthorities, that.numAnswers + that.numAuthorities + that.numAdditionals)); - this.numAdditionals += that.numAdditionals; - } - } - else - { - throw new IllegalArgumentException(); - } - } - - int elapseSinceArrival() - { - return (int) (System.currentTimeMillis() - receivedTime); - } -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSListener.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSListener.java deleted file mode 100644 index 269a5f0b62..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSListener.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -// REMIND: Listener should follow Java idiom for listener or have a different -// name. - -/** - * DNSListener. - * Listener for record updates. - * - * @author Werner Randelshofer, Rick Blair - * @version 1.0 May 22, 2004 Created. - */ -public interface DNSListener -{ - /** - * Update a DNS record. - */ - void updateRecord(JmDNS jmdns, long now, DNSRecord record); -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSOutgoing.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSOutgoing.java deleted file mode 100644 index a39dfec01a..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSOutgoing.java +++ /dev/null @@ -1,394 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.io.IOException; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * An outgoing DNS message. - * - * @version %I%, %G% - * @author Arthur van Hoff, Rick Blair, Werner Randelshofer - */ -final class DNSOutgoing -{ - private static Logger logger = Logger.getLogger(DNSOutgoing.class.toString()); - int id; - int flags; - private boolean multicast; - private int numQuestions; - private int numAnswers; - private int numAuthorities; - private int numAdditionals; - private Hashtable names; - - byte data[]; - int off; - int len; - - /** - * Create an outgoing multicast query or response. - */ - DNSOutgoing(int flags) - { - this(flags, true); - } - - /** - * Create an outgoing query or response. - */ - DNSOutgoing(int flags, boolean multicast) - { - this.flags = flags; - this.multicast = multicast; - names = new Hashtable(); - data = new byte[DNSConstants.MAX_MSG_TYPICAL]; - off = 12; - } - - /** - * Add a question to the message. - */ - void addQuestion(DNSQuestion rec) throws IOException - { - if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0) - { - throw new IllegalStateException("Questions must be added before answers"); - } - numQuestions++; - writeQuestion(rec); - } - - /** - * Add an answer if it is not suppressed. - */ - void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException - { - if (numAuthorities > 0 || numAdditionals > 0) - { - throw new IllegalStateException("Answers must be added before authorities and additionals"); - } - if (!rec.suppressedBy(in)) - { - addAnswer(rec, 0); - } - } - - /** - * Add an additional answer to the record. Omit if there is no room. - */ - void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException - { - if ((off < DNSConstants.MAX_MSG_TYPICAL - 200) && !rec.suppressedBy(in)) - { - writeRecord(rec, 0); - numAdditionals++; - } - } - - /** - * Add an answer to the message. - */ - void addAnswer(DNSRecord rec, long now) throws IOException - { - if (numAuthorities > 0 || numAdditionals > 0) - { - throw new IllegalStateException("Questions must be added before answers"); - } - if (rec != null) - { - if ((now == 0) || !rec.isExpired(now)) - { - writeRecord(rec, now); - numAnswers++; - } - } - } - - private LinkedList authorativeAnswers = new LinkedList(); - - /** - * Add an authorative answer to the message. - */ - void addAuthorativeAnswer(DNSRecord rec) throws IOException - { - if (numAdditionals > 0) - { - throw new IllegalStateException("Authorative answers must be added before additional answers"); - } - authorativeAnswers.add(rec); - writeRecord(rec, 0); - numAuthorities++; - - // VERIFY: - - } - - void writeByte(int value) throws IOException - { - if (off >= data.length) - { - throw new IOException("buffer full"); - } - data[off++] = (byte) value; - } - - void writeBytes(String str, int off, int len) throws IOException - { - for (int i = 0; i < len; i++) - { - writeByte(str.charAt(off + i)); - } - } - - void writeBytes(byte data[]) throws IOException - { - if (data != null) - { - writeBytes(data, 0, data.length); - } - } - - void writeBytes(byte data[], int off, int len) throws IOException - { - for (int i = 0; i < len; i++) - { - writeByte(data[off + i]); - } - } - - void writeShort(int value) throws IOException - { - writeByte(value >> 8); - writeByte(value); - } - - void writeInt(int value) throws IOException - { - writeShort(value >> 16); - writeShort(value); - } - - void writeUTF(String str, int off, int len) throws IOException - { - // compute utf length - int utflen = 0; - for (int i = 0; i < len; i++) - { - int ch = str.charAt(off + i); - if ((ch >= 0x0001) && (ch <= 0x007F)) - { - utflen += 1; - } - else - { - if (ch > 0x07FF) - { - utflen += 3; - } - else - { - utflen += 2; - } - } - } - // write utf length - writeByte(utflen); - // write utf data - for (int i = 0; i < len; i++) - { - int ch = str.charAt(off + i); - if ((ch >= 0x0001) && (ch <= 0x007F)) - { - writeByte(ch); - } - else - { - if (ch > 0x07FF) - { - writeByte(0xE0 | ((ch >> 12) & 0x0F)); - writeByte(0x80 | ((ch >> 6) & 0x3F)); - writeByte(0x80 | ((ch >> 0) & 0x3F)); - } - else - { - writeByte(0xC0 | ((ch >> 6) & 0x1F)); - writeByte(0x80 | ((ch >> 0) & 0x3F)); - } - } - } - } - - void writeName(String name) throws IOException - { - while (true) - { - int n = name.indexOf('.'); - if (n < 0) - { - n = name.length(); - } - if (n <= 0) - { - writeByte(0); - return; - } - Integer offset = (Integer) names.get(name); - if (offset != null) - { - int val = offset.intValue(); - - if (val > off) - { - logger.log(Level.WARNING, "DNSOutgoing writeName failed val=" + val + " name=" + name); - } - - writeByte((val >> 8) | 0xC0); - writeByte(val); - return; - } - names.put(name, new Integer(off)); - writeUTF(name, 0, n); - name = name.substring(n); - if (name.startsWith(".")) - { - name = name.substring(1); - } - } - } - - void writeQuestion(DNSQuestion question) throws IOException - { - writeName(question.name); - writeShort(question.type); - writeShort(question.clazz); - } - - void writeRecord(DNSRecord rec, long now) throws IOException - { - int save = off; - try - { - writeName(rec.name); - writeShort(rec.type); - writeShort(rec.clazz | ((rec.unique && multicast) ? DNSConstants.CLASS_UNIQUE : 0)); - writeInt((now == 0) ? rec.ttl : rec.getRemainingTTL(now)); - writeShort(0); - int start = off; - rec.write(this); - int len = off - start; - data[start - 2] = (byte) (len >> 8); - data[start - 1] = (byte) (len & 0xFF); - } - catch (IOException e) - { - off = save; - throw e; - } - } - - /** - * Finish the message before sending it off. - */ - void finish() throws IOException - { - int save = off; - off = 0; - - writeShort(multicast ? 0 : id); - writeShort(flags); - writeShort(numQuestions); - writeShort(numAnswers); - writeShort(numAuthorities); - writeShort(numAdditionals); - off = save; - } - - boolean isQuery() - { - return (flags & DNSConstants.FLAGS_QR_MASK) == DNSConstants.FLAGS_QR_QUERY; - } - - public boolean isEmpty() - { - return numQuestions == 0 && numAuthorities == 0 - && numAdditionals == 0 && numAnswers == 0; - } - - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append(isQuery() ? "dns[query," : "dns[response,"); - //buf.append(packet.getAddress().getHostAddress()); - buf.append(':'); - //buf.append(packet.getPort()); - //buf.append(",len="); - //buf.append(packet.getLength()); - buf.append(",id=0x"); - buf.append(Integer.toHexString(id)); - if (flags != 0) - { - buf.append(",flags=0x"); - buf.append(Integer.toHexString(flags)); - if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0) - { - buf.append(":r"); - } - if ((flags & DNSConstants.FLAGS_AA) != 0) - { - buf.append(":aa"); - } - if ((flags & DNSConstants.FLAGS_TC) != 0) - { - buf.append(":tc"); - } - } - if (numQuestions > 0) - { - buf.append(",questions="); - buf.append(numQuestions); - } - if (numAnswers > 0) - { - buf.append(",answers="); - buf.append(numAnswers); - } - if (numAuthorities > 0) - { - buf.append(",authorities="); - buf.append(numAuthorities); - } - if (numAdditionals > 0) - { - buf.append(",additionals="); - buf.append(numAdditionals); - } - buf.append(",\nnames=" + names); - buf.append(",\nauthorativeAnswers=" + authorativeAnswers); - - buf.append("]"); - return buf.toString(); - } - -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSQuestion.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSQuestion.java deleted file mode 100644 index a206d81704..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSQuestion.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.logging.Logger; - -/** - * A DNS question. - * - * @version %I%, %G% - * @author Arthur van Hoff - */ -final class DNSQuestion extends DNSEntry -{ - private static Logger logger = Logger.getLogger(DNSQuestion.class.toString()); - - /** - * Create a question. - */ - DNSQuestion(String name, int type, int clazz) - { - super(name, type, clazz); - } - - /** - * Check if this question is answered by a given DNS record. - */ - boolean answeredBy(DNSRecord rec) - { - return (clazz == rec.clazz) && ((type == rec.type) || (type == DNSConstants.TYPE_ANY)) && - name.equals(rec.name); - } - - /** - * For debugging only. - */ - public String toString() - { - return toString("question", null); - } -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSRecord.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSRecord.java deleted file mode 100644 index 954b311c28..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSRecord.java +++ /dev/null @@ -1,686 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * DNS record - * - * @version %I%, %G% - * @author Arthur van Hoff, Rick Blair, Werner Randelshofer, Pierre Frisch - */ -public abstract class DNSRecord extends DNSEntry -{ - private static Logger logger = Logger.getLogger(DNSRecord.class.toString()); - int ttl; - private long created; - - /** - * Create a DNSRecord with a name, type, clazz, and ttl. - */ - DNSRecord(String name, int type, int clazz, int ttl) - { - super(name, type, clazz); - this.ttl = ttl; - this.created = System.currentTimeMillis(); - } - - /** - * True if this record is the same as some other record. - */ - public boolean equals(Object other) - { - return (other instanceof DNSRecord) && sameAs((DNSRecord) other); - } - - /** - * True if this record is the same as some other record. - */ - boolean sameAs(DNSRecord other) - { - return super.equals(other) && sameValue((DNSRecord) other); - } - - /** - * True if this record has the same value as some other record. - */ - abstract boolean sameValue(DNSRecord other); - - /** - * True if this record has the same type as some other record. - */ - boolean sameType(DNSRecord other) - { - return type == other.type; - } - - /** - * Handles a query represented by this record. - * - * @return Returns true if a conflict with one of the services registered - * with JmDNS or with the hostname occured. - */ - abstract boolean handleQuery(JmDNS dns, long expirationTime); - - /** - * Handles a responserepresented by this record. - * - * @return Returns true if a conflict with one of the services registered - * with JmDNS or with the hostname occured. - */ - abstract boolean handleResponse(JmDNS dns); - - /** - * Adds this as an answer to the provided outgoing datagram. - */ - abstract DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException; - - /** - * True if this record is suppressed by the answers in a message. - */ - boolean suppressedBy(DNSIncoming msg) - { - try - { - for (int i = msg.numAnswers; i-- > 0;) - { - if (suppressedBy((DNSRecord) msg.answers.get(i))) - { - return true; - } - } - return false; - } - catch (ArrayIndexOutOfBoundsException e) - { - logger.log(Level.WARNING, "suppressedBy() message " + msg + " exception ", e); - // msg.print(true); - return false; - } - } - - /** - * True if this record would be supressed by an answer. - * This is the case if this record would not have a - * significantly longer TTL. - */ - boolean suppressedBy(DNSRecord other) - { - if (sameAs(other) && (other.ttl > ttl / 2)) - { - return true; - } - return false; - } - - /** - * Get the expiration time of this record. - */ - long getExpirationTime(int percent) - { - return created + (percent * ttl * 10L); - } - - /** - * Get the remaining TTL for this record. - */ - int getRemainingTTL(long now) - { - return (int) Math.max(0, (getExpirationTime(100) - now) / 1000); - } - - /** - * Check if the record is expired. - */ - public boolean isExpired(long now) - { - return getExpirationTime(100) <= now; - } - - /** - * Check if the record is stale, ie it has outlived - * more than half of its TTL. - */ - boolean isStale(long now) - { - return getExpirationTime(50) <= now; - } - - /** - * Reset the TTL of a record. This avoids having to - * update the entire record in the cache. - */ - void resetTTL(DNSRecord other) - { - created = other.created; - ttl = other.ttl; - } - - /** - * Write this record into an outgoing message. - */ - abstract void write(DNSOutgoing out) throws IOException; - - /** - * Address record. - */ - public static class Address extends DNSRecord - { - private static Logger logger = Logger.getLogger(Address.class.toString()); - InetAddress addr; - - Address(String name, int type, int clazz, int ttl, InetAddress addr) - { - super(name, type, clazz, ttl); - this.addr = addr; - } - - Address(String name, int type, int clazz, int ttl, byte[] rawAddress) - { - super(name, type, clazz, ttl); - try - { - this.addr = InetAddress.getByAddress(rawAddress); - } - catch (UnknownHostException exception) - { - logger.log(Level.WARNING, "Address() exception ", exception); - } - } - - void write(DNSOutgoing out) throws IOException - { - if (addr != null) - { - byte[] buffer = addr.getAddress(); - if (DNSConstants.TYPE_A == type) - { - // If we have a type A records we should answer with a IPv4 address - if (addr instanceof Inet4Address) - { - // All is good - } - else - { - // Get the last four bytes - byte[] tempbuffer = buffer; - buffer = new byte[4]; - System.arraycopy(tempbuffer, 12, buffer, 0, 4); - } - } - else - { - // If we have a type AAAA records we should answer with a IPv6 address - if (addr instanceof Inet4Address) - { - byte[] tempbuffer = buffer; - buffer = new byte[16]; - for (int i = 0; i < 16; i++) - { - if (i < 11) - { - buffer[i] = tempbuffer[i - 12]; - } - else - { - buffer[i] = 0; - } - } - } - } - int length = buffer.length; - out.writeBytes(buffer, 0, length); - } - } - - boolean same(DNSRecord other) - { - return ((sameName(other)) && ((sameValue(other)))); - } - - boolean sameName(DNSRecord other) - { - return name.equalsIgnoreCase(((Address) other).name); - } - - boolean sameValue(DNSRecord other) - { - return addr.equals(((Address) other).getAddress()); - } - - InetAddress getAddress() - { - return addr; - } - - /** - * 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. - */ - private byte[] toByteArray() - { - try - { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - dout.write(name.getBytes("UTF8")); - dout.writeShort(type); - dout.writeShort(clazz); - //dout.writeInt(len); - byte[] buffer = addr.getAddress(); - for (int i = 0; i < buffer.length; i++) - { - dout.writeByte(buffer[i]); - } - dout.close(); - return bout.toByteArray(); - } - catch (IOException e) - { - throw new InternalError(); - } - } - - /** - * Does a lexicographic comparison of the byte array representation - * of this record and that record. - * This is needed for tie-break tests according to - * draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2. - */ - private int lexCompare(DNSRecord.Address that) - { - byte[] thisBytes = this.toByteArray(); - byte[] thatBytes = that.toByteArray(); - for (int i = 0, n = Math.min(thisBytes.length, thatBytes.length); i < n; i++) - { - if (thisBytes[i] > thatBytes[i]) - { - return 1; - } - else - { - if (thisBytes[i] < thatBytes[i]) - { - return -1; - } - } - } - return thisBytes.length - thatBytes.length; - } - - /** - * Does the necessary actions, when this as a query. - */ - boolean handleQuery(JmDNS dns, long expirationTime) - { - DNSRecord.Address dnsAddress = dns.getLocalHost().getDNSAddressRecord(this); - if (dnsAddress != null) - { - if (dnsAddress.sameType(this) && dnsAddress.sameName(this) && (!dnsAddress.sameValue(this))) - { - logger.finer("handleQuery() Conflicting probe detected. dns state " + dns.getState() + " lex compare " + lexCompare(dnsAddress)); - // Tie-breaker test - if (dns.getState().isProbing() && lexCompare(dnsAddress) >= 0) - { - // We lost the tie-break. We have to choose a different name. - dns.getLocalHost().incrementHostName(); - dns.getCache().clear(); - for (Iterator i = dns.services.values().iterator(); i.hasNext();) - { - ServiceInfo info = (ServiceInfo) i.next(); - info.revertState(); - } - } - dns.revertState(); - return true; - } - } - return false; - } - - /** - * Does the necessary actions, when this as a response. - */ - boolean handleResponse(JmDNS dns) - { - DNSRecord.Address dnsAddress = dns.getLocalHost().getDNSAddressRecord(this); - if (dnsAddress != null) - { - if (dnsAddress.sameType(this) && dnsAddress.sameName(this) && (!dnsAddress.sameValue(this))) - { - logger.finer("handleResponse() Denial detected"); - - if (dns.getState().isProbing()) - { - dns.getLocalHost().incrementHostName(); - dns.getCache().clear(); - for (Iterator i = dns.services.values().iterator(); i.hasNext();) - { - ServiceInfo info = (ServiceInfo) i.next(); - info.revertState(); - } - } - dns.revertState(); - return true; - } - } - return false; - } - - DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException - { - return out; - } - - public String toString() - { - return toString(" address '" + (addr != null ? addr.getHostAddress() : "null") + "'"); - } - - } - - /** - * Pointer record. - */ - public static class Pointer extends DNSRecord - { - private static Logger logger = Logger.getLogger(Pointer.class.toString()); - String alias; - - Pointer(String name, int type, int clazz, int ttl, String alias) - { - super(name, type, clazz, ttl); - this.alias = alias; - } - - void write(DNSOutgoing out) throws IOException - { - out.writeName(alias); - } - - boolean sameValue(DNSRecord other) - { - return alias.equals(((Pointer) other).alias); - } - - boolean handleQuery(JmDNS dns, long expirationTime) - { - // Nothing to do (?) - // I think there is no possibility for conflicts for this record type? - return false; - } - - boolean handleResponse(JmDNS dns) - { - // Nothing to do (?) - // I think there is no possibility for conflicts for this record type? - return false; - } - - String getAlias() - { - return alias; - } - - DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException - { - return out; - } - - public String toString() - { - return toString(alias); - } - } - - public static class Text extends DNSRecord - { - private static Logger logger = Logger.getLogger(Text.class.toString()); - final public byte text[]; - - Text(String name, int type, int clazz, int ttl, byte text[]) - { - super(name, type, clazz, ttl); - this.text = text; - } - - void write(DNSOutgoing out) throws IOException - { - out.writeBytes(text, 0, text.length); - } - - boolean sameValue(DNSRecord other) - { - Text txt = (Text) other; - if (txt.text.length != text.length) - { - return false; - } - for (int i = text.length; i-- > 0;) - { - if (txt.text[i] != text[i]) - { - return false; - } - } - return true; - } - - boolean handleQuery(JmDNS dns, long expirationTime) - { - // Nothing to do (?) - // I think there is no possibility for conflicts for this record type? - return false; - } - - boolean handleResponse(JmDNS dns) - { - // Nothing to do (?) - // Shouldn't we care if we get a conflict at this level? - /* - ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); - if (info != null) { - if (! Arrays.equals(text,info.text)) { - info.revertState(); - return true; - } - }*/ - return false; - } - - DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException - { - return out; - } - - public String toString() - { - return toString((text.length > 10) ? new String(text, 0, 7) + "..." : new String(text)); - } - } - - /** - * Service record. - */ - public static class Service extends DNSRecord - { - private static Logger logger = Logger.getLogger(Service.class.toString()); - int priority; - int weight; - int port; - String server; - - Service(String name, int type, int clazz, int ttl, int priority, int weight, int port, String server) - { - super(name, type, clazz, ttl); - this.priority = priority; - this.weight = weight; - this.port = port; - this.server = server; - } - - void write(DNSOutgoing out) throws IOException - { - out.writeShort(priority); - out.writeShort(weight); - out.writeShort(port); - out.writeName(server); - } - - private byte[] toByteArray() - { - try - { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - dout.write(name.getBytes("UTF8")); - dout.writeShort(type); - dout.writeShort(clazz); - //dout.writeInt(len); - dout.writeShort(priority); - dout.writeShort(weight); - dout.writeShort(port); - dout.write(server.getBytes("UTF8")); - dout.close(); - return bout.toByteArray(); - } - catch (IOException e) - { - throw new InternalError(); - } - } - - private int lexCompare(DNSRecord.Service that) - { - byte[] thisBytes = this.toByteArray(); - byte[] thatBytes = that.toByteArray(); - for (int i = 0, n = Math.min(thisBytes.length, thatBytes.length); i < n; i++) - { - if (thisBytes[i] > thatBytes[i]) - { - return 1; - } - else - { - if (thisBytes[i] < thatBytes[i]) - { - return -1; - } - } - } - return thisBytes.length - thatBytes.length; - } - - boolean sameValue(DNSRecord other) - { - Service s = (Service) other; - return (priority == s.priority) && (weight == s.weight) && (port == s.port) && server.equals(s.server); - } - - boolean handleQuery(JmDNS dns, long expirationTime) - { - ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); - if (info != null - && (port != info.port || !server.equalsIgnoreCase(dns.getLocalHost().getName()))) - { - logger.finer("handleQuery() Conflicting probe detected"); - - // Tie breaker test - if (info.getState().isProbing() && lexCompare(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, - DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, - DNSConstants.DNS_TTL, info.priority, - info.weight, info.port, dns.getLocalHost().getName())) >= 0) - { - // We lost the tie break - String oldName = info.getQualifiedName().toLowerCase(); - info.setName(dns.incrementName(info.getName())); - dns.services.remove(oldName); - dns.services.put(info.getQualifiedName().toLowerCase(), info); - logger.finer("handleQuery() Lost tie break: new unique name chosen:" + info.getName()); - - } - info.revertState(); - return true; - - } - return false; - } - - boolean handleResponse(JmDNS dns) - { - ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); - if (info != null - && (port != info.port || !server.equalsIgnoreCase(dns.getLocalHost().getName()))) - { - logger.finer("handleResponse() Denial detected"); - - if (info.getState().isProbing()) - { - String oldName = info.getQualifiedName().toLowerCase(); - info.setName(dns.incrementName(info.getName())); - dns.services.remove(oldName); - dns.services.put(info.getQualifiedName().toLowerCase(), info); - logger.finer("handleResponse() New unique name chose:" + info.getName()); - - } - info.revertState(); - return true; - } - return false; - } - - DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr, int port, DNSOutgoing out) throws IOException - { - ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase()); - if (info != null) - { - if (this.port == info.port != server.equals(dns.getLocalHost().getName())) - { - return dns.addAnswer(in, addr, port, out, - new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, - DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, - DNSConstants.DNS_TTL, info.priority, - info.weight, info.port, dns.getLocalHost().getName())); - } - } - return out; - } - - public String toString() - { - return toString(server + ":" + port); - } - } - - public String toString(String other) - { - return toString("record", ttl + "/" + getRemainingTTL(System.currentTimeMillis()) + "," + other); - } -} - diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSState.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSState.java deleted file mode 100644 index 3e26d354fd..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/DNSState.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.ArrayList; -import java.util.logging.Logger; - -/** - * DNSState defines the possible states for services registered with JmDNS. - * - * @author Werner Randelshofer, Rick Blair - * @version 1.0 May 23, 2004 Created. - */ -public class DNSState implements Comparable -{ - private static Logger logger = Logger.getLogger(DNSState.class.toString()); - - private final String name; - - /** - * Ordinal of next state to be created. - */ - private static int nextOrdinal = 0; - /** - * Assign an ordinal to this state. - */ - private final int ordinal = nextOrdinal++; - /** - * Logical sequence of states. - * The sequence is consistent with the ordinal of a state. - * This is used for advancing through states. - */ - private final static ArrayList sequence = new ArrayList(); - - private DNSState(String name) - { - this.name = name; - sequence.add(this); - } - - public final String toString() - { - return name; - } - - public static final DNSState PROBING_1 = new DNSState("probing 1"); - public static final DNSState PROBING_2 = new DNSState("probing 2"); - public static final DNSState PROBING_3 = new DNSState("probing 3"); - public static final DNSState ANNOUNCING_1 = new DNSState("announcing 1"); - public static final DNSState ANNOUNCING_2 = new DNSState("announcing 2"); - public static final DNSState ANNOUNCED = new DNSState("announced"); - public static final DNSState CANCELED = new DNSState("canceled"); - - /** - * Returns the next advanced state. - * In general, this advances one step in the following sequence: PROBING_1, - * PROBING_2, PROBING_3, ANNOUNCING_1, ANNOUNCING_2, ANNOUNCED. - * Does not advance for ANNOUNCED and CANCELED state. - */ - public final DNSState advance() - { - return (isProbing() || isAnnouncing()) ? (DNSState) sequence.get(ordinal + 1) : this; - } - - /** - * Returns to the next reverted state. - * All states except CANCELED revert to PROBING_1. - * Status CANCELED does not revert. - */ - public final DNSState revert() - { - return (this == CANCELED) ? this : PROBING_1; - } - - /** - * Returns true, if this is a probing state. - */ - public boolean isProbing() - { - return compareTo(PROBING_1) >= 0 && compareTo(PROBING_3) <= 0; - } - - /** - * Returns true, if this is an announcing state. - */ - public boolean isAnnouncing() - { - return compareTo(ANNOUNCING_1) >= 0 && compareTo(ANNOUNCING_2) <= 0; - } - - /** - * Returns true, if this is an announced state. - */ - public boolean isAnnounced() - { - return compareTo(ANNOUNCED) == 0; - } - - /** - * Compares two states. - * The states compare as follows: - * PROBING_1 < PROBING_2 < PROBING_3 < ANNOUNCING_1 < - * ANNOUNCING_2 < RESPONDING < ANNOUNCED < CANCELED. - */ - public int compareTo(Object o) - { - return ordinal - ((DNSState) o).ordinal; - } -} \ No newline at end of file diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/HostInfo.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/HostInfo.java deleted file mode 100644 index b464888a6c..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/HostInfo.java +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.net.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * HostInfo information on the local host to be able to cope with change of addresses. - * - * @version %I%, %G% - * @author Pierre Frisch, Werner Randelshofer - */ -class HostInfo -{ - private static Logger logger = Logger.getLogger(HostInfo.class.toString()); - protected String name; - protected InetAddress address; - protected NetworkInterface interfaze; - /** - * This is used to create a unique name for the host name. - */ - private int hostNameCount; - - public HostInfo(InetAddress address, String name) - { - super(); - this.address = address; - this.name = name; - if (address != null) - { - try - { - interfaze = NetworkInterface.getByInetAddress(address); - } - catch (Exception exception) - { - // FIXME Shouldn't we take an action here? - logger.log(Level.WARNING, "LocalHostInfo() exception ", exception); - } - } - } - - public String getName() - { - return name; - } - - public InetAddress getAddress() - { - return address; - } - - public NetworkInterface getInterface() - { - return interfaze; - } - - synchronized String incrementHostName() - { - hostNameCount++; - int plocal = name.indexOf(".local."); - int punder = name.lastIndexOf("-"); - name = name.substring(0, (punder == -1 ? plocal : punder)) + "-" + hostNameCount + ".local."; - return name; - } - - boolean shouldIgnorePacket(DatagramPacket packet) - { - boolean result = false; - if (getAddress() != null) - { - InetAddress from = packet.getAddress(); - if (from != null) - { - if (from.isLinkLocalAddress() && (!getAddress().isLinkLocalAddress())) - { - // Ignore linklocal packets on regular interfaces, unless this is - // also a linklocal interface. This is to avoid duplicates. This is - // a terrible hack caused by the lack of an API to get the address - // of the interface on which the packet was received. - result = true; - } - if (from.isLoopbackAddress() && (!getAddress().isLoopbackAddress())) - { - // Ignore loopback packets on a regular interface unless this is - // also a loopback interface. - result = true; - } - } - } - return result; - } - - DNSRecord.Address getDNSAddressRecord(DNSRecord.Address address) - { - return (DNSConstants.TYPE_AAAA == address.type ? getDNS6AddressRecord() : getDNS4AddressRecord()); - } - - DNSRecord.Address getDNS4AddressRecord() - { - if ((getAddress() != null) && - ((getAddress() instanceof Inet4Address) || - ((getAddress() instanceof Inet6Address) && (((Inet6Address) getAddress()).isIPv4CompatibleAddress())))) - { - return new DNSRecord.Address(getName(), DNSConstants.TYPE_A, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, getAddress()); - } - return null; - } - - DNSRecord.Address getDNS6AddressRecord() - { - if ((getAddress() != null) && (getAddress() instanceof Inet6Address)) - { - return new DNSRecord.Address(getName(), DNSConstants.TYPE_AAAA, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, getAddress()); - } - return null; - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("local host info["); - buf.append(getName() != null ? getName() : "no name"); - buf.append(", "); - buf.append(getInterface() != null ? getInterface().getDisplayName() : "???"); - buf.append(":"); - buf.append(getAddress() != null ? getAddress().getHostAddress() : "no address"); - buf.append("]"); - return buf.toString(); - } - -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/JmDNS.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/JmDNS.java deleted file mode 100644 index 8ab1c0e32b..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/JmDNS.java +++ /dev/null @@ -1,2132 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.InetAddress; -import java.net.MulticastSocket; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -// REMIND: multiple IP addresses - -/** - * mDNS implementation in Java. - * - * @version %I%, %G% - */ -public class JmDNS { - private static Logger logger = Logger.getLogger(JmDNS.class.toString()); - /** - * The version of JmDNS. - */ - public static String VERSION = "2.0"; - - /** - * This is the multicast group, we are listening to for multicast DNS messages. - */ - private InetAddress group; - /** - * This is our multicast socket. - */ - private MulticastSocket socket; - - /** - * Used to fix live lock problem on unregester. - */ - - protected boolean closed = false; - - /** - * Holds instances of JmDNS.DNSListener. - * Must by a synchronized collection, because it is updated from - * concurrent threads. - */ - private List listeners; - /** - * Holds instances of ServiceListener's. - * Keys are Strings holding a fully qualified service type. - * Values are LinkedList's of ServiceListener's. - */ - private Map serviceListeners; - /** - * Holds instances of ServiceTypeListener's. - */ - private List typeListeners; - - - /** - * Cache for DNSEntry's. - */ - private DNSCache cache; - - /** - * This hashtable holds the services that have been registered. - * Keys are instances of String which hold an all lower-case version of the - * fully qualified service name. - * Values are instances of ServiceInfo. - */ - Map services; - - /** - * This hashtable holds the service types that have been registered or - * that have been received in an incoming datagram. - * Keys are instances of String which hold an all lower-case version of the - * fully qualified service type. - * Values hold the fully qualified service type. - */ - Map serviceTypes; - /** - * This is the shutdown hook, we registered with the java runtime. - */ - private Thread shutdown; - - /** - * Handle on the local host - */ - HostInfo localHost; - - private Thread incomingListener = null; - - /** - * Throttle count. - * This is used to count the overall number of probes sent by JmDNS. - * When the last throttle increment happened . - */ - private int throttle; - /** - * Last throttle increment. - */ - private long lastThrottleIncrement; - - /** - * The timer is used to dispatch all outgoing messages of JmDNS. - * It is also used to dispatch maintenance tasks for the DNS cache. - */ - private Timer timer; - - /** - * The source for random values. - * This is used to introduce random delays in responses. This reduces the - * potential for collisions on the network. - */ - private final static Random random = new Random(); - - /** - * This lock is used to coordinate processing of incoming and outgoing - * messages. This is needed, because the Rendezvous Conformance Test - * does not forgive race conditions. - */ - private Object ioLock = new Object(); - - /** - * If an incoming package which needs an answer is truncated, we store it - * here. We add more incoming DNSRecords to it, until the JmDNS.Responder - * timer picks it up. - * Remind: This does not work well with multiple planned answers for packages - * that came in from different clients. - */ - private DNSIncoming plannedAnswer; - - // State machine - /** - * The state of JmDNS. - *

- * For proper handling of concurrency, this variable must be - * changed only using methods advanceState(), revertState() and cancel(). - */ - private DNSState state = DNSState.PROBING_1; - - /** - * Timer task associated to the host name. - * This is used to prevent from having multiple tasks associated to the host - * name at the same time. - */ - TimerTask task; - - /** - * This hashtable is used to maintain a list of service types being collected - * by this JmDNS instance. - * The key of the hashtable is a service type name, the value is an instance - * of JmDNS.ServiceCollector. - * - * @see #list - */ - private HashMap serviceCollectors = new HashMap(); - - /** - * Create an instance of JmDNS. - */ - public JmDNS() throws IOException { - logger.finer("JmDNS instance created"); - try { - InetAddress addr = InetAddress.getLocalHost(); - init(addr.isLoopbackAddress() ? null : addr, addr.getHostName()); // [PJYF Oct 14 2004] Why do we disallow the loopback address? - } catch (IOException e) { - init(null, "computer"); - } - } - - /** - * Create an instance of JmDNS and bind it to a - * specific network interface given its IP-address. - */ - public JmDNS(InetAddress addr) throws IOException { - try { - init(addr, addr.getHostName()); - } catch (IOException e) { - init(null, "computer"); - } - } - - /** - * Initialize everything. - * - * @param address The interface to which JmDNS binds to. - * @param name The host name of the interface. - */ - private void init(InetAddress address, String name) throws IOException { - // A host name with "." is illegal. so strip off everything and append .local. - int idx = name.indexOf("."); - if (idx > 0) { - name = name.substring(0, idx); - } - name += ".local."; - // localHost to IP address binding - localHost = new HostInfo(address, name); - - cache = new DNSCache(100); - - listeners = Collections.synchronizedList(new ArrayList()); - serviceListeners = new HashMap(); - typeListeners = new ArrayList(); - - services = new Hashtable(20); - serviceTypes = new Hashtable(20); - - timer = new Timer("JmDNS.Timer"); - new RecordReaper().start(); - shutdown = new Thread(new Shutdown(), "JmDNS.Shutdown"); - Runtime.getRuntime().addShutdownHook(shutdown); - - incomingListener = new Thread(new SocketListener(), "JmDNS.SocketListener"); - - // Bind to multicast socket - openMulticastSocket(localHost); - start(services.values()); - } - - private void start(Collection serviceInfos) { - state = DNSState.PROBING_1; - incomingListener.start(); - new Prober().start(); - for (Iterator iterator = serviceInfos.iterator(); iterator.hasNext(); ) { - try { - registerService(new ServiceInfo((ServiceInfo) iterator.next())); - } catch (Exception exception) { - logger.log(Level.WARNING, "start() Registration exception ", exception); - } - } - } - - private void openMulticastSocket(HostInfo hostInfo) throws IOException { - if (group == null) { - group = InetAddress.getByName(DNSConstants.MDNS_GROUP); - } - if (socket != null) { - this.closeMulticastSocket(); - } - socket = new MulticastSocket(DNSConstants.MDNS_PORT); - if ((hostInfo != null) && (localHost.getInterface() != null)) { - socket.setNetworkInterface(hostInfo.getInterface()); - } - socket.setTimeToLive(255); - socket.joinGroup(group); - } - - private void closeMulticastSocket() { - logger.finer("closeMulticastSocket()"); - if (socket != null) { - // close socket - try { - socket.leaveGroup(group); - socket.close(); - if (incomingListener != null) { - incomingListener.join(); - } - } catch (Exception exception) { - logger.log(Level.WARNING, "closeMulticastSocket() Close socket exception ", exception); - } - socket = null; - } - } - - // State machine - - /** - * Sets the state and notifies all objects that wait on JmDNS. - */ - synchronized void advanceState() { - state = state.advance(); - notifyAll(); - } - - /** - * Sets the state and notifies all objects that wait on JmDNS. - */ - synchronized void revertState() { - state = state.revert(); - notifyAll(); - } - - /** - * Sets the state and notifies all objects that wait on JmDNS. - */ - synchronized void cancel() { - state = DNSState.CANCELED; - notifyAll(); - } - - /** - * Returns the current state of this info. - */ - DNSState getState() { - return state; - } - - - /** - * Return the DNSCache associated with the cache variable - */ - DNSCache getCache() { - return cache; - } - - /** - * Return the HostName associated with this JmDNS instance. - * Note: May not be the same as what started. The host name is subject to - * negotiation. - */ - public String getHostName() { - return localHost.getName(); - } - - public HostInfo getLocalHost() { - return localHost; - } - - /** - * Return the address of the interface to which this instance of JmDNS is - * bound. - */ - public InetAddress getInterface() throws IOException { - return socket.getInterface(); - } - - /** - * Get service information. If the information is not cached, the method - * will block until updated information is received. - *

- * Usage note: Do not call this method from the AWT event dispatcher thread. - * You will make the user interface unresponsive. - * - * @param type fully qualified service type, such as _http._tcp.local. . - * @param name unqualified service name, such as foobar . - * @return null if the service information cannot be obtained - */ - public ServiceInfo getServiceInfo(String type, String name) { - return getServiceInfo(type, name, 3 * 1000); - } - - /** - * Get service information. If the information is not cached, the method - * will block for the given timeout until updated information is received. - *

- * Usage note: If you call this method from the AWT event dispatcher thread, - * use a small timeout, or you will make the user interface unresponsive. - * - * @param type full qualified service type, such as _http._tcp.local. . - * @param name unqualified service name, such as foobar . - * @param timeout timeout in milliseconds - * @return null if the service information cannot be obtained - */ - public ServiceInfo getServiceInfo(String type, String name, int timeout) { - ServiceInfo info = new ServiceInfo(type, name); - new ServiceInfoResolver(info).start(); - - try { - long end = System.currentTimeMillis() + timeout; - long delay; - synchronized (info) { - while (!info.hasData() && (delay = end - System.currentTimeMillis()) > 0) { - info.wait(delay); - } - } - } catch (InterruptedException e) { - // empty - } - - return (info.hasData()) ? info : null; - } - - /** - * Request service information. The information about the service is - * requested and the ServiceListener.resolveService method is called as soon - * as it is available. - *

- * Usage note: Do not call this method from the AWT event dispatcher thread. - * You will make the user interface unresponsive. - * - * @param type full qualified service type, such as _http._tcp.local. . - * @param name unqualified service name, such as foobar . - */ - public void requestServiceInfo(String type, String name) { - requestServiceInfo(type, name, 3 * 1000); - } - - /** - * Request service information. The information about the service is requested - * and the ServiceListener.resolveService method is called as soon as it is available. - * - * @param type full qualified service type, such as _http._tcp.local. . - * @param name unqualified service name, such as foobar . - * @param timeout timeout in milliseconds - */ - public void requestServiceInfo(String type, String name, int timeout) { - registerServiceType(type); - ServiceInfo info = new ServiceInfo(type, name); - new ServiceInfoResolver(info).start(); - - try { - long end = System.currentTimeMillis() + timeout; - long delay; - synchronized (info) { - while (!info.hasData() && (delay = end - System.currentTimeMillis()) > 0) { - info.wait(delay); - } - } - } catch (InterruptedException e) { - // empty - } - } - - void handleServiceResolved(ServiceInfo info) { - List list = (List) serviceListeners.get(info.type.toLowerCase()); - if (list != null) { - ServiceEvent event = new ServiceEvent(this, info.type, info.getName(), info); - // Iterate on a copy in case listeners will modify it - final ArrayList listCopy = new ArrayList(list); - for (Iterator iterator = listCopy.iterator(); iterator.hasNext(); ) { - ((ServiceListener) iterator.next()).serviceResolved(event); - } - } - } - - /** - * Listen for service types. - * - * @param listener listener for service types - */ - public void addServiceTypeListener(ServiceTypeListener listener) throws IOException { - synchronized (this) { - typeListeners.remove(listener); - typeListeners.add(listener); - } - - // report cached service types - for (Iterator iterator = serviceTypes.values().iterator(); iterator.hasNext(); ) { - listener.serviceTypeAdded(new ServiceEvent(this, (String) iterator.next(), null, null)); - } - - new TypeResolver().start(); - } - - /** - * Remove listener for service types. - * - * @param listener listener for service types - */ - public void removeServiceTypeListener(ServiceTypeListener listener) { - synchronized (this) { - typeListeners.remove(listener); - } - } - - /** - * Listen for services of a given type. The type has to be a fully qualified - * type name such as _http._tcp.local.. - * - * @param type full qualified service type, such as _http._tcp.local.. - * @param listener listener for service updates - */ - public void addServiceListener(String type, ServiceListener listener) { - String lotype = type.toLowerCase(); - removeServiceListener(lotype, listener); - List list = null; - synchronized (this) { - list = (List) serviceListeners.get(lotype); - if (list == null) { - list = Collections.synchronizedList(new LinkedList()); - serviceListeners.put(lotype, list); - } - list.add(listener); - } - - // report cached service types - for (Iterator i = cache.iterator(); i.hasNext(); ) { - for (DNSCache.CacheNode n = (DNSCache.CacheNode) i.next(); n != null; n = n.next()) { - DNSRecord rec = (DNSRecord) n.getValue(); - if (rec.type == DNSConstants.TYPE_SRV) { - if (rec.name.endsWith(type)) { - listener.serviceAdded(new ServiceEvent(this, type, toUnqualifiedName(type, rec.name), null)); - } - } - } - } - new ServiceResolver(type).start(); - } - - /** - * Remove listener for services of a given type. - * - * @param listener listener for service updates - */ - public void removeServiceListener(String type, ServiceListener listener) { - type = type.toLowerCase(); - List list = (List) serviceListeners.get(type); - if (list != null) { - synchronized (this) { - list.remove(listener); - if (list.size() == 0) { - serviceListeners.remove(type); - } - } - } - } - - /** - * Register a service. The service is registered for access by other jmdns clients. - * The name of the service may be changed to make it unique. - */ - public void registerService(ServiceInfo info) throws IOException { - registerServiceType(info.type); - - // bind the service to this address - info.server = localHost.getName(); - info.addr = localHost.getAddress(); - - synchronized (this) { - makeServiceNameUnique(info); - services.put(info.getQualifiedName().toLowerCase(), info); - } - - new /*Service*/Prober().start(); - try { - synchronized (info) { - while (info.getState().compareTo(DNSState.ANNOUNCED) < 0) { - info.wait(); - } - } - } catch (InterruptedException e) { - //empty - } - logger.fine("registerService() JmDNS registered service as " + info); - } - - /** - * Unregister a service. The service should have been registered. - */ - public void unregisterService(ServiceInfo info) { - synchronized (this) { - services.remove(info.getQualifiedName().toLowerCase()); - } - info.cancel(); - - // Note: We use this lock object to synchronize on it. - // Synchronizing on another object (e.g. the ServiceInfo) does - // not make sense, because the sole purpose of the lock is to - // wait until the canceler has finished. If we synchronized on - // the ServiceInfo or on the Canceler, we would block all - // accesses to synchronized methods on that object. This is not - // what we want! - Object lock = new Object(); - try { - new Canceler(info, lock).start(); - - // Remind: We get a deadlock here, if the Canceler does not run! - try { - synchronized (lock) { - //don'r wait forever - lock.wait(5000); - } - } catch (InterruptedException e) { - // empty - } - } catch (Throwable e) { - logger.info("Failed to properly unregister "); - } - } - - /** - * Unregister all services. - */ - public void unregisterAllServices() { - logger.finer("unregisterAllServices()"); - if (services.size() == 0) { - return; - } - - Collection list; - synchronized (this) { - list = new LinkedList(services.values()); - services.clear(); - } - for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { - ((ServiceInfo) iterator.next()).cancel(); - } - - try { - Object lock = new Object(); - new Canceler(list, lock).start(); - // Remind: We get a livelock here, if the Canceler does not run! - try { - synchronized (lock) { - if (!closed) { - lock.wait(5000); - } - } - } catch (InterruptedException e) { - // empty - } - } catch (Throwable e) { - logger.info("Failed to unregister"); - } - - - } - - /** - * Register a service type. If this service type was not already known, - * all service listeners will be notified of the new service type. Service types - * are automatically registered as they are discovered. - */ - public void registerServiceType(String type) { - String name = type.toLowerCase(); - if (serviceTypes.get(name) == null) { - if ((type.indexOf("._mdns._udp.") < 0) && !type.endsWith(".in-addr.arpa.")) { - Collection list; - synchronized (this) { - serviceTypes.put(name, type); - list = new LinkedList(typeListeners); - } - for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { - ((ServiceTypeListener) iterator.next()).serviceTypeAdded(new ServiceEvent(this, type, null, null)); - } - } - } - } - - /** - * Generate a possibly unique name for a host using the information we - * have in the cache. - * - * @return returns true, if the name of the host had to be changed. - */ - private boolean makeHostNameUnique(DNSRecord.Address host) { - String originalName = host.getName(); - long now = System.currentTimeMillis(); - - boolean collision; - do { - collision = false; - - // Check for collision in cache - for (DNSCache.CacheNode j = cache.find(host.getName().toLowerCase()); j != null; j = j.next()) { - DNSRecord a = (DNSRecord) j.getValue(); - if (false) { - host.name = incrementName(host.getName()); - collision = true; - break; - } - } - } - while (collision); - - if (originalName.equals(host.getName())) { - return false; - } else { - return true; - } - } - - /** - * Generate a possibly unique name for a service using the information we - * have in the cache. - * - * @return returns true, if the name of the service info had to be changed. - */ - private boolean makeServiceNameUnique(ServiceInfo info) { - String originalQualifiedName = info.getQualifiedName(); - long now = System.currentTimeMillis(); - - boolean collision; - do { - collision = false; - - // Check for collision in cache - for (DNSCache.CacheNode j = cache.find(info.getQualifiedName().toLowerCase()); j != null; j = j.next()) { - DNSRecord a = (DNSRecord) j.getValue(); - if ((a.type == DNSConstants.TYPE_SRV) && !a.isExpired(now)) { - DNSRecord.Service s = (DNSRecord.Service) a; - if (s.port != info.port || !s.server.equals(localHost.getName())) { - logger.finer("makeServiceNameUnique() JmDNS.makeServiceNameUnique srv collision:" + a + " s.server=" + s.server + " " + localHost.getName() + " equals:" + (s.server.equals(localHost.getName()))); - info.setName(incrementName(info.getName())); - collision = true; - break; - } - } - } - - // Check for collision with other service infos published by JmDNS - Object selfService = services.get(info.getQualifiedName().toLowerCase()); - if (selfService != null && selfService != info) { - info.setName(incrementName(info.getName())); - collision = true; - } - } - while (collision); - - return !(originalQualifiedName.equals(info.getQualifiedName())); - } - - String incrementName(String name) { - try { - int l = name.lastIndexOf('('); - int r = name.lastIndexOf(')'); - if ((l >= 0) && (l < r)) { - name = name.substring(0, l) + "(" + (Integer.parseInt(name.substring(l + 1, r)) + 1) + ")"; - } else { - name += " (2)"; - } - } catch (NumberFormatException e) { - name += " (2)"; - } - return name; - } - - /** - * Add a listener for a question. The listener will receive updates - * of answers to the question as they arrive, or from the cache if they - * are already available. - */ - public void addListener(DNSListener listener, DNSQuestion question) { - long now = System.currentTimeMillis(); - - // add the new listener - synchronized (this) { - listeners.add(listener); - } - - // report existing matched records - if (question != null) { - for (DNSCache.CacheNode i = cache.find(question.name); i != null; i = i.next()) { - DNSRecord c = (DNSRecord) i.getValue(); - if (question.answeredBy(c) && !c.isExpired(now)) { - listener.updateRecord(this, now, c); - } - } - } - } - - /** - * Remove a listener from all outstanding questions. The listener will no longer - * receive any updates. - */ - public void removeListener(DNSListener listener) { - synchronized (this) { - listeners.remove(listener); - } - } - - - // Remind: Method updateRecord should receive a better name. - - /** - * Notify all listeners that a record was updated. - */ - void updateRecord(long now, DNSRecord rec) { - // We do not want to block the entire DNS while we are updating the record for each listener (service info) - List listenerList = null; - synchronized (this) { - listenerList = new ArrayList(listeners); - } - for (Iterator iterator = listenerList.iterator(); iterator.hasNext(); ) { - DNSListener listener = (DNSListener) iterator.next(); - listener.updateRecord(this, now, rec); - } - if (rec.type == DNSConstants.TYPE_PTR || rec.type == DNSConstants.TYPE_SRV) { - List serviceListenerList = null; - synchronized (this) { - serviceListenerList = (List) serviceListeners.get(rec.name.toLowerCase()); - // Iterate on a copy in case listeners will modify it - if (serviceListenerList != null) { - serviceListenerList = new ArrayList(serviceListenerList); - } - } - if (serviceListenerList != null) { - boolean expired = rec.isExpired(now); - String type = rec.getName(); - String name = ((DNSRecord.Pointer) rec).getAlias(); - // DNSRecord old = (DNSRecord)services.get(name.toLowerCase()); - if (!expired) { - // new record - ServiceEvent event = new ServiceEvent(this, type, toUnqualifiedName(type, name), null); - for (Iterator iterator = serviceListenerList.iterator(); iterator.hasNext(); ) { - ((ServiceListener) iterator.next()).serviceAdded(event); - } - } else { - // expire record - ServiceEvent event = new ServiceEvent(this, type, toUnqualifiedName(type, name), null); - for (Iterator iterator = serviceListenerList.iterator(); iterator.hasNext(); ) { - ((ServiceListener) iterator.next()).serviceRemoved(event); - } - } - } - } - } - - /** - * Handle an incoming response. Cache answers, and pass them on to - * the appropriate questions. - */ - private void handleResponse(DNSIncoming msg) throws IOException { - long now = System.currentTimeMillis(); - - boolean hostConflictDetected = false; - boolean serviceConflictDetected = false; - - for (Iterator i = msg.answers.iterator(); i.hasNext(); ) { - boolean isInformative = false; - DNSRecord rec = (DNSRecord) i.next(); - boolean expired = rec.isExpired(now); - - // update the cache - DNSRecord c = (DNSRecord) cache.get(rec); - if (c != null) { - if (expired) { - isInformative = true; - cache.remove(c); - } else { - c.resetTTL(rec); - rec = c; - } - } else { - if (!expired) { - isInformative = true; - cache.add(rec); - } - } - switch (rec.type) { - case DNSConstants.TYPE_PTR: - // handle _mdns._udp records - if (rec.getName().indexOf("._mdns._udp.") >= 0) { - if (!expired && rec.name.startsWith("_services._mdns._udp.")) { - isInformative = true; - registerServiceType(((DNSRecord.Pointer) rec).alias); - } - continue; - } - registerServiceType(rec.name); - break; - } - - if ((rec.getType() == DNSConstants.TYPE_A) || (rec.getType() == DNSConstants.TYPE_AAAA)) { - hostConflictDetected |= rec.handleResponse(this); - } else { - serviceConflictDetected |= rec.handleResponse(this); - } - - // notify the listeners - if (isInformative) { - updateRecord(now, rec); - } - } - - if (hostConflictDetected || serviceConflictDetected) { - new Prober().start(); - } - } - - /** - * Handle an incoming query. See if we can answer any part of it - * given our service infos. - */ - private void handleQuery(DNSIncoming in, InetAddress addr, int port) throws IOException { - // Track known answers - boolean hostConflictDetected = false; - boolean serviceConflictDetected = false; - long expirationTime = System.currentTimeMillis() + DNSConstants.KNOWN_ANSWER_TTL; - for (Iterator i = in.answers.iterator(); i.hasNext(); ) { - DNSRecord answer = (DNSRecord) i.next(); - if ((answer.getType() == DNSConstants.TYPE_A) || (answer.getType() == DNSConstants.TYPE_AAAA)) { - hostConflictDetected |= answer.handleQuery(this, expirationTime); - } else { - serviceConflictDetected |= answer.handleQuery(this, expirationTime); - } - } - - if (plannedAnswer != null) { - plannedAnswer.append(in); - } else { - if (in.isTruncated()) { - plannedAnswer = in; - } - - new Responder(in, addr, port).start(); - } - - if (hostConflictDetected || serviceConflictDetected) { - new Prober().start(); - } - } - - /** - * Add an answer to a question. Deal with the case when the - * outgoing packet overflows - */ - DNSOutgoing addAnswer(DNSIncoming in, InetAddress addr, int port, DNSOutgoing out, DNSRecord rec) throws IOException { - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - } - try { - out.addAnswer(in, rec); - } catch (IOException e) { - out.flags |= DNSConstants.FLAGS_TC; - out.id = in.id; - out.finish(); - send(out); - - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - out.addAnswer(in, rec); - } - return out; - } - - - /** - * Send an outgoing multicast DNS message. - */ - private void send(DNSOutgoing out) throws IOException { - out.finish(); - if (!out.isEmpty()) { - DatagramPacket packet = new DatagramPacket(out.data, out.off, group, DNSConstants.MDNS_PORT); - - try { - DNSIncoming msg = new DNSIncoming(packet); - logger.finest("send() JmDNS out:" + msg.print(true)); - } catch (IOException e) { - logger.throwing(getClass().toString(), "send(DNSOutgoing) - JmDNS can not parse what it sends!!!", e); - } - socket.send(packet); - } - } - - /** - * Listen for multicast packets. - */ - class SocketListener implements Runnable { - public void run() { - try { - byte buf[] = new byte[DNSConstants.MAX_MSG_ABSOLUTE]; - DatagramPacket packet = new DatagramPacket(buf, buf.length); - while (state != DNSState.CANCELED) { - packet.setLength(buf.length); - socket.receive(packet); - if (state == DNSState.CANCELED) { - break; - } - try { - if (localHost.shouldIgnorePacket(packet)) { - continue; - } - - DNSIncoming msg = new DNSIncoming(packet); - logger.finest("SocketListener.run() JmDNS in:" + msg.print(true)); - - synchronized (ioLock) { - if (msg.isQuery()) { - if (packet.getPort() != DNSConstants.MDNS_PORT) { - handleQuery(msg, packet.getAddress(), packet.getPort()); - } - handleQuery(msg, group, DNSConstants.MDNS_PORT); - } else { - handleResponse(msg); - } - } - } catch (IOException e) { - logger.log(Level.WARNING, "run() exception ", e); - } - } - } catch (IOException e) { - if (state != DNSState.CANCELED) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - } - } - } - - - /** - * Periodicaly removes expired entries from the cache. - */ - private class RecordReaper extends TimerTask { - public void start() { - timer.schedule(this, DNSConstants.RECORD_REAPER_INTERVAL, DNSConstants.RECORD_REAPER_INTERVAL); - } - - public void run() { - synchronized (JmDNS.this) { - if (state == DNSState.CANCELED) { - return; - } - logger.finest("run() JmDNS reaping cache"); - - // Remove expired answers from the cache - // ------------------------------------- - // To prevent race conditions, we defensively copy all cache - // entries into a list. - List list = new ArrayList(); - synchronized (cache) { - for (Iterator i = cache.iterator(); i.hasNext(); ) { - for (DNSCache.CacheNode n = (DNSCache.CacheNode) i.next(); n != null; n = n.next()) { - list.add(n.getValue()); - } - } - } - // Now, we remove them. - long now = System.currentTimeMillis(); - for (Iterator i = list.iterator(); i.hasNext(); ) { - DNSRecord c = (DNSRecord) i.next(); - if (c.isExpired(now)) { - updateRecord(now, c); - cache.remove(c); - } - } - } - } - } - - - /** - * The Prober sends three consecutive probes for all service infos - * that needs probing as well as for the host name. - * The state of each service info of the host name is advanced, when a probe has - * been sent for it. - * When the prober has run three times, it launches an Announcer. - *

- * If a conflict during probes occurs, the affected service infos (and affected - * host name) are taken away from the prober. This eventually causes the prober - * tho cancel itself. - */ - private class Prober extends TimerTask { - /** - * The state of the prober. - */ - DNSState taskState = DNSState.PROBING_1; - - public Prober() { - // Associate the host name to this, if it needs probing - if (state == DNSState.PROBING_1) { - task = this; - } - // Associate services to this, if they need probing - synchronized (JmDNS.this) { - for (Iterator iterator = services.values().iterator(); iterator.hasNext(); ) { - ServiceInfo info = (ServiceInfo) iterator.next(); - if (info.getState() == DNSState.PROBING_1) { - info.task = this; - } - } - } - } - - - public void start() { - long now = System.currentTimeMillis(); - if (now - lastThrottleIncrement < DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL) { - throttle++; - } else { - throttle = 1; - } - lastThrottleIncrement = now; - - if (state == DNSState.ANNOUNCED && throttle < DNSConstants.PROBE_THROTTLE_COUNT) { - timer.schedule(this, random.nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL), DNSConstants.PROBE_WAIT_INTERVAL); - } else { - timer.schedule(this, DNSConstants.PROBE_CONFLICT_INTERVAL, DNSConstants.PROBE_CONFLICT_INTERVAL); - } - } - - public boolean cancel() { - // Remove association from host name to this - if (task == this) { - task = null; - } - - // Remove associations from services to this - synchronized (JmDNS.this) { - for (Iterator i = services.values().iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - if (info.task == this) { - info.task = null; - } - } - } - - return super.cancel(); - } - - public void run() { - synchronized (ioLock) { - DNSOutgoing out = null; - try { - // send probes for JmDNS itself - if (state == taskState && task == this) { - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY); - } - out.addQuestion(new DNSQuestion(localHost.getName(), DNSConstants.TYPE_ANY, DNSConstants.CLASS_IN)); - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - out.addAuthorativeAnswer(answer); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - out.addAuthorativeAnswer(answer); - } - advanceState(); - } - // send probes for services - // Defensively copy the services into a local list, - // to prevent race conditions with methods registerService - // and unregisterService. - List list; - synchronized (JmDNS.this) { - list = new LinkedList(services.values()); - } - for (Iterator i = list.iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - - synchronized (info) { - if (info.getState() == taskState && info.task == this) { - info.advanceState(); - logger.fine("run() JmDNS probing " + info.getQualifiedName() + " state " + info.getState()); - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY); - out.addQuestion(new DNSQuestion(info.getQualifiedName(), DNSConstants.TYPE_ANY, DNSConstants.CLASS_IN)); - } - out.addAuthorativeAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName())); - } - } - } - if (out != null) { - logger.finer("run() JmDNS probing #" + taskState); - send(out); - } else { - // If we have nothing to send, another timer taskState ahead - // of us has done the job for us. We can cancel. - cancel(); - return; - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - - taskState = taskState.advance(); - if (!taskState.isProbing()) { - cancel(); - - new Announcer().start(); - } - } - } - - } - - /** - * The Announcer sends an accumulated query of all announces, and advances - * the state of all serviceInfos, for which it has sent an announce. - * The Announcer also sends announcements and advances the state of JmDNS itself. - *

- * When the announcer has run two times, it finishes. - */ - private class Announcer extends TimerTask { - /** - * The state of the announcer. - */ - DNSState taskState = DNSState.ANNOUNCING_1; - - public Announcer() { - // Associate host to this, if it needs announcing - if (state == DNSState.ANNOUNCING_1) { - task = this; - } - // Associate services to this, if they need announcing - synchronized (JmDNS.this) { - for (Iterator s = services.values().iterator(); s.hasNext(); ) { - ServiceInfo info = (ServiceInfo) s.next(); - if (info.getState() == DNSState.ANNOUNCING_1) { - info.task = this; - } - } - } - } - - public void start() { - timer.schedule(this, DNSConstants.ANNOUNCE_WAIT_INTERVAL, DNSConstants.ANNOUNCE_WAIT_INTERVAL); - } - - public boolean cancel() { - // Remove association from host to this - if (task == this) { - task = null; - } - - // Remove associations from services to this - synchronized (JmDNS.this) { - for (Iterator i = services.values().iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - if (info.task == this) { - info.task = null; - } - } - } - - return super.cancel(); - } - - public void run() { - DNSOutgoing out = null; - try { - // send probes for JmDNS itself - if (state == taskState) { - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - } - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - advanceState(); - } - // send announces for services - // Defensively copy the services into a local list, - // to prevent race conditions with methods registerService - // and unregisterService. - List list; - synchronized (JmDNS.this) { - list = new ArrayList(services.values()); - } - for (Iterator i = list.iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - synchronized (info) { - if (info.getState() == taskState && info.task == this) { - info.advanceState(); - logger.finer("run() JmDNS announcing " + info.getQualifiedName() + " state " + info.getState()); - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - } - out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName()), 0); - out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0); - out.addAnswer(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.text), 0); - } - } - } - if (out != null) { - logger.finer("run() JmDNS announcing #" + taskState); - send(out); - } else { - // If we have nothing to send, another timer taskState ahead - // of us has done the job for us. We can cancel. - cancel(); - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - - taskState = taskState.advance(); - if (!taskState.isAnnouncing()) { - cancel(); - - new Renewer().start(); - } - } - } - - /** - * The Renewer is there to send renewal announcment when the record expire for ours infos. - */ - private class Renewer extends TimerTask { - /** - * The state of the announcer. - */ - DNSState taskState = DNSState.ANNOUNCED; - - public Renewer() { - // Associate host to this, if it needs renewal - if (state == DNSState.ANNOUNCED) { - task = this; - } - // Associate services to this, if they need renewal - synchronized (JmDNS.this) { - for (Iterator s = services.values().iterator(); s.hasNext(); ) { - ServiceInfo info = (ServiceInfo) s.next(); - if (info.getState() == DNSState.ANNOUNCED) { - info.task = this; - } - } - } - } - - public void start() { - timer.schedule(this, DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL, DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL); - } - - public boolean cancel() { - // Remove association from host to this - if (task == this) { - task = null; - } - - // Remove associations from services to this - synchronized (JmDNS.this) { - for (Iterator i = services.values().iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - if (info.task == this) { - info.task = null; - } - } - } - - return super.cancel(); - } - - public void run() { - DNSOutgoing out = null; - try { - // send probes for JmDNS itself - if (state == taskState) { - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - } - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - advanceState(); - } - // send announces for services - // Defensively copy the services into a local list, - // to prevent race conditions with methods registerService - // and unregisterService. - List list; - synchronized (JmDNS.this) { - list = new ArrayList(services.values()); - } - for (Iterator i = list.iterator(); i.hasNext(); ) { - ServiceInfo info = (ServiceInfo) i.next(); - synchronized (info) { - if (info.getState() == taskState && info.task == this) { - info.advanceState(); - logger.finer("run() JmDNS announced " + info.getQualifiedName() + " state " + info.getState()); - if (out == null) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - } - out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName()), 0); - out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0); - out.addAnswer(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.text), 0); - } - } - } - if (out != null) { - logger.finer("run() JmDNS announced"); - send(out); - } else { - // If we have nothing to send, another timer taskState ahead - // of us has done the job for us. We can cancel. - cancel(); - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - - taskState = taskState.advance(); - if (!taskState.isAnnounced()) { - cancel(); - - } - } - } - - /** - * The Responder sends a single answer for the specified service infos - * and for the host name. - */ - private class Responder extends TimerTask { - private DNSIncoming in; - private InetAddress addr; - private int port; - - public Responder(DNSIncoming in, InetAddress addr, int port) { - this.in = in; - this.addr = addr; - this.port = port; - } - - public void start() { - // According to draft-cheshire-dnsext-multicastdns.txt - // chapter "8 Responding": - // We respond immediately if we know for sure, that we are - // the only one who can respond to the query. - // In all other cases, we respond within 20-120 ms. - // - // According to draft-cheshire-dnsext-multicastdns.txt - // chapter "7.2 Multi-Packet Known Answer Suppression": - // We respond after 20-120 ms if the query is truncated. - - boolean iAmTheOnlyOne = true; - for (Iterator i = in.questions.iterator(); i.hasNext(); ) { - DNSEntry entry = (DNSEntry) i.next(); - if (entry instanceof DNSQuestion) { - DNSQuestion q = (DNSQuestion) entry; - logger.finest("start() question=" + q); - iAmTheOnlyOne &= (q.type == DNSConstants.TYPE_SRV - || q.type == DNSConstants.TYPE_TXT - || q.type == DNSConstants.TYPE_A - || q.type == DNSConstants.TYPE_AAAA - || localHost.getName().equalsIgnoreCase(q.name) - || services.containsKey(q.name.toLowerCase())); - if (!iAmTheOnlyOne) { - break; - } - } - } - int delay = (iAmTheOnlyOne && !in.isTruncated()) ? 0 : DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + random.nextInt(DNSConstants.RESPONSE_MAX_WAIT_INTERVAL - DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) - in.elapseSinceArrival(); - if (delay < 0) { - delay = 0; - } - logger.finest("start() Responder chosen delay=" + delay); - timer.schedule(this, delay); - } - - public void run() { - synchronized (ioLock) { - if (plannedAnswer == in) { - plannedAnswer = null; - } - - // We use these sets to prevent duplicate records - // FIXME - This should be moved into DNSOutgoing - HashSet questions = new HashSet(); - HashSet answers = new HashSet(); - - - if (state == DNSState.ANNOUNCED) { - try { - long now = System.currentTimeMillis(); - long expirationTime = now + 1; //=now+DNSConstants.KNOWN_ANSWER_TTL; - boolean isUnicast = (port != DNSConstants.MDNS_PORT); - - - // Answer questions - for (Iterator iterator = in.questions.iterator(); iterator.hasNext(); ) { - DNSEntry entry = (DNSEntry) iterator.next(); - if (entry instanceof DNSQuestion) { - DNSQuestion q = (DNSQuestion) entry; - - // for unicast responses the question must be included - if (isUnicast) { - //out.addQuestion(q); - questions.add(q); - } - - int type = q.type; - if (type == DNSConstants.TYPE_ANY || type == DNSConstants.TYPE_SRV) { // I ama not sure of why there is a special case here [PJYF Oct 15 2004] - if (localHost.getName().equalsIgnoreCase(q.getName())) { - // type = DNSConstants.TYPE_A; - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - answers.add(answer); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - answers.add(answer); - } - type = DNSConstants.TYPE_IGNORE; - } else { - if (serviceTypes.containsKey(q.getName().toLowerCase())) { - type = DNSConstants.TYPE_PTR; - } - } - } - - switch (type) { - case DNSConstants.TYPE_A: { - // Answer a query for a domain name - //out = addAnswer( in, addr, port, out, host ); - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - answers.add(answer); - } - break; - } - case DNSConstants.TYPE_AAAA: { - // Answer a query for a domain name - DNSRecord answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - answers.add(answer); - } - break; - } - case DNSConstants.TYPE_PTR: { - // Answer a query for services of a given type - - // find matching services - for (Iterator serviceIterator = services.values().iterator(); serviceIterator.hasNext(); ) { - ServiceInfo info = (ServiceInfo) serviceIterator.next(); - if (info.getState() == DNSState.ANNOUNCED) { - if (q.name.equalsIgnoreCase(info.type)) { - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - answers.add(answer); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - answers.add(answer); - } - answers.add(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName())); - answers.add(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName())); - answers.add(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text)); - } - } - } - if (q.name.equalsIgnoreCase("_services._mdns._udp.local.")) { - for (Iterator serviceTypeIterator = serviceTypes.values().iterator(); serviceTypeIterator.hasNext(); ) { - answers.add(new DNSRecord.Pointer("_services._mdns._udp.local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, (String) serviceTypeIterator.next())); - } - } - break; - } - case DNSConstants.TYPE_SRV: - case DNSConstants.TYPE_ANY: - case DNSConstants.TYPE_TXT: { - ServiceInfo info = (ServiceInfo) services.get(q.name.toLowerCase()); - if (info != null && info.getState() == DNSState.ANNOUNCED) { - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - answers.add(answer); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - answers.add(answer); - } - answers.add(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName())); - answers.add(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName())); - answers.add(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text)); - } - break; - } - default: { - //System.out.println("JmDNSResponder.unhandled query:"+q); - break; - } - } - } - } - - - // remove known answers, if the ttl is at least half of - // the correct value. (See Draft Cheshire chapter 7.1.). - for (Iterator i = in.answers.iterator(); i.hasNext(); ) { - DNSRecord knownAnswer = (DNSRecord) i.next(); - if (knownAnswer.ttl > DNSConstants.DNS_TTL / 2 && answers.remove(knownAnswer)) { - logger.log(Level.FINER, "JmDNS Responder Known Answer Removed"); - } - } - - - // responde if we have answers - if (answers.size() != 0) { - logger.finer("run() JmDNS responding"); - DNSOutgoing out = null; - if (isUnicast) { - out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false); - } - - for (Iterator i = questions.iterator(); i.hasNext(); ) { - out.addQuestion((DNSQuestion) i.next()); - } - for (Iterator i = answers.iterator(); i.hasNext(); ) { - out = addAnswer(in, addr, port, out, (DNSRecord) i.next()); - } - send(out); - } - cancel(); - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - close(); - } - } - } - } - } - - /** - * Helper class to resolve service types. - *

- * The TypeResolver queries three times consecutively for service types, and then - * removes itself from the timer. - *

- * The TypeResolver will run only if JmDNS is in state ANNOUNCED. - */ - private class TypeResolver extends TimerTask { - public void start() { - timer.schedule(this, DNSConstants.QUERY_WAIT_INTERVAL, DNSConstants.QUERY_WAIT_INTERVAL); - } - - /** - * Counts the number of queries that were sent. - */ - int count = 0; - - public void run() { - try { - if (state == DNSState.ANNOUNCED) { - if (++count < 3) { - logger.finer("run() JmDNS querying type"); - DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY); - out.addQuestion(new DNSQuestion("_services._mdns._udp.local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN)); - for (Iterator iterator = serviceTypes.values().iterator(); iterator.hasNext(); ) { - out.addAnswer(new DNSRecord.Pointer("_services._mdns._udp.local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, (String) iterator.next()), 0); - } - send(out); - } else { - // After three queries, we can quit. - cancel(); - } - ; - } else { - if (state == DNSState.CANCELED) { - cancel(); - } - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - } - } - - /** - * The ServiceResolver queries three times consecutively for services of - * a given type, and then removes itself from the timer. - *

- * The ServiceResolver will run only if JmDNS is in state ANNOUNCED. - * REMIND: Prevent having multiple service resolvers for the same type in the - * timer queue. - */ - private class ServiceResolver extends TimerTask { - /** - * Counts the number of queries being sent. - */ - int count = 0; - private String type; - - public ServiceResolver(String type) { - this.type = type; - } - - public void start() { - timer.schedule(this, DNSConstants.QUERY_WAIT_INTERVAL, DNSConstants.QUERY_WAIT_INTERVAL); - } - - public void run() { - try { - if (state == DNSState.ANNOUNCED) { - if (count++ < 3) { - logger.finer("run() JmDNS querying service"); - long now = System.currentTimeMillis(); - DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY); - out.addQuestion(new DNSQuestion(type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN)); - for (Iterator s = services.values().iterator(); s.hasNext(); ) { - final ServiceInfo info = (ServiceInfo) s.next(); - try { - out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName()), now); - } catch (IOException ee) { - break; - } - } - send(out); - } else { - // After three queries, we can quit. - cancel(); - } - ; - } else { - if (state == DNSState.CANCELED) { - cancel(); - } - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - } - } - - /** - * The ServiceInfoResolver queries up to three times consecutively for - * a service info, and then removes itself from the timer. - *

- * The ServiceInfoResolver will run only if JmDNS is in state ANNOUNCED. - * REMIND: Prevent having multiple service resolvers for the same info in the - * timer queue. - */ - private class ServiceInfoResolver extends TimerTask { - /** - * Counts the number of queries being sent. - */ - int count = 0; - private ServiceInfo info; - - public ServiceInfoResolver(ServiceInfo info) { - this.info = info; - info.dns = JmDNS.this; - addListener(info, new DNSQuestion(info.getQualifiedName(), DNSConstants.TYPE_ANY, DNSConstants.CLASS_IN)); - } - - public void start() { - timer.schedule(this, DNSConstants.QUERY_WAIT_INTERVAL, DNSConstants.QUERY_WAIT_INTERVAL); - } - - public void run() { - try { - if (state == DNSState.ANNOUNCED) { - if (count++ < 3 && !info.hasData()) { - long now = System.currentTimeMillis(); - DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY); - out.addQuestion(new DNSQuestion(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN)); - out.addQuestion(new DNSQuestion(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN)); - if (info.server != null) { - out.addQuestion(new DNSQuestion(info.server, DNSConstants.TYPE_A, DNSConstants.CLASS_IN)); - } - out.addAnswer((DNSRecord) cache.get(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN), now); - out.addAnswer((DNSRecord) cache.get(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN), now); - if (info.server != null) { - out.addAnswer((DNSRecord) cache.get(info.server, DNSConstants.TYPE_A, DNSConstants.CLASS_IN), now); - } - send(out); - } else { - // After three queries, we can quit. - cancel(); - removeListener(info); - } - ; - } else { - if (state == DNSState.CANCELED) { - cancel(); - removeListener(info); - } - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - } - } - - /** - * The Canceler sends two announces with TTL=0 for the specified services. - */ - private class Canceler extends TimerTask { - /** - * Counts the number of announces being sent. - */ - int count = 0; - /** - * The services that need cancelling. - * Note: We have to use a local variable here, because the services - * that are canceled, are removed immediately from variable JmDNS.services. - */ - private ServiceInfo[] infos; - /** - * We call notifyAll() on the lock object, when we have canceled the - * service infos. - * This is used by method JmDNS.unregisterService() and - * JmDNS.unregisterAllServices, to ensure that the JmDNS - * socket stays open until the Canceler has canceled all services. - *

- * Note: We need this lock, because ServiceInfos do the transition from - * state ANNOUNCED to state CANCELED before we get here. We could get - * rid of this lock, if we added a state named CANCELLING to DNSState. - */ - private Object lock; - int ttl = 0; - - public Canceler(ServiceInfo info, Object lock) { - this.infos = new ServiceInfo[]{info}; - this.lock = lock; - addListener(info, new DNSQuestion(info.getQualifiedName(), DNSConstants.TYPE_ANY, DNSConstants.CLASS_IN)); - } - - public Canceler(ServiceInfo[] infos, Object lock) { - this.infos = infos; - this.lock = lock; - } - - public Canceler(Collection infos, Object lock) { - this.infos = (ServiceInfo[]) infos.toArray(new ServiceInfo[infos.size()]); - this.lock = lock; - } - - public void start() { - timer.schedule(this, 0, DNSConstants.ANNOUNCE_WAIT_INTERVAL); - } - - public void run() { - try { - if (++count < 3) { - logger.finer("run() JmDNS canceling service"); - // announce the service - //long now = System.currentTimeMillis(); - DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); - for (int i = 0; i < infos.length; i++) { - ServiceInfo info = infos[i]; - out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, ttl, info.getQualifiedName()), 0); - out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, ttl, info.priority, info.weight, info.port, localHost.getName()), 0); - out.addAnswer(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN, ttl, info.text), 0); - DNSRecord answer = localHost.getDNS4AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - answer = localHost.getDNS6AddressRecord(); - if (answer != null) { - out.addAnswer(answer, 0); - } - } - send(out); - } else { - // After three successful announcements, we are finished. - synchronized (lock) { - closed = true; - lock.notifyAll(); - } - cancel(); - } - } catch (Throwable e) { - logger.log(Level.WARNING, "run() exception ", e); - recover(); - } - } - } - - // REMIND: Why is this not an anonymous inner class? - - /** - * Shutdown operations. - */ - private class Shutdown implements Runnable { - public void run() { - shutdown = null; - close(); - } - } - - /** - * Recover jmdns when there is an error. - */ - protected void recover() { - logger.finer("recover()"); - // We have an IO error so lets try to recover if anything happens lets close it. - // This should cover the case of the IP address changing under our feet - if (DNSState.CANCELED != state) { - synchronized (this) { // Synchronize only if we are not already in process to prevent dead locks - // - logger.finer("recover() Cleanning up"); - // Stop JmDNS - state = DNSState.CANCELED; // This protects against recursive calls - - // We need to keep a copy for reregistration - Collection oldServiceInfos = new ArrayList(services.values()); - - // Cancel all services - unregisterAllServices(); - disposeServiceCollectors(); - // - // close multicast socket - closeMulticastSocket(); - // - cache.clear(); - logger.finer("recover() All is clean"); - // - // All is clear now start the services - // - try { - openMulticastSocket(localHost); - start(oldServiceInfos); - } catch (Exception exception) { - logger.log(Level.WARNING, "recover() Start services exception ", exception); - } - logger.log(Level.WARNING, "recover() We are back!"); - } - } - } - - /** - * Close down jmdns. Release all resources and unregister all services. - */ - public void close() { - if (state != DNSState.CANCELED) { - synchronized (this) { // Synchronize only if we are not already in process to prevent dead locks - // Stop JmDNS - state = DNSState.CANCELED; // This protects against recursive calls - - unregisterAllServices(); - disposeServiceCollectors(); - - // close socket - closeMulticastSocket(); - - // Stop the timer - timer.cancel(); - - // remove the shutdown hook - if (shutdown != null) { - Runtime.getRuntime().removeShutdownHook(shutdown); - } - - } - } - } - - /** - * List cache entries, for debugging only. - */ - void print() { - System.out.println("---- cache ----"); - cache.print(); - System.out.println(); - } - - /** - * List Services and serviceTypes. - * Debugging Only - */ - - public void printServices() { - System.err.println(toString()); - } - - public String toString() { - StringBuffer aLog = new StringBuffer(); - aLog.append("\t---- Services -----"); - if (services != null) { - for (Iterator k = services.keySet().iterator(); k.hasNext(); ) { - Object key = k.next(); - aLog.append("\n\t\tService: " + key + ": " + services.get(key)); - } - } - aLog.append("\n"); - aLog.append("\t---- Types ----"); - if (serviceTypes != null) { - for (Iterator k = serviceTypes.keySet().iterator(); k.hasNext(); ) { - Object key = k.next(); - aLog.append("\n\t\tType: " + key + ": " + serviceTypes.get(key)); - } - } - aLog.append("\n"); - aLog.append(cache.toString()); - aLog.append("\n"); - aLog.append("\t---- Service Collectors ----"); - if (serviceCollectors != null) { - synchronized (serviceCollectors) { - for (Iterator k = serviceCollectors.keySet().iterator(); k.hasNext(); ) { - Object key = k.next(); - aLog.append("\n\t\tService Collector: " + key + ": " + serviceCollectors.get(key)); - } - serviceCollectors.clear(); - } - } - return aLog.toString(); - } - - /** - * Returns a list of service infos of the specified type. - * - * @param type Service type name, such as _http._tcp.local.. - * @return An array of service instance names. - */ - public ServiceInfo[] list(String type) { - // Implementation note: The first time a list for a given type is - // requested, a ServiceCollector is created which collects service - // infos. This greatly speeds up the performance of subsequent calls - // to this method. The caveats are, that 1) the first call to this method - // for a given type is slow, and 2) we spawn a ServiceCollector - // instance for each service type which increases network traffic a - // little. - - ServiceCollector collector; - - boolean newCollectorCreated; - synchronized (serviceCollectors) { - collector = (ServiceCollector) serviceCollectors.get(type); - if (collector == null) { - collector = new ServiceCollector(type); - serviceCollectors.put(type, collector); - addServiceListener(type, collector); - newCollectorCreated = true; - } else { - newCollectorCreated = false; - } - } - - // After creating a new ServiceCollector, we collect service infos for - // 200 milliseconds. This should be enough time, to get some service - // infos from the network. - if (newCollectorCreated) { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - } - } - - return collector.list(); - } - - /** - * This method disposes all ServiceCollector instances which have been - * created by calls to method list(type). - * - * @see #list - */ - private void disposeServiceCollectors() { - logger.finer("disposeServiceCollectors()"); - synchronized (serviceCollectors) { - for (Iterator i = serviceCollectors.values().iterator(); i.hasNext(); ) { - ServiceCollector collector = (ServiceCollector) i.next(); - removeServiceListener(collector.type, collector); - } - serviceCollectors.clear(); - } - } - - /** - * Instances of ServiceCollector are used internally to speed up the - * performance of method list(type). - * - * @see #list - */ - private static class ServiceCollector implements ServiceListener { - private static Logger logger = Logger.getLogger(ServiceCollector.class.toString()); - /** - * A set of collected service instance names. - */ - private Map infos = Collections.synchronizedMap(new HashMap()); - - public String type; - - public ServiceCollector(String type) { - this.type = type; - } - - /** - * A service has been added. - */ - public void serviceAdded(ServiceEvent event) { - synchronized (infos) { - event.getDNS().requestServiceInfo(event.getType(), event.getName(), 0); - } - } - - /** - * A service has been removed. - */ - public void serviceRemoved(ServiceEvent event) { - synchronized (infos) { - infos.remove(event.getName()); - } - } - - /** - * A service hase been resolved. Its details are now available in the - * ServiceInfo record. - */ - public void serviceResolved(ServiceEvent event) { - synchronized (infos) { - infos.put(event.getName(), event.getInfo()); - } - } - - /** - * Returns an array of all service infos which have been collected by this - * ServiceCollector. - */ - public ServiceInfo[] list() { - synchronized (infos) { - return (ServiceInfo[]) infos.values().toArray(new ServiceInfo[infos.size()]); - } - } - - public String toString() { - StringBuffer aLog = new StringBuffer(); - synchronized (infos) { - for (Iterator k = infos.keySet().iterator(); k.hasNext(); ) { - Object key = k.next(); - aLog.append("\n\t\tService: " + key + ": " + infos.get(key)); - } - } - return aLog.toString(); - } - } - - ; - - private static String toUnqualifiedName(String type, String qualifiedName) { - if (qualifiedName.endsWith(type)) { - return qualifiedName.substring(0, qualifiedName.length() - type.length() - 1); - } else { - return qualifiedName; - } - } -} - diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceEvent.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceEvent.java deleted file mode 100644 index a6df607230..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceEvent.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.EventObject; -import java.util.logging.Logger; - -/** - * ServiceEvent. - * - * @author Werner Randelshofer, Rick Blair - * @version %I%, %G% - */ -public class ServiceEvent extends EventObject -{ - private static Logger logger = Logger.getLogger(ServiceEvent.class.toString()); - /** - * The type name of the service. - */ - private String type; - /** - * The instance name of the service. Or null, if the event was - * fired to a service type listener. - */ - private String name; - /** - * The service info record, or null if the service could be be resolved. - * This is also null, if the event was fired to a service type listener. - */ - private ServiceInfo info; - - /** - * Creates a new instance. - * - * @param source the JmDNS instance which originated the event. - * @param type the type name of the service. - * @param name the instance name of the service. - * @param info the service info record, or null if the service could be be resolved. - */ - public ServiceEvent(JmDNS source, String type, String name, ServiceInfo info) - { - super(source); - this.type = type; - this.name = name; - this.info = info; - } - - /** - * Returns the JmDNS instance which originated the event. - */ - public JmDNS getDNS() - { - return (JmDNS) getSource(); - } - - /** - * Returns the fully qualified type of the service. - */ - public String getType() - { - return type; - } - - /** - * Returns the instance name of the service. - * Always returns null, if the event is sent to a service type listener. - */ - public String getName() - { - return name; - } - - /** - * Returns the service info record, or null if the service could not be - * resolved. - * Always returns null, if the event is sent to a service type listener. - */ - public ServiceInfo getInfo() - { - return info; - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("<" + getClass().getName() + "> "); - buf.append(super.toString()); - buf.append(" name "); - buf.append(getName()); - buf.append(" type "); - buf.append(getType()); - buf.append(" info "); - buf.append(getInfo()); - return buf.toString(); - } - -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceInfo.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceInfo.java deleted file mode 100644 index b91a9a2a36..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceInfo.java +++ /dev/null @@ -1,673 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.InetAddress; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.TimerTask; -import java.util.Vector; -import java.util.logging.Logger; - -/** - * JmDNS service information. - * - * @version %I%, %G% - * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer - */ -public class ServiceInfo implements DNSListener -{ - private static Logger logger = Logger.getLogger(ServiceInfo.class.toString()); - public final static byte[] NO_VALUE = new byte[0]; - JmDNS dns; - - // State machine - /** - * The state of this service info. - * This is used only for services announced by JmDNS. - *

- * For proper handling of concurrency, this variable must be - * changed only using methods advanceState(), revertState() and cancel(). - */ - private DNSState state = DNSState.PROBING_1; - - /** - * Task associated to this service info. - * Possible tasks are JmDNS.Prober, JmDNS.Announcer, JmDNS.Responder, - * JmDNS.Canceler. - */ - TimerTask task; - - String type; - private String name; - String server; - int port; - int weight; - int priority; - byte text[]; - Hashtable props; - InetAddress addr; - - - /** - * Construct a service description for registrating with JmDNS. - * - * @param type fully qualified service type name, such as _http._tcp.local.. - * @param name unqualified service instance name, such as foobar - * @param port the local port on which the service runs - * @param text string describing the service - */ - public ServiceInfo(String type, String name, int port, String text) - { - this(type, name, port, 0, 0, text); - } - - /** - * Construct a service description for registrating with JmDNS. - * - * @param type fully qualified service type name, such as _http._tcp.local.. - * @param name unqualified service instance name, such as foobar - * @param port the local port on which the service runs - * @param weight weight of the service - * @param priority priority of the service - * @param text string describing the service - */ - public ServiceInfo(String type, String name, int port, int weight, int priority, String text) - { - this(type, name, port, weight, priority, (byte[]) null); - try - { - ByteArrayOutputStream out = new ByteArrayOutputStream(text.length()); - writeUTF(out, text); - this.text = out.toByteArray(); - } - catch (IOException e) - { - throw new RuntimeException("unexpected exception: " + e); - } - } - - /** - * Construct a service description for registrating with JmDNS. The properties hashtable must - * map property names to either Strings or byte arrays describing the property values. - * - * @param type fully qualified service type name, such as _http._tcp.local.. - * @param name unqualified service instance name, such as foobar - * @param port the local port on which the service runs - * @param weight weight of the service - * @param priority priority of the service - * @param props properties describing the service - */ - public ServiceInfo(String type, String name, int port, int weight, int priority, Hashtable props) - { - this(type, name, port, weight, priority, new byte[0]); - if (props != null) - { - try - { - ByteArrayOutputStream out = new ByteArrayOutputStream(256); - for (Enumeration e = props.keys(); e.hasMoreElements();) - { - String key = (String) e.nextElement(); - Object val = props.get(key); - ByteArrayOutputStream out2 = new ByteArrayOutputStream(100); - writeUTF(out2, key); - if (val instanceof String) - { - out2.write('='); - writeUTF(out2, (String) val); - } - else - { - if (val instanceof byte[]) - { - out2.write('='); - byte[] bval = (byte[]) val; - out2.write(bval, 0, bval.length); - } - else - { - if (val != NO_VALUE) - { - throw new IllegalArgumentException("invalid property value: " + val); - } - } - } - byte data[] = out2.toByteArray(); - out.write(data.length); - out.write(data, 0, data.length); - } - this.text = out.toByteArray(); - } - catch (IOException e) - { - throw new RuntimeException("unexpected exception: " + e); - } - } - } - - /** - * Construct a service description for registrating with JmDNS. - * - * @param type fully qualified service type name, such as _http._tcp.local.. - * @param name unqualified service instance name, such as foobar - * @param port the local port on which the service runs - * @param weight weight of the service - * @param priority priority of the service - * @param text bytes describing the service - */ - public ServiceInfo(String type, String name, int port, int weight, int priority, byte text[]) - { - this.type = type; - this.name = name; - this.port = port; - this.weight = weight; - this.priority = priority; - this.text = text; - } - - /** - * Construct a service record during service discovery. - */ - ServiceInfo(String type, String name) - { - if (!type.endsWith(".")) - { - throw new IllegalArgumentException("type must be fully qualified DNS name ending in '.': " + type); - } - - this.type = type; - this.name = name; - } - - /** - * During recovery we need to duplicate service info to reregister them - */ - ServiceInfo(ServiceInfo info) - { - if (info != null) - { - this.type = info.type; - this.name = info.name; - this.port = info.port; - this.weight = info.weight; - this.priority = info.priority; - this.text = info.text; - } - } - - /** - * Fully qualified service type name, such as _http._tcp.local. . - */ - public String getType() - { - return type; - } - - /** - * Unqualified service instance name, such as foobar . - */ - public String getName() - { - return name; - } - - /** - * Sets the service instance name. - * - * @param name unqualified service instance name, such as foobar - */ - void setName(String name) - { - this.name = name; - } - - /** - * Fully qualified service name, such as foobar._http._tcp.local. . - */ - public String getQualifiedName() - { - return name + "." + type; - } - - /** - * Get the name of the server. - */ - public String getServer() - { - return server; - } - - /** - * Get the host address of the service (ie X.X.X.X). - */ - public String getHostAddress() - { - return (addr != null ? addr.getHostAddress() : ""); - } - - public InetAddress getAddress() - { - return addr; - } - - /** - * Get the InetAddress of the service. - */ - public InetAddress getInetAddress() - { - return addr; - } - - /** - * Get the port for the service. - */ - public int getPort() - { - return port; - } - - /** - * Get the priority of the service. - */ - public int getPriority() - { - return priority; - } - - /** - * Get the weight of the service. - */ - public int getWeight() - { - return weight; - } - - /** - * Get the text for the serivce as raw bytes. - */ - public byte[] getTextBytes() - { - return text; - } - - /** - * Get the text for the service. This will interpret the text bytes - * as a UTF8 encoded string. Will return null if the bytes are not - * a valid UTF8 encoded string. - */ - public String getTextString() - { - if ((text == null) || (text.length == 0) || ((text.length == 1) && (text[0] == 0))) - { - return null; - } - return readUTF(text, 0, text.length); - } - - /** - * Get the URL for this service. An http URL is created by - * combining the address, port, and path properties. - */ - public String getURL() - { - return getURL("http"); - } - - /** - * Get the URL for this service. An URL is created by - * combining the protocol, address, port, and path properties. - */ - public String getURL(String protocol) - { - String url = protocol + "://" + getAddress() + ":" + getPort(); - String path = getPropertyString("path"); - if (path != null) - { - if (path.indexOf("://") >= 0) - { - url = path; - } - else - { - url += path.startsWith("/") ? path : "/" + path; - } - } - return url; - } - - /** - * Get a property of the service. This involves decoding the - * text bytes into a property list. Returns null if the property - * is not found or the text data could not be decoded correctly. - */ - public synchronized byte[] getPropertyBytes(String name) - { - return (byte[]) getProperties().get(name); - } - - /** - * Get a property of the service. This involves decoding the - * text bytes into a property list. Returns null if the property - * is not found, the text data could not be decoded correctly, or - * the resulting bytes are not a valid UTF8 string. - */ - public synchronized String getPropertyString(String name) - { - byte data[] = (byte[]) getProperties().get(name); - if (data == null) - { - return null; - } - if (data == NO_VALUE) - { - return "true"; - } - return readUTF(data, 0, data.length); - } - - /** - * Enumeration of the property names. - */ - public Enumeration getPropertyNames() - { - Hashtable props = getProperties(); - return (props != null) ? props.keys() : new Vector().elements(); - } - - /** - * Write a UTF string with a length to a stream. - */ - void writeUTF(OutputStream out, String str) throws IOException - { - for (int i = 0, len = str.length(); i < len; i++) - { - int c = str.charAt(i); - if ((c >= 0x0001) && (c <= 0x007F)) - { - out.write(c); - } - else - { - if (c > 0x07FF) - { - out.write(0xE0 | ((c >> 12) & 0x0F)); - out.write(0x80 | ((c >> 6) & 0x3F)); - out.write(0x80 | ((c >> 0) & 0x3F)); - } - else - { - out.write(0xC0 | ((c >> 6) & 0x1F)); - out.write(0x80 | ((c >> 0) & 0x3F)); - } - } - } - } - - /** - * Read data bytes as a UTF stream. - */ - String readUTF(byte data[], int off, int len) - { - StringBuffer buf = new StringBuffer(); - for (int end = off + len; off < end;) - { - int ch = data[off++] & 0xFF; - switch (ch >> 4) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxxxxxx - break; - case 12: - case 13: - if (off >= len) - { - return null; - } - // 110x xxxx 10xx xxxx - ch = ((ch & 0x1F) << 6) | (data[off++] & 0x3F); - break; - case 14: - if (off + 2 >= len) - { - return null; - } - // 1110 xxxx 10xx xxxx 10xx xxxx - ch = ((ch & 0x0f) << 12) | ((data[off++] & 0x3F) << 6) | (data[off++] & 0x3F); - break; - default: - if (off + 1 >= len) - { - return null; - } - // 10xx xxxx, 1111 xxxx - ch = ((ch & 0x3F) << 4) | (data[off++] & 0x0f); - break; - } - buf.append((char) ch); - } - return buf.toString(); - } - - synchronized Hashtable getProperties() - { - if ((props == null) && (text != null)) - { - Hashtable props = new Hashtable(); - int off = 0; - while (off < text.length) - { - // length of the next key value pair - int len = text[off++] & 0xFF; - if ((len == 0) || (off + len > text.length)) - { - props.clear(); - break; - } - // look for the '=' - int i = 0; - for (; (i < len) && (text[off + i] != '='); i++) - { - ; - } - - // get the property name - String name = readUTF(text, off, i); - if (name == null) - { - props.clear(); - break; - } - if (i == len) - { - props.put(name, NO_VALUE); - } - else - { - byte value[] = new byte[len - ++i]; - System.arraycopy(text, off + i, value, 0, len - i); - props.put(name, value); - off += len; - } - } - this.props = props; - } - return props; - } - - // REMIND: Oops, this shouldn't be public! - /** - * JmDNS callback to update a DNS record. - */ - public void updateRecord(JmDNS jmdns, long now, DNSRecord rec) - { - if ((rec != null) && !rec.isExpired(now)) - { - switch (rec.type) - { - case DNSConstants.TYPE_A: // IPv4 - case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested - if (rec.name.equals(server)) - { - addr = ((DNSRecord.Address) rec).getAddress(); - - } - break; - case DNSConstants.TYPE_SRV: - if (rec.name.equals(getQualifiedName())) - { - DNSRecord.Service srv = (DNSRecord.Service) rec; - server = srv.server; - port = srv.port; - weight = srv.weight; - priority = srv.priority; - addr = null; - // changed to use getCache() instead - jeffs - // updateRecord(jmdns, now, (DNSRecord)jmdns.cache.get(server, TYPE_A, CLASS_IN)); - updateRecord(jmdns, now, (DNSRecord) jmdns.getCache().get(server, DNSConstants.TYPE_A, DNSConstants.CLASS_IN)); - } - break; - case DNSConstants.TYPE_TXT: - if (rec.name.equals(getQualifiedName())) - { - DNSRecord.Text txt = (DNSRecord.Text) rec; - text = txt.text; - } - break; - } - // Future Design Pattern - // This is done, to notify the wait loop in method - // JmDNS.getServiceInfo(type, name, timeout); - if (hasData() && dns != null) - { - dns.handleServiceResolved(this); - dns = null; - } - synchronized (this) - { - notifyAll(); - } - } - } - - /** - * Returns true if the service info is filled with data. - */ - boolean hasData() - { - return server != null && addr != null && text != null; - } - - - // State machine - /** - * Sets the state and notifies all objects that wait on the ServiceInfo. - */ - synchronized void advanceState() - { - state = state.advance(); - notifyAll(); - } - - /** - * Sets the state and notifies all objects that wait on the ServiceInfo. - */ - synchronized void revertState() - { - state = state.revert(); - notifyAll(); - } - - /** - * Sets the state and notifies all objects that wait on the ServiceInfo. - */ - synchronized void cancel() - { - state = DNSState.CANCELED; - notifyAll(); - } - - /** - * Returns the current state of this info. - */ - DNSState getState() - { - return state; - } - - - public int hashCode() - { - return getQualifiedName().hashCode(); - } - - public boolean equals(Object obj) - { - return (obj instanceof ServiceInfo) && getQualifiedName().equals(((ServiceInfo) obj).getQualifiedName()); - } - - public String getNiceTextString() - { - StringBuffer buf = new StringBuffer(); - for (int i = 0, len = text.length; i < len; i++) - { - if (i >= 20) - { - buf.append("..."); - break; - } - int ch = text[i] & 0xFF; - if ((ch < ' ') || (ch > 127)) - { - buf.append("\\0"); - buf.append(Integer.toString(ch, 8)); - } - else - { - buf.append((char) ch); - } - } - return buf.toString(); - } - - public String toString() - { - StringBuffer buf = new StringBuffer(); - buf.append("service["); - buf.append(getQualifiedName()); - buf.append(','); - buf.append(getAddress()); - buf.append(':'); - buf.append(port); - buf.append(','); - buf.append(getNiceTextString()); - buf.append(']'); - return buf.toString(); - } -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceListener.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceListener.java deleted file mode 100644 index 0c529771d2..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.EventListener; - -/** - * Listener for service updates. - * - * @version %I%, %G% - * @author Arthur van Hoff, Werner Randelshofer - */ -public interface ServiceListener extends EventListener -{ - /** - * A service has been added. - * - * @param event The ServiceEvent providing the name and fully qualified type - * of the service. - */ - void serviceAdded(ServiceEvent event); - - /** - * A service has been removed. - * - * @param event The ServiceEvent providing the name and fully qualified type - * of the service. - */ - void serviceRemoved(ServiceEvent event); - - /** - * A service has been resolved. Its details are now available in the - * ServiceInfo record. - * - * @param event The ServiceEvent providing the name, the fully qualified - * type of the service, and the service info record, or null if the service - * could not be resolved. - */ - void serviceResolved(ServiceEvent event); -} diff --git a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceTypeListener.java b/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceTypeListener.java deleted file mode 100644 index 2987abafcc..0000000000 --- a/activemq-jmdns_1.0/src/main/java/org/apache/activemq/jmdns/ServiceTypeListener.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright 2003-2005 Arthur van Hoff, Rick Blair - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.activemq.jmdns; - -import java.util.EventListener; - -/** - * Listener for service types. - * - * @version %I%, %G% - * @author Arthur van Hoff, Werner Randelshofer - */ -public interface ServiceTypeListener extends EventListener -{ - /** - * A new service type was discovered. - * - * @param event The service event providing the fully qualified type of - * the service. - */ - void serviceTypeAdded(ServiceEvent event); -} diff --git a/activemq-jmdns_1.0/src/main/resources/META-INF/NOTICE b/activemq-jmdns_1.0/src/main/resources/META-INF/NOTICE deleted file mode 100644 index 1495155864..0000000000 --- a/activemq-jmdns_1.0/src/main/resources/META-INF/NOTICE +++ /dev/null @@ -1,17 +0,0 @@ -=============================================================== -== NOTICE File for JmDNS == -=============================================================== - -Java Multicast Domain Name Server (JmDNS) - -This project was originally developed by Arthur van Hoff under the GNU -Lesser General Public License as jRendevous. It was moved to Sourceforge -by Rick Blair and renamed to JmDNS with the Arthur's kind permission. - -Currently it has been re-released under the Apache License, Version 2.0. - -Details of the Apache License, Version 2.0 can be found at: -http://www.apache.org/licenses/ - - -For other details please see the README.txt file. diff --git a/activemq-jmdns_1.0/src/main/resources/META-INF/README.txt b/activemq-jmdns_1.0/src/main/resources/META-INF/README.txt deleted file mode 100644 index e54a65e5a9..0000000000 --- a/activemq-jmdns_1.0/src/main/resources/META-INF/README.txt +++ /dev/null @@ -1,117 +0,0 @@ -// %Z%%M%, %I%, %G% -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -//This library is now licensed under the Apache License Version 2.0 Please -//see the file NOTICE. - - -Arthur van Hoff -avh@strangeberry.com - -Rick Blair -rickblair@mac.com - -** JmDNS - -This is an implemenation of multi-cast DNS in Java. It currently -supports service discovery and service registration. It is fully -interoperable with Apple's Rendezvous. - - - -** Requirements - -jmdns has been tested using the JDK 1.3.1 and JDK 1.4.0 -on the following platforms: - -Windows 9x, XP, 2000 -Linux RedHat 7.3-9.0, Mandrake -Mac OSX - - - -** Running jmdns from the Command Line - -GUI browser: - - java -jar lib/jmdns.jar -browse - -TTY browser for a particular service type: - - java -jar lib/jmdns.jar -bs _http._tcp local. - -Register a service: - - java -jar lib/jmdns.jar -rs foobar _http._tcp local. 1234 path=index.html - -List service types: - - java -jar lib/jmdns.jar -bt - -To print debugging output specify -d as the first argument. - - - -** Sample Code for Service Registration - - import javax.jmdns.*; - - JmDNS jmdns = new JmDNS(); - jmdns.registerService( - new ServiceInfo("_http._tcp.local.", "foo._http._tcp.local.", 1234, 0, 0, "path=index.html") - ); - - -** Sample code for Serivice Discovery - - import javax.jmdns.*; - - static class SampleListener implements ServiceListener - { - public void addService(JmDNS jmdns, String type, String name) - { - System.out.println("ADD: " + jmdns.getServiceInfo(type, name)); - } - public void removeService(JmDNS jmdns, String type, String name) - { - System.out.println("REMOVE: " + name); - } - public void resolveService(JmDNS jmdns, String type, String name, ServiceInfo info) - { - System.out.println("RESOLVED: " + info); - } - } - - JmDNS jmdns = new JmDNS(); - jmdns.addServiceListener("_http._tcp.local.", new SampleListener()); - - -** Changes since October 2003 - -- Renamed package com.strangeberry.rendezvous to javax.jmdns -- fixed unicast queries -- fixed property handling -- use the hostname instead of the service name is address resolution -- Added Apache License. - --------------------------------------------------------------------- -The activemq-jmdns_1.0 source is derived from http://repo1.maven.org/maven2/jmdns/jmdns/1.0/jmdns-1.0-sources.jar - -Changes to apache activemq version: -- renamed package javax.jmdns to org.apache.activemq.jmdns -- removed classes with lgpl source headers, leaving only the org.apache.activemq.jmdns package. - diff --git a/activemq-karaf/src/main/resources/features.xml b/activemq-karaf/src/main/resources/features.xml index bff5b70797..97e0b0bcb1 100644 --- a/activemq-karaf/src/main/resources/features.xml +++ b/activemq-karaf/src/main/resources/features.xml @@ -75,6 +75,7 @@ mvn:org.apache.httpcomponents/httpcore-osgi/${httpclient-version} mvn:org.apache.httpcomponents/httpclient-osgi/${httpclient-version} mvn:org.springframework/spring-oxm/${spring-version} + mvn:javax.jmdns/jmdns/${jmdns-version} diff --git a/assembly/pom.xml b/assembly/pom.xml index b956b88c07..e39f296181 100755 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -158,8 +158,8 @@ jaxp-api - org.apache.activemq - activemq-jmdns_1.0 + javax.jmdns + jmdns com.thoughtworks.xstream diff --git a/assembly/src/main/descriptors/common-bin.xml b/assembly/src/main/descriptors/common-bin.xml index a036554954..146907e36e 100644 --- a/assembly/src/main/descriptors/common-bin.xml +++ b/assembly/src/main/descriptors/common-bin.xml @@ -138,7 +138,6 @@ ${pom.groupId}:activemq-xmpp ${pom.groupId}:activemq-spring ${pom.groupId}:activeio-core - ${pom.groupId}:activemq-jmdns_1.0 commons-beanutils:commons-beanutils commons-collections:commons-collections commons-httpclient:commons-httpclient @@ -168,6 +167,7 @@ org.apache.velocity:velocity org.apache.servicemix.bundles:org.apache.servicemix.bundles.josql org.jasypt:jasypt + javax.jmdns:jmdns org.fusesource.fuse-extra:fusemq-leveldb org.fusesource.hawtbuf:hawtbuf diff --git a/pom.xml b/pom.xml index b72b07ddad..5807ff8121 100755 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,7 @@ 1.9.0 1.0 7.6.5.v20120716 + 3.4.1 2.1.v20100127 1.1.2 1.3.2 @@ -204,7 +205,6 @@ activemq-web-console activemq-xmpp assembly - activemq-jmdns_1.0 kahadb @@ -246,11 +246,6 @@ activemq-jaas ${activemq-version} - - org.apache.activemq - activemq-jmdns_1.0 - ${activemq-version} - org.apache.activemq activemq-pool @@ -479,6 +474,14 @@ true + + + javax.jmdns + jmdns + ${jmdns-version} + true + + commons-daemon