util/Zeroconf.py
changeset 1784 64beb9e9c749
parent 1783 3311eea28d56
child 1826 91796f408540
--- 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 <a href="http://strangeberry.com">StrangeBerry</a>,
-    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 <a href="http://strangeberry.com">StrangeBerry</a>,
+#     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)