diff options
Diffstat (limited to 'providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java')
-rw-r--r-- | providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java | 347 |
1 files changed, 228 insertions, 119 deletions
diff --git a/providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java b/providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java index 069a78941..82eef09f9 100644 --- a/providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java +++ b/providers/bundles/org.eclipse.ecf.provider.jmdns/jmdns/javax/jmdns/impl/tasks/Responder.java @@ -4,178 +4,287 @@ package javax.jmdns.impl.tasks; +import java.net.InetAddress; import java.util.HashSet; -import java.util.Set; -import java.util.Timer; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.Iterator; +import java.util.TimerTask; +//import java.util.logging.Level; +//import java.util.logging.Logger; +import javax.jmdns.impl.DNSConstants; +import javax.jmdns.impl.DNSEntry; import javax.jmdns.impl.DNSIncoming; import javax.jmdns.impl.DNSOutgoing; import javax.jmdns.impl.DNSQuestion; import javax.jmdns.impl.DNSRecord; +import javax.jmdns.impl.DNSState; import javax.jmdns.impl.JmDNSImpl; -import javax.jmdns.impl.constants.DNSConstants; +import javax.jmdns.impl.ServiceInfoImpl; /** - * The Responder sends a single answer for the specified service infos and for the host name. + * The Responder sends a single answer for the specified service infos + * and for the host name. */ -public class Responder extends DNSTask +public class Responder extends TimerTask { - static Logger logger = Logger.getLogger(Responder.class.getName()); +// static Logger logger = Logger.getLogger(Responder.class.getName()); /** - * + * */ - private DNSIncoming _in; + private final JmDNSImpl jmDNSImpl; + private DNSIncoming in; + private InetAddress addr; + private int port; - /** - * - */ - private boolean _unicast; - - public Responder(JmDNSImpl jmDNSImpl, DNSIncoming in, int port) - { - super(jmDNSImpl); - this._in = in; - this._unicast = (port != DNSConstants.MDNS_PORT); - } - - /* - * (non-Javadoc) - * - * @see javax.jmdns.impl.tasks.DNSTask#getName() - */ - @Override - public String getName() + public Responder(JmDNSImpl jmDNSImpl, DNSIncoming in, InetAddress addr, int port) { - return "Responder(" + (this.getDns() != null ? this.getDns().getName() : "") + ")"; + this.jmDNSImpl = jmDNSImpl; + this.in = in; + this.addr = addr; + this.port = port; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() + public void start() { - return super.toString() + " incomming: " + _in; - } - - /* - * (non-Javadoc) - * - * @see javax.jmdns.impl.tasks.DNSTask#start(java.util.Timer) - */ - @Override - public void start(Timer timer) - { - // According to draft-cheshire-dnsext-multicastdns.txt chapter "7 Responding": - // We respond immediately if we know for sure, that we are the only one who can respond to the query. + // According to draft-cheshire-dnsext-multicastdns.txt + // chapter "8 Responding": + // We respond immediately if we know for sure, that we are + // the only one who can respond to the query. // In all other cases, we respond within 20-120 ms. // - // According to draft-cheshire-dnsext-multicastdns.txt chapter "6.2 Multi-Packet Known Answer Suppression": + // According to draft-cheshire-dnsext-multicastdns.txt + // chapter "7.2 Multi-Packet Known Answer Suppression": // We respond after 20-120 ms if the query is truncated. boolean iAmTheOnlyOne = true; - for (DNSQuestion question : _in.getQuestions()) + for (Iterator i = in.getQuestions().iterator(); i.hasNext();) { - if (logger.isLoggable(Level.FINEST)) - { - logger.finest(this.getName() + "start() question=" + question); - } - iAmTheOnlyOne = question.iAmTheOnlyOne(this.getDns()); - if (!iAmTheOnlyOne) + DNSEntry entry = (DNSEntry) i.next(); + if (entry instanceof DNSQuestion) { - break; + DNSQuestion q = (DNSQuestion) entry; +// logger.finest("start() question=" + q); + iAmTheOnlyOne &= (q.getType() == DNSConstants.TYPE_SRV + || q.getType() == DNSConstants.TYPE_TXT + || q.getType() == DNSConstants.TYPE_A + || q.getType() == DNSConstants.TYPE_AAAA + || this.jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(q.getName()) + || this.jmDNSImpl.getServices().containsKey(q.getName().toLowerCase())); + if (!iAmTheOnlyOne) + { + break; + } } } - int delay = (iAmTheOnlyOne && !_in.isTruncated()) ? 0 : DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + JmDNSImpl.getRandom().nextInt(DNSConstants.RESPONSE_MAX_WAIT_INTERVAL - DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) - _in.elapseSinceArrival(); + int delay = (iAmTheOnlyOne && !in.isTruncated()) ? 0 : DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + JmDNSImpl.getRandom().nextInt(DNSConstants.RESPONSE_MAX_WAIT_INTERVAL - DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) - in.elapseSinceArrival(); if (delay < 0) { delay = 0; } - if (logger.isLoggable(Level.FINEST)) - { - logger.finest(this.getName() + "start() Responder chosen delay=" + delay); - } - if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) - { - timer.schedule(this, delay); - } +// logger.finest("start() Responder chosen delay=" + delay); + this.jmDNSImpl.schedule(this, delay); } - @Override public void run() { - this.getDns().respondToQuery(_in); + synchronized (this.jmDNSImpl.getIoLock()) + { + if (this.jmDNSImpl.getPlannedAnswer() == in) + { + this.jmDNSImpl.setPlannedAnswer(null); + } - // We use these sets to prevent duplicate records - Set<DNSQuestion> questions = new HashSet<DNSQuestion>(); - Set<DNSRecord> answers = new HashSet<DNSRecord>(); + // We use these sets to prevent duplicate records + // FIXME - This should be moved into DNSOutgoing + HashSet questions = new HashSet(); + HashSet answers = new HashSet(); - if (this.getDns().isAnnounced()) - { - try + + if (this.jmDNSImpl.getState() == DNSState.ANNOUNCED) { - // Answer questions - for (DNSQuestion question : _in.getQuestions()) + try { - if (logger.isLoggable(Level.FINER)) + boolean isUnicast = (port != DNSConstants.MDNS_PORT); + + + // Answer questions + for (Iterator iterator = in.getQuestions().iterator(); iterator.hasNext();) { - logger.finer(this.getName() + "run() JmDNS responding to: " + question); + DNSEntry entry = (DNSEntry) iterator.next(); + if (entry instanceof DNSQuestion) + { + DNSQuestion q = (DNSQuestion) entry; + + // for unicast responses the question must be included + if (isUnicast) + { + //out.addQuestion(q); + questions.add(q); + } + + int type = q.getType(); + if (type == DNSConstants.TYPE_ANY || type == DNSConstants.TYPE_SRV) + { // I ama not sure of why there is a special case here [PJYF Oct 15 2004] + if (this.jmDNSImpl.getLocalHost().getName().equalsIgnoreCase(q.getName())) + { + // type = DNSConstants.TYPE_A; + DNSRecord answer = this.jmDNSImpl.getLocalHost().getDNS4AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + answer = this.jmDNSImpl.getLocalHost().getDNS6AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + type = DNSConstants.TYPE_IGNORE; + } + else + { + if (this.jmDNSImpl.getServiceTypes().containsKey(q.getName().toLowerCase())) + { + type = DNSConstants.TYPE_PTR; + } + } + } + + switch (type) + { + case DNSConstants.TYPE_A: + { + // Answer a query for a domain name + //out = addAnswer( in, addr, port, out, host ); + DNSRecord answer = this.jmDNSImpl.getLocalHost().getDNS4AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + break; + } + case DNSConstants.TYPE_AAAA: + { + // Answer a query for a domain name + DNSRecord answer = this.jmDNSImpl.getLocalHost().getDNS6AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + break; + } + case DNSConstants.TYPE_PTR: + { + // Answer a query for services of a given type + + // find matching services + for (Iterator serviceIterator = this.jmDNSImpl.getServices().values().iterator(); serviceIterator.hasNext();) + { + ServiceInfoImpl info = (ServiceInfoImpl) serviceIterator.next(); + if (info.getState() == DNSState.ANNOUNCED) + { + if (q.getName().equalsIgnoreCase(info.getType())) + { + DNSRecord answer = this.jmDNSImpl.getLocalHost().getDNS4AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + answer = this.jmDNSImpl.getLocalHost().getDNS6AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + answers.add(new DNSRecord.Pointer(info.getType(), DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName())); + answers.add(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, + info.getPriority(), info.getWeight(), info.getPort(), this.jmDNSImpl.getLocalHost().getName())); + answers.add(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, + info.getText())); + } + } + } + if (q.getName().equalsIgnoreCase("_services" + DNSConstants.DNS_META_QUERY + "local.")) + { + for (Iterator serviceTypeIterator = this.jmDNSImpl.getServiceTypes().values().iterator(); serviceTypeIterator.hasNext();) + { + answers.add(new DNSRecord.Pointer("_services" + DNSConstants.DNS_META_QUERY + "local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, (String) serviceTypeIterator.next())); + } + } + break; + } + case DNSConstants.TYPE_SRV: + case DNSConstants.TYPE_ANY: + case DNSConstants.TYPE_TXT: + { + ServiceInfoImpl info = (ServiceInfoImpl) this.jmDNSImpl.getServices().get(q.getName().toLowerCase()); + if (info != null && info.getState() == DNSState.ANNOUNCED) + { + DNSRecord answer = this.jmDNSImpl.getLocalHost().getDNS4AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + answer = this.jmDNSImpl.getLocalHost().getDNS6AddressRecord(); + if (answer != null) + { + answers.add(answer); + } + answers.add(new DNSRecord.Pointer(info.getType(), DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName())); + answers.add(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, + info.getPriority(), info.getWeight(), info.getPort(), this.jmDNSImpl.getLocalHost().getName())); + answers.add(new DNSRecord.Text(info.getQualifiedName(), DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.getText())); + } + break; + } + default : + { + //System.out.println("JmDNSResponder.unhandled query:"+q); + break; + } + } + } } - // for unicast responses the question must be included - if (_unicast) + + + // remove known answers, if the ttl is at least half of + // the correct value. (See Draft Cheshire chapter 7.1.). + for (Iterator i = in.getAnswers().iterator(); i.hasNext();) { - // out.addQuestion(q); - questions.add(question); + DNSRecord knownAnswer = (DNSRecord) i.next(); + if (knownAnswer.getTtl() > DNSConstants.DNS_TTL / 2 && answers.remove(knownAnswer)) + { +// logger.log(Level.FINER, "JmDNS Responder Known Answer Removed"); + } } - question.addAnswers(this.getDns(), answers); - } - // remove known answers, if the ttl is at least half of the correct value. (See Draft Cheshire chapter 7.1.). - long now = System.currentTimeMillis(); - for (DNSRecord knownAnswer : _in.getAnswers()) - { - if (knownAnswer.isStale(now)) + // responde if we have answers + if (answers.size() != 0) { - answers.remove(knownAnswer); - if (logger.isLoggable(Level.FINER)) +// logger.finer("run() JmDNS responding"); + DNSOutgoing out = null; + if (isUnicast) + { + out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false); + } + + for (Iterator i = questions.iterator(); i.hasNext();) + { + out.addQuestion((DNSQuestion) i.next()); + } + for (Iterator i = answers.iterator(); i.hasNext();) { - logger.finer(this.getName() + "JmDNS Responder Known Answer Removed"); + out = this.jmDNSImpl.addAnswer(in, addr, port, out, (DNSRecord) i.next()); } + this.jmDNSImpl.send(out); } + this.cancel(); } - - // respond if we have answers - if (answers.size() != 0) + catch (Throwable e) { - if (logger.isLoggable(Level.FINER)) - { - logger.finer(this.getName() + "run() JmDNS responding"); - } - DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, !_unicast, _in.getSenderUDPPayload()); - out.setId(_in.getId()); - for (DNSQuestion question : questions) - { - out = this.addQuestion(out, question); - } - for (DNSRecord answer : answers) - { - out = this.addAnswer(out, _in, answer); - } - if (!out.isEmpty()) - this.getDns().send(out); +// logger.log(Level.WARNING, "run() exception ", e); + this.jmDNSImpl.close(); } - // this.cancel(); - } - catch (Throwable e) - { - logger.log(Level.WARNING, "run() exception ", e); - this.getDns().close(); } } } |