summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@qt.io>2017-01-30 12:26:06 +0100
committerOliver Wolff <oliver.wolff@qt.io>2017-01-31 08:43:34 +0000
commitc9218dbb84581c0e2f2ab6a7a858f64c70e8c58a (patch)
tree57a28e43579bb8e07a465eb1aaff02d95359368f
parent4abc1ebedc13b7ec9a3ea8537dc08d0268c0022b (diff)
winrt: Add bluetooth server support
Task-numer: QTBUG-37779 Change-Id: Ieb3ed5dfea7d60b3875cbe97bb26f8060bebcc17 Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
-rw-r--r--src/bluetooth/bluetooth.pro4
-rw-r--r--src/bluetooth/qbluetoothserver.cpp2
-rw-r--r--src/bluetooth/qbluetoothserver_p.h20
-rw-r--r--src/bluetooth/qbluetoothserver_winrt.cpp243
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_p.h22
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_winrt.cpp378
-rw-r--r--src/bluetooth/qbluetoothsocket_winrt.cpp21
7 files changed, 682 insertions, 8 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index 20f89b8e..b47e234e 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -200,9 +200,9 @@ qtConfig(bluez):qtHaveModule(dbus) {
SOURCES += \
qbluetoothdevicediscoveryagent_winrt.cpp \
qbluetoothlocaldevice_p.cpp \
- qbluetoothserver_p.cpp \
+ qbluetoothserver_winrt.cpp \
qbluetoothservicediscoveryagent_winrt.cpp \
- qbluetoothserviceinfo_p.cpp \
+ qbluetoothserviceinfo_winrt.cpp \
qbluetoothsocket_winrt.cpp \
qlowenergycontroller_winrt.cpp
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index a27eb385..41b1d822 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -257,7 +257,7 @@ bool QBluetoothServer::isListening() const
{
Q_D(const QBluetoothServer);
-#ifdef QT_ANDROID_BLUETOOTH
+#if defined(QT_ANDROID_BLUETOOTH) || defined(QT_WINRT_BLUETOOTH)
return d->isListening();
#endif
diff --git a/src/bluetooth/qbluetoothserver_p.h b/src/bluetooth/qbluetoothserver_p.h
index 8797cebd..833c781b 100644
--- a/src/bluetooth/qbluetoothserver_p.h
+++ b/src/bluetooth/qbluetoothserver_p.h
@@ -69,6 +69,12 @@ QT_FORWARD_DECLARE_CLASS(QSocketNotifier)
class ServerAcceptanceThread;
#endif
+#ifdef QT_WINRT_BLUETOOTH
+#include <wrl.h>
+// No forward declares because QBluetoothServerPrivate::listener does not work with them
+#include <windows.networking.sockets.h>
+#endif
+
QT_BEGIN_NAMESPACE
class QBluetoothAddress;
@@ -114,7 +120,21 @@ public:
bool isListening() const;
bool initiateActiveListening(const QBluetoothUuid& uuid, const QString &serviceName);
bool deactivateActiveListening();
+#elif defined(QT_WINRT_BLUETOOTH)
+ EventRegistrationToken connectionToken {-1};
+
+ mutable QMutex pendingConnectionsMutex;
+ QVector<Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocket>> pendingConnections;
+
+ Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> socketListener;
+ HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *listener,
+ ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args);
+public:
+ bool isListening() const;
+ Microsoft::WRL::ComPtr<ABI::Windows::Networking::Sockets::IStreamSocketListener> listener() { return socketListener; }
+ bool initiateActiveListening(const QString &serviceName);
+ bool deactivateActiveListening();
#endif
};
diff --git a/src/bluetooth/qbluetoothserver_winrt.cpp b/src/bluetooth/qbluetoothserver_winrt.cpp
new file mode 100644
index 00000000..effe4dc9
--- /dev/null
+++ b/src/bluetooth/qbluetoothserver_winrt.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothserver.h"
+#include "qbluetoothserver_p.h"
+#include "qbluetoothsocket.h"
+#include "qbluetoothsocket_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <qfunctions_winrt.h>
+
+#include <windows.networking.h>
+#include <windows.networking.connectivity.h>
+#include <windows.networking.sockets.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Devices;
+using namespace ABI::Windows::Devices::Enumeration;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Networking;
+using namespace ABI::Windows::Networking::Sockets;
+using namespace ABI::Windows::Networking::Connectivity;
+
+typedef ITypedEventHandler<StreamSocketListener *, StreamSocketListenerConnectionReceivedEventArgs *> ClientConnectedHandler;
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+
+QHash<QBluetoothServerPrivate *, int> __fakeServerPorts;
+
+QBluetoothServerPrivate::QBluetoothServerPrivate(QBluetoothServiceInfo::Protocol sType)
+ : maxPendingConnections(1), serverType(sType), m_lastError(QBluetoothServer::NoError), socket(0)
+{
+ socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
+}
+
+QBluetoothServerPrivate::~QBluetoothServerPrivate()
+{
+ deactivateActiveListening();
+ __fakeServerPorts.remove(this);
+ if (socket)
+ delete socket;
+}
+
+bool QBluetoothServerPrivate::isListening() const
+{
+ return __fakeServerPorts.contains(const_cast<QBluetoothServerPrivate *>(this));
+}
+
+bool QBluetoothServerPrivate::initiateActiveListening(const QString &serviceName)
+{
+ HStringReference serviceNameRef(reinterpret_cast<LPCWSTR>(serviceName.utf16()));
+
+ ComPtr<IAsyncAction> bindAction;
+ HRESULT hr = socketListener->BindServiceNameAsync(serviceNameRef.Get(), &bindAction);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(bindAction);
+ Q_ASSERT_SUCCEEDED(hr);
+ return true;
+}
+
+bool QBluetoothServerPrivate::deactivateActiveListening()
+{
+ if (!isListening())
+ return true;
+
+ HRESULT hr;
+ hr = socketListener->remove_ConnectionReceived(connectionToken);
+ Q_ASSERT_SUCCEEDED(hr);
+ return true;
+}
+
+HRESULT QBluetoothServerPrivate::handleClientConnection(IStreamSocketListener *listener,
+ IStreamSocketListenerConnectionReceivedEventArgs *args)
+{
+ Q_Q(QBluetoothServer);
+ if (!socketListener || socketListener.Get() != listener) {
+ qCDebug(QT_BT_WINRT) << "Accepting connection from wrong listener. We should not be here.";
+ Q_UNREACHABLE();
+ return S_OK;
+ }
+
+ HRESULT hr;
+ ComPtr<IStreamSocket> socket;
+ hr = args->get_Socket(&socket);
+ Q_ASSERT_SUCCEEDED(hr);
+ QMutexLocker locker(&pendingConnectionsMutex);
+ if (pendingConnections.count() < maxPendingConnections) {
+ qCDebug(QT_BT_WINRT) << "Accepting connection";
+ pendingConnections.append(socket);
+ q->newConnection();
+ } else {
+ qCDebug(QT_BT_WINRT) << "Refusing connection";
+ }
+
+ return S_OK;
+}
+
+void QBluetoothServer::close()
+{
+ Q_D(QBluetoothServer);
+
+ d->deactivateActiveListening();
+ __fakeServerPorts.remove(d);
+}
+
+bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
+{
+ Q_UNUSED(address);
+ Q_D(QBluetoothServer);
+ if (serverType() != QBluetoothServiceInfo::RfcommProtocol) {
+ d->m_lastError = UnsupportedProtocolError;
+ emit error(d->m_lastError);
+ return false;
+ }
+
+ if (isListening())
+ return false;
+
+ HRESULT hr;
+ hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocketListener).Get(),
+ &d->socketListener);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = d->socketListener->add_ConnectionReceived(Callback<ClientConnectedHandler>(d, &QBluetoothServerPrivate::handleClientConnection).Get(),
+ &d->connectionToken);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ //We can not register an actual Rfcomm port, because the platform does not allow it
+ //but we need a way to associate a server with a service
+ if (port == 0) { //Try to assign a non taken port id
+ for (int i = 1; ; i++){
+ if (__fakeServerPorts.key(i) == 0) {
+ port = i;
+ break;
+ }
+ }
+ }
+
+ if (__fakeServerPorts.key(port) == 0) {
+ __fakeServerPorts[d] = port;
+
+ qCDebug(QT_BT_WINRT) << "Port" << port << "registered";
+ } else {
+ qCWarning(QT_BT_WINRT) << "server with port" << port << "already registered or port invalid";
+ d->m_lastError = ServiceAlreadyRegisteredError;
+ emit error(d->m_lastError);
+ return false;
+ }
+
+ return true;
+}
+
+void QBluetoothServer::setMaxPendingConnections(int numConnections)
+{
+ Q_D(QBluetoothServer);
+ QMutexLocker locker(&d->pendingConnectionsMutex);
+ d->maxPendingConnections = numConnections;
+}
+
+bool QBluetoothServer::hasPendingConnections() const
+{
+ Q_D(const QBluetoothServer);
+ QMutexLocker locker(&d->pendingConnectionsMutex);
+ return !d->pendingConnections.isEmpty();
+}
+
+QBluetoothSocket *QBluetoothServer::nextPendingConnection()
+{
+ Q_D(QBluetoothServer);
+
+ ComPtr<IStreamSocket> socket = d->pendingConnections.takeFirst();
+
+ QBluetoothSocket *newSocket = new QBluetoothSocket();
+ bool success = newSocket->d_ptr->setSocketDescriptor(qintptr(socket.Get()), d->serverType);
+ if (!success) {
+ delete newSocket;
+ newSocket = 0;
+ }
+
+ return newSocket;
+}
+
+QBluetoothAddress QBluetoothServer::serverAddress() const
+{
+ return QBluetoothAddress();
+}
+
+quint16 QBluetoothServer::serverPort() const
+{
+ //We return the fake port
+ Q_D(const QBluetoothServer);
+ return __fakeServerPorts.value((QBluetoothServerPrivate*)d, 0);
+}
+
+void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
+{
+ Q_UNUSED(security);
+}
+
+QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
+{
+ return QBluetooth::NoSecurity;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothserviceinfo_p.h b/src/bluetooth/qbluetoothserviceinfo_p.h
index f1f3b669..2e223a7b 100644
--- a/src/bluetooth/qbluetoothserviceinfo_p.h
+++ b/src/bluetooth/qbluetoothserviceinfo_p.h
@@ -62,6 +62,22 @@
class OrgBluezServiceInterface;
class OrgBluezProfileManager1Interface;
+#ifdef QT_WINRT_BLUETOOTH
+#include <wrl.h>
+
+namespace ABI {
+ namespace Windows {
+ namespace Devices {
+ namespace Bluetooth {
+ namespace Rfcomm {
+ struct IRfcommServiceProvider;
+ }
+ }
+ }
+ }
+}
+#endif
+
QT_BEGIN_NAMESPACE
class QBluetoothServiceInfo;
@@ -98,6 +114,12 @@ private:
QString profilePath;
#endif
+#ifdef QT_WINRT_BLUETOOTH
+ Microsoft::WRL::ComPtr<ABI::Windows::Devices::Bluetooth::Rfcomm::IRfcommServiceProvider> serviceProvider;
+
+ bool writeSdpAttributes();
+#endif
+
mutable bool registered;
};
diff --git a/src/bluetooth/qbluetoothserviceinfo_winrt.cpp b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
new file mode 100644
index 00000000..77376dd9
--- /dev/null
+++ b/src/bluetooth/qbluetoothserviceinfo_winrt.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothserviceinfo.h"
+#include "qbluetoothserviceinfo_p.h"
+#include "qbluetoothserver_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <qfunctions_winrt.h>
+
+#include <wrl.h>
+#include <windows.devices.bluetooth.h>
+#include <windows.devices.bluetooth.rfcomm.h>
+#include <windows.foundation.h>
+#include <windows.networking.sockets.h>
+#include <windows.storage.streams.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+using namespace ABI::Windows::Devices::Bluetooth;
+using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace ABI::Windows::Networking::Sockets;
+using namespace ABI::Windows::Storage::Streams;
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
+
+#define TYPE_UINT8 8
+#define TYPE_UINT16 9
+#define TYPE_UINT32 10
+#define TYPE_SHORT_UUID 25
+#define TYPE_LONG_UUID 28
+#define TYPE_STRING 37
+#define TYPE_SEQUENCE 53
+
+extern QHash<QBluetoothServerPrivate *, int> __fakeServerPorts;
+
+static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
+{
+ ComPtr<IDataWriter> writer;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
+ &writer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ switch (int(attribute.type())) {
+ case QMetaType::Void:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::Void";
+ return nullptr;
+ case QMetaType::UChar:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UChar";
+ hr = writer->WriteByte(TYPE_UINT8);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteByte(attribute.value<quint8>());
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ case QMetaType::UShort:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UShort";
+ hr = writer->WriteByte(TYPE_UINT16);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteUInt16(attribute.value<quint16>());
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ case QMetaType::UInt:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UInt";
+ hr = writer->WriteByte(TYPE_UINT32);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteByte(attribute.value<quint32>());
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ case QMetaType::Char:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::Char";
+ return nullptr;
+ break;
+ case QMetaType::Short:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::Short";
+ return nullptr;
+ break;
+ case QMetaType::Int:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::Int";
+ return nullptr;
+ break;
+ case QMetaType::QString: {
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString";
+ hr = writer->WriteByte(TYPE_STRING);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString stringValue = attribute.value<QString>();
+ hr = writer->WriteByte(stringValue.length());
+ Q_ASSERT_SUCCEEDED(hr);
+ HStringReference stringRef(reinterpret_cast<LPCWSTR>(stringValue.utf16()));
+ quint32 bytesWritten;
+ hr = writer->WriteString(stringRef.Get(), &bytesWritten);
+ if (bytesWritten != stringValue.length()) {
+ qCWarning(QT_BT_WINRT) << "Did not write full value to buffer";
+ return nullptr;
+ }
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ }
+ case QMetaType::Bool:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::Bool";
+ return nullptr;
+ break;
+ case QMetaType::QUrl:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::QUrl";
+ return nullptr;
+ break;
+ case QVariant::UserType:
+ if (attribute.userType() == qMetaTypeId<QBluetoothUuid>()) {
+ QBluetoothUuid uuid = attribute.value<QBluetoothUuid>();
+ const int minimumSize = uuid.minimumSize();
+ switch (uuid.minimumSize()) {
+ case 0:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register Uuid of length 0";
+ return nullptr;
+ break;
+ case 2:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 2" << uuid;
+ hr = writer->WriteByte(TYPE_SHORT_UUID);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteUInt16(uuid.toUInt16());
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ case 4:
+ qCWarning(QT_BT_WINRT) << "Don't know how to register Uuid of length 4";
+ return nullptr;
+ break;
+ case 16:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 16";
+ hr = writer->WriteByte(TYPE_LONG_UUID);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteGuid(uuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ default:
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute";
+ hr = writer->WriteByte(TYPE_LONG_UUID);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteGuid(uuid);
+ Q_ASSERT_SUCCEEDED(hr);
+ break;
+ }
+ } else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
+ qCDebug(QT_BT_WINRT) << "Registering sequence attribute";
+ hr = writer->WriteByte(TYPE_SEQUENCE);
+ Q_ASSERT_SUCCEEDED(hr);
+ const QBluetoothServiceInfo::Sequence *sequence =
+ static_cast<const QBluetoothServiceInfo::Sequence *>(attribute.data());
+ ComPtr<IDataWriter> tmpWriter;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
+ &tmpWriter);
+ Q_ASSERT_SUCCEEDED(hr);
+ foreach (const QVariant &v, *sequence) {
+ ComPtr<IBuffer> tmpBuffer = bufferFromAttribute(v);
+ if (!tmpBuffer) {
+ qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute in sequence";
+ return nullptr;
+ }
+ quint32 l;
+ hr = tmpBuffer->get_Length(&l);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = tmpWriter->WriteBuffer(tmpBuffer.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
+ ComPtr<IBuffer> tmpBuffer;
+ hr = tmpWriter->DetachBuffer(&tmpBuffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ // write sequence length
+ quint32 length;
+ tmpBuffer->get_Length(&length);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = writer->WriteByte(length + 1);
+ Q_ASSERT_SUCCEEDED(hr);
+ // write sequence data
+ hr = writer->WriteBuffer(tmpBuffer.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+ qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registered sequence attribute with length" << length;
+ } else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
+ qCWarning(QT_BT_WINRT) << "Don't know how to register user type Alternative";
+ return false;
+ }
+ break;
+ default:
+ qCWarning(QT_BT_WINRT) << "Unknown variant type", attribute.userType();
+ return nullptr;
+ }
+ ComPtr<IBuffer> buffer;
+ hr = writer->DetachBuffer(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+ return buffer;
+}
+
+QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
+ : registered(false)
+{
+}
+
+QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
+{
+}
+
+bool QBluetoothServiceInfoPrivate::isRegistered() const
+{
+ return registered;
+}
+
+bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
+{
+ Q_UNUSED(localAdapter);
+ if (registered)
+ return false;
+
+ if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
+ qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Only RFCOMM services can be registered on WinRT";
+ return false;
+ }
+
+ QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
+ if (!sPriv)
+ return false;
+
+ HRESULT hr;
+ QBluetoothUuid uuid = attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>();
+ ComPtr<IRfcommServiceIdStatics> serviceIdStatics;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Rfcomm_RfcommServiceId).Get(),
+ IID_PPV_ARGS(&serviceIdStatics));
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IRfcommServiceId> serviceId;
+ hr = serviceIdStatics->FromUuid(uuid, &serviceId);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IRfcommServiceProviderStatics> providerStatics;
+ hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Rfcomm_RfcommServiceProvider).Get(),
+ IID_PPV_ARGS(&providerStatics));
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IAsyncOperation<RfcommServiceProvider *>> op;
+ hr = providerStatics->CreateAsync(serviceId.Get(), &op);
+ Q_ASSERT_SUCCEEDED(hr);
+ hr = QWinRTFunctions::await(op, serviceProvider.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ ComPtr<IStreamSocketListener> listener = sPriv->listener();
+ if (!listener) {
+ qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not obtain listener from server.";
+ return false;
+ }
+
+
+ HString serviceIdHString;
+ serviceId->AsString(serviceIdHString.GetAddressOf());
+ Q_ASSERT_SUCCEEDED(hr);
+ const QString serviceIdString = QString::fromWCharArray(WindowsGetStringRawBuffer(serviceIdHString.Get(), nullptr));
+
+ //tell the server what service name our listener should have
+ //and start the real listener
+ bool result = sPriv->initiateActiveListening(serviceIdString);
+ if (!result) {
+ return false;
+ }
+
+ result = writeSdpAttributes();
+ if (!result) {
+ return false;
+ }
+
+ hr = serviceProvider->StartAdvertising(listener.Get());
+ if (FAILED(hr)) {
+ qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not start advertising. Check your SDP data.";
+ return false;
+ }
+
+ registered = true;
+ return true;
+}
+
+bool QBluetoothServiceInfoPrivate::unregisterService()
+{
+ if (!registered)
+ return false;
+
+ QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
+ if (!sPriv) {
+ //QBluetoothServer::close() was called without prior call to unregisterService().
+ //Now it is unregistered anyway.
+ registered = false;
+ return true;
+ }
+
+ bool result = sPriv->deactivateActiveListening();
+ if (!result)
+ return false;
+
+ HRESULT hr;
+ hr = serviceProvider->StopAdvertising();
+ Q_ASSERT_SUCCEEDED(hr);
+
+ registered = false;
+ return true;
+}
+
+bool QBluetoothServiceInfoPrivate::writeSdpAttributes()
+{
+ if (!serviceProvider)
+ return false;
+
+ ComPtr<IDataWriter> writer;
+ HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
+ &writer);
+ Q_ASSERT_SUCCEEDED(hr);
+ ComPtr<IMap<UINT32, IBuffer *>> rawAttributes;
+ hr = serviceProvider->get_SdpRawAttributes(&rawAttributes);
+ Q_ASSERT_SUCCEEDED(hr);
+ for (quint16 key : attributes.keys()) {
+ // The SDP Class Id List and RFCOMM and L2CAP protocol descriptors are automatically
+ // generated by the RfcommServiceProvider. Do not specify it in the SDP raw attribute map.
+ if (key == QBluetoothServiceInfo::ServiceClassIds
+ || key == QBluetoothServiceInfo::ProtocolDescriptorList)
+ continue;
+ const QVariant attribute = attributes.value(key);
+ HRESULT hr;
+ ComPtr<IBuffer> buffer = bufferFromAttribute(attribute);
+ if (!buffer) {
+ qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute with id:" << key;
+ return false;
+ }
+
+ hr = writer->WriteBuffer(buffer.Get());
+ Q_ASSERT_SUCCEEDED(hr);
+
+ hr = writer->DetachBuffer(&buffer);
+ Q_ASSERT_SUCCEEDED(hr);
+
+ boolean replaced;
+ hr = rawAttributes->Insert(key, buffer.Get(), &replaced);
+ Q_ASSERT_SUCCEEDED(hr);
+ Q_ASSERT(!replaced);
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/bluetooth/qbluetoothsocket_winrt.cpp b/src/bluetooth/qbluetoothsocket_winrt.cpp
index 98847b18..855af16d 100644
--- a/src/bluetooth/qbluetoothsocket_winrt.cpp
+++ b/src/bluetooth/qbluetoothsocket_winrt.cpp
@@ -533,11 +533,22 @@ void QBluetoothSocketPrivate::close()
bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
{
- Q_UNUSED(socketDescriptor);
- Q_UNUSED(socketType)
- Q_UNUSED(socketState);
- Q_UNUSED(openMode);
- return false;
+ Q_Q(QBluetoothSocket);
+ if (socketType != QBluetoothServiceInfo::RfcommProtocol)
+ return false;
+
+ m_socketObject = nullptr;
+ socket = -1;
+
+ m_socketObject = reinterpret_cast<IStreamSocket *>(qintptr(socketDescriptor));
+ if (!m_socketObject)
+ return false;
+ socket = qintptr(m_socketObject.Get());
+ m_worker->setSocket(m_socketObject);
+ if (socketState == QBluetoothSocket::ConnectedState)
+ m_worker->startReading();
+ q->setOpenMode(openMode);
+ return true;
}
qint64 QBluetoothSocketPrivate::bytesAvailable() const