1# Lint as: python2, python3 2# Copyright 2014 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6from __future__ import absolute_import 7from __future__ import division 8from __future__ import print_function 9 10import dbus 11import dbus.mainloop.glib 12import six 13import time 14 15from autotest_lib.client.common_lib.cros.network import apmanager_constants 16from autotest_lib.client.cros import dbus_util 17 18 19class ApmanagerProxyError(Exception): 20 """Exceptions raised by ApmanagerProxy and it's children.""" 21 pass 22 23 24class ApmanagerProxy(object): 25 """A wrapper around a DBus proxy for apmanager.""" 26 27 # Core DBus error names 28 DBUS_ERROR_UNKNOWN_OBJECT = 'org.freedesktop.DBus.Error.UnknownObject' 29 DBUS_ERROR_SERVICE_UNKNOWN = 'org.freedesktop.DBus.Error.ServiceUnknown' 30 DBUS_ERROR_UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod' 31 32 # apmanager Service and Interface names. 33 DBUS_SERVICE = 'org.chromium.apmanager' 34 DBUS_PROPERTY_INTERFACE = 'org.freedesktop.DBus.Properties' 35 DBUS_CONFIG_INTERFACE = 'org.chromium.apmanager.Config' 36 DBUS_SERVICE_INTERFACE = 'org.chromium.apmanager.Service' 37 DBUS_MANAGER_INTERFACE = 'org.chromium.apmanager.Manager' 38 DBUS_MANAGER_PATH = '/org/chromium/apmanager/Manager' 39 40 # AP Service property keys 41 SERVICE_PROPERTY_CONFIG = 'Config' 42 43 # Mapping for property to dbus type function. 44 CONFIG_PROPERTY_DBUS_TYPE_MAPPING = { 45 apmanager_constants.CONFIG_BRIDGE_INTERFACE: dbus.String, 46 apmanager_constants.CONFIG_CHANNEL: dbus.UInt16, 47 apmanager_constants.CONFIG_HIDDEN_NETWORK: dbus.Boolean, 48 apmanager_constants.CONFIG_HW_MODE: dbus.String, 49 apmanager_constants.CONFIG_INTERFACE_NAME: dbus.String, 50 apmanager_constants.CONFIG_OPERATION_MODE: dbus.String, 51 apmanager_constants.CONFIG_PASSPHRASE: dbus.String, 52 apmanager_constants.CONFIG_SECURITY_MODE: dbus.String, 53 apmanager_constants.CONFIG_SERVER_ADDRESS_INDEX: dbus.UInt16, 54 apmanager_constants.CONFIG_SSID: dbus.String} 55 56 POLLING_INTERVAL_SECONDS = 0.2 57 58 59 def __init__(self, bus=None, timeout_seconds=10): 60 if bus is None: 61 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 62 bus = dbus.SystemBus() 63 self._bus = bus 64 self._manager = None 65 self._connect_to_dbus(timeout_seconds) 66 67 68 def _connect_to_dbus(self, timeout_seconds): 69 """Connect to apmanager over DBus and initialize the DBus object for 70 org.chromium.apmanager.Manager interface. 71 72 If apmanager is not yet running, retry until it is, or until 73 |timeout_seconds| expires. 74 75 @param timeout_seconds float number of seconds to wait for connecting 76 to apmanager's DBus service. 77 78 """ 79 end_time = time.time() + timeout_seconds 80 while self._manager is None and time.time() < end_time: 81 try: 82 self._manager = \ 83 self._get_dbus_object(self.DBUS_MANAGER_INTERFACE, 84 self.DBUS_MANAGER_PATH) 85 except dbus.exceptions.DBusException as e: 86 if (e.get_dbus_name() != 87 ApmanagerProxy.DBUS_ERROR_SERVICE_UNKNOWN): 88 raise ApmanagerProxyError('Error connecting to apmanager') 89 else: 90 # Wait a moment before retrying 91 time.sleep(ApmanagerProxy.POLLING_INTERVAL_SECONDS) 92 if self._manager is None: 93 raise ApmanagerProxyError('Timeout connecting to apmanager') 94 95 96 def _get_dbus_object(self, interface_name, path): 97 """Return the DBus object of interface |interface_name| at |path| in 98 apmanager DBUS service. 99 100 @param interface_name string (e.g. self.DBUS_SERVICE_INTERFACE). 101 @param path path to object in apmanager (e.g. '/manager/services/1'). 102 @return DBus proxy object. 103 104 """ 105 return dbus.Interface( 106 self._bus.get_object(self.DBUS_SERVICE, path), 107 interface_name) 108 109 110 def _get_dbus_property(self, dbus_object, interface_name, property_key): 111 """get property on a dbus Interface 112 113 @param dbus_object DBus object to read property from 114 @param interface_name string name of the interface 115 @param property_key string name of property on interface 116 @return python typed object representing property value or None 117 118 """ 119 # Get the property interface for the given DBus object. 120 property_interface = self._get_dbus_object( 121 self.DBUS_PROPERTY_INTERFACE, 122 dbus_object.object_path) 123 # Invoke Get method on the property interface. 124 try: 125 value = dbus_util.dbus2primitive( 126 property_interface.Get(dbus.String(interface_name), 127 dbus.String(property_key))); 128 except dbus.exceptions.DBusException as e: 129 raise ApmanagerProxyError( 130 'Failed to get property %s on interface %s' % 131 (property_key, interface_name)) 132 return value 133 134 135 def _set_dbus_property(self, 136 dbus_object, 137 interface_name, 138 property_key, 139 value): 140 """set property on a dbus Interface 141 142 @param dbus_object DBus object to set property on 143 @param interface_name string name of the interface 144 @param property_key string name of property on interface 145 @param value dbus_type value to set for property 146 147 """ 148 # Get the property interface for the given DBus object. 149 property_interface = self._get_dbus_object( 150 self.DBUS_PROPERTY_INTERFACE, 151 dbus_object.object_path) 152 # Invoke Set method on the property interface. 153 try: 154 property_interface.Set(dbus.String(interface_name), 155 dbus.String(property_key), 156 value); 157 except dbus.exceptions.DBusException as e: 158 raise ApmanagerProxyError( 159 'Failed to set property %s on interface %s' % 160 (property_key, interface_name)) 161 162 163 # TODO(zqiu): add more optional parameters for setting additional 164 # service configurations. 165 def start_service(self, config_params): 166 """Create/start an AP service with provided configurations. 167 168 @param config_params dictionary of configuration parameters. 169 @return string object path of the newly created service. 170 171 """ 172 service = self._get_dbus_object( 173 self.DBUS_SERVICE_INTERFACE, 174 dbus_util.dbus2primitive(self._manager.CreateService())) 175 # Get configuration object for the service. 176 service_config = self._get_dbus_object( 177 self.DBUS_CONFIG_INTERFACE, 178 self._get_dbus_property(service, 179 self.DBUS_SERVICE_INTERFACE, 180 self.SERVICE_PROPERTY_CONFIG)) 181 # Set configuration properties. 182 for name, value in six.iteritems(config_params): 183 if name in self.CONFIG_PROPERTY_DBUS_TYPE_MAPPING: 184 func = self.CONFIG_PROPERTY_DBUS_TYPE_MAPPING[name] 185 self._set_dbus_property(service_config, 186 self.DBUS_CONFIG_INTERFACE, 187 name, 188 func(value, variant_level=1)) 189 else: 190 raise ApmanagerProxyError('Unknown configuration parameter [%s]' 191 % name) 192 193 # Start AP service. 194 service.Start() 195 return service.object_path 196 197 198 def terminate_service(self, service_path): 199 """ Terminate and remove the AP service |service|. 200 201 @param service_path string object path of the service. 202 203 """ 204 self._manager.RemoveService(dbus.ObjectPath(service_path)) 205