/// <summary> Add an additional answer to the record. Omit if there is no room.</summary> internal void AddAdditionalAnswer(DNSIncoming in_Renamed, DNSRecord rec) { if ((off < DNSConstants.MAX_MSG_TYPICAL - 200) && !rec.SuppressedBy(in_Renamed)) { WriteRecord(rec, 0); numAdditionals++; } }
/// <summary> True if this record would be supressed by an answer. /// This is the case if this record would not have a /// significantly longer TTL. /// </summary> internal virtual bool SuppressedBy(DNSRecord other) { if (SameAs(other) && (other.ttl > ttl / 2)) { return(true); } return(false); }
/// <summary> Add an answer if it is not suppressed.</summary> internal void AddAnswer(DNSIncoming in_Renamed, DNSRecord rec) { if (numAuthorities > 0 || numAdditionals > 0) { // TODO is this the right exception throw new Exception("Answers must be added before authorities and additionals"); } if (!rec.SuppressedBy(in_Renamed)) { AddAnswer(rec, 0); } }
// Remind: Method updateRecord should receive a better name. /// <summary> Notify all listeners that a record was updated.</summary> internal virtual void UpdateRecord(long now, DNSRecord rec) { // We do not want to block the entire DNS while we are updating the record for each listener (service info) IList listenerList = null; lock (this) { listenerList = new ArrayList(listeners); } foreach (IDNSListener listener in listenerList) { listener.UpdateRecord(this, now, rec); } if (rec.type == DNSConstants.TYPE_PTR || rec.type == DNSConstants.TYPE_SRV) { IList serviceListenerList = null; lock (this) { serviceListenerList = (IList)serviceListeners[rec.name.ToLower()]; // Iterate on a copy in case listeners will modify it if (serviceListenerList != null) { serviceListenerList = new ArrayList(serviceListenerList); } } if (serviceListenerList != null) { bool expired = rec.IsExpired(now); string type = rec.Name; string name = ((Pointer)rec).Alias; // DNSRecord old = (DNSRecord)services.get(name.toLowerCase()); if (!expired) { // new record ServiceEvent event_Renamed = new ServiceEvent(this, type, ToUnqualifiedName(type, name), null); foreach (IServiceListener listener in serviceListenerList) { listener.ServiceAdded(this, event_Renamed); } } else { // expire record ServiceEvent event_Renamed = new ServiceEvent(this, type, ToUnqualifiedName(type, name), null); foreach (IServiceListener listener in serviceListenerList) { listener.ServiceRemoved(this, event_Renamed); } } } } }
// REMIND: Oops, this shouldn't be public! /// <summary> JmDNS callback to update a DNS record.</summary> public virtual void UpdateRecord(mDNS jmdns, long now, DNSRecord rec) { if ((rec != null) && !rec.IsExpired(now)) { switch (rec.type) { case DNSConstants.TYPE_A: // IPv4 case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested if (rec.name.Equals(server)) { addr = ((Address)rec).IPAddress; } break; case DNSConstants.TYPE_SRV: if (rec.name.Equals(QualifiedName)) { Service srv = (Service)rec; server = srv.server; port = srv.port; weight = srv.weight; priority = srv.priority; addr = null; // changed to use getCache() instead - jeffs // updateRecord(jmdns, now, (DNSRecord)jmdns.cache.get(server, TYPE_A, CLASS_IN)); UpdateRecord(jmdns, now, (DNSRecord)jmdns.Cache.get_Renamed(server, DNSConstants.TYPE_A, DNSConstants.CLASS_IN)); } break; case DNSConstants.TYPE_TXT: if (rec.name.Equals(QualifiedName)) { Text txt = (Text)rec; text = txt.text; } break; } // Future Design Pattern // This is done, to notify the wait loop in method // JmDNS.getServiceInfo(type, name, timeout); if (HasData && dns != null) { dns.HandleServiceResolved(this); dns = null; } lock (this) { Monitor.PulseAll(this); } } }
/// <summary> Add an authorative answer to the message.</summary> internal void AddAuthorativeAnswer(DNSRecord rec) { if (numAdditionals > 0) { // TODO is this the right exception? throw new Exception("Authorative answers must be added before additional answers"); } authorativeAnswers.Add(rec); WriteRecord(rec, 0); numAuthorities++; // VERIFY: }
internal override bool SameValue(DNSRecord other) { Text txt = (Text) other; if (txt.text.Length != text.Length) { return false; } for (int i = text.Length; i-- > 0; ) { if (txt.text[i] != text[i]) { return false; } } return true; }
/// <summary> Add an answer to the message.</summary> internal void AddAnswer(DNSRecord rec, long now) { if (numAuthorities > 0 || numAdditionals > 0) { // TODO is this the right exception? throw new Exception("Questions must be added before answers"); } if (rec != null) { if ((now == 0) || !rec.IsExpired(now)) { WriteRecord(rec, now); numAnswers++; } } }
internal override bool SameValue(DNSRecord other) { Text txt = (Text)other; if (txt.text.Length != text.Length) { return(false); } for (int i = text.Length; i-- > 0;) { if (txt.text[i] != text[i]) { return(false); } } return(true); }
public void Run(object state) { try { if (++count < 3) { logger.Debug("run() JmDNS canceling service"); // announce the service DNSOutgoing out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); for (int i = 0; i < infos.Length; i++) { ServiceInfo info = infos[i]; out_Renamed.AddAnswer(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, ttl, info.QualifiedName), 0); out_Renamed.AddAnswer(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, ttl, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name), 0); out_Renamed.AddAnswer(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN, ttl, info.text), 0); DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { out_Renamed.AddAnswer(answer, 0); } answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { out_Renamed.AddAnswer(answer, 0); } } Enclosing_Instance.Send(out_Renamed); } else { // After three successful announcements, we are finished. lock (lock_Renamed) { Monitor.PulseAll(lock_Renamed); } // TODO: omit cancel? //cancel(); } } catch (Exception e) { logger.Warn("run() exception ", e); Enclosing_Instance.Recover(); } }
/// <summary> Generate a possibly unique name for a service using the information we /// have in the cache. /// /// </summary> /// <returns> returns true, if the name of the service info had to be changed. /// </returns> private bool makeServiceNameUnique(ServiceInfo info) { string originalQualifiedName = info.QualifiedName; long now = (DateTime.Now.Ticks - 621355968000000000) / 10000; bool collision; do { collision = false; // Check for collision in cache for (DNSCache.CacheNode j = cache.find(info.QualifiedName.ToLower()); j != null; j = j.Next) { DNSRecord a = (DNSRecord)j.Value; if ((a.type == DNSConstants.TYPE_SRV) && !a.IsExpired(now)) { Service s = (Service)a; if (s.port != info.port || !s.server.Equals(localHost.Name)) { logger.Debug("makeServiceNameUnique() JmDNS.makeServiceNameUnique srv collision:" + a + " s.server=" + s.server + " " + localHost.Name + " equals:" + (s.server.Equals(localHost.Name))); info.SetName(IncrementName(info.getName())); collision = true; break; } } } // Check for collision with other service infos published by JmDNS object selfService = services[info.QualifiedName.ToLower()]; if (selfService != null && selfService != info) { info.SetName(IncrementName(info.getName())); collision = true; } }while (collision); return(!(originalQualifiedName.Equals(info.QualifiedName))); }
internal void WriteRecord(DNSRecord rec, long now) { int save = off; try { WriteName(rec.name); WriteShort(rec.type); WriteShort(rec.clazz | ((rec.unique && multicast)?DNSConstants.CLASS_UNIQUE:0)); WriteInt((now == 0)?rec.ttl:rec.GetRemainingTTL(now)); WriteShort(0); int start = off; rec.Write(this); int len = off - start; data[start - 2] = (sbyte)(len >> 8); data[start - 1] = (sbyte)(len & 0xFF); } catch (IOException e) { off = save; throw e; } }
/// <summary> Add a listener for a question. The listener will receive updates /// of answers to the question as they arrive, or from the cache if they /// are already available. /// </summary> internal virtual void AddListener(IDNSListener listener, DNSQuestion question) { long now = (DateTime.Now.Ticks - 621355968000000000) / 10000; // add the new listener lock (this) { listeners.Add(listener); } // report existing matched records if (question != null) { for (DNSCache.CacheNode i = cache.find(question.name); i != null; i = i.Next) { DNSRecord c = (DNSRecord)i.Value; if (question.IsAnsweredBy(c) && !c.IsExpired(now)) { listener.UpdateRecord(this, now, c); } } } }
internal override bool SameValue(DNSRecord other) { Service s = (Service) other; return (priority == s.priority) && (weight == s.weight) && (port == s.port) && server.Equals(s.server); }
/// <summary> True if this record would be supressed by an answer. /// This is the case if this record would not have a /// significantly longer TTL. /// </summary> internal virtual bool SuppressedBy(DNSRecord other) { if (SameAs(other) && (other.ttl > ttl / 2)) { return true; } return false; }
/// <summary> True if this record has the same value as some other record.</summary> internal abstract bool SameValue(DNSRecord other);
internal virtual bool Same(DNSRecord other) { return((SameName(other)) && ((SameValue(other)))); }
internal virtual bool SameName(DNSRecord other) { return(name.ToUpper().Equals(((Address)other).name.ToUpper())); }
internal void WriteRecord(DNSRecord rec, long now) { int save = off; try { WriteName(rec.name); WriteShort(rec.type); WriteShort(rec.clazz | ((rec.unique && multicast)?DNSConstants.CLASS_UNIQUE:0)); WriteInt((now == 0)?rec.ttl:rec.GetRemainingTTL(now)); WriteShort(0); int start = off; rec.Write(this); int len = off - start; data[start - 2] = (sbyte) (len >> 8); data[start - 1] = (sbyte) (len & 0xFF); } catch (IOException e) { off = save; throw e; } }
internal override bool SameValue(DNSRecord other) { return addr.Equals(((Address) other).IPAddress); }
/// <summary> Check if this question is answered by a given DNS record.</summary> internal bool IsAnsweredBy(DNSRecord rec) { return (clazz == rec.clazz) && ((type == rec.type) || (type == DNSConstants.TYPE_ANY)) && name.Equals(rec.name); }
internal override bool SameValue(DNSRecord other) { Service s = (Service)other; return((priority == s.priority) && (weight == s.weight) && (port == s.port) && server.Equals(s.server)); }
internal override bool SameValue(DNSRecord other) { return(alias.Equals(((Pointer)other).alias)); }
internal override bool SameValue(DNSRecord other) { return alias.Equals(((Pointer) other).alias); }
internal virtual bool Same(DNSRecord other) { return ((SameName(other)) && ((SameValue(other)))); }
/// <summary> True if this record is the same as some other record.</summary> internal virtual bool SameAs(DNSRecord other) { return(base.Equals(other) && SameValue((DNSRecord)other)); }
internal override bool SameValue(DNSRecord other) { return(addr.Equals(((Address)other).IPAddress)); }
/// <summary> Add an answer to a question. Deal with the case when the /// outgoing packet overflows /// </summary> internal virtual DNSOutgoing AddAnswer(DNSIncoming in_Renamed, IPAddress addr, int port, DNSOutgoing out_Renamed, DNSRecord rec) { if (out_Renamed == null) { out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); } try { out_Renamed.AddAnswer(in_Renamed, rec); } catch { out_Renamed.flags |= DNSConstants.FLAGS_TC; out_Renamed.id = in_Renamed.id; out_Renamed.Finish(); Send(out_Renamed); out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); out_Renamed.AddAnswer(in_Renamed, rec); } return(out_Renamed); }
/// <summary> True if this record is the same as some other record.</summary> internal virtual bool SameAs(DNSRecord other) { return base.Equals(other) && SameValue((DNSRecord) other); }
/// <summary> Parse a message from a datagram packet.</summary> internal DNSIncoming(SupportClass.PacketSupport packet) { this.packet = packet; this.data = SupportClass.ToSByteArray(packet.Data); this.len = packet.Length; // TODO: will this always be 0 in .NET?? this.off = 0; this.questions = ArrayList.ReadOnly(new ArrayList()); this.answers = ArrayList.ReadOnly(new ArrayList()); this.receivedTime = (DateTime.Now.Ticks - 621355968000000000) / 10000; try { id = ReadUnsignedShort(); flags = ReadUnsignedShort(); numQuestions = ReadUnsignedShort(); numAnswers = ReadUnsignedShort(); numAuthorities = ReadUnsignedShort(); numAdditionals = ReadUnsignedShort(); // parse questions if (numQuestions > 0) { questions = ArrayList.Synchronized(new ArrayList(numQuestions)); for (int i = 0; i < numQuestions; i++) { DNSQuestion question = new DNSQuestion(ReadName(), ReadUnsignedShort(), ReadUnsignedShort()); questions.Add(question); } } // parse answers int n = numAnswers + numAuthorities + numAdditionals; if (n > 0) { answers = ArrayList.Synchronized(new ArrayList(n)); for (int i = 0; i < n; i++) { string domain = ReadName(); int type = ReadUnsignedShort(); int clazz = ReadUnsignedShort(); int ttl = ReadInt(); int len = ReadUnsignedShort(); int end = off + len; DNSRecord rec = null; switch (type) { case DNSConstants.TYPE_A: // IPv4 case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested rec = new Address(domain, type, clazz, ttl, ReadBytes(off, len)); break; case DNSConstants.TYPE_CNAME: case DNSConstants.TYPE_PTR: rec = new Pointer(domain, type, clazz, ttl, ReadName()); break; case DNSConstants.TYPE_TXT: rec = new Text(domain, type, clazz, ttl, ReadBytes(off, len)); break; case DNSConstants.TYPE_SRV: rec = new Service(domain, type, clazz, ttl, ReadUnsignedShort(), ReadUnsignedShort(), ReadUnsignedShort(), ReadName()); break; case DNSConstants.TYPE_HINFO: // Maybe we should do something with those break; default: logger.Debug("DNSIncoming() unknown type:" + type); break; } if (rec != null) { // Add a record, if we were able to create one. answers.Add(rec); } else { // Addjust the numbers for the skipped record if (answers.Count < numAnswers) { numAnswers--; } else if (answers.Count < numAnswers + numAuthorities) { numAuthorities--; } else if (answers.Count < numAnswers + numAuthorities + numAdditionals) { numAdditionals--; } } off = end; } } } catch (IOException e) { logger.Warn("DNSIncoming() dump " + Print(true) + "\n exception ", e); throw e; } }
/// <summary> Reset the TTL of a record. This avoids having to /// update the entire record in the cache. /// </summary> internal virtual void ResetTTL(DNSRecord other) { created = other.created; ttl = other.ttl; }
// Remind: Method updateRecord should receive a better name. /// <summary> Notify all listeners that a record was updated.</summary> internal virtual void UpdateRecord(long now, DNSRecord rec) { // We do not want to block the entire DNS while we are updating the record for each listener (service info) IList listenerList = null; lock (this) { listenerList = new ArrayList(listeners); } foreach (IDNSListener listener in listenerList) { listener.UpdateRecord(this, now, rec); } if (rec.type == DNSConstants.TYPE_PTR || rec.type == DNSConstants.TYPE_SRV) { IList serviceListenerList = null; lock (this) { serviceListenerList = (IList) serviceListeners[rec.name.ToLower()]; // Iterate on a copy in case listeners will modify it if (serviceListenerList != null) serviceListenerList = new ArrayList(serviceListenerList); } if (serviceListenerList != null) { bool expired = rec.IsExpired(now); string type = rec.Name; string name = ((Pointer) rec).Alias; // DNSRecord old = (DNSRecord)services.get(name.toLowerCase()); if (!expired) { // new record ServiceEvent event_Renamed = new ServiceEvent(this, type, ToUnqualifiedName(type, name), null); foreach (IServiceListener listener in serviceListenerList) { listener.ServiceAdded(this, event_Renamed); } } else { // expire record ServiceEvent event_Renamed = new ServiceEvent(this, type, ToUnqualifiedName(type, name), null); foreach (IServiceListener listener in serviceListenerList) { listener.ServiceRemoved(this, event_Renamed); } } } } }
internal virtual bool SameName(DNSRecord other) { return name.ToUpper().Equals(((Address) other).name.ToUpper()); }
/// <summary> True if this record has the same type as some other record.</summary> internal virtual bool SameType(DNSRecord other) { return type == other.type; }
/// <summary> Handle an incoming response. Cache answers, and pass them on to /// the appropriate questions. /// </summary> internal void HandleResponse(DNSIncoming msg) { long now = (DateTime.Now.Ticks - 621355968000000000) / 10000; bool hostConflictDetected = false; bool serviceConflictDetected = false; for (int recIdx = 0; recIdx < msg.answers.Count; recIdx++) { DNSRecord rec = (DNSRecord)msg.answers[recIdx]; bool isInformative = false; bool expired = rec.IsExpired(now); // update the cache DNSRecord c = (DNSRecord)cache.get_Renamed(rec); if (c != null) { if (expired) { isInformative = true; cache.remove(c); } else { c.ResetTTL(rec); rec = c; msg.answers[recIdx] = c; // put back into collection } } else { if (!expired) { isInformative = true; cache.add(rec); } } switch (rec.type) { case DNSConstants.TYPE_PTR: // handle _mdns._udp records if (rec.Name.IndexOf("._mdns._udp.") >= 0) { if (!expired && rec.name.StartsWith("_services._mdns._udp.")) { isInformative = true; RegisterServiceType(((Pointer)rec).alias); } continue; } RegisterServiceType(rec.name); break; } if ((rec.GetEntryType() == DNSConstants.TYPE_A) || (rec.GetEntryType() == DNSConstants.TYPE_AAAA)) { hostConflictDetected |= rec.HandleResponse(this); } else { serviceConflictDetected |= rec.HandleResponse(this); } // notify the listeners if (isInformative) { UpdateRecord(now, rec); } } if (hostConflictDetected || serviceConflictDetected) { new Prober(this).start(); } }
public void Run(object state) { DNSOutgoing out_Renamed = null; try { // send probes for JmDNS itself if (Enclosing_Instance.State == taskState) { if (out_Renamed == null) { out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); } DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { out_Renamed.AddAnswer(answer, 0); } answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { out_Renamed.AddAnswer(answer, 0); } Enclosing_Instance.AdvanceState(); } // send announces for services // Defensively copy the services into a local list, // to prevent race conditions with methods registerService // and unregisterService. IList list; lock (Enclosing_Instance) { list = new ArrayList(Enclosing_Instance.services.Values); } foreach (ServiceInfo info in list) { lock (info) { if (info.State == taskState && info.task == this) { info.AdvanceState(); logger.Debug("run() JmDNS announcing " + info.QualifiedName + " state " + info.State); if (out_Renamed == null) { out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); } out_Renamed.AddAnswer(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.QualifiedName), 0); out_Renamed.AddAnswer(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name), 0); out_Renamed.AddAnswer(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.text), 0); } } } if (out_Renamed != null) { logger.Debug("run() JmDNS announcing #" + taskState); Enclosing_Instance.Send(out_Renamed); } else { // If we have nothing to send, another timer taskState ahead // of us has done the job for us. We can cancel. cancel(); } } catch (Exception e) { logger.Warn("run() exception ", e); Enclosing_Instance.Recover(); } taskState = taskState.Advance(); if (!taskState.Announcing) { cancel(); new Renewer(enclosingInstance).start(); } }
/// <summary> Add an answer to a question. Deal with the case when the /// outgoing packet overflows /// </summary> internal virtual DNSOutgoing AddAnswer(DNSIncoming in_Renamed, IPAddress addr, int port, DNSOutgoing out_Renamed, DNSRecord rec) { if (out_Renamed == null) { out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); } try { out_Renamed.AddAnswer(in_Renamed, rec); } catch { out_Renamed.flags |= DNSConstants.FLAGS_TC; out_Renamed.id = in_Renamed.id; out_Renamed.Finish(); Send(out_Renamed); out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA); out_Renamed.AddAnswer(in_Renamed, rec); } return out_Renamed; }
// REMIND: Oops, this shouldn't be public! /// <summary> JmDNS callback to update a DNS record.</summary> public virtual void UpdateRecord(mDNS jmdns, long now, DNSRecord rec) { if ((rec != null) && !rec.IsExpired(now)) { switch (rec.type) { case DNSConstants.TYPE_A: // IPv4 case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested if (rec.name.Equals(server)) { addr = ((Address) rec).IPAddress; } break; case DNSConstants.TYPE_SRV: if (rec.name.Equals(QualifiedName)) { Service srv = (Service) rec; server = srv.server; port = srv.port; weight = srv.weight; priority = srv.priority; addr = null; // changed to use getCache() instead - jeffs // updateRecord(jmdns, now, (DNSRecord)jmdns.cache.get(server, TYPE_A, CLASS_IN)); UpdateRecord(jmdns, now, (DNSRecord) jmdns.Cache.get_Renamed(server, DNSConstants.TYPE_A, DNSConstants.CLASS_IN)); } break; case DNSConstants.TYPE_TXT: if (rec.name.Equals(QualifiedName)) { Text txt = (Text) rec; text = txt.text; } break; } // Future Design Pattern // This is done, to notify the wait loop in method // JmDNS.getServiceInfo(type, name, timeout); if (HasData && dns != null) { dns.HandleServiceResolved(this); dns = null; } lock (this) { Monitor.PulseAll(this); } } }
/// <summary> True if this record has the same type as some other record.</summary> internal virtual bool SameType(DNSRecord other) { return(type == other.type); }
public void Run(object state) { lock (Enclosing_Instance.IOLock) { if (Enclosing_Instance.PlannedAnswer == in_Renamed) { Enclosing_Instance.PlannedAnswer = null; } // We use these sets to prevent duplicate records // FIXME - This should be moved into DNSOutgoing // TODO: check these for compatibility SupportClass.HashSetSupport questions = new SupportClass.HashSetSupport(); SupportClass.HashSetSupport answers = new SupportClass.HashSetSupport(); if (Enclosing_Instance.State == DNSState.ANNOUNCED) { try { long now = (DateTime.Now.Ticks - 621355968000000000) / 10000; long expirationTime = now + 1; //=now+DNSConstants.KNOWN_ANSWER_TTL; bool isUnicast = (port != DNSConstants.MDNS_PORT); // Answer questions foreach (DNSEntry entry in in_Renamed.questions) { if (entry is DNSQuestion) { DNSQuestion q = (DNSQuestion)entry; // for unicast responses the question must be included if (isUnicast) { //out.addQuestion(q); questions.Add(q); } int type = q.type; 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 (Enclosing_Instance.localHost.Name.ToUpper().Equals(q.Name.ToUpper())) { // type = DNSConstants.TYPE_A; DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { answers.Add(answer); } answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { answers.Add(answer); } type = DNSConstants.TYPE_IGNORE; } else if (Enclosing_Instance.serviceTypes.Contains(q.Name.ToLower())) { 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 = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { answers.Add(answer); } break; } case DNSConstants.TYPE_AAAA: { // Answer a query for a domain name DNSRecord answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { answers.Add(answer); } break; } case DNSConstants.TYPE_PTR: { // Answer a query for services of a given type // find matching services foreach (ServiceInfo info in Enclosing_Instance.services.Values) { if (info.State == DNSState.ANNOUNCED) { if (q.name.ToUpper().Equals(info.type.ToUpper())) { DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { answers.Add(answer); } answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { answers.Add(answer); } answers.Add(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.QualifiedName)); answers.Add(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name)); answers.Add(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text)); } } } if (q.name.ToUpper().Equals("_services._mdns._udp.local.".ToUpper())) { foreach (String s in Enclosing_Instance.serviceTypes.Values) { answers.Add(new Pointer("_services._mdns._udp.local.", DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, s)); } } break; } case DNSConstants.TYPE_SRV: case DNSConstants.TYPE_ANY: case DNSConstants.TYPE_TXT: { ServiceInfo info = (ServiceInfo)Enclosing_Instance.services[q.name.ToLower()]; if (info != null && info.State == DNSState.ANNOUNCED) { DNSRecord answer = Enclosing_Instance.localHost.DNS4AddressRecord; if (answer != null) { answers.Add(answer); } answer = Enclosing_Instance.localHost.DNS6AddressRecord; if (answer != null) { answers.Add(answer); } answers.Add(new Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.QualifiedName)); answers.Add(new Service(info.QualifiedName, DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, Enclosing_Instance.localHost.Name)); answers.Add(new Text(info.QualifiedName, DNSConstants.TYPE_TXT, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.text)); } break; } default: { //Console.WriteLine("JmDNSResponder.unhandled query:"+q); break; } } } } // remove known answers, if the ttl is at least half of // the correct value. (See Draft Cheshire chapter 7.1.). foreach (DNSRecord knownAnswer in in_Renamed.answers) { bool tempBoolean; tempBoolean = answers.Contains(knownAnswer); answers.Remove(knownAnswer); if (knownAnswer.ttl > DNSConstants.DNS_TTL / 2 && tempBoolean) { logger.Debug("JmDNS Responder Known Answer Removed"); } } // responde if we have answers if (answers.Count != 0) { logger.Debug("run() JmDNS responding"); DNSOutgoing out_Renamed = null; if (isUnicast) { out_Renamed = new DNSOutgoing(DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA, false); } foreach (DNSQuestion question in questions) { out_Renamed.AddQuestion(question); } foreach (DNSRecord answer in answers) { out_Renamed = Enclosing_Instance.AddAnswer(in_Renamed, addr, port, out_Renamed, answer); } Enclosing_Instance.Send(out_Renamed); } // TODO: do we need this? //cancel(); } catch (Exception e) { logger.Warn("run() exception ", e); Enclosing_Instance.Close(); } } } }
/// <summary> Check if this question is answered by a given DNS record.</summary> internal bool IsAnsweredBy(DNSRecord rec) { return((clazz == rec.clazz) && ((type == rec.type) || (type == DNSConstants.TYPE_ANY)) && name.Equals(rec.name)); }