diff options
Diffstat (limited to 'src/javax/jmdns/impl/tasks/Responder.java')
-rw-r--r-- | src/javax/jmdns/impl/tasks/Responder.java | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/javax/jmdns/impl/tasks/Responder.java b/src/javax/jmdns/impl/tasks/Responder.java new file mode 100644 index 0000000..1fbbe75 --- /dev/null +++ b/src/javax/jmdns/impl/tasks/Responder.java @@ -0,0 +1,157 @@ +// Copyright 2003-2005 Arthur van Hoff, Rick Blair +// Licensed under Apache License version 2.0 +// Original license LGPL + +package javax.jmdns.impl.tasks; + +import java.util.HashSet; +import java.util.Set; +import java.util.Timer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.jmdns.impl.DNSIncoming; +import javax.jmdns.impl.DNSOutgoing; +import javax.jmdns.impl.DNSQuestion; +import javax.jmdns.impl.DNSRecord; +import javax.jmdns.impl.JmDNSImpl; +import javax.jmdns.impl.constants.DNSConstants; + +/** + * The Responder sends a single answer for the specified service infos and for the host name. + */ +public class Responder extends DNSTask { + static Logger logger = Logger.getLogger(Responder.class.getName()); + + /** + * + */ + private final DNSIncoming _in; + + /** + * + */ + private final 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() { + return "Responder(" + (this.getDns() != null ? this.getDns().getName() : "") + ")"; + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + 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. + // 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": + // We respond after 20-120 ms if the query is truncated. + + boolean iAmTheOnlyOne = true; + for (DNSQuestion question : _in.getQuestions()) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(this.getName() + "start() question=" + question); + } + iAmTheOnlyOne = question.iAmTheOnlyOne(this.getDns()); + 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(); + 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); + } + } + + @Override + public void run() { + this.getDns().respondToQuery(_in); + + // We use these sets to prevent duplicate records + Set<DNSQuestion> questions = new HashSet<DNSQuestion>(); + Set<DNSRecord> answers = new HashSet<DNSRecord>(); + + if (this.getDns().isAnnounced()) { + try { + // Answer questions + for (DNSQuestion question : _in.getQuestions()) { + if (logger.isLoggable(Level.FINER)) { + logger.finer(this.getName() + "run() JmDNS responding to: " + question); + } + // for unicast responses the question must be included + if (_unicast) { + // out.addQuestion(q); + questions.add(question); + } + + 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)) { + answers.remove(knownAnswer); + if (logger.isLoggable(Level.FINER)) { + logger.finer(this.getName() + "JmDNS Responder Known Answer Removed"); + } + } + } + + // respond if we have answers + if (!answers.isEmpty()) { + 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) { + if (question != null) { + out = this.addQuestion(out, question); + } + } + for (DNSRecord answer : answers) { + if (answer != null) { + out = this.addAnswer(out, _in, answer); + + } + } + if (!out.isEmpty()) this.getDns().send(out); + } + // this.cancel(); + } catch (Throwable e) { + logger.log(Level.WARNING, this.getName() + "run() exception ", e); + this.getDns().close(); + } + } + } +}
\ No newline at end of file |