michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsWifiScannerDBus.h" michael@0: #include "nsWifiAccessPoint.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray *aAccessPoints) michael@0: : mAccessPoints(aAccessPoints) michael@0: { michael@0: MOZ_ASSERT(mAccessPoints); michael@0: michael@0: mConnection = dbus_bus_get(DBUS_BUS_SYSTEM, nullptr); michael@0: MOZ_ASSERT(mConnection); michael@0: dbus_connection_set_exit_on_disconnect(mConnection, false); michael@0: michael@0: MOZ_COUNT_CTOR(nsWifiScannerDBus); michael@0: } michael@0: michael@0: nsWifiScannerDBus::~nsWifiScannerDBus() michael@0: { michael@0: if (!mConnection) { michael@0: dbus_connection_unref(mConnection); michael@0: } michael@0: MOZ_COUNT_DTOR(nsWifiScannerDBus); michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::Scan() michael@0: { michael@0: return SendMessage("org.freedesktop.NetworkManager", michael@0: "/org/freedesktop/NetworkManager", michael@0: "GetDevices"); michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::SendMessage(const char* aInterface, michael@0: const char* aPath, michael@0: const char* aFuncCall) michael@0: { michael@0: DBusMessage* msg = michael@0: dbus_message_new_method_call("org.freedesktop.NetworkManager", michael@0: aPath, aInterface, aFuncCall); michael@0: if (!msg) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: DBusMessageIter argsIter; michael@0: dbus_message_iter_init_append(msg, &argsIter); michael@0: michael@0: if (!strcmp(aFuncCall, "Get")) { michael@0: const char* paramInterface = "org.freedesktop.NetworkManager.Device"; michael@0: if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, michael@0: ¶mInterface)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: const char* paramDeviceType = "DeviceType"; michael@0: if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, michael@0: ¶mDeviceType)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else if (!strcmp(aFuncCall, "GetAll")) { michael@0: const char* param = ""; michael@0: if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, ¶m)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: DBusError err; michael@0: dbus_error_init(&err); michael@0: michael@0: // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html michael@0: // Refer to function dbus_connection_send_with_reply_and_block. michael@0: const uint32_t DBUS_DEFAULT_TIMEOUT = -1; michael@0: DBusMessage* reply = nullptr; michael@0: reply = dbus_connection_send_with_reply_and_block(mConnection, msg, michael@0: DBUS_DEFAULT_TIMEOUT, &err); michael@0: if (dbus_error_is_set(&err)) { michael@0: dbus_error_free(&err); michael@0: michael@0: // In the GetAccessPoints case, if there are no access points, error is set. michael@0: // We don't want to error out here. michael@0: if (!strcmp(aFuncCall, "GetAccessPoints")) { michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult rv; michael@0: if (!strcmp(aFuncCall, "GetDevices")) { michael@0: rv = IdentifyDevices(reply); michael@0: } else if (!strcmp(aFuncCall, "Get")) { michael@0: rv = IdentifyDeviceType(reply, aPath); michael@0: } else if (!strcmp(aFuncCall, "GetAccessPoints")) { michael@0: rv = IdentifyAccessPoints(reply); michael@0: } else if (!strcmp(aFuncCall, "GetAll")) { michael@0: rv = IdentifyAPProperties(reply); michael@0: } else { michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: dbus_message_unref(reply); michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg) michael@0: { michael@0: DBusMessageIter iter; michael@0: nsresult rv = GetDBusIterator(aMsg, &iter); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: const char* devicePath; michael@0: do { michael@0: if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: dbus_message_iter_get_basic(&iter, &devicePath); michael@0: if (!devicePath) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get"); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } while (dbus_message_iter_next(&iter)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath) michael@0: { michael@0: DBusMessageIter args; michael@0: if (!dbus_message_iter_init(aMsg, &args)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: DBusMessageIter variantIter; michael@0: dbus_message_iter_recurse(&args, &variantIter); michael@0: if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: uint32_t deviceType; michael@0: dbus_message_iter_get_basic(&variantIter, &deviceType); michael@0: michael@0: // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html michael@0: // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE. michael@0: const uint32_t NM_DEVICE_TYPE_WIFI = 2; michael@0: nsresult rv = NS_OK; michael@0: if (deviceType == NM_DEVICE_TYPE_WIFI) { michael@0: rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless", michael@0: aDevicePath, "GetAccessPoints"); michael@0: } michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg) michael@0: { michael@0: DBusMessageIter iter; michael@0: nsresult rv = GetDBusIterator(aMsg, &iter); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: const char* path; michael@0: do { michael@0: if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: dbus_message_iter_get_basic(&iter, &path); michael@0: if (!path) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll"); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } while (dbus_message_iter_next(&iter)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg) michael@0: { michael@0: DBusMessageIter arr; michael@0: nsresult rv = GetDBusIterator(aMsg, &arr); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsRefPtr ap = new nsWifiAccessPoint(); michael@0: do { michael@0: DBusMessageIter dict; michael@0: dbus_message_iter_recurse(&arr, &dict); michael@0: michael@0: do { michael@0: const char* key; michael@0: dbus_message_iter_get_basic(&dict, &key); michael@0: if (!key) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: dbus_message_iter_next(&dict); michael@0: michael@0: DBusMessageIter variant; michael@0: dbus_message_iter_recurse(&dict, &variant); michael@0: michael@0: if (!strncmp(key, "Ssid", strlen("Ssid"))) { michael@0: nsresult rv = StoreSsid(&variant, ap); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: break; michael@0: } michael@0: michael@0: if (!strncmp(key, "HwAddress", strlen("HwAddress"))) { michael@0: nsresult rv = SetMac(&variant, ap); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: break; michael@0: } michael@0: michael@0: if (!strncmp(key, "Strength", strlen("Strength"))) { michael@0: if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: uint8_t strength; michael@0: dbus_message_iter_get_basic(&variant, &strength); michael@0: ap->setSignal(strength); michael@0: } michael@0: } while (dbus_message_iter_next(&dict)); michael@0: } while (dbus_message_iter_next(&arr)); michael@0: michael@0: mAccessPoints->AppendObject(ap); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) michael@0: { michael@0: if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: DBusMessageIter variantMember; michael@0: dbus_message_iter_recurse(aVariant, &variantMember); michael@0: michael@0: const uint32_t MAX_SSID_LEN = 32; michael@0: char ssid[MAX_SSID_LEN]; michael@0: memset(ssid, '\0', ArrayLength(ssid)); michael@0: uint32_t i = 0; michael@0: do { michael@0: if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: dbus_message_iter_get_basic(&variantMember, &ssid[i]); michael@0: i++; michael@0: } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN); michael@0: michael@0: aAp->setSSID(ssid, i); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp) michael@0: { michael@0: if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format. michael@0: char* hwAddress; michael@0: dbus_message_iter_get_basic(aVariant, &hwAddress); michael@0: if (!hwAddress) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: const uint32_t MAC_LEN = 6; michael@0: uint8_t macAddress[MAC_LEN]; michael@0: char* token = strtok(hwAddress, ":"); michael@0: for (uint32_t i = 0; i < ArrayLength(macAddress); i++) { michael@0: if (!token) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: macAddress[i] = strtoul(token, nullptr, 16); michael@0: token = strtok(nullptr, ":"); michael@0: } michael@0: aAp->setMac(macAddress); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg, michael@0: DBusMessageIter* aIterArray) michael@0: { michael@0: DBusMessageIter iter; michael@0: if (!dbus_message_iter_init(aMsg, &iter)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: dbus_message_iter_recurse(&iter, aIterArray); michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // mozilla michael@0: michael@0: nsresult michael@0: nsWifiMonitor::DoScan() michael@0: { michael@0: nsCOMArray accessPoints; michael@0: mozilla::nsWifiScannerDBus wifiScanner(&accessPoints); michael@0: nsCOMArray lastAccessPoints; michael@0: michael@0: while (mKeepGoing) { michael@0: accessPoints.Clear(); michael@0: nsresult rv = wifiScanner.Scan(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: bool accessPointsChanged = !AccessPointsEqual(accessPoints, michael@0: lastAccessPoints); michael@0: ReplaceArray(lastAccessPoints, accessPoints); michael@0: michael@0: rv = CallWifiListeners(lastAccessPoints, accessPointsChanged); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: LOG(("waiting on monitor\n")); michael@0: mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: mon.Wait(PR_SecondsToInterval(60)); michael@0: } michael@0: michael@0: return NS_OK; michael@0: }