1
2
3
4
5 package javax.jmdns.impl.tasks;
6
7 import java.util.HashSet;
8 import java.util.Set;
9 import java.util.Timer;
10 import java.util.logging.Level;
11 import java.util.logging.Logger;
12
13 import javax.jmdns.impl.DNSIncoming;
14 import javax.jmdns.impl.DNSOutgoing;
15 import javax.jmdns.impl.DNSQuestion;
16 import javax.jmdns.impl.DNSRecord;
17 import javax.jmdns.impl.JmDNSImpl;
18 import javax.jmdns.impl.constants.DNSConstants;
19
20
21
22
23 public class Responder extends DNSTask {
24 static Logger logger = Logger.getLogger(Responder.class.getName());
25
26
27
28
29 private final DNSIncoming _in;
30
31
32
33
34 private final boolean _unicast;
35
36 public Responder(JmDNSImpl jmDNSImpl, DNSIncoming in, int port) {
37 super(jmDNSImpl);
38 this._in = in;
39 this._unicast = (port != DNSConstants.MDNS_PORT);
40 }
41
42
43
44
45
46 @Override
47 public String getName() {
48 return "Responder(" + (this.getDns() != null ? this.getDns().getName() : "") + ")";
49 }
50
51
52
53
54
55 @Override
56 public String toString() {
57 return super.toString() + " incomming: " + _in;
58 }
59
60
61
62
63
64 @Override
65 public void start(Timer timer) {
66
67
68
69
70
71
72
73 boolean iAmTheOnlyOne = true;
74 for (DNSQuestion question : _in.getQuestions()) {
75 if (logger.isLoggable(Level.FINEST)) {
76 logger.finest(this.getName() + "start() question=" + question);
77 }
78 iAmTheOnlyOne = question.iAmTheOnlyOne(this.getDns());
79 if (!iAmTheOnlyOne) {
80 break;
81 }
82 }
83 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();
84 if (delay < 0) {
85 delay = 0;
86 }
87 if (logger.isLoggable(Level.FINEST)) {
88 logger.finest(this.getName() + "start() Responder chosen delay=" + delay);
89 }
90 if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) {
91 timer.schedule(this, delay);
92 }
93 }
94
95 @Override
96 public void run() {
97 this.getDns().respondToQuery(_in);
98
99
100 Set<DNSQuestion> questions = new HashSet<DNSQuestion>();
101 Set<DNSRecord> answers = new HashSet<DNSRecord>();
102
103 if (this.getDns().isAnnounced()) {
104 try {
105
106 for (DNSQuestion question : _in.getQuestions()) {
107 if (logger.isLoggable(Level.FINER)) {
108 logger.finer(this.getName() + "run() JmDNS responding to: " + question);
109 }
110
111 if (_unicast) {
112
113 questions.add(question);
114 }
115
116 question.addAnswers(this.getDns(), answers);
117 }
118
119
120 long now = System.currentTimeMillis();
121 for (DNSRecord knownAnswer : _in.getAnswers()) {
122 if (knownAnswer.isStale(now)) {
123 answers.remove(knownAnswer);
124 if (logger.isLoggable(Level.FINER)) {
125 logger.finer(this.getName() + "JmDNS Responder Known Answer Removed");
126 }
127 }
128 }
129
130
131 if (!answers.isEmpty()) {
132 if (logger.isLoggable(Level.FINER)) {
133 logger.finer(this.getName() + "run() JmDNS responding");
134 }
135 DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, !_unicast, _in.getSenderUDPPayload());
136 out.setId(_in.getId());
137 for (DNSQuestion question : questions) {
138 if (question != null) {
139 out = this.addQuestion(out, question);
140 }
141 }
142 for (DNSRecord answer : answers) {
143 if (answer != null) {
144 out = this.addAnswer(out, _in, answer);
145
146 }
147 }
148 if (!out.isEmpty()) this.getDns().send(out);
149 }
150
151 } catch (Throwable e) {
152 logger.log(Level.WARNING, this.getName() + "run() exception ", e);
153 this.getDns().close();
154 }
155 }
156 }
157 }