From cf1cb5ef0ff41c9a66e64d272293ad04efa180f0 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 5 Jul 2019 13:40:04 +0200 Subject: QBluetoothServiceInfo - remove the code-duplicate (macOS) Task-number: QTBUG-75348 Change-Id: I5e2e08291cd17c1f1ef8639d422f4421520ed371 Reviewed-by: Oliver Wolff Reviewed-by: Alex Blasche --- src/bluetooth/bluetooth.pro | 1 - src/bluetooth/qbluetoothserviceinfo.cpp | 5 + src/bluetooth/qbluetoothserviceinfo_osx.mm | 386 ++++++----------------------- src/bluetooth/qbluetoothserviceinfo_p.h | 22 +- 4 files changed, 93 insertions(+), 321 deletions(-) (limited to 'src') diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro index 4c7a7876..265ad7f1 100644 --- a/src/bluetooth/bluetooth.pro +++ b/src/bluetooth/bluetooth.pro @@ -174,7 +174,6 @@ qtConfig(bluez) { qbluetoothtransferreply_osx_p.h \ qlowenergycontroller_darwin_p.h - SOURCES -= qbluetoothserviceinfo.cpp SOURCES -= qbluetoothservicediscoveryagent.cpp } else:ios|tvos { DEFINES += QT_IOS_BLUETOOTH diff --git a/src/bluetooth/qbluetoothserviceinfo.cpp b/src/bluetooth/qbluetoothserviceinfo.cpp index 7c3780ec..23a78c81 100644 --- a/src/bluetooth/qbluetoothserviceinfo.cpp +++ b/src/bluetooth/qbluetoothserviceinfo.cpp @@ -180,7 +180,12 @@ bool QBluetoothServiceInfo::isRegistered() const bool QBluetoothServiceInfo::registerService(const QBluetoothAddress &localAdapter) { +#ifdef QT_OSX_BLUETOOTH + Q_UNUSED(localAdapter) + return d_ptr->registerService(*this); +#else return d_ptr->registerService(localAdapter); +#endif } /*! diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm index c0f914f6..41e4e8b7 100644 --- a/src/bluetooth/qbluetoothserviceinfo_osx.mm +++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm @@ -38,6 +38,7 @@ ****************************************************************************/ #include "osx/osxbtservicerecord_p.h" +#include "qbluetoothserviceinfo_p.h" #include "qbluetoothserviceinfo.h" #include "qbluetoothdeviceinfo.h" #include "qbluetoothserver_p.h" @@ -55,85 +56,116 @@ QT_BEGIN_NAMESPACE -class QBluetoothServiceInfoPrivate +namespace { + +using DarwinBluetooth::RetainPolicy; +using ServiceInfo = QBluetoothServiceInfo; + +// Alas, since there is no d_ptr<->q_ptr link (which is not that bad in itself), +// I need these getters duplicated here: +ServiceInfo::Protocol socket_protocol(const QBluetoothServiceInfoPrivate &privateInfo) { -public: + ServiceInfo::Sequence parameters = privateInfo.protocolDescriptor(QBluetoothUuid::Rfcomm); + if (!parameters.isEmpty()) + return ServiceInfo::RfcommProtocol; - typedef QBluetoothServiceInfo QSInfo; + parameters = privateInfo.protocolDescriptor(QBluetoothUuid::L2cap); + if (!parameters.isEmpty()) + return ServiceInfo::L2capProtocol; - bool registerService(const OSXBluetooth::ObjCStrongReference &serviceDict); - bool isRegistered() const; - bool unregisterService(); + return ServiceInfo::UnknownProtocol; +} - QBluetoothDeviceInfo deviceInfo; - QMap attributes; +int channel_or_psm(const QBluetoothServiceInfoPrivate &privateInfo, QBluetoothUuid::ProtocolUuid uuid) +{ + const auto parameters = privateInfo.protocolDescriptor(uuid); + if (parameters.isEmpty()) + return -1; + else if (parameters.count() == 1) + return 0; - QBluetoothServiceInfo::Sequence protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const; - QBluetoothServiceInfo::Protocol socketProtocol() const; - int protocolServiceMultiplexer() const; - int serverChannel() const; + return parameters.at(1).toInt(); +} -private: +} // unnamed namespace - bool registered = false; +QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate() +{ +} - typedef OSXBluetooth::ObjCScopedPointer SDPRecord; - SDPRecord serviceRecord; - BluetoothSDPServiceRecordHandle serviceRecordHandle = 0; -}; +QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate() +{ +} -bool QBluetoothServiceInfoPrivate::registerService(const OSXBluetooth::ObjCStrongReference &serviceDict) +bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAddress) +{ + Q_UNUSED(localAddress); + return false; +} + +bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothServiceInfo &info) { using namespace OSXBluetooth; - Q_ASSERT(serviceDict); + if (isRegistered()) + return false; + + using namespace OSXBluetooth; + + ObjCStrongReference serviceDict(iobluetooth_service_dictionary(info)); + if (!serviceDict) { + qCWarning(QT_BT_OSX) << "failed to create a service dictionary"; + return false; + } + Q_ASSERT(!registered); Q_ASSERT_X(!serviceRecord, Q_FUNC_INFO, "not registered, but serviceRecord is not nil"); SDPRecord newRecord; - newRecord.reset([[IOBluetoothSDPServiceRecord - publishedServiceRecordWithDictionary:serviceDict] retain]); + newRecord.reset([IOBluetoothSDPServiceRecord + publishedServiceRecordWithDictionary:serviceDict], RetainPolicy::doInitialRetain); if (!newRecord) { qCWarning(QT_BT_OSX) << "failed to register a service record"; return false; } BluetoothSDPServiceRecordHandle newRecordHandle = 0; - if ([newRecord getServiceRecordHandle:&newRecordHandle] != kIOReturnSuccess) { + auto *ioSDPRecord = newRecord.getAs(); + if ([ioSDPRecord getServiceRecordHandle:&newRecordHandle] != kIOReturnSuccess) { qCWarning(QT_BT_OSX) << "failed to register a service record"; - [newRecord removeServiceRecord]; + [ioSDPRecord removeServiceRecord]; return false; } - const QSInfo::Protocol type = socketProtocol(); + const ServiceInfo::Protocol type = info.socketProtocol(); quint16 realPort = 0; QBluetoothServerPrivate *server = nullptr; bool configured = false; if (type == QBluetoothServiceInfo::L2capProtocol) { BluetoothL2CAPPSM psm = 0; - server = QBluetoothServerPrivate::registeredServer(protocolServiceMultiplexer(), type); - if ([newRecord getL2CAPPSM:&psm] == kIOReturnSuccess) { + server = QBluetoothServerPrivate::registeredServer(info.protocolServiceMultiplexer(), type); + if ([ioSDPRecord getL2CAPPSM:&psm] == kIOReturnSuccess) { configured = true; realPort = psm; } } else if (type == QBluetoothServiceInfo::RfcommProtocol) { BluetoothRFCOMMChannelID channelID = 0; - server = QBluetoothServerPrivate::registeredServer(serverChannel(), type); - if ([newRecord getRFCOMMChannelID:&channelID] == kIOReturnSuccess) { + server = QBluetoothServerPrivate::registeredServer(info.serverChannel(), type); + if ([ioSDPRecord getRFCOMMChannelID:&channelID] == kIOReturnSuccess) { configured = true; realPort = channelID; } } if (!configured) { - [newRecord removeServiceRecord]; + [ioSDPRecord removeServiceRecord]; qCWarning(QT_BT_OSX) << "failed to register a service record"; return false; } registered = true; - serviceRecord.reset(newRecord.take()); + serviceRecord.swap(newRecord); serviceRecordHandle = newRecordHandle; if (server) @@ -154,17 +186,18 @@ bool QBluetoothServiceInfoPrivate::unregisterService() Q_ASSERT_X(serviceRecord, Q_FUNC_INFO, "service registered, but serviceRecord is nil"); - [serviceRecord removeServiceRecord]; - serviceRecord.reset(nil); + auto *nativeRecord = serviceRecord.getAs(); + [nativeRecord removeServiceRecord]; + serviceRecord.reset(); - const QSInfo::Protocol type = socketProtocol(); + const ServiceInfo::Protocol type = socket_protocol(*this); QBluetoothServerPrivate *server = nullptr; const QMutexLocker lock(&QBluetoothServerPrivate::channelMapMutex()); - if (type == QSInfo::RfcommProtocol) - server = QBluetoothServerPrivate::registeredServer(serverChannel(), type); - else if (type == QSInfo::L2capProtocol) - server = QBluetoothServerPrivate::registeredServer(protocolServiceMultiplexer(), type); + if (type == ServiceInfo::RfcommProtocol) + server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::Rfcomm), type); + else if (type == ServiceInfo::L2capProtocol) + server = QBluetoothServerPrivate::registeredServer(channel_or_psm(*this, QBluetoothUuid::L2cap), type); if (server) server->stopListener(); @@ -175,281 +208,4 @@ bool QBluetoothServiceInfoPrivate::unregisterService() return true; } -bool QBluetoothServiceInfo::isRegistered() const -{ - return d_ptr->isRegistered(); -} - -bool QBluetoothServiceInfo::registerService(const QBluetoothAddress &localAdapter) -{ - Q_UNUSED(localAdapter); - if (isRegistered()) - return false; - - using namespace OSXBluetooth; - - ObjCStrongReference serviceDict(iobluetooth_service_dictionary(*this)); - if (!serviceDict) { - qCWarning(QT_BT_OSX) << "failed to create a service dictionary"; - return false; - } - - return d_ptr->registerService(serviceDict); -} - -bool QBluetoothServiceInfo::unregisterService() -{ - return d_ptr->unregisterService(); -} - -QBluetoothServiceInfo::QBluetoothServiceInfo() - : d_ptr(new QBluetoothServiceInfoPrivate) -{ -} - -QBluetoothServiceInfo::QBluetoothServiceInfo(const QBluetoothServiceInfo &other) - : d_ptr(other.d_ptr) -{ -} - -QBluetoothServiceInfo::~QBluetoothServiceInfo() -{ -} - -bool QBluetoothServiceInfo::isValid() const -{ - return !d_ptr->attributes.isEmpty(); -} - -bool QBluetoothServiceInfo::isComplete() const -{ - return d_ptr->attributes.contains(ProtocolDescriptorList); -} - -QBluetoothDeviceInfo QBluetoothServiceInfo::device() const -{ - return d_ptr->deviceInfo; -} - -void QBluetoothServiceInfo::setDevice(const QBluetoothDeviceInfo &device) -{ - d_ptr->deviceInfo = device; -} - -void QBluetoothServiceInfo::setAttribute(quint16 attributeId, const QVariant &value) -{ - d_ptr->attributes[attributeId] = value; -} - -QVariant QBluetoothServiceInfo::attribute(quint16 attributeId) const -{ - return d_ptr->attributes.value(attributeId); -} - -QList QBluetoothServiceInfo::attributes() const -{ - return d_ptr->attributes.keys(); -} - -bool QBluetoothServiceInfo::contains(quint16 attributeId) const -{ - return d_ptr->attributes.contains(attributeId); -} - -void QBluetoothServiceInfo::removeAttribute(quint16 attributeId) -{ - d_ptr->attributes.remove(attributeId); -} - -QBluetoothServiceInfo::Protocol QBluetoothServiceInfo::socketProtocol() const -{ - return d_ptr->socketProtocol(); -} - -int QBluetoothServiceInfo::protocolServiceMultiplexer() const -{ - return d_ptr->protocolServiceMultiplexer(); -} - -int QBluetoothServiceInfo::serverChannel() const -{ - return d_ptr->serverChannel(); -} - -QBluetoothServiceInfo::Sequence QBluetoothServiceInfo::protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const -{ - return d_ptr->protocolDescriptor(protocol); -} - -QList QBluetoothServiceInfo::serviceClassUuids() const -{ - QList results; - - const QVariant var = attribute(QBluetoothServiceInfo::ServiceClassIds); - if (!var.isValid()) - return results; - - const QBluetoothServiceInfo::Sequence seq = var.value(); - for (int i = 0; i < seq.count(); i++) - results.append(seq.at(i).value()); - - return results; -} - -QBluetoothServiceInfo &QBluetoothServiceInfo::operator=(const QBluetoothServiceInfo &other) -{ - if (this != &other) - d_ptr = other.d_ptr; - - return *this; -} - -static void dumpAttributeVariant(QDebug dbg, const QVariant &var, const QString& indent) -{ - switch (int(var.type())) { - case QMetaType::Void: - dbg << QString::asprintf("%sEmpty\n", indent.toUtf8().constData()); - break; - case QMetaType::UChar: - dbg << QString::asprintf("%suchar %u\n", indent.toUtf8().constData(), var.toUInt()); - break; - case QMetaType::UShort: - dbg << QString::asprintf("%sushort %u\n", indent.toUtf8().constData(), var.toUInt()); - break; - case QMetaType::UInt: - dbg << QString::asprintf("%suint %u\n", indent.toUtf8().constData(), var.toUInt()); - break; - case QMetaType::Char: - dbg << QString::asprintf("%schar %d\n", indent.toUtf8().constData(), var.toInt()); - break; - case QMetaType::Short: - dbg << QString::asprintf("%sshort %d\n", indent.toUtf8().constData(), var.toInt()); - break; - case QMetaType::Int: - dbg << QString::asprintf("%sint %d\n", indent.toUtf8().constData(), var.toInt()); - break; - case QMetaType::QString: - dbg << QString::asprintf("%sstring %s\n", indent.toUtf8().constData(), - var.toString().toUtf8().constData()); - break; - case QMetaType::QByteArray: - dbg << QString::asprintf("%sbytearray %s\n", indent.toUtf8().constData(), - var.toByteArray().toHex().constData()); - break; - case QMetaType::Bool: - dbg << QString::asprintf("%sbool %d\n", indent.toUtf8().constData(), var.toBool()); - break; - case QMetaType::QUrl: - dbg << QString::asprintf("%surl %s\n", indent.toUtf8().constData(), - var.toUrl().toString().toUtf8().constData()); - break; - case QVariant::UserType: - if (var.userType() == qMetaTypeId()) { - QBluetoothUuid uuid = var.value(); - switch (uuid.minimumSize()) { - case 0: - dbg << QString::asprintf("%suuid NULL\n", indent.toUtf8().constData()); - break; - case 2: - dbg << QString::asprintf("%suuid2 %04x\n", indent.toUtf8().constData(), - uuid.toUInt16()); - break; - case 4: - dbg << QString::asprintf("%suuid %08x\n", indent.toUtf8().constData(), - uuid.toUInt32()); - break; - case 16: - dbg << QString::asprintf("%suuid %s\n", - indent.toUtf8().constData(), - QByteArray(reinterpret_cast(uuid.toUInt128().data), 16).toHex().constData()); - break; - default: - dbg << QString::asprintf("%suuid ???\n", indent.toUtf8().constData()); - } - } else if (var.userType() == qMetaTypeId()) { - dbg << QString::asprintf("%sSequence\n", indent.toUtf8().constData()); - const QBluetoothServiceInfo::Sequence *sequence = static_cast(var.data()); - for (const QVariant &v : *sequence) - dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t')); - } else if (var.userType() == qMetaTypeId()) { - dbg << QString::asprintf("%sAlternative\n", indent.toUtf8().constData()); - const QBluetoothServiceInfo::Alternative *alternative = static_cast(var.data()); - for (const QVariant &v : *alternative) - dumpAttributeVariant(dbg, v, indent + QLatin1Char('\t')); - } - break; - default: - dbg << QString::asprintf("%sunknown variant type %d\n", indent.toUtf8().constData(), - var.userType()); - } -} - -QDebug operator << (QDebug dbg, const QBluetoothServiceInfo &info) -{ - QDebugStateSaver saver(dbg); - dbg.noquote() << "\n"; - const QList attributes = info.attributes(); - for (quint16 id : attributes) { - dumpAttributeVariant(dbg, info.attribute(id), QString::fromLatin1("(%1)\t").arg(id)); - } - return dbg; -} - -QBluetoothServiceInfo::Sequence QBluetoothServiceInfoPrivate::protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const -{ - if (!attributes.contains(QBluetoothServiceInfo::ProtocolDescriptorList)) - return QBluetoothServiceInfo::Sequence(); - - const QBluetoothServiceInfo::Sequence sequence - = attributes.value(QBluetoothServiceInfo::ProtocolDescriptorList).value(); - for (const QVariant &v : sequence) { - QBluetoothServiceInfo::Sequence parameters = v.value(); - if (parameters.empty()) - continue; - if (parameters.at(0).userType() == qMetaTypeId()) { - if (parameters.at(0).value() == protocol) - return parameters; - } - } - - return QBluetoothServiceInfo::Sequence(); -} - -QBluetoothServiceInfo::Protocol QBluetoothServiceInfoPrivate::socketProtocol() const -{ - QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::Rfcomm); - if (!parameters.isEmpty()) - return QBluetoothServiceInfo::RfcommProtocol; - - parameters = protocolDescriptor(QBluetoothUuid::L2cap); - if (!parameters.isEmpty()) - return QBluetoothServiceInfo::L2capProtocol; - - return QBluetoothServiceInfo::UnknownProtocol; -} - - -int QBluetoothServiceInfoPrivate::protocolServiceMultiplexer() const -{ - const QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::L2cap); - if (parameters.isEmpty()) - return -1; - else if (parameters.count() == 1) - return 0; - - return parameters.at(1).toUInt(); -} - - -int QBluetoothServiceInfoPrivate::serverChannel() const -{ - const QBluetoothServiceInfo::Sequence parameters = protocolDescriptor(QBluetoothUuid::Rfcomm); - if (parameters.isEmpty()) - return -1; - else if (parameters.count() == 1) - return 0; - - return parameters.at(1).toUInt(); -} - QT_END_NAMESPACE diff --git a/src/bluetooth/qbluetoothserviceinfo_p.h b/src/bluetooth/qbluetoothserviceinfo_p.h index e4e835e4..a0515b8c 100644 --- a/src/bluetooth/qbluetoothserviceinfo_p.h +++ b/src/bluetooth/qbluetoothserviceinfo_p.h @@ -59,6 +59,10 @@ #include #include +#ifdef Q_OS_MACOS +#include "osx/btraii_p.h" +#endif + class OrgBluezServiceInterface; class OrgBluezProfileManager1Interface; @@ -82,7 +86,6 @@ QT_BEGIN_NAMESPACE class QBluetoothServiceInfo; -#ifndef QT_OSX_BLUETOOTH class QBluetoothServiceInfoPrivate : public QObject @@ -120,11 +123,20 @@ private: bool writeSdpAttributes(); #endif - mutable bool registered; -}; +#if QT_OSX_BLUETOOTH +public: + bool registerService(const QBluetoothServiceInfo &info); -#endif +private: + + using SDPRecord = DarwinBluetooth::ScopedPointer; + SDPRecord serviceRecord; + quint32 serviceRecordHandle = 0; +#endif // QT_OSX_BLUETOOTH + + mutable bool registered = false; +}; QT_END_NAMESPACE -#endif +#endif // QBLUETOOTHSERVICEINFO_P_H -- cgit v1.2.3