qbluetoothsocket_winrt: Use recommended service connection approach if possible
MSDN documentation states that the recommended way of RFCOMM service connection is via connectionHostName and connectionServiceName (see https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommdeviceservice). So whenever possible, we should use this information from the native device service when connecting directly to the discovered service. As QBluetoothServiceInfo is basically just a wrapper for the attributes map this information is stored in its private pendant and extracted when a connection attempt is being made. Task-number: QTBUG-62520 Change-Id: I95be5df89a722531393b45fd136d37f302393ca8 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
This commit is contained in:
parent
ea85065cbb
commit
672ebe7690
|
|
@ -52,6 +52,7 @@
|
|||
#include <windows.devices.enumeration.h>
|
||||
#include <windows.devices.bluetooth.h>
|
||||
#include <windows.foundation.collections.h>
|
||||
#include <windows.networking.h>
|
||||
#include <windows.storage.streams.h>
|
||||
#include <wrl.h>
|
||||
|
||||
|
|
@ -208,6 +209,14 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
|
|||
hr = service->get_ConnectionServiceName(name.GetAddressOf());
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
|
||||
ComPtr<ABI::Windows::Networking::IHostName> host;
|
||||
hr = service->get_ConnectionHostName(host.GetAddressOf());
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
HString hostName;
|
||||
hr = host->get_RawName(hostName.GetAddressOf());
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
const QString qHostName = QString::fromWCharArray(WindowsGetStringRawBuffer(hostName.Get(),
|
||||
nullptr));
|
||||
ComPtr<IRfcommServiceId> id;
|
||||
hr = service->get_ServiceId(&id);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
|
@ -217,6 +226,8 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
|
|||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
QBluetoothServiceInfo info;
|
||||
info.setAttribute(0xBEEF, QVariant(qHostName));
|
||||
info.setAttribute(0xBEF0, QVariant(serviceName));
|
||||
info.setServiceName(serviceName);
|
||||
info.setServiceUuid(uuid);
|
||||
ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
|
||||
|
|
|
|||
|
|
@ -640,6 +640,13 @@ void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
|
|||
connectToService(service, d->openMode);
|
||||
d->discoveryAgent->deleteLater();
|
||||
d->discoveryAgent = nullptr;
|
||||
#ifdef QT_WINRT_BLUETOOTH
|
||||
} else if (!service.attribute(0xBEEF).isNull()
|
||||
&& !service.attribute(0xBEF0).isNull()) {
|
||||
connectToService(service, d->openMode);
|
||||
d->discoveryAgent->deleteLater();
|
||||
d->discoveryAgent = nullptr;
|
||||
#endif
|
||||
} else {
|
||||
qCDebug(QT_BT) << "Could not find port/psm for potential remote service";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,10 +359,11 @@ bool QBluetoothSocketPrivateWinRT::ensureNativeSocket(QBluetoothServiceInfo::Pro
|
|||
return true;
|
||||
}
|
||||
|
||||
void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
|
||||
void QBluetoothSocketPrivateWinRT::connectToService(Microsoft::WRL::ComPtr<IHostName> hostName,
|
||||
const QString &serviceName,
|
||||
QIODevice::OpenMode openMode)
|
||||
{
|
||||
Q_Q(QBluetoothSocket);
|
||||
Q_UNUSED(openMode);
|
||||
|
||||
if (socket == -1 && !ensureNativeSocket(socketType)) {
|
||||
errorString = QBluetoothSocket::tr("Unknown socket error");
|
||||
|
|
@ -370,20 +371,9 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
|
|||
return;
|
||||
}
|
||||
|
||||
const QString addressString = address.toString();
|
||||
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
|
||||
ComPtr<IHostNameFactory> hostNameFactory;
|
||||
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
|
||||
&hostNameFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<IHostName> remoteHost;
|
||||
hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
|
||||
RETURN_VOID_IF_FAILED("QBluetoothSocketPrivateWinRT::connectToService: Could not create hostname.");
|
||||
HStringReference serviceNameReference(reinterpret_cast<LPCWSTR>(serviceName.utf16()));
|
||||
|
||||
const QString portString = QString::number(port);
|
||||
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
|
||||
|
||||
hr = m_socketObject->ConnectAsync(remoteHost.Get(), portReference.Get(), &m_connectOp);
|
||||
HRESULT hr = m_socketObject->ConnectAsync(hostName.Get(), serviceNameReference.Get(), &m_connectOp);
|
||||
if (hr == E_ACCESSDENIED) {
|
||||
qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
|
||||
"Please check your manifest capabilities.");
|
||||
|
|
@ -404,6 +394,29 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
|
|||
Q_ASSERT_SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
|
||||
{
|
||||
Q_Q(QBluetoothSocket);
|
||||
|
||||
if (socket == -1 && !ensureNativeSocket(socketType)) {
|
||||
errorString = QBluetoothSocket::tr("Unknown socket error");
|
||||
q->setSocketError(QBluetoothSocket::UnknownSocketError);
|
||||
return;
|
||||
}
|
||||
|
||||
const QString addressString = address.toString();
|
||||
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(addressString.utf16()));
|
||||
ComPtr<IHostNameFactory> hostNameFactory;
|
||||
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
|
||||
&hostNameFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<IHostName> remoteHost;
|
||||
hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
|
||||
RETURN_VOID_IF_FAILED("QBluetoothSocketPrivateWinRT::connectToService: Could not create hostname.");
|
||||
const QString portString = QString::number(port);
|
||||
connectToService(remoteHost, portString, openMode);
|
||||
}
|
||||
|
||||
void QBluetoothSocketPrivateWinRT::connectToService(
|
||||
const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
|
||||
{
|
||||
|
|
@ -425,6 +438,8 @@ void QBluetoothSocketPrivateWinRT::connectToService(
|
|||
return;
|
||||
}
|
||||
|
||||
const QString connectionHostName = service.attribute(0xBEEF).toString();
|
||||
const QString connectionServiceName = service.attribute(0xBEF0).toString();
|
||||
if (service.protocolServiceMultiplexer() > 0) {
|
||||
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
|
||||
|
||||
|
|
@ -434,7 +449,22 @@ void QBluetoothSocketPrivateWinRT::connectToService(
|
|||
return;
|
||||
}
|
||||
connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), openMode);
|
||||
} else if (service.serverChannel() > 0) {
|
||||
} else if (!connectionHostName.isEmpty() && !connectionServiceName.isEmpty()) {
|
||||
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
|
||||
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
|
||||
errorString = QBluetoothSocket::tr("Unknown socket error");
|
||||
q->setSocketError(QBluetoothSocket::UnknownSocketError);
|
||||
return;
|
||||
}
|
||||
HStringReference hostNameRef(reinterpret_cast<LPCWSTR>(connectionHostName.utf16()));
|
||||
ComPtr<IHostNameFactory> hostNameFactory;
|
||||
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Networking_HostName).Get(),
|
||||
&hostNameFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
ComPtr<IHostName> remoteHost;
|
||||
hr = hostNameFactory->CreateHostName(hostNameRef.Get(), &remoteHost);
|
||||
connectToService(remoteHost, connectionServiceName, openMode);
|
||||
} else if (service.serverChannel() > 0) {
|
||||
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
|
||||
|
||||
if (!ensureNativeSocket(QBluetoothServiceInfo::RfcommProtocol)) {
|
||||
|
|
@ -443,7 +473,7 @@ void QBluetoothSocketPrivateWinRT::connectToService(
|
|||
return;
|
||||
}
|
||||
connectToServiceHelper(service.device().address(), service.serverChannel(), openMode);
|
||||
} else {
|
||||
} else {
|
||||
// try doing service discovery to see if we can find the socket
|
||||
if (service.serviceUuid().isNull()
|
||||
&& !service.serviceClassUuids().contains(QBluetoothUuid::SerialPort)) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,19 @@
|
|||
|
||||
QT_FORWARD_DECLARE_CLASS(SocketWorker)
|
||||
|
||||
namespace ABI {
|
||||
namespace Windows {
|
||||
namespace Networking {
|
||||
struct IHostName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Microsoft {
|
||||
namespace WRL {
|
||||
template <typename T> class ComPtr;
|
||||
}
|
||||
}
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QBluetoothSocketPrivateWinRT final: public QBluetoothSocketBasePrivate
|
||||
|
|
@ -125,6 +138,8 @@ private slots:
|
|||
void handleError(QBluetoothSocket::SocketError error);
|
||||
|
||||
private:
|
||||
void connectToService(Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> hostName,
|
||||
const QString &serviceName, QIODevice::OpenMode openMode);
|
||||
HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action,
|
||||
ABI::Windows::Foundation::AsyncStatus status);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue