| 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 |  |