|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "nsWifiScannerDBus.h" |
|
6 #include "nsWifiAccessPoint.h" |
|
7 |
|
8 namespace mozilla { |
|
9 |
|
10 nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint> *aAccessPoints) |
|
11 : mAccessPoints(aAccessPoints) |
|
12 { |
|
13 MOZ_ASSERT(mAccessPoints); |
|
14 |
|
15 mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr); |
|
16 MOZ_ASSERT(mConnection); |
|
17 dbus_connection_set_exit_on_disconnect(mConnection, false); |
|
18 |
|
19 MOZ_COUNT_CTOR(nsWifiScannerDBus); |
|
20 } |
|
21 |
|
22 nsWifiScannerDBus::~nsWifiScannerDBus() |
|
23 { |
|
24 if (!mConnection) { |
|
25 dbus_connection_unref(mConnection); |
|
26 } |
|
27 MOZ_COUNT_DTOR(nsWifiScannerDBus); |
|
28 } |
|
29 |
|
30 nsresult |
|
31 nsWifiScannerDBus::Scan() |
|
32 { |
|
33 return SendMessage("org.freedesktop.NetworkManager", |
|
34 "/org/freedesktop/NetworkManager", |
|
35 "GetDevices"); |
|
36 } |
|
37 |
|
38 nsresult |
|
39 nsWifiScannerDBus::SendMessage(const char* aInterface, |
|
40 const char* aPath, |
|
41 const char* aFuncCall) |
|
42 { |
|
43 DBusMessage* msg = |
|
44 dbus_message_new_method_call("org.freedesktop.NetworkManager", |
|
45 aPath, aInterface, aFuncCall); |
|
46 if (!msg) { |
|
47 return NS_ERROR_FAILURE; |
|
48 } |
|
49 |
|
50 DBusMessageIter argsIter; |
|
51 dbus_message_iter_init_append(msg, &argsIter); |
|
52 |
|
53 if (!strcmp(aFuncCall, "Get")) { |
|
54 const char* paramInterface = "org.freedesktop.NetworkManager.Device"; |
|
55 if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, |
|
56 ¶mInterface)) { |
|
57 return NS_ERROR_FAILURE; |
|
58 } |
|
59 |
|
60 const char* paramDeviceType = "DeviceType"; |
|
61 if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, |
|
62 ¶mDeviceType)) { |
|
63 return NS_ERROR_FAILURE; |
|
64 } |
|
65 } else if (!strcmp(aFuncCall, "GetAll")) { |
|
66 const char* param = ""; |
|
67 if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, ¶m)) { |
|
68 return NS_ERROR_FAILURE; |
|
69 } |
|
70 } |
|
71 |
|
72 DBusError err; |
|
73 dbus_error_init(&err); |
|
74 |
|
75 // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html |
|
76 // Refer to function dbus_connection_send_with_reply_and_block. |
|
77 const uint32_t DBUS_DEFAULT_TIMEOUT = -1; |
|
78 DBusMessage* reply = nullptr; |
|
79 reply = dbus_connection_send_with_reply_and_block(mConnection, msg, |
|
80 DBUS_DEFAULT_TIMEOUT, &err); |
|
81 if (dbus_error_is_set(&err)) { |
|
82 dbus_error_free(&err); |
|
83 |
|
84 // In the GetAccessPoints case, if there are no access points, error is set. |
|
85 // We don't want to error out here. |
|
86 if (!strcmp(aFuncCall, "GetAccessPoints")) { |
|
87 return NS_OK; |
|
88 } |
|
89 return NS_ERROR_FAILURE; |
|
90 } |
|
91 |
|
92 nsresult rv; |
|
93 if (!strcmp(aFuncCall, "GetDevices")) { |
|
94 rv = IdentifyDevices(reply); |
|
95 } else if (!strcmp(aFuncCall, "Get")) { |
|
96 rv = IdentifyDeviceType(reply, aPath); |
|
97 } else if (!strcmp(aFuncCall, "GetAccessPoints")) { |
|
98 rv = IdentifyAccessPoints(reply); |
|
99 } else if (!strcmp(aFuncCall, "GetAll")) { |
|
100 rv = IdentifyAPProperties(reply); |
|
101 } else { |
|
102 rv = NS_ERROR_FAILURE; |
|
103 } |
|
104 dbus_message_unref(reply); |
|
105 return rv; |
|
106 } |
|
107 |
|
108 nsresult |
|
109 nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg) |
|
110 { |
|
111 DBusMessageIter iter; |
|
112 nsresult rv = GetDBusIterator(aMsg, &iter); |
|
113 NS_ENSURE_SUCCESS(rv, rv); |
|
114 |
|
115 const char* devicePath; |
|
116 do { |
|
117 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { |
|
118 return NS_ERROR_FAILURE; |
|
119 } |
|
120 |
|
121 dbus_message_iter_get_basic(&iter, &devicePath); |
|
122 if (!devicePath) { |
|
123 return NS_ERROR_FAILURE; |
|
124 } |
|
125 |
|
126 rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get"); |
|
127 NS_ENSURE_SUCCESS(rv, rv); |
|
128 } while (dbus_message_iter_next(&iter)); |
|
129 |
|
130 return NS_OK; |
|
131 } |
|
132 |
|
133 nsresult |
|
134 nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath) |
|
135 { |
|
136 DBusMessageIter args; |
|
137 if (!dbus_message_iter_init(aMsg, &args)) { |
|
138 return NS_ERROR_FAILURE; |
|
139 } |
|
140 |
|
141 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { |
|
142 return NS_ERROR_FAILURE; |
|
143 } |
|
144 |
|
145 DBusMessageIter variantIter; |
|
146 dbus_message_iter_recurse(&args, &variantIter); |
|
147 if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) { |
|
148 return NS_ERROR_FAILURE; |
|
149 } |
|
150 |
|
151 uint32_t deviceType; |
|
152 dbus_message_iter_get_basic(&variantIter, &deviceType); |
|
153 |
|
154 // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html |
|
155 // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE. |
|
156 const uint32_t NM_DEVICE_TYPE_WIFI = 2; |
|
157 nsresult rv = NS_OK; |
|
158 if (deviceType == NM_DEVICE_TYPE_WIFI) { |
|
159 rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless", |
|
160 aDevicePath, "GetAccessPoints"); |
|
161 } |
|
162 |
|
163 return rv; |
|
164 } |
|
165 |
|
166 nsresult |
|
167 nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg) |
|
168 { |
|
169 DBusMessageIter iter; |
|
170 nsresult rv = GetDBusIterator(aMsg, &iter); |
|
171 NS_ENSURE_SUCCESS(rv, rv); |
|
172 |
|
173 const char* path; |
|
174 do { |
|
175 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { |
|
176 return NS_ERROR_FAILURE; |
|
177 } |
|
178 dbus_message_iter_get_basic(&iter, &path); |
|
179 if (!path) { |
|
180 return NS_ERROR_FAILURE; |
|
181 } |
|
182 |
|
183 rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll"); |
|
184 NS_ENSURE_SUCCESS(rv, rv); |
|
185 } while (dbus_message_iter_next(&iter)); |
|
186 |
|
187 return NS_OK; |
|
188 } |
|
189 |
|
190 nsresult |
|
191 nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg) |
|
192 { |
|
193 DBusMessageIter arr; |
|
194 nsresult rv = GetDBusIterator(aMsg, &arr); |
|
195 NS_ENSURE_SUCCESS(rv, rv); |
|
196 |
|
197 nsRefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint(); |
|
198 do { |
|
199 DBusMessageIter dict; |
|
200 dbus_message_iter_recurse(&arr, &dict); |
|
201 |
|
202 do { |
|
203 const char* key; |
|
204 dbus_message_iter_get_basic(&dict, &key); |
|
205 if (!key) { |
|
206 return NS_ERROR_FAILURE; |
|
207 } |
|
208 dbus_message_iter_next(&dict); |
|
209 |
|
210 DBusMessageIter variant; |
|
211 dbus_message_iter_recurse(&dict, &variant); |
|
212 |
|
213 if (!strncmp(key, "Ssid", strlen("Ssid"))) { |
|
214 nsresult rv = StoreSsid(&variant, ap); |
|
215 NS_ENSURE_SUCCESS(rv, rv); |
|
216 break; |
|
217 } |
|
218 |
|
219 if (!strncmp(key, "HwAddress", strlen("HwAddress"))) { |
|
220 nsresult rv = SetMac(&variant, ap); |
|
221 NS_ENSURE_SUCCESS(rv, rv); |
|
222 break; |
|
223 } |
|
224 |
|
225 if (!strncmp(key, "Strength", strlen("Strength"))) { |
|
226 if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) { |
|
227 return NS_ERROR_FAILURE; |
|
228 } |
|
229 |
|
230 uint8_t strength; |
|
231 dbus_message_iter_get_basic(&variant, &strength); |
|
232 ap->setSignal(strength); |
|
233 } |
|
234 } while (dbus_message_iter_next(&dict)); |
|
235 } while (dbus_message_iter_next(&arr)); |
|
236 |
|
237 mAccessPoints->AppendObject(ap); |
|
238 return NS_OK; |
|
239 } |
|
240 |
|
241 nsresult |
|
242 nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) |
|
243 { |
|
244 if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) { |
|
245 return NS_ERROR_FAILURE; |
|
246 } |
|
247 |
|
248 DBusMessageIter variantMember; |
|
249 dbus_message_iter_recurse(aVariant, &variantMember); |
|
250 |
|
251 const uint32_t MAX_SSID_LEN = 32; |
|
252 char ssid[MAX_SSID_LEN]; |
|
253 memset(ssid, '\0', ArrayLength(ssid)); |
|
254 uint32_t i = 0; |
|
255 do { |
|
256 if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) { |
|
257 return NS_ERROR_FAILURE; |
|
258 } |
|
259 |
|
260 dbus_message_iter_get_basic(&variantMember, &ssid[i]); |
|
261 i++; |
|
262 } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN); |
|
263 |
|
264 aAp->setSSID(ssid, i); |
|
265 return NS_OK; |
|
266 } |
|
267 |
|
268 nsresult |
|
269 nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) |
|
270 { |
|
271 if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) { |
|
272 return NS_ERROR_FAILURE; |
|
273 } |
|
274 |
|
275 // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format. |
|
276 char* hwAddress; |
|
277 dbus_message_iter_get_basic(aVariant, &hwAddress); |
|
278 if (!hwAddress) { |
|
279 return NS_ERROR_FAILURE; |
|
280 } |
|
281 |
|
282 const uint32_t MAC_LEN = 6; |
|
283 uint8_t macAddress[MAC_LEN]; |
|
284 char* token = strtok(hwAddress, ":"); |
|
285 for (uint32_t i = 0; i < ArrayLength(macAddress); i++) { |
|
286 if (!token) { |
|
287 return NS_ERROR_FAILURE; |
|
288 } |
|
289 macAddress[i] = strtoul(token, nullptr, 16); |
|
290 token = strtok(nullptr, ":"); |
|
291 } |
|
292 aAp->setMac(macAddress); |
|
293 return NS_OK; |
|
294 } |
|
295 |
|
296 nsresult |
|
297 nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg, |
|
298 DBusMessageIter* aIterArray) |
|
299 { |
|
300 DBusMessageIter iter; |
|
301 if (!dbus_message_iter_init(aMsg, &iter)) { |
|
302 return NS_ERROR_FAILURE; |
|
303 } |
|
304 |
|
305 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { |
|
306 return NS_ERROR_FAILURE; |
|
307 } |
|
308 |
|
309 dbus_message_iter_recurse(&iter, aIterArray); |
|
310 return NS_OK; |
|
311 } |
|
312 |
|
313 } // mozilla |
|
314 |
|
315 nsresult |
|
316 nsWifiMonitor::DoScan() |
|
317 { |
|
318 nsCOMArray<nsWifiAccessPoint> accessPoints; |
|
319 mozilla::nsWifiScannerDBus wifiScanner(&accessPoints); |
|
320 nsCOMArray<nsWifiAccessPoint> lastAccessPoints; |
|
321 |
|
322 while (mKeepGoing) { |
|
323 accessPoints.Clear(); |
|
324 nsresult rv = wifiScanner.Scan(); |
|
325 NS_ENSURE_SUCCESS(rv, rv); |
|
326 bool accessPointsChanged = !AccessPointsEqual(accessPoints, |
|
327 lastAccessPoints); |
|
328 ReplaceArray(lastAccessPoints, accessPoints); |
|
329 |
|
330 rv = CallWifiListeners(lastAccessPoints, accessPointsChanged); |
|
331 NS_ENSURE_SUCCESS(rv, rv); |
|
332 |
|
333 LOG(("waiting on monitor\n")); |
|
334 mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor); |
|
335 mon.Wait(PR_SecondsToInterval(60)); |
|
336 } |
|
337 |
|
338 return NS_OK; |
|
339 } |