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.enumeration.h>
|
||||||
#include <windows.devices.bluetooth.h>
|
#include <windows.devices.bluetooth.h>
|
||||||
#include <windows.foundation.collections.h>
|
#include <windows.foundation.collections.h>
|
||||||
|
#include <windows.networking.h>
|
||||||
#include <windows.storage.streams.h>
|
#include <windows.storage.streams.h>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
|
|
||||||
|
|
@ -208,6 +209,14 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
|
||||||
hr = service->get_ConnectionServiceName(name.GetAddressOf());
|
hr = service->get_ConnectionServiceName(name.GetAddressOf());
|
||||||
Q_ASSERT_SUCCEEDED(hr);
|
Q_ASSERT_SUCCEEDED(hr);
|
||||||
const QString serviceName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
|
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;
|
ComPtr<IRfcommServiceId> id;
|
||||||
hr = service->get_ServiceId(&id);
|
hr = service->get_ServiceId(&id);
|
||||||
Q_ASSERT_SUCCEEDED(hr);
|
Q_ASSERT_SUCCEEDED(hr);
|
||||||
|
|
@ -217,6 +226,8 @@ void QWinRTBluetoothServiceDiscoveryWorker::processServiceSearchResult(quint64 a
|
||||||
Q_ASSERT_SUCCEEDED(hr);
|
Q_ASSERT_SUCCEEDED(hr);
|
||||||
|
|
||||||
QBluetoothServiceInfo info;
|
QBluetoothServiceInfo info;
|
||||||
|
info.setAttribute(0xBEEF, QVariant(qHostName));
|
||||||
|
info.setAttribute(0xBEF0, QVariant(serviceName));
|
||||||
info.setServiceName(serviceName);
|
info.setServiceName(serviceName);
|
||||||
info.setServiceUuid(uuid);
|
info.setServiceUuid(uuid);
|
||||||
ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
|
ComPtr<IAsyncOperation<IMapView<UINT32, IBuffer *> *>> op;
|
||||||
|
|
|
||||||
|
|
@ -640,6 +640,13 @@ void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
|
||||||
connectToService(service, d->openMode);
|
connectToService(service, d->openMode);
|
||||||
d->discoveryAgent->deleteLater();
|
d->discoveryAgent->deleteLater();
|
||||||
d->discoveryAgent = nullptr;
|
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 {
|
} else {
|
||||||
qCDebug(QT_BT) << "Could not find port/psm for potential remote service";
|
qCDebug(QT_BT) << "Could not find port/psm for potential remote service";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -359,10 +359,11 @@ bool QBluetoothSocketPrivateWinRT::ensureNativeSocket(QBluetoothServiceInfo::Pro
|
||||||
return true;
|
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_Q(QBluetoothSocket);
|
||||||
Q_UNUSED(openMode);
|
|
||||||
|
|
||||||
if (socket == -1 && !ensureNativeSocket(socketType)) {
|
if (socket == -1 && !ensureNativeSocket(socketType)) {
|
||||||
errorString = QBluetoothSocket::tr("Unknown socket error");
|
errorString = QBluetoothSocket::tr("Unknown socket error");
|
||||||
|
|
@ -370,20 +371,9 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString addressString = address.toString();
|
HStringReference serviceNameReference(reinterpret_cast<LPCWSTR>(serviceName.utf16()));
|
||||||
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);
|
HRESULT hr = m_socketObject->ConnectAsync(hostName.Get(), serviceNameReference.Get(), &m_connectOp);
|
||||||
HStringReference portReference(reinterpret_cast<LPCWSTR>(portString.utf16()));
|
|
||||||
|
|
||||||
hr = m_socketObject->ConnectAsync(remoteHost.Get(), portReference.Get(), &m_connectOp);
|
|
||||||
if (hr == E_ACCESSDENIED) {
|
if (hr == E_ACCESSDENIED) {
|
||||||
qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
|
qErrnoWarning(hr, "QBluetoothSocketPrivateWinRT::connectToService: Unable to connect to bluetooth socket."
|
||||||
"Please check your manifest capabilities.");
|
"Please check your manifest capabilities.");
|
||||||
|
|
@ -404,6 +394,29 @@ void QBluetoothSocketPrivateWinRT::connectToServiceHelper(const QBluetoothAddres
|
||||||
Q_ASSERT_SUCCEEDED(hr);
|
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(
|
void QBluetoothSocketPrivateWinRT::connectToService(
|
||||||
const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
|
const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
|
||||||
{
|
{
|
||||||
|
|
@ -425,6 +438,8 @@ void QBluetoothSocketPrivateWinRT::connectToService(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString connectionHostName = service.attribute(0xBEEF).toString();
|
||||||
|
const QString connectionServiceName = service.attribute(0xBEF0).toString();
|
||||||
if (service.protocolServiceMultiplexer() > 0) {
|
if (service.protocolServiceMultiplexer() > 0) {
|
||||||
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
|
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
|
||||||
|
|
||||||
|
|
@ -434,6 +449,21 @@ void QBluetoothSocketPrivateWinRT::connectToService(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), openMode);
|
connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(), openMode);
|
||||||
|
} 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) {
|
} else if (service.serverChannel() > 0) {
|
||||||
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
|
Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,19 @@
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(SocketWorker)
|
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
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QBluetoothSocketPrivateWinRT final: public QBluetoothSocketBasePrivate
|
class QBluetoothSocketPrivateWinRT final: public QBluetoothSocketBasePrivate
|
||||||
|
|
@ -125,6 +138,8 @@ private slots:
|
||||||
void handleError(QBluetoothSocket::SocketError error);
|
void handleError(QBluetoothSocket::SocketError error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void connectToService(Microsoft::WRL::ComPtr<ABI::Windows::Networking::IHostName> hostName,
|
||||||
|
const QString &serviceName, QIODevice::OpenMode openMode);
|
||||||
HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action,
|
HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *action,
|
||||||
ABI::Windows::Foundation::AsyncStatus status);
|
ABI::Windows::Foundation::AsyncStatus status);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue