Revision control

++ // Copyright (C) 2026 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include "qbluetoothserviceinfo_p.h"
++
++ #include <QtBluetooth/qbluetoothserviceinfo.h>
++ #include <QtBluetooth/private/qbluetoothserver_ohos_p.h>
++ #include <QtBluetooth/private/qohosbluetoothserver_p.h>
++
++ #include <QtCore/qloggingcategory.h>
++
++ #include <optional>
++
++ QT_BEGIN_NAMESPACE
++
++ Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
++
++ namespace {
++
++ std::optional<quint16> tryGetRfcommServerPort(int serverChannel)
++ {
++ if (serverChannel < 0) {
++ qCWarning(QT_BT_OHOS, "%s: Only RFCOMM services can be registered on HarmonyOS", Q_FUNC_INFO);
++ return std::nullopt;
++ }
++
++ if (serverChannel == 0) {
++ qCCritical(
++ QT_BT_OHOS, "%s: No RFCOMM port in the service. Cannot register service.", Q_FUNC_INFO);
++ return std::nullopt;
++ }
++
++ return static_cast<quint16>(serverChannel);
++ }
++
++ }
++
++ QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate() = default;
++
++ QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
++ {
++ unregisterService();
++ }
++
++ bool QBluetoothServiceInfoPrivate::isRegisteredWithServerProxy() const
++ {
++ const auto serverProxy = registeredServerProxy.lock();
++ return serverProxy && optRegisteredServiceId
++ && serverProxy->tryGetRegisteredServiceId() == optRegisteredServiceId;
++ }
++
++ bool QBluetoothServiceInfoPrivate::isRegistered() const
++ {
++ return registered && isRegisteredWithServerProxy();
++ }
++
++ bool QBluetoothServiceInfoPrivate::unregisterService()
++ {
++ if (!registered)
++ return false;
++
++ registered = false;
++
++ if (isRegisteredWithServerProxy()) {
++ registeredServerProxy.lock()->close();
++ } else {
++ qCDebug(
++ QT_BT_OHOS, "%s: the server is already closed. The service is unregistered anyway.",
++ Q_FUNC_INFO);
++ }
++
++ registeredServerProxy.reset();
++ optRegisteredServiceId.reset();
++
++ return true;
++ }
++
++ bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
++ {
++ if (!localAdapter.isNull()) {
++ qCWarning(
++ QT_BT_OHOS,
++ "%s: HarmonyOS does not support multi device adapters. Ignoring local adapter address ...",
++ Q_FUNC_INFO);
++ }
++
++ if (isRegistered())
++ return false;
++
++ registered = false;
++ registeredServerProxy.reset();
++ optRegisteredServiceId.reset();
++
++ const auto optPort = tryGetRfcommServerPort(serverChannel());
++ if (!optPort)
++ return false;
++
++ const auto serviceName = attributes.value(QBluetoothServiceInfo::ServiceName).toString();
++ const auto uuid = attributes.value(QBluetoothServiceInfo::ServiceId).value<QBluetoothUuid>();
++
++ if (serviceName.isEmpty()) {
++ qCCritical(
++ QT_BT_OHOS, "%s: No service name in the service. Cannot register service.",
++ Q_FUNC_INFO);
++ return false;
++ }
++
++ if (uuid.isNull()) {
++ qCCritical(
++ QT_BT_OHOS, "%s: No service UUID in the service. Cannot register service.",
++ Q_FUNC_INFO);
++ return false;
++ }
++
++ if (QtOhosBluetooth::isServiceNameAlreadyRegistered(serviceName)) {
++ qCCritical(QT_BT_OHOS, "%s: Server with such service name is registered", Q_FUNC_INFO);
++ return false;
++ }
++
++ auto serverProxyContext = QtOhosBluetooth::tryGetServerProxyContext(*optPort);
++ if (!serverProxyContext) {
++ qCCritical(QT_BT_OHOS, "%s: Server is not active. Cannot register services.", Q_FUNC_INFO);
++ return false;
++ }
++
++ auto proxy = serverProxyContext->bluetoothServerProxy;
++
++ if (proxy->isServiceRegistered()) {
++ qCCritical(
++ QT_BT_OHOS, "%s: Server has already registered service. Cannot register services.",
++ Q_FUNC_INFO);
++ return false;
++ }
++
++ const auto secure = (serverProxyContext->securityFlags != QBluetooth::Security::NoSecurity);
++
++ if (!proxy->listen(serviceName, uuid.toString(QUuid::WithoutBraces), secure))
++ return false;
++
++ if (!proxy->accept()) {
++ proxy->close();
++ return false;
++ }
++
++ registered = true;
++ registeredServerProxy = proxy;
++ optRegisteredServiceId = proxy->tryGetRegisteredServiceId();
++
++ return true;
++ }
++
++ QT_END_NAMESPACE