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