diff -r 31e63e25b4cc -r 64beb9e9c749 util/Zeroconf.py
--- a/util/Zeroconf.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/Zeroconf.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,82 +1,78 @@
-""" Multicast DNS Service Discovery for Python, v0.12
- Copyright (C) 2003, Paul Scott-Murphy
-
- This module provides a framework for the use of DNS Service Discovery
- using IP multicast. It has been tested against the JRendezvous
- implementation from StrangeBerry,
- and against the mDNSResponder from Mac OS X 10.3.8.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-"""
-
-"""0.12 update - allow selection of binding interface
- typo fix - Thanks A. M. Kuchlingi
- removed all use of word 'Rendezvous' - this is an API change"""
-
-"""0.11 update - correction to comments for addListener method
- support for new record types seen from OS X
- - IPv6 address
- - hostinfo
- ignore unknown DNS record types
- fixes to name decoding
- works alongside other processes using port 5353 (e.g. on Mac OS X)
- tested against Mac OS X 10.3.2's mDNSResponder
- corrections to removal of list entries for service browser"""
-
-"""0.10 update - Jonathon Paisley contributed these corrections:
- always multicast replies, even when query is unicast
- correct a pointer encoding problem
- can now write records in any order
- traceback shown on failure
- better TXT record parsing
- server is now separate from name
- can cancel a service browser
-
- modified some unit tests to accommodate these changes"""
-
-"""0.09 update - remove all records on service unregistration
- fix DOS security problem with readName"""
-
-"""0.08 update - changed licensing to LGPL"""
-
-"""0.07 update - faster shutdown on engine
- pointer encoding of outgoing names
- ServiceBrowser now works
- new unit tests"""
-
-"""0.06 update - small improvements with unit tests
- added defined exception types
- new style objects
- fixed hostname/interface problem
- fixed socket timeout problem
- fixed addServiceListener() typo bug
- using select() for socket reads
- tested on Debian unstable with Python 2.2.2"""
-
-"""0.05 update - ensure case insensitivty on domain names
- support for unicast DNS queries"""
-
-"""0.04 update - added some unit tests
- added __ne__ adjuncts where required
- ensure names end in '.local.'
- timeout on receiving socket for clean shutdown"""
-
-__author__ = "Paul Scott-Murphy"
-__email__ = "paul at scott dash murphy dot com"
-__version__ = "0.12"
+# Multicast DNS Service Discovery for Python, v0.12
+# Copyright (C) 2003, Paul Scott-Murphy
+#
+# This module provides a framework for the use of DNS Service Discovery
+# using IP multicast. It has been tested against the JRendezvous
+# implementation from StrangeBerry,
+# and against the mDNSResponder from Mac OS X 10.3.8.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+#
+# 0.12 update - allow selection of binding interface
+# typo fix - Thanks A. M. Kuchlingi
+# removed all use of word 'Rendezvous' - this is an API change
+#
+# 0.11 update - correction to comments for addListener method
+# support for new record types seen from OS X
+# - IPv6 address
+# - hostinfo
+# ignore unknown DNS record types
+# fixes to name decoding
+# works alongside other processes using port 5353 (e.g. on Mac OS X)
+# tested against Mac OS X 10.3.2's mDNSResponder
+# corrections to removal of list entries for service browser
+#
+# 0.10 update - Jonathon Paisley contributed these corrections:
+# always multicast replies, even when query is unicast
+# correct a pointer encoding problem
+# can now write records in any order
+# traceback shown on failure
+# better TXT record parsing
+# server is now separate from name
+# can cancel a service browser
+#
+# modified some unit tests to accommodate these changes
+#
+# 0.09 update - remove all records on service unregistration
+# fix DOS security problem with readName
+#
+# 0.08 update - changed licensing to LGPL
+#
+# 0.07 update - faster shutdown on engine
+# pointer encoding of outgoing names
+# ServiceBrowser now works
+# new unit tests
+#
+# 0.06 update - small improvements with unit tests
+# added defined exception types
+# new style objects
+# fixed hostname/interface problem
+# fixed socket timeout problem
+# fixed addServiceListener() typo bug
+# using select() for socket reads
+# tested on Debian unstable with Python 2.2.2
+#
+# 0.05 update - ensure case insensitivty on domain names
+# support for unicast DNS queries
+#
+# 0.04 update - added some unit tests
+# added __ne__ adjuncts where required
+# ensure names end in '.local.'
+# timeout on receiving socket for clean shutdown
import string
import time
@@ -86,6 +82,12 @@
import select
import traceback
+
+__author__ = "Paul Scott-Murphy"
+__email__ = "paul at scott dash murphy dot com"
+__version__ = "0.12"
+
+
__all__ = ["Zeroconf", "ServiceInfo", "ServiceBrowser"]
# hook for threads
@@ -101,27 +103,27 @@
_BROWSER_TIME = 500
# Some DNS constants
-
+
_MDNS_ADDR = '224.0.0.251'
-_MDNS_PORT = 5353;
-_DNS_PORT = 53;
-_DNS_TTL = 60 * 60; # one hour default TTL
-
-_MAX_MSG_TYPICAL = 1460 # unused
+_MDNS_PORT = 5353
+_DNS_PORT = 53
+_DNS_TTL = 60 * 60 # one hour default TTL
+
+_MAX_MSG_TYPICAL = 1460 # unused
_MAX_MSG_ABSOLUTE = 8972
-_FLAGS_QR_MASK = 0x8000 # query response mask
-_FLAGS_QR_QUERY = 0x0000 # query
-_FLAGS_QR_RESPONSE = 0x8000 # response
-
-_FLAGS_AA = 0x0400 # Authorative answer
-_FLAGS_TC = 0x0200 # Truncated
-_FLAGS_RD = 0x0100 # Recursion desired
-_FLAGS_RA = 0x8000 # Recursion available
-
-_FLAGS_Z = 0x0040 # Zero
-_FLAGS_AD = 0x0020 # Authentic data
-_FLAGS_CD = 0x0010 # Checking disabled
+_FLAGS_QR_MASK = 0x8000 # query response mask
+_FLAGS_QR_QUERY = 0x0000 # query
+_FLAGS_QR_RESPONSE = 0x8000 # response
+
+_FLAGS_AA = 0x0400 # Authorative answer
+_FLAGS_TC = 0x0200 # Truncated
+_FLAGS_RD = 0x0100 # Recursion desired
+_FLAGS_RA = 0x8000 # Recursion available
+
+_FLAGS_Z = 0x0040 # Zero
+_FLAGS_AD = 0x0020 # Authentic data
+_FLAGS_CD = 0x0010 # Checking disabled
_CLASS_IN = 1
_CLASS_CS = 2
@@ -150,65 +152,76 @@
_TYPE_TXT = 16
_TYPE_AAAA = 28
_TYPE_SRV = 33
-_TYPE_ANY = 255
+_TYPE_ANY = 255
# Mapping constants to names
-_CLASSES = { _CLASS_IN : "in",
- _CLASS_CS : "cs",
- _CLASS_CH : "ch",
- _CLASS_HS : "hs",
- _CLASS_NONE : "none",
- _CLASS_ANY : "any" }
-
-_TYPES = { _TYPE_A : "a",
- _TYPE_NS : "ns",
- _TYPE_MD : "md",
- _TYPE_MF : "mf",
- _TYPE_CNAME : "cname",
- _TYPE_SOA : "soa",
- _TYPE_MB : "mb",
- _TYPE_MG : "mg",
- _TYPE_MR : "mr",
- _TYPE_NULL : "null",
- _TYPE_WKS : "wks",
- _TYPE_PTR : "ptr",
- _TYPE_HINFO : "hinfo",
- _TYPE_MINFO : "minfo",
- _TYPE_MX : "mx",
- _TYPE_TXT : "txt",
- _TYPE_AAAA : "quada",
- _TYPE_SRV : "srv",
- _TYPE_ANY : "any" }
+_CLASSES = {
+ _CLASS_IN: "in",
+ _CLASS_CS: "cs",
+ _CLASS_CH: "ch",
+ _CLASS_HS: "hs",
+ _CLASS_NONE: "none",
+ _CLASS_ANY: "any"
+}
+
+_TYPES = {
+ _TYPE_A: "a",
+ _TYPE_NS: "ns",
+ _TYPE_MD: "md",
+ _TYPE_MF: "mf",
+ _TYPE_CNAME: "cname",
+ _TYPE_SOA: "soa",
+ _TYPE_MB: "mb",
+ _TYPE_MG: "mg",
+ _TYPE_MR: "mr",
+ _TYPE_NULL: "null",
+ _TYPE_WKS: "wks",
+ _TYPE_PTR: "ptr",
+ _TYPE_HINFO: "hinfo",
+ _TYPE_MINFO: "minfo",
+ _TYPE_MX: "mx",
+ _TYPE_TXT: "txt",
+ _TYPE_AAAA: "quada",
+ _TYPE_SRV: "srv",
+ _TYPE_ANY: "any"
+}
# utility functions
+
def currentTimeMillis():
"""Current system time in milliseconds"""
return time.time() * 1000
# Exceptions
+
class NonLocalNameException(Exception):
pass
+
class NonUniqueNameException(Exception):
pass
+
class NamePartTooLongException(Exception):
pass
+
class AbstractMethodException(Exception):
pass
+
class BadTypeInNameException(Exception):
pass
# implementation classes
+
class DNSEntry(object):
"""A DNS entry"""
-
+
def __init__(self, name, type, clazz):
self.key = string.lower(name)
self.name = name
@@ -230,14 +243,14 @@
"""Class accessor"""
try:
return _CLASSES[clazz]
- except:
+ except Exception:
return "?(%s)" % (clazz)
def getType(self, type):
"""Type accessor"""
try:
return _TYPES[type]
- except:
+ except Exception:
return "?(%s)" % (type)
def toString(self, hdr, other):
@@ -254,9 +267,10 @@
result += "]"
return result
+
class DNSQuestion(DNSEntry):
"""A DNS question entry"""
-
+
def __init__(self, name, type, clazz):
if not name.endswith(".local."):
raise NonLocalNameException
@@ -273,7 +287,7 @@
class DNSRecord(DNSEntry):
"""A DNS record - like a DNS entry, but has a TTL"""
-
+
def __init__(self, name, type, clazz, ttl):
DNSEntry.__init__(self, name, type, clazz)
self.ttl = ttl
@@ -332,9 +346,10 @@
arg = "%s/%s,%s" % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
return DNSEntry.toString(self, "record", arg)
+
class DNSAddress(DNSRecord):
"""A DNS address record"""
-
+
def __init__(self, name, type, clazz, ttl, address):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.address = address
@@ -353,9 +368,10 @@
"""String representation"""
try:
return socket.inet_ntoa(self.address)
- except:
+ except Exception:
return self.address
+
class DNSHinfo(DNSRecord):
"""A DNS host information record"""
@@ -378,10 +394,11 @@
def __repr__(self):
"""String representation"""
return self.cpu + " " + self.os
-
+
+
class DNSPointer(DNSRecord):
"""A DNS pointer record"""
-
+
def __init__(self, name, type, clazz, ttl, alias):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.alias = alias
@@ -400,9 +417,10 @@
"""String representation"""
return self.toString(self.alias)
+
class DNSText(DNSRecord):
"""A DNS text record"""
-
+
def __init__(self, name, type, clazz, ttl, text):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.text = text
@@ -424,9 +442,10 @@
else:
return self.toString(self.text)
+
class DNSService(DNSRecord):
"""A DNS service record"""
-
+
def __init__(self, name, type, clazz, ttl, priority, weight, port, server):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.priority = priority
@@ -451,9 +470,10 @@
"""String representation"""
return self.toString("%s:%s" % (self.server, self.port))
+
class DNSIncoming(object):
"""Object representation of an incoming DNS packet"""
-
+
def __init__(self, data):
"""Constructor from string holding bytes of packet"""
self.offset = 0
@@ -464,7 +484,7 @@
self.numAnswers = 0
self.numAuthorities = 0
self.numAdditionals = 0
-
+
self.readHeader()
self.readQuestions()
self.readOthers()
@@ -491,7 +511,7 @@
name = self.readName()
info = struct.unpack(format, self.data[self.offset:self.offset+length])
self.offset += length
-
+
question = DNSQuestion(name, info[0], info[1])
self.questions.append(question)
@@ -512,7 +532,7 @@
def readString(self, len):
"""Reads a string of a given length from the packet"""
format = '!' + str(len) + 's'
- length = struct.calcsize(format)
+ length = struct.calcsize(format)
info = struct.unpack(format, self.data[self.offset:self.offset+length])
self.offset += length
return info[0]
@@ -555,13 +575,13 @@
# so this is left for debugging. New types
# encountered need to be parsed properly.
#
- #print "UNKNOWN TYPE = " + str(info[0])
- #raise BadTypeInNameException
+ # print "UNKNOWN TYPE = " + str(info[0])
+ # raise BadTypeInNameException
pass
if rec is not None:
self.answers.append(rec)
-
+
def isQuery(self):
"""Returns true if this is a query"""
return (self.flags & _FLAGS_QR_MASK) == _FLAGS_QR_QUERY
@@ -574,7 +594,7 @@
"""Reads a UTF-8 string of a given length from the packet"""
result = self.data[offset:offset+len].decode('utf-8')
return result
-
+
def readName(self):
"""Reads a domain name from the packet"""
result = ''
@@ -607,12 +627,12 @@
self.offset = off
return result
-
-
+
+
class DNSOutgoing(object):
"""Object representation of an outgoing packet"""
-
- def __init__(self, flags, multicast = 1):
+
+ def __init__(self, flags, multicast=1):
self.finished = 0
self.id = 0
self.multicast = multicast
@@ -620,7 +640,7 @@
self.names = {}
self.data = []
self.size = 12
-
+
self.questions = []
self.answers = []
self.authorities = []
@@ -660,7 +680,7 @@
format = '!H'
self.data.insert(index, struct.pack(format, value))
self.size += 2
-
+
def writeShort(self, value):
"""Writes an unsigned short to the packet"""
format = '!H'
@@ -739,9 +759,9 @@
self.size += 2
record.write(self)
self.size -= 2
-
+
length = len(''.join(self.data[index:]))
- self.insertShort(index, length) # Here is the short we adjusted for
+ self.insertShort(index, length) # Here is the short we adjusted for
def packet(self):
"""Returns a string containing the packet's bytes
@@ -758,7 +778,7 @@
self.writeRecord(authority, 0)
for additional in self.additionals:
self.writeRecord(additional, 0)
-
+
self.insertShort(0, len(self.additionals))
self.insertShort(0, len(self.authorities))
self.insertShort(0, len(self.answers))
@@ -773,7 +793,7 @@
class DNSCache(object):
"""A cache of DNS entries"""
-
+
def __init__(self):
self.cache = {}
@@ -781,7 +801,7 @@
"""Adds an entry"""
try:
list = self.cache[entry.key]
- except:
+ except Exception:
list = self.cache[entry.key] = []
list.append(entry)
@@ -790,7 +810,7 @@
try:
list = self.cache[entry.key]
list.remove(entry)
- except:
+ except Exception:
pass
def get(self, entry):
@@ -799,7 +819,7 @@
try:
list = self.cache[entry.key]
return list[list.index(entry)]
- except:
+ except Exception:
return None
def getByDetails(self, name, type, clazz):
@@ -812,7 +832,7 @@
"""Returns a list of entries whose key matches the name."""
try:
return self.cache[name]
- except:
+ except Exception:
return []
def entries(self):
@@ -820,7 +840,7 @@
def add(x, y): return x+y
try:
return reduce(add, self.cache.values())
- except:
+ except Exception:
return []
@@ -839,7 +859,7 @@
def __init__(self, zeroconf):
threading.Thread.__init__(self)
self.zeroconf = zeroconf
- self.readers = {} # maps socket to reader
+ self.readers = {} # maps socket to reader
self.timeout = 5
self.condition = threading.Condition()
self.start()
@@ -860,10 +880,10 @@
for socket in rr:
try:
self.readers[socket].handle_read()
- except:
+ except Exception:
# Ignore errors that occur on shutdown
pass
- except:
+ except Exception:
pass
def getReaders(self):
@@ -872,7 +892,7 @@
result = self.readers.keys()
self.condition.release()
return result
-
+
def addReader(self, reader, socket):
self.condition.acquire()
self.readers[socket] = reader
@@ -890,6 +910,7 @@
self.condition.notify()
self.condition.release()
+
class Listener(object):
"""A Listener is used by this module to listen on the multicast
group to which DNS messages are sent, allowing the implementation
@@ -897,7 +918,7 @@
It requires registration with an Engine object in order to have
the read() method called when a socket is availble for reading."""
-
+
def __init__(self, zeroconf):
self.zeroconf = zeroconf
self.zeroconf.engine.addReader(self, self.zeroconf.socket)
@@ -924,7 +945,7 @@
class Reaper(threading.Thread):
"""A Reaper is used by this module to remove cache entries that
have expired."""
-
+
def __init__(self, zeroconf):
threading.Thread.__init__(self)
self.zeroconf = zeroconf
@@ -948,7 +969,7 @@
The listener object will have its addService() and
removeService() methods called when this browser
discovers changes in the services availability."""
-
+
def __init__(self, zeroconf, type, listener):
"""Creates a browser for a specific type"""
threading.Thread.__init__(self)
@@ -959,7 +980,7 @@
self.nextTime = currentTimeMillis()
self.delay = _BROWSER_TIME
self.list = []
-
+
self.done = 0
self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
@@ -976,14 +997,16 @@
if not expired:
oldrecord.resetTTL(record)
else:
+ def callback(x):
+ return self.listener.removeService(x, self.type, record.alias)
del(self.services[record.alias.lower()])
- callback = lambda x: self.listener.removeService(x, self.type, record.alias)
self.list.append(callback)
return
- except:
+ except Exception:
if not expired:
+ def callback(x):
+ return self.listener.addService(x, self.type, record.alias)
self.services[record.alias.lower()] = record
- callback = lambda x: self.listener.addService(x, self.type, record.alias)
self.list.append(callback)
expires = record.getExpirationTime(75)
@@ -1019,11 +1042,11 @@
if event is not None:
event(self.zeroconf)
-
+
class ServiceInfo(object):
"""Service information"""
-
+
def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None):
"""Create a service description.
@@ -1089,7 +1112,7 @@
index += 1
strs.append(text[index:index+length])
index += length
-
+
for s in strs:
eindex = s.find('=')
if eindex == -1:
@@ -1105,14 +1128,14 @@
value = 0
# Only update non-existent properties
- if key and result.get(key) == None:
+ if key and result.get(key) is None:
result[key] = value
self.properties = result
- except:
+ except Exception:
traceback.print_exc()
self.properties = None
-
+
def getType(self):
"""Type accessor"""
return self.type
@@ -1200,7 +1223,7 @@
result = 1
finally:
zeroconf.removeListener(self)
-
+
return result
def __eq__(self, other):
@@ -1225,7 +1248,7 @@
result += self.text[:17] + "..."
result += "]"
return result
-
+
class Zeroconf(object):
"""Implementation of Zeroconf Multicast DNS Service Discovery
@@ -1242,7 +1265,7 @@
try:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
- except:
+ except Exception:
# SO_REUSEADDR should be equivalent to SO_REUSEPORT for
# multicast UDP sockets (p 731, "TCP/IP Illustrated,
# Volume 2"), but some BSD-derived systems require
@@ -1257,7 +1280,7 @@
self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
try:
self.socket.bind(self.group)
- except:
+ except Exception:
# Some versions of linux raise an exception even though
# the SO_REUSE* options have been set, so ignore it
#
@@ -1274,7 +1297,7 @@
self.cache = DNSCache()
self.condition = threading.Condition()
-
+
self.engine = Engine(self)
self.listener = Listener(self)
self.reaper = Reaper(self)
@@ -1354,7 +1377,7 @@
"""Unregister a service."""
try:
del(self.services[info.name.lower()])
- except:
+ except Exception:
pass
now = currentTimeMillis()
nextTime = now
@@ -1439,7 +1462,7 @@
try:
self.listeners.remove(listener)
self.notifyAll()
- except:
+ except Exception:
pass
def updateRecord(self, now, rec):
@@ -1465,7 +1488,7 @@
record = entry
else:
self.cache.add(record)
-
+
self.updateRecord(now, record)
def handleQuery(self, msg, addr, port):
@@ -1479,7 +1502,7 @@
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, 0)
for question in msg.questions:
out.addQuestion(question)
-
+
for question in msg.questions:
if question.type == _TYPE_PTR:
for service in self.services.values():
@@ -1491,36 +1514,37 @@
try:
if out is None:
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
-
+
# Answer A record queries for any service addresses we know
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))
-
+
service = self.services.get(question.name.lower(), None)
- if not service: continue
-
+ 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:
out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
- except:
+ except Exception:
traceback.print_exc()
-
+
if out is not None and out.answers:
out.id = msg.id
self.send(out, addr, port)
- def send(self, out, addr = _MDNS_ADDR, port = _MDNS_PORT):
+ def send(self, out, addr=_MDNS_ADDR, port=_MDNS_PORT):
"""Sends an outgoing packet."""
# This is a quick test to see if we can parse the packets we generate
- #temp = DNSIncoming(out.packet())
+ # temp = DNSIncoming(out.packet())
try:
bytes_sent = self.socket.sendto(out.packet(), 0, (addr, port))
- except:
+ except Exception:
# Ignore this, it may be a temporary loss of network connection
pass
@@ -1534,15 +1558,16 @@
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.close()
-
+
# Test a few module features, including service registration, service
# query (for Zoe), and service unregistration.
-if __name__ == '__main__':
+
+if __name__ == '__main__':
print "Multicast DNS Service Discovery for Python, version", __version__
r = Zeroconf()
print "1. Testing registration of a service..."
- desc = {'version':'0.10','a':'test value', 'b':'another value'}
+ 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)
print " Registering service..."
r.registerService(info)