// Copyright 2003-2005 Arthur van Hoff, Rick Blair // Licensed under Apache License version 2.0 // Original license LGPL package javax.jmdns.impl; import java.net.InetAddress; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceInfo.Fields; import javax.jmdns.impl.JmDNSImpl.ServiceTypeEntry; import javax.jmdns.impl.constants.DNSConstants; import javax.jmdns.impl.constants.DNSRecordClass; import javax.jmdns.impl.constants.DNSRecordType; /** * A DNS question. * * @author Arthur van Hoff, Pierre Frisch */ public class DNSQuestion extends DNSEntry { private static Logger logger = Logger.getLogger(DNSQuestion.class.getName()); /** * Address question. */ private static class DNS4Address extends DNSQuestion { DNS4Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { DNSRecord answer = jmDNSImpl.getLocalHost().getDNSAddressRecord(this.getRecordType(), DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL); if (answer != null) { answers.add(answer); } } @Override public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { String name = this.getName().toLowerCase(); return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name); } } /** * Address question. */ private static class DNS6Address extends DNSQuestion { DNS6Address(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { DNSRecord answer = jmDNSImpl.getLocalHost().getDNSAddressRecord(this.getRecordType(), DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL); if (answer != null) { answers.add(answer); } } @Override public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { String name = this.getName().toLowerCase(); return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name); } } /** * Host Information question. */ private static class HostInformation extends DNSQuestion { HostInformation(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } } /** * Pointer question. */ private static class Pointer extends DNSQuestion { Pointer(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { // find matching services for (ServiceInfo serviceInfo : jmDNSImpl.getServices().values()) { this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) serviceInfo); } if (this.isServicesDiscoveryMetaQuery()) { for (String serviceType : jmDNSImpl.getServiceTypes().keySet()) { ServiceTypeEntry typeEntry = jmDNSImpl.getServiceTypes().get(serviceType); answers.add(new DNSRecord.Pointer("_services._dns-sd._udp.local.", DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL, typeEntry.getType())); } } else if (this.isReverseLookup()) { String ipValue = this.getQualifiedNameMap().get(Fields.Instance); if ((ipValue != null) && (ipValue.length() > 0)) { InetAddress address = jmDNSImpl.getLocalHost().getInetAddress(); String hostIPAddress = (address != null ? address.getHostAddress() : ""); if (ipValue.equalsIgnoreCase(hostIPAddress)) { if (this.isV4ReverseLookup()) { answers.add(jmDNSImpl.getLocalHost().getDNSReverseAddressRecord(DNSRecordType.TYPE_A, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL)); } if (this.isV6ReverseLookup()) { answers.add(jmDNSImpl.getLocalHost().getDNSReverseAddressRecord(DNSRecordType.TYPE_AAAA, DNSRecordClass.NOT_UNIQUE, DNSConstants.DNS_TTL)); } } } } else if (this.isDomainDiscoveryQuery()) { // FIXME [PJYF Nov 16 2010] We do not currently support domain discovery } } } /** * Service question. */ private static class Service extends DNSQuestion { Service(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { String loname = this.getName().toLowerCase(); if (jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(loname)) { // type = DNSConstants.TYPE_A; answers.addAll(jmDNSImpl.getLocalHost().answers(this.isUnique(), DNSConstants.DNS_TTL)); return; } // Service type request if (jmDNSImpl.getServiceTypes().containsKey(loname)) { DNSQuestion question = new Pointer(this.getName(), DNSRecordType.TYPE_PTR, this.getRecordClass(), this.isUnique()); question.addAnswers(jmDNSImpl, answers); return; } this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(loname)); } @Override public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { String name = this.getName().toLowerCase(); return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name); } } /** * Text question. */ private static class Text extends DNSQuestion { Text(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(this.getName().toLowerCase())); } @Override public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { String name = this.getName().toLowerCase(); return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name); } } /** * AllRecords question. */ private static class AllRecords extends DNSQuestion { AllRecords(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } @Override public boolean isSameType(DNSEntry entry) { // We match all non null entry return (entry != null); } @Override public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { String loname = this.getName().toLowerCase(); if (jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(loname)) { // type = DNSConstants.TYPE_A; answers.addAll(jmDNSImpl.getLocalHost().answers(this.isUnique(), DNSConstants.DNS_TTL)); return; } // Service type request if (jmDNSImpl.getServiceTypes().containsKey(loname)) { DNSQuestion question = new Pointer(this.getName(), DNSRecordType.TYPE_PTR, this.getRecordClass(), this.isUnique()); question.addAnswers(jmDNSImpl, answers); return; } this.addAnswersForServiceInfo(jmDNSImpl, answers, (ServiceInfoImpl) jmDNSImpl.getServices().get(loname)); } @Override public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { String name = this.getName().toLowerCase(); return jmDNSImpl.getLocalHost().getName().equals(name) || jmDNSImpl.getServices().keySet().contains(name); } } DNSQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { super(name, type, recordClass, unique); } /** * Create a question. * * @param name * DNS name to be resolved * @param type * Record type to resolve * @param recordClass * Record class to resolve * @param unique * Request unicast response (Currently not supported in this implementation) * @return new question */ public static DNSQuestion newQuestion(String name, DNSRecordType type, DNSRecordClass recordClass, boolean unique) { switch (type) { case TYPE_A: return new DNS4Address(name, type, recordClass, unique); case TYPE_A6: return new DNS6Address(name, type, recordClass, unique); case TYPE_AAAA: return new DNS6Address(name, type, recordClass, unique); case TYPE_ANY: return new AllRecords(name, type, recordClass, unique); case TYPE_HINFO: return new HostInformation(name, type, recordClass, unique); case TYPE_PTR: return new Pointer(name, type, recordClass, unique); case TYPE_SRV: return new Service(name, type, recordClass, unique); case TYPE_TXT: return new Text(name, type, recordClass, unique); default: return new DNSQuestion(name, type, recordClass, unique); } } /** * Check if this question is answered by a given DNS record. */ boolean answeredBy(DNSEntry rec) { return this.isSameRecordClass(rec) && this.isSameType(rec) && this.getName().equals(rec.getName()); } /** * Adds answers to the list for our question. * * @param jmDNSImpl * DNS holding the records * @param answers * List of previous answer to append. */ public void addAnswers(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers) { // By default we do nothing } protected void addAnswersForServiceInfo(JmDNSImpl jmDNSImpl, Set<DNSRecord> answers, ServiceInfoImpl info) { if ((info != null) && info.isAnnounced()) { if (this.getName().equalsIgnoreCase(info.getQualifiedName()) || this.getName().equalsIgnoreCase(info.getType())) { answers.addAll(jmDNSImpl.getLocalHost().answers(DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL)); answers.addAll(info.answers(DNSRecordClass.UNIQUE, DNSConstants.DNS_TTL, jmDNSImpl.getLocalHost())); } if (logger.isLoggable(Level.FINER)) { logger.finer(jmDNSImpl.getName() + " DNSQuestion(" + this.getName() + ").addAnswersForServiceInfo(): info: " + info + "\n" + answers); } } } /* * (non-Javadoc) * @see javax.jmdns.impl.DNSEntry#isStale(long) */ @Override public boolean isStale(long now) { return false; } /* * (non-Javadoc) * @see javax.jmdns.impl.DNSEntry#isExpired(long) */ @Override public boolean isExpired(long now) { return false; } /** * Checks if we are the only to be able to answer that question. * * @param jmDNSImpl * DNS holding the records * @return <code>true</code> if we are the only one with the answer to the question, <code>false</code> otherwise. */ public boolean iAmTheOnlyOne(JmDNSImpl jmDNSImpl) { return false; } /* * (non-Javadoc) * @see javax.jmdns.impl.DNSEntry#toString(java.lang.StringBuilder) */ @Override public void toString(StringBuilder aLog) { // do nothing } }