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 "qbluetoothserver_ohos_p.h"
++
++ #include <QtBluetooth/qbluetoothserver.h>
++ #include <QtBluetooth/qbluetoothsocket.h>
++ #include <QtBluetooth/private/qbluetoothserver_p.h>
++ #include <QtBluetooth/private/qohosbluetoothaccess_p.h>
++ #include <QtBluetooth/private/qohosbluetoothcommon_p.h>
++ #include <QtBluetooth/private/qohosbluetoothserver_p.h>
++ #include <QtBluetooth/private/qohosbluetoothsocket_p.h>
++
++ #include <QtCore/q20utility.h>
++ #include <QtCore/qloggingcategory.h>
++
++ #include <memory>
++
++ QT_BEGIN_NAMESPACE
++
++ using QtOhosBluetooth::QOhosBluetoothErrorCode;
++
++ Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
++
++ namespace {
++
++ QBluetoothServer::Error mapToServerError(QOhosBluetoothErrorCode errorCode)
++ {
++ switch (errorCode) {
++ case QOhosBluetoothErrorCode::PermissionDenied:
++ return QBluetoothServer::MissingPermissionsError;
++ case QOhosBluetoothErrorCode::CapabilityNotSupported:
++ case QOhosBluetoothErrorCode::ProfileNotSupported:
++ return QBluetoothServer::UnsupportedProtocolError;
++ case QOhosBluetoothErrorCode::InputOutput:
++ return QBluetoothServer::InputOutputError;
++ case QOhosBluetoothErrorCode::BluetoothDisabled:
++ case QOhosBluetoothErrorCode::ServiceStopped:
++ return QBluetoothServer::PoweredOffError;
++ case QOhosBluetoothErrorCode::InvalidParameter:
++ case QOhosBluetoothErrorCode::UserDidNotRespond:
++ case QOhosBluetoothErrorCode::UserRefused:
++ case QOhosBluetoothErrorCode::OperationFailed:
++ break;
++ }
++
++ return QBluetoothServer::UnknownError;
++ }
++
++ }
++
++ QBluetoothServerPrivate::QBluetoothServerPrivate(
++ QBluetoothServiceInfo::Protocol sType, QBluetoothServer *parent)
++ : serverType(sType)
++ , q_ptr(parent)
++ {
++ }
++
++ QBluetoothServerPrivate::~QBluetoothServerPrivate() = default;
++
++ bool QBluetoothServerPrivate::isListening() const
++ {
++ return socket != nullptr && socket->state() == QBluetoothSocket::SocketState::ListeningState;
++ }
++
++ void QBluetoothServerPrivate::resetServerContext()
++ {
++ socket = nullptr;
++ m_bluetoothServerProxyContext.reset();
++ }
++
++ void QBluetoothServer::close()
++ {
++ d_ptr->resetServerContext();
++ }
++
++ bool QBluetoothServer::listen(const QBluetoothAddress &address, quint16 port)
++ {
++ if (!address.isNull()) {
++ qCWarning(
++ QT_BT_OHOS,
++ "%s: HarmonyOS does not support multi device adapters. Ignoring local adapter address ...",
++ Q_FUNC_INFO);
++ }
++
++ const auto reportError = [this](Error error) {
++ d_ptr->m_lastError = error;
++ QMetaObject::invokeMethod(
++ this,
++ [this, error]() {
++ Q_EMIT errorOccurred(error);
++ },
++ Qt::QueuedConnection);
++ };
++
++ if (serverType() != QBluetoothServiceInfo::RfcommProtocol) {
++ reportError(UnsupportedProtocolError);
++ return false;
++ }
++
++ if (!QtOhosBluetooth::checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
++ reportError(MissingPermissionsError);
++ return false;
++ }
++
++ auto accessProxy = QtOhosBluetooth::QOhosBluetoothAccessProxy::instance();
++ if (accessProxy->tryGetBluetoothState()
++ != QtOhosBluetooth::QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
++ reportError(PoweredOffError);
++ return false;
++ }
++
++ if (isListening()) {
++ reportError(ServiceAlreadyRegisteredError);
++ return false;
++ }
++
++ if (d_ptr->m_bluetoothServerProxyContext
++ && !d_ptr->m_bluetoothServerProxyContext->bluetoothServerProxy->isServiceRegistered()) {
++ d_ptr->resetServerContext();
++ }
++
++ if (!d_ptr->m_bluetoothServerProxyContext) {
++ d_ptr->m_bluetoothServerProxyContext = QtOhosBluetooth::makeServerProxyContext(port);
++ if (!d_ptr->m_bluetoothServerProxyContext) {
++ reportError(ServiceAlreadyRegisteredError);
++ return false;
++ }
++ d_ptr->m_bluetoothServerProxyContext->securityFlags = d_ptr->securityFlags;
++ d_ptr->socket = d_ptr->m_bluetoothServerProxyContext->bluetoothSocket.get();
++
++ auto serverProxy = d_ptr->m_bluetoothServerProxyContext->bluetoothServerProxy.get();
++
++ QObject::connect(
++ serverProxy, &QtOhosBluetooth::QOhosBluetoothServerProxy::clientAccepted,
++ this,
++ [this](int clientSocketDescriptor) {
++ auto context = d_ptr->m_bluetoothServerProxyContext;
++ if (!context) {
++ QtOhosBluetooth::QOhosBluetoothSocketProxy::dropPendingSocketHandle(
++ clientSocketDescriptor);
++ return;
++ }
++
++ if (q20::cmp_greater_equal(
++ context->pendingConnectionSockets.size(),
++ d_ptr->maxPendingConnections)) {
++ qCDebug(
++ QT_BT_OHOS,
++ "%s: maximum number of pending connections reached. Rejecting the client ...",
++ Q_FUNC_INFO);
++ QtOhosBluetooth::QOhosBluetoothSocketProxy::dropPendingSocketHandle(
++ clientSocketDescriptor);
++ return;
++ }
++
++ auto pendingConnectionSocket = std::make_unique<QBluetoothSocket>();
++ const auto socketDescriptorSet = pendingConnectionSocket->setSocketDescriptor(
++ clientSocketDescriptor, QBluetoothServiceInfo::RfcommProtocol,
++ QBluetoothSocket::SocketState::ConnectedState, QBluetoothSocket::ReadWrite);
++
++ if (!socketDescriptorSet) {
++ QtOhosBluetooth::QOhosBluetoothSocketProxy::dropPendingSocketHandle(
++ clientSocketDescriptor);
++ return;
++ }
++
++ context->pendingConnectionSockets.push_back(std::move(pendingConnectionSocket));
++ Q_EMIT newConnection();
++ });
++
++ QObject::connect(
++ serverProxy, &QtOhosBluetooth::QOhosBluetoothServerProxy::errorOccurred,
++ this,
++ [this](QOhosBluetoothErrorCode errorCode) {
++ d_ptr->m_lastError = mapToServerError(errorCode);
++ Q_EMIT errorOccurred(d_ptr->m_lastError);
++ });
++
++ QObject::connect(
++ serverProxy, &QtOhosBluetooth::QOhosBluetoothServerProxy::acceptingStopped,
++ this,
++ [this]() {
++ auto context = d_ptr->m_bluetoothServerProxyContext;
++ if (context && context->bluetoothServerProxy->isServiceRegistered())
++ return;
++
++ if (d_ptr->socket)
++ d_ptr->socket->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
++ });
++ }
++
++ d_ptr->socket->setSocketState(QBluetoothSocket::SocketState::ListeningState);
++ return true;
++ }
++
++ void QBluetoothServer::setMaxPendingConnections(int numConnections)
++ {
++ d_ptr->maxPendingConnections = numConnections;
++ }
++
++ bool QBluetoothServer::hasPendingConnections() const
++ {
++ auto context = d_ptr->m_bluetoothServerProxyContext;
++ return context && !context->pendingConnectionSockets.empty();
++ }
++
++ QBluetoothSocket *QBluetoothServer::nextPendingConnection()
++ {
++ auto context = d_ptr->m_bluetoothServerProxyContext;
++ if (!context || context->pendingConnectionSockets.empty())
++ return nullptr;
++
++ auto pendingConnectionSocket = std::move(context->pendingConnectionSockets.front());
++ context->pendingConnectionSockets.pop_front();
++
++ return pendingConnectionSocket.release();
++ }
++
++ QBluetoothAddress QBluetoothServer::serverAddress() const
++ {
++ return {};
++ }
++
++ quint16 QBluetoothServer::serverPort() const
++ {
++ auto context = d_ptr->m_bluetoothServerProxyContext;
++ return context ? context->port : 0;
++ }
++
++ void QBluetoothServer::setSecurityFlags(QBluetooth::SecurityFlags security)
++ {
++ if (isListening()) {
++ qCWarning(
++ QT_BT_OHOS,
++ "%s: the security flags must be set before listen(). Ignoring the new flags ...",
++ Q_FUNC_INFO);
++ return;
++ }
++
++ d_ptr->securityFlags = security;
++ }
++
++ QBluetooth::SecurityFlags QBluetoothServer::securityFlags() const
++ {
++ return d_ptr->securityFlags;
++ }
++
++ QT_END_NAMESPACE