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 { DNS4Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)31 DNS4Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 32 super(name, type, recordClass, unique); 33 } 34 35 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 { DNS6Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)55 DNS6Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 56 super(name, type, recordClass, unique); 57 } 58 59 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 { HostInformation(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)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 { Pointer(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)88 Pointer(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 89 super(name, type, recordClass, unique); 90 } 91 92 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 { Service(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)128 Service(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 129 super(name, type, recordClass, unique); 130 } 131 132 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 { Text(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)162 Text(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 163 super(name, type, recordClass, unique); 164 } 165 166 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 { AllRecords(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)183 AllRecords(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { 184 super(name, type, recordClass, unique); 185 } 186 187 @Override isSameType(DNSEntry entry)188 public boolean isSameType(DNSEntry entry) { 189 // We match all non null entry 190 return (entry != null); 191 } 192 193 @Override addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)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 iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 DNSQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)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 */ newQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique)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 */ answeredBy(DNSEntry rec)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 */ addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers)274 public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { 275 // By default we do nothing 276 } 277 addAnswersForServiceInfo(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers, ServiceInfoImpl info)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 isStale(long now)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 isExpired(long now)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 */ iAmTheOnlyOne(JmDNSImpl jmDNSImpl)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 toString(StringBuilder aLog)324 public void toString(StringBuilder aLog) { 325 // do nothing 326 } 327 328 }