Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohosbluetoothserver.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtBluetooth/private/qohosbluetoothaccess_p.h>
7#include <QtBluetooth/private/qohosbluetoothcommon_p.h>
8#include <QtBluetooth/private/qohosbluetoothenums_p.h>
9#include <QtBluetooth/private/qohosbluetoothsocket_p.h>
10
11#include <QtCore/qloggingcategory.h>
12#include <QtCore/private/qcore_ohos_p.h>
13#include <QtCore/private/qnapi_p.h>
14#include <QtCore/private/qohoslogger_p.h>
15
16#include <memory>
17#include <optional>
18
20
21Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
22
23namespace QtOhosBluetooth {
24
25namespace {
26
27using SppType = QtOhosBluetooth::enums::ohos::bluetooth::socket::SppType;
28
29}
30
31QOhosBluetoothServerProxy::QOhosBluetoothServerProxy()
32{
33 QObject::connect(
34 QOhosBluetoothAccessProxy::instance().get(),
35 &QOhosBluetoothAccessProxy::stateChanged,
36 this,
37 [this](QOhosBluetoothAccessProxy::BluetoothState bluetoothState) {
38 if (bluetoothState == QOhosBluetoothAccessProxy::BluetoothState::STATE_ON)
39 return;
40
41 if (!m_serverSocketHandle)
42 return;
43
44 const auto self = weak_from_this().lock();
45 if (!self)
46 return;
47
48 qCWarning(
49 QT_BT_OHOS, "%s: bluetooth is turned off. Closing the server ...", Q_FUNC_INFO);
50 reportError(QOhosBluetoothErrorCode::BluetoothDisabled);
51 close();
52 });
53}
54
55bool QOhosBluetoothServerProxy::listen(const QString &serviceName, const QString &uuid, bool secure)
56{
57 if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
58 reportError(QOhosBluetoothErrorCode::PermissionDenied);
59 return false;
60 }
61
62 struct SppListenResult
63 {
64 int serverSocketId = invalidSocketDescriptor;
65 std::optional<QOhosBluetoothErrorCode> optErrorCode = std::nullopt;
66 };
67
68 const auto listenResult = QOhosJsThreadGateway::evalWithPromise<SppListenResult>(
69 [&](QOhosJsState &jsState, QOhosTaskPromise<SppListenResult> evalPromise) {
70 auto sppOptions = QNapi::makeObject(
71 jsState.env(),
72 {
73 {"uuid", uuid.toStdString()},
74 {"secure", secure},
75 {"type", jsState.mapOhosEnumToJs(SppType::SPP_RFCOMM)},
76 });
77
78 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
79
80 try {
81 jsState.eval(
82 "@ohos.bluetooth.socket.sppListen(*)",
83 {
84 serviceName.toStdString(),
85 sppOptions,
86 [thenPromise = std::move(thenCatchPromises.first)](
87 const QNapi::CallbackInfo &callbackInfo) {
88 QNapi::Value error;
89 QNapi::Value data;
90 callbackInfo.getLeadingArgs(Q_FUNC_INFO, error, data);
91 int socketId = data.IsNumber()
92 ? QNapi::checkedCast<QNapi::Number>(data).Int32Value()
93 : invalidSocketDescriptor;
94
95 if (socketId == invalidSocketDescriptor) {
96 thenPromise(
97 SppListenResult{
98 socketId, tryGetKnownErrorCode(error, Q_FUNC_INFO)});
99 return;
100 }
101
102 thenPromise(SppListenResult{socketId, {}});
103 }
104 });
105 } catch (const Napi::Error &error) {
106 thenCatchPromises.second(
107 SppListenResult{
108 invalidSocketDescriptor,
109 tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO)});
110 }
111 });
112
113 if (listenResult.optErrorCode) {
114 qCCritical(
115 QT_BT_OHOS, "%s: sppListen() failed with error code: %u", Q_FUNC_INFO,
116 qToUnderlying(*listenResult.optErrorCode));
117 reportError(*listenResult.optErrorCode);
118 return false;
119 }
120
121 if (listenResult.serverSocketId == invalidSocketDescriptor) {
122 qCCritical(QT_BT_OHOS, "%s: sppListen() reported no server socket", Q_FUNC_INFO);
123 reportError(QOhosBluetoothErrorCode::OperationFailed);
124 return false;
125 }
126
127 m_serverSocketHandle = makeSppServerSocketHandle(listenResult.serverSocketId);
128 m_registeredServiceName = serviceName;
129 m_optRegisteredServiceId = ++m_registeredServicesCounter;
130
131 return true;
132}
133
135{
136 if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
137 reportError(QOhosBluetoothErrorCode::PermissionDenied);
138 return false;
139 }
140
141 if (!m_serverSocketHandle) {
142 qCCritical(
143 QT_BT_OHOS, "%s: Cannot accept clients connections. There is no server socket created",
144 Q_FUNC_INFO);
145 return false;
146 }
147
148 auto optAcceptErrorCode = QOhosJsThreadGateway::eval(
149 [&](QOhosJsState &jsState) -> std::optional<QOhosBluetoothErrorCode> {
150 try {
151 jsState.eval(
152 "@ohos.bluetooth.socket.sppAccept(*)",
153 {
154 *m_serverSocketHandle,
155 [selfWeakRef = weak_from_this(), armedServerSocketWatch = QtOhos::makeWeakPtr(m_serverSocketHandle)](
156 const QNapi::CallbackInfo &callbackInfo) {
157 QNapi::Value error;
158 QNapi::Value data;
159 callbackInfo.getLeadingArgs(Q_FUNC_INFO, error, data);
160 int clientSocketId = data.IsNumber()
161 ? QNapi::checkedCast<QNapi::Number>(data).Int32Value()
162 : invalidSocketDescriptor;
163
164 if (clientSocketId == invalidSocketDescriptor) {
165 const bool abortedByOwnServerSocketClose =
166 armedServerSocketWatch.expired();
167 if (abortedByOwnServerSocketClose) {
168 qOhosPrintfInfo(
169 "%s: sppAccept() was aborted by closing the server socket",
170 Q_FUNC_INFO);
171 return;
172 }
173
174 const auto errorCode =
175 tryGetKnownErrorCode(error, Q_FUNC_INFO)
176 .value_or(QOhosBluetoothErrorCode::OperationFailed);
177 qOhosPrintfError(
178 "%s: sppAccept() failed with error code: %u", Q_FUNC_INFO,
179 qToUnderlying(errorCode));
180 QtOhos::invokeInQtThread(
181 [selfWeakRef, errorCode]() {
182 if (const auto self = selfWeakRef.lock())
183 self->onAcceptFailed(errorCode);
184 });
185 return;
186 }
187
188 auto clientSocketHandle = makeSppClientSocketHandle(clientSocketId);
189
190 QtOhos::invokeInQtThread(
191 [selfWeakRef, clientSocketHandle]() {
192 if (const auto self = selfWeakRef.lock())
193 self->onClientAccepted(clientSocketHandle);
194 });
195 }
196 });
197 return std::nullopt;
198 } catch (const Napi::Error &error) {
199 return tryGetKnownErrorCode(error.Value(), Q_FUNC_INFO);
200 }
201 });
202
203 if (optAcceptErrorCode) {
204 qCCritical(
205 QT_BT_OHOS, "%s: sppAccept() failed with error code: %u", Q_FUNC_INFO,
206 qToUnderlying(*optAcceptErrorCode));
207 reportError(*optAcceptErrorCode);
208 return false;
209 }
210
211 return true;
212}
213
214void QOhosBluetoothServerProxy::onClientAccepted(std::shared_ptr<int> clientSocketHandle)
215{
217 qCDebug(
218 QT_BT_OHOS, "%s: service is not registered anymore. Dropping the accepted client ...",
219 Q_FUNC_INFO);
220 return;
221 }
222
223 if (!QOhosBluetoothSocketProxy::registerPendingSocketHandle(clientSocketHandle)) {
224 reportError(QOhosBluetoothErrorCode::OperationFailed);
225 scheduleAcceptNextConnection();
226 return;
227 }
228
229 Q_EMIT clientAccepted(*clientSocketHandle);
230
231 scheduleAcceptNextConnection();
232}
233
234void QOhosBluetoothServerProxy::onAcceptFailed(QOhosBluetoothErrorCode errorCode)
235{
237 return;
238
239 reportError(errorCode);
240 close();
241}
242
243void QOhosBluetoothServerProxy::scheduleAcceptNextConnection()
244{
245 QMetaObject::invokeMethod(
246 this,
247 [selfWeakRef = weak_from_this()]() {
248 if (const auto self = selfWeakRef.lock())
249 self->acceptNextConnection();
250 },
251 Qt::QueuedConnection);
252}
253
254void QOhosBluetoothServerProxy::acceptNextConnection()
255{
257 return;
258
259 if (!checkAccessBluetoothPermissionGranted(Q_FUNC_INFO)) {
260 reportError(QOhosBluetoothErrorCode::PermissionDenied);
261 close();
262 return;
263 }
264
265 const auto optBluetoothState = QOhosBluetoothAccessProxy::instance()->tryGetBluetoothState();
266 if (!optBluetoothState) {
267 qCWarning(
268 QT_BT_OHOS,
269 "%s: the bluetooth state is unknown. Cannot accept next clients connections",
270 Q_FUNC_INFO);
271 reportError(QOhosBluetoothErrorCode::OperationFailed);
272 close();
273 return;
274 }
275
276 if (*optBluetoothState != QOhosBluetoothAccessProxy::BluetoothState::STATE_ON) {
277 qCWarning(
278 QT_BT_OHOS, "%s: bluetooth is turned off. Cannot accept next clients connections",
279 Q_FUNC_INFO);
280 reportError(QOhosBluetoothErrorCode::BluetoothDisabled);
281 close();
282 return;
283 }
284
285 if (!accept())
286 close();
287}
288
290{
291 if (!m_serverSocketHandle)
292 return;
293
294 m_serverSocketHandle.reset();
295 m_registeredServiceName.reset();
296 m_optRegisteredServiceId.reset();
297
298 reportAcceptingStopped();
299}
300
302{
303 return bool(m_registeredServiceName);
304}
305
307{
308 return m_registeredServiceName;
309}
310
312{
313 return m_optRegisteredServiceId;
314}
315
316void QOhosBluetoothServerProxy::reportError(QOhosBluetoothErrorCode errorCode)
317{
318 QMetaObject::invokeMethod(
319 this,
320 [this, errorCode]() {
321 Q_EMIT errorOccurred(errorCode);
322 },
323 Qt::QueuedConnection);
324}
325
326void QOhosBluetoothServerProxy::reportAcceptingStopped()
327{
328 QMetaObject::invokeMethod(
329 this, &QOhosBluetoothServerProxy::acceptingStopped, Qt::QueuedConnection);
330}
331
332}
333
334QT_END_NAMESPACE
335
336#include "moc_qohosbluetoothserver_p.cpp"
std::optional< std::uint64_t > tryGetRegisteredServiceId() const
std::optional< QString > tryGetRegisteredServiceName() const
bool listen(const QString &serviceName, const QString &uuid, bool secure)
Combined button and popup list for selecting options.