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
qbluetoothsocket_ohos.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/qbluetoothdeviceinfo.h>
7#include <QtBluetooth/qbluetoothsocket.h>
8#include <QtBluetooth/private/qohosbluetoothlocaldevice_p.h>
9#include <QtBluetooth/private/qohosbluetoothsocket_p.h>
10
11#include <QtCore/q26numeric.h>
12#include <QtCore/qloggingcategory.h>
13
14#include <cstring>
15
16QT_BEGIN_NAMESPACE
17
18using QtOhosBluetooth::QOhosBluetoothErrorCode;
19
20Q_DECLARE_LOGGING_CATEGORY(QT_BT_OHOS)
21
22namespace {
23
24struct SocketErrorReport
25{
26 QBluetoothSocket::SocketError error = QBluetoothSocket::SocketError::UnknownSocketError;
27 QString message;
28};
29
30SocketErrorReport makeSocketErrorReport(QOhosBluetoothErrorCode errorCode)
31{
32 switch (errorCode) {
33 case QOhosBluetoothErrorCode::PermissionDenied:
34 return {
35 .error = QBluetoothSocket::SocketError::MissingPermissionsError,
36 .message = QBluetoothSocket::tr("Missing permissions for socket operation")};
37 case QOhosBluetoothErrorCode::InvalidParameter:
38 return {
39 .error = QBluetoothSocket::SocketError::OperationError,
40 .message = QBluetoothSocket::tr("Socket operation rejected by the system")};
41 case QOhosBluetoothErrorCode::CapabilityNotSupported:
42 case QOhosBluetoothErrorCode::ProfileNotSupported:
43 return {
44 .error = QBluetoothSocket::SocketError::UnsupportedProtocolError,
45 .message = QBluetoothSocket::tr("Socket type not supported")};
46 case QOhosBluetoothErrorCode::InputOutput:
47 return {
48 .error = QBluetoothSocket::SocketError::UnknownSocketError,
49 .message = QBluetoothSocket::tr("I/O error on socket")};
50 case QOhosBluetoothErrorCode::ServiceStopped:
51 case QOhosBluetoothErrorCode::BluetoothDisabled:
52 return {
53 .error = QBluetoothSocket::SocketError::NetworkError,
54 .message = QBluetoothSocket::tr("Bluetooth is not available")};
55 case QOhosBluetoothErrorCode::UserDidNotRespond:
56 case QOhosBluetoothErrorCode::UserRefused:
57 case QOhosBluetoothErrorCode::OperationFailed:
58 break;
59 }
60
61 return {
62 .error = QBluetoothSocket::SocketError::OperationError,
63 .message = QBluetoothSocket::tr("Operation failed on socket")};
64}
65
66}
67
68QBluetoothSocketPrivateOhos::QBluetoothSocketPrivateOhos(QBluetoothSocket *qq)
69 : QBluetoothSocketBasePrivate{qq}
70{
71 secFlags = QBluetooth::Security::Secure;
72
73 QObject::connect(
74 &m_bluetoothSocketProxy, &QtOhosBluetooth::QOhosBluetoothSocketProxy::connected,
75 this,
76 [this](int socketDescriptor) {
77 if (state != QBluetoothSocket::SocketState::ConnectingState)
78 return;
79
80 socket = socketDescriptor;
81 q_ptr->setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered);
82 q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
83
84 if (!rxBuffer.isEmpty())
85 Q_EMIT q_ptr->readyRead();
86 });
87
88 QObject::connect(
89 &m_bluetoothSocketProxy, &QtOhosBluetooth::QOhosBluetoothSocketProxy::disconnected,
90 this,
91 [this]() {
92 onProxyDisconnected();
93 });
94
95 QObject::connect(
96 &m_bluetoothSocketProxy, &QtOhosBluetooth::QOhosBluetoothSocketProxy::dataReceived,
97 this,
98 [this](const QByteArray &receivedData) {
99 if (state != QBluetoothSocket::SocketState::ConnectingState
100 && state != QBluetoothSocket::SocketState::ConnectedState) {
101 return;
102 }
103
104 char *target = rxBuffer.reserve(receivedData.size());
105 std::memcpy(target, receivedData.constData(), receivedData.size());
106
107 if (state == QBluetoothSocket::SocketState::ConnectedState)
108 Q_EMIT q_ptr->readyRead();
109 });
110
111 QObject::connect(
112 &m_bluetoothSocketProxy, &QtOhosBluetooth::QOhosBluetoothSocketProxy::errorOccurred,
113 this,
114 [this](QOhosBluetoothErrorCode errorCode) {
115 onProxyError(errorCode);
116 });
117}
118
119QBluetoothSocketPrivateOhos::~QBluetoothSocketPrivateOhos()
120{
121 abort();
122}
123
124void QBluetoothSocketPrivateOhos::onProxyError(QOhosBluetoothErrorCode errorCode)
125{
126 const auto report = makeSocketErrorReport(errorCode);
127
128 errorString = report.message;
129 q_ptr->setSocketError(report.error);
130
131 if (state == QBluetoothSocket::SocketState::ConnectingState
132 || state == QBluetoothSocket::SocketState::ClosingState) {
133 socket = QtOhosBluetooth::invalidSocketDescriptor;
134 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
135 }
136}
137
138void QBluetoothSocketPrivateOhos::onProxyDisconnected()
139{
140 socket = QtOhosBluetooth::invalidSocketDescriptor;
141 q_ptr->setOpenMode(QIODevice::NotOpen);
142 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
143 Q_EMIT q_ptr->readChannelFinished();
144}
145
146bool QBluetoothSocketPrivateOhos::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
147{
148 socketType = type;
149
150 return type == QBluetoothServiceInfo::RfcommProtocol;
151}
152
153void QBluetoothSocketPrivateOhos::connectToServiceHelper(
154 const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
155{
156 if (openMode != QIODevice::ReadWrite)
157 qCWarning(QT_BT_OHOS, "%s: Only read-write socket mode supported.", Q_FUNC_INFO);
158
159 if (state != QBluetoothSocket::SocketState::UnconnectedState) {
160 qCWarning(QT_BT_OHOS, "%s: Called on busy socket", Q_FUNC_INFO);
161 errorString = QBluetoothSocket::tr("Trying to connect while connection is established");
162 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
163 return;
164 }
165
166 rxBuffer.clear();
167 q_ptr->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
168
169 const auto secure = (secFlags != QBluetooth::Security::NoSecurity);
170
171 const auto connectRequested = m_bluetoothSocketProxy.connect(
172 address.toString(), uuid.toString(QUuid::WithoutBraces), secure);
173
174 if (!connectRequested)
175 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
176}
177
178void QBluetoothSocketPrivateOhos::connectToService(
179 const QBluetoothServiceInfo &serviceInfo, QIODevice::OpenMode openMode)
180{
181 const auto protocol = serviceInfo.socketProtocol() != QBluetoothServiceInfo::UnknownProtocol
182 ? serviceInfo.socketProtocol()
183 : q_ptr->socketType();
184
185 if (!ensureNativeSocket(protocol)) {
186 qCWarning(QT_BT_OHOS, "%s: Only RfcommProtocol supported", Q_FUNC_INFO);
187 errorString = QBluetoothSocket::tr("Socket type not supported");
188 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
189 return;
190 }
191
192 connectToServiceHelper(serviceInfo.device().address(), serviceInfo.serviceUuid(), openMode);
193}
194
195void QBluetoothSocketPrivateOhos::connectToService(
196 const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
197{
198 if (!ensureNativeSocket(q_ptr->socketType())) {
199 qCWarning(QT_BT_OHOS, "%s: Only RfcommProtocol supported", Q_FUNC_INFO);
200 errorString = QBluetoothSocket::tr("Socket type not supported");
201 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
202 return;
203 }
204
205 connectToServiceHelper(address, uuid, openMode);
206}
207
208void QBluetoothSocketPrivateOhos::connectToService(
209 const QBluetoothAddress &, quint16, QIODevice::OpenMode)
210{
211 qCWarning(
212 QT_BT_OHOS, "%s: HarmonyOS connects to a service by its UUID, not by an RFCOMM port",
213 Q_FUNC_INFO);
214 errorString = QBluetoothSocket::tr("Connecting to a port is not supported");
215 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
216}
217
218void QBluetoothSocketPrivateOhos::abort()
219{
220 close();
221}
222
223QString QBluetoothSocketPrivateOhos::localName() const
224{
225 const auto optLocalDeviceName =
226 QtOhosBluetooth::QOhosBluetoothLocalDeviceProxy::instance()->tryGetLocalDeviceName();
227 return optLocalDeviceName
228 ? *optLocalDeviceName
229 : QString();
230}
231
232QBluetoothAddress QBluetoothSocketPrivateOhos::localAddress() const
233{
234 return {};
235}
236
237quint16 QBluetoothSocketPrivateOhos::localPort() const
238{
239 return 0;
240}
241
242QString QBluetoothSocketPrivateOhos::peerName() const
243{
244 const auto optName = m_bluetoothSocketProxy.tryGetPeerDeviceName();
245 return optName
246 ? *optName
247 : QString();
248}
249
250QBluetoothAddress QBluetoothSocketPrivateOhos::peerAddress() const
251{
252 const auto optAddress = m_bluetoothSocketProxy.tryGetPeerDeviceAddress();
253 return optAddress
254 ? QBluetoothAddress(*optAddress)
255 : QBluetoothAddress();
256}
257
258quint16 QBluetoothSocketPrivateOhos::peerPort() const
259{
260 return 0;
261}
262
263qint64 QBluetoothSocketPrivateOhos::writeData(const char *data, qint64 maxSize)
264{
265 if (state != QBluetoothSocket::SocketState::ConnectedState) {
266 errorString = QBluetoothSocket::tr("No SPP connection between devices. Cannot write.");
267 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
268 return -1;
269 }
270
271 if (!m_bluetoothSocketProxy.write(data, maxSize))
272 return -1;
273
274 QMetaObject::invokeMethod(
275 q_ptr,
276 [this, maxSize]() {
277 Q_EMIT q_ptr->bytesWritten(maxSize);
278 },
279 Qt::QueuedConnection);
280
281 return maxSize;
282}
283
284qint64 QBluetoothSocketPrivateOhos::readData(char *data, qint64 maxSize)
285{
286 if (!rxBuffer.isEmpty())
287 return rxBuffer.read(data, q26::saturate_cast<qsizetype>(maxSize));
288
289 if (state != QBluetoothSocket::SocketState::ConnectedState) {
290 errorString = QBluetoothSocket::tr("Cannot read while not connected");
291 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
292 return -1;
293 }
294
295 return 0;
296}
297
298void QBluetoothSocketPrivateOhos::close()
299{
300 m_bluetoothSocketProxy.close();
301}
302
303bool QBluetoothSocketPrivateOhos::setSocketDescriptor(
304 int socketDescriptor, QBluetoothServiceInfo::Protocol type,
305 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
306{
307 if (openMode != QIODevice::ReadWrite)
308 qCWarning(QT_BT_OHOS, "%s: Only read-write socket mode supported.", Q_FUNC_INFO);
309
310 if (!ensureNativeSocket(type)) {
311 qCWarning(QT_BT_OHOS, "%s: Only RfcommProtocol supported", Q_FUNC_INFO);
312 errorString = QBluetoothSocket::tr("Socket type not supported");
313 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
314 return false;
315 }
316
317 if (socketState != QBluetoothSocket::SocketState::ConnectedState) {
318 qCWarning(
319 QT_BT_OHOS, "%s: a socket accepted by the server can only be taken over as connected",
320 Q_FUNC_INFO);
321 errorString = QBluetoothSocket::tr("Taking over the socket failed");
322 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
323 return false;
324 }
325
326 if (state != QBluetoothSocket::SocketState::UnconnectedState
327 || socket != QtOhosBluetooth::invalidSocketDescriptor) {
328 qCWarning(QT_BT_OHOS, "%s: Called on busy socket", Q_FUNC_INFO);
329 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
330 q_ptr->setSocketError(QBluetoothSocket::SocketError::OperationError);
331 return false;
332 }
333
334 auto socketHandle =
335 QtOhosBluetooth::QOhosBluetoothSocketProxy::takePendingSocketHandle(socketDescriptor);
336 if (!socketHandle) {
337 qCWarning(
338 QT_BT_OHOS, "%s: no socket accepted by the server for descriptor %d", Q_FUNC_INFO,
339 socketDescriptor);
340 errorString = QBluetoothSocket::tr("Taking over the socket failed");
341 q_ptr->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
342 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
343 return false;
344 }
345
346 rxBuffer.clear();
347
348 if (!m_bluetoothSocketProxy.takeOverSocket(std::move(socketHandle))) {
349 errorString = QBluetoothSocket::tr("Obtaining data channel for service failed");
350 q_ptr->setSocketError(QBluetoothSocket::SocketError::NetworkError);
351 q_ptr->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
352 return false;
353 }
354
355 socket = socketDescriptor;
356 q_ptr->setOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered);
357 q_ptr->setSocketState(socketState);
358
359 return true;
360}
361
362qint64 QBluetoothSocketPrivateOhos::bytesAvailable() const
363{
364 return rxBuffer.size();
365}
366
367bool QBluetoothSocketPrivateOhos::canReadLine() const
368{
369 return rxBuffer.canReadLine();
370}
371
372qint64 QBluetoothSocketPrivateOhos::bytesToWrite() const
373{
374 return 0;
375}
376
377QT_END_NAMESPACE