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"
16#include <QtBluetooth/qbluetoothdeviceinfo.h>
17#include <QtBluetooth/qbluetoothserviceinfo.h>
19#include <QtCore/qloggingcategory.h>
20#include <QtCore/qrandom.h>
22#include <QtNetwork/qlocalsocket.h>
28using namespace Qt::StringLiterals;
31Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
33QBluetoothSocketPrivateBluezDBus::QBluetoothSocketPrivateBluezDBus()
35 secFlags = QBluetooth::Security::NoSecurity;
45 case QBluetoothServiceInfo::UnknownProtocol:
47 case QBluetoothServiceInfo::RfcommProtocol:
48 case QBluetoothServiceInfo::L2capProtocol:
57 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
70 QDBusConnection::systemBus());
73 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
77 auto reply = manager.GetManagedObjects();
78 reply.waitForFinished();
83 for (ManagedObjectList::const_iterator it = objectList.constBegin();
84 it != objectList.constEnd(); ++it) {
85 const QDBusObjectPath &path = it.key();
86 const InterfaceList &ifaceList = it.value();
88 for (InterfaceList::const_iterator ifaceIter = ifaceList.constBegin();
89 ifaceIter != ifaceList.constEnd(); ++ifaceIter) {
90 if (ifaceIter.key() == QStringLiteral(
"org.bluez.Device1")) {
91 if (path.path().indexOf(adapterPath) != 0)
95 path.path(), QDBusConnection::systemBus());
96 if (device.adapter().path() != adapterPath)
99 const QBluetoothAddress btAddress(device.address());
100 if (btAddress.isNull() || btAddress != address)
112 const QBluetoothAddress &address,
const QBluetoothUuid &uuid,
113 QIODevice::OpenMode openMode)
115 Q_Q(QBluetoothSocket);
118 bool success =
false;
119 profileUuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
120 const QString remoteDeviceUuid = uuid.toString(QUuid::WithoutBraces);
122 if (!profileManager) {
123 profileManager =
new OrgBluezProfileManager1Interface(
124 QStringLiteral(
"org.bluez"),
125 QStringLiteral(
"/org/bluez"),
126 QDBusConnection::systemBus(),
130 if (profileContext) {
131 qCDebug(QT_BT_BLUEZ) <<
"Profile context still active. close socket first.";
132 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
137 profileContext =
new OrgBluezProfile1ContextInterface(
this);
138 connect(profileContext, &OrgBluezProfile1ContextInterface::newConnection,
139 this, &QBluetoothSocketPrivateBluezDBus::remoteConnected);
141 for (i = 0; i < 10 && !success; i++) {
145 profilePath = u"/qt/btsocket/%1%2/%3"_s.
146 arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
147 arg(QCoreApplication::applicationPid()).
148 arg(QRandomGenerator::global()->generate());
150 success = QDBusConnection::systemBus().registerObject(
151 profilePath, profileContext, QDBusConnection::ExportAllSlots);
156 qCWarning(QT_BT_BLUEZ) <<
"Cannot export serial client profile on DBus";
158 delete profileContext;
159 profileContext =
nullptr;
161 errorString = QBluetoothSocket::tr(
"Cannot export profile on DBus");
162 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
167 QVariantMap profileOptions;
168 profileOptions.insert(QStringLiteral(
"Role"), QStringLiteral(
"client"));
169 profileOptions.insert(QStringLiteral(
"Service"), remoteDeviceUuid);
170 profileOptions.insert(QStringLiteral(
"Name"),
171 QStringLiteral(
"QBluetoothSocket-%1").arg(QCoreApplication::applicationPid()));
176 qCDebug(QT_BT_BLUEZ) <<
"Registering client profile on" << profilePath <<
"with options:";
177 qCDebug(QT_BT_BLUEZ) << profileOptions;
178 QDBusPendingReply<> reply = profileManager->RegisterProfile(
179 QDBusObjectPath(profilePath),
182 reply.waitForFinished();
183 if (reply.isError()) {
184 qCWarning(QT_BT_BLUEZ) <<
"Client profile registration failed:"
185 << reply.error().message();
187 QDBusConnection::systemBus().unregisterObject(profilePath);
188 errorString = QBluetoothSocket::tr(
"Cannot register profile on DBus");
189 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
193 remoteDevicePath = findRemoteDevicePath(address);
194 if (remoteDevicePath.isEmpty()) {
195 qCWarning(QT_BT_BLUEZ) <<
"Unknown remote device:" << address
196 <<
"Try device discovery first";
199 errorString = QBluetoothSocket::tr(
"Cannot find remote device");
200 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
205 QDBusConnection::systemBus());
206 reply = device.ConnectProfile(remoteDeviceUuid);
207 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(reply,
this);
208 connect(watcher, &QDBusPendingCallWatcher::finished,
209 this, &QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler);
211 q->setOpenMode(openMode);
212 q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
216 QDBusPendingCallWatcher *watcher)
218 Q_Q(QBluetoothSocket);
220 QDBusPendingReply<> reply = *watcher;
221 if (reply.isError()) {
222 qCWarning(QT_BT_BLUEZ) <<
"Cannot connect to profile/service.";
226 errorString = QBluetoothSocket::tr(
"Cannot connect to remote profile");
227 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
229 watcher->deleteLater();
233 if (profileManager) {
234 qCDebug(QT_BT_BLUEZ) <<
"Unregistering client profile on" << profilePath
235 <<
"in connectToServiceReplyHandler() callback.";
237 QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
238 reply.waitForFinished();
240 qCWarning(QT_BT_BLUEZ) <<
"Unregister profile:" << reply.error().message();
242 QDBusConnection::systemBus().unregisterObject(profilePath);
244 delete profileManager;
245 profileManager =
nullptr;
250 const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
252 Q_Q(QBluetoothSocket);
253 QBluetoothUuid targetService;
255 targetService = service.serviceUuid();
256 if (targetService.isNull()) {
258 if (service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort))
259 targetService = QBluetoothUuid::ServiceClassUuid::SerialPort;
262 if (targetService.isNull()) {
263 qCWarning(QT_BT_BLUEZ) <<
"Cannot find appropriate serviceUuid"
264 <<
"or SerialPort service class uuid";
265 errorString = QBluetoothSocket::tr(
"Missing serviceUuid or Serial Port service class uuid");
266 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
270 if (service.socketProtocol() != QBluetoothServiceInfo::Protocol::UnknownProtocol)
271 socketType = service.socketProtocol();
272 qCDebug(QT_BT_BLUEZ) <<
"Socket protocol used:" << socketType;
274 connectToService(service.device().address(), targetService, openMode);
278 const QBluetoothAddress &address,
const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
280 Q_Q(QBluetoothSocket);
282 if (address.isNull()) {
283 qCWarning(QT_BT_BLUEZ) <<
"Invalid address to remote address passed.";
284 errorString = QBluetoothSocket::tr(
"Invalid Bluetooth address passed to connectToService()");
285 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
290 qCWarning(QT_BT_BLUEZ) <<
"Cannot find appropriate serviceUuid"
291 <<
"or SerialPort service class uuid";
292 errorString = QBluetoothSocket::tr(
"Missing serviceUuid or Serial Port service class uuid");
293 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
297 if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
298 qCWarning(QT_BT_BLUEZ) <<
"QBluetoothSocketPrivateBluezDBus::connectToService called on busy socket";
299 errorString = QBluetoothSocket::tr(
"Trying to connect while connection is in progress");
300 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
304 if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
305 qCWarning(QT_BT_BLUEZ) <<
"QBluetoothSocketPrivateBluezDBus::connectToService cannot "
306 "connect with 'UnknownProtocol' (type provided by given service)";
307 errorString = QBluetoothSocket::tr(
"Socket type not supported");
308 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
312 if (!ensureNativeSocket(q->socketType())) {
313 errorString = QBluetoothSocket::tr(
"Socket type not supported");
314 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
317 connectToServiceHelper(address, uuid, openMode);
321 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
327 Q_Q(QBluetoothSocket);
329 errorString = tr(
"Connecting to port is not supported via Bluez DBus");
330 q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
331 qCWarning(QT_BT_BLUEZ) <<
"Connecting to port is not supported (Uuid required)";
337 localSocket->close();
340 Q_Q(QBluetoothSocket);
343 q->setOpenMode(QIODevice::NotOpen);
344 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
345 emit q->readChannelFinished();
352 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
357 QDBusConnection::systemBus());
358 return QString(adapter.alias());
364 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
366 return QBluetoothAddress();
369 QDBusConnection::systemBus());
370 return QBluetoothAddress(adapter.address());
378 descriptor =
int(localSocket->socketDescriptor());
379 if (descriptor == -1)
382 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
384 socklen_t addrLength =
sizeof(addr);
386 if (::getsockname(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
387 return (addr.rc_channel);
388 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
390 socklen_t addrLength =
sizeof(addr);
392 if (::getsockname(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
401 if (remoteDevicePath.isEmpty())
405 QDBusConnection::systemBus());
406 return device.alias();
411 if (remoteDevicePath.isEmpty())
412 return QBluetoothAddress();
415 QDBusConnection::systemBus());
416 return QBluetoothAddress(device.address());
424 descriptor =
int(localSocket->socketDescriptor());
425 if (descriptor == -1)
428 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
430 socklen_t addrLength =
sizeof(addr);
432 if (::getpeername(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
433 return addr.rc_channel;
434 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
436 socklen_t addrLength =
sizeof(addr);
438 if (::getpeername(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
450 Q_Q(QBluetoothSocket);
452 if (state != QBluetoothSocket::SocketState::ConnectedState) {
453 errorString = QBluetoothSocket::tr(
"Cannot write while not connected");
454 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
459 return localSocket->write(data, maxSize);
469 Q_Q(QBluetoothSocket);
471 if (state != QBluetoothSocket::SocketState::ConnectedState) {
472 errorString = QBluetoothSocket::tr(
"Cannot read while not connected");
473 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
478 return localSocket->read(data, maxSize);
489 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
491 Q_UNUSED(socketDescriptor);
492 Q_UNUSED(socketType);
493 Q_UNUSED(socketState);
501 return localSocket->bytesAvailable();
509 return localSocket->canReadLine();
517 return localSocket->bytesToWrite();
524 Q_Q(QBluetoothSocket);
526 int descriptor = ::dup(fd.fileDescriptor());
527 localSocket =
new QLocalSocket(
this);
528 bool success = localSocket->setSocketDescriptor(
529 descriptor, QLocalSocket::ConnectedState, q->openMode());
530 if (!success || !localSocket->isValid()) {
531 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
533 localSocket =
nullptr;
535 connect(localSocket, &QLocalSocket::readyRead,
536 q, &QBluetoothSocket::readyRead);
537 connect(localSocket, &QLocalSocket::stateChanged,
538 this, &QBluetoothSocketPrivateBluezDBus::socketStateChanged);
539 connect(localSocket, &QLocalSocket::bytesWritten,
540 q, &QBluetoothSocket::bytesWritten);
543 q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
549 Q_Q(QBluetoothSocket);
552 case QLocalSocket::ClosingState:
553 q->setSocketState(QBluetoothSocket::SocketState::ClosingState);
555 case QLocalSocket::UnconnectedState:
557 q->setOpenMode(QIODevice::NotOpen);
558 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
559 emit q->readChannelFinished();
570 Q_Q(QBluetoothSocket);
572 if (profilePath.isEmpty())
575 qCDebug(QT_BT_BLUEZ) <<
"Clearing profile called for" << profilePath;
578 localSocket->close();
579 localSocket->deleteLater();
580 localSocket =
nullptr;
585 if (q->state() == QBluetoothSocket::SocketState::ConnectedState) {
587 QDBusConnection::systemBus());
588 auto reply = device.DisconnectProfile(profileUuid);
589 reply.waitForFinished();
590 if (reply.isError()) {
591 qCWarning(QT_BT_BLUEZ) <<
"Disconnect profile failed:"
592 << reply.error().message();
596 if (profileContext) {
597 delete profileContext;
598 profileContext =
nullptr;
601 if (profileManager) {
602 qCDebug(QT_BT_BLUEZ) <<
"Unregistering client profile on" << profilePath
603 <<
"in clearSocket().";
605 QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
606 reply.waitForFinished();
608 qCWarning(QT_BT_BLUEZ) <<
"Unregister profile:" << reply.error().message();
610 QDBusConnection::systemBus().unregisterObject(profilePath);
612 delete profileManager;
613 profileManager =
nullptr;
616 remoteDevicePath.clear();
622#include "moc_qbluetoothsocket_bluezdbus_p.cpp"
QMap< QDBusObjectPath, InterfaceList > ManagedObjectList
QBluetoothSocketPrivateBluezDBus()
quint16 peerPort() const override
qint64 readData(char *data, qint64 maxSize) override
qint64 bytesAvailable() const override
~QBluetoothSocketPrivateBluezDBus() override
quint16 localPort() const override
bool canReadLine() const override
void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode) override
void connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode) override
void connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) override
void connectToServiceHelper(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
QBluetoothAddress peerAddress() const override
qint64 bytesToWrite() const override
QString peerName() const override
QBluetoothAddress localAddress() const override
qint64 writeData(const char *data, qint64 maxSize) override
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, QBluetoothSocket::SocketState socketState=QBluetoothSocket::SocketState::ConnectedState, QBluetoothSocket::OpenMode openMode=QBluetoothSocket::ReadWrite) override
QString localName() const override
void connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) override
static QString findRemoteDevicePath(const QBluetoothAddress &address)