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)
34 : QBluetoothSocketBasePrivate{qq}
36 secFlags = QBluetooth::Security::NoSecurity;
46 case QBluetoothServiceInfo::UnknownProtocol:
48 case QBluetoothServiceInfo::RfcommProtocol:
49 case QBluetoothServiceInfo::L2capProtocol:
58 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
71 QDBusConnection::systemBus());
74 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
78 auto reply = manager.GetManagedObjects();
79 reply.waitForFinished();
84 for (ManagedObjectList::const_iterator it = objectList.constBegin();
85 it != objectList.constEnd(); ++it) {
86 const QDBusObjectPath &path = it.key();
87 const InterfaceList &ifaceList = it.value();
89 for (InterfaceList::const_iterator ifaceIter = ifaceList.constBegin();
90 ifaceIter != ifaceList.constEnd(); ++ifaceIter) {
91 if (ifaceIter.key() == QStringLiteral(
"org.bluez.Device1")) {
92 if (path.path().indexOf(adapterPath) != 0)
96 path.path(), QDBusConnection::systemBus());
97 if (device.adapter().path() != adapterPath)
100 const QBluetoothAddress btAddress(device.address());
101 if (btAddress.isNull() || btAddress != address)
113 const QBluetoothAddress &address,
const QBluetoothUuid &uuid,
114 QIODevice::OpenMode openMode)
116 Q_Q(QBluetoothSocket);
119 bool success =
false;
120 profileUuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
121 const QString remoteDeviceUuid = uuid.toString(QUuid::WithoutBraces);
123 if (!profileManager) {
124 profileManager =
new OrgBluezProfileManager1Interface(
125 QStringLiteral(
"org.bluez"),
126 QStringLiteral(
"/org/bluez"),
127 QDBusConnection::systemBus(),
131 if (profileContext) {
132 qCDebug(QT_BT_BLUEZ) <<
"Profile context still active. close socket first.";
133 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
138 profileContext =
new OrgBluezProfile1ContextInterface(
this);
139 connect(profileContext, &OrgBluezProfile1ContextInterface::newConnection,
140 this, &QBluetoothSocketPrivateBluezDBus::remoteConnected);
142 for (i = 0; i < 10 && !success; i++) {
146 profilePath = u"/qt/btsocket/%1%2/%3"_s.
147 arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
148 arg(QCoreApplication::applicationPid()).
149 arg(QRandomGenerator::global()->generate());
151 success = QDBusConnection::systemBus().registerObject(
152 profilePath, profileContext, QDBusConnection::ExportAllSlots);
157 qCWarning(QT_BT_BLUEZ) <<
"Cannot export serial client profile on DBus";
159 delete profileContext;
160 profileContext =
nullptr;
162 errorString = QBluetoothSocket::tr(
"Cannot export profile on DBus");
163 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
168 QVariantMap profileOptions;
169 profileOptions.insert(QStringLiteral(
"Role"), QStringLiteral(
"client"));
170 profileOptions.insert(QStringLiteral(
"Service"), remoteDeviceUuid);
171 profileOptions.insert(QStringLiteral(
"Name"),
172 QStringLiteral(
"QBluetoothSocket-%1").arg(QCoreApplication::applicationPid()));
177 qCDebug(QT_BT_BLUEZ) <<
"Registering client profile on" << profilePath <<
"with options:";
178 qCDebug(QT_BT_BLUEZ) << profileOptions;
179 QDBusPendingReply<> reply = profileManager->RegisterProfile(
180 QDBusObjectPath(profilePath),
183 reply.waitForFinished();
184 if (reply.isError()) {
185 qCWarning(QT_BT_BLUEZ) <<
"Client profile registration failed:"
186 << reply.error().message();
188 QDBusConnection::systemBus().unregisterObject(profilePath);
189 errorString = QBluetoothSocket::tr(
"Cannot register profile on DBus");
190 q->setSocketError(QBluetoothSocket::SocketError::UnknownSocketError);
194 remoteDevicePath = findRemoteDevicePath(address);
195 if (remoteDevicePath.isEmpty()) {
196 qCWarning(QT_BT_BLUEZ) <<
"Unknown remote device:" << address
197 <<
"Try device discovery first";
200 errorString = QBluetoothSocket::tr(
"Cannot find remote device");
201 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
206 QDBusConnection::systemBus());
207 reply = device.ConnectProfile(remoteDeviceUuid);
208 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(reply,
this);
209 connect(watcher, &QDBusPendingCallWatcher::finished,
210 this, &QBluetoothSocketPrivateBluezDBus::connectToServiceReplyHandler);
212 q->setOpenMode(openMode);
213 q->setSocketState(QBluetoothSocket::SocketState::ConnectingState);
217 QDBusPendingCallWatcher *watcher)
219 Q_Q(QBluetoothSocket);
221 QDBusPendingReply<> reply = *watcher;
222 if (reply.isError()) {
223 qCWarning(QT_BT_BLUEZ) <<
"Cannot connect to profile/service.";
227 errorString = QBluetoothSocket::tr(
"Cannot connect to remote profile");
228 q->setSocketError(QBluetoothSocket::SocketError::HostNotFoundError);
230 watcher->deleteLater();
234 if (profileManager) {
235 qCDebug(QT_BT_BLUEZ) <<
"Unregistering client profile on" << profilePath
236 <<
"in connectToServiceReplyHandler() callback.";
238 QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
239 reply.waitForFinished();
241 qCWarning(QT_BT_BLUEZ) <<
"Unregister profile:" << reply.error().message();
243 QDBusConnection::systemBus().unregisterObject(profilePath);
245 delete profileManager;
246 profileManager =
nullptr;
251 const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
253 Q_Q(QBluetoothSocket);
254 QBluetoothUuid targetService;
256 targetService = service.serviceUuid();
257 if (targetService.isNull()) {
259 if (service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort))
260 targetService = QBluetoothUuid::ServiceClassUuid::SerialPort;
263 if (targetService.isNull()) {
264 qCWarning(QT_BT_BLUEZ) <<
"Cannot find appropriate serviceUuid"
265 <<
"or SerialPort service class uuid";
266 errorString = QBluetoothSocket::tr(
"Missing serviceUuid or Serial Port service class uuid");
267 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
271 if (service.socketProtocol() != QBluetoothServiceInfo::Protocol::UnknownProtocol)
272 socketType = service.socketProtocol();
273 qCDebug(QT_BT_BLUEZ) <<
"Socket protocol used:" << socketType;
275 connectToService(service.device().address(), targetService, openMode);
279 const QBluetoothAddress &address,
const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
281 Q_Q(QBluetoothSocket);
283 if (address.isNull()) {
284 qCWarning(QT_BT_BLUEZ) <<
"Invalid address to remote address passed.";
285 errorString = QBluetoothSocket::tr(
"Invalid Bluetooth address passed to connectToService()");
286 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
291 qCWarning(QT_BT_BLUEZ) <<
"Cannot find appropriate serviceUuid"
292 <<
"or SerialPort service class uuid";
293 errorString = QBluetoothSocket::tr(
"Missing serviceUuid or Serial Port service class uuid");
294 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
298 if (q->state() != QBluetoothSocket::SocketState::UnconnectedState) {
299 qCWarning(QT_BT_BLUEZ) <<
"QBluetoothSocketPrivateBluezDBus::connectToService called on busy socket";
300 errorString = QBluetoothSocket::tr(
"Trying to connect while connection is in progress");
301 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
305 if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
306 qCWarning(QT_BT_BLUEZ) <<
"QBluetoothSocketPrivateBluezDBus::connectToService cannot "
307 "connect with 'UnknownProtocol' (type provided by given service)";
308 errorString = QBluetoothSocket::tr(
"Socket type not supported");
309 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
313 if (!ensureNativeSocket(q->socketType())) {
314 errorString = QBluetoothSocket::tr(
"Socket type not supported");
315 q->setSocketError(QBluetoothSocket::SocketError::UnsupportedProtocolError);
318 connectToServiceHelper(address, uuid, openMode);
322 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
328 Q_Q(QBluetoothSocket);
330 errorString = tr(
"Connecting to port is not supported via Bluez DBus");
331 q->setSocketError(QBluetoothSocket::SocketError::ServiceNotFoundError);
332 qCWarning(QT_BT_BLUEZ) <<
"Connecting to port is not supported (Uuid required)";
338 localSocket->close();
341 Q_Q(QBluetoothSocket);
344 q->setOpenMode(QIODevice::NotOpen);
345 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
346 emit q->readChannelFinished();
353 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
358 QDBusConnection::systemBus());
359 return QString(adapter.alias());
365 const QString adapterPath = findAdapterForAddress(QBluetoothAddress(), &ok);
367 return QBluetoothAddress();
370 QDBusConnection::systemBus());
371 return QBluetoothAddress(adapter.address());
379 descriptor =
int(localSocket->socketDescriptor());
380 if (descriptor == -1)
383 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
385 socklen_t addrLength =
sizeof(addr);
387 if (::getsockname(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
388 return (addr.rc_channel);
389 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
391 socklen_t addrLength =
sizeof(addr);
393 if (::getsockname(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
402 if (remoteDevicePath.isEmpty())
406 QDBusConnection::systemBus());
407 return device.alias();
412 if (remoteDevicePath.isEmpty())
413 return QBluetoothAddress();
416 QDBusConnection::systemBus());
417 return QBluetoothAddress(device.address());
425 descriptor =
int(localSocket->socketDescriptor());
426 if (descriptor == -1)
429 if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
431 socklen_t addrLength =
sizeof(addr);
433 if (::getpeername(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
434 return addr.rc_channel;
435 }
else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
437 socklen_t addrLength =
sizeof(addr);
439 if (::getpeername(descriptor,
reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
451 Q_Q(QBluetoothSocket);
453 if (state != QBluetoothSocket::SocketState::ConnectedState) {
454 errorString = QBluetoothSocket::tr(
"Cannot write while not connected");
455 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
460 return localSocket->write(data, maxSize);
470 Q_Q(QBluetoothSocket);
472 if (state != QBluetoothSocket::SocketState::ConnectedState) {
473 errorString = QBluetoothSocket::tr(
"Cannot read while not connected");
474 q->setSocketError(QBluetoothSocket::SocketError::OperationError);
479 return localSocket->read(data, maxSize);
490 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
492 Q_UNUSED(socketDescriptor);
493 Q_UNUSED(socketType);
494 Q_UNUSED(socketState);
502 return localSocket->bytesAvailable();
510 return localSocket->canReadLine();
518 return localSocket->bytesToWrite();
525 Q_Q(QBluetoothSocket);
527 int descriptor = ::dup(fd.fileDescriptor());
528 localSocket =
new QLocalSocket(
this);
529 bool success = localSocket->setSocketDescriptor(
530 descriptor, QLocalSocket::ConnectedState, q->openMode());
531 if (!success || !localSocket->isValid()) {
532 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
534 localSocket =
nullptr;
536 connect(localSocket, &QLocalSocket::readyRead,
537 q, &QBluetoothSocket::readyRead);
538 connect(localSocket, &QLocalSocket::stateChanged,
539 this, &QBluetoothSocketPrivateBluezDBus::socketStateChanged);
540 connect(localSocket, &QLocalSocket::bytesWritten,
541 q, &QBluetoothSocket::bytesWritten);
544 q->setSocketState(QBluetoothSocket::SocketState::ConnectedState);
550 Q_Q(QBluetoothSocket);
553 case QLocalSocket::ClosingState:
554 q->setSocketState(QBluetoothSocket::SocketState::ClosingState);
556 case QLocalSocket::UnconnectedState:
558 q->setOpenMode(QIODevice::NotOpen);
559 q->setSocketState(QBluetoothSocket::SocketState::UnconnectedState);
560 emit q->readChannelFinished();
571 Q_Q(QBluetoothSocket);
573 if (profilePath.isEmpty())
576 qCDebug(QT_BT_BLUEZ) <<
"Clearing profile called for" << profilePath;
579 localSocket->close();
580 localSocket->deleteLater();
581 localSocket =
nullptr;
586 if (q->state() == QBluetoothSocket::SocketState::ConnectedState) {
588 QDBusConnection::systemBus());
589 auto reply = device.DisconnectProfile(profileUuid);
590 reply.waitForFinished();
591 if (reply.isError()) {
592 qCWarning(QT_BT_BLUEZ) <<
"Disconnect profile failed:"
593 << reply.error().message();
597 if (profileContext) {
598 delete profileContext;
599 profileContext =
nullptr;
602 if (profileManager) {
603 qCDebug(QT_BT_BLUEZ) <<
"Unregistering client profile on" << profilePath
604 <<
"in clearSocket().";
606 QDBusPendingReply<> reply = profileManager->UnregisterProfile(QDBusObjectPath(profilePath));
607 reply.waitForFinished();
609 qCWarning(QT_BT_BLUEZ) <<
"Unregister profile:" << reply.error().message();
611 QDBusConnection::systemBus().unregisterObject(profilePath);
613 delete profileManager;
614 profileManager =
nullptr;
617 remoteDevicePath.clear();
623#include "moc_qbluetoothsocket_bluezdbus_p.cpp"
QMap< QDBusObjectPath, InterfaceList > ManagedObjectList
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
QBluetoothSocketPrivateBluezDBus(QBluetoothSocket *qq)
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)