Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu@sugarlabs.org>2010-01-17 16:44:12 (GMT)
committer Tomeu Vizoso <tomeu@sugarlabs.org>2010-01-17 16:44:12 (GMT)
commit2351cf86536c3b7708157bd676c4cbd86c6796f1 (patch)
tree92d25a8b556d18df8595f613653280957d998ac2 /src
parent15c69e4c19b37a04e7857afdcd2355fcf16334bb (diff)
Implement mesh support again for NM 0.7 (dsd) #230
Diffstat (limited to 'src')
-rw-r--r--src/jarabe/desktop/meshbox.py222
-rw-r--r--src/jarabe/model/Makefile.am1
-rw-r--r--src/jarabe/model/network.py32
-rw-r--r--src/jarabe/model/olpcmesh.py214
4 files changed, 456 insertions, 13 deletions
diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
index 7b8e3a7..38f1e71 100644
--- a/src/jarabe/desktop/meshbox.py
+++ b/src/jarabe/desktop/meshbox.py
@@ -36,6 +36,7 @@ from sugar.graphics.menuitem import MenuItem
from sugar.activity.activityhandle import ActivityHandle
from sugar.activity import activityfactory
from sugar.util import unique_id
+from sugar import profile
from jarabe.model import neighborhood
from jarabe.view.buddyicon import BuddyIcon
@@ -51,17 +52,20 @@ from jarabe.model.network import Settings
from jarabe.model.network import IP4Config
from jarabe.model.network import WirelessSecurity
from jarabe.model.network import AccessPoint
+from jarabe.model.network import OlpcMesh as OlpcMeshSettings
+from jarabe.model.olpcmesh import OlpcMeshManager
_NM_SERVICE = 'org.freedesktop.NetworkManager'
_NM_IFACE = 'org.freedesktop.NetworkManager'
_NM_PATH = '/org/freedesktop/NetworkManager'
_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-_ICON_NAME = 'network-wireless'
-
+_AP_ICON_NAME = 'network-wireless'
+_OLPC_MESH_ICON_NAME = 'network-mesh'
class WirelessNetworkView(CanvasPulsingIcon):
def __init__(self, initial_ap):
@@ -149,7 +153,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
and self._name[-15] == '#'
def _create_palette(self):
- icon_name = get_icon_state(_ICON_NAME, self._strength)
+ icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
self._palette_icon = Icon(icon_name=icon_name,
icon_size=style.STANDARD_ICON_SIZE,
badge_name=self.props.badge_name)
@@ -224,9 +228,9 @@ class WirelessNetworkView(CanvasPulsingIcon):
if self._mode == network.NM_802_11_MODE_INFRA:
connection.set_connected()
- icon_name = '%s-connected' % _ICON_NAME
+ icon_name = '%s-connected' % _AP_ICON_NAME
else:
- icon_name = _ICON_NAME
+ icon_name = _AP_ICON_NAME
icon_name = get_icon_state(icon_name, self._strength)
if icon_name:
@@ -419,6 +423,17 @@ class WirelessNetworkView(CanvasPulsingIcon):
return None
return self._access_points[ap_path]
+ def is_olpc_mesh(self):
+ return self._mode == network.NM_802_11_MODE_ADHOC \
+ and self.name == "olpc-mesh"
+
+ def remove_all_aps(self):
+ for ap in self._access_points.values():
+ ap.disconnect()
+ self._access_points = {}
+ self._active_ap = None
+ self.update_strength()
+
def disconnect(self):
self._bus.remove_signal_receiver(self.__device_state_changed_cb,
signal_name='StateChanged',
@@ -430,6 +445,146 @@ class WirelessNetworkView(CanvasPulsingIcon):
dbus_interface=_NM_WIRELESS_IFACE)
+class OlpcMeshView(CanvasPulsingIcon):
+ def __init__(self, mesh_mgr, channel):
+ CanvasPulsingIcon.__init__(self, icon_name=_OLPC_MESH_ICON_NAME,
+ size=style.STANDARD_ICON_SIZE, cache=True)
+ self._bus = dbus.SystemBus()
+ self._channel = channel
+ self._mesh_mgr = mesh_mgr
+ self._disconnect_item = None
+ self._connect_item = None
+ self._greyed_out = False
+ self._name = ''
+ self._device_state = None
+ self._connection = None
+ self._active = False
+ device = mesh_mgr.mesh_device
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+ interface_props = dbus.Interface(device,
+ 'org.freedesktop.DBus.Properties')
+ interface_props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_device_state_reply_cb,
+ error_handler=self.__get_device_state_error_cb)
+ interface_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel',
+ reply_handler=self.__get_active_channel_reply_cb,
+ error_handler=self.__get_active_channel_error_cb)
+
+ self._bus.add_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=device.object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
+ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+ self.props.pulse_color = pulse_color
+ self.props.base_color = profile.get_color()
+ self._palette = self._create_palette()
+ self.set_palette(self._palette)
+
+ def _create_palette(self):
+ _palette = palette.Palette(_("Mesh Network %d") % self._channel)
+
+ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
+ self._connect_item.connect('activate', self.__connect_activate_cb)
+ _palette.menu.append(self._connect_item)
+
+ return _palette
+
+ def __get_device_state_reply_cb(self, state):
+ self._device_state = state
+ self._update()
+
+ def __get_device_state_error_cb(self, err):
+ logging.error('Error getting the device state: %s', err)
+
+ def __device_state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update()
+
+ def __get_active_channel_reply_cb(self, channel):
+ self._active = (channel == self._channel)
+ self._update()
+
+ def __get_active_channel_error_cb(self, err):
+ logging.error('Error getting the active channel: %s', err)
+
+ def __wireless_properties_changed_cb(self, properties):
+ if 'ActiveChannel' in properties:
+ channel = properties['ActiveChannel']
+ self._active = (channel == self._channel)
+ self._update()
+
+ def _update(self):
+ if self._active:
+ state = self._device_state
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+ if state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_NEED_AUTH,
+ network.DEVICE_STATE_IP_CONFIG]:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connecting...')
+ self.props.pulsing = True
+ elif state == network.DEVICE_STATE_ACTIVATED:
+ if self._disconnect_item:
+ self._disconnect_item.show()
+ self._connect_item.hide()
+ self._palette.props.secondary_text = _('Connected')
+ self.props.pulsing = False
+ else:
+ if self._disconnect_item:
+ self._disconnect_item.hide()
+ self._connect_item.show()
+ self._palette.props.secondary_text = None
+ self.props.pulsing = False
+
+ def _update_color(self):
+ if self._greyed_out:
+ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
+ else:
+ self.props.base_color = profile.get_color()
+
+ def __connect_activate_cb(self, icon):
+ self._connect()
+
+ def __button_release_event_cb(self, icon, event):
+ self._connect()
+
+ def _connect(self):
+ self._mesh_mgr.user_activate_channel(self._channel)
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Connection activated: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to activate connection: %s', err)
+
+ def set_filter(self, query):
+ self._greyed_out = (query != '')
+ self._update_color()
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+ self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
+ signal_name='PropertiesChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_OLPC_MESH_IFACE)
+
+
class ActivityView(hippo.CanvasBox):
def __init__(self, model):
hippo.CanvasBox.__init__(self)
@@ -730,6 +885,8 @@ class NetworkManagerObserver(object):
device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
self._devices[device_o] = DeviceObserver(self._box, device)
+ elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ self._box.enable_olpc_mesh(device)
def _get_device_path_error_cb(self, err):
logging.error('Failed to get device type: %s', err)
@@ -742,7 +899,13 @@ class NetworkManagerObserver(object):
observer = self._devices[device_o]
observer.disconnect()
del self._devices[device_o]
-
+ return
+
+ device = self._bus.get_object(_NM_SERVICE, device_o)
+ props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
+ device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ self._box.disable_olpc_mesh(device)
class MeshBox(gtk.VBox):
__gtype_name__ = 'SugarMeshBox'
@@ -757,7 +920,7 @@ class MeshBox(gtk.VBox):
self._model = neighborhood.get_model()
self._buddies = {}
self._activities = {}
- self._mesh = {}
+ self._mesh = []
self._buddy_to_activity = {}
self._suspended = True
self._query = ''
@@ -902,6 +1065,14 @@ class MeshBox(gtk.VBox):
del self.wireless_networks[hash]
def _ap_props_changed_cb(self, ap, old_hash):
+ # if we have mesh hardware, ignore OLPC mesh networks that appear as
+ # normal wifi networks
+ if len(self._mesh) > 0 and ap.mode == network.NM_802_11_MODE_ADHOC \
+ and ap.name == "olpc-mesh":
+ logging.debug("ignoring OLPC mesh IBSS")
+ ap.disconnect()
+ return
+
if old_hash is None: # new AP finished initializing
self._add_ap_to_network(ap)
return
@@ -936,18 +1107,49 @@ class MeshBox(gtk.VBox):
self._remove_net_if_empty(net, ap.network_hash())
return
- logging.error('Can not remove access point %s', ap_o)
+ # it's not an error if the AP isn't found, since we might have ignored
+ # it (e.g. olpc-mesh adhoc network)
+ logging.debug('Can not remove access point %s' % ap_o)
+
+ def _add_olpc_mesh_icon(self, mesh_mgr, channel):
+ icon = OlpcMeshView(mesh_mgr, channel)
+ self._layout.add(icon)
+ self._mesh.append(icon)
+
+ def enable_olpc_mesh(self, mesh_device):
+ mesh_mgr = OlpcMeshManager(mesh_device)
+ self._add_olpc_mesh_icon(mesh_mgr, 1)
+ self._add_olpc_mesh_icon(mesh_mgr, 6)
+ self._add_olpc_mesh_icon(mesh_mgr, 11)
+
+ # the OLPC mesh can be recognised as a "normal" wifi network. remove
+ # any such normal networks if they have been created
+ for hash, net in self.wireless_networks.iteritems():
+ if not net.is_olpc_mesh():
+ continue
+
+ logging.debug("removing OLPC mesh IBSS")
+ net.remove_all_aps()
+ net.disconnect()
+ self._layout.remove(net)
+ del self.wireless_networks[hash]
+
+ def disable_olpc_mesh(self, mesh_device):
+ for icon in self._mesh:
+ icon.disconnect()
+ self._layout.remove(icon)
+ self._mesh = []
def suspend(self):
if not self._suspended:
self._suspended = True
- for net in self.wireless_networks.values():
+ for net in self.wireless_networks.values() + self._mesh:
net.props.paused = True
def resume(self):
if self._suspended:
self._suspended = False
- for net in self.wireless_networks.values():
+ for net in self.wireless_networks.values() + self._mesh:
net.props.paused = False
def _toolbar_query_changed_cb(self, toolbar, query):
diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am
index 399db65..18d44da 100644
--- a/src/jarabe/model/Makefile.am
+++ b/src/jarabe/model/Makefile.am
@@ -6,6 +6,7 @@ sugar_PYTHON = \
filetransfer.py \
friends.py \
invites.py \
+ olpcmesh.py \
owner.py \
neighborhood.py \
network.py \
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
index 10b73ab..b3c30d9 100644
--- a/src/jarabe/model/network.py
+++ b/src/jarabe/model/network.py
@@ -29,6 +29,7 @@ from sugar import env
DEVICE_TYPE_802_3_ETHERNET = 1
DEVICE_TYPE_802_11_WIRELESS = 2
+DEVICE_TYPE_802_11_OLPC_MESH = 6
DEVICE_STATE_UNKNOWN = 0
DEVICE_STATE_UNMANAGED = 1
@@ -103,6 +104,8 @@ class WirelessSecurity(object):
return wireless_security
class Wireless(object):
+ nm_name = "802-11-wireless"
+
def __init__(self):
self.ssid = None
self.security = None
@@ -119,6 +122,25 @@ class Wireless(object):
wireless['band'] = self.band
return wireless
+
+class OlpcMesh(object):
+ nm_name = "802-11-olpc-mesh"
+
+ def __init__(self, channel, anycast_addr):
+ self.channel = channel
+ self.anycast_addr = anycast_addr
+
+ def get_dict(self):
+ ret = {
+ "ssid": dbus.ByteArray("olpc-mesh"),
+ "channel": self.channel,
+ }
+
+ if self.anycast_addr:
+ ret["dhcp-anycast-address"] = dbus.ByteArray(self.anycast_addr)
+ return ret
+
+
class Connection(object):
def __init__(self):
self.id = None
@@ -147,16 +169,20 @@ class IP4Config(object):
return ip4_config
class Settings(object):
- def __init__(self):
+ def __init__(self, wireless_cfg=None):
self.connection = Connection()
- self.wireless = Wireless()
self.ip4_config = None
self.wireless_security = None
+ if wireless_cfg is not None:
+ self.wireless = wireless_cfg
+ else:
+ self.wireless = Wireless()
+
def get_dict(self):
settings = {}
settings['connection'] = self.connection.get_dict()
- settings['802-11-wireless'] = self.wireless.get_dict()
+ settings[self.wireless.nm_name] = self.wireless.get_dict()
if self.wireless_security is not None:
settings['802-11-wireless-security'] = \
self.wireless_security.get_dict()
diff --git a/src/jarabe/model/olpcmesh.py b/src/jarabe/model/olpcmesh.py
new file mode 100644
index 0000000..cbd7ddd
--- /dev/null
+++ b/src/jarabe/model/olpcmesh.py
@@ -0,0 +1,214 @@
+# Copyright (C) 2009 One Laptop per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import logging
+
+import dbus
+import gobject
+
+from jarabe.model import network
+from jarabe.model.network import Settings
+from jarabe.model.network import OlpcMesh as OlpcMeshSettings
+from sugar.util import unique_id
+
+_NM_SERVICE = 'org.freedesktop.NetworkManager'
+_NM_IFACE = 'org.freedesktop.NetworkManager'
+_NM_PATH = '/org/freedesktop/NetworkManager'
+_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
+_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+
+_XS_ANYCAST = "\xc0\x27\xc0\x27\xc0\x00"
+
+DEVICE_STATE_UNKNOWN = 0
+DEVICE_STATE_UNMANAGED = 1
+DEVICE_STATE_UNAVAILABLE = 2
+DEVICE_STATE_DISCONNECTED = 3
+DEVICE_STATE_PREPARE = 4
+DEVICE_STATE_CONFIG = 5
+DEVICE_STATE_NEED_AUTH = 6
+DEVICE_STATE_IP_CONFIG = 7
+DEVICE_STATE_ACTIVATED = 8
+DEVICE_STATE_FAILED = 9
+
+class OlpcMeshManager(object):
+ def __init__(self, mesh_device):
+ self._bus = dbus.SystemBus()
+
+ self.mesh_device = mesh_device
+ self.eth_device = self._get_companion_device()
+
+ self._connection_queue = []
+ """Stack of connections that we'll iterate through until we find one
+ that works.
+
+ """
+
+ props = dbus.Interface(self.mesh_device,
+ 'org.freedesktop.DBus.Properties')
+ props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_mesh_state_reply_cb,
+ error_handler=self.__get_state_error_cb)
+
+ props = dbus.Interface(self.eth_device,
+ 'org.freedesktop.DBus.Properties')
+ props.Get(_NM_DEVICE_IFACE, 'State',
+ reply_handler=self.__get_eth_state_reply_cb,
+ error_handler=self.__get_state_error_cb)
+
+ self._bus.add_signal_receiver(self.__eth_device_state_changed_cb,
+ signal_name='StateChanged',
+ path=self.eth_device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ self._bus.add_signal_receiver(self.__mshdev_state_changed_cb,
+ signal_name='StateChanged',
+ path=self.mesh_device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ self._idle_source = 0
+ self._mesh_device_state = DEVICE_STATE_UNKNOWN
+ self._eth_device_state = DEVICE_STATE_UNKNOWN
+
+ if self._have_configured_connections():
+ self._start_automesh()
+ else:
+ self._start_automesh_timer()
+
+ def _get_companion_device(self):
+ props = dbus.Interface(self.mesh_device,
+ 'org.freedesktop.DBus.Properties')
+ eth_device_o = props.Get(_NM_OLPC_MESH_IFACE, 'Companion')
+ return self._bus.get_object(_NM_SERVICE, eth_device_o)
+
+ def _have_configured_connections(self):
+ return len(network.get_settings().connections) > 0
+
+ def _start_automesh_timer(self):
+ """Start our timer system which basically looks for 10 seconds of
+ inactivity on both devices, then starts automesh.
+
+ """
+ if self._idle_source != 0:
+ gobject.source_remove(self._idle_source)
+ self._idle_source = gobject.timeout_add_seconds(10, self._idle_check)
+
+ def __get_state_error_cb(self, err):
+ logging.debug('Error getting the device state: %s', err)
+
+ def __get_mesh_state_reply_cb(self, state):
+ self._mesh_device_state = state
+ self._maybe_schedule_idle_check()
+
+ def __get_eth_state_reply_cb(self, state):
+ self._eth_device_state = state
+ self._maybe_schedule_idle_check()
+
+ def __eth_device_state_changed_cb(self, new_state, old_state, reason):
+ """If a connection is activated on the eth device, stop trying our
+ automatic connections.
+
+ """
+ self._eth_device_state = new_state
+ self._maybe_schedule_idle_check()
+
+ if new_state >= DEVICE_STATE_PREPARE \
+ and new_state <= DEVICE_STATE_ACTIVATED \
+ and len(self._connection_queue) > 0:
+ self._connection_queue = []
+
+ def __mshdev_state_changed_cb(self, new_state, old_state, reason):
+ self._mesh_device_state = new_state
+ self._maybe_schedule_idle_check()
+
+ if new_state == DEVICE_STATE_FAILED:
+ self._try_next_connection_from_queue()
+ elif new_state == DEVICE_STATE_ACTIVATED \
+ and len(self._connection_queue) > 0:
+ self._empty_connection_queue()
+
+ def _maybe_schedule_idle_check(self):
+ if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
+ and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+ self._start_automesh_timer()
+
+ def _idle_check(self):
+ if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
+ and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+ logging.debug("starting automesh due to inactivity")
+ self._start_automesh()
+ return False
+
+ def _make_connection(self, channel, anycast_address=None):
+ wireless_config = OlpcMeshSettings(channel, anycast_address)
+ settings = Settings(wireless_cfg=wireless_config)
+ if not anycast_address:
+ settings.ip4_config = network.IP4Config()
+ settings.ip4_config.method = 'link-local'
+ settings.connection.id = 'olpc-mesh-' + str(channel)
+ settings.connection.uuid = unique_id()
+ settings.connection.type = '802-11-olpc-mesh'
+ connection = network.add_connection(settings.connection.id, settings)
+ return connection
+
+ def __activate_reply_cb(self, connection):
+ logging.debug('Connection activated: %s', connection)
+
+ def __activate_error_cb(self, err):
+ logging.error('Failed to activate connection: %s', err)
+
+ def _activate_connection(self, channel, anycast_address=None):
+ logging.debug("activate channel %d anycast %s",
+ (channel, repr(anycast_address)))
+ proxy = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ network_manager = dbus.Interface(proxy, _NM_IFACE)
+ connection = self._make_connection(channel, anycast_address)
+
+ network_manager.ActivateConnection(network.SETTINGS_SERVICE,
+ connection.path,
+ self.mesh_device.object_path,
+ self.mesh_device.object_path,
+ reply_handler=self.__activate_reply_cb,
+ error_handler=self.__activate_error_cb)
+
+ def _try_next_connection_from_queue(self):
+ if len(self._connection_queue) == 0:
+ return
+
+ channel, anycast = self._connection_queue.pop()
+ self._activate_connection(channel, anycast)
+
+ def _empty_connection_queue(self):
+ self._connection_queue = []
+
+ def user_activate_channel(self, channel):
+ """Activate a mesh connection on a user-specified channel.
+ Looks for XS first, then resorts to simple mesh."""
+ self._empty_connection_queue()
+ self._connection_queue.append((channel, None))
+ self._connection_queue.append((channel, _XS_ANYCAST))
+ self._try_next_connection_from_queue()
+
+ def _start_automesh(self):
+ """Start meshing automatically, intended when there are no better
+ networks to connect to. First looks for XS on all channels, then falls
+ back to simple mesh on channel 1."""
+ self._empty_connection_queue()
+ self._connection_queue.append((1, None))
+ self._connection_queue.append((11, _XS_ANYCAST))
+ self._connection_queue.append((6, _XS_ANYCAST))
+ self._connection_queue.append((1, _XS_ANYCAST))
+ self._try_next_connection_from_queue()
+