1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/wifi/nsWifiScannerDBus.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,339 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsWifiScannerDBus.h" 1.9 +#include "nsWifiAccessPoint.h" 1.10 + 1.11 +namespace mozilla { 1.12 + 1.13 +nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint> *aAccessPoints) 1.14 +: mAccessPoints(aAccessPoints) 1.15 +{ 1.16 + MOZ_ASSERT(mAccessPoints); 1.17 + 1.18 + mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr); 1.19 + MOZ_ASSERT(mConnection); 1.20 + dbus_connection_set_exit_on_disconnect(mConnection, false); 1.21 + 1.22 + MOZ_COUNT_CTOR(nsWifiScannerDBus); 1.23 +} 1.24 + 1.25 +nsWifiScannerDBus::~nsWifiScannerDBus() 1.26 +{ 1.27 + if (!mConnection) { 1.28 + dbus_connection_unref(mConnection); 1.29 + } 1.30 + MOZ_COUNT_DTOR(nsWifiScannerDBus); 1.31 +} 1.32 + 1.33 +nsresult 1.34 +nsWifiScannerDBus::Scan() 1.35 +{ 1.36 + return SendMessage("org.freedesktop.NetworkManager", 1.37 + "/org/freedesktop/NetworkManager", 1.38 + "GetDevices"); 1.39 +} 1.40 + 1.41 +nsresult 1.42 +nsWifiScannerDBus::SendMessage(const char* aInterface, 1.43 + const char* aPath, 1.44 + const char* aFuncCall) 1.45 +{ 1.46 + DBusMessage* msg = 1.47 + dbus_message_new_method_call("org.freedesktop.NetworkManager", 1.48 + aPath, aInterface, aFuncCall); 1.49 + if (!msg) { 1.50 + return NS_ERROR_FAILURE; 1.51 + } 1.52 + 1.53 + DBusMessageIter argsIter; 1.54 + dbus_message_iter_init_append(msg, &argsIter); 1.55 + 1.56 + if (!strcmp(aFuncCall, "Get")) { 1.57 + const char* paramInterface = "org.freedesktop.NetworkManager.Device"; 1.58 + if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, 1.59 + ¶mInterface)) { 1.60 + return NS_ERROR_FAILURE; 1.61 + } 1.62 + 1.63 + const char* paramDeviceType = "DeviceType"; 1.64 + if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, 1.65 + ¶mDeviceType)) { 1.66 + return NS_ERROR_FAILURE; 1.67 + } 1.68 + } else if (!strcmp(aFuncCall, "GetAll")) { 1.69 + const char* param = ""; 1.70 + if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, ¶m)) { 1.71 + return NS_ERROR_FAILURE; 1.72 + } 1.73 + } 1.74 + 1.75 + DBusError err; 1.76 + dbus_error_init(&err); 1.77 + 1.78 + // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html 1.79 + // Refer to function dbus_connection_send_with_reply_and_block. 1.80 + const uint32_t DBUS_DEFAULT_TIMEOUT = -1; 1.81 + DBusMessage* reply = nullptr; 1.82 + reply = dbus_connection_send_with_reply_and_block(mConnection, msg, 1.83 + DBUS_DEFAULT_TIMEOUT, &err); 1.84 + if (dbus_error_is_set(&err)) { 1.85 + dbus_error_free(&err); 1.86 + 1.87 + // In the GetAccessPoints case, if there are no access points, error is set. 1.88 + // We don't want to error out here. 1.89 + if (!strcmp(aFuncCall, "GetAccessPoints")) { 1.90 + return NS_OK; 1.91 + } 1.92 + return NS_ERROR_FAILURE; 1.93 + } 1.94 + 1.95 + nsresult rv; 1.96 + if (!strcmp(aFuncCall, "GetDevices")) { 1.97 + rv = IdentifyDevices(reply); 1.98 + } else if (!strcmp(aFuncCall, "Get")) { 1.99 + rv = IdentifyDeviceType(reply, aPath); 1.100 + } else if (!strcmp(aFuncCall, "GetAccessPoints")) { 1.101 + rv = IdentifyAccessPoints(reply); 1.102 + } else if (!strcmp(aFuncCall, "GetAll")) { 1.103 + rv = IdentifyAPProperties(reply); 1.104 + } else { 1.105 + rv = NS_ERROR_FAILURE; 1.106 + } 1.107 + dbus_message_unref(reply); 1.108 + return rv; 1.109 +} 1.110 + 1.111 +nsresult 1.112 +nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg) 1.113 +{ 1.114 + DBusMessageIter iter; 1.115 + nsresult rv = GetDBusIterator(aMsg, &iter); 1.116 + NS_ENSURE_SUCCESS(rv, rv); 1.117 + 1.118 + const char* devicePath; 1.119 + do { 1.120 + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { 1.121 + return NS_ERROR_FAILURE; 1.122 + } 1.123 + 1.124 + dbus_message_iter_get_basic(&iter, &devicePath); 1.125 + if (!devicePath) { 1.126 + return NS_ERROR_FAILURE; 1.127 + } 1.128 + 1.129 + rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get"); 1.130 + NS_ENSURE_SUCCESS(rv, rv); 1.131 + } while (dbus_message_iter_next(&iter)); 1.132 + 1.133 + return NS_OK; 1.134 +} 1.135 + 1.136 +nsresult 1.137 +nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath) 1.138 +{ 1.139 + DBusMessageIter args; 1.140 + if (!dbus_message_iter_init(aMsg, &args)) { 1.141 + return NS_ERROR_FAILURE; 1.142 + } 1.143 + 1.144 + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { 1.145 + return NS_ERROR_FAILURE; 1.146 + } 1.147 + 1.148 + DBusMessageIter variantIter; 1.149 + dbus_message_iter_recurse(&args, &variantIter); 1.150 + if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) { 1.151 + return NS_ERROR_FAILURE; 1.152 + } 1.153 + 1.154 + uint32_t deviceType; 1.155 + dbus_message_iter_get_basic(&variantIter, &deviceType); 1.156 + 1.157 + // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html 1.158 + // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE. 1.159 + const uint32_t NM_DEVICE_TYPE_WIFI = 2; 1.160 + nsresult rv = NS_OK; 1.161 + if (deviceType == NM_DEVICE_TYPE_WIFI) { 1.162 + rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless", 1.163 + aDevicePath, "GetAccessPoints"); 1.164 + } 1.165 + 1.166 + return rv; 1.167 +} 1.168 + 1.169 +nsresult 1.170 +nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg) 1.171 +{ 1.172 + DBusMessageIter iter; 1.173 + nsresult rv = GetDBusIterator(aMsg, &iter); 1.174 + NS_ENSURE_SUCCESS(rv, rv); 1.175 + 1.176 + const char* path; 1.177 + do { 1.178 + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { 1.179 + return NS_ERROR_FAILURE; 1.180 + } 1.181 + dbus_message_iter_get_basic(&iter, &path); 1.182 + if (!path) { 1.183 + return NS_ERROR_FAILURE; 1.184 + } 1.185 + 1.186 + rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll"); 1.187 + NS_ENSURE_SUCCESS(rv, rv); 1.188 + } while (dbus_message_iter_next(&iter)); 1.189 + 1.190 + return NS_OK; 1.191 +} 1.192 + 1.193 +nsresult 1.194 +nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg) 1.195 +{ 1.196 + DBusMessageIter arr; 1.197 + nsresult rv = GetDBusIterator(aMsg, &arr); 1.198 + NS_ENSURE_SUCCESS(rv, rv); 1.199 + 1.200 + nsRefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint(); 1.201 + do { 1.202 + DBusMessageIter dict; 1.203 + dbus_message_iter_recurse(&arr, &dict); 1.204 + 1.205 + do { 1.206 + const char* key; 1.207 + dbus_message_iter_get_basic(&dict, &key); 1.208 + if (!key) { 1.209 + return NS_ERROR_FAILURE; 1.210 + } 1.211 + dbus_message_iter_next(&dict); 1.212 + 1.213 + DBusMessageIter variant; 1.214 + dbus_message_iter_recurse(&dict, &variant); 1.215 + 1.216 + if (!strncmp(key, "Ssid", strlen("Ssid"))) { 1.217 + nsresult rv = StoreSsid(&variant, ap); 1.218 + NS_ENSURE_SUCCESS(rv, rv); 1.219 + break; 1.220 + } 1.221 + 1.222 + if (!strncmp(key, "HwAddress", strlen("HwAddress"))) { 1.223 + nsresult rv = SetMac(&variant, ap); 1.224 + NS_ENSURE_SUCCESS(rv, rv); 1.225 + break; 1.226 + } 1.227 + 1.228 + if (!strncmp(key, "Strength", strlen("Strength"))) { 1.229 + if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) { 1.230 + return NS_ERROR_FAILURE; 1.231 + } 1.232 + 1.233 + uint8_t strength; 1.234 + dbus_message_iter_get_basic(&variant, &strength); 1.235 + ap->setSignal(strength); 1.236 + } 1.237 + } while (dbus_message_iter_next(&dict)); 1.238 + } while (dbus_message_iter_next(&arr)); 1.239 + 1.240 + mAccessPoints->AppendObject(ap); 1.241 + return NS_OK; 1.242 +} 1.243 + 1.244 +nsresult 1.245 +nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) 1.246 +{ 1.247 + if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) { 1.248 + return NS_ERROR_FAILURE; 1.249 + } 1.250 + 1.251 + DBusMessageIter variantMember; 1.252 + dbus_message_iter_recurse(aVariant, &variantMember); 1.253 + 1.254 + const uint32_t MAX_SSID_LEN = 32; 1.255 + char ssid[MAX_SSID_LEN]; 1.256 + memset(ssid, '\0', ArrayLength(ssid)); 1.257 + uint32_t i = 0; 1.258 + do { 1.259 + if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) { 1.260 + return NS_ERROR_FAILURE; 1.261 + } 1.262 + 1.263 + dbus_message_iter_get_basic(&variantMember, &ssid[i]); 1.264 + i++; 1.265 + } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN); 1.266 + 1.267 + aAp->setSSID(ssid, i); 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +nsresult 1.272 +nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) 1.273 +{ 1.274 + if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) { 1.275 + return NS_ERROR_FAILURE; 1.276 + } 1.277 + 1.278 + // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format. 1.279 + char* hwAddress; 1.280 + dbus_message_iter_get_basic(aVariant, &hwAddress); 1.281 + if (!hwAddress) { 1.282 + return NS_ERROR_FAILURE; 1.283 + } 1.284 + 1.285 + const uint32_t MAC_LEN = 6; 1.286 + uint8_t macAddress[MAC_LEN]; 1.287 + char* token = strtok(hwAddress, ":"); 1.288 + for (uint32_t i = 0; i < ArrayLength(macAddress); i++) { 1.289 + if (!token) { 1.290 + return NS_ERROR_FAILURE; 1.291 + } 1.292 + macAddress[i] = strtoul(token, nullptr, 16); 1.293 + token = strtok(nullptr, ":"); 1.294 + } 1.295 + aAp->setMac(macAddress); 1.296 + return NS_OK; 1.297 +} 1.298 + 1.299 +nsresult 1.300 +nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg, 1.301 + DBusMessageIter* aIterArray) 1.302 +{ 1.303 + DBusMessageIter iter; 1.304 + if (!dbus_message_iter_init(aMsg, &iter)) { 1.305 + return NS_ERROR_FAILURE; 1.306 + } 1.307 + 1.308 + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 1.309 + return NS_ERROR_FAILURE; 1.310 + } 1.311 + 1.312 + dbus_message_iter_recurse(&iter, aIterArray); 1.313 + return NS_OK; 1.314 +} 1.315 + 1.316 +} // mozilla 1.317 + 1.318 +nsresult 1.319 +nsWifiMonitor::DoScan() 1.320 +{ 1.321 + nsCOMArray<nsWifiAccessPoint> accessPoints; 1.322 + mozilla::nsWifiScannerDBus wifiScanner(&accessPoints); 1.323 + nsCOMArray<nsWifiAccessPoint> lastAccessPoints; 1.324 + 1.325 + while (mKeepGoing) { 1.326 + accessPoints.Clear(); 1.327 + nsresult rv = wifiScanner.Scan(); 1.328 + NS_ENSURE_SUCCESS(rv, rv); 1.329 + bool accessPointsChanged = !AccessPointsEqual(accessPoints, 1.330 + lastAccessPoints); 1.331 + ReplaceArray(lastAccessPoints, accessPoints); 1.332 + 1.333 + rv = CallWifiListeners(lastAccessPoints, accessPointsChanged); 1.334 + NS_ENSURE_SUCCESS(rv, rv); 1.335 + 1.336 + LOG(("waiting on monitor\n")); 1.337 + mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor); 1.338 + mon.Wait(PR_SecondsToInterval(60)); 1.339 + } 1.340 + 1.341 + return NS_OK; 1.342 +}