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>
15#include <windows.devices.bluetooth.h>
16#include <windows.networking.sockets.h>
17#include <windows.storage.streams.h>
20using namespace Microsoft::WRL;
21using namespace Microsoft::WRL::Wrappers;
22using namespace ABI::Windows::Devices::Bluetooth;
23using namespace ABI::Windows::Devices::Bluetooth::Rfcomm;
24using namespace ABI::Windows::Foundation;
25using namespace ABI::Windows::Foundation::Collections;
27using namespace ABI::Windows::Networking::Sockets;
42 hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(),
44 Q_ASSERT_SUCCEEDED(hr);
51#define READ_BUFFER_SIZE 65536
56 PCWSTR rawString = string.GetRawBuffer(&length);
59 return QString::fromWCharArray(rawString,
int(length));
64 ComPtr<IBuffer> tempBuffer;
65 if (len > UINT32_MAX) {
66 qCWarning(QT_BT_WINDOWS) <<
"writeIOStream can only write up to" << UINT32_MAX <<
"bytes.";
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);
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);
85 hr = QWinRTFunctions::await(op, &bytesWritten);
86 RETURN_IF_FAILED(
"Failed to write to stream",
return -1);
240 qErrnoWarning(
hr,
"onReadyRead(): Could not read into socket stream buffer.");
253 qErrnoWarning(
hr,
"onReadyRead(): Failed to set socket read callback.");
264 QList<QByteArray> m_pendingData;
265 bool m_shuttingDown =
false;
267 ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> m_readOp;
270QBluetoothSocketPrivateWinRT::QBluetoothSocketPrivateWinRT()
271 : m_worker(
new SocketWorker())
274 secFlags = QBluetooth::Security::NoSecurity;
275 connect(m_worker, &SocketWorker::newDataReceived,
276 this, &QBluetoothSocketPrivateWinRT::handleNewData, Qt::QueuedConnection);
277 connect(m_worker, &SocketWorker::socketErrorOccured,
278 this, &QBluetoothSocketPrivateWinRT::handleError, Qt::QueuedConnection);
281QBluetoothSocketPrivateWinRT::~QBluetoothSocketPrivateWinRT()
287bool QBluetoothSocketPrivateWinRT::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
290 if (type == socketType)
292 m_socketObject =
nullptr;
296 if (socketType != QBluetoothServiceInfo::RfcommProtocol)
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");
305 socket = qintptr(m_socketObject.Get());
306 m_worker->setSocket(m_socketObject);
311void QBluetoothSocketPrivateWinRT::connectToService(
Microsoft::
WRL::
ComPtr<IHostName> hostName,
312 const QString &serviceName,
313 QIODevice::OpenMode openMode)
315 Q_Q(QBluetoothSocket);
317 if (socket == -1 && !ensureNativeSocket(socketType)) {
318 errorString = QBluetoothSocket::tr(
"Unknown socket error");
319 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
323 HStringReference serviceNameReference(
reinterpret_cast<LPCWSTR>(serviceName.utf16()));
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.");
329 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
332 Q_ASSERT_SUCCEEDED(hr);
334 q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
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");
342void QBluetoothSocketPrivateWinRT::connectToServiceHelper(
const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
344 Q_Q(QBluetoothSocket);
346 if (socket == -1 && !ensureNativeSocket(socketType)) {
347 errorString = QBluetoothSocket::tr(
"Unknown socket error");
348 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
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(),
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);
365void QBluetoothSocketPrivateWinRT::connectToService(
366 const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
368 Q_Q(QBluetoothSocket);
370 if (q->state() != QBluetoothSocket::SocketState::UnconnectedState
371 && q->state() != QBluetoothSocket::SocketState::ServiceLookupState) {
372 qCWarning(QT_BT_WINDOWS) <<
"QBluetoothSocket::connectToService called on busy socket";
373 errorString = QBluetoothSocket::tr(
"Trying to connect while connection is in progress");
374 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
380 if (service.socketProtocol() != QBluetoothServiceInfo::RfcommProtocol) {
381 errorString = QBluetoothSocket::tr(
"Socket type not supported");
382 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
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);
391 if (!ensureNativeSocket(QBluetoothServiceInfo::L2capProtocol)) {
392 errorString = QBluetoothSocket::tr(
"Unknown socket error");
393 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
396 connectToServiceHelper(service.device().address(),
397 quint16(service.protocolServiceMultiplexer()), openMode);
398 }
else if (!connectionHostName.isEmpty() && !connectionServiceName.isEmpty()) {
399 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
400 if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
401 errorString = QBluetoothSocket::tr(
"Unknown socket error");
402 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
405 HStringReference hostNameRef(
reinterpret_cast<LPCWSTR>(connectionHostName.utf16()));
406 ComPtr<IHostNameFactory> hostNameFactory;
407 HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
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);
416 if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
417 errorString = QBluetoothSocket::tr(
"Unknown socket error");
418 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
421 connectToServiceHelper(service.device().address(), quint16(service.serverChannel()),
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";
430 qCDebug(QT_BT_WINDOWS) <<
"Need a port/psm, doing discovery";
431 q->doDeviceDiscovery(service, openMode);
435void QBluetoothSocketPrivateWinRT::connectToService(
436 const QBluetoothAddress &address,
const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
438 Q_Q(QBluetoothSocket);
440 if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
441 qCWarning(QT_BT_WINDOWS) <<
"QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
442 errorString = QBluetoothSocket::tr(
"Trying to connect while connection is in progress");
443 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
447 if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
448 errorString = QBluetoothSocket::tr(
"Socket type not supported");
449 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
453 QBluetoothServiceInfo service;
454 QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice);
455 service.setDevice(device);
456 service.setServiceUuid(uuid);
457 q->doDeviceDiscovery(service, openMode);
460void QBluetoothSocketPrivateWinRT::connectToService(
461 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
463 Q_Q(QBluetoothSocket);
465 if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
466 qCWarning(QT_BT_WINDOWS) <<
"QBluetoothSocketPrivateWinRT::connectToService called on busy socket";
467 errorString = QBluetoothSocket::tr(
"Trying to connect while connection is in progress");
468 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
472 if (q->socketType() != QBluetoothServiceInfo::RfcommProtocol) {
473 errorString = QBluetoothSocket::tr(
"Socket type not supported");
474 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
478 connectToServiceHelper(address, port, openMode);
481void QBluetoothSocketPrivateWinRT::abort()
483 Q_Q(QBluetoothSocket);
484 if (state == QBluetoothSocket::SocketState::UnconnectedState)
487 disconnect(m_worker, &SocketWorker::newDataReceived,
488 this, &QBluetoothSocketPrivateWinRT::handleNewData);
489 disconnect(m_worker, &SocketWorker::socketErrorOccured,
490 this, &QBluetoothSocketPrivateWinRT::handleError);
492 m_worker->deleteLater();
495 m_socketObject =
nullptr;
499 const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
500 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
502 q->setOpenMode(QIODevice::NotOpen);
503 emit q->readChannelFinished();
507QString QBluetoothSocketPrivateWinRT::localName()
const
509 const QBluetoothAddress address = localAddress();
510 if (address.isNull())
513 QBluetoothLocalDevice device(address);
514 return device.name();
521 QString addressStr(qt_QStringFromHString(address));
522 if (addressStr.startsWith(QLatin1Char(
'(')) && addressStr.endsWith(QLatin1Char(
')'))) {
523 addressStr = addressStr.sliced(1, addressStr.size() - 2);
528QBluetoothAddress QBluetoothSocketPrivateWinRT::localAddress()
const
531 return QBluetoothAddress();
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);
541 HString localAddress;
542 hr = localHost->get_CanonicalName(localAddress.GetAddressOf());
543 Q_ASSERT_SUCCEEDED(hr);
544 return QBluetoothAddress(fromWinApiAddress(std::move(localAddress)));
546 return QBluetoothAddress();
549quint16 QBluetoothSocketPrivateWinRT::localPort()
const
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);
562 const uint port = qt_QStringFromHString(localPortString).toUInt(&ok);
563 if (!ok || port > UINT16_MAX) {
564 qCWarning(QT_BT_WINDOWS) <<
"Unexpected local port";
567 return quint16(port);
570QString QBluetoothSocketPrivateWinRT::peerName()
const
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);
583 HString remoteHostName;
584 hr = remoteHost->get_DisplayName(remoteHostName.GetAddressOf());
585 Q_ASSERT_SUCCEEDED(hr);
586 return qt_QStringFromHString(remoteHostName);
591QBluetoothAddress QBluetoothSocketPrivateWinRT::peerAddress()
const
594 return QBluetoothAddress();
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);
604 HString remoteAddress;
605 hr = remoteHost->get_CanonicalName(remoteAddress.GetAddressOf());
606 Q_ASSERT_SUCCEEDED(hr);
607 return QBluetoothAddress(fromWinApiAddress(std::move(remoteAddress)));
609 return QBluetoothAddress();
612quint16 QBluetoothSocketPrivateWinRT::peerPort()
const
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);
625 const uint port = qt_QStringFromHString(remotePortString).toUInt(&ok);
626 if (!ok || port > UINT16_MAX) {
627 qCWarning(QT_BT_WINDOWS) <<
"Unexpected remote port";
630 return quint16(port);
633qint64 QBluetoothSocketPrivateWinRT::writeData(
const char *data, qint64 maxSize)
635 Q_Q(QBluetoothSocket);
637 if (state != QBluetoothSocket::SocketState::ConnectedState) {
638 errorString = QBluetoothSocket::tr(
"Cannot write while not connected");
639 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
643 ComPtr<IOutputStream> stream;
645 hr = m_socketObject->get_OutputStream(&stream);
646 Q_ASSERT_SUCCEEDED(hr);
648 qint64 bytesWritten = writeIOStream(stream, data, maxSize);
649 if (bytesWritten < 0) {
650 qCWarning(QT_BT_WINDOWS) <<
"Socket::writeData: " << state;
651 errorString = QBluetoothSocket::tr(
"Cannot read while not connected");
652 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
655 emit q->bytesWritten(bytesWritten);
659qint64 QBluetoothSocketPrivateWinRT::readData(
char *data, qint64 maxSize)
661 Q_Q(QBluetoothSocket);
663 if (state != QBluetoothSocket::SocketState::ConnectedState) {
664 errorString = QBluetoothSocket::tr(
"Cannot read while not connected");
665 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
669 if (!rxBuffer.isEmpty()) {
670 if (maxSize > INT_MAX)
672 return rxBuffer.read(data,
int(maxSize));
678void QBluetoothSocketPrivateWinRT::close()
683bool QBluetoothSocketPrivateWinRT::setSocketDescriptor(
int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
684 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
686 Q_UNUSED(socketDescriptor);
687 Q_UNUSED(socketType);
688 Q_UNUSED(socketState);
690 qCWarning(QT_BT_WINDOWS) <<
"No socket descriptor support on WinRT.";
694bool QBluetoothSocketPrivateWinRT::setSocketDescriptor(ComPtr<IStreamSocket> socketPtr, QBluetoothServiceInfo::Protocol socketType,
695 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
697 Q_Q(QBluetoothSocket);
698 if (socketType != QBluetoothServiceInfo::RfcommProtocol || !socketPtr)
701 m_socketObject = socketPtr;
702 socket = qintptr(m_socketObject.Get());
703 m_worker->setSocket(m_socketObject);
704 q->setSocketState(socketState);
705 if (socketState == QBluetoothSocket::SocketState::ConnectedState)
706 m_worker->startReading();
708 q->setOpenMode(openMode | QIODevice::Unbuffered);
712qint64 QBluetoothSocketPrivateWinRT::bytesAvailable()
const
714 return rxBuffer.size();
717qint64 QBluetoothSocketPrivateWinRT::bytesToWrite()
const
722bool QBluetoothSocketPrivateWinRT::canReadLine()
const
724 return rxBuffer.canReadLine();
727void QBluetoothSocketPrivateWinRT::handleNewData(
const QList<QByteArray> &data)
731 QMetaObject::invokeMethod(
this,
"addToPendingData", Qt::QueuedConnection,
732 Q_ARG(QList<QByteArray>, data));
735void QBluetoothSocketPrivateWinRT::handleError(QBluetoothSocket::SocketError error)
737 Q_Q(QBluetoothSocket);
739 case QBluetoothSocket::SocketError::NetworkError:
740 errorString = QBluetoothSocket::tr(
"Network error");
742 case QBluetoothSocket::SocketError::RemoteHostClosedError:
743 errorString = QBluetoothSocket::tr(
"Remote host closed connection");
746 errorString = QBluetoothSocket::tr(
"Unknown socket error");
749 q->setSocketError(error);
750 const bool wasConnected = q->state() == QBluetoothSocket::SocketState::ConnectedState;
751 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
753 q->setOpenMode(QIODevice::NotOpen);
754 emit q->readChannelFinished();
758void QBluetoothSocketPrivateWinRT::addToPendingData(
const QList<QByteArray> &data)
760 Q_Q(QBluetoothSocket);
761 for (
const QByteArray &newData : data) {
762 char *writePointer = rxBuffer.reserve(newData.length());
763 memcpy(writePointer, newData.data(), size_t(newData.length()));
768HRESULT QBluetoothSocketPrivateWinRT::handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action, ABI::Windows::Foundation::AsyncStatus status)
770 Q_Q(QBluetoothSocket);
771 if (status != Completed || !m_connectOp) {
772 errorString = QBluetoothSocket::tr(
"Unknown socket error");
773 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
774 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
778 HRESULT hr = action->GetResults();
783 case HRESULT_FROM_WIN32(WSAETIMEDOUT):
784 errorString = QBluetoothSocket::tr(
"Connection timed out");
785 q->setSocketError(QBluetoothSocket::SocketError::NetworkError);
786 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
789 case HRESULT_FROM_WIN32(WSAEHOSTUNREACH):
790 errorString = QBluetoothSocket::tr(
"Host not reachable");
791 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
792 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
795 case HRESULT_FROM_WIN32(WSAECONNREFUSED):
796 errorString = QBluetoothSocket::tr(
"Host refused connection");
797 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
798 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
802 errorString = QBluetoothSocket::tr(
"Unknown socket error");
803 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
804 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
811 ComPtr<IAsyncInfo> info;
812 hr = m_connectOp.As(&info);
813 Q_ASSERT_SUCCEEDED(hr);
816 Q_ASSERT_SUCCEEDED(hr);
818 Q_ASSERT_SUCCEEDED(hr);
824 q->setOpenMode(requestedOpenMode | QIODevice::Unbuffered);
825 q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
826 m_worker->startReading();
833#include "qbluetoothsocket_winrt.moc"
void socketErrorOccured(QBluetoothSocket::SocketError error)
static qint64 writeIOStream(ComPtr< IOutputStream > stream, const char *data, qint64 len)
IAsyncOperationWithProgress< IBuffer *, UINT32 > IAsyncBufferOperation
static QString fromWinApiAddress(HString address)
static QString qt_QStringFromHString(const HString &string)
IAsyncOperationWithProgressCompletedHandler< IBuffer *, UINT32 > SocketReadCompletedHandler
void mainThreadCoInit(void *caller)
void mainThreadCoUninit(void *caller)
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher)
ComPtr< IBufferFactory > bufferFactory