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