Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/shell
diff options
context:
space:
mode:
authorDan Williams <dcbw@localhost.localdomain>2006-09-12 16:36:24 (GMT)
committer Dan Williams <dcbw@localhost.localdomain>2006-09-12 16:36:24 (GMT)
commitf205e8c67bdfc1f6861e9d5ac1a68abaa6ff1117 (patch)
tree8f0e7f1d51261797f40b41e5697b53a519addf44 /shell
parent4ae80802cedfc8c1e8b01b80470db843e14f4bf7 (diff)
Rework PS owner service handling to use avahi flags for local services
Diffstat (limited to 'shell')
-rw-r--r--shell/PresenceService/Buddy.py9
-rw-r--r--shell/PresenceService/PresenceService.py162
-rw-r--r--shell/PresenceService/Service.py7
3 files changed, 83 insertions, 95 deletions
diff --git a/shell/PresenceService/Buddy.py b/shell/PresenceService/Buddy.py
index 6a8a245..a91eed2 100644
--- a/shell/PresenceService/Buddy.py
+++ b/shell/PresenceService/Buddy.py
@@ -287,9 +287,9 @@ class Buddy(object):
class Owner(Buddy):
"""Class representing the owner of the machine. This is the client
portion of the Owner, paired with the server portion in Owner.py."""
- def __init__(self, ps, bus_name, object_id, nick):
+ def __init__(self, ps, bus_name, object_id):
Buddy.__init__(self, bus_name, object_id, None)
- self._nick_name = nick
+ self._nick_name = env.get_nick_name()
self._color = env.get_color()
self._ps = ps
@@ -303,9 +303,12 @@ class Owner(Buddy):
# service added to the Owner determines the owner's address
source_addr = service.get_source_address()
if self._address is None:
- if self._ps.is_local_ip_address(source_addr):
+ if service.is_local():
self._address = source_addr
self._dbus_helper.PropertyChanged(['ip4_address'])
+ logging.debug("Adding owner service %s.%s at %s:%d." % (service.get_name(),
+ service.get_type(), service.get_source_address(),
+ service.get_port()))
return Buddy.add_service(self, service)
def is_owner(self):
diff --git a/shell/PresenceService/PresenceService.py b/shell/PresenceService/PresenceService.py
index 56b54a3..3b0bc1a 100644
--- a/shell/PresenceService/PresenceService.py
+++ b/shell/PresenceService/PresenceService.py
@@ -4,32 +4,15 @@ import Service
import Activity
import random
import logging
-from sugar import env
from sugar import util
-def _get_local_ip_address(ifname):
- """Call Linux specific bits to retrieve our own IP address."""
- import socket
- import sys
- import fcntl
-
- addr = None
- SIOCGIFADDR = 0x8915
- sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- try:
- ifreq = (ifname + '\0'*32)[:32]
- result = fcntl.ioctl(sockfd.fileno(), SIOCGIFADDR, ifreq)
- addr = socket.inet_ntoa(result[20:24])
- except IOError, exc:
- print "Error getting IP address: %s" % exc
- sockfd.close()
- return addr
-
-
+_SA_UNRESOLVED = 0
+_SA_RESOLVE_PENDING = 1
+_SA_RESOLVED = 2
class ServiceAdv(object):
"""Wrapper class to track services from Avahi."""
- def __init__(self, interface, protocol, name, stype, domain):
+ def __init__(self, interface, protocol, name, stype, domain, local):
self._interface = interface
self._protocol = protocol
if type(name) != type(u""):
@@ -42,7 +25,10 @@ class ServiceAdv(object):
raise ValueError("service advertisement domain must be unicode.")
self._domain = domain
self._service = None
- self._resolved = False
+ if type(local) != type(False):
+ raise ValueError("local must be a boolean.")
+ self._local = local
+ self._state = _SA_UNRESOLVED
def interface(self):
return self._interface
@@ -54,16 +40,21 @@ class ServiceAdv(object):
return self._stype
def domain(self):
return self._domain
+ def is_local(self):
+ return self._local
def service(self):
return self._service
def set_service(self, service):
if not isinstance(service, Service.Service):
raise ValueError("must be a valid service.")
self._service = service
- def resolved(self):
- return self._resolved
- def set_resolved(self, resolved):
- self._resolved = resolved
+ def state(self):
+ return self._state
+ def set_state(self, state):
+ if state == _SA_RESOLVE_PENDING:
+ if self._state == _SA_RESOLVED:
+ raise ValueError("Can't reset to resolve pending from resolved.")
+ self._state = state
_PRESENCE_SERVICE = "org.laptop.Presence"
@@ -246,10 +237,9 @@ class PresenceService(object):
self._services = {} # (name, type) -> Service
self._activities = {} # activity id -> Activity
- # Keep track of stuff we're already browsing with ZC
+ # Keep track of stuff we're already browsing
self._service_type_browsers = {}
self._service_browsers = {}
- self._resolve_queue = [] # Track resolve requests
# Resolved service list
self._service_advs = []
@@ -263,10 +253,9 @@ class PresenceService(object):
self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
# Our owner object
- owner_nick = env.get_nick_name()
objid = self._get_next_object_id()
- self._owner = Buddy.Owner(self, self._bus_name, objid, owner_nick)
- self._buddies[owner_nick] = self._owner
+ self._owner = Buddy.Owner(self, self._bus_name, objid)
+ self._buddies[self._owner.get_name()] = self._owner
self._started = False
@@ -341,13 +330,10 @@ class PresenceService(object):
def get_owner(self):
return self._owner
- def is_local_ip_address(self, address):
- if address in self._local_addrs.values():
- return True
- return False
-
- def _find_service_adv(self, interface=None, protocol=None, name=None, stype=None, domain=None):
- """Search a list of service advertisements for ones matching certain criteria."""
+ def _find_service_adv(self, interface=None, protocol=None, name=None,
+ stype=None, domain=None, local=None):
+ """Search a list of service advertisements for ones matching
+ certain criteria."""
adv_list = []
for adv in self._service_advs:
if interface and adv.interface() != interface:
@@ -360,10 +346,12 @@ class PresenceService(object):
continue
if domain and adv.domain() != domain:
continue
+ if local is not None and adv.is_local() != local:
+ continue
adv_list.append(adv)
return adv_list
- def _handle_new_service_for_buddy(self, service):
+ def _handle_new_service_for_buddy(self, service, local):
"""Deal with a new discovered service object."""
# Once a service is resolved, we match it up to an existing buddy,
# or create a new Buddy if this is the first service known about the buddy
@@ -420,21 +408,17 @@ class PresenceService(object):
self._dbus_helper.ActivityDisappeared(activity.object_path())
del self._activities[actid]
- def _resolve_service_reply_cb(self, interface, protocol, full_name, stype, domain, host, aprotocol, address, port, txt, flags):
- """When the service discovery finally gets here, we've got enough information about the
- service to assign it to a buddy."""
- logging.debug("resolved service '%s' type '%s' domain '%s' to %s:%s" % (full_name, stype, domain, address, port))
+ def _resolve_service_reply_cb(self, adv, interface, protocol, full_name,
+ stype, domain, host, aprotocol, address, port, txt, flags):
+ """When the service discovery finally gets here, we've got enough
+ information about the service to assign it to a buddy."""
+ logging.debug("Resolved service '%s' type '%s' domain '%s' to " \
+ " %s:%s" % (full_name, stype, domain, address, port))
- # If this service was previously unresolved, remove it from the
- # unresolved list
- adv_list = self._find_service_adv(interface=interface, protocol=protocol,
- name=full_name, stype=stype, domain=domain)
- if not adv_list:
+ if not adv in self._service_advs:
+ return False
+ if adv.state() != _SA_RESOLVED:
return False
- adv = adv_list[0]
- adv.set_resolved(True)
- if adv in self._resolve_queue:
- self._resolve_queue.remove(adv)
# See if we know about this service already
key = (full_name, stype)
@@ -442,12 +426,12 @@ class PresenceService(object):
objid = self._get_next_object_id()
service = Service.Service(self._bus_name, objid, name=full_name,
stype=stype, domain=domain, address=address, port=port,
- properties=txt, source_address=address)
+ properties=txt, source_address=address, local=adv.is_local())
self._services[key] = service
else:
# Already tracking this service; likely we were the one that shared it
- # in the first place, and therefore the source address would have been
- # set yet
+ # in the first place, and therefore the source address would not have
+ # been set yet
service = self._services[key]
if not service.get_source_address():
service.set_source_address(address)
@@ -456,51 +440,44 @@ class PresenceService(object):
adv.set_service(service)
# Merge the service into our buddy and activity lists, if needed
- buddy = self._handle_new_service_for_buddy(service)
+ buddy = self._handle_new_service_for_buddy(service, adv.is_local())
if buddy and service.get_activity_id():
self._handle_new_activity_service(service)
return False
- def _resolve_service_reply_cb_glue(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
- gobject.idle_add(self._resolve_service_reply_cb, interface, protocol,
- name, stype, domain, host, aprotocol, address, port, txt, flags)
+ def _resolve_service_reply_cb_glue(self, adv, interface, protocol, name,
+ stype, domain, host, aprotocol, address, port, txt, flags):
+ adv.set_state(_SA_RESOLVED)
+ gobject.idle_add(self._resolve_service_reply_cb, adv, interface,
+ protocol, name, stype, domain, host, aprotocol, address,
+ port, txt, flags)
- def _resolve_service_error_handler(self, err):
- logging.error("error resolving service: %s" % err)
+ def _resolve_service_error_handler(self, adv, err):
+ adv.set_state(_SA_UNRESOLVED)
+ logging.error("Error resolving service %s.%s: %s" % (adv.name(), adv.stype(), err))
def _resolve_service(self, adv):
"""Resolve and lookup a ZeroConf service to obtain its address and TXT records."""
# Ask avahi to resolve this particular service
- logging.debug('resolving service %s %s' % (adv.name(), adv.stype()))
self._mdns_service.ResolveService(int(adv.interface()), int(adv.protocol()), adv.name(),
adv.stype(), adv.domain(), avahi.PROTO_UNSPEC, dbus.UInt32(0),
- reply_handler=self._resolve_service_reply_cb_glue,
- error_handler=self._resolve_service_error_handler)
+ reply_handler=lambda *args: self._resolve_service_reply_cb_glue(adv, *args),
+ error_handler=lambda *args: self._resolve_service_error_handler(adv, *args))
return False
def _service_appeared_cb(self, interface, protocol, full_name, stype, domain, flags):
- logging.debug("found service '%s' (%d) of type '%s' in domain '%s' on %i.%i." % (full_name, flags, stype, domain, interface, protocol))
-
- # Add the service to our unresolved services list
+ local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
adv_list = self._find_service_adv(interface=interface, protocol=protocol,
- name=full_name, stype=stype, domain=domain)
+ name=full_name, stype=stype, domain=domain, local=local)
adv = None
if not adv_list:
adv = ServiceAdv(interface=interface, protocol=protocol, name=full_name,
- stype=stype, domain=domain)
+ stype=stype, domain=domain, local=local)
self._service_advs.append(adv)
else:
adv = adv_list[0]
- # Find out the IP address of this interface, if we haven't already
- if interface not in self._local_addrs.keys():
- ifname = self._mdns_service.GetNetworkInterfaceNameByIndex(interface)
- if ifname:
- addr = _get_local_ip_address(ifname)
- if addr:
- self._local_addrs[interface] = addr
-
# Decompose service name if we can
(actid, buddy_name) = Service.decompose_service_name(full_name)
@@ -508,11 +485,12 @@ class PresenceService(object):
resolve = False
if actid is not None or stype in self._registered_service_types:
resolve = True
- if resolve and not adv in self._resolve_queue:
- self._resolve_queue.append(adv)
+ if resolve and adv.state() == _SA_UNRESOLVED:
+ logging.debug("Found '%s' (%d) of type '%s' in domain" \
+ " '%s' on %i.%i; will resolve." % (full_name, flags, stype,
+ domain, interface, protocol))
+ adv.set_state(_SA_RESOLVE_PENDING)
gobject.idle_add(self._resolve_service, adv)
- else:
- logging.debug("Do not resolve service '%s' of type '%s', we don't care about it." % (full_name, stype))
return False
@@ -520,22 +498,27 @@ class PresenceService(object):
gobject.idle_add(self._service_appeared_cb, interface, protocol, name, stype, domain, flags)
def _service_disappeared_cb(self, interface, protocol, full_name, stype, domain, flags):
- logging.debug("service '%s' of type '%s' in domain '%s' on %i.%i disappeared." % (full_name, stype, domain, interface, protocol))
-
+ local = flags & avahi.LOOKUP_RESULT_OUR_OWN > 0
# If it's an unresolved service, remove it from our unresolved list
adv_list = self._find_service_adv(interface=interface, protocol=protocol,
- name=full_name, stype=stype, domain=domain)
+ name=full_name, stype=stype, domain=domain, local=local)
if not adv_list:
return False
# Get the service object; if none, we have nothing left to do
adv = adv_list[0]
- if adv in self._resolve_queue:
- self._resolve_queue.remove(adv)
service = adv.service()
+ self._service_advs.remove(adv)
+ del adv
if not service:
return False
+ logging.debug("Service %s.%s on %i.%i disappeared." % (full_name,
+ stype, domain, interface, protocol))
+
+ self._dbus_helper.ServiceDisappeared(service.object_path())
+ self._handle_remove_activity_service(service)
+
# Decompose service name if we can
(actid, buddy_name) = Service.decompose_service_name(full_name)
@@ -546,8 +529,6 @@ class PresenceService(object):
pass
else:
buddy.remove_service(service)
- self._dbus_helper.ServiceDisappeared(service.object_path())
- self._handle_remove_activity_service(service)
if not buddy.is_valid():
self._dbus_helper.BuddyDisappeared(buddy.object_path())
del self._buddies[buddy_name]
@@ -567,7 +548,6 @@ class PresenceService(object):
s_browser = self._mdns_service.ServiceBrowserNew(interface, protocol, stype, domain, dbus.UInt32(0))
browser_obj = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, s_browser),
avahi.DBUS_INTERFACE_SERVICE_BROWSER)
- logging.debug("now browsing for services of type '%s' in domain '%s' on %i.%i ..." % (stype, domain, interface, protocol))
browser_obj.connect_to_signal('ItemNew', self._service_appeared_cb_glue)
browser_obj.connect_to_signal('ItemRemove', self._service_disappeared_cb_glue)
@@ -600,7 +580,7 @@ class PresenceService(object):
raise Exception("Avahi does not appear to be running. '%s'" % str_exc)
else:
raise exc
- logging.debug("now browsing domain '%s' on %i.%i ..." % (domain, interface, protocol))
+ logging.debug("Browsing domain '%s' on %i.%i ..." % (domain, interface, protocol))
browser_obj.connect_to_signal('ItemNew', self._new_service_type_cb_glue)
self._service_type_browsers[(interface, protocol, domain)] = browser_obj
return False
@@ -667,7 +647,7 @@ class PresenceService(object):
objid = self._get_next_object_id()
service = Service.Service(self._bus_name, objid, name=name,
stype=stype, domain=domain, address=address, port=port,
- properties=properties, source_address=None)
+ properties=properties, source_address=None, local=True)
self._services[(name, stype)] = service
port = service.get_port()
diff --git a/shell/PresenceService/Service.py b/shell/PresenceService/Service.py
index a908ce9..3c65d99 100644
--- a/shell/PresenceService/Service.py
+++ b/shell/PresenceService/Service.py
@@ -104,7 +104,8 @@ class Service(object):
"""Encapsulates information about a specific ZeroConf/mDNS
service as advertised on the network."""
def __init__(self, bus_name, object_id, name, stype, domain=u"local",
- address=None, port=-1, properties=None, source_address=None):
+ address=None, port=-1, properties=None, source_address=None,
+ local=False):
if not bus_name:
raise ValueError("DBus bus name must be valid")
if not object_id or type(object_id) != type(1):
@@ -138,6 +139,7 @@ class Service(object):
self._properties = {}
self.set_properties(properties)
self._avahi_entry_group = None
+ self._local = local
# Source address is the unicast source IP
self._source_address = None
@@ -180,6 +182,9 @@ class Service(object):
raise RuntimeError("Can only set a service's owner once")
self._owner = owner
+ def is_local(self):
+ return self._local
+
def get_name(self):
"""Return the service's name, usually that of the
buddy who provides it."""