util/Zeroconf.py
changeset 1780 c52d1460cea8
parent 1762 fcc406143e5b
child 1782 5b6ad7a7fd9d
equal deleted inserted replaced
1779:6cf16e5bfbf9 1780:c52d1460cea8
   239 
   239 
   240     def getClazz(self, clazz):
   240     def getClazz(self, clazz):
   241         """Class accessor"""
   241         """Class accessor"""
   242         try:
   242         try:
   243             return _CLASSES[clazz]
   243             return _CLASSES[clazz]
   244         except:
   244         except Exception:
   245             return "?(%s)" % (clazz)
   245             return "?(%s)" % (clazz)
   246 
   246 
   247     def getType(self, type):
   247     def getType(self, type):
   248         """Type accessor"""
   248         """Type accessor"""
   249         try:
   249         try:
   250             return _TYPES[type]
   250             return _TYPES[type]
   251         except:
   251         except Exception:
   252             return "?(%s)" % (type)
   252             return "?(%s)" % (type)
   253 
   253 
   254     def toString(self, hdr, other):
   254     def toString(self, hdr, other):
   255         """String representation with additional information"""
   255         """String representation with additional information"""
   256         result = "%s[%s,%s" % (hdr, self.getType(self.type), self.getClazz(self.clazz))
   256         result = "%s[%s,%s" % (hdr, self.getType(self.type), self.getClazz(self.clazz))
   364 
   364 
   365     def __repr__(self):
   365     def __repr__(self):
   366         """String representation"""
   366         """String representation"""
   367         try:
   367         try:
   368             return socket.inet_ntoa(self.address)
   368             return socket.inet_ntoa(self.address)
   369         except:
   369         except Exception:
   370             return self.address
   370             return self.address
   371 
   371 
   372 
   372 
   373 class DNSHinfo(DNSRecord):
   373 class DNSHinfo(DNSRecord):
   374     """A DNS host information record"""
   374     """A DNS host information record"""
   797 
   797 
   798     def add(self, entry):
   798     def add(self, entry):
   799         """Adds an entry"""
   799         """Adds an entry"""
   800         try:
   800         try:
   801             list = self.cache[entry.key]
   801             list = self.cache[entry.key]
   802         except:
   802         except Exception:
   803             list = self.cache[entry.key] = []
   803             list = self.cache[entry.key] = []
   804         list.append(entry)
   804         list.append(entry)
   805 
   805 
   806     def remove(self, entry):
   806     def remove(self, entry):
   807         """Removes an entry"""
   807         """Removes an entry"""
   808         try:
   808         try:
   809             list = self.cache[entry.key]
   809             list = self.cache[entry.key]
   810             list.remove(entry)
   810             list.remove(entry)
   811         except:
   811         except Exception:
   812             pass
   812             pass
   813 
   813 
   814     def get(self, entry):
   814     def get(self, entry):
   815         """Gets an entry by key.  Will return None if there is no
   815         """Gets an entry by key.  Will return None if there is no
   816         matching entry."""
   816         matching entry."""
   817         try:
   817         try:
   818             list = self.cache[entry.key]
   818             list = self.cache[entry.key]
   819             return list[list.index(entry)]
   819             return list[list.index(entry)]
   820         except:
   820         except Exception:
   821             return None
   821             return None
   822 
   822 
   823     def getByDetails(self, name, type, clazz):
   823     def getByDetails(self, name, type, clazz):
   824         """Gets an entry by details.  Will return None if there is
   824         """Gets an entry by details.  Will return None if there is
   825         no matching entry."""
   825         no matching entry."""
   828 
   828 
   829     def entriesWithName(self, name):
   829     def entriesWithName(self, name):
   830         """Returns a list of entries whose key matches the name."""
   830         """Returns a list of entries whose key matches the name."""
   831         try:
   831         try:
   832             return self.cache[name]
   832             return self.cache[name]
   833         except:
   833         except Exception:
   834             return []
   834             return []
   835 
   835 
   836     def entries(self):
   836     def entries(self):
   837         """Returns a list of all entries"""
   837         """Returns a list of all entries"""
   838         def add(x, y): return x+y
   838         def add(x, y): return x+y
   839         try:
   839         try:
   840             return reduce(add, self.cache.values())
   840             return reduce(add, self.cache.values())
   841         except:
   841         except Exception:
   842             return []
   842             return []
   843 
   843 
   844 
   844 
   845 class Engine(threading.Thread):
   845 class Engine(threading.Thread):
   846     """An engine wraps read access to sockets, allowing objects that
   846     """An engine wraps read access to sockets, allowing objects that
   876                 try:
   876                 try:
   877                     rr, wr, er = select.select(rs, [], [], self.timeout)
   877                     rr, wr, er = select.select(rs, [], [], self.timeout)
   878                     for socket in rr:
   878                     for socket in rr:
   879                         try:
   879                         try:
   880                             self.readers[socket].handle_read()
   880                             self.readers[socket].handle_read()
   881                         except:
   881                         except Exception:
   882                             # Ignore errors that occur on shutdown
   882                             # Ignore errors that occur on shutdown
   883                             pass
   883                             pass
   884                 except:
   884                 except Exception:
   885                     pass
   885                     pass
   886 
   886 
   887     def getReaders(self):
   887     def getReaders(self):
   888         result = []
   888         result = []
   889         self.condition.acquire()
   889         self.condition.acquire()
   998                     def callback(x):
   998                     def callback(x):
   999                         return self.listener.removeService(x, self.type, record.alias)
   999                         return self.listener.removeService(x, self.type, record.alias)
  1000                     del(self.services[record.alias.lower()])
  1000                     del(self.services[record.alias.lower()])
  1001                     self.list.append(callback)
  1001                     self.list.append(callback)
  1002                     return
  1002                     return
  1003             except:
  1003             except Exception:
  1004                 if not expired:
  1004                 if not expired:
  1005                     def callback(x):
  1005                     def callback(x):
  1006                         return self.listener.addService(x, self.type, record.alias)
  1006                         return self.listener.addService(x, self.type, record.alias)
  1007                     self.services[record.alias.lower()] = record
  1007                     self.services[record.alias.lower()] = record
  1008                     self.list.append(callback)
  1008                     self.list.append(callback)
  1128                 # Only update non-existent properties
  1128                 # Only update non-existent properties
  1129                 if key and result.get(key) is None:
  1129                 if key and result.get(key) is None:
  1130                     result[key] = value
  1130                     result[key] = value
  1131 
  1131 
  1132             self.properties = result
  1132             self.properties = result
  1133         except:
  1133         except Exception:
  1134             traceback.print_exc()
  1134             traceback.print_exc()
  1135             self.properties = None
  1135             self.properties = None
  1136 
  1136 
  1137     def getType(self):
  1137     def getType(self):
  1138         """Type accessor"""
  1138         """Type accessor"""
  1261         self.group = ('', _MDNS_PORT)
  1261         self.group = ('', _MDNS_PORT)
  1262         self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  1262         self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  1263         try:
  1263         try:
  1264             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  1264             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  1265             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  1265             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  1266         except:
  1266         except Exception:
  1267             # SO_REUSEADDR should be equivalent to SO_REUSEPORT for
  1267             # SO_REUSEADDR should be equivalent to SO_REUSEPORT for
  1268             # multicast UDP sockets (p 731, "TCP/IP Illustrated,
  1268             # multicast UDP sockets (p 731, "TCP/IP Illustrated,
  1269             # Volume 2"), but some BSD-derived systems require
  1269             # Volume 2"), but some BSD-derived systems require
  1270             # SO_REUSEPORT to be specified explicity.  Also, not all
  1270             # SO_REUSEPORT to be specified explicity.  Also, not all
  1271             # versions of Python have SO_REUSEPORT available.  So
  1271             # versions of Python have SO_REUSEPORT available.  So
  1276             pass
  1276             pass
  1277         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 255)
  1277         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 255)
  1278         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
  1278         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
  1279         try:
  1279         try:
  1280             self.socket.bind(self.group)
  1280             self.socket.bind(self.group)
  1281         except:
  1281         except Exception:
  1282             # Some versions of linux raise an exception even though
  1282             # Some versions of linux raise an exception even though
  1283             # the SO_REUSE* options have been set, so ignore it
  1283             # the SO_REUSE* options have been set, so ignore it
  1284             #
  1284             #
  1285             pass
  1285             pass
  1286 
  1286 
  1373 
  1373 
  1374     def unregisterService(self, info):
  1374     def unregisterService(self, info):
  1375         """Unregister a service."""
  1375         """Unregister a service."""
  1376         try:
  1376         try:
  1377             del(self.services[info.name.lower()])
  1377             del(self.services[info.name.lower()])
  1378         except:
  1378         except Exception:
  1379             pass
  1379             pass
  1380         now = currentTimeMillis()
  1380         now = currentTimeMillis()
  1381         nextTime = now
  1381         nextTime = now
  1382         i = 0
  1382         i = 0
  1383         while i < 3:
  1383         while i < 3:
  1458     def removeListener(self, listener):
  1458     def removeListener(self, listener):
  1459         """Removes a listener."""
  1459         """Removes a listener."""
  1460         try:
  1460         try:
  1461             self.listeners.remove(listener)
  1461             self.listeners.remove(listener)
  1462             self.notifyAll()
  1462             self.notifyAll()
  1463         except:
  1463         except Exception:
  1464             pass
  1464             pass
  1465 
  1465 
  1466     def updateRecord(self, now, rec):
  1466     def updateRecord(self, now, rec):
  1467         """Used to notify listeners of new information that has updated
  1467         """Used to notify listeners of new information that has updated
  1468         a record."""
  1468         a record."""
  1527                         out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
  1527                         out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
  1528                     if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
  1528                     if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
  1529                         out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
  1529                         out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
  1530                     if question.type == _TYPE_SRV:
  1530                     if question.type == _TYPE_SRV:
  1531                         out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
  1531                         out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
  1532                 except:
  1532                 except Exception:
  1533                     traceback.print_exc()
  1533                     traceback.print_exc()
  1534 
  1534 
  1535         if out is not None and out.answers:
  1535         if out is not None and out.answers:
  1536             out.id = msg.id
  1536             out.id = msg.id
  1537             self.send(out, addr, port)
  1537             self.send(out, addr, port)
  1540         """Sends an outgoing packet."""
  1540         """Sends an outgoing packet."""
  1541         # This is a quick test to see if we can parse the packets we generate
  1541         # This is a quick test to see if we can parse the packets we generate
  1542         #temp = DNSIncoming(out.packet())
  1542         #temp = DNSIncoming(out.packet())
  1543         try:
  1543         try:
  1544             bytes_sent = self.socket.sendto(out.packet(), 0, (addr, port))
  1544             bytes_sent = self.socket.sendto(out.packet(), 0, (addr, port))
  1545         except:
  1545         except Exception:
  1546             # Ignore this, it may be a temporary loss of network connection
  1546             # Ignore this, it may be a temporary loss of network connection
  1547             pass
  1547             pass
  1548 
  1548 
  1549     def close(self):
  1549     def close(self):
  1550         """Ends the background threads, and prevent this instance from
  1550         """Ends the background threads, and prevent this instance from