Back to index

system-config-printer  1.3.9+20120706
dnssdresolve.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 ## Copyright (C) 2010, 2011 Red Hat, Inc.
00004 ## Authors:
00005 ##  Tim Waugh <twaugh@redhat.com>
00006 
00007 ## This program is free software; you can redistribute it and/or modify
00008 ## it under the terms of the GNU General Public License as published by
00009 ## the Free Software Foundation; either version 2 of the License, or
00010 ## (at your option) any later version.
00011 
00012 ## This program is distributed in the hope that it will be useful,
00013 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 ## GNU General Public License for more details.
00016 
00017 ## You should have received a copy of the GNU General Public License
00018 ## along with this program; if not, write to the Free Software
00019 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020 
00021 import dbus, re
00022 from debug import *
00023 
00024 class DNSSDHostNamesResolver:
00025     def __init__ (self, devices):
00026         self._devices = devices
00027         self._unresolved = len (devices)
00028         self._device_uri_by_name = {}
00029         debugprint ("+%s" % self)
00030 
00031     def __del__ (self):
00032         debugprint ("-%s" % self)
00033 
00034     def resolve (self, reply_handler):
00035 
00036         def expandhex (searchres):
00037             expr = searchres.group(0)
00038             return chr(int(expr[1:], 16))
00039 
00040         self._reply_handler = reply_handler
00041 
00042         bus = dbus.SystemBus ()
00043         if not bus:
00044             reply_handler ([])
00045             del self._devices
00046             del self._reply_handler
00047             return
00048 
00049         for uri, device in self._devices.iteritems ():
00050             if not uri.startswith ("dnssd://"):
00051                 self._unresolved -= 1
00052                 continue
00053 
00054             # We need to resolve the DNS-SD hostname in order to
00055             # compare with other network devices.
00056             p = uri[8:].find ("/")
00057             if p == -1:
00058                 hostname = uri[8:]
00059             else:
00060                 hostname = uri[8:8+p]
00061 
00062             hostname = hostname.encode('utf-8')
00063             hostname = re.sub("%(?i)[\dabcdef]{2}", expandhex, hostname)
00064 
00065             elements = hostname.rsplit (".", 3)
00066             if len (elements) != 4:
00067                 self._resolved ()
00068                 continue
00069 
00070             name, stype, protocol, domain = elements
00071             stype += "." + protocol #  e.g. _printer._tcp
00072 
00073             try:
00074                 obj = bus.get_object ("org.freedesktop.Avahi", "/")
00075                 server = dbus.Interface (obj,
00076                                          "org.freedesktop.Avahi.Server")
00077                 self._device_uri_by_name[(name, stype, domain)] = uri
00078                 debugprint ("Resolving address for %s" % hostname)
00079                 server.ResolveService (-1, -1,
00080                                         name, stype, domain,
00081                                         -1, 0,
00082                                         reply_handler=self._reply,
00083                                         error_handler=lambda e:
00084                                             self._error (uri, e))
00085             except dbus.DBusException, e:
00086                 debugprint ("Failed to resolve address: %s" % e)
00087                 self._resolved ()
00088 
00089     def _resolved (self):
00090         self._unresolved -= 1
00091         if self._unresolved == 0:
00092             debugprint ("All addresses resolved")
00093             self._reply_handler (self._devices)
00094             del self._devices
00095             del self._reply_handler
00096 
00097     def _reply (self, interface, protocol, name, stype, domain,
00098                 host, aprotocol, address, port, txt, flags):
00099         uri = self._device_uri_by_name[(name.encode ('utf-8'), stype, domain)]
00100         self._devices[uri].address = address
00101         hostname = host
00102         p = hostname.find(".")
00103         if p != -1:
00104             hostname = hostname[:p]
00105         debugprint ("%s is at %s (%s)" % (uri, address, hostname))
00106         self._devices[uri].hostname = hostname
00107         self._resolved ()
00108 
00109     def _error (self, uri, error):
00110         debugprint ("Error resolving %s: %s" % (uri, error))
00111         self._resolved ()
00112 
00113 if __name__ == '__main__':
00114     class Device:
00115         def __repr__ (self):
00116             try:
00117                 return "<Device @ %s>" % self.address
00118             except:
00119                 return "<Device>"
00120 
00121     devices = {"dnssd://dlk-08E206-P1._printer._tcp.local/": Device(),
00122                "dnssd://foo._printer._tcp.local/": Device()}
00123     from dbus.glib import DBusGMainLoop
00124     DBusGMainLoop (set_as_default=True)
00125 
00126     class Test:
00127         def __init__ (self, loop, devices):
00128             self._loop = loop
00129             self._devices = devices
00130 
00131         def run (self):
00132             r = DNSSDHostNamesResolver (self._devices)
00133             r.resolve (reply_handler=self.reply)
00134             return False
00135 
00136         def reply (self, *args):
00137             print args
00138             self._loop.quit ()
00139 
00140     import gobject
00141     loop = gobject.MainLoop ()
00142     set_debugging (True)
00143     gobject.idle_add (Test (loop, devices).run)
00144     loop.run ()