$search
00001 // Copyright 2003-2005 Arthur van Hoff, Rick Blair 00002 // Licensed under Apache License version 2.0 00003 // Original license LGPL 00004 00005 package javax.jmdns.impl.tasks; 00006 00007 import java.util.HashSet; 00008 import java.util.Set; 00009 import java.util.Timer; 00010 import java.util.logging.Level; 00011 import java.util.logging.Logger; 00012 00013 import javax.jmdns.impl.DNSIncoming; 00014 import javax.jmdns.impl.DNSOutgoing; 00015 import javax.jmdns.impl.DNSQuestion; 00016 import javax.jmdns.impl.DNSRecord; 00017 import javax.jmdns.impl.JmDNSImpl; 00018 import javax.jmdns.impl.constants.DNSConstants; 00019 00023 public class Responder extends DNSTask { 00024 static Logger logger = Logger.getLogger(Responder.class.getName()); 00025 00029 private final DNSIncoming _in; 00030 00034 private final boolean _unicast; 00035 00036 public Responder(JmDNSImpl jmDNSImpl, DNSIncoming in, int port) { 00037 super(jmDNSImpl); 00038 this._in = in; 00039 this._unicast = (port != DNSConstants.MDNS_PORT); 00040 } 00041 00042 /* 00043 * (non-Javadoc) 00044 * @see javax.jmdns.impl.tasks.DNSTask#getName() 00045 */ 00046 @Override 00047 public String getName() { 00048 return "Responder(" + (this.getDns() != null ? this.getDns().getName() : "") + ")"; 00049 } 00050 00051 /* 00052 * (non-Javadoc) 00053 * @see java.lang.Object#toString() 00054 */ 00055 @Override 00056 public String toString() { 00057 return super.toString() + " incomming: " + _in; 00058 } 00059 00060 /* 00061 * (non-Javadoc) 00062 * @see javax.jmdns.impl.tasks.DNSTask#start(java.util.Timer) 00063 */ 00064 @Override 00065 public void start(Timer timer) { 00066 // According to draft-cheshire-dnsext-multicastdns.txt chapter "7 Responding": 00067 // We respond immediately if we know for sure, that we are the only one who can respond to the query. 00068 // In all other cases, we respond within 20-120 ms. 00069 // 00070 // According to draft-cheshire-dnsext-multicastdns.txt chapter "6.2 Multi-Packet Known Answer Suppression": 00071 // We respond after 20-120 ms if the query is truncated. 00072 00073 boolean iAmTheOnlyOne = true; 00074 for (DNSQuestion question : _in.getQuestions()) { 00075 if (logger.isLoggable(Level.FINEST)) { 00076 logger.finest(this.getName() + "start() question=" + question); 00077 } 00078 iAmTheOnlyOne = question.iAmTheOnlyOne(this.getDns()); 00079 if (!iAmTheOnlyOne) { 00080 break; 00081 } 00082 } 00083 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(); 00084 if (delay < 0) { 00085 delay = 0; 00086 } 00087 if (logger.isLoggable(Level.FINEST)) { 00088 logger.finest(this.getName() + "start() Responder chosen delay=" + delay); 00089 } 00090 if (!this.getDns().isCanceling() && !this.getDns().isCanceled()) { 00091 timer.schedule(this, delay); 00092 } 00093 } 00094 00095 @Override 00096 public void run() { 00097 this.getDns().respondToQuery(_in); 00098 00099 // We use these sets to prevent duplicate records 00100 Set<DNSQuestion> questions = new HashSet<DNSQuestion>(); 00101 Set<DNSRecord> answers = new HashSet<DNSRecord>(); 00102 00103 if (this.getDns().isAnnounced()) { 00104 try { 00105 // Answer questions 00106 for (DNSQuestion question : _in.getQuestions()) { 00107 if (logger.isLoggable(Level.FINER)) { 00108 logger.finer(this.getName() + "run() JmDNS responding to: " + question); 00109 } 00110 // for unicast responses the question must be included 00111 if (_unicast) { 00112 // out.addQuestion(q); 00113 questions.add(question); 00114 } 00115 00116 question.addAnswers(this.getDns(), answers); 00117 } 00118 00119 // remove known answers, if the ttl is at least half of the correct value. (See Draft Cheshire chapter 7.1.). 00120 long now = System.currentTimeMillis(); 00121 for (DNSRecord knownAnswer : _in.getAnswers()) { 00122 if (knownAnswer.isStale(now)) { 00123 answers.remove(knownAnswer); 00124 if (logger.isLoggable(Level.FINER)) { 00125 logger.finer(this.getName() + "JmDNS Responder Known Answer Removed"); 00126 } 00127 } 00128 } 00129 00130 // respond if we have answers 00131 if (!answers.isEmpty()) { 00132 if (logger.isLoggable(Level.FINER)) { 00133 logger.finer(this.getName() + "run() JmDNS responding"); 00134 } 00135 DNSOutgoing out = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, !_unicast, _in.getSenderUDPPayload()); 00136 out.setId(_in.getId()); 00137 for (DNSQuestion question : questions) { 00138 if (question != null) { 00139 out = this.addQuestion(out, question); 00140 } 00141 } 00142 for (DNSRecord answer : answers) { 00143 if (answer != null) { 00144 out = this.addAnswer(out, _in, answer); 00145 00146 } 00147 } 00148 if (!out.isEmpty()) this.getDns().send(out); 00149 } 00150 // this.cancel(); 00151 } catch (Throwable e) { 00152 logger.log(Level.WARNING, this.getName() + "run() exception ", e); 00153 this.getDns().close(); 00154 } 00155 } 00156 } 00157 }