Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtBluetooth module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qbluetoothserviceinfo.h"
41#include "qbluetoothserviceinfo_p.h"
42#include "qbluetoothserver_p.h"
43
44#include <QtCore/private/qeventdispatcher_winrt_p.h>
45#include <QtCore/QLoggingCategory>
46#ifdef CLASSIC_APP_BUILD
47#define Q_OS_WINRT
48#endif
49#include <qfunctions_winrt.h>
50
51#include <wrl.h>
52#include <windows.devices.bluetooth.h>
53#include <windows.devices.bluetooth.rfcomm.h>
54#include <windows.foundation.h>
55#include <windows.networking.sockets.h>
56#include <windows.storage.streams.h>
57
58using namespace Microsoft::WRL;
59using namespace Microsoft::WRL::Wrappers;
60using namespace ABI::Windows::Devices::Bluetooth;
61using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
62using namespace ABI::Windows::Foundation;
63using namespace ABI::Windows::Foundation::Collections;
64using namespace ABI::Windows::Networking::Sockets;
65using namespace ABI::Windows::Storage::Streams;
66
67QT_BEGIN_NAMESPACE
68
69Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINRT)
70
71#define TYPE_VOID 0
72#define TYPE_UINT8 8
73#define TYPE_UINT16 9
74#define TYPE_UINT32 10
75#define TYPE_UINT64 11
76//#define TYPE_UINT128 12
77#define TYPE_INT8 16
78#define TYPE_INT16 17
79#define TYPE_INT32 18
80#define TYPE_INT64 19
81//#define TYPE_INT128 20
82#define TYPE_UUID16 25
83#define TYPE_UUID32 26
84#define TYPE_UUID128 28
85#define TYPE_STRING_BASE 32
86#define TYPE_BOOLEAN 40
87#define TYPE_SEQUENCE_BASE 48
88#define TYPE_ALTERNATIVE_BASE 56
89#define TYPE_URL_BASE 64
90
91extern QHash<QBluetoothServerPrivate *, int> __fakeServerPorts;
92
93inline bool typeIsOfBase(unsigned char type, unsigned char baseType)
94{
95 return ((type & baseType) == baseType);
96}
97
98qint64 getLengthForBaseType(unsigned char type, ComPtr<IDataReader> &reader)
99{
100 const bool isOfBase = (typeIsOfBase(type, TYPE_STRING_BASE)
101 || typeIsOfBase(type, TYPE_SEQUENCE_BASE)
102 || typeIsOfBase(type, TYPE_ALTERNATIVE_BASE)
103 || typeIsOfBase(type, TYPE_URL_BASE));
104 if (!isOfBase)
105 return -1;
106
107 HRESULT hr;
108 // For these types, the first 5 bits are the base type followed by 3 bits
109 // describing the size index. This index decides how many additional bits
110 // have to be read to get the type's length.
111 const unsigned char sizeIndex = (type & 0x7);
112 switch (sizeIndex) {
113 case 5: {
114 quint8 length;
115 hr = reader->ReadByte(&length);
116 RETURN_IF_FAILED("Could not read length from buffer", return -1);
117 return length;
118 } case 6: {
119 quint16 length;
120 hr = reader->ReadUInt16(&length);
121 RETURN_IF_FAILED("Could not read length from buffer", return -1);
122 return length;
123 } case 7: {
124 quint32 length;
125 hr = reader->ReadUInt32(&length);
126 RETURN_IF_FAILED("Could not read length from buffer", return -1);
127 return length;
128 }
129 }
130 return -1;
131}
132
133bool writeStringHelper(const QString &string, ComPtr<IDataWriter> writer)
134{
135 HRESULT hr;
136 const int stringLength = string.length();
137 unsigned char type = TYPE_STRING_BASE;
138 if (stringLength < 0) {
139 qCWarning(QT_BT_WINRT) << "Can not write invalid string value to buffer";
140 return false;
141 } if (stringLength <= 0xff) {
142 type += 5;
143 hr = writer->WriteByte(type);
144 RETURN_FALSE_IF_FAILED("Could not write string type data.");
145 hr = writer->WriteByte(stringLength);
146 RETURN_FALSE_IF_FAILED("Could not write string length.");
147 } else if (stringLength <= 0xffff) {
148 type += 6;
149 hr = writer->WriteByte(type);
150 RETURN_FALSE_IF_FAILED("Could not write string type data.");
151 hr = writer->WriteUInt16(stringLength);
152 RETURN_FALSE_IF_FAILED("Could not write string length.");
153 } else {
154 type += 7;
155 hr = writer->WriteByte(type);
156 RETURN_FALSE_IF_FAILED("Could not write string type data.");
157 hr = writer->WriteUInt32(stringLength);
158 RETURN_FALSE_IF_FAILED("Could not write string length.");
159 }
160 HStringReference stringRef(reinterpret_cast<LPCWSTR>(string.utf16()));
161 quint32 bytesWritten;
162 hr = writer->WriteString(stringRef.Get(), &bytesWritten);
163 RETURN_FALSE_IF_FAILED("Could not write string to buffer.");
164 if (bytesWritten != string.length()) {
165 qCWarning(QT_BT_WINRT) << "Did not write full value to buffer";
166 return false;
167 }
168 return true;
169}
170
171bool repairProfileDescriptorListIfNeeded(ComPtr<IBuffer> &buffer)
172{
173 ComPtr<IDataReaderStatics> dataReaderStatics;
174 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataReader).Get(),
175 &dataReaderStatics);
176 Q_ASSERT_SUCCEEDED(hr);
177
178 ComPtr<IDataReader> reader;
179 hr = dataReaderStatics->FromBuffer(buffer.Get(), reader.GetAddressOf());
180 Q_ASSERT_SUCCEEDED(hr);
181
182 BYTE type;
183 hr = reader->ReadByte(&type);
184 Q_ASSERT_SUCCEEDED(hr);
185 if (!typeIsOfBase(type, TYPE_SEQUENCE_BASE)) {
186 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Malformed profile descriptor list read";
187 return false;
188 }
189
190 qint64 length = getLengthForBaseType(type, reader);
191 hr = reader->ReadByte(&type);
192 Q_ASSERT_SUCCEEDED(hr);
193 // We have to "repair" the structure if the outer sequence contains a uuid directly
194 if (type == TYPE_UUID16 && length == 4) {
195 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Repairing profile descriptor list";
196 quint16 uuid;
197 hr = reader->ReadUInt16(&uuid);
198 Q_ASSERT_SUCCEEDED(hr);
199
200 ComPtr<IDataWriter> writer;
201 hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
202 &writer);
203 Q_ASSERT_SUCCEEDED(hr);
204
205 hr = writer->WriteByte(TYPE_SEQUENCE_BASE + 5);
206 Q_ASSERT_SUCCEEDED(hr);
207 // 8 == length of nested sequence (outer sequence -> inner sequence -> uuid and version)
208 hr = writer->WriteByte(8);
209 Q_ASSERT_SUCCEEDED(hr);
210 hr = writer->WriteByte(TYPE_SEQUENCE_BASE + 5);
211 Q_ASSERT_SUCCEEDED(hr);
212 hr = writer->WriteByte(7);
213 Q_ASSERT_SUCCEEDED(hr);
214 hr = writer->WriteByte(TYPE_UUID16);
215 Q_ASSERT_SUCCEEDED(hr);
216 hr = writer->WriteUInt16(uuid);
217 Q_ASSERT_SUCCEEDED(hr);
218 // Write default version to make WinRT happy
219 hr = writer->WriteByte(TYPE_UINT16);
220 Q_ASSERT_SUCCEEDED(hr);
221 hr = writer->WriteUInt16(0x100);
222 Q_ASSERT_SUCCEEDED(hr);
223
224 hr = writer->DetachBuffer(&buffer);
225 Q_ASSERT_SUCCEEDED(hr);
226 }
227
228 return true;
229}
230
231static ComPtr<IBuffer> bufferFromAttribute(const QVariant &attribute)
232{
233 ComPtr<IDataWriter> writer;
234 HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
235 &writer);
236 Q_ASSERT_SUCCEEDED(hr);
237
238 switch (int(attribute.type())) {
239 case QMetaType::Void:
240 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Void:";
241 hr = writer->WriteByte(TYPE_VOID);
242 Q_ASSERT_SUCCEEDED(hr);
243 break;
244 case QMetaType::UChar:
245 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UChar:" << attribute.value<quint8>();
246 hr = writer->WriteByte(TYPE_UINT8);
247 Q_ASSERT_SUCCEEDED(hr);
248 hr = writer->WriteByte(attribute.value<quint8>());
249 Q_ASSERT_SUCCEEDED(hr);
250 break;
251 case QMetaType::UShort:
252 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UShort:" << attribute.value<quint16>();
253 hr = writer->WriteByte(TYPE_UINT16);
254 Q_ASSERT_SUCCEEDED(hr);
255 hr = writer->WriteUInt16(attribute.value<quint16>());
256 Q_ASSERT_SUCCEEDED(hr);
257 break;
258 case QMetaType::UInt:
259 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::UInt:" << attribute.value<quint32>();
260 hr = writer->WriteByte(TYPE_UINT32);
261 Q_ASSERT_SUCCEEDED(hr);
262 hr = writer->WriteUInt32(attribute.value<quint32>());
263 Q_ASSERT_SUCCEEDED(hr);
264 break;
265 case QMetaType::ULongLong:
266 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::ULongLong:" << attribute.value<quint64>();
267 hr = writer->WriteByte(TYPE_UINT64);
268 Q_ASSERT_SUCCEEDED(hr);
269 hr = writer->WriteUInt64(attribute.value<quint64>());
270 Q_ASSERT_SUCCEEDED(hr);
271 break;
272 case QMetaType::Char:
273 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Char:" << attribute.value<qint8>();
274 hr = writer->WriteByte(TYPE_INT8);
275 Q_ASSERT_SUCCEEDED(hr);
276 hr = writer->WriteByte(attribute.value<qint8>());
277 Q_ASSERT_SUCCEEDED(hr);
278 break;
279 case QMetaType::Short:
280 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Short:" << attribute.value<qint16>();
281 hr = writer->WriteByte(TYPE_INT16);
282 Q_ASSERT_SUCCEEDED(hr);
283 hr = writer->WriteInt16(attribute.value<qint16>());
284 Q_ASSERT_SUCCEEDED(hr);
285 break;
286 case QMetaType::Int:
287 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Int:" << attribute.value<qint32>();
288 hr = writer->WriteByte(TYPE_INT32);
289 Q_ASSERT_SUCCEEDED(hr);
290 hr = writer->WriteInt32(attribute.value<qint32>());
291 Q_ASSERT_SUCCEEDED(hr);
292 break;
293 case QMetaType::LongLong:
294 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::LongLong:" << attribute.value<qint64>();
295 hr = writer->WriteByte(TYPE_INT64);
296 Q_ASSERT_SUCCEEDED(hr);
297 hr = writer->WriteInt64(attribute.value<qint64>());
298 Q_ASSERT_SUCCEEDED(hr);
299 break;
300 case QMetaType::QByteArray: {
301 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QByteArray:" << attribute.value<QString>();
302 const QString stringValue = QString::fromLatin1(attribute.value<QByteArray>().toHex());
303 const bool writeSuccess = writeStringHelper(stringValue, writer);
304 if (!writeSuccess)
305 return nullptr;
306 break;
307 }
308 case QMetaType::QString: {
309 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::QString:" << attribute.value<QString>();
310 const QString stringValue = attribute.value<QString>();
311 const bool writeSucces = writeStringHelper(stringValue, writer);
312 if (!writeSucces)
313 return nullptr;
314 break;
315 }
316 case QMetaType::Bool:
317 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering attribute of type QMetaType::Bool:" << attribute.value<bool>();
318 hr = writer->WriteByte(TYPE_BOOLEAN);
319 Q_ASSERT_SUCCEEDED(hr);
320 hr = writer->WriteByte(attribute.value<bool>());
321 Q_ASSERT_SUCCEEDED(hr);
322 break;
323 case QMetaType::QUrl:
324 qCWarning(QT_BT_WINRT) << "Don't know how to register QMetaType::QUrl";
325 return nullptr;
326 break;
327 case QVariant::UserType:
328 if (attribute.userType() == qMetaTypeId<QBluetoothUuid>()) {
329 QBluetoothUuid uuid = attribute.value<QBluetoothUuid>();
330 const int minimumSize = uuid.minimumSize();
331 switch (uuid.minimumSize()) {
332 case 0:
333 qCWarning(QT_BT_WINRT) << "Don't know how to register Uuid of length 0";
334 return nullptr;
335 case 2:
336 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 2:" << uuid;
337 hr = writer->WriteByte(TYPE_UUID16);
338 Q_ASSERT_SUCCEEDED(hr);
339 hr = writer->WriteUInt16(uuid.toUInt16());
340 Q_ASSERT_SUCCEEDED(hr);
341 break;
342 case 4:
343 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute with length 4:" << uuid;
344 hr = writer->WriteByte(TYPE_UUID32);
345 Q_ASSERT_SUCCEEDED(hr);
346 hr = writer->WriteUInt32(uuid.toUInt32());
347 Q_ASSERT_SUCCEEDED(hr);
348 break;
349 case 16:
350 default:
351 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registering Uuid attribute:" << uuid;
352 hr = writer->WriteByte(TYPE_UUID128);
353 Q_ASSERT_SUCCEEDED(hr);
354 hr = writer->WriteGuid(uuid);
355 Q_ASSERT_SUCCEEDED(hr);
356 break;
357 }
358 } else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Sequence>()) {
359 qCDebug(QT_BT_WINRT) << "Registering sequence attribute";
360 const QBluetoothServiceInfo::Sequence *sequence =
361 static_cast<const QBluetoothServiceInfo::Sequence *>(attribute.data());
362 ComPtr<IDataWriter> tmpWriter;
363 HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
364 &tmpWriter);
365 Q_ASSERT_SUCCEEDED(hr);
366 for (const QVariant &v : *sequence) {
367 ComPtr<IBuffer> tmpBuffer = bufferFromAttribute(v);
368 if (!tmpBuffer) {
369 qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute in sequence";
370 return nullptr;
371 }
372 quint32 l;
373 hr = tmpBuffer->get_Length(&l);
374 Q_ASSERT_SUCCEEDED(hr);
375 hr = tmpWriter->WriteBuffer(tmpBuffer.Get());
376 Q_ASSERT_SUCCEEDED(hr);
377 }
378 ComPtr<IBuffer> tmpBuffer;
379 hr = tmpWriter->DetachBuffer(&tmpBuffer);
380 Q_ASSERT_SUCCEEDED(hr);
381 // write sequence length
382 quint32 length;
383 tmpBuffer->get_Length(&length);
384 Q_ASSERT_SUCCEEDED(hr);
385 unsigned char type = TYPE_SEQUENCE_BASE;
386 length += 1;
387 if (length <= 0xff) {
388 type += 5;
389 hr = writer->WriteByte(type);
390 Q_ASSERT_SUCCEEDED(hr);
391 hr = writer->WriteByte(length);
392 Q_ASSERT_SUCCEEDED(hr);
393 } else if (length <= 0xffff) {
394 type += 6;
395 hr = writer->WriteByte(type);
396 Q_ASSERT_SUCCEEDED(hr);
397 hr = writer->WriteUInt16(length);
398 Q_ASSERT_SUCCEEDED(hr);
399 } else {
400 type += 7;
401 hr = writer->WriteByte(type);
402 Q_ASSERT_SUCCEEDED(hr);
403 hr = writer->WriteUInt32(length);
404 Q_ASSERT_SUCCEEDED(hr);
405 }
406 // write sequence data
407 hr = writer->WriteBuffer(tmpBuffer.Get());
408 Q_ASSERT_SUCCEEDED(hr);
409 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registered sequence attribute with length" << length;
410 } else if (attribute.userType() == qMetaTypeId<QBluetoothServiceInfo::Alternative>()) {
411 qCWarning(QT_BT_WINRT) << "Don't know how to register user type Alternative";
412 return nullptr;
413 }
414 break;
415 default:
416 qCWarning(QT_BT_WINRT) << "Unknown variant type" << attribute.userType();
417 return nullptr;
418 }
419 ComPtr<IBuffer> buffer;
420 hr = writer->DetachBuffer(&buffer);
421 Q_ASSERT_SUCCEEDED(hr);
422 return buffer;
423}
424
425QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
426 : registered(false)
427{
428}
429
430QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
431{
432}
433
434bool QBluetoothServiceInfoPrivate::isRegistered() const
435{
436 return registered;
437}
438
439bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
440{
441 Q_UNUSED(localAdapter);
442 if (registered)
443 return false;
444
445 if (protocolDescriptor(QBluetoothUuid::Rfcomm).isEmpty()) {
446 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Only RFCOMM services can be registered on WinRT";
447 return false;
448 }
449
450 QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
451 if (!sPriv)
452 return false;
453
454 HRESULT hr;
455 QBluetoothUuid uuid = attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>();
456 ComPtr<IRfcommServiceIdStatics> serviceIdStatics;
457 hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Rfcomm_RfcommServiceId).Get(),
458 IID_PPV_ARGS(&serviceIdStatics));
459 Q_ASSERT_SUCCEEDED(hr);
460 ComPtr<IRfcommServiceId> serviceId;
461 hr = serviceIdStatics->FromUuid(uuid, &serviceId);
462 Q_ASSERT_SUCCEEDED(hr);
463 ComPtr<IRfcommServiceProviderStatics> providerStatics;
464 hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_Rfcomm_RfcommServiceProvider).Get(),
465 IID_PPV_ARGS(&providerStatics));
466 Q_ASSERT_SUCCEEDED(hr);
467 ComPtr<IAsyncOperation<RfcommServiceProvider *>> op;
468 hr = QEventDispatcherWinRT::runOnXamlThread([providerStatics, serviceId, &op]
469 {
470 HRESULT hr;
471 hr = providerStatics->CreateAsync(serviceId.Get(), &op);
472 return hr;
473 });
474 Q_ASSERT_SUCCEEDED(hr);
475 hr = QWinRTFunctions::await(op, serviceProvider.GetAddressOf());
476 if (hr == HRESULT_FROM_WIN32(ERROR_DEVICE_NOT_AVAILABLE)) {
477 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "No bluetooth adapter available.";
478 return false;
479 } else {
480 Q_ASSERT_SUCCEEDED(hr);
481 }
482
483 ComPtr<IStreamSocketListener> listener = sPriv->listener();
484 if (!listener) {
485 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not obtain listener from server.";
486 return false;
487 }
488
489
490 HString serviceIdHString;
491 serviceId->AsString(serviceIdHString.GetAddressOf());
492 Q_ASSERT_SUCCEEDED(hr);
493 const QString serviceIdString = QString::fromWCharArray(WindowsGetStringRawBuffer(serviceIdHString.Get(), nullptr));
494
495 //tell the server what service name our listener should have
496 //and start the real listener
497 bool result = sPriv->initiateActiveListening(serviceIdString);
498 if (!result) {
499 return false;
500 }
501
502 result = writeSdpAttributes();
503 if (!result) {
504 qCWarning(QT_BT_WINRT) << "Could not write SDP attributes.";
505 return false;
506 }
507 qCDebug(QT_BT_WINRT) << "SDP attributes written.";
508
509 ComPtr<IRfcommServiceProvider2> serviceProvider2;
510 hr = serviceProvider.As(&serviceProvider2);
511 Q_ASSERT_SUCCEEDED(hr);
512 hr = QEventDispatcherWinRT::runOnXamlThread([listener, serviceProvider2] {
513 HRESULT hr;
514 hr = serviceProvider2->StartAdvertisingWithRadioDiscoverability(listener.Get(), true);
515 return hr;
516 });
517 if (FAILED(hr)) {
518 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Could not start advertising. Check your SDP data.";
519 return false;
520 }
521
522 registered = true;
523 return true;
524}
525
526bool QBluetoothServiceInfoPrivate::unregisterService()
527{
528 if (!registered)
529 return false;
530
531 QBluetoothServerPrivate *sPriv = __fakeServerPorts.key(serverChannel());
532 if (!sPriv) {
533 //QBluetoothServer::close() was called without prior call to unregisterService().
534 //Now it is unregistered anyway.
535 registered = false;
536 return true;
537 }
538
539 bool result = sPriv->deactivateActiveListening();
540 if (!result)
541 return false;
542
543 HRESULT hr;
544 hr = serviceProvider->StopAdvertising();
545 Q_ASSERT_SUCCEEDED(hr);
546
547 registered = false;
548 return true;
549}
550
551bool QBluetoothServiceInfoPrivate::writeSdpAttributes()
552{
553 if (!serviceProvider)
554 return false;
555
556 ComPtr<IDataWriter> writer;
557 HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_DataWriter).Get(),
558 &writer);
559 Q_ASSERT_SUCCEEDED(hr);
560 ComPtr<IMap<UINT32, IBuffer *>> rawAttributes;
561 hr = serviceProvider->get_SdpRawAttributes(&rawAttributes);
562 Q_ASSERT_SUCCEEDED(hr);
563 const QList<quint16> keys = attributes.keys();
564 for (quint16 key : keys) {
565 // The SDP Class Id List and RFCOMM and L2CAP protocol descriptors are automatically
566 // generated by the RfcommServiceProvider. Do not specify it in the SDP raw attribute map.
567 if (key == QBluetoothServiceInfo::ServiceClassIds
568 || key == QBluetoothServiceInfo::ProtocolDescriptorList)
569 continue;
570 const QVariant attribute = attributes.value(key);
571 HRESULT hr;
572 ComPtr<IBuffer> buffer = bufferFromAttribute(attribute);
573 if (!buffer) {
574 qCWarning(QT_BT_WINRT) << "Could not create buffer from attribute with id:" << key;
575 return false;
576 }
577
578 // Other backends support a wrong structure in profile descriptor list. In order to make
579 // WinRT accept the list without breaking existing apps we have to repair this structure.
580 if (key == QBluetoothServiceInfo::BluetoothProfileDescriptorList) {
581 if (!repairProfileDescriptorListIfNeeded(buffer)) {
582 qCWarning(QT_BT_WINRT) << Q_FUNC_INFO << "Error while checking/repairing structure of profile descriptor list";
583 return false;
584 }
585 }
586
587 hr = writer->WriteBuffer(buffer.Get());
588 Q_ASSERT_SUCCEEDED(hr);
589
590 hr = writer->DetachBuffer(&buffer);
591 Q_ASSERT_SUCCEEDED(hr);
592
593 boolean replaced;
594 hr = rawAttributes->Insert(key, buffer.Get(), &replaced);
595 Q_ASSERT_SUCCEEDED(hr);
596 Q_ASSERT(!replaced);
597 qCDebug(QT_BT_WINRT) << Q_FUNC_INFO << "Registered attribute" << QString::number(key, 16).rightJustified(4, '0') << "with value" << attribute;
598 }
599 return true;
600}
601
602QT_END_NAMESPACE
603

Warning: That file was not part of the compilation database. It may have many parsing errors.