home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1432 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  45.7 KB  |  1,491 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __author__ = 'Paul Scott-Murphy'
  5. __email__ = 'paul at scott dash murphy dot com'
  6. __version__ = '0.12'
  7. import string
  8. import time
  9. import struct
  10. import socket
  11. import threading
  12. import select
  13. import traceback
  14. __all__ = [
  15.     'Zeroconf',
  16.     'ServiceInfo',
  17.     'ServiceBrowser']
  18. globals()['_GLOBAL_DONE'] = 0
  19. _UNREGISTER_TIME = 125
  20. _CHECK_TIME = 175
  21. _REGISTER_TIME = 225
  22. _LISTENER_TIME = 200
  23. _BROWSER_TIME = 500
  24. _MDNS_ADDR = '224.0.0.251'
  25. _MDNS_PORT = 5353
  26. _DNS_PORT = 53
  27. _DNS_TTL = 60 * 60
  28. _MAX_MSG_TYPICAL = 1460
  29. _MAX_MSG_ABSOLUTE = 8972
  30. _FLAGS_QR_MASK = 32768
  31. _FLAGS_QR_QUERY = 0
  32. _FLAGS_QR_RESPONSE = 32768
  33. _FLAGS_AA = 1024
  34. _FLAGS_TC = 512
  35. _FLAGS_RD = 256
  36. _FLAGS_RA = 32768
  37. _FLAGS_Z = 64
  38. _FLAGS_AD = 32
  39. _FLAGS_CD = 16
  40. _CLASS_IN = 1
  41. _CLASS_CS = 2
  42. _CLASS_CH = 3
  43. _CLASS_HS = 4
  44. _CLASS_NONE = 254
  45. _CLASS_ANY = 255
  46. _CLASS_MASK = 32767
  47. _CLASS_UNIQUE = 32768
  48. _TYPE_A = 1
  49. _TYPE_NS = 2
  50. _TYPE_MD = 3
  51. _TYPE_MF = 4
  52. _TYPE_CNAME = 5
  53. _TYPE_SOA = 6
  54. _TYPE_MB = 7
  55. _TYPE_MG = 8
  56. _TYPE_MR = 9
  57. _TYPE_NULL = 10
  58. _TYPE_WKS = 11
  59. _TYPE_PTR = 12
  60. _TYPE_HINFO = 13
  61. _TYPE_MINFO = 14
  62. _TYPE_MX = 15
  63. _TYPE_TXT = 16
  64. _TYPE_AAAA = 28
  65. _TYPE_SRV = 33
  66. _TYPE_ANY = 255
  67. _CLASSES = {
  68.     _CLASS_IN: 'in',
  69.     _CLASS_CS: 'cs',
  70.     _CLASS_CH: 'ch',
  71.     _CLASS_HS: 'hs',
  72.     _CLASS_NONE: 'none',
  73.     _CLASS_ANY: 'any' }
  74. _TYPES = {
  75.     _TYPE_A: 'a',
  76.     _TYPE_NS: 'ns',
  77.     _TYPE_MD: 'md',
  78.     _TYPE_MF: 'mf',
  79.     _TYPE_CNAME: 'cname',
  80.     _TYPE_SOA: 'soa',
  81.     _TYPE_MB: 'mb',
  82.     _TYPE_MG: 'mg',
  83.     _TYPE_MR: 'mr',
  84.     _TYPE_NULL: 'null',
  85.     _TYPE_WKS: 'wks',
  86.     _TYPE_PTR: 'ptr',
  87.     _TYPE_HINFO: 'hinfo',
  88.     _TYPE_MINFO: 'minfo',
  89.     _TYPE_MX: 'mx',
  90.     _TYPE_TXT: 'txt',
  91.     _TYPE_AAAA: 'quada',
  92.     _TYPE_SRV: 'srv',
  93.     _TYPE_ANY: 'any' }
  94.  
  95. def currentTimeMillis():
  96.     return time.time() * 1000
  97.  
  98.  
  99. class NonLocalNameException(Exception):
  100.     pass
  101.  
  102.  
  103. class NonUniqueNameException(Exception):
  104.     pass
  105.  
  106.  
  107. class NamePartTooLongException(Exception):
  108.     pass
  109.  
  110.  
  111. class AbstractMethodException(Exception):
  112.     pass
  113.  
  114.  
  115. class BadTypeInNameException(Exception):
  116.     pass
  117.  
  118.  
  119. class DNSEntry(object):
  120.     
  121.     def __init__(self, name, type, clazz):
  122.         self.key = string.lower(name)
  123.         self.name = name
  124.         self.type = type
  125.         self.clazz = clazz & _CLASS_MASK
  126.         self.unique = clazz & _CLASS_UNIQUE != 0
  127.  
  128.     
  129.     def __eq__(self, other):
  130.         if isinstance(other, DNSEntry):
  131.             if self.name == other.name and self.type == other.type:
  132.                 pass
  133.             return self.clazz == other.clazz
  134.         return 0
  135.  
  136.     
  137.     def __ne__(self, other):
  138.         return not self.__eq__(other)
  139.  
  140.     
  141.     def getClazz(self, clazz):
  142.         
  143.         try:
  144.             return _CLASSES[clazz]
  145.         except:
  146.             return '?(%s)' % clazz
  147.  
  148.  
  149.     
  150.     def getType(self, type):
  151.         
  152.         try:
  153.             return _TYPES[type]
  154.         except:
  155.             return '?(%s)' % type
  156.  
  157.  
  158.     
  159.     def toString(self, hdr, other):
  160.         result = '%s[%s,%s' % (hdr, self.getType(self.type), self.getClazz(self.clazz))
  161.         if self.unique:
  162.             result += '-unique,'
  163.         else:
  164.             result += ','
  165.         result += self.name
  166.         if other is not None:
  167.             result += ',%s]' % other
  168.         else:
  169.             result += ']'
  170.         return result
  171.  
  172.  
  173.  
  174. class DNSQuestion(DNSEntry):
  175.     
  176.     def __init__(self, name, type, clazz):
  177.         if not name.endswith('.local.'):
  178.             raise NonLocalNameException('DNSQuestion: Not a local name ' + name)
  179.         name.endswith('.local.')
  180.         DNSEntry.__init__(self, name, type, clazz)
  181.  
  182.     
  183.     def answeredBy(self, rec):
  184.         if self.clazz == rec.clazz:
  185.             if self.type == rec.type or self.type == _TYPE_ANY:
  186.                 pass
  187.         return self.name == rec.name
  188.  
  189.     
  190.     def __repr__(self):
  191.         return DNSEntry.toString(self, 'question', None)
  192.  
  193.  
  194.  
  195. class DNSRecord(DNSEntry):
  196.     
  197.     def __init__(self, name, type, clazz, ttl):
  198.         DNSEntry.__init__(self, name, type, clazz)
  199.         self.ttl = ttl
  200.         self.created = currentTimeMillis()
  201.  
  202.     
  203.     def __eq__(self, other):
  204.         if isinstance(other, DNSRecord):
  205.             return DNSEntry.__eq__(self, other)
  206.         return 0
  207.  
  208.     
  209.     def suppressedBy(self, msg):
  210.         for record in msg.answers:
  211.             if self.suppressedByAnswer(record):
  212.                 return 1
  213.         
  214.         return 0
  215.  
  216.     
  217.     def suppressedByAnswer(self, other):
  218.         if self == other and other.ttl > self.ttl / 2:
  219.             return 1
  220.         return 0
  221.  
  222.     
  223.     def getExpirationTime(self, percent):
  224.         return self.created + percent * self.ttl * 10
  225.  
  226.     
  227.     def getRemainingTTL(self, now):
  228.         return max(0, (self.getExpirationTime(100) - now) / 1000)
  229.  
  230.     
  231.     def isExpired(self, now):
  232.         return self.getExpirationTime(100) <= now
  233.  
  234.     
  235.     def isStale(self, now):
  236.         return self.getExpirationTime(50) <= now
  237.  
  238.     
  239.     def resetTTL(self, other):
  240.         self.created = other.created
  241.         self.ttl = other.ttl
  242.  
  243.     
  244.     def write(self, out):
  245.         raise AbstractMethodException
  246.  
  247.     
  248.     def toString(self, other):
  249.         arg = '%s/%s,%s' % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
  250.         return DNSEntry.toString(self, 'record', arg)
  251.  
  252.  
  253.  
  254. class DNSAddress(DNSRecord):
  255.     
  256.     def __init__(self, name, type, clazz, ttl, address):
  257.         DNSRecord.__init__(self, name, type, clazz, ttl)
  258.         self.address = address
  259.  
  260.     
  261.     def write(self, out):
  262.         out.writeString(self.address, len(self.address))
  263.  
  264.     
  265.     def __eq__(self, other):
  266.         if isinstance(other, DNSAddress):
  267.             return self.address == other.address
  268.         return 0
  269.  
  270.     
  271.     def __repr__(self):
  272.         
  273.         try:
  274.             return socket.inet_ntoa(self.address)
  275.         except:
  276.             return self.address
  277.  
  278.  
  279.  
  280.  
  281. class DNSHinfo(DNSRecord):
  282.     
  283.     def __init__(self, name, type, clazz, ttl, cpu, os):
  284.         DNSRecord.__init__(self, name, type, clazz, ttl)
  285.         self.cpu = cpu
  286.         self.os = os
  287.  
  288.     
  289.     def write(self, out):
  290.         out.writeString(self.cpu, len(self.cpu))
  291.         out.writeString(self.os, len(self.os))
  292.  
  293.     
  294.     def __eq__(self, other):
  295.         if isinstance(other, DNSHinfo):
  296.             if self.cpu == other.cpu:
  297.                 pass
  298.             return self.os == other.os
  299.         return 0
  300.  
  301.     
  302.     def __repr__(self):
  303.         return self.cpu + ' ' + self.os
  304.  
  305.  
  306.  
  307. class DNSPointer(DNSRecord):
  308.     
  309.     def __init__(self, name, type, clazz, ttl, alias):
  310.         DNSRecord.__init__(self, name, type, clazz, ttl)
  311.         self.alias = alias
  312.  
  313.     
  314.     def write(self, out):
  315.         out.writeName(self.alias)
  316.  
  317.     
  318.     def __eq__(self, other):
  319.         if isinstance(other, DNSPointer):
  320.             return self.alias == other.alias
  321.         return 0
  322.  
  323.     
  324.     def __repr__(self):
  325.         return self.toString(self.alias)
  326.  
  327.  
  328.  
  329. class DNSText(DNSRecord):
  330.     
  331.     def __init__(self, name, type, clazz, ttl, text):
  332.         DNSRecord.__init__(self, name, type, clazz, ttl)
  333.         self.text = text
  334.  
  335.     
  336.     def write(self, out):
  337.         out.writeString(self.text, len(self.text))
  338.  
  339.     
  340.     def __eq__(self, other):
  341.         if isinstance(other, DNSText):
  342.             return self.text == other.text
  343.         return 0
  344.  
  345.     
  346.     def __repr__(self):
  347.         if len(self.text) > 10:
  348.             return self.toString(self.text[:7] + '...')
  349.         return self.toString(self.text)
  350.  
  351.  
  352.  
  353. class DNSService(DNSRecord):
  354.     
  355.     def __init__(self, name, type, clazz, ttl, priority, weight, port, server):
  356.         DNSRecord.__init__(self, name, type, clazz, ttl)
  357.         self.priority = priority
  358.         self.weight = weight
  359.         self.port = port
  360.         self.server = server
  361.  
  362.     
  363.     def write(self, out):
  364.         out.writeShort(self.priority)
  365.         out.writeShort(self.weight)
  366.         out.writeShort(self.port)
  367.         out.writeName(self.server)
  368.  
  369.     
  370.     def __eq__(self, other):
  371.         if isinstance(other, DNSService):
  372.             if self.priority == other.priority and self.weight == other.weight and self.port == other.port:
  373.                 pass
  374.             return self.server == other.server
  375.         return 0
  376.  
  377.     
  378.     def __repr__(self):
  379.         return self.toString('%s:%s' % (self.server, self.port))
  380.  
  381.  
  382.  
  383. class DNSIncoming(object):
  384.     
  385.     def __init__(self, data):
  386.         self.offset = 0
  387.         self.data = data
  388.         self.questions = []
  389.         self.answers = []
  390.         self.numQuestions = 0
  391.         self.numAnswers = 0
  392.         self.numAuthorities = 0
  393.         self.numAdditionals = 0
  394.         self.readHeader()
  395.         self.readQuestions()
  396.         self.readOthers()
  397.  
  398.     
  399.     def readHeader(self):
  400.         format = '!HHHHHH'
  401.         length = struct.calcsize(format)
  402.         info = struct.unpack(format, self.data[self.offset:self.offset + length])
  403.         self.offset += length
  404.         self.id = info[0]
  405.         self.flags = info[1]
  406.         self.numQuestions = info[2]
  407.         self.numAnswers = info[3]
  408.         self.numAuthorities = info[4]
  409.         self.numAdditionals = info[5]
  410.  
  411.     
  412.     def readQuestions(self):
  413.         format = '!HH'
  414.         length = struct.calcsize(format)
  415.         for i in range(0, self.numQuestions):
  416.             name = self.readName()
  417.             info = struct.unpack(format, self.data[self.offset:self.offset + length])
  418.             self.offset += length
  419.             question = DNSQuestion(name, info[0], info[1])
  420.             self.questions.append(question)
  421.         
  422.  
  423.     
  424.     def readInt(self):
  425.         format = '!I'
  426.         length = struct.calcsize(format)
  427.         info = struct.unpack(format, self.data[self.offset:self.offset + length])
  428.         self.offset += length
  429.         return info[0]
  430.  
  431.     
  432.     def readCharacterString(self):
  433.         length = ord(self.data[self.offset])
  434.         self.offset += 1
  435.         return self.readString(length)
  436.  
  437.     
  438.     def readString(self, len):
  439.         format = '!' + str(len) + 's'
  440.         length = struct.calcsize(format)
  441.         info = struct.unpack(format, self.data[self.offset:self.offset + length])
  442.         self.offset += length
  443.         return info[0]
  444.  
  445.     
  446.     def readUnsignedShort(self):
  447.         format = '!H'
  448.         length = struct.calcsize(format)
  449.         info = struct.unpack(format, self.data[self.offset:self.offset + length])
  450.         self.offset += length
  451.         return info[0]
  452.  
  453.     
  454.     def readOthers(self):
  455.         format = '!HHiH'
  456.         length = struct.calcsize(format)
  457.         n = self.numAnswers + self.numAuthorities + self.numAdditionals
  458.         for i in range(0, n):
  459.             domain = self.readName()
  460.             info = struct.unpack(format, self.data[self.offset:self.offset + length])
  461.             self.offset += length
  462.             rec = None
  463.             if info[0] == _TYPE_A:
  464.                 rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(4))
  465.             elif info[0] == _TYPE_CNAME or info[0] == _TYPE_PTR:
  466.                 rec = DNSPointer(domain, info[0], info[1], info[2], self.readName())
  467.             elif info[0] == _TYPE_TXT:
  468.                 rec = DNSText(domain, info[0], info[1], info[2], self.readString(info[3]))
  469.             elif info[0] == _TYPE_SRV:
  470.                 rec = DNSService(domain, info[0], info[1], info[2], self.readUnsignedShort(), self.readUnsignedShort(), self.readUnsignedShort(), self.readName())
  471.             elif info[0] == _TYPE_HINFO:
  472.                 rec = DNSHinfo(domain, info[0], info[1], info[2], self.readCharacterString(), self.readCharacterString())
  473.             elif info[0] == _TYPE_AAAA:
  474.                 rec = DNSAddress(domain, info[0], info[1], info[2], self.readString(16))
  475.             
  476.             if rec is not None:
  477.                 self.answers.append(rec)
  478.                 continue
  479.         
  480.  
  481.     
  482.     def isQuery(self):
  483.         return self.flags & _FLAGS_QR_MASK == _FLAGS_QR_QUERY
  484.  
  485.     
  486.     def isResponse(self):
  487.         return self.flags & _FLAGS_QR_MASK == _FLAGS_QR_RESPONSE
  488.  
  489.     
  490.     def readUTF(self, offset, len):
  491.         result = self.data[offset:offset + len].decode('utf-8')
  492.         return result
  493.  
  494.     
  495.     def readName(self):
  496.         result = ''
  497.         off = self.offset
  498.         next = -1
  499.         first = off
  500.         while None:
  501.             len = ord(self.data[off])
  502.             off += 1
  503.             if len == 0:
  504.                 break
  505.             
  506.             t = len & 192
  507.             if t == 0:
  508.                 result = ''.join((result, self.readUTF(off, len) + '.'))
  509.                 off += len
  510.                 continue
  511.             if t == 192:
  512.                 if next < 0:
  513.                     next = off + 1
  514.                 
  515.                 off = (len & 63) << 8 | ord(self.data[off])
  516.                 if off >= first:
  517.                     raise ValueError('Bad domain name (circular) at ' + str(off))
  518.                 off >= first
  519.                 first = off
  520.                 continue
  521.             raise ValueError('Bad domain name at ' + str(off))
  522.             continue
  523.             if next >= 0:
  524.                 self.offset = next
  525.             else:
  526.                 self.offset = off
  527.         return result
  528.  
  529.  
  530.  
  531. class DNSOutgoing(object):
  532.     
  533.     def __init__(self, flags, multicast = 1):
  534.         self.finished = 0
  535.         self.id = 0
  536.         self.multicast = multicast
  537.         self.flags = flags
  538.         self.names = { }
  539.         self.data = []
  540.         self.size = 12
  541.         self.questions = []
  542.         self.answers = []
  543.         self.authorities = []
  544.         self.additionals = []
  545.  
  546.     
  547.     def addQuestion(self, record):
  548.         self.questions.append(record)
  549.  
  550.     
  551.     def addAnswer(self, inp, record):
  552.         if not record.suppressedBy(inp):
  553.             self.addAnswerAtTime(record, 0)
  554.         
  555.  
  556.     
  557.     def addAnswerAtTime(self, record, now):
  558.         if record is not None:
  559.             if now == 0 or not record.isExpired(now):
  560.                 self.answers.append((record, now))
  561.             
  562.         
  563.  
  564.     
  565.     def addAuthorativeAnswer(self, record):
  566.         self.authorities.append(record)
  567.  
  568.     
  569.     def addAdditionalAnswer(self, record):
  570.         self.additionals.append(record)
  571.  
  572.     
  573.     def writeByte(self, value):
  574.         format = '!c'
  575.         self.data.append(struct.pack(format, chr(value)))
  576.         self.size += 1
  577.  
  578.     
  579.     def insertShort(self, index, value):
  580.         format = '!H'
  581.         self.data.insert(index, struct.pack(format, value))
  582.         self.size += 2
  583.  
  584.     
  585.     def writeShort(self, value):
  586.         format = '!H'
  587.         self.data.append(struct.pack(format, value))
  588.         self.size += 2
  589.  
  590.     
  591.     def writeInt(self, value):
  592.         format = '!I'
  593.         self.data.append(struct.pack(format, value))
  594.         self.size += 4
  595.  
  596.     
  597.     def writeString(self, value, length):
  598.         format = '!' + str(length) + 's'
  599.         self.data.append(struct.pack(format, value))
  600.         self.size += length
  601.  
  602.     
  603.     def writeUTF(self, s):
  604.         utfstr = s.encode('utf-8')
  605.         length = len(utfstr)
  606.         if length > 64:
  607.             raise NamePartTooLongException
  608.         length > 64
  609.         self.writeByte(length)
  610.         self.writeString(utfstr, length)
  611.  
  612.     
  613.     def writeName(self, name):
  614.         
  615.         try:
  616.             index = self.names[name]
  617.         except KeyError:
  618.             self.names[name] = self.size
  619.             parts = name.split('.')
  620.             if parts[-1] == '':
  621.                 parts = parts[:-1]
  622.             
  623.             for part in parts:
  624.                 self.writeUTF(part)
  625.             
  626.             self.writeByte(0)
  627.             return None
  628.  
  629.         self.writeByte(index >> 8 | 192)
  630.         self.writeByte(index)
  631.  
  632.     
  633.     def writeQuestion(self, question):
  634.         self.writeName(question.name)
  635.         self.writeShort(question.type)
  636.         self.writeShort(question.clazz)
  637.  
  638.     
  639.     def writeRecord(self, record, now):
  640.         self.writeName(record.name)
  641.         self.writeShort(record.type)
  642.         if record.unique and self.multicast:
  643.             self.writeShort(record.clazz | _CLASS_UNIQUE)
  644.         else:
  645.             self.writeShort(record.clazz)
  646.         if now == 0:
  647.             self.writeInt(record.ttl)
  648.         else:
  649.             self.writeInt(record.getRemainingTTL(now))
  650.         index = len(self.data)
  651.         self.size += 2
  652.         record.write(self)
  653.         self.size -= 2
  654.         length = len(''.join(self.data[index:]))
  655.         self.insertShort(index, length)
  656.  
  657.     
  658.     def packet(self):
  659.         if not self.finished:
  660.             self.finished = 1
  661.             for question in self.questions:
  662.                 self.writeQuestion(question)
  663.             
  664.             for answer, time in self.answers:
  665.                 self.writeRecord(answer, time)
  666.             
  667.             for authority in self.authorities:
  668.                 self.writeRecord(authority, 0)
  669.             
  670.             for additional in self.additionals:
  671.                 self.writeRecord(additional, 0)
  672.             
  673.             self.insertShort(0, len(self.additionals))
  674.             self.insertShort(0, len(self.authorities))
  675.             self.insertShort(0, len(self.answers))
  676.             self.insertShort(0, len(self.questions))
  677.             self.insertShort(0, self.flags)
  678.             if self.multicast:
  679.                 self.insertShort(0, 0)
  680.             else:
  681.                 self.insertShort(0, self.id)
  682.         
  683.         return ''.join(self.data)
  684.  
  685.  
  686.  
  687. class DNSCache(object):
  688.     
  689.     def __init__(self):
  690.         self.cache = { }
  691.  
  692.     
  693.     def add(self, entry):
  694.         
  695.         try:
  696.             list = self.cache[entry.key]
  697.         except:
  698.             list = self.cache[entry.key] = []
  699.  
  700.         list.append(entry)
  701.  
  702.     
  703.     def remove(self, entry):
  704.         
  705.         try:
  706.             list = self.cache[entry.key]
  707.             list.remove(entry)
  708.         except:
  709.             pass
  710.  
  711.  
  712.     
  713.     def get(self, entry):
  714.         
  715.         try:
  716.             list = self.cache[entry.key]
  717.             return list[list.index(entry)]
  718.         except:
  719.             return None
  720.  
  721.  
  722.     
  723.     def getByDetails(self, name, type, clazz):
  724.         entry = DNSEntry(name, type, clazz)
  725.         return self.get(entry)
  726.  
  727.     
  728.     def entriesWithName(self, name):
  729.         
  730.         try:
  731.             return self.cache[name]
  732.         except:
  733.             return []
  734.  
  735.  
  736.     
  737.     def entries(self):
  738.         
  739.         def add(x, y):
  740.             return x + y
  741.  
  742.         
  743.         try:
  744.             return reduce(add, self.cache.values())
  745.         except:
  746.             return []
  747.  
  748.  
  749.  
  750.  
  751. class Engine(threading.Thread):
  752.     
  753.     def __init__(self, zeroconf):
  754.         threading.Thread.__init__(self)
  755.         self.zeroconf = zeroconf
  756.         self.readers = { }
  757.         self.timeout = 5
  758.         self.condition = threading.Condition()
  759.         self.setDaemon(True)
  760.         self.start()
  761.  
  762.     
  763.     def run(self):
  764.         while not globals()['_GLOBAL_DONE']:
  765.             rs = self.getReaders()
  766.             if len(rs) == 0:
  767.                 self.condition.acquire()
  768.                 self.condition.wait(self.timeout)
  769.                 self.condition.release()
  770.                 continue
  771.             DEBUG = DEBUG
  772.             import calibre.constants
  773.             
  774.             try:
  775.                 (rr, wr, er) = select.select(rs, [], [], self.timeout)
  776.                 for socket in rr:
  777.                     
  778.                     try:
  779.                         self.readers[socket].handle_read()
  780.                     continue
  781.                     except NonLocalNameException:
  782.                         err = None
  783.                         print err
  784.                         continue
  785.                         except UnicodeDecodeError:
  786.                             if DEBUG:
  787.                                 traceback.print_exc()
  788.                             
  789.                             DEBUG
  790.                             traceback.print_exc()
  791.                             continue
  792.                         
  793.                     continue
  794.                     continue
  795.  
  796.                 return None
  797.  
  798.  
  799.     
  800.     def getReaders(self):
  801.         result = []
  802.         self.condition.acquire()
  803.         result = self.readers.keys()
  804.         self.condition.release()
  805.         return result
  806.  
  807.     
  808.     def addReader(self, reader, socket):
  809.         self.condition.acquire()
  810.         self.readers[socket] = reader
  811.         self.condition.notify()
  812.         self.condition.release()
  813.  
  814.     
  815.     def delReader(self, socket):
  816.         self.condition.acquire()
  817.         del self.readers[socket]
  818.         self.condition.notify()
  819.         self.condition.release()
  820.  
  821.     
  822.     def notify(self):
  823.         self.condition.acquire()
  824.         self.condition.notify()
  825.         self.condition.release()
  826.  
  827.  
  828.  
  829. class Listener(object):
  830.     
  831.     def __init__(self, zeroconf):
  832.         self.zeroconf = zeroconf
  833.         self.zeroconf.engine.addReader(self, self.zeroconf.socket)
  834.  
  835.     
  836.     def handle_read(self):
  837.         (addr, port) = (data,)
  838.         self.data = data
  839.         msg = DNSIncoming(data)
  840.         if msg.isQuery():
  841.             if port == _MDNS_PORT:
  842.                 self.zeroconf.handleQuery(msg, _MDNS_ADDR, _MDNS_PORT)
  843.             elif port == _DNS_PORT:
  844.                 self.zeroconf.handleQuery(msg, addr, port)
  845.                 self.zeroconf.handleQuery(msg, _MDNS_ADDR, _MDNS_PORT)
  846.             
  847.         else:
  848.             self.zeroconf.handleResponse(msg)
  849.  
  850.  
  851.  
  852. class Reaper(threading.Thread):
  853.     
  854.     def __init__(self, zeroconf):
  855.         threading.Thread.__init__(self)
  856.         self.zeroconf = zeroconf
  857.         self.setDaemon(True)
  858.         self.start()
  859.  
  860.     
  861.     def run(self):
  862.         while None:
  863.             
  864.             try:
  865.                 self.zeroconf.wait(10000)
  866.             except TypeError:
  867.                 globals()['_GLOBAL_DONE'] = 1
  868.                 return None
  869.  
  870.             if globals()['_GLOBAL_DONE']:
  871.                 return None
  872.             now = currentTimeMillis()
  873.             for record in self.zeroconf.cache.entries():
  874.                 if record.isExpired(now):
  875.                     self.zeroconf.updateRecord(now, record)
  876.                     self.zeroconf.cache.remove(record)
  877.                     continue
  878.                 globals()['_GLOBAL_DONE']
  879.             
  880.             continue
  881.             return None
  882.  
  883.  
  884.  
  885. class ServiceBrowser(threading.Thread):
  886.     
  887.     def __init__(self, zeroconf, type, listener):
  888.         threading.Thread.__init__(self)
  889.         self.zeroconf = zeroconf
  890.         self.type = type
  891.         self.listener = listener
  892.         self.services = { }
  893.         self.nextTime = currentTimeMillis()
  894.         self.delay = _BROWSER_TIME
  895.         self.list = []
  896.         self.done = 0
  897.         self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
  898.         self.start()
  899.  
  900.     
  901.     def updateRecord(self, zeroconf, now, record):
  902.         if record.type == _TYPE_PTR and record.name == self.type:
  903.             expired = record.isExpired(now)
  904.             
  905.             try:
  906.                 oldrecord = self.services[record.alias.lower()]
  907.                 if not expired:
  908.                     oldrecord.resetTTL(record)
  909.                 else:
  910.                     del self.services[record.alias.lower()]
  911.                     
  912.                     callback = lambda x: self.listener.removeService(x, self.type, record.alias)
  913.                     self.list.append(callback)
  914.                     return None
  915.             except:
  916.                 if not expired:
  917.                     self.services[record.alias.lower()] = record
  918.                     
  919.                     callback = lambda x: self.listener.addService(x, self.type, record.alias)
  920.                     self.list.append(callback)
  921.                 
  922.             
  923.  
  924.             expires = record.getExpirationTime(75)
  925.             if expires < self.nextTime:
  926.                 self.nextTime = expires
  927.             
  928.         
  929.  
  930.     
  931.     def cancel(self):
  932.         self.done = 1
  933.         self.zeroconf.notifyAll()
  934.  
  935.     
  936.     def run(self):
  937.         while None:
  938.             event = None
  939.             now = currentTimeMillis()
  940.             if len(self.list) == 0 and self.nextTime > now:
  941.                 self.zeroconf.wait(self.nextTime - now)
  942.             
  943.             if globals()['_GLOBAL_DONE'] or self.done:
  944.                 return None
  945.             now = currentTimeMillis()
  946.             if len(self.list) > 0:
  947.                 event = self.list.pop(0)
  948.             
  949.             if event is not None:
  950.                 event(self.zeroconf)
  951.                 continue
  952.             continue
  953.             return None
  954.  
  955.  
  956.  
  957. class ServiceInfo(object):
  958.     
  959.     def __init__(self, type, name, address = None, port = None, weight = 0, priority = 0, properties = None, server = None):
  960.         if not name.endswith(type):
  961.             raise BadTypeInNameException
  962.         name.endswith(type)
  963.         self.type = type
  964.         self.name = name
  965.         self.address = address
  966.         self.port = port
  967.         self.weight = weight
  968.         self.priority = priority
  969.         if server:
  970.             self.server = server
  971.         else:
  972.             self.server = name
  973.         self.setProperties(properties)
  974.  
  975.     
  976.     def setProperties(self, properties):
  977.         if isinstance(properties, dict):
  978.             self.properties = properties
  979.             list = []
  980.             result = ''
  981.             for key in properties:
  982.                 value = properties[key]
  983.                 if value is None:
  984.                     suffix = ''.encode('utf-8')
  985.                 elif isinstance(value, str):
  986.                     suffix = value.encode('utf-8')
  987.                 elif isinstance(value, int):
  988.                     if value:
  989.                         suffix = 'true'
  990.                     else:
  991.                         suffix = 'false'
  992.                 else:
  993.                     suffix = ''.encode('utf-8')
  994.                 list.append('='.join((key, suffix)))
  995.             
  996.             for item in list:
  997.                 result = ''.join((result, struct.pack('!c', chr(len(item))), item))
  998.             
  999.             self.text = result
  1000.         else:
  1001.             self.text = properties
  1002.  
  1003.     
  1004.     def setText(self, text):
  1005.         self.text = text
  1006.         
  1007.         try:
  1008.             result = { }
  1009.             end = len(text)
  1010.             index = 0
  1011.             strs = []
  1012.             while index < end:
  1013.                 length = ord(text[index])
  1014.                 index += 1
  1015.                 strs.append(text[index:index + length])
  1016.                 index += length
  1017.             for s in strs:
  1018.                 eindex = s.find('=')
  1019.                 if eindex == -1:
  1020.                     key = s
  1021.                     value = 0
  1022.                 else:
  1023.                     key = s[:eindex]
  1024.                     value = s[eindex + 1:]
  1025.                     if value == 'true':
  1026.                         value = 1
  1027.                     elif value == 'false' or not value:
  1028.                         value = 0
  1029.                     
  1030.                 if key and result.get(key) == None:
  1031.                     result[key] = value
  1032.                     continue
  1033.             
  1034.             self.properties = result
  1035.         except:
  1036.             traceback.print_exc()
  1037.             self.properties = None
  1038.  
  1039.  
  1040.     
  1041.     def getType(self):
  1042.         return self.type
  1043.  
  1044.     
  1045.     def getName(self):
  1046.         if self.type is not None and self.name.endswith('.' + self.type):
  1047.             return self.name[:len(self.name) - len(self.type) - 1]
  1048.         return self.name
  1049.  
  1050.     
  1051.     def getAddress(self):
  1052.         return self.address
  1053.  
  1054.     
  1055.     def getPort(self):
  1056.         return self.port
  1057.  
  1058.     
  1059.     def getPriority(self):
  1060.         return self.priority
  1061.  
  1062.     
  1063.     def getWeight(self):
  1064.         return self.weight
  1065.  
  1066.     
  1067.     def getProperties(self):
  1068.         return self.properties
  1069.  
  1070.     
  1071.     def getText(self):
  1072.         return self.text
  1073.  
  1074.     
  1075.     def getServer(self):
  1076.         return self.server
  1077.  
  1078.     
  1079.     def updateRecord(self, zeroconf, now, record):
  1080.         if record is not None and not record.isExpired(now):
  1081.             if record.type == _TYPE_A:
  1082.                 if record.name == self.server:
  1083.                     self.address = record.address
  1084.                 
  1085.             elif record.type == _TYPE_SRV:
  1086.                 if record.name == self.name:
  1087.                     self.server = record.server
  1088.                     self.port = record.port
  1089.                     self.weight = record.weight
  1090.                     self.priority = record.priority
  1091.                     self.updateRecord(zeroconf, now, zeroconf.cache.getByDetails(self.server, _TYPE_A, _CLASS_IN))
  1092.                 
  1093.             elif record.type == _TYPE_TXT:
  1094.                 if record.name == self.name:
  1095.                     self.setText(record.text)
  1096.                 
  1097.             
  1098.         
  1099.  
  1100.     
  1101.     def request(self, zeroconf, timeout):
  1102.         now = currentTimeMillis()
  1103.         delay = _LISTENER_TIME
  1104.         next = now + delay
  1105.         last = now + timeout
  1106.         result = 0
  1107.         
  1108.         try:
  1109.             zeroconf.addListener(self, DNSQuestion(self.name, _TYPE_ANY, _CLASS_IN))
  1110.             while self.server is None and self.address is None or self.text is None:
  1111.                 if last <= now:
  1112.                     return 0
  1113.                 zeroconf.wait(min(next, last) - now)
  1114.                 now = currentTimeMillis()
  1115.                 continue
  1116.                 None if next <= now else last <= now
  1117.             result = 1
  1118.         finally:
  1119.             zeroconf.removeListener(self)
  1120.  
  1121.         return result
  1122.  
  1123.     
  1124.     def __eq__(self, other):
  1125.         if isinstance(other, ServiceInfo):
  1126.             return other.name == self.name
  1127.         return 0
  1128.  
  1129.     
  1130.     def __ne__(self, other):
  1131.         return not self.__eq__(other)
  1132.  
  1133.     
  1134.     def __repr__(self):
  1135.         result = 'service[%s,%s:%s,' % (self.name, socket.inet_ntoa(self.getAddress()), self.port)
  1136.         if self.text is None:
  1137.             result += 'None'
  1138.         elif len(self.text) < 20:
  1139.             result += self.text
  1140.         else:
  1141.             result += self.text[:17] + '...'
  1142.         result += ']'
  1143.         return result
  1144.  
  1145.  
  1146.  
  1147. class Zeroconf(object):
  1148.     
  1149.     def __init__(self, bindaddress = None):
  1150.         globals()['_GLOBAL_DONE'] = 0
  1151.         if bindaddress is None:
  1152.             self.intf = socket.gethostbyname(socket.gethostname())
  1153.         else:
  1154.             self.intf = bindaddress
  1155.         self.group = ('', _MDNS_PORT)
  1156.         self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  1157.         
  1158.         try:
  1159.             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  1160.             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  1161.         except:
  1162.             pass
  1163.  
  1164.         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 255)
  1165.         self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
  1166.         
  1167.         try:
  1168.             self.socket.bind(self.group)
  1169.         except:
  1170.             pass
  1171.  
  1172.         self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
  1173.         self.listeners = []
  1174.         self.browsers = []
  1175.         self.services = { }
  1176.         self.servicetypes = { }
  1177.         self.cache = DNSCache()
  1178.         self.condition = threading.Condition()
  1179.         self.engine = Engine(self)
  1180.         self.listener = Listener(self)
  1181.         self.reaper = Reaper(self)
  1182.  
  1183.     
  1184.     def isLoopback(self):
  1185.         return self.intf.startswith('127.0.0.1')
  1186.  
  1187.     
  1188.     def isLinklocal(self):
  1189.         return self.intf.startswith('169.254.')
  1190.  
  1191.     
  1192.     def wait(self, timeout):
  1193.         self.condition.acquire()
  1194.         self.condition.wait(timeout / 1000)
  1195.         self.condition.release()
  1196.  
  1197.     
  1198.     def notifyAll(self):
  1199.         self.condition.acquire()
  1200.         self.condition.notifyAll()
  1201.         self.condition.release()
  1202.  
  1203.     
  1204.     def getServiceInfo(self, type, name, timeout = 3000):
  1205.         info = ServiceInfo(type, name)
  1206.         if info.request(self, timeout):
  1207.             return info
  1208.  
  1209.     
  1210.     def addServiceListener(self, type, listener):
  1211.         self.removeServiceListener(listener)
  1212.         self.browsers.append(ServiceBrowser(self, type, listener))
  1213.  
  1214.     
  1215.     def removeServiceListener(self, listener):
  1216.         for browser in self.browsers:
  1217.             if browser.listener == listener:
  1218.                 browser.cancel()
  1219.                 del browser
  1220.                 continue
  1221.         
  1222.  
  1223.     
  1224.     def registerService(self, info, ttl = _DNS_TTL):
  1225.         self.checkService(info)
  1226.         self.services[info.name.lower()] = info
  1227.         if self.servicetypes.has_key(info.type):
  1228.             self.servicetypes[info.type] += 1
  1229.         else:
  1230.             self.servicetypes[info.type] = 1
  1231.         now = currentTimeMillis()
  1232.         nextTime = now
  1233.         i = 0
  1234.         while i < 3:
  1235.             if now < nextTime:
  1236.                 self.wait(nextTime - now)
  1237.                 now = currentTimeMillis()
  1238.                 continue
  1239.             
  1240.             out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1241.             out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, ttl, info.name), 0)
  1242.             out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, ttl, info.priority, info.weight, info.port, info.server), 0)
  1243.             out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, ttl, info.text), 0)
  1244.             if info.address:
  1245.                 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, ttl, info.address), 0)
  1246.             
  1247.             self.send(out)
  1248.             i += 1
  1249.             nextTime += _REGISTER_TIME
  1250.  
  1251.     
  1252.     def unregisterService(self, info):
  1253.         
  1254.         try:
  1255.             del self.services[info.name.lower()]
  1256.             if self.servicetypes[info.type] > 1:
  1257.                 self.servicetypes[info.type] -= 1
  1258.             else:
  1259.                 del self.servicetypes[info.type]
  1260.         except:
  1261.             pass
  1262.  
  1263.         now = currentTimeMillis()
  1264.         nextTime = now
  1265.         i = 0
  1266.         while i < 3:
  1267.             if now < nextTime:
  1268.                 self.wait(nextTime - now)
  1269.                 now = currentTimeMillis()
  1270.                 continue
  1271.             
  1272.             out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1273.             out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
  1274.             out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.name), 0)
  1275.             out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
  1276.             if info.address:
  1277.                 out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
  1278.             
  1279.             self.send(out)
  1280.             i += 1
  1281.             nextTime += _UNREGISTER_TIME
  1282.  
  1283.     
  1284.     def unregisterAllServices(self):
  1285.         if len(self.services) > 0:
  1286.             now = currentTimeMillis()
  1287.             nextTime = now
  1288.             i = 0
  1289.             while i < 3:
  1290.                 if now < nextTime:
  1291.                     self.wait(nextTime - now)
  1292.                     now = currentTimeMillis()
  1293.                     continue
  1294.                 
  1295.                 out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1296.                 for info in self.services.values():
  1297.                     out.addAnswerAtTime(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, 0, info.name), 0)
  1298.                     out.addAnswerAtTime(DNSService(info.name, _TYPE_SRV, _CLASS_IN, 0, info.priority, info.weight, info.port, info.server), 0)
  1299.                     out.addAnswerAtTime(DNSText(info.name, _TYPE_TXT, _CLASS_IN, 0, info.text), 0)
  1300.                     if info.address:
  1301.                         out.addAnswerAtTime(DNSAddress(info.server, _TYPE_A, _CLASS_IN, 0, info.address), 0)
  1302.                         continue
  1303.                 
  1304.                 self.send(out)
  1305.                 i += 1
  1306.                 nextTime += _UNREGISTER_TIME
  1307.         
  1308.  
  1309.     
  1310.     def checkService(self, info):
  1311.         now = currentTimeMillis()
  1312.         nextTime = now
  1313.         i = 0
  1314.         while i < 3:
  1315.             for record in self.cache.entriesWithName(info.type):
  1316.                 if record.type == _TYPE_PTR and not record.isExpired(now) and record.alias == info.name:
  1317.                     if info.name.find('.') < 0:
  1318.                         info.name = info.name + '.[' + info.address + ':' + info.port + '].' + info.type
  1319.                         self.checkService(info)
  1320.                         return None
  1321.                     raise NonUniqueNameException
  1322.                 record.alias == info.name
  1323.             
  1324.             if now < nextTime:
  1325.                 self.wait(nextTime - now)
  1326.                 now = currentTimeMillis()
  1327.                 continue
  1328.             
  1329.             out = DNSOutgoing(_FLAGS_QR_QUERY | _FLAGS_AA)
  1330.             self.debug = out
  1331.             out.addQuestion(DNSQuestion(info.type, _TYPE_PTR, _CLASS_IN))
  1332.             out.addAuthorativeAnswer(DNSPointer(info.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, info.name))
  1333.             self.send(out)
  1334.             i += 1
  1335.             nextTime += _CHECK_TIME
  1336.  
  1337.     
  1338.     def addListener(self, listener, question):
  1339.         now = currentTimeMillis()
  1340.         self.listeners.append(listener)
  1341.         if question is not None:
  1342.             for record in self.cache.entriesWithName(question.name):
  1343.                 if question.answeredBy(record) and not record.isExpired(now):
  1344.                     listener.updateRecord(self, now, record)
  1345.                     continue
  1346.             
  1347.         
  1348.         self.notifyAll()
  1349.  
  1350.     
  1351.     def removeListener(self, listener):
  1352.         
  1353.         try:
  1354.             self.listeners.remove(listener)
  1355.             self.notifyAll()
  1356.         except:
  1357.             pass
  1358.  
  1359.  
  1360.     
  1361.     def updateRecord(self, now, rec):
  1362.         for listener in self.listeners:
  1363.             listener.updateRecord(self, now, rec)
  1364.         
  1365.         self.notifyAll()
  1366.  
  1367.     
  1368.     def handleResponse(self, msg):
  1369.         now = currentTimeMillis()
  1370.         for record in msg.answers:
  1371.             expired = record.isExpired(now)
  1372.             if record in self.cache.entries():
  1373.                 if expired:
  1374.                     self.cache.remove(record)
  1375.                 else:
  1376.                     entry = self.cache.get(record)
  1377.                     if entry is not None:
  1378.                         entry.resetTTL(record)
  1379.                         record = entry
  1380.                     
  1381.             else:
  1382.                 self.cache.add(record)
  1383.             self.updateRecord(now, record)
  1384.         
  1385.  
  1386.     
  1387.     def handleQuery(self, msg, addr, port):
  1388.         out = None
  1389.         if port != _MDNS_PORT:
  1390.             out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, 0)
  1391.             for question in msg.questions:
  1392.                 out.addQuestion(question)
  1393.             
  1394.         
  1395.         for question in msg.questions:
  1396.             if question.type == _TYPE_PTR:
  1397.                 if question.name == '_services._dns-sd._udp.local.':
  1398.                     for stype in self.servicetypes.keys():
  1399.                         if out is None:
  1400.                             out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1401.                         
  1402.                         out.addAnswer(msg, DNSPointer('_services._dns-sd._udp.local.', _TYPE_PTR, _CLASS_IN, _DNS_TTL, stype))
  1403.                     
  1404.                 
  1405.                 for service in self.services.values():
  1406.                     if question.name == service.type:
  1407.                         if out is None:
  1408.                             out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1409.                         
  1410.                         out.addAnswer(msg, DNSPointer(service.type, _TYPE_PTR, _CLASS_IN, _DNS_TTL, service.name))
  1411.                         continue
  1412.                 
  1413.             
  1414.             try:
  1415.                 if out is None:
  1416.                     out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
  1417.                 
  1418.                 if question.type == _TYPE_A or question.type == _TYPE_ANY:
  1419.                     for service in self.services.values():
  1420.                         if service.server == question.name.lower():
  1421.                             out.addAnswer(msg, DNSAddress(question.name, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
  1422.                             continue
  1423.                     
  1424.                 
  1425.                 service = self.services.get(question.name.lower(), None)
  1426.                 if not service:
  1427.                     continue
  1428.                 
  1429.                 if question.type == _TYPE_SRV or question.type == _TYPE_ANY:
  1430.                     out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
  1431.                 
  1432.                 if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
  1433.                     out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
  1434.                 
  1435.                 if question.type == _TYPE_SRV:
  1436.                     out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
  1437.             continue
  1438.             traceback.print_exc()
  1439.             continue
  1440.  
  1441.         
  1442.         if out is not None and out.answers:
  1443.             out.id = msg.id
  1444.             self.send(out, addr, port)
  1445.         
  1446.  
  1447.     
  1448.     def send(self, out, addr = _MDNS_ADDR, port = _MDNS_PORT):
  1449.         
  1450.         try:
  1451.             self.socket.sendto(out.packet(), 0, (addr, port))
  1452.         except:
  1453.             pass
  1454.  
  1455.  
  1456.     
  1457.     def close(self):
  1458.         if globals()['_GLOBAL_DONE'] == 0:
  1459.             globals()['_GLOBAL_DONE'] = 1
  1460.             self.notifyAll()
  1461.             self.engine.notify()
  1462.             self.unregisterAllServices()
  1463.             self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
  1464.             self.socket.close()
  1465.         
  1466.  
  1467.  
  1468. if __name__ == '__main__':
  1469.     print 'Multicast DNS Service Discovery for Python, version', __version__
  1470.     r = Zeroconf()
  1471.     print '1. Testing registration of a service...'
  1472.     desc = {
  1473.         'version': '0.10',
  1474.         'a': 'test value',
  1475.         'b': 'another value' }
  1476.     info = ServiceInfo('_http._tcp.local.', 'My Service Name._http._tcp.local.', socket.inet_aton('127.0.0.1'), 1234, 0, 0, desc)
  1477.     print '   Registering service...'
  1478.     r.registerService(info)
  1479.     print '   Registration done.'
  1480.     print '2. Testing query of service information...'
  1481.     print '   Getting ZOE service:', str(r.getServiceInfo('_http._tcp.local.', 'ZOE._http._tcp.local.'))
  1482.     print '   Query done.'
  1483.     print '3. Testing query of own service...'
  1484.     print '   Getting self:', str(r.getServiceInfo('_http._tcp.local.', 'My Service Name._http._tcp.local.'))
  1485.     print '   Query done.'
  1486.     print '4. Testing unregister of service information...'
  1487.     r.unregisterService(info)
  1488.     print '   Unregister done.'
  1489.     r.close()
  1490.  
  1491.