Home | History | Annotate | Download | only in impl
      1 // Copyright 2003-2005 Arthur van Hoff, Rick Blair
      2 // Licensed under Apache License version 2.0
      3 // Original license LGPL
      4 
      5 package javax.jmdns.impl;
      6 
      7 import java.net.InetAddress;
      8 import java.util.Set;
      9 import java.util.logging.Level;
     10 import java.util.logging.Logger;
     11 
     12 import javax.jmdns.ServiceInfo;
     13 import javax.jmdns.ServiceInfo.Fields;
     14 import javax.jmdns.impl.JmDNSImpl.ServiceTypeEntry;
     15 import javax.jmdns.impl.constants.DNSConstants;
     16 import javax.jmdns.impl.constants.DNSRecordClass;
     17 import javax.jmdns.impl.constants.DNSRecordType;
     18 
     19 /**
     20  * A DNS question.
     21  *
     22  * @author Arthur van Hoff, Pierre Frisch
     23  */
     24 public class DNSQuestion extends DNSEntry {
     25     private static Logger logger = Logger.getLogger(DNSQuestion.class.getName());
     26 
     27     /**
     28      * Address question.
     29      */
     30     private static class DNS4Address extends DNSQuestion {
     31         DNS4Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
     32             super(name, type, recordClass, unique);
     33         }
     34 
     35         @Override
     36         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
     37             DNSRecord answer = jmDNSImpl.getLocalHost().getDNSAddressRecord(this.getRecordType(), DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL);
     38             if (answer != null) {
     39                 answers.add(answer);
     40             }
     41         }
     42 
     43         @Override
     44         public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
     45             String name = this.getName().toLowerCase();
     46             return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name);
     47         }
     48 
     49     }
     50 
     51     /**
     52      * Address question.
     53      */
     54     private static class DNS6Address extends DNSQuestion {
     55         DNS6Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
     56             super(name, type, recordClass, unique);
     57         }
     58 
     59         @Override
     60         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
     61             DNSRecord answer = jmDNSImpl.getLocalHost().getDNSAddressRecord(this.getRecordType(), DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL);
     62             if (answer != null) {
     63                 answers.add(answer);
     64             }
     65         }
     66 
     67         @Override
     68         public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
     69             String name = this.getName().toLowerCase();
     70             return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name);
     71         }
     72 
     73     }
     74 
     75     /**
     76      * Host Information question.
     77      */
     78     private static class HostInformation extends DNSQuestion {
     79         HostInformation(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
     80             super(name, type, recordClass, unique);
     81         }
     82     }
     83 
     84     /**
     85      * Pointer question.
     86      */
     87     private static class Pointer extends DNSQuestion {
     88         Pointer(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
     89             super(name, type, recordClass, unique);
     90         }
     91 
     92         @Override
     93         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
     94             // find matching services
     95             for (ServiceInfo serviceInfo : jmDNSImpl.getServices().values()) {
     96                 this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) serviceInfo);
     97             }
     98             if (this.isServicesDiscoveryMetaQuery()) {
     99                 for (String serviceType : jmDNSImpl.getServiceTypes().keySet()) {
    100                     ServiceTypeEntry typeEntry = jmDNSImpl.getServiceTypes().get(serviceType);
    101                     answers.add(new DNSRecord.Pointer("_services._dns-sd._udp.local.", DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL, typeEntry.getType()));
    102                 }
    103             } else if (this.isReverseLookup()) {
    104                 String ipValue = this.getQualifiedNameMap().get(Fields.Instance);
    105                 if ((ipValue != null) && (ipValue.length() > 0)) {
    106                     InetAddress address = jmDNSImpl.getLocalHost().getInetAddress();
    107                     String hostIPAddress = (address != null ? address.getHostAddress() : "");
    108                     if (ipValue.equalsIgnoreCase(hostIPAddress)) {
    109                         if (this.isV4ReverseLookup()) {
    110                             answers.add(jmDNSImpl.getLocalHost().getDNSReverseAddressRecord(DNSRecordType.TYPE_A, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL));
    111                         }
    112                         if (this.isV6ReverseLookup()) {
    113                             answers.add(jmDNSImpl.getLocalHost().getDNSReverseAddressRecord(DNSRecordType.TYPE_AAAA, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL));
    114                         }
    115                     }
    116                 }
    117             } else if (this.isDomainDiscoveryQuery()) {
    118                 // FIXME [PJYF Nov 16 2010] We do not currently support domain discovery
    119             }
    120         }
    121 
    122     }
    123 
    124     /**
    125      * Service question.
    126      */
    127     private static class Service extends DNSQuestion {
    128         Service(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
    129             super(name, type, recordClass, unique);
    130         }
    131 
    132         @Override
    133         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
    134             String loname = this.getName().toLowerCase();
    135             if (jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(loname)) {
    136                 // type = DNSConstants.TYPE_A;
    137                 answers.addAll(jmDNSImpl.getLocalHost().answers(this.isUnique(), DNSConstants.DNS_TTL));
    138                 return;
    139             }
    140             // Service type request
    141             if (jmDNSImpl.getServiceTypes().containsKey(loname)) {
    142                 DNSQuestion question = new Pointer(this.getName(), DNSRecordType.TYPE_PTR, this.getRecordClass(), this.isUnique());
    143                 question.addAnswers(jmDNSImpl, answers);
    144                 return;
    145             }
    146 
    147             this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(loname));
    148         }
    149 
    150         @Override
    151         public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
    152             String name = this.getName().toLowerCase();
    153             return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name);
    154         }
    155 
    156     }
    157 
    158     /**
    159      * Text question.
    160      */
    161     private static class Text extends DNSQuestion {
    162         Text(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
    163             super(name, type, recordClass, unique);
    164         }
    165 
    166         @Override
    167         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
    168             this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(this.getName().toLowerCase()));
    169         }
    170 
    171         @Override
    172         public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
    173             String name = this.getName().toLowerCase();
    174             return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name);
    175         }
    176 
    177     }
    178 
    179     /**
    180      * AllRecords question.
    181      */
    182     private static class AllRecords extends DNSQuestion {
    183         AllRecords(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
    184             super(name, type, recordClass, unique);
    185         }
    186 
    187         @Override
    188         public boolean isSameType(DNSEntry entry) {
    189             // We match all non null entry
    190             return (entry != null);
    191         }
    192 
    193         @Override
    194         public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
    195             String loname = this.getName().toLowerCase();
    196             if (jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(loname)) {
    197                 // type = DNSConstants.TYPE_A;
    198                 answers.addAll(jmDNSImpl.getLocalHost().answers(this.isUnique(), DNSConstants.DNS_TTL));
    199                 return;
    200             }
    201             // Service type request
    202             if (jmDNSImpl.getServiceTypes().containsKey(loname)) {
    203                 DNSQuestion question = new Pointer(this.getName(), DNSRecordType.TYPE_PTR, this.getRecordClass(), this.isUnique());
    204                 question.addAnswers(jmDNSImpl, answers);
    205                 return;
    206             }
    207 
    208             this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(loname));
    209         }
    210 
    211         @Override
    212         public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
    213             String name = this.getName().toLowerCase();
    214             return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name);
    215         }
    216 
    217     }
    218 
    219     DNSQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
    220         super(name, type, recordClass, unique);
    221     }
    222 
    223     /**
    224      * Create a question.
    225      *
    226      * @param name
    227      *            DNS name to be resolved
    228      * @param type
    229      *            Record type to resolve
    230      * @param recordClass
    231      *            Record class to resolve
    232      * @param unique
    233      *            Request unicast response (Currently not supported in this implementation)
    234      * @return new question
    235      */
    236     public static DNSQuestion newQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) {
    237         switch (type) {
    238             case TYPE_A:
    239                 return new DNS4Address(name, type, recordClass, unique);
    240             case TYPE_A6:
    241                 return new DNS6Address(name, type, recordClass, unique);
    242             case TYPE_AAAA:
    243                 return new DNS6Address(name, type, recordClass, unique);
    244             case TYPE_ANY:
    245                 return new AllRecords(name, type, recordClass, unique);
    246             case TYPE_HINFO:
    247                 return new HostInformation(name, type, recordClass, unique);
    248             case TYPE_PTR:
    249                 return new Pointer(name, type, recordClass, unique);
    250             case TYPE_SRV:
    251                 return new Service(name, type, recordClass, unique);
    252             case TYPE_TXT:
    253                 return new Text(name, type, recordClass, unique);
    254             default:
    255                 return new DNSQuestion(name, type, recordClass, unique);
    256         }
    257     }
    258 
    259     /**
    260      * Check if this question is answered by a given DNS record.
    261      */
    262     boolean answeredBy(DNSEntry rec) {
    263         return this.isSameRecordClass(rec) && this.isSameType(rec) && this.getName().equals(rec.getName());
    264     }
    265 
    266     /**
    267      * Adds answers to the list for our question.
    268      *
    269      * @param jmDNSImpl
    270      *            DNS holding the records
    271      * @param answers
    272      *            List of previous answer to append.
    273      */
    274     public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) {
    275         // By default we do nothing
    276     }
    277 
    278     protected void addAnswersForServiceInfo(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers, ServiceInfoImpl info) {
    279         if ((info != null) && info.isAnnounced()) {
    280             if (this.getName().equalsIgnoreCase(info.getQualifiedName()) || this.getName().equalsIgnoreCase(info.getType())) {
    281                 answers.addAll(jmDNSImpl.getLocalHost().answers(DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL));
    282                 answers.addAll(info.answers(DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, jmDNSImpl.getLocalHost()));
    283             }
    284             if (logger.isLoggable(Level.FINER)) {
    285                 logger.finer(jmDNSImpl.getName() + " DNSQuestion(" + this.getName() + ").addAnswersForServiceInfo(): info: " + info + "\n" + answers);
    286             }
    287         }
    288     }
    289 
    290     /*
    291      * (non-Javadoc)
    292      * @see javax.jmdns.impl.DNSEntry#isStale(long)
    293      */
    294     @Override
    295     public boolean isStale(long now) {
    296         return false;
    297     }
    298 
    299     /*
    300      * (non-Javadoc)
    301      * @see javax.jmdns.impl.DNSEntry#isExpired(long)
    302      */
    303     @Override
    304     public boolean isExpired(long now) {
    305         return false;
    306     }
    307 
    308     /**
    309      * Checks if we are the only to be able to answer that question.
    310      *
    311      * @param jmDNSImpl
    312      *            DNS holding the records
    313      * @return <code>true</code> if we are the only one with the answer to the question, <code>false</code> otherwise.
    314      */
    315     public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) {
    316         return false;
    317     }
    318 
    319     /*
    320      * (non-Javadoc)
    321      * @see javax.jmdns.impl.DNSEntry#toString(java.lang.StringBuilder)
    322      */
    323     @Override
    324     public void toString(StringBuilder aLog) {
    325         // do nothing
    326     }
    327 
    328 }