def run(self): while 1: event = None now = dns.currentTimeMillis() if len(self.list) == 0 and self.nextTime > now: self.zeroconf.wait(self.nextTime - now) if globals()['_GLOBAL_DONE'] or self.done: return now = dns.currentTimeMillis() if self.nextTime <= now: out = dns.DNSOutgoing(dns._FLAGS_QR_QUERY) out.addQuestion(dns.DNSQuestion(self.type, dns._TYPE_PTR, dns._CLASS_IN)) for record in list(self.services.values()): if not record.isExpired(now): out.addAnswerAtTime(record, now) self.zeroconf.send(out) self.nextTime = now + self.delay self.delay = min(20 * 1000, self.delay * 2) if len(self.list) > 0: event = self.list.pop(0) if event is not None: event(self.zeroconf)
def checkService(self, info): """Checks the network for a unique service name, modifying the ServiceInfo passed in if it is not unique.""" now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: for record in self.cache.entriesWithName(info.type): if record.type == dns._TYPE_PTR and not record.isExpired(now) and record.alias == info.name: if (info.name.find('.') < 0): info.name = info.name + ".[" + info.address + ":" + info.port + "]." + info.type self.checkService(info) return raise NonUniqueNameException if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_QUERY | dns._FLAGS_AA) self.debug = out out.addQuestion(dns.DNSQuestion(info.type, dns._TYPE_PTR, dns._CLASS_IN)) out.addAuthorativeAnswer(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, dns._DNS_TTL, info.name)) self.send(out) i += 1 nextTime += _CHECK_TIME
def registerService(self, info, ttl=dns._DNS_TTL): """Registers service information to the network with a default TTL of 60 seconds. Zeroconf will then respond to requests for information for that service. The name of the service may be changed if needed to make it unique on the network.""" #print "REGISTERING SERVICE!" #log.debug(">>",self.services[info.name.lower()]) #import pdb #pdb.set_trace() self.checkService(info) self.services[info.name.lower()] = info log.debug(">>",self.services[info.name.lower()]) now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, ttl, info.name), 0) out.addAnswerAtTime(dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime(dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, ttl, info.text), 0) if info.address: out.addAnswerAtTime(dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, ttl, info.address), 0) self.send(out) i += 1 nextTime += _REGISTER_TIME print("registerService end")
def unregisterAllServices(self): """Unregister all registered services.""" if len(self.services) > 0: now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) for info in self.services.values(): out.addAnswerAtTime( dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime( dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime( dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime( dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def unregisterService(self, info): """Unregister a service.""" try: del (self.services[info.name.lower()]) except: pass now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime( dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime( dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0) out.addAnswerAtTime( dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime( dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def unregisterService(self, info): """Unregister a service.""" try: del(self.services[info.name.lower()]) self.servicetypes[info.type] -= 1 if self.servicetypes[info.type] <= 0: del self.servicetypes[info.type] except: pass now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) out.addAnswerAtTime(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime(dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0) out.addAnswerAtTime(dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime(dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def send(self, out, addr=dns._MDNS_ADDR, port=dns._MDNS_PORT): """Sends an outgoing packet. Note: this method is instrumented to provide low-level prevention of packet floods by throttling same-message sending to once per _MINIMUM_REPEAT_TIME ms. That will fail for a "regular" DNS server, which should also use the addr/port combo... """ current = dns.currentTimeMillis() log.info('%s messages in suppression_queue', len(self.suppression_queue)) while self.suppression_queue and self.suppression_queue[0][0] < current: log.debug('Removing...') self.suppression_queue.pop(0) packet = out.packet() sent = False for i, (expire, old_packet) in enumerate(self.suppression_queue[:]): if old_packet == packet: log.debug('Dropping to prevent flood') sent = True if not sent: try: sent = self.socket.sendto(packet, 0, (addr, port)) except: # Ignore this, it may be a temporary loss of network connection pass self.suppression_queue.append((current + _MINIMUM_REPEAT_TIME, packet)) return sent
def send(self, out, addr = dns._MDNS_ADDR, port = dns._MDNS_PORT): """Sends an outgoing packet. Note: this method is instrumented to provide low-level prevention of packet floods by throttling same-message sending to once per _MINIMUM_REPEAT_TIME ms. That will fail for a "regular" DNS server, which should also use the addr/port combo... """ current = dns.currentTimeMillis() log.info( '%s messages in suppression_queue', len(self.suppression_queue)) while self.suppression_queue and self.suppression_queue[0][0] < current: log.debug( 'Removing...' ) self.suppression_queue.pop(0) packet = out.packet() sent = False for i,(expire,old_packet) in enumerate(self.suppression_queue[:]): if old_packet == packet: log.debug( 'Dropping to prevent flood' ) sent = True if not sent: try: sent = self.socket.sendto(packet, 0, (addr, port)) except: # Ignore this, it may be a temporary loss of network connection pass self.suppression_queue.append( (current + _MINIMUM_REPEAT_TIME, packet ) ) return sent
def registerService(self, info, ttl=dns._DNS_TTL): """Registers service information to the network with a default TTL of 60 seconds. Zeroconf will then respond to requests for information for that service. The name of the service may be changed if needed to make it unique on the network.""" self.checkService(info) self.services[info.name.lower()] = info now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = self.serviceAnnouncement(info, ttl) self.send(out) i += 1 nextTime += _REGISTER_TIME
def registerService(self, info, ttl=dns._DNS_TTL): """Registers service information to the network with a default TTL of 60 seconds. Zeroconf will then respond to requests for information for that service. The name of the service may be changed if needed to make it unique on the network.""" self.checkService(info) self.services[info.name.lower()] = info now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = self.serviceAnnouncement( info, ttl ) self.send(out) i += 1 nextTime += _REGISTER_TIME
def addListener(self, listener, question): """Adds a listener for a given question. The listener will have its updateRecord method called when information is available to answer the question.""" now = dns.currentTimeMillis() self.listeners.append(listener) if question is not None: for record in self.cache.entriesWithName(question.name): if question.answeredBy(record) and not record.isExpired(now): listener.updateRecord(self, now, record) self.notifyAll()
def unregisterAllServices(self): """Unregister all registered services.""" if len(self.services) > 0: now = dns.currentTimeMillis() nextTime = now i = 0 while i < 3: if now < nextTime: self.wait(nextTime - now) now = dns.currentTimeMillis() continue out = dns.DNSOutgoing(dns._FLAGS_QR_RESPONSE | dns._FLAGS_AA) for info in list(self.services.values()): out.addAnswerAtTime(dns.DNSPointer(info.type, dns._TYPE_PTR, dns._CLASS_IN, 0, info.name), 0) out.addAnswerAtTime(dns.DNSService(info.name, dns._TYPE_SRV, dns._CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0) out.addAnswerAtTime(dns.DNSText(info.name, dns._TYPE_TXT, dns._CLASS_IN, 0, info.text), 0) if info.address: out.addAnswerAtTime(dns.DNSAddress(info.server, dns._TYPE_A, dns._CLASS_IN, 0, info.address), 0) self.send(out) i += 1 nextTime += _UNREGISTER_TIME
def run(self): while 1: if globals()['_GLOBAL_DONE']: return try: self.zeroconf.wait(10 * 1000) except ValueError as err: break if globals()['_GLOBAL_DONE']: return now = dns.currentTimeMillis() for record in self.zeroconf.cache.entries(): if record.isExpired(now): self.zeroconf.updateRecord(now, record) self.zeroconf.cache.remove(record)
def __init__(self, zeroconf, type, listener): """Creates a browser for a specific type""" threading.Thread.__init__(self) self.zeroconf = zeroconf self.type = type self.listener = listener self.daemon = True self.services = {} self.nextTime = dns.currentTimeMillis() self.delay = _BROWSER_TIME self.list = [] self.done = 0 self.zeroconf.addListener(self, dns.DNSQuestion(self.type, dns._TYPE_PTR, dns._CLASS_IN)) self.start()
def handleResponse(self, msg): """Deal with incoming response packets. All answers are held in the cache, and listeners are notified.""" now = dns.currentTimeMillis() for record in msg.answers: expired = record.isExpired(now) if record in self.cache.entries(): if expired: self.cache.remove(record) else: entry = self.cache.get(record) if entry is not None: entry.resetTTL(record) record = entry else: self.cache.add(record) self.updateRecord(now, record)