summaryrefslogtreecommitdiff
path: root/src/javax/jmdns/impl/tasks/Responder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/jmdns/impl/tasks/Responder.java')
-rw-r--r--src/javax/jmdns/impl/tasks/Responder.java157
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