##// END OF EJS Templates
zeroconf: wrap long lines
timeless -
r28299:acea9dd8 default
parent child Browse files
Show More
@@ -34,7 +34,7 b' from __future__ import absolute_import, '
34 34 - hostinfo
35 35 ignore unknown DNS record types
36 36 fixes to name decoding
37 works alongside other processes using port 5353 (e.g. on Mac OS X)
37 works alongside other processes using port 5353 (e.g. Mac OS X)
38 38 tested against Mac OS X 10.3.2's mDNSResponder
39 39 corrections to removal of list entries for service browser"""
40 40
@@ -228,7 +228,8 b' class DNSEntry(object):'
228 228 def __eq__(self, other):
229 229 """Equality test on name, type, and class"""
230 230 if isinstance(other, DNSEntry):
231 return self.name == other.name and self.type == other.type and self.clazz == other.clazz
231 return (self.name == other.name and self.type == other.type and
232 self.clazz == other.clazz)
232 233 return 0
233 234
234 235 def __ne__(self, other):
@@ -251,7 +252,8 b' class DNSEntry(object):'
251 252
252 253 def toString(self, hdr, other):
253 254 """String representation with additional information"""
254 result = "%s[%s,%s" % (hdr, self.getType(self.type), self.getClazz(self.clazz))
255 result = ("%s[%s,%s" %
256 (hdr, self.getType(self.type), self.getClazz(self.clazz)))
255 257 if self.unique:
256 258 result += "-unique,"
257 259 else:
@@ -273,7 +275,9 b' class DNSQuestion(DNSEntry):'
273 275
274 276 def answeredBy(self, rec):
275 277 """Returns true if the question is answered by the record"""
276 return self.clazz == rec.clazz and (self.type == rec.type or self.type == _TYPE_ANY) and self.name == rec.name
278 return (self.clazz == rec.clazz and
279 (self.type == rec.type or self.type == _TYPE_ANY) and
280 self.name == rec.name)
277 281
278 282 def __repr__(self):
279 283 """String representation"""
@@ -338,7 +342,8 b' class DNSRecord(DNSEntry):'
338 342
339 343 def toString(self, other):
340 344 """String representation with additional information"""
341 arg = "%s/%s,%s" % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
345 arg = ("%s/%s,%s" %
346 (self.ttl, self.getRemainingTTL(currentTimeMillis()), other))
342 347 return DNSEntry.toString(self, "record", arg)
343 348
344 349 class DNSAddress(DNSRecord):
@@ -453,7 +458,10 b' class DNSService(DNSRecord):'
453 458 def __eq__(self, other):
454 459 """Tests equality on priority, weight, port and server"""
455 460 if isinstance(other, DNSService):
456 return self.priority == other.priority and self.weight == other.weight and self.port == other.port and self.server == other.server
461 return (self.priority == other.priority and
462 self.weight == other.weight and
463 self.port == other.port and
464 self.server == other.server)
457 465 return 0
458 466
459 467 def __repr__(self):
@@ -498,7 +506,8 b' class DNSIncoming(object):'
498 506 length = struct.calcsize(format)
499 507 for i in range(0, self.numQuestions):
500 508 name = self.readName()
501 info = struct.unpack(format, self.data[self.offset:self.offset+length])
509 info = struct.unpack(format,
510 self.data[self.offset:self.offset+length])
502 511 self.offset += length
503 512
504 513 try:
@@ -538,28 +547,39 b' class DNSIncoming(object):'
538 547 return info[0]
539 548
540 549 def readOthers(self):
541 """Reads the answers, authorities and additionals section of the packet"""
550 """Reads answers, authorities and additionals section of the packet"""
542 551 format = '!HHiH'
543 552 length = struct.calcsize(format)
544 553 n = self.numAnswers + self.numAuthorities + self.numAdditionals
545 554 for i in range(0, n):
546 555 domain = self.readName()
547 info = struct.unpack(format, self.data[self.offset:self.offset+length])
556 info = struct.unpack(format,
557 self.data[self.offset:self.offset+length])
548 558 self.offset += length
549 559
550 560 rec = None
551 561 if info[0] == _TYPE_A:
552 rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(4))
562 rec = DNSAddress(domain, info[0], info[1], info[2],
563 self.readString(4))
553 564 elif info[0] == _TYPE_CNAME or info[0] == _TYPE_PTR:
554 rec = DNSPointer(domain, info[0], info[1], info[2], self.readName())
565 rec = DNSPointer(domain, info[0], info[1], info[2],
566 self.readName())
555 567 elif info[0] == _TYPE_TXT:
556 rec = DNSText(domain, info[0], info[1], info[2], self.readString(info[3]))
568 rec = DNSText(domain, info[0], info[1], info[2],
569 self.readString(info[3]))
557 570 elif info[0] == _TYPE_SRV:
558 rec = DNSService(domain, info[0], info[1], info[2], self.readUnsignedShort(), self.readUnsignedShort(), self.readUnsignedShort(), self.readName())
571 rec = DNSService(domain, info[0], info[1], info[2],
572 self.readUnsignedShort(),
573 self.readUnsignedShort(),
574 self.readUnsignedShort(),
575 self.readName())
559 576 elif info[0] == _TYPE_HINFO:
560 rec = DNSHinfo(domain, info[0], info[1], info[2], self.readCharacterString(), self.readCharacterString())
577 rec = DNSHinfo(domain, info[0], info[1], info[2],
578 self.readCharacterString(),
579 self.readCharacterString())
561 580 elif info[0] == _TYPE_AAAA:
562 rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(16))
581 rec = DNSAddress(domain, info[0], info[1], info[2],
582 self.readString(16))
563 583 else:
564 584 # Try to ignore types we don't know about
565 585 # this may mean the rest of the name is
@@ -972,7 +992,8 b' class ServiceBrowser(threading.Thread):'
972 992
973 993 self.done = 0
974 994
975 self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
995 self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR,
996 _CLASS_IN))
976 997 self.start()
977 998
978 999 def updateRecord(self, zeroconf, now, record):
@@ -987,13 +1008,15 b' class ServiceBrowser(threading.Thread):'
987 1008 oldrecord.resetTTL(record)
988 1009 else:
989 1010 del(self.services[record.alias.lower()])
990 callback = lambda x: self.listener.removeService(x, self.type, record.alias)
1011 callback = (lambda x:
1012 self.listener.removeService(x, self.type, record.alias))
991 1013 self.list.append(callback)
992 1014 return
993 1015 except Exception:
994 1016 if not expired:
995 1017 self.services[record.alias.lower()] = record
996 callback = lambda x: self.listener.addService(x, self.type, record.alias)
1018 callback = (lambda x:
1019 self.listener.addService(x, self.type, record.alias))
997 1020 self.list.append(callback)
998 1021
999 1022 expires = record.getExpirationTime(75)
@@ -1034,7 +1057,8 b' class ServiceBrowser(threading.Thread):'
1034 1057 class ServiceInfo(object):
1035 1058 """Service information"""
1036 1059
1037 def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None):
1060 def __init__(self, type, name, address=None, port=None, weight=0,
1061 priority=0, properties=None, server=None):
1038 1062 """Create a service description.
1039 1063
1040 1064 type: fully qualified service type name
@@ -1043,7 +1067,8 b' class ServiceInfo(object):'
1043 1067 port: port that the service runs on
1044 1068 weight: weight of the service
1045 1069 priority: priority of the service
1046 properties: dictionary of properties (or a string holding the bytes for the text field)
1070 properties: dictionary of properties (or a string holding the bytes for
1071 the text field)
1047 1072 server: fully qualified name for service host (defaults to name)"""
1048 1073
1049 1074 if not name.endswith(type):
@@ -1081,7 +1106,8 b' class ServiceInfo(object):'
1081 1106 suffix = ''
1082 1107 list.append('='.join((key, suffix)))
1083 1108 for item in list:
1084 result = ''.join((result, struct.pack('!c', chr(len(item))), item))
1109 result = ''.join((result, struct.pack('!c', chr(len(item))),
1110 item))
1085 1111 self.text = result
1086 1112 else:
1087 1113 self.text = properties
@@ -1175,7 +1201,9 b' class ServiceInfo(object):'
1175 1201 self.weight = record.weight
1176 1202 self.priority = record.priority
1177 1203 #self.address = None
1178 self.updateRecord(zeroconf, now, zeroconf.cache.getByDetails(self.server, _TYPE_A, _CLASS_IN))
1204 self.updateRecord(zeroconf, now,
1205 zeroconf.cache.getByDetails(self.server,
1206 _TYPE_A, _CLASS_IN))
1179 1207 elif record.type == _TYPE_TXT:
1180 1208 if record.name == self.name:
1181 1209 self.setText(record.text)
@@ -1190,19 +1218,34 b' class ServiceInfo(object):'
1190 1218 last = now + timeout
1191 1219 result = 0
1192 1220 try:
1193 zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY, _CLASS_IN))
1194 while self.server is None or self.address is None or self.text is None:
1221 zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY,
1222 _CLASS_IN))
1223 while (self.server is None or self.address is None or
1224 self.text is None):
1195 1225 if last <= now:
1196 1226 return 0
1197 1227 if next <= now:
1198 1228 out = DNSOutgoing(_FLAGS_QR_QUERY)
1199 out.addQuestion(DNSQuestion(self.name, _TYPE_SRV, _CLASS_IN))
1200 out.addAnswerAtTime(zeroconf.cache.getByDetails(self.name, _TYPE_SRV, _CLASS_IN), now)
1201 out.addQuestion(DNSQuestion(self.name, _TYPE_TXT, _CLASS_IN))
1202 out.addAnswerAtTime(zeroconf.cache.getByDetails(self.name, _TYPE_TXT, _CLASS_IN), now)
1229 out.addQuestion(DNSQuestion(self.name, _TYPE_SRV,
1230 _CLASS_IN))
1231 out.addAnswerAtTime(
1232 zeroconf.cache.getByDetails(self.name,
1233 _TYPE_SRV,
1234 _CLASS_IN),
1235 now)
1236 out.addQuestion(DNSQuestion(self.name, _TYPE_TXT,
1237 _CLASS_IN))
1238 out.addAnswerAtTime(
1239 zeroconf.cache.getByDetails(self.name, _TYPE_TXT,
1240 _CLASS_IN),
1241 now)
1203 1242 if self.server is not None:
1204 out.addQuestion(DNSQuestion(self.server, _TYPE_A, _CLASS_IN))
1205 out.addAnswerAtTime(zeroconf.cache.getByDetails(self.server, _TYPE_A, _CLASS_IN), now)
1243 out.addQuestion(
1244 DNSQuestion(self.server, _TYPE_A, _CLASS_IN))
1245 out.addAnswerAtTime(
1246 zeroconf.cache.getByDetails(self.server, _TYPE_A,
1247 _CLASS_IN),
1248 now)
1206 1249 zeroconf.send(out)
1207 1250 next = now + delay
1208 1251 delay = delay * 2
@@ -1227,7 +1270,8 b' class ServiceInfo(object):'
1227 1270
1228 1271 def __repr__(self):
1229 1272 """String representation"""
1230 result = "service[%s,%s:%s," % (self.name, socket.inet_ntoa(self.getAddress()), self.port)
1273 result = ("service[%s,%s:%s," %
1274 (self.name, socket.inet_ntoa(self.getAddress()), self.port))
1231 1275 if self.text is None:
1232 1276 result += "None"
1233 1277 else:
@@ -1276,7 +1320,8 b' class Zeroconf(object):'
1276 1320 # Some versions of linux raise an exception even though
1277 1321 # SO_REUSEADDR and SO_REUSEPORT have been set, so ignore it
1278 1322 pass
1279 self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
1323 self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
1324 socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
1280 1325
1281 1326 self.listeners = []
1282 1327 self.browsers = []
@@ -1353,11 +1398,20 b' class Zeroconf(object):'
1353 1398 now = currentTimeMillis()
1354 1399 continue
1355 1400 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
1356 out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, ttl, info.name), 0)
1357 out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0)
1358 out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text), 0)
1401 out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
1402 _CLASS_IN, ttl, info.name), 0)
1403 out.addAnswerAtTime(
1404 DNSService(
1405 info.name, _TYPE_SRV,
1406 _CLASS_IN, ttl, info.priority, info.weight, info.port,
1407 info.server),
1408 0)
1409 out.addAnswerAtTime(
1410 DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text),
1411 0)
1359 1412 if info.address:
1360 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, ttl, info.address), 0)
1413 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
1414 _CLASS_IN, ttl, info.address), 0)
1361 1415 self.send(out)
1362 1416 i += 1
1363 1417 nextTime += _REGISTER_TIME
@@ -1381,11 +1435,18 b' class Zeroconf(object):'
1381 1435 now = currentTimeMillis()
1382 1436 continue
1383 1437 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
1384 out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
1385 out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0)
1386 out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
1438 out.addAnswerAtTime(
1439 DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
1440 out.addAnswerAtTime(
1441 DNSService(info.name, _TYPE_SRV,
1442 _CLASS_IN, 0, info.priority, info.weight, info.port,
1443 info.name),
1444 0)
1445 out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
1446 _CLASS_IN, 0, info.text), 0)
1387 1447 if info.address:
1388 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
1448 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
1449 _CLASS_IN, 0, info.address), 0)
1389 1450 self.send(out)
1390 1451 i += 1
1391 1452 nextTime += _UNREGISTER_TIME
@@ -1403,11 +1464,18 b' class Zeroconf(object):'
1403 1464 continue
1404 1465 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
1405 1466 for info in self.services.values():
1406 out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
1407 out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0)
1408 out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
1467 out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR,
1468 _CLASS_IN, 0, info.name), 0)
1469 out.addAnswerAtTime(
1470 DNSService(info.name, _TYPE_SRV,
1471 _CLASS_IN, 0, info.priority, info.weight,
1472 info.port, info.server),
1473 0)
1474 out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT,
1475 _CLASS_IN, 0, info.text), 0)
1409 1476 if info.address:
1410 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
1477 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A,
1478 _CLASS_IN, 0, info.address), 0)
1411 1479 self.send(out)
1412 1480 i += 1
1413 1481 nextTime += _UNREGISTER_TIME
@@ -1420,9 +1488,11 b' class Zeroconf(object):'
1420 1488 i = 0
1421 1489 while i < 3:
1422 1490 for record in self.cache.entriesWithName(info.type):
1423 if record.type == _TYPE_PTR and not record.isExpired(now) and record.alias == info.name:
1491 if (record.type == _TYPE_PTR and not record.isExpired(now) and
1492 record.alias == info.name):
1424 1493 if (info.name.find('.') < 0):
1425 info.name = info.name + ".[" + info.address + ":" + info.port + "]." + info.type
1494 info.name = ("%w.[%s:%d].%s" %
1495 (info.name, info.address, info.port, info.type))
1426 1496 self.checkService(info)
1427 1497 return
1428 1498 raise NonUniqueNameException
@@ -1433,7 +1503,8 b' class Zeroconf(object):'
1433 1503 out = DNSOutgoing(_FLAGS_QR_QUERY | _FLAGS_AA)
1434 1504 self.debug = out
1435 1505 out.addQuestion(DNSQuestion(info.type, _TYPE_PTR, _CLASS_IN))
1436 out.addAuthoritativeAnswer(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, info.name))
1506 out.addAuthoritativeAnswer(DNSPointer(info.type, _TYPE_PTR,
1507 _CLASS_IN, _DNS_TTL, info.name))
1437 1508 self.send(out)
1438 1509 i += 1
1439 1510 nextTime += _CHECK_TIME
@@ -1502,12 +1573,17 b' class Zeroconf(object):'
1502 1573 for stype in self.servicetypes.keys():
1503 1574 if out is None:
1504 1575 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
1505 out.addAnswer(msg, DNSPointer("_services._dns-sd._udp.local.", _TYPE_PTR, _CLASS_IN, _DNS_TTL, stype))
1576 out.addAnswer(msg,
1577 DNSPointer(
1578 "_services._dns-sd._udp.local.",
1579 _TYPE_PTR, _CLASS_IN,
1580 _DNS_TTL, stype))
1506 1581 for service in self.services.values():
1507 1582 if question.name == service.type:
1508 1583 if out is None:
1509 1584 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
1510 out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, service.name))
1585 out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR,
1586 _CLASS_IN, _DNS_TTL, service.name))
1511 1587 else:
1512 1588 try:
1513 1589 if out is None:
@@ -1517,17 +1593,31 b' class Zeroconf(object):'
1517 1593 if question.type == _TYPE_A or question.type == _TYPE_ANY:
1518 1594 for service in self.services.values():
1519 1595 if service.server == question.name.lower():
1520 out.addAnswer(msg, DNSAddress(question.name, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
1596 out.addAnswer(msg,
1597 DNSAddress(question.name, _TYPE_A,
1598 _CLASS_IN | _CLASS_UNIQUE,
1599 _DNS_TTL, service.address))
1521 1600
1522 1601 service = self.services.get(question.name.lower(), None)
1523 1602 if not service: continue
1524 1603
1525 if question.type == _TYPE_SRV or question.type == _TYPE_ANY:
1526 out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
1527 if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
1528 out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
1604 if (question.type == _TYPE_SRV or
1605 question.type == _TYPE_ANY):
1606 out.addAnswer(msg,
1607 DNSService(question.name, _TYPE_SRV,
1608 _CLASS_IN | _CLASS_UNIQUE,
1609 _DNS_TTL, service.priority,
1610 service.weight, service.port,
1611 service.server))
1612 if (question.type == _TYPE_TXT or
1613 question.type == _TYPE_ANY):
1614 out.addAnswer(msg, DNSText(question.name, _TYPE_TXT,
1615 _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
1529 1616 if question.type == _TYPE_SRV:
1530 out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
1617 out.addAdditionalAnswer(
1618 DNSAddress(service.server, _TYPE_A,
1619 _CLASS_IN | _CLASS_UNIQUE,
1620 _DNS_TTL, service.address))
1531 1621 except Exception:
1532 1622 traceback.print_exc()
1533 1623
@@ -1553,7 +1643,8 b' class Zeroconf(object):'
1553 1643 self.notifyAll()
1554 1644 self.engine.notify()
1555 1645 self.unregisterAllServices()
1556 self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
1646 self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP,
1647 socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
1557 1648 self.socket.close()
1558 1649
1559 1650 # Test a few module features, including service registration, service
@@ -1564,15 +1655,20 b" if __name__ == '__main__':"
1564 1655 r = Zeroconf()
1565 1656 print("1. Testing registration of a service...")
1566 1657 desc = {'version':'0.10','a':'test value', 'b':'another value'}
1567 info = ServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.", socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
1658 info = ServiceInfo("_http._tcp.local.",
1659 "My Service Name._http._tcp.local.",
1660 socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
1568 1661 print(" Registering service...")
1569 1662 r.registerService(info)
1570 1663 print(" Registration done.")
1571 1664 print("2. Testing query of service information...")
1572 print(" Getting ZOE service:", str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local.")))
1665 print(" Getting ZOE service:",
1666 str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local.")))
1573 1667 print(" Query done.")
1574 1668 print("3. Testing query of own service...")
1575 print(" Getting self:", str(r.getServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.")))
1669 print(" Getting self:",
1670 str(r.getServiceInfo("_http._tcp.local.",
1671 "My Service Name._http._tcp.local.")))
1576 1672 print(" Query done.")
1577 1673 print("4. Testing unregister of service information...")
1578 1674 r.unregisterService(info)
General Comments 0
You need to be logged in to leave comments. Login now