Implementation of the Blackberry bearer engine.
authorRafael Roquetto <rafael.roquetto.qnx@kdab.com>
Mon, 7 May 2012 09:55:30 +0000 (11:55 +0200)
committerQt by Nokia <qt-info@nokia.com>
Thu, 24 May 2012 15:59:07 +0000 (17:59 +0200)
An implementation for Blackberry devices based on the BPS netstatus APIs.

Change-Id: I2c019efecb7296b6db626b626d4618ded4d3df37
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Nicolas Arnaud-Cormos <nicolas@kdab.com>
src/plugins/bearer/bearer.pro
src/plugins/bearer/blackberry/blackberry.json [new file with mode: 0644]
src/plugins/bearer/blackberry/blackberry.pro [new file with mode: 0644]
src/plugins/bearer/blackberry/main.cpp [new file with mode: 0644]
src/plugins/bearer/blackberry/qbbengine.cpp [new file with mode: 0644]
src/plugins/bearer/blackberry/qbbengine.h [new file with mode: 0644]

index 12b18ac..899eede 100644 (file)
@@ -7,6 +7,7 @@ linux*:contains(QT_CONFIG, dbus) {
 
 #win32:SUBDIRS += nla
 win32:SUBDIRS += generic
+blackberry:SUBDIRS += blackberry
 win32:!wince*:SUBDIRS += nativewifi
 macx:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan
 macx:SUBDIRS += generic
diff --git a/src/plugins/bearer/blackberry/blackberry.json b/src/plugins/bearer/blackberry/blackberry.json
new file mode 100644 (file)
index 0000000..233f05c
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "blackberry" ]
+}
diff --git a/src/plugins/bearer/blackberry/blackberry.pro b/src/plugins/bearer/blackberry/blackberry.pro
new file mode 100644 (file)
index 0000000..5d4cf29
--- /dev/null
@@ -0,0 +1,21 @@
+TARGET = qbbbearer
+load(qt_plugin)
+
+QT = core-private network-private
+
+# Uncomment this to enable debugging output for the plugin
+#DEFINES += QBBENGINE_DEBUG
+
+HEADERS += qbbengine.h \
+           ../qnetworksession_impl.h \
+           ../qbearerengine_impl.h
+
+SOURCES += qbbengine.cpp \
+           ../qnetworksession_impl.cpp \
+           main.cpp
+
+OTHER_FILES += blackberry.json
+
+DESTDIR = $$QT.network.plugins/bearer
+target.path += $$[QT_INSTALL_PLUGINS]/bearer
+INSTALLS += target
diff --git a/src/plugins/bearer/blackberry/main.cpp b/src/plugins/bearer/blackberry/main.cpp
new file mode 100644 (file)
index 0000000..d293e31
--- /dev/null
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbbengine.h"
+
+#include <QtNetwork/private/qbearerplugin_p.h>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+QT_BEGIN_NAMESPACE
+
+class QBBEnginePlugin : public QBearerEnginePlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QBearerEngineFactoryInterface" FILE "blackberry.json")
+
+public:
+    QStringList keys() const;
+    QBearerEngine *create(const QString &key) const;
+};
+
+QStringList QBBEnginePlugin::keys() const
+{
+    return QStringList() << QStringLiteral("blackberry");
+}
+
+QBearerEngine *QBBEnginePlugin::create(const QString &key) const
+{
+    if (key == QStringLiteral("blackberry"))
+        return new QBBEngine;
+
+    return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
+
+#endif // QT_NO_BEARERMANAGEMENT
diff --git a/src/plugins/bearer/blackberry/qbbengine.cpp b/src/plugins/bearer/blackberry/qbbengine.cpp
new file mode 100644 (file)
index 0000000..7f8abd0
--- /dev/null
@@ -0,0 +1,424 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbbengine.h"
+#include "../qnetworksession_impl.h"
+
+#include <QDebug>
+#include <QThreadStorage>
+#include <QStringList>
+
+#include <bps/netstatus.h>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+#ifdef QBBENGINE_DEBUG
+#define qBearerDebug qDebug
+#else
+#define qBearerDebug QT_NO_QDEBUG_MACRO
+#endif
+
+struct NetstatusInterfaceListCleanupHelper
+{
+    static inline void cleanup(netstatus_interface_list_t *list)
+    {
+        netstatus_free_interfaces(list);
+    }
+};
+
+struct NetstatusInterfaceCleanupHelper
+{
+    static inline void cleanup(char *interface)
+    {
+        bps_free(interface);
+    }
+};
+
+struct EngineInstanceHolder
+{
+    EngineInstanceHolder(QBBEngine *engine) :
+        instance(engine) {}
+
+    QBBEngine *instance;
+};
+
+Q_GLOBAL_STATIC(QThreadStorage<EngineInstanceHolder *>, instanceStorage);
+
+static QNetworkConfiguration::BearerType
+interfaceType(netstatus_interface_type_t type)
+{
+    switch (type) {
+    case NETSTATUS_INTERFACE_TYPE_USB:
+    case NETSTATUS_INTERFACE_TYPE_WIRED:
+        return QNetworkConfiguration::BearerEthernet;
+
+    case NETSTATUS_INTERFACE_TYPE_WIFI:
+        return QNetworkConfiguration::BearerWLAN;
+
+    case NETSTATUS_INTERFACE_TYPE_BLUETOOTH_DUN:
+        return QNetworkConfiguration::BearerBluetooth;
+
+    case NETSTATUS_INTERFACE_TYPE_CELLULAR:
+        //### TODO  not sure which BearerType would be the best
+        //to return here. We need to be able to get more
+        //information on the bearer type in order to return
+        //the exact match.
+        return QNetworkConfiguration::Bearer2G;
+
+    case NETSTATUS_INTERFACE_TYPE_VPN:
+    case NETSTATUS_INTERFACE_TYPE_BB:
+    case NETSTATUS_INTERFACE_TYPE_UNKNOWN:
+        break;
+    }
+
+    return QNetworkConfiguration::BearerUnknown;
+}
+
+static QString idForName(const QString &name)
+{
+    return QStringLiteral("bps:") + name;
+}
+
+QT_BEGIN_NAMESPACE
+
+
+QBBEngine::QBBEngine(QObject *parent) :
+    QBearerEngineImpl(parent),
+    previousEventFilter(0),
+    pollingRequired(false),
+    initialized(false)
+{
+}
+
+QBBEngine::~QBBEngine()
+{
+    QAbstractEventDispatcher::instance()->setEventFilter(previousEventFilter);
+}
+
+
+QString QBBEngine::getInterfaceFromId(const QString &id)
+{
+    const QMutexLocker locker(&mutex);
+
+    return configurationInterface.value(id);
+}
+
+bool QBBEngine::hasIdentifier(const QString &id)
+{
+    const QMutexLocker locker(&mutex);
+
+    return configurationInterface.contains(id);
+}
+
+void QBBEngine::connectToId(const QString &id)
+{
+    Q_EMIT connectionError(id, OperationNotSupported);
+}
+
+void QBBEngine::disconnectFromId(const QString &id)
+{
+    Q_EMIT connectionError(id, OperationNotSupported);
+}
+
+void QBBEngine::initialize()
+{
+    if (initialized) {
+        qWarning() << Q_FUNC_INFO << "called, but instance already initialized.";
+        return;
+    }
+
+    instanceStorage()->setLocalData(new EngineInstanceHolder(this));
+
+    if (netstatus_request_events(0) != BPS_SUCCESS) {
+        qWarning() << Q_FUNC_INFO << "cannot register for network events. Polling enabled.";
+
+        const QMutexLocker locker(&pollingMutex);
+        pollingRequired = true;
+    } else {
+        previousEventFilter =
+            QAbstractEventDispatcher::instance()->setEventFilter(filterEvent);
+    }
+
+    doRequestUpdate();
+}
+
+void QBBEngine::requestUpdate()
+{
+    doRequestUpdate();
+}
+
+void QBBEngine::doRequestUpdate()
+{
+    qBearerDebug() << Q_FUNC_INFO << "entered method";
+
+    netstatus_interface_list_t interfaceList;
+
+    if ((netstatus_get_interfaces(&interfaceList)) != BPS_SUCCESS) {
+        qBearerDebug() << Q_FUNC_INFO << "cannot retrieve interface list";
+        return;
+    }
+
+    const QScopedPointer<netstatus_interface_list_t,
+          NetstatusInterfaceListCleanupHelper> holder(&interfaceList);
+
+    QSet<QString> currentConfigurations;
+
+    for (int i = 0; i < interfaceList.num_interfaces; i++) {
+        const char *interface = interfaceList.interfaces[i];
+
+        qBearerDebug() << Q_FUNC_INFO << "discovered interface" << interface;
+
+        updateConfiguration(interface);
+
+        currentConfigurations << idForName(QString::fromLatin1(interface));
+    }
+
+    QMutexLocker locker(&mutex);
+
+    const QStringList keys = accessPointConfigurations.uniqueKeys();
+
+    locker.unlock();
+
+    Q_FOREACH (const QString &id, keys) {
+        if (!currentConfigurations.contains(id))
+            removeConfiguration(id);
+    }
+
+    Q_EMIT updateCompleted();
+}
+
+QNetworkSession::State QBBEngine::sessionStateForId(const QString &id)
+{
+    const QMutexLocker locker(&mutex);
+
+    QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
+
+    if (!ptr || !ptr->isValid)
+        return QNetworkSession::Invalid;
+
+    if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active)
+        return QNetworkSession::Connected;
+    else if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered)
+        return QNetworkSession::Disconnected;
+    else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined)
+        return QNetworkSession::NotAvailable;
+    else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined)
+        return QNetworkSession::NotAvailable;
+
+    return QNetworkSession::Invalid;
+}
+
+QNetworkConfigurationManager::Capabilities QBBEngine::capabilities() const
+{
+    return QNetworkConfigurationManager::ForcedRoaming;
+}
+
+QNetworkSessionPrivate *QBBEngine::createSessionBackend()
+{
+    return new QNetworkSessionPrivateImpl;
+}
+
+QNetworkConfigurationPrivatePointer QBBEngine::defaultConfiguration()
+{
+    char *interface = 0;
+
+    if (netstatus_get_default_interface(&interface) != BPS_SUCCESS)
+        return QNetworkConfigurationPrivatePointer();
+
+    if (!interface)
+        return QNetworkConfigurationPrivatePointer();
+
+    const QScopedPointer<char, NetstatusInterfaceCleanupHelper> holder(interface);
+
+    const QString id = idForName(QString::fromLatin1(interface));
+
+    const QMutexLocker locker(&mutex);
+
+    if (accessPointConfigurations.contains(id)) {
+        qBearerDebug() << Q_FUNC_INFO << "found default interface:" << id;
+
+        return accessPointConfigurations.value(id);
+    }
+
+    return QNetworkConfigurationPrivatePointer();
+}
+
+bool QBBEngine::requiresPolling() const
+{
+    const QMutexLocker locker(&pollingMutex);
+
+    return pollingRequired;
+}
+
+bool QBBEngine::filterEvent(void *message)
+{
+    bps_event_t * const event = static_cast<bps_event_t *>(message);
+
+    Q_ASSERT(event);
+
+    QBBEngine *self = instanceStorage()->localData()->instance;
+
+    Q_ASSERT(self);
+
+    if (bps_event_get_domain(event) == netstatus_get_domain())
+        self->filterEvent(event);
+
+    if (self->previousEventFilter)
+        return self->previousEventFilter(message);
+
+    return false;
+}
+
+void QBBEngine::filterEvent(bps_event_t *event)
+{
+    Q_UNUSED(event);
+
+    qBearerDebug() << Q_FUNC_INFO << "got update request.";
+
+    doRequestUpdate();
+}
+
+void QBBEngine::updateConfiguration(const char *interface)
+{
+    netstatus_interface_details_t *details = 0;
+
+    if (netstatus_get_interface_details(interface, &details) != BPS_SUCCESS) {
+        qBearerDebug() << Q_FUNC_INFO << "cannot retrieve details for interface" << interface;
+
+        return;
+    }
+
+    const QString name = QString::fromLatin1(netstatus_interface_get_name(details));
+    const QString id = idForName(name);
+
+
+    const int numberOfIpAddresses = netstatus_interface_get_num_ip_addresses(details);
+    const bool isConnected = netstatus_interface_is_connected(details);
+    const netstatus_interface_type_t type = netstatus_interface_get_type(details);
+
+    netstatus_free_interface_details(&details);
+
+    QNetworkConfiguration::StateFlags state = QNetworkConfiguration::Defined;
+
+    if (isConnected && (numberOfIpAddresses > 0))
+        state |= QNetworkConfiguration::Active;
+
+    QMutexLocker locker(&mutex);
+
+    if (accessPointConfigurations.contains(id)) {
+        QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
+
+        bool changed = false;
+
+        QMutexLocker ptrLocker(&ptr->mutex);
+
+        if (!ptr->isValid) {
+            ptr->isValid = true;
+            changed = true;
+        }
+
+        if (ptr->name != name) {
+            ptr->name = name;
+            changed = true;
+        }
+
+        if (ptr->id != id) {
+            ptr->id = id;
+            changed = true;
+        }
+
+        if (ptr->state != state) {
+            ptr->state = state;
+            changed = true;
+        }
+
+        ptrLocker.unlock();
+
+        locker.unlock();
+
+        if (changed) {
+            qBearerDebug() << Q_FUNC_INFO << "configuration changed:" << interface;
+
+            Q_EMIT configurationChanged(ptr);
+        } else {
+            qBearerDebug() << Q_FUNC_INFO << "configuration has not changed.";
+        }
+
+        return;
+    }
+
+    QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate);
+
+    ptr->name = name;
+    ptr->isValid = true;
+    ptr->id = id;
+    ptr->state = state;
+    ptr->type = QNetworkConfiguration::InternetAccessPoint;
+    ptr->bearerType = interfaceType(type);
+
+    accessPointConfigurations.insert(id, ptr);
+    configurationInterface.insert(id, name);
+
+    locker.unlock();
+
+    qBearerDebug() << Q_FUNC_INFO << "configuration added:" << interface;
+
+    Q_EMIT configurationAdded(ptr);
+}
+
+void QBBEngine::removeConfiguration(const QString &id)
+{
+    QMutexLocker locker(&mutex);
+
+    QNetworkConfigurationPrivatePointer ptr =
+        accessPointConfigurations.take(id);
+
+    configurationInterface.remove(ptr->id);
+
+    locker.unlock();
+
+    Q_EMIT configurationRemoved(ptr);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_BEARERMANAGEMENT
+
diff --git a/src/plugins/bearer/blackberry/qbbengine.h b/src/plugins/bearer/blackberry/qbbengine.h
new file mode 100644 (file)
index 0000000..1c9a5d4
--- /dev/null
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Research In Motion
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBENGINE_H
+#define QBBENGINE_H
+
+#include "../qbearerengine_impl.h"
+
+#include <QAbstractEventDispatcher>
+
+#ifndef QT_NO_BEARERMANAGEMENT
+
+struct bps_event_t;
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkConfigurationPrivate;
+class QNetworkSessionPrivate;
+
+class QBBEngine : public QBearerEngineImpl
+{
+    Q_OBJECT
+
+public:
+    explicit QBBEngine(QObject *parent = 0);
+    ~QBBEngine();
+
+    QString getInterfaceFromId(const QString &id) Q_DECL_OVERRIDE;
+    bool hasIdentifier(const QString &id) Q_DECL_OVERRIDE;
+
+    void connectToId(const QString &id) Q_DECL_OVERRIDE;
+    void disconnectFromId(const QString &id) Q_DECL_OVERRIDE;
+
+    Q_INVOKABLE void initialize() Q_DECL_OVERRIDE;
+    Q_INVOKABLE void requestUpdate() Q_DECL_OVERRIDE;
+
+    QNetworkSession::State sessionStateForId(const QString &id) Q_DECL_OVERRIDE;
+
+    QNetworkConfigurationManager::Capabilities capabilities() const Q_DECL_OVERRIDE;
+
+    QNetworkSessionPrivate *createSessionBackend() Q_DECL_OVERRIDE;
+
+    QNetworkConfigurationPrivatePointer defaultConfiguration() Q_DECL_OVERRIDE;
+
+    bool requiresPolling() const Q_DECL_OVERRIDE;
+
+protected:
+    void updateConfiguration(const char *interface);
+    void removeConfiguration(const QString &id);
+
+private Q_SLOTS:
+    void doRequestUpdate();
+
+private:
+    static bool filterEvent(void *message);
+
+    void filterEvent(bps_event_t *event);
+
+    QHash<QString, QString> configurationInterface;
+
+    QAbstractEventDispatcher::EventFilter previousEventFilter;
+
+    mutable QMutex pollingMutex;
+
+    bool pollingRequired;
+    bool initialized;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_BEARERMANAGEMENT
+
+#endif // QBBENGINE_H