13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// /Copyright 2003-2005 Arthur van Hoff, Rick Blair 23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0 33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Original license LGPL 43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl; 63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException; 83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.DatagramPacket; 93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet4Address; 103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet6Address; 113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.InetAddress; 123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.MulticastSocket; 133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.SocketException; 143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.AbstractMap; 153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.ArrayList; 163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collection; 173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collections; 183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashMap; 193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashSet; 203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Iterator; 213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.LinkedList; 223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.List; 233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Map; 243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Properties; 253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Random; 263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Set; 273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentHashMap; 283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentMap; 293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ExecutorService; 303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.Executors; 313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.locks.ReentrantLock; 323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level; 333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger; 343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.JmDNS; 363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceEvent; 373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo; 383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo.Fields; 393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceListener; 403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceTypeListener; 413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.ListenerStatus.ServiceListenerStatus; 423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.ListenerStatus.ServiceTypeListenerStatus; 433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants; 443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass; 453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordType; 463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSState; 473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.tasks.DNSTask; 483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// REMIND: multiple IP addresses 503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/** 523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * mDNS implementation in Java. 533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Arthur van Hoff, Rick Blair, Jeff Sonstein, Werner Randelshofer, Pierre Frisch, Scott Lewis 553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class JmDNSImpl extends JmDNS implements DNSStatefulObject, DNSTaskStarter { 573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private static Logger logger = Logger.getLogger(JmDNSImpl.class.getName()); 583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public enum Operation { 603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Remove, Update, Add, RegisterServiceType, Noop 613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is the multicast group, we are listening to for multicast DNS messages. 653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private volatile InetAddress _group; 673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is our multicast socket. 693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private volatile MulticastSocket _socket; 713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Holds instances of JmDNS.DNSListener. Must by a synchronized collection, because it is updated from concurrent threads. 743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final List<DNSListener> _listeners; 763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Holds instances of ServiceListener's. Keys are Strings holding a fully qualified service type. Values are LinkedList's of ServiceListener's. 793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, List<ServiceListenerStatus>> _serviceListeners; 813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Holds instances of ServiceTypeListener's. 843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final Set<ServiceTypeListenerStatus> _typeListeners; 863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Cache for DNSEntry's. 893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final DNSCache _cache; 913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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. 943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, ServiceInfo> _services; 963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This hashtable holds the service types that have been registered or that have been received in an incoming datagram.<br/> 993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Keys are instances of String which hold an all lower-case version of the fully qualified service type.<br/> 1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Values hold the fully qualified service type. 1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, ServiceTypeEntry> _serviceTypes; 1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private volatile Delegate _delegate; 1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is used to store type entries. The type is stored as a call variable and the map support the subtypes. 1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * <p> 1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The key is the lowercase version as the value is the case preserved version. 1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * </p> 1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static class ServiceTypeEntry extends AbstractMap<String, String> implements Cloneable { 1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final Set<Map.Entry<String, String>> _entrySet; 1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final String _type; 1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private static class SubTypeEntry implements Entry<String, String>, java.io.Serializable, Cloneable { 1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private static final long serialVersionUID = 9188503522395855322L; 1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final String _key; 1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final String _value; 1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public SubTypeEntry(String subtype) { 1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(); 1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _value = (subtype != null ? subtype : ""); 1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _key = _value.toLowerCase(); 1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String getKey() { 1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _key; 1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String getValue() { 1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _value; 1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Replaces the value corresponding to this entry with the specified value (optional operation). This implementation simply throws <tt>UnsupportedOperationException</tt>, as this class implements an <i>immutable</i> map entry. 1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param value 1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * new value to be stored in this entry 1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return (Does not return) 1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception UnsupportedOperationException 1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * always 1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String setValue(String value) { 1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new UnsupportedOperationException(); 1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean equals(Object entry) { 1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!(entry instanceof Map.Entry)) { 1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return false; 1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.getKey().equals(((Map.Entry<?, ?>) entry).getKey()) && this.getValue().equals(((Map.Entry<?, ?>) entry).getValue()); 1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public int hashCode() { 1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return (_key == null ? 0 : _key.hashCode()) ^ (_value == null ? 0 : _value.hashCode()); 1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see java.lang.Object#clone() 1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public SubTypeEntry clone() { 1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Immutable object 1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this; 1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String toString() { 1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _key + "=" + _value; 1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceTypeEntry(String type) { 2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(); 2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._type = type; 2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._entrySet = new HashSet<Map.Entry<String, String>>(); 2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The type associated with this entry. 2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return the type 2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String getType() { 2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _type; 2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see java.util.AbstractMap#entrySet() 2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Set<Map.Entry<String, String>> entrySet() { 2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _entrySet; 2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Returns <code>true</code> if this set contains the specified element. More formally, returns <code>true</code> if and only if this set contains an element <code>e</code> such that 2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * <code>(o==null ? e==null : o.equals(e))</code>. 2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param subtype 2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * element whose presence in this set is to be tested 2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return <code>true</code> if this set contains the specified element 2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean contains(String subtype) { 2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return subtype != null && this.containsKey(subtype.toLowerCase()); 2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Adds the specified element to this set if it is not already present. More formally, adds the specified element <code>e</code> to this set if this set contains no element <code>e2</code> such that 2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * <code>(e==null ? e2==null : e.equals(e2))</code>. If this set already contains the element, the call leaves the set unchanged and returns <code>false</code>. 2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param subtype 2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * element to be added to this set 2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return <code>true</code> if this set did not already contain the specified element 2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean add(String subtype) { 2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (subtype == null || this.contains(subtype)) { 2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return false; 2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _entrySet.add(new SubTypeEntry(subtype)); 2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return true; 2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Returns an iterator over the elements in this set. The elements are returned in no particular order (unless this set is an instance of some class that provides a guarantee). 2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return an iterator over the elements in this set 2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Iterator<String> iterator() { 2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.keySet().iterator(); 2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see java.util.AbstractMap#clone() 2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceTypeEntry clone() { 2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceTypeEntry entry = new ServiceTypeEntry(this.getType()); 2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (Map.Entry<String, String> subTypeEntry : this.entrySet()) { 2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman entry.add(subTypeEntry.getValue()); 2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return entry; 2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see java.util.AbstractMap#toString() 2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String toString() { 2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final StringBuilder aLog = new StringBuilder(200); 2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isEmpty()) { 2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("empty"); 2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String value : this.values()) { 2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(value); 2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(", "); 2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.setLength(aLog.length() - 2); 2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return aLog.toString(); 2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is the shutdown hook, we registered with the java runtime. 2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected Thread _shutdown; 2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Handle on the local host 3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private HostInfo _localHost; 3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private Thread _incomingListener; 3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Throttle count. This is used to count the overall number of probes sent by JmDNS. When the last throttle increment happened . 3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private int _throttle; 3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Last throttle increment. 3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private long _lastThrottleIncrement; 3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ExecutorService _executor = Executors.newSingleThreadExecutor(); 3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 2009-09-16 ldeck: adding docbug patch with slight ammendments 3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 'Fixes two deadlock conditions involving JmDNS.close() - ID: 1473279' 3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // --------------------------------------------------- 3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The timer that triggers our announcements. We can't use the main timer object, because that could cause a deadlock where Prober waits on JmDNS.this lock held by close(), close() waits for us to finish, and we wait for Prober to give us back 3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * the timer thread so we can announce. (Patch from docbug in 2006-04-19 still wasn't patched .. so I'm doing it!) 3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // private final Timer _cancelerTimer; 3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // --------------------------------------------------- 3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The source for random values. This is used to introduce random delays in responses. This reduces the potential for collisions on the network. 3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final static Random _random = new Random(); 3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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. 3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ReentrantLock _ioLock = new ReentrantLock(); 3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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.<br/> 3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * FIXME [PJYF June 8 2010]: This does not work well with multiple planned answers for packages that came in from different clients. 3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private DNSIncoming _plannedAnswer; 3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // State machine 3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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. 3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see #list 3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, ServiceCollector> _serviceCollectors; 3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final String _name; 3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Main method to display API information if run from java -jar 3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param argv 3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * the command line arguments 3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static void main(String[] argv) { 3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String version = null; 3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final Properties pomProperties = new Properties(); 3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman pomProperties.load(JmDNSImpl.class.getResourceAsStream("/META-INF/maven/javax.jmdns/jmdns/pom.properties")); 3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman version = pomProperties.getProperty("version"); 3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (Exception e) { 3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman version = "RUNNING.IN.IDE.FULL"; 3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.out.println("JmDNS version \"" + version + "\""); 3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.out.println(" "); 3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.out.println("Running on java version \"" + System.getProperty("java.version") + "\"" + " (build " + System.getProperty("java.runtime.version") + ")" + " from " + System.getProperty("java.vendor")); 3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.out.println("Operating environment \"" + System.getProperty("os.name") + "\"" + " version " + System.getProperty("os.version") + " on " + System.getProperty("os.arch")); 3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.out.println("For more information on JmDNS please visit https://sourceforge.net/projects/jmdns/"); 3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Create an instance of JmDNS and bind it to a specific network interface given its IP-address. 3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param address 3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * IP address to bind to. 3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param name 3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * name of the newly created JmDNS 3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public JmDNSImpl(InetAddress address, String name) throws IOException { 3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(); 3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("JmDNS instance created"); 3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _cache = new DNSCache(100); 3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _listeners = Collections.synchronizedList(new ArrayList<DNSListener>()); 4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _serviceListeners = new ConcurrentHashMap<String, List<ServiceListenerStatus>>(); 4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _typeListeners = Collections.synchronizedSet(new HashSet<ServiceTypeListenerStatus>()); 4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _serviceCollectors = new ConcurrentHashMap<String, ServiceCollector>(); 4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _services = new ConcurrentHashMap<String, ServiceInfo>(20); 4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _serviceTypes = new ConcurrentHashMap<String, ServiceTypeEntry>(20); 4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _localHost = HostInfo.newHostInfo(address, this, name); 4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _name = (name != null ? name : _localHost.getName()); 4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // _cancelerTimer = new Timer("JmDNS.cancelerTimer"); 4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // (ldeck 2.1.1) preventing shutdown blocking thread 4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // ------------------------------------------------- 4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // _shutdown = new Thread(new Shutdown(), "JmDNS.Shutdown"); 4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Runtime.getRuntime().addShutdownHook(_shutdown); 4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // ------------------------------------------------- 4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Bind to multicast socket 4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.openMulticastSocket(this.getLocalHost()); 4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.start(this.getServices().values()); 4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startReaper(); 4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void start(Collection<? extends ServiceInfo> serviceInfos) { 4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_incomingListener == null) { 4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _incomingListener = new SocketListener(this); 4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _incomingListener.start(); 4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startProber(); 4323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo info : serviceInfos) { 4333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 4343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.registerService(new ServiceInfoImpl(info)); 4353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final Exception exception) { 4363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.WARNING, "start() Registration exception ", exception); 4373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void openMulticastSocket(HostInfo hostInfo) throws IOException { 4423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_group == null) { 4433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (hostInfo.getInetAddress() instanceof Inet6Address) { 4443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _group = InetAddress.getByName(DNSConstants.MDNS_GROUP_IPV6); 4453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 4463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _group = InetAddress.getByName(DNSConstants.MDNS_GROUP); 4473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_socket != null) { 4503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.closeMulticastSocket(); 4513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket = new MulticastSocket(DNSConstants.MDNS_PORT); 4533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((hostInfo != null) && (hostInfo.getInterface() != null)) { 4543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 4553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket.setNetworkInterface(hostInfo.getInterface()); 4563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (SocketException e) { 4573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 4583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine("openMulticastSocket() Set network interface exception: " + e.getMessage()); 4593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket.setTimeToLive(255); 4633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket.joinGroup(_group); 4643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 4663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void closeMulticastSocket() { 4673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // jP: 20010-01-18. See below. We'll need this monitor... 4683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // assert (Thread.holdsLock(this)); 4693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 4703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("closeMulticastSocket()"); 4713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_socket != null) { 4733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // close socket 4743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 4753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 4763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket.leaveGroup(_group); 4773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (SocketException exception) { 4783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 4793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket.close(); 4813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // jP: 20010-01-18. It isn't safe to join() on the listener 4823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // thread - it attempts to lock the IoLock object, and deadlock 4833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // ensues. Per issue #2933183, changed this to wait on the JmDNS 4843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // monitor, checking on each notify (or timeout) that the 4853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // listener thread has stopped. 4863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 4873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman while (_incomingListener != null && _incomingListener.isAlive()) { 4883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this) { 4893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 4903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_incomingListener != null && _incomingListener.isAlive()) { 4913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // wait time is arbitrary, we're really expecting notification. 4923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 4933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("closeMulticastSocket(): waiting for jmDNS monitor"); 4943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.wait(1000); 4963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 4973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (InterruptedException ignored) { 4983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Ignored 4993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _incomingListener = null; 5033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final Exception exception) { 5043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.WARNING, "closeMulticastSocket() Close socket exception ", exception); 5053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _socket = null; 5073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // State machine 5113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean advanceState(DNSTask task) { 5163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.advanceState(task); 5173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean revertState() { 5243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.revertState(); 5253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean cancelState() { 5323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.cancelState(); 5333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean closeState() { 5403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.closeState(); 5413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean recoverState() { 5483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.recoverState(); 5493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public JmDNSImpl getDns() { 5563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this; 5573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void associateWithTask(DNSTask task, DNSState state) { 5643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._localHost.associateWithTask(task, state); 5653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void removeAssociationWithTask(DNSTask task) { 5723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._localHost.removeAssociationWithTask(task); 5733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isAssociatedWithTask(DNSTask task, DNSState state) { 5803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isAssociatedWithTask(task, state); 5813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isProbing() { 5883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isProbing(); 5893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 5923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 5933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 5943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 5953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isAnnouncing() { 5963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isAnnouncing(); 5973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 5983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 5993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isAnnounced() { 6043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isAnnounced(); 6053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isCanceling() { 6123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isCanceling(); 6133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isCanceled() { 6203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isCanceled(); 6213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isClosing() { 6283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isClosing(); 6293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean isClosed() { 6363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.isClosed(); 6373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean waitForAnnounced(long timeout) { 6443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.waitForAnnounced(timeout); 6453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean waitForCanceled(long timeout) { 6523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._localHost.waitForCanceled(timeout); 6533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Return the DNSCache associated with the cache variable 6573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 6583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return DNS cache 6593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSCache getCache() { 6613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _cache; 6623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String getName() { 6693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _name; 6703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String getHostName() { 6773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _localHost.getName(); 6783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Returns the local host info 6823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 6833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return local host info 6843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public HostInfo getLocalHost() { 6863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _localHost; 6873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 6923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 6933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public InetAddress getInetAddress() throws IOException { 6943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _localHost.getInetAddress(); 6953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 6963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 6973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 6983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 6993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 7003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 7013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Deprecated 7023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public InetAddress getInterface() throws IOException { 7033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _socket.getInterface(); 7043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 7073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 7083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 7093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 7103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo getServiceInfo(String type, String name) { 7113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.getServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT); 7123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 7153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 7163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 7173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 7183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo getServiceInfo(String type, String name, long timeout) { 7193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.getServiceInfo(type, name, false, timeout); 7203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 7233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 7243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 7253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 7263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo getServiceInfo(String type, String name, boolean persistent) { 7273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.getServiceInfo(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT); 7283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 7313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 7323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 7333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 7343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo getServiceInfo(String type, String name, boolean persistent, long timeout) { 7353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfoImpl info = this.resolveServiceInfo(type, name, "", persistent); 7363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.waitForInfoData(info, timeout); 7373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return (info.hasData() ? info : null); 7383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl resolveServiceInfo(String type, String name, String subtype, boolean persistent) { 7413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.cleanCache(); 7423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String loType = type.toLowerCase(); 7433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.registerServiceType(type); 7443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_serviceCollectors.putIfAbsent(loType, new ServiceCollector(type)) == null) { 7453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.addServiceListener(loType, _serviceCollectors.get(loType), ListenerStatus.SYNCHONEOUS); 7463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Check if the answer is in the cache. 7493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfoImpl info = this.getServiceInfoFromCache(type, name, subtype, persistent); 7503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We still run the resolver to do the dispatch but if the info is already there it will quit immediately 7513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startServiceInfoResolver(info); 7523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return info; 7543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl getServiceInfoFromCache(String type, String name, String subtype, boolean persistent) { 7573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Check if the answer is in the cache. 7583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl info = new ServiceInfoImpl(type, name, subtype, 0, 0, 0, persistent, (byte[]) null); 7593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSEntry pointerEntry = this.getCache().getDNSEntry(new DNSRecord.Pointer(type, DNSRecordClass.CLASS_ANY, false, 0, info.getQualifiedName())); 7603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (pointerEntry instanceof DNSRecord) { 7613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl cachedInfo = (ServiceInfoImpl) ((DNSRecord) pointerEntry).getServiceInfo(persistent); 7623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedInfo != null) { 7633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // To get a complete info record we need to retrieve the service, address and the text bytes. 7643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 7653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Map<Fields, String> map = cachedInfo.getQualifiedNameMap(); 7663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] srvBytes = null; 7673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String server = ""; 7683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSEntry serviceEntry = this.getCache().getDNSEntry(info.getQualifiedName(), DNSRecordType.TYPE_SRV, DNSRecordClass.CLASS_ANY); 7693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (serviceEntry instanceof DNSRecord) { 7703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo cachedServiceEntryInfo = ((DNSRecord) serviceEntry).getServiceInfo(persistent); 7713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedServiceEntryInfo != null) { 7723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo = new ServiceInfoImpl(map, cachedServiceEntryInfo.getPort(), cachedServiceEntryInfo.getWeight(), cachedServiceEntryInfo.getPriority(), persistent, (byte[]) null); 7733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman srvBytes = cachedServiceEntryInfo.getTextBytes(); 7743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman server = cachedServiceEntryInfo.getServer(); 7753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSEntry addressEntry = this.getCache().getDNSEntry(server, DNSRecordType.TYPE_A, DNSRecordClass.CLASS_ANY); 7783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (addressEntry instanceof DNSRecord) { 7793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo cachedAddressInfo = ((DNSRecord) addressEntry).getServiceInfo(persistent); 7803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedAddressInfo != null) { 7813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (Inet4Address address : cachedAddressInfo.getInet4Addresses()) { 7823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo.addAddress(address); 7833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo._setText(cachedAddressInfo.getTextBytes()); 7853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman addressEntry = this.getCache().getDNSEntry(server, DNSRecordType.TYPE_AAAA, DNSRecordClass.CLASS_ANY); 7883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (addressEntry instanceof DNSRecord) { 7893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo cachedAddressInfo = ((DNSRecord) addressEntry).getServiceInfo(persistent); 7903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedAddressInfo != null) { 7913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (Inet6Address address : cachedAddressInfo.getInet6Addresses()) { 7923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo.addAddress(address); 7933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo._setText(cachedAddressInfo.getTextBytes()); 7953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 7973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSEntry textEntry = this.getCache().getDNSEntry(cachedInfo.getQualifiedName(), DNSRecordType.TYPE_TXT, DNSRecordClass.CLASS_ANY); 7983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (textEntry instanceof DNSRecord) { 7993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo cachedTextInfo = ((DNSRecord) textEntry).getServiceInfo(persistent); 8003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedTextInfo != null) { 8013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo._setText(cachedTextInfo.getTextBytes()); 8023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedInfo.getTextBytes().length == 0) { 8053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedInfo._setText(srvBytes); 8063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedInfo.hasData()) { 8083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info = cachedInfo; 8093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return info; 8133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void waitForInfoData(ServiceInfo info, long timeout) { 8163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (info) { 8173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman long loops = (timeout / 200L); 8183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (loops < 1) { 8193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman loops = 1; 8203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < loops; i++) { 8223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info.hasData()) { 8233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 8243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 8263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.wait(200); 8273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final InterruptedException e) { 8283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* Stub */ 8293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 8353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 8363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 8373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void requestServiceInfo(String type, String name) { 8393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.requestServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT); 8403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 8433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 8443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 8453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void requestServiceInfo(String type, String name, boolean persistent) { 8473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.requestServiceInfo(type, name, persistent, DNSConstants.SERVICE_INFO_TIMEOUT); 8483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 8513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 8523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 8533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void requestServiceInfo(String type, String name, long timeout) { 8553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.requestServiceInfo(type, name, false, DNSConstants.SERVICE_INFO_TIMEOUT); 8563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 8593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 8603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 8613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void requestServiceInfo(String type, String name, boolean persistent, long timeout) { 8633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfoImpl info = this.resolveServiceInfo(type, name, "", persistent); 8643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.waitForInfoData(info, timeout); 8653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void handleServiceResolved(ServiceEvent event) { 8683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<ServiceListenerStatus> list = _serviceListeners.get(event.getType().toLowerCase()); 8693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final List<ServiceListenerStatus> listCopy; 8703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((list != null) && (!list.isEmpty())) { 8713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((event.getInfo() != null) && event.getInfo().hasData()) { 8723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceEvent localEvent = event; 8733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (list) { 8743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listCopy = new ArrayList<ServiceListenerStatus>(list); 8753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (final ServiceListenerStatus listener : listCopy) { 8773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.submit(new Runnable() { 8783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 8793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 8813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.serviceResolved(localEvent); 8823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }); 8843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 8883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 8903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 8913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 8923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 8933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addServiceTypeListener(ServiceTypeListener listener) throws IOException { 8943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceTypeListenerStatus status = new ServiceTypeListenerStatus(listener, ListenerStatus.ASYNCHONEOUS); 8953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _typeListeners.add(status); 8963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 8973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // report cached service types 8983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String type : _serviceTypes.keySet()) { 8993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman status.serviceTypeAdded(new ServiceEventImpl(this, type, "", null)); 9003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startTypeResolver(); 9033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 9063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 9073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 9083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 9093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void removeServiceTypeListener(ServiceTypeListener listener) { 9103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceTypeListenerStatus status = new ServiceTypeListenerStatus(listener, ListenerStatus.ASYNCHONEOUS); 9113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _typeListeners.remove(status); 9123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 9153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 9163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 9173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 9183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addServiceListener(String type, ServiceListener listener) { 9193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.addServiceListener(type, listener, ListenerStatus.ASYNCHONEOUS); 9203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void addServiceListener(String type, ServiceListener listener, boolean synch) { 9233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceListenerStatus status = new ServiceListenerStatus(listener, synch); 9243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final String loType = type.toLowerCase(); 9253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<ServiceListenerStatus> list = _serviceListeners.get(loType); 9263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list == null) { 9273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_serviceListeners.putIfAbsent(loType, new LinkedList<ServiceListenerStatus>()) == null) { 9283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_serviceCollectors.putIfAbsent(loType, new ServiceCollector(type)) == null) { 9293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We have a problem here. The service collectors must be called synchronously so that their cache get cleaned up immediately or we will report . 9303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.addServiceListener(loType, _serviceCollectors.get(loType), ListenerStatus.SYNCHONEOUS); 9313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman list = _serviceListeners.get(loType); 9343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list != null) { 9363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (list) { 9373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!list.contains(listener)) { 9383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman list.add(status); 9393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // report cached service types 9433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final List<ServiceEvent> serviceEvents = new ArrayList<ServiceEvent>(); 9443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Collection<DNSEntry> dnsEntryLits = this.getCache().allValues(); 9453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSEntry entry : dnsEntryLits) { 9463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final DNSRecord record = (DNSRecord) entry; 9473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (record.getRecordType() == DNSRecordType.TYPE_SRV) { 9483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (record.getKey().endsWith(loType)) { 9493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Do not used the record embedded method for generating event this will not work. 9503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // serviceEvents.add(record.getServiceEvent(this)); 9513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman serviceEvents.add(new ServiceEventImpl(this, record.getType(), toUnqualifiedName(record.getType(), record.getName()), record.getServiceInfo())); 9523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Actually call listener with all service events added above 9563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceEvent serviceEvent : serviceEvents) { 9573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman status.serviceAdded(serviceEvent); 9583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Create/start ServiceResolver 9603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startServiceResolver(type); 9613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 9643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 9653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 9663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 9673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void removeServiceListener(String type, ServiceListener listener) { 9683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String loType = type.toLowerCase(); 9693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<ServiceListenerStatus> list = _serviceListeners.get(loType); 9703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list != null) { 9713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (list) { 9723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceListenerStatus status = new ServiceListenerStatus(listener, ListenerStatus.ASYNCHONEOUS); 9733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman list.remove(status); 9743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list.isEmpty()) { 9753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _serviceListeners.remove(loType, list); 9763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 9823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 9833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 9843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 9853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void registerService(ServiceInfo infoAbstract) throws IOException { 9863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isClosing() || this.isClosed()) { 9873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IllegalStateException("This DNS is closed."); 9883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfoImpl info = (ServiceInfoImpl) infoAbstract; 9903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 9913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info.getDns() != null) { 9923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info.getDns() != this) { 9933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IllegalStateException("A service information can only be registered with a single instamce of JmDNS."); 9943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else if (_services.get(info.getKey()) != null) { 9953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman throw new IllegalStateException("A service information can only be registered once."); 9963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 9983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.setDns(this); 9993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.registerServiceType(info.getTypeWithSubtype()); 10013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // bind the service to this address 10033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.recoverState(); 10043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.setServer(_localHost.getName()); 10053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.addAddress(_localHost.getInet4Address()); 10063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.addAddress(_localHost.getInet6Address()); 10073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.waitForAnnounced(DNSConstants.SERVICE_INFO_TIMEOUT); 10093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.makeServiceNameUnique(info); 10113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman while (_services.putIfAbsent(info.getKey(), info) != null) { 10123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.makeServiceNameUnique(info); 10133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startProber(); 10163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.waitForAnnounced(DNSConstants.SERVICE_INFO_TIMEOUT); 10173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 10193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine("registerService() JmDNS registered service as " + info); 10203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 10243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 10253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 10263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 10273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void unregisterService(ServiceInfo infoAbstract) { 10283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfoImpl info = (ServiceInfoImpl) _services.get(infoAbstract.getKey()); 10293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info != null) { 10313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.cancelState(); 10323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startCanceler(); 10333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.waitForCanceled(DNSConstants.CLOSE_TIMEOUT); 10343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _services.remove(info.getKey(), info); 10363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 10373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine("unregisterService() JmDNS unregistered service as " + info); 10383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 10403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.warning("Removing unregistered service info: " + infoAbstract.getKey()); 10413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 10453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 10463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 10473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 10483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void unregisterAllServices() { 10493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 10503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("unregisterAllServices()"); 10513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String name : _services.keySet()) { 10543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl info = (ServiceInfoImpl) _services.get(name); 10553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info != null) { 10563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 10573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Cancelling service info: " + info); 10583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.cancelState(); 10603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startCanceler(); 10633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String name : _services.keySet()) { 10653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl info = (ServiceInfoImpl) _services.get(name); 10663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info != null) { 10673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 10683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Wait for service info cancel: " + info); 10693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.waitForCanceled(DNSConstants.CLOSE_TIMEOUT); 10713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _services.remove(name, info); 10723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 10783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 10793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 10803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 10813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public boolean registerServiceType(String type) { 10823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean typeAdded = false; 10833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Map<Fields, String> map = ServiceInfoImpl.decodeQualifiedNameMapForType(type); 10843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String domain = map.get(Fields.Domain); 10853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String protocol = map.get(Fields.Protocol); 10863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String application = map.get(Fields.Application); 10873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String subtype = map.get(Fields.Subtype); 10883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 10893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final String name = (application.length() > 0 ? "_" + application + "." : "") + (protocol.length() > 0 ? "_" + protocol + "." : "") + domain + "."; 10903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final String loname = name.toLowerCase(); 10913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 10923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine(this.getName() + ".registering service type: " + type + " as: " + name + (subtype.length() > 0 ? " subtype: " + subtype : "")); 10933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 10943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!_serviceTypes.containsKey(loname) && !application.toLowerCase().equals("dns-sd") && !domain.toLowerCase().endsWith("in-addr.arpa") && !domain.toLowerCase().endsWith("ip6.arpa")) { 10953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman typeAdded = _serviceTypes.putIfAbsent(loname, new ServiceTypeEntry(name)) == null; 10963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (typeAdded) { 10973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceTypeListenerStatus[] list = _typeListeners.toArray(new ServiceTypeListenerStatus[_typeListeners.size()]); 10983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceEvent event = new ServiceEventImpl(this, name, "", null); 10993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (final ServiceTypeListenerStatus status : list) { 11003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.submit(new Runnable() { 11013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 11023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 11033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 11043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman status.serviceTypeAdded(event); 11053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }); 11073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (subtype.length() > 0) { 11113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceTypeEntry subtypes = _serviceTypes.get(loname); 11123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((subtypes != null) && (!subtypes.contains(subtype))) { 11133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (subtypes) { 11143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!subtypes.contains(subtype)) { 11153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman typeAdded = true; 11163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman subtypes.add(subtype); 11173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceTypeListenerStatus[] list = _typeListeners.toArray(new ServiceTypeListenerStatus[_typeListeners.size()]); 11183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceEvent event = new ServiceEventImpl(this, "_" + subtype + "._sub." + name, "", null); 11193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (final ServiceTypeListenerStatus status : list) { 11203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.submit(new Runnable() { 11213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 11223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 11233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 11243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman status.subTypeForServiceTypeAdded(event); 11253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }); 11273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return typeAdded; 11333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 11363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Generate a possibly unique name for a service using the information we have in the cache. 11373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 11383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return returns true, if the name of the service info had to be changed. 11393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 11403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private boolean makeServiceNameUnique(ServiceInfoImpl info) { 11413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final String originalQualifiedName = info.getKey(); 11423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final long now = System.currentTimeMillis(); 11433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean collision; 11453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman do { 11463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman collision = false; 11473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Check for collision in cache 11493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSEntry dnsEntry : this.getCache().getDNSEntryList(info.getKey())) { 11503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (DNSRecordType.TYPE_SRV.equals(dnsEntry.getRecordType()) && !dnsEntry.isExpired(now)) { 11513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final DNSRecord.Service s = (DNSRecord.Service) dnsEntry; 11523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (s.getPort() != info.getPort() || !s.getServer().equals(_localHost.getName())) { 11533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 11543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("makeServiceNameUnique() JmDNS.makeServiceNameUnique srv collision:" + dnsEntry + " s.server=" + s.getServer() + " " + _localHost.getName() + " equals:" + (s.getServer().equals(_localHost.getName()))); 11553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.setName(incrementName(info.getName())); 11573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman collision = true; 11583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 11593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Check for collision with other service infos published by JmDNS 11643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceInfo selfService = _services.get(info.getKey()); 11653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (selfService != null && selfService != info) { 11663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info.setName(incrementName(info.getName())); 11673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman collision = true; 11683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman while (collision); 11713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return !(originalQualifiedName.equals(info.getKey())); 11733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String incrementName(String name) { 11763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String aName = name; 11773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 11783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final int l = aName.lastIndexOf('('); 11793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final int r = aName.lastIndexOf(')'); 11803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((l >= 0) && (l < r)) { 11813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aName = aName.substring(0, l) + "(" + (Integer.parseInt(aName.substring(l + 1, r)) + 1) + ")"; 11823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 11833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aName += " (2)"; 11843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final NumberFormatException e) { 11863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aName += " (2)"; 11873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return aName; 11893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 11903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 11913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 11923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 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. 11933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 11943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param listener 11953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DSN listener 11963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param question 11973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DNS query 11983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 11993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void addListener(DNSListener listener, DNSQuestion question) { 12003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final long now = System.currentTimeMillis(); 12013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // add the new listener 12033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _listeners.add(listener); 12043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // report existing matched records 12063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (question != null) { 12083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSEntry dnsEntry : this.getCache().getDNSEntryList(question.getName().toLowerCase())) { 12093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (question.answeredBy(dnsEntry) && !dnsEntry.isExpired(now)) { 12103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.updateRecord(this.getCache(), now, dnsEntry); 12113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 12173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Remove a listener from all outstanding questions. The listener will no longer receive any updates. 12183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 12193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param listener 12203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DSN listener 12213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 12223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void removeListener(DNSListener listener) { 12233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _listeners.remove(listener); 12243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 12273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Renew a service when the record become stale. If there is no service collector for the type this method does nothing. 12283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 12293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param record 12303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DNS record 12313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 12323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void renewServiceCollector(DNSRecord record) { 12333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo info = record.getServiceInfo(); 12343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_serviceCollectors.containsKey(info.getType().toLowerCase())) { 12353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Create/start ServiceResolver 12363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startServiceResolver(info.getType()); 12373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Remind: Method updateRecord should receive a better name. 12413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 12423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Notify all listeners that a record was updated. 12433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 12443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param now 12453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * update date 12463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 12473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DNS record 12483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param operation 12493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * DNS cache operation 12503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 12513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void updateRecord(long now, DNSRecord rec, Operation operation) { 12523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We do not want to block the entire DNS while we are updating the record for each listener (service info) 12533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman { 12543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<DNSListener> listenerList = null; 12553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (_listeners) { 12563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listenerList = new ArrayList<DNSListener>(_listeners); 12573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSListener listener : listenerList) { 12593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.updateRecord(this.getCache(), now, rec); 12603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (DNSRecordType.TYPE_PTR.equals(rec.getRecordType())) 12633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // if (DNSRecordType.TYPE_PTR.equals(rec.getRecordType()) || DNSRecordType.TYPE_SRV.equals(rec.getRecordType())) 12643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman { 12653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceEvent event = rec.getServiceEvent(this); 12663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((event.getInfo() == null) || !event.getInfo().hasData()) { 12673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We do not care about the subtype because the info is only used if complete and the subtype will then be included. 12683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo info = this.getServiceInfoFromCache(event.getType(), event.getName(), "", false); 12693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info.hasData()) { 12703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman event = new ServiceEventImpl(this, event.getType(), event.getName(), info); 12713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<ServiceListenerStatus> list = _serviceListeners.get(event.getType().toLowerCase()); 12753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final List<ServiceListenerStatus> serviceListenerList; 12763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list != null) { 12773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (list) { 12783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman serviceListenerList = new ArrayList<ServiceListenerStatus>(list); 12793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 12813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman serviceListenerList = Collections.emptyList(); 12823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINEST)) { 12843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finest(this.getName() + ".updating record for event: " + event + " list " + serviceListenerList + " operation: " + operation); 12853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 12863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!serviceListenerList.isEmpty()) { 12873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final ServiceEvent localEvent = event; 12883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 12893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman switch (operation) { 12903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman case Add: 12913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (final ServiceListenerStatus listener : serviceListenerList) { 12923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (listener.isSynchronous()) { 12933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.serviceAdded(localEvent); 12943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 12953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.submit(new Runnable() { 12963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 12973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 12983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 12993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.serviceAdded(localEvent); 13003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }); 13023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 13053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman case Remove: 13063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (final ServiceListenerStatus listener : serviceListenerList) { 13073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (listener.isSynchronous()) { 13083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.serviceRemoved(localEvent); 13093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.submit(new Runnable() { 13113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 13123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 13133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 13143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman listener.serviceRemoved(localEvent); 13153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }); 13173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 13203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman default: 13213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 13223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 13273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void handleRecord(DNSRecord record, long now) { 13283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSRecord newRecord = record; 13293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 13303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Operation cacheOperation = Operation.Noop; 13313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final boolean expired = newRecord.isExpired(now); 13323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 13333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine(this.getName() + " handle response: " + newRecord); 13343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 13363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // update the cache 13373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!newRecord.isServicesDiscoveryMetaQuery() && !newRecord.isDomainDiscoveryQuery()) { 13383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final boolean unique = newRecord.isUnique(); 13393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final DNSRecord cachedRecord = (DNSRecord) this.getCache().getDNSEntry(newRecord); 13403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 13413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine(this.getName() + " handle response cached record: " + cachedRecord); 13423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (unique) { 13443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSEntry entry : this.getCache().getDNSEntryList(newRecord.getKey())) { 13453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newRecord.getRecordType().equals(entry.getRecordType()) && newRecord.getRecordClass().equals(entry.getRecordClass()) && (entry != cachedRecord)) { 13463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ((DNSRecord) entry).setWillExpireSoon(now); 13473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cachedRecord != null) { 13513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (expired) { 13523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // if the record has a 0 ttl that means we have a cancel record we need to delay the removal by 1s 13533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newRecord.getTTL() == 0) { 13543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.Noop; 13553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedRecord.setWillExpireSoon(now); 13563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // the actual record will be disposed of by the record reaper. 13573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.Remove; 13593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().removeDNSEntry(cachedRecord); 13603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // If the record content has changed we need to inform our listeners. 13633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!newRecord.sameValue(cachedRecord) || (!newRecord.sameSubtype(cachedRecord) && (newRecord.getSubtype().length() > 0))) { 13643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newRecord.isSingleValued()) { 13653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.Update; 13663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().replaceDNSEntry(newRecord, cachedRecord); 13673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Address record can have more than one value on multi-homed machines 13693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.Add; 13703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().addDNSEntry(newRecord); 13713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cachedRecord.resetTTL(newRecord); 13743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newRecord = cachedRecord; 13753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 13783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!expired) { 13793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.Add; 13803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().addDNSEntry(newRecord); 13813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 13853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Register new service types 13863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newRecord.getRecordType() == DNSRecordType.TYPE_PTR) { 13873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // handle DNSConstants.DNS_META_QUERY records 13883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean typeAdded = false; 13893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newRecord.isServicesDiscoveryMetaQuery()) { 13903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // The service names are in the alias. 13913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!expired) { 13923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman typeAdded = this.registerServiceType(((DNSRecord.Pointer) newRecord).getAlias()); 13933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 13953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 13963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman typeAdded |= this.registerServiceType(newRecord.getName()); 13973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (typeAdded && (cacheOperation == Operation.Noop)) { 13983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cacheOperation = Operation.RegisterServiceType; 13993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // notify the listeners 14033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (cacheOperation != Operation.Noop) { 14043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.updateRecord(now, newRecord, cacheOperation); 14053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 14103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Handle an incoming response. Cache answers, and pass them on to the appropriate questions. 14113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 14123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 14133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 14143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void handleResponse(DNSIncoming msg) throws IOException { 14153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final long now = System.currentTimeMillis(); 14163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean hostConflictDetected = false; 14183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean serviceConflictDetected = false; 14193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord newRecord : msg.getAllAnswers()) { 14213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.handleRecord(newRecord, now); 14223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (DNSRecordType.TYPE_A.equals(newRecord.getRecordType()) || DNSRecordType.TYPE_AAAA.equals(newRecord.getRecordType())) { 14243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman hostConflictDetected |= newRecord.handleResponse(this); 14253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 14263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman serviceConflictDetected |= newRecord.handleResponse(this); 14273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (hostConflictDetected || serviceConflictDetected) { 14323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startProber(); 14333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 14373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Handle an incoming query. See if we can answer any part of it given our service infos. 14383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 14393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param in 14403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param addr 14413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param port 14423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 14433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 14443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void handleQuery(DNSIncoming in, InetAddress addr, int port) throws IOException { 14453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINE)) { 14463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.fine(this.getName() + ".handle query: " + in); 14473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Track known answers 14493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean conflictDetected = false; 14503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final long expirationTime = System.currentTimeMillis() + DNSConstants.KNOWN_ANSWER_TTL; 14513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord answer : in.getAllAnswers()) { 14523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman conflictDetected |= answer.handleQuery(this, expirationTime); 14533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.ioLock(); 14563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 14573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_plannedAnswer != null) { 14593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _plannedAnswer.append(in); 14603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 14613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSIncoming plannedAnswer = in.clone(); 14623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (in.isTruncated()) { 14633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _plannedAnswer = plannedAnswer; 14643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startResponder(plannedAnswer, port); 14663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } finally { 14693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.ioUnlock(); 14703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final long now = System.currentTimeMillis(); 14733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSRecord answer : in.getAnswers()) { 14743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.handleRecord(answer, now); 14753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (conflictDetected) { 14783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.startProber(); 14793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void respondToQuery(DNSIncoming in) { 14833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.ioLock(); 14843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 14853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_plannedAnswer == in) { 14863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _plannedAnswer = null; 14873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } finally { 14893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.ioUnlock(); 14903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 14923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 14933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 14943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Add an answer to a question. Deal with the case when the outgoing packet overflows 14953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 14963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param in 14973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param addr 14983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param port 14993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param out 15003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param rec 15013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return outgoing answer 15023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 15033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSOutgoing addAnswer(DNSIncoming in, InetAddress addr, int port, DNSOutgoing out, DNSRecord rec) throws IOException { 15053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSOutgoing newOut = out; 15063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newOut == null) { 15073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false, in.getSenderUDPPayload()); 15083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 15103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut.addAnswer(in, rec); 15113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final IOException e) { 15123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut.setFlags(newOut.getFlags() | DNSConstants.FLAGS_TC); 15133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut.setId(in.getId()); 15143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman send(newOut); 15153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false, in.getSenderUDPPayload()); 15173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newOut.addAnswer(in, rec); 15183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return newOut; 15203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 15233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Send an outgoing multicast DNS message. 15243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 15253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param out 15263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @exception IOException 15273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void send(DNSOutgoing out) throws IOException { 15293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!out.isEmpty()) { 15303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman byte[] message = out.data(); 15313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final DatagramPacket packet = new DatagramPacket(message, message.length, _group, DNSConstants.MDNS_PORT); 15323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINEST)) { 15343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 15353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final DNSIncoming msg = new DNSIncoming(packet); 15363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINEST)) { 15373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finest("send(" + this.getName() + ") JmDNS out:" + msg.print(true)); 15383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final IOException e) { 15403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.throwing(getClass().toString(), "send(" + this.getName() + ") - JmDNS can not parse what it sends!!!", e); 15413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final MulticastSocket ms = _socket; 15443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (ms != null && !ms.isClosed()) { 15453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ms.send(packet); 15463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#purgeTimer() 15533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 15553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void purgeTimer() { 15563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).purgeTimer(); 15573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#purgeStateTimer() 15623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 15643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void purgeStateTimer() { 15653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).purgeStateTimer(); 15663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#cancelTimer() 15713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 15733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void cancelTimer() { 15743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).cancelTimer(); 15753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#cancelStateTimer() 15803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 15823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void cancelStateTimer() { 15833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).cancelStateTimer(); 15843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startProber() 15893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 15913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startProber() { 15923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startProber(); 15933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 15943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 15953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 15963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 15973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startAnnouncer() 15983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 15993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startAnnouncer() { 16013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startAnnouncer(); 16023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startRenewer() 16073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startRenewer() { 16103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startRenewer(); 16113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startCanceler() 16163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startCanceler() { 16193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startCanceler(); 16203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startReaper() 16253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startReaper() { 16283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startReaper(); 16293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startServiceInfoResolver(javax.jmdns.impl.ServiceInfoImpl) 16343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startServiceInfoResolver(ServiceInfoImpl info) { 16373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startServiceInfoResolver(info); 16383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startTypeResolver() 16433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startTypeResolver() { 16463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startTypeResolver(); 16473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startServiceResolver(java.lang.String) 16523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startServiceResolver(String type) { 16553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startServiceResolver(type); 16563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* 16593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * (non-Javadoc) 16603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see javax.jmdns.impl.DNSTaskStarter#startResponder(javax.jmdns.impl.DNSIncoming, int) 16613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void startResponder(DNSIncoming in, int port) { 16643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSTaskStarter.Factory.getInstance().getStarter(this.getDns()).startResponder(in, port); 16653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // REMIND: Why is this not an anonymous inner class? 16683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 16693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Shutdown operations. 16703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected class Shutdown implements Runnable { 16723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** {@inheritDoc} */ 16733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 16743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 16753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 16763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _shutdown = null; 16773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman close(); 16783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (Throwable exception) { 16793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.err.println("Error while shuting down. " + exception); 16803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final Object _recoverLock = new Object(); 16853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 16873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Recover jmdns when there is an error. 16883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 16893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void recover() { 16903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer(this.getName() + "recover()"); 16913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We have an IO error so lets try to recover if anything happens lets close it. 16923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // This should cover the case of the IP address changing under our feet 16933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isClosing() || this.isClosed() || this.isCanceling() || this.isCanceled()) { 16943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 16953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 16963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 16973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We need some definite lock here as we may have multiple timer running in the same thread that will not be stopped by the reentrant lock 16983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // in the state object. This is only a problem in this case as we are going to execute in seperate thread so that the timer can clear. 16993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (_recoverLock) { 17003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Stop JmDNS 17013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // This protects against recursive calls 17023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.cancelState()) { 17033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer(this.getName() + "recover() thread " + Thread.currentThread().getName()); 17043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Thread recover = new Thread(this.getName() + ".recover()") { 17053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 17063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 17073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 17083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 17093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 17103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman __recover(); 17113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman }; 17133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman recover.start(); 17143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void __recover() { 17193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Synchronize only if we are not already in process to prevent dead locks 17203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 17213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 17223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer(this.getName() + "recover() Cleanning up"); 17233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.warning("RECOVERING"); 17263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Purge the timer 17273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.purgeTimer(); 17283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We need to keep a copy for reregistration 17303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final Collection<ServiceInfo> oldServiceInfos = new ArrayList<ServiceInfo>(getServices().values()); 17313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Cancel all services 17333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.unregisterAllServices(); 17343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.disposeServiceCollectors(); 17353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.waitForCanceled(DNSConstants.CLOSE_TIMEOUT); 17373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Purge the canceler timer 17393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.purgeStateTimer(); 17403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 17423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // close multicast socket 17433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.closeMulticastSocket(); 17443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 17463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().clear(); 17473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 17483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer(this.getName() + "recover() All is clean"); 17493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isCanceled()) { 17523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 17533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // All is clear now start the services 17543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // 17553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo info : oldServiceInfos) { 17563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ((ServiceInfoImpl) info).recoverState(); 17573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.recoverState(); 17593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 17613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.openMulticastSocket(this.getLocalHost()); 17623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.start(oldServiceInfos); 17633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final Exception exception) { 17643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.WARNING, this.getName() + "recover() Start services exception ", exception); 17653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.WARNING, this.getName() + "recover() We are back!"); 17673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 17683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We have a problem. We could not clear the state. 17693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.WARNING, this.getName() + "recover() Could not recover we are Down!"); 17703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getDelegate() != null) { 17713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getDelegate().cannotRecoverFromIOError(this.getDns(), oldServiceInfos); 17723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void cleanCache() { 17783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman long now = System.currentTimeMillis(); 17793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSEntry entry : this.getCache().allValues()) { 17803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 17813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSRecord record = (DNSRecord) entry; 17823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (record.isExpired(now)) { 17833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.updateRecord(now, record, Operation.Remove); 17843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getCache().removeDNSEntry(record); 17853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else if (record.isStale(now)) { 17863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // we should query for the record we care about i.e. those in the service collectors 17873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.renewServiceCollector(record); 17883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (Exception exception) { 17903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.log(Level.SEVERE, this.getName() + ".Error while reaping records: " + entry, exception); 17913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.severe(this.toString()); 17923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 17953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 17963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 17973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 17983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 17993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 18003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void close() { 18013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isClosing()) { 18023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 18033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 18063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Cancelling JmDNS: " + this); 18073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Stop JmDNS 18093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // This protects against recursive calls 18103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.closeState()) { 18113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // We got the tie break now clean up 18123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Stop the timer 18143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Canceling the timer"); 18153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.cancelTimer(); 18163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Cancel all services 18183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.unregisterAllServices(); 18193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.disposeServiceCollectors(); 18203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 18223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Wait for JmDNS cancel: " + this); 18233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.waitForCanceled(DNSConstants.CLOSE_TIMEOUT); 18253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Stop the canceler timer 18273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("Canceling the state timer"); 18283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.cancelStateTimer(); 18293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Stop the executor 18313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _executor.shutdown(); 18323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // close socket 18343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.closeMulticastSocket(); 18353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // remove the shutdown hook 18373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_shutdown != null) { 18383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Runtime.getRuntime().removeShutdownHook(_shutdown); 18393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 18423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("JmDNS closed."); 18433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman advanceState(null); 18463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 18493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 18503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 18513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 18523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Deprecated 18533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void printServices() { 18543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman System.err.println(toString()); 18553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 18573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 18583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 18593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 18603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 18613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String toString() { 18623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final StringBuilder aLog = new StringBuilder(2048); 18633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\t---- Local Host -----"); 18643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t"); 18653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_localHost); 18663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t---- Services -----"); 18673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _services.keySet()) { 18683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tService: "); 18693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(key); 18703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 18713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_services.get(key)); 18723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n"); 18743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\t---- Types ----"); 18753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _serviceTypes.keySet()) { 18763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceTypeEntry subtypes = _serviceTypes.get(key); 18773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tType: "); 18783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(subtypes.getType()); 18793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 18803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(subtypes.isEmpty() ? "no subtypes" : subtypes); 18813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n"); 18833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_cache.toString()); 18843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n"); 18853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\t---- Service Collectors ----"); 18863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _serviceCollectors.keySet()) { 18873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tService Collector: "); 18883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(key); 18893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 18903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_serviceCollectors.get(key)); 18913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 18923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n"); 18933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\t---- Service Listeners ----"); 18943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _serviceListeners.keySet()) { 18953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tService Listener: "); 18963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(key); 18973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 18983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_serviceListeners.get(key)); 18993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return aLog.toString(); 19013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 19053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 19063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 19073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo[] list(String type) { 19083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.list(type, DNSConstants.SERVICE_INFO_TIMEOUT); 19093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 19133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 19143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 19153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo[] list(String type, long timeout) { 19163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.cleanCache(); 19173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Implementation note: The first time a list for a given type is 19183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // requested, a ServiceCollector is created which collects service 19193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // infos. This greatly speeds up the performance of subsequent calls 19203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // to this method. The caveats are, that 1) the first call to this 19213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // method for a given type is slow, and 2) we spawn a ServiceCollector 19223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // instance for each service type which increases network traffic a 19233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // little. 19243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String loType = type.toLowerCase(); 19263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman boolean newCollectorCreated = false; 19283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.isCanceling() || this.isCanceled()) { 19293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return new ServiceInfo[0]; 19303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceCollector collector = _serviceCollectors.get(loType); 19333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (collector == null) { 19343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman newCollectorCreated = _serviceCollectors.putIfAbsent(loType, new ServiceCollector(type)) == null; 19353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman collector = _serviceCollectors.get(loType); 19363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (newCollectorCreated) { 19373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.addServiceListener(type, collector, ListenerStatus.SYNCHONEOUS); 19383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 19413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer(this.getName() + ".collector: " + collector); 19423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // At this stage the collector should never be null but it keeps findbugs happy. 19443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return (collector != null ? collector.list(timeout) : new ServiceInfo[0]); 19453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 19493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 19503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 19513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Map<String, ServiceInfo[]> listBySubtype(String type) { 19523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this.listBySubtype(type, DNSConstants.SERVICE_INFO_TIMEOUT); 19533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 19573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 19583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 19593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Map<String, ServiceInfo[]> listBySubtype(String type, long timeout) { 19603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Map<String, List<ServiceInfo>> map = new HashMap<String, List<ServiceInfo>>(5); 19613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo info : this.list(type, timeout)) { 19623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String subtype = info.getSubtype().toLowerCase(); 19633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!map.containsKey(subtype)) { 19643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman map.put(subtype, new ArrayList<ServiceInfo>(10)); 19653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman map.get(subtype).add(info); 19673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Map<String, ServiceInfo[]> result = new HashMap<String, ServiceInfo[]>(map.size()); 19703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String subtype : map.keySet()) { 19713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<ServiceInfo> infoForSubType = map.get(subtype); 19723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman result.put(subtype, infoForSubType.toArray(new ServiceInfo[infoForSubType.size()])); 19733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return result; 19763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This method disposes all ServiceCollector instances which have been created by calls to method <code>list(type)</code>. 19803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 19813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see #list 19823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 19833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private void disposeServiceCollectors() { 19843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (logger.isLoggable(Level.FINER)) { 19853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger.finer("disposeServiceCollectors()"); 19863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String type : _serviceCollectors.keySet()) { 19883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceCollector collector = _serviceCollectors.get(type); 19893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (collector != null) { 19903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.removeServiceListener(type, collector); 19913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _serviceCollectors.remove(type, collector); 19923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 19953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 19963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 19973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Instances of ServiceCollector are used internally to speed up the performance of method <code>list(type)</code>. 19983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 19993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @see #list 20003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private static class ServiceCollector implements ServiceListener { 20023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // private static Logger logger = Logger.getLogger(ServiceCollector.class.getName()); 20033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * A set of collected service instance names. 20063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, ServiceInfo> _infos; 20083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * A set of collected service event waiting to be resolved. 20113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final ConcurrentMap<String, ServiceEvent> _events; 20133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is the type we are listening for (only used for debugging). 20163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final String _type; 20183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is used to force a wait on the first invocation of list. 20213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private volatile boolean _needToWaitForInfos; 20233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceCollector(String type) { 20253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(); 20263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _infos = new ConcurrentHashMap<String, ServiceInfo>(); 20273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _events = new ConcurrentHashMap<String, ServiceEvent>(); 20283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _type = type; 20293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _needToWaitForInfos = true; 20303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * A service has been added. 20343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 20353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param event 20363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * service event 20373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 20393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void serviceAdded(ServiceEvent event) { 20403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this) { 20413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfo info = event.getInfo(); 20423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if ((info != null) && (info.hasData())) { 20433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _infos.put(event.getName(), info); 20443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 20453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String subtype = (info != null ? info.getSubtype() : ""); 20463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman info = ((JmDNSImpl) event.getDNS()).resolveServiceInfo(event.getType(), event.getName(), subtype, true); 20473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info != null) { 20483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _infos.put(event.getName(), info); 20493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 20503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _events.put(event.getName(), event); 20513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * A service has been removed. 20583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 20593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param event 20603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * service event 20613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 20633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void serviceRemoved(ServiceEvent event) { 20643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this) { 20653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _infos.remove(event.getName()); 20663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _events.remove(event.getName()); 20673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * A service has been resolved. Its details are now available in the ServiceInfo record. 20723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 20733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param event 20743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * service event 20753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 20773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void serviceResolved(ServiceEvent event) { 20783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this) { 20793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _infos.put(event.getName(), event.getInfo()); 20803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _events.remove(event.getName()); 20813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 20843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 20853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Returns an array of all service infos which have been collected by this ServiceCollector. 20863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 20873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param timeout 20883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * timeout if the info list is empty. 20893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return Service Info array 20903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 20913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public ServiceInfo[] list(long timeout) { 20923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_infos.isEmpty() || !_events.isEmpty() || _needToWaitForInfos) { 20933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman long loops = (timeout / 200L); 20943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (loops < 1) { 20953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman loops = 1; 20963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 20973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (int i = 0; i < loops; i++) { 20983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 20993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Thread.sleep(200); 21003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (final InterruptedException e) { 21013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /* Stub */ 21023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_events.isEmpty() && !_infos.isEmpty() && !_needToWaitForInfos) { 21043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman break; 21053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _needToWaitForInfos = false; 21093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _infos.values().toArray(new ServiceInfo[_infos.size()]); 21103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 21133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * {@inheritDoc} 21143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 21153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 21163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public String toString() { 21173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman final StringBuffer aLog = new StringBuffer(); 21183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\tType: "); 21193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_type); 21203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_infos.isEmpty()) { 21213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\tNo services collected."); 21223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 21233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\tServices"); 21243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _infos.keySet()) { 21253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tService: "); 21263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(key); 21273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 21283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_infos.get(key)); 21293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (_events.isEmpty()) { 21323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\tNo event queued."); 21333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 21343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\tEvents"); 21353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (String key : _events.keySet()) { 21363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append("\n\t\tEvent: "); 21373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(key); 21383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(": "); 21393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman aLog.append(_events.get(key)); 21403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return aLog.toString(); 21433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman static String toUnqualifiedName(String type, String qualifiedName) { 21473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String loType = type.toLowerCase(); 21483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman String loQualifiedName = qualifiedName.toLowerCase(); 21493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (loQualifiedName.endsWith(loType) && !(loQualifiedName.equals(loType))) { 21503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return qualifiedName.substring(0, qualifiedName.length() - type.length() - 1); 21513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return qualifiedName; 21533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Map<String, ServiceInfo> getServices() { 21563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _services; 21573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void setLastThrottleIncrement(long lastThrottleIncrement) { 21603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._lastThrottleIncrement = lastThrottleIncrement; 21613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public long getLastThrottleIncrement() { 21643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _lastThrottleIncrement; 21653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void setThrottle(int throttle) { 21683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._throttle = throttle; 21693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public int getThrottle() { 21723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _throttle; 21733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static Random getRandom() { 21763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _random; 21773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void ioLock() { 21803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _ioLock.lock(); 21813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void ioUnlock() { 21843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _ioLock.unlock(); 21853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void setPlannedAnswer(DNSIncoming plannedAnswer) { 21883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._plannedAnswer = plannedAnswer; 21893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSIncoming getPlannedAnswer() { 21923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _plannedAnswer; 21933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman void setLocalHost(HostInfo localHost) { 21963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._localHost = localHost; 21973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 21983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 21993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Map<String, ServiceTypeEntry> getServiceTypes() { 22003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _serviceTypes; 22013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 22023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 22033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public MulticastSocket getSocket() { 22043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _socket; 22053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 22063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 22073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public InetAddress getGroup() { 22083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _group; 22093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 22103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 22113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 22123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Delegate getDelegate() { 22133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._delegate; 22143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 22153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 22163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 22173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public Delegate setDelegate(Delegate delegate) { 22183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman Delegate previous = this._delegate; 22193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._delegate = delegate; 22203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return previous; 22213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 22223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 22233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman} 2224