OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Provides wifi scan API binding for suitable for typical linux distributions. | 5 // Provides wifi scan API binding for suitable for typical linux distributions. |
6 // Currently, only the NetworkManager API is used, accessed via D-Bus (in turn | 6 // Currently, only the NetworkManager API is used, accessed via D-Bus (in turn |
7 // accessed via the GLib wrapper). | 7 // accessed via the GLib wrapper). |
8 | 8 |
9 #include "content/browser/geolocation/wifi_data_provider_linux.h" | 9 #include "content/browser/geolocation/wifi_data_provider_linux.h" |
10 | 10 |
11 #include <dbus/dbus-glib.h> | |
12 #include <dbus/dbus-glib-lowlevel.h> | |
13 #include <dbus/dbus.h> | |
14 #include <dlfcn.h> | |
15 #include <glib.h> | |
16 | |
17 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
18 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
19 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
14 #include "dbus/bus.h" | |
15 #include "dbus/message.h" | |
16 #include "dbus/object_proxy.h" | |
20 | 17 |
21 namespace { | 18 namespace { |
22 // The time periods between successive polls of the wifi data. | 19 // The time periods between successive polls of the wifi data. |
23 const int kDefaultPollingIntervalMilliseconds = 10 * 1000; // 10s | 20 const int kDefaultPollingIntervalMilliseconds = 10 * 1000; // 10s |
24 const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000; // 2 mins | 21 const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000; // 2 mins |
25 const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000; // 10 mins | 22 const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000; // 10 mins |
26 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s | 23 const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s |
27 | 24 |
28 const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager"; | 25 const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager"; |
29 const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager"; | 26 const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager"; |
30 const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager"; | 27 const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager"; |
31 | 28 |
32 // From http://projects.gnome.org/NetworkManager/developers/spec.html | 29 // From http://projects.gnome.org/NetworkManager/developers/spec.html |
33 enum { NM_DEVICE_TYPE_WIFI = 2 }; | 30 enum { NM_DEVICE_TYPE_WIFI = 2 }; |
34 | 31 |
35 // Function type matching dbus_g_bus_get_private so that we can | |
36 // dynamically determine the presence of this symbol (see | |
37 // NetworkManagerWlanApi::Init) | |
38 typedef DBusGConnection* DBusGBusGetPrivateFunc( | |
39 DBusBusType type, GMainContext* context, GError** error); | |
40 | |
41 // Utility wrappers to make various GLib & DBus structs into scoped objects. | |
42 class ScopedGPtrArrayFree { | |
43 public: | |
44 void operator()(GPtrArray* x) const { | |
45 if (x) | |
46 g_ptr_array_free(x, TRUE); | |
47 } | |
48 }; | |
49 // Use ScopedGPtrArrayPtr as if it were scoped_ptr<GPtrArray> | |
50 typedef scoped_ptr_malloc<GPtrArray, ScopedGPtrArrayFree> ScopedGPtrArrayPtr; | |
51 | |
52 class ScopedGObjectFree { | |
53 public: | |
54 void operator()(void* x) const { | |
55 if (x) | |
56 g_object_unref(x); | |
57 } | |
58 }; | |
59 // Use ScopedDBusGProxyPtr as if it were scoped_ptr<DBusGProxy> | |
60 typedef scoped_ptr_malloc<DBusGProxy, ScopedGObjectFree> ScopedDBusGProxyPtr; | |
61 | |
62 // Use ScopedGValue::v as an instance of GValue with automatic cleanup. | |
63 class ScopedGValue { | |
64 public: | |
65 ScopedGValue() | |
66 : v(empty_gvalue()) { | |
67 } | |
68 ~ScopedGValue() { | |
69 g_value_unset(&v); | |
70 } | |
71 static GValue empty_gvalue() { | |
72 GValue value = {0}; | |
73 return value; | |
74 } | |
75 | |
76 GValue v; | |
77 }; | |
78 | |
79 // Use ScopedDLHandle to automatically clean up after dlopen. | |
80 class ScopedDLHandle { | |
81 public: | |
82 ScopedDLHandle(void* handle) | |
83 : handle_(handle) { | |
84 } | |
85 ~ScopedDLHandle() { | |
86 if (handle_) | |
87 dlclose(handle_); | |
88 } | |
89 void* get() { | |
90 return handle_; | |
91 } | |
92 private: | |
93 void *handle_; | |
94 }; | |
95 | |
96 // Wifi API binding to NetworkManager, to allow reuse of the polling behavior | 32 // Wifi API binding to NetworkManager, to allow reuse of the polling behavior |
97 // defined in WifiDataProviderCommon. | 33 // defined in WifiDataProviderCommon. |
98 // TODO(joth): NetworkManager also allows for notification based handling, | 34 // TODO(joth): NetworkManager also allows for notification based handling, |
99 // however this will require reworking of the threading code to run a GLib | 35 // however this will require reworking of the threading code to run a GLib |
100 // event loop (GMainLoop). | 36 // event loop (GMainLoop). |
101 class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface { | 37 class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface { |
102 public: | 38 public: |
103 NetworkManagerWlanApi(); | 39 NetworkManagerWlanApi(); |
104 ~NetworkManagerWlanApi(); | 40 ~NetworkManagerWlanApi(); |
105 | 41 |
106 // Must be called before any other interface method. Will return false if the | 42 // Must be called before any other interface method. Will return false if the |
107 // NetworkManager session cannot be created (e.g. not present on this distro), | 43 // NetworkManager session cannot be created (e.g. not present on this distro), |
108 // in which case no other method may be called. | 44 // in which case no other method may be called. |
109 bool Init(); | 45 bool Init(); |
110 | 46 |
47 // Similar to Init() but can inject the bus object. Used for testing. | |
48 bool InitWithBus(dbus::Bus* bus); | |
49 | |
111 // WifiDataProviderCommon::WlanApiInterface | 50 // WifiDataProviderCommon::WlanApiInterface |
stevenjb
2011/08/24 23:32:04
Should probably comment that this makes blocking D
satorux1
2011/08/25 06:03:17
Done.
| |
112 bool GetAccessPointData(WifiData::AccessPointDataSet* data); | 51 virtual bool GetAccessPointData(WifiData::AccessPointDataSet* data); |
113 | 52 |
114 private: | 53 private: |
115 // Checks if the last dbus call returned an error. If it did, logs the error | |
116 // message, frees it and returns true. | |
117 // This must be called after every dbus call that accepts |&error_| | |
118 bool CheckError(); | |
119 | |
120 // Enumerates the list of available network adapter devices known to | 54 // Enumerates the list of available network adapter devices known to |
121 // NetworkManager. Ownership of the array (and contained objects) is returned | 55 // NetworkManager. Return true on success. |
122 // to the caller. | 56 bool GetAdapterDeviceList(std::vector<std::string>* device_paths); |
123 GPtrArray* GetAdapterDeviceList(); | |
124 | 57 |
125 // Given the NetworkManager path to a wireless adapater, dumps the wifi scan | 58 // Given the NetworkManager path to a wireless adapater, dumps the wifi scan |
126 // results and appends them to |data|. Returns false if a fatal error is | 59 // results and appends them to |data|. Returns false if a fatal error is |
127 // encountered such that the data set could not be populated. | 60 // encountered such that the data set could not be populated. |
128 bool GetAccessPointsForAdapter(const gchar* adapter_path, | 61 bool GetAccessPointsForAdapter(const std::string& adapter_path, |
129 WifiData::AccessPointDataSet* data); | 62 WifiData::AccessPointDataSet* data); |
130 | 63 |
131 // Internal method used by |GetAccessPointsForAdapter|, given a wifi access | 64 // Internal method used by |GetAccessPointsForAdapter|, given a wifi access |
132 // point proxy retrieves the named property into |value_out|. Returns false if | 65 // point proxy retrieves the named property and returns it. Returns NULL if |
133 // the property could not be read, or is not of type |expected_gvalue_type|. | 66 // the property could not be read. |
134 bool GetAccessPointProperty(DBusGProxy* proxy, const char* property_name, | 67 dbus::Response* GetAccessPointProperty(dbus::ObjectProxy* proxy, |
135 int expected_gvalue_type, GValue* value_out); | 68 const std::string& property_name); |
136 | 69 |
137 // Error from the last dbus call. NULL when there's no error. Freed and | 70 scoped_refptr<dbus::Bus> system_bus_; |
138 // cleared by CheckError(). | 71 dbus::ObjectProxy* network_manager_proxy_; |
139 GError* error_; | |
140 // Connection to the dbus system bus. | |
141 DBusGConnection* connection_; | |
142 // Main context | |
143 GMainContext* context_; | |
144 // Proxy to the network manager dbus service. | |
145 ScopedDBusGProxyPtr proxy_; | |
146 | 72 |
147 DISALLOW_COPY_AND_ASSIGN(NetworkManagerWlanApi); | 73 DISALLOW_COPY_AND_ASSIGN(NetworkManagerWlanApi); |
148 }; | 74 }; |
149 | 75 |
150 // Convert a wifi frequency to the corresponding channel. Adapted from | 76 // Convert a wifi frequency to the corresponding channel. Adapted from |
151 // geolocaiton/wifilib.cc in googleclient (internal to google). | 77 // geolocaiton/wifilib.cc in googleclient (internal to google). |
152 int frquency_in_khz_to_channel(int frequency_khz) { | 78 int frquency_in_khz_to_channel(int frequency_khz) { |
153 if (frequency_khz >= 2412000 && frequency_khz <= 2472000) // Channels 1-13. | 79 if (frequency_khz >= 2412000 && frequency_khz <= 2472000) // Channels 1-13. |
154 return (frequency_khz - 2407000) / 5000; | 80 return (frequency_khz - 2407000) / 5000; |
155 if (frequency_khz == 2484000) | 81 if (frequency_khz == 2484000) |
156 return 14; | 82 return 14; |
157 if (frequency_khz > 5000000 && frequency_khz < 6000000) // .11a bands. | 83 if (frequency_khz > 5000000 && frequency_khz < 6000000) // .11a bands. |
158 return (frequency_khz - 5000000) / 5000; | 84 return (frequency_khz - 5000000) / 5000; |
159 // Ignore everything else. | 85 // Ignore everything else. |
160 return AccessPointData().channel; // invalid channel | 86 return AccessPointData().channel; // invalid channel |
161 } | 87 } |
162 | 88 |
163 NetworkManagerWlanApi::NetworkManagerWlanApi() | 89 NetworkManagerWlanApi::NetworkManagerWlanApi() { |
164 : error_(NULL), | |
165 connection_(NULL), | |
166 context_(NULL) | |
167 { | |
168 } | 90 } |
169 | 91 |
170 NetworkManagerWlanApi::~NetworkManagerWlanApi() { | 92 NetworkManagerWlanApi::~NetworkManagerWlanApi() { |
171 proxy_.reset(); | |
172 if (connection_) { | |
173 dbus_connection_close(dbus_g_connection_get_connection(connection_)); | |
174 dbus_g_connection_unref(connection_); | |
175 } | |
176 if (context_) | |
177 g_main_context_unref(context_); | |
178 | |
179 DCHECK(!error_) << "Missing a call to CheckError() to clear |error_|"; | |
180 } | 93 } |
181 | 94 |
182 bool NetworkManagerWlanApi::Init() { | 95 bool NetworkManagerWlanApi::Init() { |
183 // Chrome DLL init code handles initializing the thread system, so rather than | 96 dbus::Bus::Options options; |
184 // get caught up with that nonsense here, lets just assert our requirement. | 97 options.bus_type = dbus::Bus::SYSTEM; |
185 CHECK(g_thread_supported()); | 98 return InitWithBus(new dbus::Bus(options)); |
99 } | |
186 | 100 |
187 // We require a private bus to ensure that we don't interfere with the | 101 bool NetworkManagerWlanApi::InitWithBus(dbus::Bus* bus) { |
188 // default loop on the main thread. Unforunately this functionality is only | 102 system_bus_ = bus; |
189 // available in dbus-glib-0.84 and later. We do a dynamic symbol lookup | 103 // system_bus_ will own all object proxies created from the bus. |
190 // to determine if dbus_g_bus_get_private is available. See bug | 104 network_manager_proxy_ = |
191 // http://code.google.com/p/chromium/issues/detail?id=59913 for more | 105 system_bus_->GetObjectProxy(kNetworkManagerServiceName, |
192 // information. | 106 kNetworkManagerPath); |
193 ScopedDLHandle handle(dlopen(NULL, RTLD_LAZY)); | |
194 if (!handle.get()) | |
195 return false; | |
196 | |
197 DBusGBusGetPrivateFunc *my_dbus_g_bus_get_private = | |
198 (DBusGBusGetPrivateFunc *) dlsym(handle.get(), "dbus_g_bus_get_private"); | |
199 | |
200 if (!my_dbus_g_bus_get_private) { | |
201 LOG(ERROR) << "We need dbus-glib >= 0.84 for wifi geolocation."; | |
202 return false; | |
203 } | |
204 // Get a private connection to the session bus. | |
205 context_ = g_main_context_new(); | |
206 DCHECK(context_); | |
207 connection_ = my_dbus_g_bus_get_private(DBUS_BUS_SYSTEM, context_, &error_); | |
208 | |
209 if (CheckError()) | |
210 return false; | |
211 DCHECK(connection_); | |
212 | |
213 // Disable timers on the connection since we don't need them and | |
214 // we're not going to run them anyway as the connection is associated | |
215 // with a private context. See bug http://crbug.com/40803 | |
216 dbus_bool_t ok = dbus_connection_set_timeout_functions( | |
217 dbus_g_connection_get_connection(connection_), | |
218 NULL, NULL, NULL, NULL, NULL); | |
219 DCHECK(ok); | |
220 | |
221 proxy_.reset(dbus_g_proxy_new_for_name(connection_, | |
222 kNetworkManagerServiceName, | |
223 kNetworkManagerPath, | |
224 kNetworkManagerInterface)); | |
225 DCHECK(proxy_.get()); | |
226 | |
227 // Validate the proxy object by checking we can enumerate devices. | 107 // Validate the proxy object by checking we can enumerate devices. |
228 ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); | 108 std::vector<std::string> adapter_paths; |
229 return !!device_list.get(); | 109 const bool success = GetAdapterDeviceList(&adapter_paths); |
110 VLOG(1) << "Init() result: " << success; | |
111 return success; | |
230 } | 112 } |
231 | 113 |
232 bool NetworkManagerWlanApi::GetAccessPointData( | 114 bool NetworkManagerWlanApi::GetAccessPointData( |
233 WifiData::AccessPointDataSet* data) { | 115 WifiData::AccessPointDataSet* data) { |
234 ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); | 116 std::vector<std::string> device_paths; |
235 if (device_list == NULL) { | 117 if (!GetAdapterDeviceList(&device_paths)) { |
236 DLOG(WARNING) << "Could not enumerate access points"; | 118 LOG(WARNING) << "Could not enumerate access points"; |
237 return false; | 119 return false; |
238 } | 120 } |
239 int success_count = 0; | 121 int success_count = 0; |
240 int fail_count = 0; | 122 int fail_count = 0; |
241 | 123 |
242 // Iterate the devices, getting APs for each wireless adapter found | 124 // Iterate the devices, getting APs for each wireless adapter found |
243 for (guint i = 0; i < device_list->len; i++) { | 125 for (size_t i = 0; i < device_paths.size(); ++i) { |
244 const gchar* device_path = | 126 const std::string& device_path = device_paths[i]; |
245 reinterpret_cast<const gchar*>(g_ptr_array_index(device_list, i)); | 127 VLOG(1) << "Checking device: " << device_path; |
246 | 128 |
247 ScopedDBusGProxyPtr device_properties_proxy(dbus_g_proxy_new_from_proxy( | 129 dbus::ObjectProxy* device_proxy = |
248 proxy_.get(), DBUS_INTERFACE_PROPERTIES, device_path)); | 130 system_bus_->GetObjectProxy(kNetworkManagerServiceName, |
249 ScopedGValue device_type_g_value; | 131 device_path); |
250 dbus_g_proxy_call(device_properties_proxy.get(), "Get", &error_, | |
251 G_TYPE_STRING, "org.freedesktop.NetworkManager.Device", | |
252 G_TYPE_STRING, "DeviceType", | |
253 G_TYPE_INVALID, | |
254 G_TYPE_VALUE, &device_type_g_value.v, | |
255 G_TYPE_INVALID); | |
256 if (CheckError()) | |
257 continue; | |
258 | 132 |
259 const guint device_type = g_value_get_uint(&device_type_g_value.v); | 133 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get"); |
134 dbus::MessageWriter builder(&method_call); | |
135 builder.AppendString("org.freedesktop.NetworkManager.Device"); | |
136 builder.AppendString("DeviceType"); | |
137 scoped_ptr<dbus::Response> response( | |
138 device_proxy->CallMethodAndBlock( | |
139 &method_call, | |
140 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); | |
141 if (!response.get()) { | |
142 LOG(WARNING) << "Failed to get the device type for " << device_path; | |
143 continue; // Check the next device. | |
144 } | |
145 dbus::MessageReader reader(response.get()); | |
146 uint32 device_type = 0; | |
147 if (!reader.PopVariantOfUint32(&device_type)) { | |
148 LOG(WARNING) << "Unexpected response for " << device_type << ": " | |
149 << response->ToString(); | |
150 continue; // Check the next device. | |
151 } | |
152 VLOG(1) << "Device type: " << device_type; | |
260 | 153 |
261 if (device_type == NM_DEVICE_TYPE_WIFI) { // Found a wlan adapter | 154 if (device_type == NM_DEVICE_TYPE_WIFI) { // Found a wlan adapter |
262 if (GetAccessPointsForAdapter(device_path, data)) | 155 if (GetAccessPointsForAdapter(device_path, data)) |
263 ++success_count; | 156 ++success_count; |
264 else | 157 else |
265 ++fail_count; | 158 ++fail_count; |
266 } | 159 } |
267 } | 160 } |
268 // At least one successfull scan overrides any other adapter reporting error. | 161 // At least one successfull scan overrides any other adapter reporting error. |
269 return success_count || fail_count == 0; | 162 return success_count || fail_count == 0; |
270 } | 163 } |
271 | 164 |
272 bool NetworkManagerWlanApi::CheckError() { | 165 bool NetworkManagerWlanApi::GetAdapterDeviceList( |
273 if (error_) { | 166 std::vector<std::string>* device_paths) { |
274 LOG(ERROR) << "Failed to complete NetworkManager call: " << error_->message; | 167 dbus::MethodCall method_call(kNetworkManagerInterface, "GetDevices"); |
275 g_error_free(error_); | 168 scoped_ptr<dbus::Response> response( |
276 error_ = NULL; | 169 network_manager_proxy_->CallMethodAndBlock( |
277 return true; | 170 &method_call, |
171 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); | |
172 if (!response.get()) { | |
173 LOG(WARNING) << "Failed to get the device list"; | |
174 return false; | |
278 } | 175 } |
279 return false; | 176 |
177 dbus::MessageReader reader(response.get()); | |
178 if (!reader.PopArrayOfObjectPaths(device_paths)) { | |
179 LOG(WARNING) << "Unexpected response: " << response->ToString(); | |
180 return false; | |
181 } | |
182 return true; | |
280 } | 183 } |
281 | 184 |
282 GPtrArray* NetworkManagerWlanApi::GetAdapterDeviceList() { | |
283 GPtrArray* device_list = NULL; | |
284 dbus_g_proxy_call(proxy_.get(), "GetDevices", &error_, | |
285 G_TYPE_INVALID, | |
286 dbus_g_type_get_collection("GPtrArray", | |
287 DBUS_TYPE_G_OBJECT_PATH), | |
288 &device_list, | |
289 G_TYPE_INVALID); | |
290 if (CheckError()) | |
291 return NULL; | |
292 return device_list; | |
293 } | |
294 | 185 |
295 bool NetworkManagerWlanApi::GetAccessPointsForAdapter( | 186 bool NetworkManagerWlanApi::GetAccessPointsForAdapter( |
296 const gchar* adapter_path, WifiData::AccessPointDataSet* data) { | 187 const std::string& adapter_path, WifiData::AccessPointDataSet* data) { |
297 DCHECK(proxy_.get()); | |
298 | |
299 // Create a proxy object for this wifi adapter, and ask it to do a scan | 188 // Create a proxy object for this wifi adapter, and ask it to do a scan |
300 // (or at least, dump its scan results). | 189 // (or at least, dump its scan results). |
301 ScopedDBusGProxyPtr wifi_adapter_proxy(dbus_g_proxy_new_from_proxy( | 190 dbus::ObjectProxy* device_proxy = |
302 proxy_.get(), "org.freedesktop.NetworkManager.Device.Wireless", | 191 system_bus_->GetObjectProxy(kNetworkManagerServiceName, |
303 adapter_path)); | 192 adapter_path); |
193 dbus::MethodCall method_call( | |
194 "org.freedesktop.NetworkManager.Device.Wireless", | |
195 "GetAccessPoints"); | |
196 scoped_ptr<dbus::Response> response( | |
197 device_proxy->CallMethodAndBlock( | |
198 &method_call, | |
199 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); | |
200 if (!response.get()) { | |
201 LOG(WARNING) << "Failed to get access points data for " << adapter_path; | |
202 return false; | |
203 } | |
204 dbus::MessageReader reader(response.get()); | |
205 std::vector<std::string> access_point_paths; | |
206 if (!reader.PopArrayOfObjectPaths(&access_point_paths)) { | |
207 LOG(WARNING) << "Unexpected response for " << adapter_path << ": " | |
208 << response->ToString(); | |
209 return false; | |
210 } | |
304 | 211 |
305 GPtrArray* ap_list_raw = NULL; | 212 VLOG(1) << "Wireless adapter " << adapter_path << " found " |
306 // Enumerate the access points for this adapter. | 213 << access_point_paths.size() << " access points."; |
307 dbus_g_proxy_call(wifi_adapter_proxy.get(), "GetAccessPoints", &error_, | |
308 G_TYPE_INVALID, | |
309 dbus_g_type_get_collection("GPtrArray", | |
310 DBUS_TYPE_G_OBJECT_PATH), | |
311 &ap_list_raw, | |
312 G_TYPE_INVALID); | |
313 ScopedGPtrArrayPtr ap_list(ap_list_raw); // Takes ownership. | |
314 ap_list_raw = NULL; | |
315 | 214 |
316 if (CheckError()) | 215 for (size_t i = 0; i < access_point_paths.size(); ++i) { |
317 return false; | 216 const std::string& access_point_path = access_point_paths[i]; |
217 VLOG(1) << "Checking access point: " << access_point_path; | |
318 | 218 |
319 DVLOG(1) << "Wireless adapter " << adapter_path << " found " << ap_list->len | 219 dbus::ObjectProxy* access_point_proxy = |
320 << " access points."; | 220 system_bus_->GetObjectProxy(kNetworkManagerServiceName, |
321 | 221 access_point_path); |
322 for (guint i = 0; i < ap_list->len; i++) { | |
323 const gchar* ap_path = | |
324 reinterpret_cast<const gchar*>(g_ptr_array_index(ap_list, i)); | |
325 ScopedDBusGProxyPtr access_point_proxy(dbus_g_proxy_new_from_proxy( | |
326 proxy_.get(), DBUS_INTERFACE_PROPERTIES, ap_path)); | |
327 | 222 |
328 AccessPointData access_point_data; | 223 AccessPointData access_point_data; |
329 { // Read SSID. | 224 { |
330 ScopedGValue ssid_g_value; | 225 scoped_ptr<dbus::Response> response( |
331 if (!GetAccessPointProperty(access_point_proxy.get(), "Ssid", | 226 GetAccessPointProperty(access_point_proxy, "Ssid")); |
332 G_TYPE_BOXED, &ssid_g_value.v)) | 227 if (!response.get()) |
333 continue; | 228 continue; |
334 const GArray* ssid = | 229 // The response should contain a variant that contains an array of bytes. |
335 reinterpret_cast<const GArray*>(g_value_get_boxed(&ssid_g_value.v)); | 230 dbus::MessageReader reader(response.get()); |
336 UTF8ToUTF16(ssid->data, ssid->len, &access_point_data.ssid); | 231 dbus::MessageReader variant_reader(response.get()); |
232 if (!reader.PopVariant(&variant_reader)) { | |
233 LOG(WARNING) << "Unexpected response for " << access_point_path << ": " | |
234 << response->ToString(); | |
235 continue; | |
236 } | |
237 uint8* ssid_bytes = NULL; | |
238 size_t ssid_length = 0; | |
239 if (!variant_reader.PopArrayOfBytes(&ssid_bytes, &ssid_length)) { | |
240 LOG(WARNING) << "Unexpected response for " << access_point_path << ": " | |
241 << response->ToString(); | |
242 continue; | |
243 } | |
244 std::string ssid(ssid_bytes, ssid_bytes + ssid_length); | |
245 access_point_data.ssid = UTF8ToUTF16(ssid); | |
337 } | 246 } |
338 | 247 |
339 { // Read the mac address | 248 { // Read the mac address |
340 ScopedGValue mac_g_value; | 249 scoped_ptr<dbus::Response> response( |
341 if (!GetAccessPointProperty(access_point_proxy.get(), "HwAddress", | 250 GetAccessPointProperty(access_point_proxy, "HwAddress")); |
342 G_TYPE_STRING, &mac_g_value.v)) | 251 if (!response.get()) |
343 continue; | 252 continue; |
344 std::string mac = g_value_get_string(&mac_g_value.v); | 253 dbus::MessageReader reader(response.get()); |
254 std::string mac; | |
255 if (!reader.PopVariantOfString(&mac)) { | |
256 LOG(WARNING) << "Unexpected response for " << access_point_path << ": " | |
257 << response->ToString(); | |
258 continue; | |
259 } | |
260 | |
345 ReplaceSubstringsAfterOffset(&mac, 0U, ":", ""); | 261 ReplaceSubstringsAfterOffset(&mac, 0U, ":", ""); |
346 std::vector<uint8> mac_bytes; | 262 std::vector<uint8> mac_bytes; |
347 if (!base::HexStringToBytes(mac, &mac_bytes) || mac_bytes.size() != 6) { | 263 if (!base::HexStringToBytes(mac, &mac_bytes) || mac_bytes.size() != 6) { |
348 DLOG(WARNING) << "Can't parse mac address (found " << mac_bytes.size() | 264 LOG(WARNING) << "Can't parse mac address (found " << mac_bytes.size() |
349 << " bytes) so using raw string: " << mac; | 265 << " bytes) so using raw string: " << mac; |
350 access_point_data.mac_address = UTF8ToUTF16(mac); | 266 access_point_data.mac_address = UTF8ToUTF16(mac); |
351 } else { | 267 } else { |
352 access_point_data.mac_address = MacAddressAsString16(&mac_bytes[0]); | 268 access_point_data.mac_address = MacAddressAsString16(&mac_bytes[0]); |
353 } | 269 } |
354 } | 270 } |
355 | 271 |
356 { // Read signal strength. | 272 { // Read signal strength. |
357 ScopedGValue signal_g_value; | 273 scoped_ptr<dbus::Response> response( |
358 if (!GetAccessPointProperty(access_point_proxy.get(), "Strength", | 274 GetAccessPointProperty(access_point_proxy, "Strength")); |
359 G_TYPE_UCHAR, &signal_g_value.v)) | 275 if (!response.get()) |
360 continue; | 276 continue; |
277 dbus::MessageReader reader(response.get()); | |
278 uint8 strength = 0; | |
279 if (!reader.PopVariantOfByte(&strength)) { | |
280 LOG(WARNING) << "Unexpected response for " << access_point_path << ": " | |
281 << response->ToString(); | |
282 continue; | |
283 } | |
361 // Convert strength as a percentage into dBs. | 284 // Convert strength as a percentage into dBs. |
362 access_point_data.radio_signal_strength = | 285 access_point_data.radio_signal_strength = -100 + strength / 2; |
363 -100 + g_value_get_uchar(&signal_g_value.v) / 2; | |
364 } | 286 } |
365 | 287 |
366 { // Read the channel | 288 { // Read the channel |
367 ScopedGValue freq_g_value; | 289 scoped_ptr<dbus::Response> response( |
368 if (!GetAccessPointProperty(access_point_proxy.get(), "Frequency", | 290 GetAccessPointProperty(access_point_proxy, "Frequency")); |
369 G_TYPE_UINT, &freq_g_value.v)) | 291 if (!response.get()) |
370 continue; | 292 continue; |
293 dbus::MessageReader reader(response.get()); | |
294 uint32 frequency = 0; | |
295 if (!reader.PopVariantOfUint32(&frequency)) { | |
296 LOG(WARNING) << "Unexpected response for " << access_point_path << ": " | |
297 << response->ToString(); | |
298 continue; | |
299 } | |
300 | |
371 // NetworkManager returns frequency in MHz. | 301 // NetworkManager returns frequency in MHz. |
372 access_point_data.channel = | 302 access_point_data.channel = |
373 frquency_in_khz_to_channel(g_value_get_uint(&freq_g_value.v) * 1000); | 303 frquency_in_khz_to_channel(frequency * 1000); |
374 } | 304 } |
305 VLOG(1) << "Access point data of " << access_point_path << ": " | |
306 << "SSID: " << access_point_data.ssid << ", " | |
307 << "MAC: " << access_point_data.mac_address << ", " | |
308 << "Strength: " << access_point_data.radio_signal_strength << ", " | |
309 << "Channel: " << access_point_data.channel; | |
310 | |
375 data->insert(access_point_data); | 311 data->insert(access_point_data); |
376 } | 312 } |
377 return true; | 313 return true; |
378 } | 314 } |
379 | 315 |
380 bool NetworkManagerWlanApi::GetAccessPointProperty(DBusGProxy* proxy, | 316 dbus::Response* NetworkManagerWlanApi::GetAccessPointProperty( |
381 const char* property_name, | 317 dbus::ObjectProxy* access_point_proxy, |
382 int expected_gvalue_type, | 318 const std::string& property_name) { |
383 GValue* value_out) { | 319 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get"); |
384 dbus_g_proxy_call(proxy, "Get", &error_, | 320 dbus::MessageWriter builder(&method_call); |
385 G_TYPE_STRING, "org.freedesktop.NetworkManager.AccessPoint", | 321 builder.AppendString("org.freedesktop.NetworkManager.AccessPoint"); |
386 G_TYPE_STRING, property_name, | 322 builder.AppendString(property_name); |
387 G_TYPE_INVALID, | 323 dbus::Response* response = access_point_proxy->CallMethodAndBlock( |
388 G_TYPE_VALUE, value_out, | 324 &method_call, |
389 G_TYPE_INVALID); | 325 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); |
390 if (CheckError()) | 326 if (!response) { |
391 return false; | 327 LOG(WARNING) << "Failed to get property for " << property_name; |
392 if (!G_VALUE_HOLDS(value_out, expected_gvalue_type)) { | |
393 DLOG(WARNING) << "Property " << property_name << " unexptected type " | |
394 << G_VALUE_TYPE(value_out); | |
395 return false; | |
396 } | 328 } |
397 return true; | 329 return response; |
398 } | 330 } |
399 | 331 |
400 } // namespace | 332 } // namespace |
401 | 333 |
402 // static | 334 // static |
403 template<> | 335 template<> |
404 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() { | 336 WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() { |
405 return new WifiDataProviderLinux(); | 337 return new WifiDataProviderLinux(); |
406 } | 338 } |
407 | 339 |
(...skipping 10 matching lines...) Expand all Loading... | |
418 return wlan_api.release(); | 350 return wlan_api.release(); |
419 return NULL; | 351 return NULL; |
420 } | 352 } |
421 | 353 |
422 PollingPolicyInterface* WifiDataProviderLinux::NewPollingPolicy() { | 354 PollingPolicyInterface* WifiDataProviderLinux::NewPollingPolicy() { |
423 return new GenericPollingPolicy<kDefaultPollingIntervalMilliseconds, | 355 return new GenericPollingPolicy<kDefaultPollingIntervalMilliseconds, |
424 kNoChangePollingIntervalMilliseconds, | 356 kNoChangePollingIntervalMilliseconds, |
425 kTwoNoChangePollingIntervalMilliseconds, | 357 kTwoNoChangePollingIntervalMilliseconds, |
426 kNoWifiPollingIntervalMilliseconds>; | 358 kNoWifiPollingIntervalMilliseconds>; |
427 } | 359 } |
360 | |
361 WifiDataProviderCommon::WlanApiInterface* | |
362 WifiDataProviderLinux::NewWlanApiForTesting(dbus::Bus* bus) { | |
363 scoped_ptr<NetworkManagerWlanApi> wlan_api(new NetworkManagerWlanApi); | |
364 if (wlan_api->InitWithBus(bus)) | |
365 return wlan_api.release(); | |
366 return NULL; | |
367 } | |
OLD | NEW |