--- a/hgext/zeroconf/Zeroconf.py Tue Mar 01 08:53:40 2016 +0000
+++ b/hgext/zeroconf/Zeroconf.py Tue Mar 01 09:33:39 2016 +0000
@@ -34,7 +34,7 @@
- hostinfo
ignore unknown DNS record types
fixes to name decoding
- works alongside other processes using port 5353 (e.g. on Mac OS X)
+ works alongside other processes using port 5353 (e.g. Mac OS X)
tested against Mac OS X 10.3.2's mDNSResponder
corrections to removal of list entries for service browser"""
@@ -228,7 +228,8 @@
def __eq__(self, other):
"""Equality test on name, type, and class"""
if isinstance(other, DNSEntry):
- return self.name == other.name and self.type == other.type and self.clazz == other.clazz
+ return (self.name == other.name and self.type == other.type and
+ self.clazz == other.clazz)
return 0
def __ne__(self, other):
@@ -251,7 +252,8 @@
def toString(self, hdr, other):
"""String representation with additional information"""
- result = "%s[%s,%s" % (hdr, self.getType(self.type), self.getClazz(self.clazz))
+ result = ("%s[%s,%s" %
+ (hdr, self.getType(self.type), self.getClazz(self.clazz)))
if self.unique:
result += "-unique,"
else:
@@ -273,7 +275,9 @@
def answeredBy(self, rec):
"""Returns true if the question is answered by the record"""
- return self.clazz == rec.clazz and (self.type == rec.type or self.type == _TYPE_ANY) and self.name == rec.name
+ return (self.clazz == rec.clazz and
+ (self.type == rec.type or self.type == _TYPE_ANY) and
+ self.name == rec.name)
def __repr__(self):
"""String representation"""
@@ -338,7 +342,8 @@
def toString(self, other):
"""String representation with additional information"""
- arg = "%s/%s,%s" % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
+ arg = ("%s/%s,%s" %
+ (self.ttl, self.getRemainingTTL(currentTimeMillis()), other))
return DNSEntry.toString(self, "record", arg)
class DNSAddress(DNSRecord):
@@ -453,7 +458,10 @@
def __eq__(self, other):
"""Tests equality on priority, weight, port and server"""
if isinstance(other, DNSService):
- return self.priority == other.priority and self.weight == other.weight and self.port == other.port and self.server == other.server
+ return (self.priority == other.priority and
+ self.weight == other.weight and
+ self.port == other.port and
+ self.server == other.server)
return 0
def __repr__(self):
@@ -498,7 +506,8 @@
length = struct.calcsize(format)
for i in range(0, self.numQuestions):
name = self.readName()
- info = struct.unpack(format, self.data[self.offset:self.offset+length])
+ info = struct.unpack(format,
+ self.data[self.offset:self.offset+length])
self.offset += length
try:
@@ -538,28 +547,39 @@
return info[0]
def readOthers(self):
- """Reads the answers, authorities and additionals section of the packet"""
+ """Reads answers, authorities and additionals section of the packet"""
format = '!HHiH'
length = struct.calcsize(format)
n = self.numAnswers + self.numAuthorities + self.numAdditionals
for i in range(0, n):
domain = self.readName()
- info = struct.unpack(format, self.data[self.offset:self.offset+length])
+ info = struct.unpack(format,
+ self.data[self.offset:self.offset+length])
self.offset += length
rec = None
if info[0] == _TYPE_A:
- rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(4))
+ rec = DNSAddress(domain, info[0], info[1], info[2],
+ self.readString(4))
elif info[0] == _TYPE_CNAME or info[0] == _TYPE_PTR:
- rec = DNSPointer(domain, info[0], info[1], info[2], self.readName())
+ rec = DNSPointer(domain, info[0], info[1], info[2],
+ self.readName())
elif info[0] == _TYPE_TXT:
- rec = DNSText(domain, info[0], info[1], info[2], self.readString(info[3]))
+ rec = DNSText(domain, info[0], info[1], info[2],
+ self.readString(info[3]))
elif info[0] == _TYPE_SRV:
- rec = DNSService(domain, info[0], info[1], info[2], self.readUnsignedShort(), self.readUnsignedShort(), self.readUnsignedShort(), self.readName())
+ rec = DNSService(domain, info[0], info[1], info[2],
+ self.readUnsignedShort(),
+ self.readUnsignedShort(),
+ self.readUnsignedShort(),
+ self.readName())
elif info[0] == _TYPE_HINFO:
- rec = DNSHinfo(domain, info[0], info[1], info[2], self.readCharacterString(), self.readCharacterString())
+ rec = DNSHinfo(domain, info[0], info[1], info[2],
+ self.readCharacterString(),
+ self.readCharacterString())
elif info[0] == _TYPE_AAAA:
- rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(16))
+ rec = DNSAddress(domain, info[0], info[1], info[2],
+ self.readString(16))
else:
# Try to ignore types we don't know about
# this may mean the rest of the name is
@@ -972,7 +992,8 @@
self.done = 0
- self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
+ self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR,
+ _CLASS_IN))
self.start()
def updateRecord(self, zeroconf, now, record):
@@ -987,13 +1008,15 @@
oldrecord.resetTTL(record)
else:
del(self.services[record.alias.lower()])
- callback = lambda x: self.listener.removeService(x, self.type, record.alias)
+ callback = (lambda x:
+ self.listener.removeService(x, self.type, record.alias))
self.list.append(callback)
return
except Exception:
if not expired:
self.services[record.alias.lower()] = record
- callback = lambda x: self.listener.addService(x, self.type, record.alias)
+ callback = (lambda x:
+ self.listener.addService(x, self.type, record.alias))
self.list.append(callback)
expires = record.getExpirationTime(75)
@@ -1034,7 +1057,8 @@
class ServiceInfo(object):
"""Service information"""
- def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None):
+ def __init__(self, type, name, address=None, port=None, weight=0,
+ priority=0, properties=None, server=None):
"""Create a service description.
type: fully qualified service type name
@@ -1043,7 +1067,8 @@
port: port that the service runs on
weight: weight of the service
priority: priority of the service
- properties: dictionary of properties (or a string holding the bytes for the text field)
+ properties: dictionary of properties (or a string holding the bytes for
+ the text field)
server: fully qualified name for service host (defaults to name)"""
if not name.endswith(type):
@@ -1081,7 +1106,8 @@
suffix = ''
list.append('='.join((key, suffix)))
for item in list:
- result = ''.join((result, struct.pack('!c', chr(len(item))), item))
+ result = ''.join((result, struct.pack('!c', chr(len(item))),
+ item))
self.text = result
else:
self.text = properties
@@ -1175,7 +1201,9 @@
self.weight = record.weight
self.priority = record.priority
#self.address = None
- self.updateRecord(zeroconf, now, zeroconf.cache.getByDetails(self.server, _TYPE_A, _CLASS_IN))
+ self.updateRecord(zeroconf, now,
+ zeroconf.cache.getByDetails(self.server,
+ _TYPE_A, _CLASS_IN))
elif record.type == _TYPE_TXT:
if record.name == self.name:
self.setText(record.text)
@@ -1190,19 +1218,34 @@
last = now + timeout
result = 0
try:
- zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY, _CLASS_IN))
- while self.server is None or self.address is None or self.text is None:
+ zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY,
+ _CLASS_IN))
+ while (self.server is None or self.address is None or
+ self.text is None):
if last <= now:
return 0
if next <= now:
out = DNSOutgoing(_FLAGS_QR_QUERY)
- out.addQuestion(DNSQuestion(self.name, _TYPE_SRV, _CLASS_IN))
- out.addAnswerAtTime(zeroconf.cache.getByDetails(self.name, _TYPE_SRV, _CLASS_IN), now)
- out.addQuestion(DNSQuestion(self.name, _TYPE_TXT, _CLASS_IN))
- out.addAnswerAtTime(zeroconf.cache.getByDetails(self.name, _TYPE_TXT, _CLASS_IN), now)
+ out.addQuestion(DNSQuestion(self.name, _TYPE_SRV,
+ _CLASS_IN))
+ out.addAnswerAtTime(
+ zeroconf.cache.getByDetails(self.name,
+ _TYPE_SRV,
+ _CLASS_IN),
+ now)
+ out.addQuestion(DNSQuestion(self.name, _TYPE_TXT,
+ _CLASS_IN))
+ out.addAnswerAtTime(
+ zeroconf.cache.getByDetails(self.name, _TYPE_TXT,
+ _CLASS_IN),
+ now)
if self.server is not None:
- out.addQuestion(DNSQuestion(self.server, _TYPE_A, _CLASS_IN))
- out.addAnswerAtTime(zeroconf.cache.getByDetails(self.server, _TYPE_A, _CLASS_IN), now)
+ out.addQuestion(
+ DNSQuestion(self.server, _TYPE_A, _CLASS_IN))
+ out.addAnswerAtTime(
+ zeroconf.cache.getByDetails(self.server, _TYPE_A,
+ _CLASS_IN),
+ now)
zeroconf.send(out)
next = now + delay
delay = delay * 2
@@ -1227,7 +1270,8 @@
def __repr__(self):
"""String representation"""
- result = "service[%s,%s:%s," % (self.name, socket.inet_ntoa(self.getAddress()), self.port)
+ result = ("service[%s,%s:%s," %
+ (self.name, socket.inet_ntoa(self.getAddress()), self.port))
if self.text is None:
result += "None"
else:
@@ -1276,7 +1320,8 @@
# Some versions of linux raise an exception even though
# SO_REUSEADDR and SO_REUSEPORT have been set, so ignore it
pass
- self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
+ self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
+ socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
self.listeners = []
self.browsers = []
@@ -1353,11 +1398,20 @@
now = currentTimeMillis()
continue
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
- out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, ttl, info.name), 0)
- out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0)
- out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text), 0)
+ out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
+ _CLASS_IN, ttl, info.name), 0)
+ out.addAnswerAtTime(
+ DNSService(
+ info.name, _TYPE_SRV,
+ _CLASS_IN, ttl, info.priority, info.weight, info.port,
+ info.server),
+ 0)
+ out.addAnswerAtTime(
+ DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text),
+ 0)
if info.address:
- out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, ttl, info.address), 0)
+ out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
+ _CLASS_IN, ttl, info.address), 0)
self.send(out)
i += 1
nextTime += _REGISTER_TIME
@@ -1381,11 +1435,18 @@
now = currentTimeMillis()
continue
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
- out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
- out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0)
- out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
+ out.addAnswerAtTime(
+ DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
+ out.addAnswerAtTime(
+ DNSService(info.name, _TYPE_SRV,
+ _CLASS_IN, 0, info.priority, info.weight, info.port,
+ info.name),
+ 0)
+ out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
+ _CLASS_IN, 0, info.text), 0)
if info.address:
- out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
+ out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
+ _CLASS_IN, 0, info.address), 0)
self.send(out)
i += 1
nextTime += _UNREGISTER_TIME
@@ -1403,11 +1464,18 @@
continue
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
for info in self.services.values():
- out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
- out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0)
- out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
+ out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
+ _CLASS_IN, 0, info.name), 0)
+ out.addAnswerAtTime(
+ DNSService(info.name, _TYPE_SRV,
+ _CLASS_IN, 0, info.priority, info.weight,
+ info.port, info.server),
+ 0)
+ out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
+ _CLASS_IN, 0, info.text), 0)
if info.address:
- out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
+ out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
+ _CLASS_IN, 0, info.address), 0)
self.send(out)
i += 1
nextTime += _UNREGISTER_TIME
@@ -1420,9 +1488,11 @@
i = 0
while i < 3:
for record in self.cache.entriesWithName(info.type):
- if record.type == _TYPE_PTR and not record.isExpired(now) and record.alias == info.name:
+ if (record.type == _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
+ info.name = ("%w.[%s:%d].%s" %
+ (info.name, info.address, info.port, info.type))
self.checkService(info)
return
raise NonUniqueNameException
@@ -1433,7 +1503,8 @@
out = DNSOutgoing(_FLAGS_QR_QUERY | _FLAGS_AA)
self.debug = out
out.addQuestion(DNSQuestion(info.type, _TYPE_PTR, _CLASS_IN))
- out.addAuthoritativeAnswer(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, info.name))
+ out.addAuthoritativeAnswer(DNSPointer(info.type, _TYPE_PTR,
+ _CLASS_IN, _DNS_TTL, info.name))
self.send(out)
i += 1
nextTime += _CHECK_TIME
@@ -1502,12 +1573,17 @@
for stype in self.servicetypes.keys():
if out is None:
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
- out.addAnswer(msg, DNSPointer("_services._dns-sd._udp.local.", _TYPE_PTR, _CLASS_IN, _DNS_TTL, stype))
+ out.addAnswer(msg,
+ DNSPointer(
+ "_services._dns-sd._udp.local.",
+ _TYPE_PTR, _CLASS_IN,
+ _DNS_TTL, stype))
for service in self.services.values():
if question.name == service.type:
if out is None:
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
- out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, service.name))
+ out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR,
+ _CLASS_IN, _DNS_TTL, service.name))
else:
try:
if out is None:
@@ -1517,17 +1593,31 @@
if question.type == _TYPE_A or question.type == _TYPE_ANY:
for service in self.services.values():
if service.server == question.name.lower():
- out.addAnswer(msg, DNSAddress(question.name, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
+ out.addAnswer(msg,
+ DNSAddress(question.name, _TYPE_A,
+ _CLASS_IN | _CLASS_UNIQUE,
+ _DNS_TTL, service.address))
service = self.services.get(question.name.lower(), None)
if not service: continue
- if question.type == _TYPE_SRV or question.type == _TYPE_ANY:
- out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
- if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
- out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
+ if (question.type == _TYPE_SRV or
+ question.type == _TYPE_ANY):
+ out.addAnswer(msg,
+ DNSService(question.name, _TYPE_SRV,
+ _CLASS_IN | _CLASS_UNIQUE,
+ _DNS_TTL, service.priority,
+ service.weight, service.port,
+ service.server))
+ if (question.type == _TYPE_TXT or
+ question.type == _TYPE_ANY):
+ out.addAnswer(msg, DNSText(question.name, _TYPE_TXT,
+ _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
if question.type == _TYPE_SRV:
- out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
+ out.addAdditionalAnswer(
+ DNSAddress(service.server, _TYPE_A,
+ _CLASS_IN | _CLASS_UNIQUE,
+ _DNS_TTL, service.address))
except Exception:
traceback.print_exc()
@@ -1553,7 +1643,8 @@
self.notifyAll()
self.engine.notify()
self.unregisterAllServices()
- self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
+ self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP,
+ socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
self.socket.close()
# Test a few module features, including service registration, service
@@ -1564,15 +1655,20 @@
r = Zeroconf()
print("1. Testing registration of a service...")
desc = {'version':'0.10','a':'test value', 'b':'another value'}
- info = ServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.", socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
+ info = ServiceInfo("_http._tcp.local.",
+ "My Service Name._http._tcp.local.",
+ socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
print(" Registering service...")
r.registerService(info)
print(" Registration done.")
print("2. Testing query of service information...")
- print(" Getting ZOE service:", str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local.")))
+ print(" Getting ZOE service:",
+ str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local.")))
print(" Query done.")
print("3. Testing query of own service...")
- print(" Getting self:", str(r.getServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.")))
+ print(" Getting self:",
+ str(r.getServiceInfo("_http._tcp.local.",
+ "My Service Name._http._tcp.local.")))
print(" Query done.")
print("4. Testing unregister of service information...")
r.unregisterService(info)