1 | // Copyright (C) 2018 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 | |
4 | #include "qbluetoothsocket.h" |
5 | #include "qbluetoothsocket_bluezdbus_p.h" |
6 | |
7 | #include "bluez/bluez_data_p.h" |
8 | #include "bluez/bluez5_helper_p.h" |
9 | #include "bluez/adapter1_bluez5_p.h" |
10 | #include "bluez/device1_bluez5_p.h" |
11 | #include "bluez/objectmanager_p.h" |
12 | #include "bluez/profile1_p.h" |
13 | #include "bluez/profile1context_p.h" |
14 | #include "bluez/profilemanager1_p.h" |
15 | |
16 | #include <QtBluetooth/qbluetoothdeviceinfo.h> |
17 | #include <QtBluetooth/qbluetoothserviceinfo.h> |
18 | |
19 | #include <QtCore/qloggingcategory.h> |
20 | #include <QtCore/qrandom.h> |
21 | |
22 | #include <QtNetwork/qlocalsocket.h> |
23 | |
24 | #include <unistd.h> |
25 | |
26 | QT_BEGIN_NAMESPACE |
27 | |
28 | using namespace Qt::StringLiterals; |
29 | |
30 | Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ) |
31 | |
32 | QBluetoothSocketPrivateBluezDBus::QBluetoothSocketPrivateBluezDBus() |
33 | { |
34 | secFlags = QBluetooth::Security::NoSecurity; |
35 | } |
36 | |
37 | QBluetoothSocketPrivateBluezDBus::~QBluetoothSocketPrivateBluezDBus() |
38 | { |
39 | } |
40 | |
41 | bool QBluetoothSocketPrivateBluezDBus::ensureNativeSocket(QBluetoothServiceInfo::Protocol type) |
42 | { |
43 | switch (type) { |
44 | case QBluetoothServiceInfo::UnknownProtocol: |
45 | break; |
46 | case QBluetoothServiceInfo::RfcommProtocol: |
47 | case QBluetoothServiceInfo::L2capProtocol: |
48 | socketType = type; |
49 | return true; |
50 | } |
51 | |
52 | return false; |
53 | } |
54 | |
55 | void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper( |
56 | const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) |
57 | { |
58 | // TODO Remove when Bluez4 support dropped |
59 | // Only used by QBluetoothSocketPrivateBluez |
60 | Q_UNUSED(openMode); |
61 | Q_UNUSED(address); |
62 | Q_UNUSED(port); |
63 | } |
64 | |
65 | static QString findRemoteDevicePath(const QBluetoothAddress &address) |
66 | { |
67 | OrgFreedesktopDBusObjectManagerInterface manager(QStringLiteral("org.bluez"), |
68 | QStringLiteral("/"), |
69 | QDBusConnection::systemBus()); |
70 | |
71 | bool ok = false; |
72 | const QString adapterPath = findAdapterForAddress(wantedAddress: QBluetoothAddress(), ok: &ok); |
73 | if (!ok) |
74 | return QString(); |
75 | |
76 | auto reply = manager.GetManagedObjects(); |
77 | reply.waitForFinished(); |
78 | if (reply.isError()) |
79 | return QString(); |
80 | |
81 | ManagedObjectList objectList = reply.value(); |
82 | for (ManagedObjectList::const_iterator it = objectList.constBegin(); |
83 | it != objectList.constEnd(); ++it) { |
84 | const QDBusObjectPath &path = it.key(); |
85 | const InterfaceList &ifaceList = it.value(); |
86 | |
87 | for (InterfaceList::const_iterator ifaceIter = ifaceList.constBegin(); |
88 | ifaceIter != ifaceList.constEnd(); ++ifaceIter) { |
89 | if (ifaceIter.key() == QStringLiteral("org.bluez.Device1")) { |
90 | if (path.path().indexOf(s: adapterPath) != 0) |
91 | continue; // devices whose path does not start with same path we skip |
92 | |
93 | OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), |
94 | path.path(), QDBusConnection::systemBus()); |
95 | if (device.adapter().path() != adapterPath) |
96 | continue; |
97 | |
98 | const QBluetoothAddress btAddress(device.address()); |
99 | if (btAddress.isNull() || btAddress != address) |
100 | continue; |
101 | |
102 | return path.path(); |
103 | } |
104 | } |
105 | } |
106 | |
107 | return QString(); |
108 | } |
109 | |
110 | void QBluetoothSocketPrivateBluezDBus::connectToServiceHelper( |
111 | const QBluetoothAddress &address, const QBluetoothUuid &uuid, |
112 | QIODevice::OpenMode openMode) |
113 | { |
114 | Q_Q(QBluetoothSocket); |
115 | |
116 | int i = 0; |
117 | bool success = false; |
118 | profileUuid = uuid.toString(mode: QUuid::WithoutBraces); |
119 | |
120 | if (!profileManager) { |
121 | profileManager = new OrgBluezProfileManager1Interface( |
122 | QStringLiteral("org.bluez"), |
123 | QStringLiteral("/org/bluez"), |
124 | QDBusConnection::systemBus(), |
125 | this); |
126 | } |
127 | |
128 | if (profileContext) { |
129 | qCDebug(QT_BT_BLUEZ) << "Profile context still active. close socket first."; |
130 | q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError); |
131 | return; |
132 | } |
133 | |
134 | |
135 | profileContext = new OrgBluezProfile1ContextInterface(this); |
136 | connect(sender: profileContext, signal: &OrgBluezProfile1ContextInterface::newConnection, |
137 | context: this, slot: &QBluetoothSocketPrivateBluezDBus::remoteConnected); |
138 | |
139 | for (i = 0; i < 10 && !success; i++) { |
140 | // profile registration might fail in case other service uses same path |
141 | // try 10 times and otherwise abort |
142 | |
143 | profilePath = u"/qt/btsocket/%1%2/%3"_s. |
144 | arg(a: sanitizeNameForDBus(text: QCoreApplication::applicationName())). |
145 | arg(a: QCoreApplication::applicationPid()). |
146 | arg(a: QRandomGenerator::global()->generate()); |
147 | |
148 | success = QDBusConnection::systemBus().registerObject( |
149 | path: profilePath, object: profileContext, options: QDBusConnection::ExportAllSlots); |
150 | } |
151 | |
152 | if (!success) { |
153 | // we could not register the profile |
154 | qCWarning(QT_BT_BLUEZ) << "Cannot export serial client profile on DBus"; |
155 | |
156 | delete profileContext; |
157 | profileContext = nullptr; |
158 | |
159 | errorString = QBluetoothSocket::tr(s: "Cannot export profile on DBus"); |
160 | q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError); |
161 | |
162 | return; |
163 | } |
164 | |
165 | QVariantMap profileOptions; |
166 | profileOptions.insert(QStringLiteral("Role"), QStringLiteral( "client")); |
167 | profileOptions.insert(QStringLiteral("Service"), value: profileUuid); |
168 | profileOptions.insert(QStringLiteral("Name"), |
169 | QStringLiteral("QBluetoothSocket-%1").arg(a: QCoreApplication::applicationPid())); |
170 | |
171 | // TODO support more profile parameter |
172 | // profileOptions.insert(QStringLiteral("Channel"), 0); |
173 | |
174 | qCDebug(QT_BT_BLUEZ) << "Registering client profile on"<< profilePath << "with options:"; |
175 | qCDebug(QT_BT_BLUEZ) << profileOptions; |
176 | QDBusPendingReply<> reply = profileManager->RegisterProfile( |
177 | profile: QDBusObjectPath(profilePath), |
178 | UUID: profileUuid, |
179 | options: profileOptions); |
180 | reply.waitForFinished(); |
181 | if (reply.isError()) { |
182 | qCWarning(QT_BT_BLUEZ) << "Client profile registration failed:" |
183 | << reply.error().message(); |
184 | |
185 | QDBusConnection::systemBus().unregisterObject(path: profilePath); |
186 | errorString = QBluetoothSocket::tr(s: "Cannot register profile on DBus"); |
187 | q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError); |
188 | return; |
189 | } |
190 | |
191 | remoteDevicePath = findRemoteDevicePath(address); |
192 | if (remoteDevicePath.isEmpty()) { |
193 | qCWarning(QT_BT_BLUEZ) << "Unknown remote device:"<< address |
194 | << "Try device discovery first"; |
195 | clearSocket(); |
196 | |
197 | errorString = QBluetoothSocket::tr(s: "Cannot find remote device"); |
198 | q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError); |
199 | return; |
200 | } |
201 | |
202 | OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath, |
203 | QDBusConnection::systemBus()); |
204 | reply = device.ConnectProfile(UUID: profileUuid); |
205 | QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); |
206 | connect(sender: watcher, signal: &QDBusPendingCallWatcher::finished, |
207 | context: this, slot: &QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler); |
208 | |
209 | q->setOpenMode(openMode); |
210 | q->setSocketState(QBluetoothSocket::SocketState::ConnectingState); |
211 | } |
212 | |
213 | void QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler( |
214 | QDBusPendingCallWatcher *watcher) |
215 | { |
216 | Q_Q(QBluetoothSocket); |
217 | |
218 | QDBusPendingReply<> reply = *watcher; |
219 | if (reply.isError()) { |
220 | qCWarning(QT_BT_BLUEZ) << "Cannot connect to profile/service."; |
221 | |
222 | clearSocket(); |
223 | |
224 | errorString = QBluetoothSocket::tr(s: "Cannot connect to remote profile"); |
225 | q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError); |
226 | } |
227 | watcher->deleteLater(); |
228 | |
229 | // QTBUG-82413, unregisterProfile at profileUuid, |
230 | // so it can be registered for new devices connecting to the same profile UUID. |
231 | if (profileManager) { |
232 | qCDebug(QT_BT_BLUEZ) << "Unregistering client profile on"<< profilePath |
233 | << "in connectToServiceReplyHandler() callback."; |
234 | |
235 | QDBusPendingReply<> reply = profileManager->UnregisterProfile(profile: QDBusObjectPath(profilePath)); |
236 | reply.waitForFinished(); |
237 | if (reply.isError()) |
238 | qCWarning(QT_BT_BLUEZ) << "Unregister profile:"<< reply.error().message(); |
239 | |
240 | QDBusConnection::systemBus().unregisterObject(path: profilePath); |
241 | |
242 | delete profileManager; |
243 | profileManager = nullptr; |
244 | } |
245 | } |
246 | |
247 | void QBluetoothSocketPrivateBluezDBus::connectToService( |
248 | const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode) |
249 | { |
250 | Q_Q(QBluetoothSocket); |
251 | QBluetoothUuid targetService; |
252 | |
253 | targetService = service.serviceUuid(); |
254 | if (targetService.isNull()) { |
255 | // Do we have serialport service class? |
256 | if (service.serviceClassUuids().contains(t: QBluetoothUuid::ServiceClassUuid::SerialPort)) |
257 | targetService = QBluetoothUuid::ServiceClassUuid::SerialPort; |
258 | } |
259 | |
260 | if (targetService.isNull()) { |
261 | qCWarning(QT_BT_BLUEZ) << "Cannot find appropriate serviceUuid" |
262 | << "or SerialPort service class uuid"; |
263 | errorString = QBluetoothSocket::tr(s: "Missing serviceUuid or Serial Port service class uuid"); |
264 | q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError); |
265 | return; |
266 | } |
267 | |
268 | if (service.socketProtocol() != QBluetoothServiceInfo::Protocol::UnknownProtocol) |
269 | socketType = service.socketProtocol(); |
270 | qCDebug(QT_BT_BLUEZ) << "Socket protocol used:"<< socketType; |
271 | |
272 | connectToService(address: service.device().address(), uuid: targetService, openMode); |
273 | } |
274 | |
275 | void QBluetoothSocketPrivateBluezDBus::connectToService( |
276 | const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode) |
277 | { |
278 | Q_Q(QBluetoothSocket); |
279 | |
280 | if (address.isNull()) { |
281 | qCWarning(QT_BT_BLUEZ) << "Invalid address to remote address passed."; |
282 | errorString = QBluetoothSocket::tr(s: "Invalid Bluetooth address passed to connectToService()"); |
283 | q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError); |
284 | return; |
285 | } |
286 | |
287 | if (uuid.isNull()) { |
288 | qCWarning(QT_BT_BLUEZ) << "Cannot find appropriate serviceUuid" |
289 | << "or SerialPort service class uuid"; |
290 | errorString = QBluetoothSocket::tr(s: "Missing serviceUuid or Serial Port service class uuid"); |
291 | q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError); |
292 | return; |
293 | } |
294 | |
295 | if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) { |
296 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluezDBus::connectToService called on busy socket"; |
297 | errorString = QBluetoothSocket::tr(s: "Trying to connect while connection is in progress"); |
298 | q->setSocketError(QBluetoothSocket::SocketError::OperationError); |
299 | return; |
300 | } |
301 | |
302 | if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) { |
303 | qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluezDBus::connectToService cannot " |
304 | "connect with 'UnknownProtocol' (type provided by given service)"; |
305 | errorString = QBluetoothSocket::tr(s: "Socket type not supported"); |
306 | q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError); |
307 | return; |
308 | } |
309 | |
310 | if (!ensureNativeSocket(type: q->socketType())) { |
311 | errorString = QBluetoothSocket::tr(s: "Socket type not supported"); |
312 | q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError); |
313 | return; |
314 | } |
315 | connectToServiceHelper(address, uuid, openMode); |
316 | } |
317 | |
318 | void QBluetoothSocketPrivateBluezDBus::connectToService( |
319 | const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) |
320 | { |
321 | |
322 | Q_UNUSED(port); |
323 | Q_UNUSED(address); |
324 | Q_UNUSED(openMode); |
325 | Q_Q(QBluetoothSocket); |
326 | |
327 | errorString = tr(s: "Connecting to port is not supported via Bluez DBus"); |
328 | q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError); |
329 | qCWarning(QT_BT_BLUEZ) << "Connecting to port is not supported (Uuid required)"; |
330 | } |
331 | |
332 | void QBluetoothSocketPrivateBluezDBus::abort() |
333 | { |
334 | if (localSocket) { |
335 | localSocket->close(); |
336 | // delayed disconnected signal emission when localSocket closes |
337 | } else { |
338 | Q_Q(QBluetoothSocket); |
339 | |
340 | clearSocket(); |
341 | q->setOpenMode(QIODevice::NotOpen); |
342 | q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState); |
343 | emit q->readChannelFinished(); |
344 | } |
345 | } |
346 | |
347 | QString QBluetoothSocketPrivateBluezDBus::localName() const |
348 | { |
349 | bool ok = false; |
350 | const QString adapterPath = findAdapterForAddress(wantedAddress: QBluetoothAddress(), ok: &ok); |
351 | if (!ok) |
352 | return QString(); |
353 | |
354 | OrgBluezAdapter1Interface adapter(QStringLiteral("org.bluez"), adapterPath, |
355 | QDBusConnection::systemBus()); |
356 | return QString(adapter.alias()); |
357 | } |
358 | |
359 | QBluetoothAddress QBluetoothSocketPrivateBluezDBus::localAddress() const |
360 | { |
361 | bool ok = false; |
362 | const QString adapterPath = findAdapterForAddress(wantedAddress: QBluetoothAddress(), ok: &ok); |
363 | if (!ok) |
364 | return QBluetoothAddress(); |
365 | |
366 | OrgBluezAdapter1Interface adapter(QStringLiteral("org.bluez"), adapterPath, |
367 | QDBusConnection::systemBus()); |
368 | return QBluetoothAddress(adapter.address()); |
369 | } |
370 | |
371 | quint16 QBluetoothSocketPrivateBluezDBus::localPort() const |
372 | { |
373 | int descriptor = -1; |
374 | |
375 | if (localSocket) |
376 | descriptor = int(localSocket->socketDescriptor()); |
377 | if (descriptor == -1) |
378 | return 0; |
379 | |
380 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
381 | sockaddr_rc addr; |
382 | socklen_t addrLength = sizeof(addr); |
383 | |
384 | if (::getsockname(fd: descriptor, addr: reinterpret_cast<sockaddr *>(&addr), len: &addrLength) == 0) |
385 | return (addr.rc_channel); |
386 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
387 | sockaddr_l2 addr; |
388 | socklen_t addrLength = sizeof(addr); |
389 | |
390 | if (::getsockname(fd: descriptor, addr: reinterpret_cast<sockaddr *>(&addr), len: &addrLength) == 0) |
391 | return addr.l2_psm; |
392 | } |
393 | |
394 | return 0; |
395 | } |
396 | |
397 | QString QBluetoothSocketPrivateBluezDBus::peerName() const |
398 | { |
399 | if (remoteDevicePath.isEmpty()) |
400 | return QString(); |
401 | |
402 | OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath, |
403 | QDBusConnection::systemBus()); |
404 | return device.alias(); |
405 | } |
406 | |
407 | QBluetoothAddress QBluetoothSocketPrivateBluezDBus::peerAddress() const |
408 | { |
409 | if (remoteDevicePath.isEmpty()) |
410 | return QBluetoothAddress(); |
411 | |
412 | OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath, |
413 | QDBusConnection::systemBus()); |
414 | return QBluetoothAddress(device.address()); |
415 | } |
416 | |
417 | quint16 QBluetoothSocketPrivateBluezDBus::peerPort() const |
418 | { |
419 | int descriptor = -1; |
420 | |
421 | if (localSocket) |
422 | descriptor = int(localSocket->socketDescriptor()); |
423 | if (descriptor == -1) |
424 | return 0; |
425 | |
426 | if (socketType == QBluetoothServiceInfo::RfcommProtocol) { |
427 | sockaddr_rc addr; |
428 | socklen_t addrLength = sizeof(addr); |
429 | |
430 | if (::getpeername(fd: descriptor, addr: reinterpret_cast<sockaddr *>(&addr), len: &addrLength) == 0) |
431 | return addr.rc_channel; |
432 | } else if (socketType == QBluetoothServiceInfo::L2capProtocol) { |
433 | sockaddr_l2 addr; |
434 | socklen_t addrLength = sizeof(addr); |
435 | |
436 | if (::getpeername(fd: descriptor, addr: reinterpret_cast<sockaddr *>(&addr), len: &addrLength) == 0) |
437 | return addr.l2_psm; |
438 | } |
439 | |
440 | return 0; |
441 | } |
442 | |
443 | qint64 QBluetoothSocketPrivateBluezDBus::writeData(const char *data, qint64 maxSize) |
444 | { |
445 | Q_UNUSED(data); |
446 | Q_UNUSED(maxSize); |
447 | |
448 | Q_Q(QBluetoothSocket); |
449 | |
450 | if (state != QBluetoothSocket::SocketState::ConnectedState) { |
451 | errorString = QBluetoothSocket::tr(s: "Cannot write while not connected"); |
452 | q->setSocketError(QBluetoothSocket::SocketError::OperationError); |
453 | return -1; |
454 | } |
455 | |
456 | if (localSocket) |
457 | return localSocket->write(data, len: maxSize); |
458 | |
459 | return -1; |
460 | } |
461 | |
462 | qint64 QBluetoothSocketPrivateBluezDBus::readData(char *data, qint64 maxSize) |
463 | { |
464 | Q_UNUSED(data); |
465 | Q_UNUSED(maxSize); |
466 | |
467 | Q_Q(QBluetoothSocket); |
468 | |
469 | if (state != QBluetoothSocket::SocketState::ConnectedState) { |
470 | errorString = QBluetoothSocket::tr(s: "Cannot read while not connected"); |
471 | q->setSocketError(QBluetoothSocket::SocketError::OperationError); |
472 | return -1; |
473 | } |
474 | |
475 | if (localSocket) |
476 | return localSocket->read(data, maxlen: maxSize); |
477 | |
478 | return -1; |
479 | } |
480 | |
481 | void QBluetoothSocketPrivateBluezDBus::close() |
482 | { |
483 | abort(); |
484 | } |
485 | |
486 | bool QBluetoothSocketPrivateBluezDBus::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, |
487 | QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode) |
488 | { |
489 | Q_UNUSED(socketDescriptor); |
490 | Q_UNUSED(socketType); |
491 | Q_UNUSED(socketState); |
492 | Q_UNUSED(openMode); |
493 | return false; |
494 | } |
495 | |
496 | qint64 QBluetoothSocketPrivateBluezDBus::bytesAvailable() const |
497 | { |
498 | if (localSocket) |
499 | return localSocket->bytesAvailable(); |
500 | |
501 | return 0; |
502 | } |
503 | |
504 | bool QBluetoothSocketPrivateBluezDBus::canReadLine() const |
505 | { |
506 | if (localSocket) |
507 | return localSocket->canReadLine(); |
508 | |
509 | return false; |
510 | } |
511 | |
512 | qint64 QBluetoothSocketPrivateBluezDBus::bytesToWrite() const |
513 | { |
514 | if (localSocket) |
515 | return localSocket->bytesToWrite(); |
516 | |
517 | return 0; |
518 | } |
519 | |
520 | void QBluetoothSocketPrivateBluezDBus::remoteConnected(const QDBusUnixFileDescriptor &fd) |
521 | { |
522 | Q_Q(QBluetoothSocket); |
523 | |
524 | int descriptor = ::dup(fd: fd.fileDescriptor()); |
525 | localSocket = new QLocalSocket(this); |
526 | bool success = localSocket->setSocketDescriptor( |
527 | socketDescriptor: descriptor, socketState: QLocalSocket::ConnectedState, openMode: q->openMode()); |
528 | if (!success || !localSocket->isValid()) { |
529 | q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState); |
530 | delete localSocket; |
531 | localSocket = nullptr; |
532 | } else { |
533 | connect(sender: localSocket, signal: &QLocalSocket::readyRead, |
534 | context: q, slot: &QBluetoothSocket::readyRead); |
535 | connect(sender: localSocket, signal: &QLocalSocket::stateChanged, |
536 | context: this, slot: &QBluetoothSocketPrivateBluezDBus::socketStateChanged); |
537 | connect(sender: localSocket, signal: &QLocalSocket::bytesWritten, |
538 | context: q, slot: &QBluetoothSocket::bytesWritten); |
539 | |
540 | socket = descriptor; |
541 | q->setSocketState(QBluetoothSocket::SocketState::ConnectedState); |
542 | } |
543 | } |
544 | |
545 | void QBluetoothSocketPrivateBluezDBus::socketStateChanged(QLocalSocket::LocalSocketState newState) |
546 | { |
547 | Q_Q(QBluetoothSocket); |
548 | |
549 | switch (newState) { |
550 | case QLocalSocket::ClosingState: |
551 | q->setSocketState(QBluetoothSocket::SocketState::ClosingState); |
552 | break; |
553 | case QLocalSocket::UnconnectedState: |
554 | clearSocket(); |
555 | q->setOpenMode(QIODevice::NotOpen); |
556 | q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState); |
557 | emit q->readChannelFinished(); |
558 | break; |
559 | default: |
560 | // ConnectingState and ConnectedState not mapped |
561 | // (already set at the time when the socket is created) |
562 | break; |
563 | } |
564 | } |
565 | |
566 | void QBluetoothSocketPrivateBluezDBus::clearSocket() |
567 | { |
568 | Q_Q(QBluetoothSocket); |
569 | |
570 | if (profilePath.isEmpty()) |
571 | return; |
572 | |
573 | qCDebug(QT_BT_BLUEZ) << "Clearing profile called for"<< profilePath; |
574 | |
575 | if (localSocket) { |
576 | localSocket->close(); |
577 | localSocket->deleteLater(); |
578 | localSocket = nullptr; |
579 | } |
580 | |
581 | socket = -1; |
582 | |
583 | if (q->state() == QBluetoothSocket::SocketState::ConnectedState) { |
584 | OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), remoteDevicePath, |
585 | QDBusConnection::systemBus()); |
586 | auto reply = device.DisconnectProfile(UUID: profileUuid); |
587 | reply.waitForFinished(); |
588 | if (reply.isError()) { |
589 | qCWarning(QT_BT_BLUEZ) << "Disconnect profile failed:" |
590 | << reply.error().message(); |
591 | } |
592 | } |
593 | |
594 | if (profileContext) { |
595 | delete profileContext; |
596 | profileContext = nullptr; |
597 | } |
598 | |
599 | if (profileManager) { |
600 | qCDebug(QT_BT_BLUEZ) << "Unregistering client profile on"<< profilePath |
601 | << "in clearSocket()."; |
602 | |
603 | QDBusPendingReply<> reply = profileManager->UnregisterProfile(profile: QDBusObjectPath(profilePath)); |
604 | reply.waitForFinished(); |
605 | if (reply.isError()) |
606 | qCWarning(QT_BT_BLUEZ) << "Unregister profile:"<< reply.error().message(); |
607 | |
608 | QDBusConnection::systemBus().unregisterObject(path: profilePath); |
609 | |
610 | delete profileManager; |
611 | profileManager = nullptr; |
612 | } |
613 | |
614 | remoteDevicePath.clear(); |
615 | profileUuid.clear(); |
616 | profilePath.clear(); |
617 | } |
618 | QT_END_NAMESPACE |
619 | |
620 | #include "moc_qbluetoothsocket_bluezdbus_p.cpp" |
621 |
Definitions
- QBluetoothSocketPrivateBluezDBus
- ~QBluetoothSocketPrivateBluezDBus
- ensureNativeSocket
- connectToServiceHelper
- findRemoteDevicePath
- connectToServiceHelper
- connectToServiceReplyHandler
- connectToService
- connectToService
- connectToService
- abort
- localName
- localAddress
- localPort
- peerName
- peerAddress
- peerPort
- writeData
- readData
- close
- setSocketDescriptor
- bytesAvailable
- canReadLine
- bytesToWrite
- remoteConnected
- socketStateChanged
Start learning QML with our Intro Training
Find out more