Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbluetoothsocket_winrt.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QtBluetooth/QBluetoothLocalDevice>
8#include <QtBluetooth/qbluetoothdeviceinfo.h>
9#include <QtBluetooth/qbluetoothserviceinfo.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtCore/QPointer>
12#include <QtCore/private/qfunctions_winrt_p.h>
13
14#include <robuffer.h>
15#include <windows.devices.bluetooth.h>
16#include <windows.networking.sockets.h>
17#include <windows.storage.streams.h>
18#include <wrl.h>
19
20using namespace Microsoft::WRL;
21using namespace Microsoft::WRL::Wrappers;
23using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
24using namespace ABI::Windows::Foundation;
25using namespace ABI::Windows::Foundation::Collections;
26using namespace ABI::Windows::Networking;
27using namespace ABI::Windows::Networking::Sockets;
28using namespace ABI::Windows::Storage::Streams;
29
30typedef IAsyncOperationWithProgressCompletedHandler<IBuffer *, UINT32> SocketReadCompletedHandler;
31typedef IAsyncOperationWithProgress<IBuffer *, UINT32> IAsyncBufferOperation;
32
34
35Q_DECLARE_LOGGING_CATEGORY(QT_BT_WINDOWS)
36
38{
40 {
41 HRESULT hr;
42 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
43 &bufferFactory);
44 Q_ASSERT_SUCCEEDED(hr);
45 }
46
47 ComPtr<IBufferFactory> bufferFactory;
48};
50
51#define READ_BUFFER_SIZE 65536
52
53static inline QString qt_QStringFromHString(const HString &string)
54{
55 UINT32 length;
56 PCWSTR rawString = string.GetRawBuffer(&length);
57 if (length > INT_MAX)
58 length = INT_MAX;
59 return QString::fromWCharArray(rawString, int(length));
60}
61
62static qint64 writeIOStream(ComPtr<IOutputStream> stream, const char *data, qint64 len)
63{
64 ComPtr<IBuffer> tempBuffer;
65 if (len > UINT32_MAX) {
66 qCWarning(QT_BT_WINDOWS) << "writeIOStream can only write up to" << UINT32_MAX << "bytes.";
67 len = UINT32_MAX;
68 }
69 quint32 ulen = static_cast<quint32>(len);
70 HRESULT hr = g->bufferFactory->Create(ulen, &tempBuffer);
71 Q_ASSERT_SUCCEEDED(hr);
72 hr = tempBuffer->put_Length(ulen);
73 Q_ASSERT_SUCCEEDED(hr);
74 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
75 hr = tempBuffer.As(&byteArrayAccess);
76 Q_ASSERT_SUCCEEDED(hr);
77 byte *bytes;
78 hr = byteArrayAccess->Buffer(&bytes);
79 Q_ASSERT_SUCCEEDED(hr);
80 memcpy(bytes, data, ulen);
81 ComPtr<IAsyncOperationWithProgress<UINT32, UINT32>> op;
82 hr = stream->WriteAsync(tempBuffer.Get(), &op);
83 RETURN_IF_FAILED("Failed to write to stream", return -1);
84 UINT32 bytesWritten;
85 hr = QWinRTFunctions::await(op, &bytesWritten);
86 RETURN_IF_FAILED("Failed to write to stream", return -1);
87 return bytesWritten;
88}
89
90class SocketWorker : public QObject
91{
93public:
95 {
96 }
97
99 {
100 }
101 void close()
102 {
103 m_shuttingDown = true;
104 if (m_readOp) {
105 onReadyRead(m_readOp.Get(), Canceled);
106 ComPtr<IAsyncInfo> info;
107 HRESULT hr = m_readOp.As(&info);
108 Q_ASSERT_SUCCEEDED(hr);
109 if (info) {
110 hr = info->Cancel();
111 Q_ASSERT_SUCCEEDED(hr);
112 hr = info->Close();
113 Q_ASSERT_SUCCEEDED(hr);
114 }
115 m_readOp.Reset();
116 }
117 }
118
119signals:
120 void newDataReceived(const QList<QByteArray> &data);
122
123public slots:
125 {
126 const QList<QByteArray> newData = std::move(m_pendingData);
127 m_pendingData.clear();
128 emit newDataReceived(newData);
129 }
130
131public:
133 {
134 ComPtr<IBuffer> tempBuffer;
135 HRESULT hr = g->bufferFactory->Create(READ_BUFFER_SIZE, &tempBuffer);
136 Q_ASSERT_SUCCEEDED(hr);
137 ComPtr<IInputStream> stream;
138 hr = m_socket->get_InputStream(&stream);
139 Q_ASSERT_SUCCEEDED(hr);
140 hr = stream->ReadAsync(tempBuffer.Get(), READ_BUFFER_SIZE, InputStreamOptions_Partial, m_readOp.GetAddressOf());
141 Q_ASSERT_SUCCEEDED(hr);
142 QPointer<SocketWorker> thisPtr(this);
143 hr = m_readOp->put_Completed(
144 Callback<SocketReadCompletedHandler>([thisPtr](IAsyncBufferOperation *asyncInfo,
145 AsyncStatus status) {
146 if (thisPtr)
147 return thisPtr->onReadyRead(asyncInfo, status);
148 return S_OK;
149 }).Get());
150 Q_ASSERT_SUCCEEDED(hr);
151 }
152
153 HRESULT onReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status)
154 {
155 if (m_shuttingDown)
156 return S_OK;
157
158 if (asyncInfo == m_readOp.Get())
159 m_readOp.Reset();
160 else
161 Q_ASSERT(false);
162
163 // A read in UnconnectedState will close the socket and return -1 and thus tell the caller,
164 // that the connection was closed. The socket cannot be closed here, as the subsequent read
165 // might fail then.
166 if (status == Error || status == Canceled) {
168 return S_OK;
169 }
170
171 ComPtr<IBuffer> tempBuffer;
172 HRESULT hr = asyncInfo->GetResults(&tempBuffer);
173 if (FAILED(hr)) {
174 qErrnoWarning(hr, "Failed to get read results buffer");
176 return S_OK;
177 }
178
179 UINT32 bufferLength;
180 hr = tempBuffer->get_Length(&bufferLength);
181 if (FAILED(hr)) {
182 qErrnoWarning(hr, "Failed to get buffer length");
184 return S_OK;
185 }
186 // A zero sized buffer length signals, that the remote host closed the connection. The socket
187 // cannot be closed though, as the following read might have socket descriptor -1 and thus and
188 // the closing of the socket won't be communicated to the caller. So only the error is set. The
189 // actual socket close happens inside of read.
190 if (!bufferLength) {
192 return S_OK;
193 }
194
195 ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess;
196 hr = tempBuffer.As(&byteArrayAccess);
197 if (FAILED(hr)) {
198 qErrnoWarning(hr, "Failed to get cast buffer");
200 return S_OK;
201 }
202 byte *data;
203 hr = byteArrayAccess->Buffer(&data);
204 if (FAILED(hr)) {
205 qErrnoWarning(hr, "Failed to access buffer data");
207 return S_OK;
208 }
209
210 QByteArray newData(reinterpret_cast<const char*>(data), int(bufferLength));
211 if (m_pendingData.isEmpty())
212 QMetaObject::invokeMethod(this, "notifyAboutNewData", Qt::QueuedConnection);
213 m_pendingData << newData;
214
215 UINT32 readBufferLength;
216 ComPtr<IInputStream> stream;
217 hr = m_socket->get_InputStream(&stream);
218 if (FAILED(hr)) {
219 qErrnoWarning(hr, "Failed to obtain input stream");
221 return S_OK;
222 }
223
224 // Reuse the stream buffer
225 hr = tempBuffer->get_Capacity(&readBufferLength);
226 if (FAILED(hr)) {
227 qErrnoWarning(hr, "Failed to get buffer capacity");
229 return S_OK;
230 }
231 hr = tempBuffer->put_Length(0);
232 if (FAILED(hr)) {
233 qErrnoWarning(hr, "Failed to set buffer length");
235 return S_OK;
236 }
237
238 hr = stream->ReadAsync(tempBuffer.Get(), readBufferLength, InputStreamOptions_Partial, &m_readOp);
239 if (FAILED(hr)) {
240 qErrnoWarning(hr, "onReadyRead(): Could not read into socket stream buffer.");
242 return S_OK;
243 }
244 QPointer<SocketWorker> thisPtr(this);
245 hr = m_readOp->put_Completed(
246 Callback<SocketReadCompletedHandler>([thisPtr](IAsyncBufferOperation *asyncInfo,
247 AsyncStatus status) {
248 if (thisPtr)
249 return thisPtr->onReadyRead(asyncInfo, status);
250 return S_OK;
251 }).Get());
252 if (FAILED(hr)) {
253 qErrnoWarning(hr, "onReadyRead(): Failed to set socket read callback.");
255 return S_OK;
256 }
257 return S_OK;
258 }
259
260 void setSocket(ComPtr<IStreamSocket> socket) { m_socket = socket; }
261
262private:
263 ComPtr<IStreamSocket> m_socket;
264 QList<QByteArray> m_pendingData;
265 bool m_shuttingDown = false;
266
267 ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> m_readOp;
268};
269
271 : m_worker(new SocketWorker())
272{
273 mainThreadCoInit(this);
276 this, &QBluetoothSocketPrivateWinRT::handleNewData, Qt::QueuedConnection);
278 this, &QBluetoothSocketPrivateWinRT::handleError, Qt::QueuedConnection);
279}
280
286
288{
289 if (socket != -1) {
290 if (type == socketType)
291 return true;
292 m_socketObject = nullptr;
293 socket = -1;
294 }
297 return false;
298
299 HRESULT hr;
300 hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Networking_Sockets_StreamSocket).Get(), &m_socketObject);
301 if (FAILED(hr) || !m_socketObject) {
302 qErrnoWarning(hr, "ensureNativeSocket: Could not create socket instance");
303 return false;
304 }
307
308 return true;
309}
310
312 const QString &serviceName,
313 QIODevice::OpenMode openMode)
314{
315 Q_Q(QBluetoothSocket);
316
317 if (socket == -1 && !ensureNativeSocket(socketType)) {
318 errorString = QBluetoothSocket::tr("Unknown socket error");
320 return;
321 }
322
323 HStringReference serviceNameReference(reinterpret_cast<LPCWSTR>(serviceName.utf16()));
324
325 HRESULT hr = m_socketObject->ConnectAsync(hostName.Get(), serviceNameReference.Get(), &m_connectOp);
326 if (hr == E_ACCESSDENIED) {
327 qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
328 "Please check your manifest capabilities.");
330 return;
331 }
332 Q_ASSERT_SUCCEEDED(hr);
333
335 requestedOpenMode = openMode;
336 hr = m_connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>(
337 this, &QBluetoothSocketPrivateWinRT::handleConnectOpFinished).Get());
338 RETURN_VOID_IF_FAILED("connectToHostByName: Could not register \"connectOp\" callback");
339 return;
340}
341
343{
344 Q_Q(QBluetoothSocket);
345
346 if (socket == -1 && !ensureNativeSocket(socketType)) {
347 errorString = QBluetoothSocket::tr("Unknown socket error");
349 return;
350 }
351
352 const QString addressString = address.toString();
353 HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
354 ComPtr<IHostNameFactory> hostNameFactory;
355 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
356 &hostNameFactory);
357 Q_ASSERT_SUCCEEDED(hr);
358 ComPtr<IHostName> remoteHost;
359 hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
360 RETURN_VOID_IF_FAILED("QBluetoothSocketPrivateWinRT::connectToService: Could not create hostname.");
361 const QString portString = QString::number(port);
362 connectToService(remoteHost, portString, openMode);
363}
364
366 const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
367{
368 Q_Q(QBluetoothSocket);
369
372 qCWarning(QT_BT_WINDOWS) << "QBluetoothSocket::connectToService called on busy socket";
373 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
375 return;
376 }
377
378 // we are checking the service protocol and not socketType()
379 // socketType will change in ensureNativeSocket()
380 if (service.socketProtocol() != QBluetoothServiceInfo::RfcommProtocol) {
381 errorString = QBluetoothSocket::tr("Socket type not supported");
383 return;
384 }
385
386 const QString connectionHostName = service.attribute(0xBEEF).toString();
387 const QString connectionServiceName = service.attribute(0xBEF0).toString();
388 if (service.protocolServiceMultiplexer() > 0) {
389 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
390
392 errorString = QBluetoothSocket::tr("Unknown socket error");
394 return;
395 }
396 connectToServiceHelper(service.device().address(),
397 quint16(service.protocolServiceMultiplexer()), openMode);
398 } else if (!connectionHostName.isEmpty() && !connectionServiceName.isEmpty()) {
399 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
401 errorString = QBluetoothSocket::tr("Unknown socket error");
403 return;
404 }
405 HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(connectionHostName.utf16()));
406 ComPtr<IHostNameFactory> hostNameFactory;
407 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
408 &hostNameFactory);
409 Q_ASSERT_SUCCEEDED(hr);
410 ComPtr<IHostName> remoteHost;
411 hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
412 connectToService(remoteHost, connectionServiceName, openMode);
413 } else if (service.serverChannel() > 0) {
414 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
415
417 errorString = QBluetoothSocket::tr("Unknown socket error");
419 return;
420 }
421 connectToServiceHelper(service.device().address(), quint16(service.serverChannel()),
422 openMode);
423 } else {
424 // try doing service discovery to see if we can find the socket
425 if (service.serviceUuid().isNull()
426 && !service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort)) {
427 qCWarning(QT_BT_WINDOWS) << "No port, no PSM, and no UUID provided. Unable to connect";
428 return;
429 }
430 qCDebug(QT_BT_WINDOWS) << "Need a port/psm, doing discovery";
431 q->doDeviceDiscovery(service, openMode);
432 }
433}
434
436 const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
437{
438 Q_Q(QBluetoothSocket);
439
441 qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
442 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
444 return;
445 }
446
447 if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
448 errorString = QBluetoothSocket::tr("Socket type not supported");
450 return;
451 }
452
453 QBluetoothServiceInfo service;
455 service.setDevice(device);
456 service.setServiceUuid(uuid);
457 q->doDeviceDiscovery(service, openMode);
458}
459
461 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
462{
463 Q_Q(QBluetoothSocket);
464
466 qCWarning(QT_BT_WINDOWS) << "QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
467 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
469 return;
470 }
471
472 if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
473 errorString = QBluetoothSocket::tr("Socket type not supported");
475 return;
476 }
477
479}
480
482{
483 Q_Q(QBluetoothSocket);
485 return;
486
488 this, &QBluetoothSocketPrivateWinRT::handleNewData);
490 this, &QBluetoothSocketPrivateWinRT::handleError);
491 m_worker->close();
493
494 if (socket != -1) {
495 m_socketObject = nullptr;
496 socket = -1;
497 }
498
499 const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
501 if (wasConnected) {
502 q->setOpenMode(QIODevice::NotOpen);
503 emit q->readChannelFinished();
504 }
505}
506
508{
510 if (address.isNull())
511 return QString();
512
514 return device.name();
515}
516
518{
519 // WinAPI returns address with parentheses around it. We need to remove
520 // them to convert to QBluetoothAddress.
522 if (addressStr.startsWith(QLatin1Char('(')) && addressStr.endsWith(QLatin1Char(')'))) {
523 addressStr = addressStr.sliced(1, addressStr.size() - 2);
524 }
525 return addressStr;
526}
527
529{
530 if (!m_socketObject)
531 return QBluetoothAddress();
532
533 HRESULT hr;
534 ComPtr<IStreamSocketInformation> info;
535 hr = m_socketObject->get_Information(&info);
536 Q_ASSERT_SUCCEEDED(hr);
537 ComPtr<IHostName> localHost;
538 hr = info->get_LocalAddress(&localHost);
539 Q_ASSERT_SUCCEEDED(hr);
540 if (localHost) {
541 HString localAddress;
542 hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
543 Q_ASSERT_SUCCEEDED(hr);
545 }
546 return QBluetoothAddress();
547}
548
550{
551 if (!m_socketObject)
552 return 0;
553
554 HRESULT hr;
555 ComPtr<IStreamSocketInformation> info;
556 hr = m_socketObject->get_Information(&info);
557 Q_ASSERT_SUCCEEDED(hr);
558 HString localPortString;
559 hr = info->get_LocalPort(localPortString.GetAddressOf());
560 Q_ASSERT_SUCCEEDED(hr);
561 bool ok = true;
562 const uint port = qt_QStringFromHString(localPortString).toUInt(&ok);
563 if (!ok || port > UINT16_MAX) {
564 qCWarning(QT_BT_WINDOWS) << "Unexpected local port";
565 return 0;
566 }
567 return quint16(port);
568}
569
571{
572 if (!m_socketObject)
573 return QString();
574
575 HRESULT hr;
576 ComPtr<IStreamSocketInformation> info;
577 hr = m_socketObject->get_Information(&info);
578 Q_ASSERT_SUCCEEDED(hr);
579 ComPtr<IHostName> remoteHost;
580 hr = info->get_RemoteHostName(&remoteHost);
581 Q_ASSERT_SUCCEEDED(hr);
582 if (remoteHost) {
583 HString remoteHostName;
584 hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
585 Q_ASSERT_SUCCEEDED(hr);
586 return qt_QStringFromHString(remoteHostName);
587 }
588 return {};
589}
590
592{
593 if (!m_socketObject)
594 return QBluetoothAddress();
595
596 HRESULT hr;
597 ComPtr<IStreamSocketInformation> info;
598 hr = m_socketObject->get_Information(&info);
599 Q_ASSERT_SUCCEEDED(hr);
600 ComPtr<IHostName> remoteHost;
601 hr = info->get_RemoteAddress(&remoteHost);
602 Q_ASSERT_SUCCEEDED(hr);
603 if (remoteHost) {
604 HString remoteAddress;
605 hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
606 Q_ASSERT_SUCCEEDED(hr);
607 return QBluetoothAddress(fromWinApiAddress(std::move(remoteAddress)));
608 }
609 return QBluetoothAddress();
610}
611
613{
614 if (!m_socketObject)
615 return 0;
616
617 HRESULT hr;
618 ComPtr<IStreamSocketInformation> info;
619 hr = m_socketObject->get_Information(&info);
620 Q_ASSERT_SUCCEEDED(hr);
621 HString remotePortString;
622 hr = info->get_RemotePort(remotePortString.GetAddressOf());
623 Q_ASSERT_SUCCEEDED(hr);
624 bool ok = true;
625 const uint port = qt_QStringFromHString(remotePortString).toUInt(&ok);
626 if (!ok || port > UINT16_MAX) {
627 qCWarning(QT_BT_WINDOWS) << "Unexpected remote port";
628 return 0;
629 }
630 return quint16(port);
631}
632
634{
635 Q_Q(QBluetoothSocket);
636
638 errorString = QBluetoothSocket::tr("Cannot write while not connected");
640 return -1;
641 }
642
643 ComPtr<IOutputStream> stream;
644 HRESULT hr;
645 hr = m_socketObject->get_OutputStream(&stream);
646 Q_ASSERT_SUCCEEDED(hr);
647
649 if (bytesWritten < 0) {
650 qCWarning(QT_BT_WINDOWS) << "Socket::writeData: " << state;
651 errorString = QBluetoothSocket::tr("Cannot read while not connected");
653 }
654
655 emit q->bytesWritten(bytesWritten);
656 return bytesWritten;
657}
658
660{
661 Q_Q(QBluetoothSocket);
662
664 errorString = QBluetoothSocket::tr("Cannot read while not connected");
666 return -1;
667 }
668
669 if (!rxBuffer.isEmpty()) {
670 if (maxSize > INT_MAX)
671 maxSize = INT_MAX;
672 return rxBuffer.read(data, int(maxSize));
673 }
674
675 return 0;
676}
677
682
684 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
685{
686 Q_UNUSED(socketDescriptor);
688 Q_UNUSED(socketState);
690 qCWarning(QT_BT_WINDOWS) << "No socket descriptor support on WinRT.";
691 return false;
692}
693
695 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
696{
697 Q_Q(QBluetoothSocket);
699 return false;
700
701 m_socketObject = socketPtr;
704 q->setSocketState(socketState);
707 // QBluetoothSockets are unbuffered on Windows
708 q->setOpenMode(openMode | QIODevice::Unbuffered);
709 return true;
710}
711
716
718{
719 return 0; // nothing because always unbuffered
720}
721
726
727void QBluetoothSocketPrivateWinRT::handleNewData(const QList<QByteArray> &data)
728{
729 // Defer putting the data into the list until the next event loop iteration
730 // (where the readyRead signal is emitted as well)
731 QMetaObject::invokeMethod(this, "addToPendingData", Qt::QueuedConnection,
732 Q_ARG(QList<QByteArray>, data));
733}
734
735void QBluetoothSocketPrivateWinRT::handleError(QBluetoothSocket::SocketError error)
736{
737 Q_Q(QBluetoothSocket);
738 switch (error) {
740 errorString = QBluetoothSocket::tr("Network error");
741 break;
743 errorString = QBluetoothSocket::tr("Remote host closed connection");
744 break;
745 default:
746 errorString = QBluetoothSocket::tr("Unknown socket error");
747 }
748
749 q->setSocketError(error);
750 const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
752 if (wasConnected) {
753 q->setOpenMode(QIODevice::NotOpen);
754 emit q->readChannelFinished();
755 }
756}
757
759{
760 Q_Q(QBluetoothSocket);
761 QMutexLocker locker(&m_readMutex);
763 for (const QByteArray &newData : data) {
764 char *writePointer = rxBuffer.reserve(newData.length());
765 memcpy(writePointer, newData.data(), size_t(newData.length()));
766 }
767 locker.unlock();
768 emit q->readyRead();
769}
770
771HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action, ABI::Windows::Foundation::AsyncStatus status)
772{
773 Q_Q(QBluetoothSocket);
774 if (status != Completed || !m_connectOp) { // Protect against a late callback
775 errorString = QBluetoothSocket::tr("Unknown socket error");
778 return S_OK;
779 }
780
781 HRESULT hr = action->GetResults();
782 switch (hr) {
783
784 // A connection attempt failed because the connected party did not properly respond after a
785 // period of time, or established connection failed because connected host has failed to respond.
786 case HRESULT_FROM_WIN32(WSAETIMEDOUT):
787 errorString = QBluetoothSocket::tr("Connection timed out");
790 return S_OK;
791 // A socket operation was attempted to an unreachable host.
792 case HRESULT_FROM_WIN32(WSAEHOSTUNREACH):
793 errorString = QBluetoothSocket::tr("Host not reachable");
796 return S_OK;
797 // No connection could be made because the target machine actively refused it.
798 case HRESULT_FROM_WIN32(WSAECONNREFUSED):
799 errorString = QBluetoothSocket::tr("Host refused connection");
802 return S_OK;
803 default:
804 if (FAILED(hr)) {
805 errorString = QBluetoothSocket::tr("Unknown socket error");
808 return S_OK;
809 }
810 }
811
812 // The callback might be triggered several times if we do not cancel/reset it here
813 if (m_connectOp) {
814 ComPtr<IAsyncInfo> info;
815 hr = m_connectOp.As(&info);
816 Q_ASSERT_SUCCEEDED(hr);
817 if (info) {
818 hr = info->Cancel();
819 Q_ASSERT_SUCCEEDED(hr);
820 hr = info->Close();
821 Q_ASSERT_SUCCEEDED(hr);
822 }
823 m_connectOp.Reset();
824 }
825
826 // QBluetoothSockets are unbuffered on Windows
827 q->setOpenMode(requestedOpenMode | QIODevice::Unbuffered);
830
831 return S_OK;
832}
833
835
836#include "qbluetoothsocket_winrt.moc"
IOBluetoothDevice * device
\inmodule QtBluetooth
\inmodule QtBluetooth
\inmodule QtBluetooth
\inmodule QtBluetooth
Protocol
This enum describes the socket protocol used by the service.
QBluetoothSocket::OpenMode openMode
QBluetooth::SecurityFlags secFlags
QBluetoothServiceInfo::Protocol socketType
QBluetoothSocket::SocketState state
void connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) override
qint64 writeData(const char *data, qint64 maxSize) override
qint64 readData(char *data, qint64 maxSize) override
Q_INVOKABLE void addToPendingData(const QList< QByteArray > &data)
QBluetoothAddress peerAddress() const override
Microsoft::WRL::ComPtr< ABI::Windows::Foundation::IAsyncAction > m_connectOp
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override
bool setSocketDescriptor(Microsoft::WRL::ComPtr< ABI::Windows::Networking::Sockets::IStreamSocket > socket, QBluetoothServiceInfo::Protocol socketType, QBluetoothSocket::SocketState socketState=QBluetoothSocket::SocketState::ConnectedState, QBluetoothSocket::OpenMode openMode=QBluetoothSocket::ReadWrite) override
Microsoft::WRL::ComPtr< ABI::Windows::Networking::Sockets::IStreamSocket > m_socketObject
QBluetoothAddress localAddress() const override
void connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode) override
\inmodule QtBluetooth
SocketState
This enum describes the state of the Bluetooth socket.
SocketError
This enum describes Bluetooth socket error types.
\inmodule QtBluetooth
\inmodule QtCore
Definition qbytearray.h:57
bool isEmpty() const noexcept
Definition qlist.h:401
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qmutex.h:313
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:319
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
qsizetype read(char *target, qsizetype size)
char * reserve(qsizetype size)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
Definition qstring.cpp:6995
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
Q_INVOKABLE void notifyAboutNewData()
HRESULT onReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status)
void setSocket(ComPtr< IStreamSocket > socket)
void newDataReceived(const QList< QByteArray > &data)
void socketErrorOccured(QBluetoothSocket::SocketError error)
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
@ QueuedConnection
static qint64 writeIOStream(ComPtr< IOutputStream > stream, const char *data, qint64 len)
IAsyncOperationWithProgressCompletedHandler< IBuffer *, UINT32 > SocketReadCompletedHandler
#define READ_BUFFER_SIZE
IAsyncOperationWithProgress< IBuffer *, UINT32 > IAsyncBufferOperation
static QString fromWinApiAddress(HString address)
static QString qt_QStringFromHString(const HString &string)
void mainThreadCoInit(void *caller)
void mainThreadCoUninit(void *caller)
DBusConnection const char DBusError * error
EGLStreamKHR stream
EGLOutputPortEXT port
static QT_BEGIN_NAMESPACE const char * socketType(QSocketNotifier::Type type)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define Q_ARG(Type, data)
Definition qobjectdefs.h:63
GLenum GLsizei GLuint GLint * bytesWritten
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLboolean GLboolean g
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define tr(X)
#define Q_OBJECT
#define Q_INVOKABLE
#define slots
#define signals
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
ptrdiff_t qintptr
Definition qtypes.h:166
long HRESULT
myObject disconnect()
[26]
QTcpSocket * socket
[1]
QHostInfo info
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
ComPtr< IBufferFactory > bufferFactory