View Javadoc

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 }