/PicoRendezvous.py

https://github.com/jamescw/regrowl · Python · 83 lines · 63 code · 10 blank · 10 comment · 8 complexity · 5221a8dc1f23a5eef09761c4d8b43b7c MD5 · raw file

  1. #!/usr/bin/env python
  2. """Minimalist Rendezvous Client for Python"""
  3. __version__ = "0.2"
  4. __author__ = "Rui Carmo (http://the.taoofmac.com)"
  5. __copyright__ = "(C) 2004 Rui Carmo. Code under BSD License."
  6. import string, os, socket, struct
  7. from SocketServer import *
  8. _MDNS_ADDR = '224.0.0.251'
  9. _MDNS_PORT = 5353
  10. class PicoRendezvous(UDPServer):
  11. allow_reuse_address = True
  12. replies = []
  13. def __init__(self):
  14. UDPServer.__init__(self, ("localhost", _MDNS_PORT), _ReplyHandler)
  15. # end def
  16. def query(self, proto):
  17. self.data = struct.pack( "!HHHHHH", 0, 0, 1, 0, 0, 0 )
  18. # pack query
  19. parts = proto.split('.')
  20. if parts[-1] == '':
  21. parts = parts[:-1]
  22. for part in parts:
  23. utf = part.encode('utf-8')
  24. l = len(utf)
  25. self.data += struct.pack("B", l)
  26. self.data += struct.pack('!' + str(l) + 's', utf)
  27. self.data += struct.pack("B", 0)
  28. # query for any PTR records
  29. self.data += struct.pack( "!BBH", 0, 12, 1 )
  30. try:
  31. self.socket.sendto(self.data,0,(_MDNS_ADDR,_MDNS_PORT))
  32. except:
  33. pass
  34. tenths = 0
  35. while tenths < 20:
  36. self.handle_request()
  37. tenths = tenths + 1
  38. return self.replies
  39. # end def
  40. def server_bind(self):
  41. self.group = ('', _MDNS_PORT)
  42. self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  43. try:
  44. self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  45. self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  46. except:
  47. pass
  48. self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 255)
  49. self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
  50. try:
  51. self.socket.bind(self.group)
  52. except:
  53. pass
  54. hostname = socket.gethostname() + '.local'
  55. hostip = socket.gethostbyname(hostname)
  56. host = socket.inet_aton(hostip)
  57. self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, host + socket.inet_aton('0.0.0.0'))
  58. self.socket.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
  59. self.socket.settimeout(0.1)
  60. # end def
  61. # end class
  62. class _ReplyHandler(DatagramRequestHandler):
  63. def handle(self):
  64. ip = self.client_address[0]
  65. if ip not in self.server.replies:
  66. self.server.replies.append(ip)
  67. # end def
  68. # end class
  69. if __name__ == '__main__':
  70. print "Starting Unit Test"
  71. print " - please make sure Growl is listening for network notifications"
  72. p = PicoRendezvous()
  73. print p.query('_growl._tcp')