Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbluetoothsocket_bluez.cpp
Go to the documentation of this file.
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"
7
9#include <QtBluetooth/QBluetoothLocalDevice>
10#include "bluez/bluez_data_p.h"
11
12#include <qplatformdefs.h>
13#include <QtCore/private/qcore_unix_p.h>
14
15#include <QtCore/QLoggingCategory>
16
17#include <errno.h>
18#include <unistd.h>
19#include <string.h>
20
21#include <QtCore/QSocketNotifier>
22
24
26
32
34{
35 delete readNotifier;
36 readNotifier = nullptr;
38 connectWriteNotifier = nullptr;
39
40 // If the socket wasn't closed/aborted make sure we free the socket file descriptor
41 if (socket != -1)
43}
44
46{
47 if (socket != -1) {
48 if (socketType == type)
49 return true;
50
51 delete readNotifier;
52 readNotifier = nullptr;
54 connectWriteNotifier = nullptr;
56 }
57
59
60 switch (type) {
62 socket = ::socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
63 break;
65 socket = ::socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
66 break;
67 default:
68 socket = -1;
69 }
70
71 if (socket == -1)
72 return false;
73
74 int flags = fcntl(socket, F_GETFL, 0);
75 fcntl(socket, F_SETFL, flags | O_NONBLOCK);
76
79 QObject::connect(readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_readNotify()));
81 QObject::connect(connectWriteNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_writeNotify()));
82
85
86
87 return true;
88}
89
91{
93 int result = -1;
94
95 if (socket == -1 && !ensureNativeSocket(socketType)) {
96 errorString = QBluetoothSocket::tr("Unknown socket error");
98 return;
99 }
100
101 // apply preferred security level
102 // ignore QBluetooth::Security::Authentication -> not used anymore by kernel
103 struct bt_security security;
104 memset(&security, 0, sizeof(security));
105
107 security.level = BT_SECURITY_LOW;
109 security.level = BT_SECURITY_MEDIUM;
111 security.level = BT_SECURITY_HIGH;
112
113 if (setsockopt(socket, SOL_BLUETOOTH, BT_SECURITY,
114 &security, sizeof(security)) != 0) {
115 qCWarning(QT_BT_BLUEZ) << "Failed to set socket option, closing socket for safety" << errno;
116 qCWarning(QT_BT_BLUEZ) << "Error: " << qt_error_string(errno);
117 errorString = QBluetoothSocket::tr("Cannot set connection security level");
119 return;
120 }
121
124
125 memset(&addr, 0, sizeof(addr));
126 addr.rc_family = AF_BLUETOOTH;
127 addr.rc_channel = port;
128
129 convertAddress(address.toUInt64(), addr.rc_bdaddr.b);
130
133
134 result = ::connect(socket, (sockaddr *)&addr, sizeof(addr));
137
138 memset(&addr, 0, sizeof(addr));
139 addr.l2_family = AF_BLUETOOTH;
140 // This is an ugly hack but the socket class does what's needed already.
141 // For L2CP GATT we need a channel rather than a socket and the LE address type
142 // We don't want to make this public API offering for now especially since
143 // only Linux (of all platforms supported by this library) supports this type
144 // of socket.
145
146#if QT_CONFIG(bluez) && !defined(QT_BLUEZ_NO_BTLE)
147 if (lowEnergySocketType) {
148 addr.l2_cid = htobs(port);
149 addr.l2_bdaddr_type = lowEnergySocketType;
150 } else {
151 addr.l2_psm = htobs(port);
152 }
153#else
154 addr.l2_psm = htobs(port);
155#endif
156
157 convertAddress(address.toUInt64(), addr.l2_bdaddr.b);
158
161
162 result = ::connect(socket, (sockaddr *)&addr, sizeof(addr));
163 }
164
165 if (result >= 0 || (result == -1 && errno == EINPROGRESS)) {
166 connecting = true;
168 q->setOpenMode(openMode);
169 } else {
172 }
173}
174
176 const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
177{
178 Q_Q(QBluetoothSocket);
179
182 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
183 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
185 return;
186 }
187
188 // we are checking the service protocol and not socketType()
189 // socketType will change in ensureNativeSocket()
190 if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
191 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocket::connectToService cannot "
192 "connect with 'UnknownProtocol' (type provided by given service)";
193 errorString = QBluetoothSocket::tr("Socket type not supported");
195 return;
196 }
197
198 if (service.protocolServiceMultiplexer() > 0) {
199 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::L2capProtocol);
200
202 errorString = QBluetoothSocket::tr("Unknown socket error");
204 return;
205 }
206 connectToServiceHelper(service.device().address(), service.protocolServiceMultiplexer(),
207 openMode);
208 } else if (service.serverChannel() > 0) {
209 Q_ASSERT(service.socketProtocol() == QBluetoothServiceInfo::RfcommProtocol);
210
212 errorString = QBluetoothSocket::tr("Unknown socket error");
214 return;
215 }
216 connectToServiceHelper(service.device().address(), service.serverChannel(), openMode);
217 } else {
218 // try doing service discovery to see if we can find the socket
219 if (service.serviceUuid().isNull()
220 && !service.serviceClassUuids().contains(QBluetoothUuid::ServiceClassUuid::SerialPort)) {
221 qCWarning(QT_BT_BLUEZ) << "No port, no PSM, and no UUID provided. Unable to connect";
222 return;
223 }
224 qCDebug(QT_BT_BLUEZ) << "Need a port/psm, doing discovery";
225 q->doDeviceDiscovery(service, openMode);
226 }
227}
228
230 const QBluetoothAddress &address, const QBluetoothUuid &uuid,
231 QIODevice::OpenMode openMode)
232{
233 Q_Q(QBluetoothSocket);
234
236 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
237 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
239 return;
240 }
241
242 if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
243 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot "
244 "connect with 'UnknownProtocol' (type provided by given service)";
245 errorString = QBluetoothSocket::tr("Socket type not supported");
247 return;
248 }
249
250 QBluetoothServiceInfo service;
252 service.setDevice(device);
253 service.setServiceUuid(uuid);
254 q->doDeviceDiscovery(service, openMode);
255}
256
258 const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
259{
260 Q_Q(QBluetoothSocket);
261
262 if (q->socketType() == QBluetoothServiceInfo::UnknownProtocol) {
263 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService cannot "
264 "connect with 'UnknownProtocol' (type provided by given service)";
265 errorString = QBluetoothSocket::tr("Socket type not supported");
267 return;
268 }
269
271 qCWarning(QT_BT_BLUEZ) << "QBluetoothSocketPrivateBluez::connectToService called on busy socket";
272 errorString = QBluetoothSocket::tr("Trying to connect while connection is in progress");
274 return;
275 }
277}
278
279void QBluetoothSocketPrivateBluez::_q_writeNotify()
280{
281 Q_Q(QBluetoothSocket);
283 int errorno, len;
284 len = sizeof(errorno);
285 ::getsockopt(socket, SOL_SOCKET, SO_ERROR, &errorno, (socklen_t*)&len);
286 if(errorno) {
287 errorString = qt_error_string(errorno);
289 return;
290 }
291
293
295 connecting = false;
296 }
297 else {
298 if (txBuffer.size() == 0) {
300 return;
301 }
302
303 char buf[1024];
304
305 const auto size = txBuffer.read(buf, 1024);
306 const auto writtenBytes = qt_safe_write(socket, buf, size);
307 if (writtenBytes < 0) {
308 switch (errno) {
309 case EAGAIN:
311 break;
312 default:
313 // every other case returns error
314 errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(errno)) ;
316 break;
317 }
318 } else {
319 if (writtenBytes < size) {
320 // add remainder back to buffer
321 char* remainder = buf + writtenBytes;
322 txBuffer.ungetBlock(remainder, size - writtenBytes);
323 }
324 if (writtenBytes > 0)
325 emit q->bytesWritten(writtenBytes);
326 }
327
328 if (txBuffer.size()) {
330 }
333 this->close();
334 }
335 }
336}
337
338void QBluetoothSocketPrivateBluez::_q_readNotify()
339{
340 Q_Q(QBluetoothSocket);
342// qint64 readFromDevice = q->readData(writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE);
343 const auto readFromDevice = ::read(socket, writePointer, QPRIVATELINEARBUFFER_BUFFERSIZE);
345 if(readFromDevice <= 0){
346 int errsv = errno;
347 readNotifier->setEnabled(false);
350 qCWarning(QT_BT_BLUEZ) << Q_FUNC_INFO << socket << "error:" << readFromDevice << errorString;
351 if (errsv == EHOSTDOWN)
353 else if (errsv == ECONNRESET)
355 else
357
358 q->disconnectFromService();
359 }
360 else {
361 emit q->readyRead();
362 }
363}
364
366{
367 delete readNotifier;
368 readNotifier = nullptr;
370 connectWriteNotifier = nullptr;
371
372 // We don't transition through Closing for abort, so
373 // we don't call disconnectFromService or
374 // QBluetoothSocket::close
376 socket = -1;
377
378 Q_Q(QBluetoothSocket);
379
380 q->setOpenMode(QIODevice::NotOpen);
382 emit q->readChannelFinished();
383}
384
386{
388 if (address.isNull())
389 return QString();
390
392 return device.name();
393}
394
396{
399 socklen_t addrLength = sizeof(addr);
400
401 if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
402 return QBluetoothAddress(convertAddress(addr.rc_bdaddr.b));
405 socklen_t addrLength = sizeof(addr);
406
407 if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
408 return QBluetoothAddress(convertAddress(addr.l2_bdaddr.b));
409 }
410
411 return QBluetoothAddress();
412}
413
415{
418 socklen_t addrLength = sizeof(addr);
419
420 if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
421 return addr.rc_channel;
424 socklen_t addrLength = sizeof(addr);
425
426 if (::getsockname(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
427 return addr.l2_psm;
428 }
429
430 return 0;
431}
432
434{
436
439 socklen_t addrLength = sizeof(addr);
440
441 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) < 0)
442 return QString();
443
444 convertAddress(addr.rc_bdaddr.b, &bdaddr);
447 socklen_t addrLength = sizeof(addr);
448
449 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) < 0)
450 return QString();
451
452 convertAddress(addr.l2_bdaddr.b, &bdaddr);
453 } else {
454 qCWarning(QT_BT_BLUEZ) << "peerName() called on socket of unknown type";
455 return QString();
456 }
457
458 const QString peerAddress = QBluetoothAddress(bdaddr).toString();
459
463 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
464 reply.waitForFinished();
465 if (reply.isError())
466 return QString();
467
468 ManagedObjectList managedObjectList = reply.value();
469 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
470 it != managedObjectList.constEnd(); ++it) {
471 const InterfaceList &ifaceList = it.value();
472
473 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
474 ++jt) {
475 const QString &iface = jt.key();
476 const QVariantMap &ifaceValues = jt.value();
477
478 if (iface == QStringLiteral("org.bluez.Device1")) {
479 if (ifaceValues.value(QStringLiteral("Address")).toString() == peerAddress)
480 return ifaceValues.value(QStringLiteral("Alias")).toString();
481 }
482 }
483 }
484 return QString();
485}
486
488{
491 socklen_t addrLength = sizeof(addr);
492
493 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
494 return QBluetoothAddress(convertAddress(addr.rc_bdaddr.b));
497 socklen_t addrLength = sizeof(addr);
498
499 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
500 return QBluetoothAddress(convertAddress(addr.l2_bdaddr.b));
501 }
502
503 return QBluetoothAddress();
504}
505
507{
510 socklen_t addrLength = sizeof(addr);
511
512 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
513 return addr.rc_channel;
516 socklen_t addrLength = sizeof(addr);
517
518 if (::getpeername(socket, reinterpret_cast<sockaddr *>(&addr), &addrLength) == 0)
519 return addr.l2_psm;
520 }
521
522 return 0;
523}
524
526{
527 Q_Q(QBluetoothSocket);
528
530 errorString = QBluetoothSocket::tr("Cannot write while not connected");
532 return -1;
533 }
534
535 if (q->openMode() & QIODevice::Unbuffered) {
536 auto sz = ::qt_safe_write(socket, data, maxSize);
537 if (sz < 0) {
538 switch (errno) {
539 case EAGAIN:
540 sz = 0;
541 break;
542 default:
543 errorString = QBluetoothSocket::tr("Network Error: %1").arg(qt_error_string(errno));
545 }
546 }
547
548 if (sz > 0)
549 emit q->bytesWritten(sz);
550
551 return sz;
552 }
553 else {
554
556 return -1;
557
558 if(txBuffer.size() == 0) {
560 QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection);
561 }
562
563 char *txbuf = txBuffer.reserve(maxSize);
564 memcpy(txbuf, data, maxSize);
565
566 return maxSize;
567 }
568}
569
571{
572 Q_Q(QBluetoothSocket);
573
575 errorString = QBluetoothSocket::tr("Cannot read while not connected");
577 return -1;
578 }
579
580 if (!rxBuffer.isEmpty())
581 return rxBuffer.read(data, maxSize);
582
583 return 0;
584}
585
587{
588 // If we have pending data on the write buffer, wait until it has been written,
589 // after which this close() will be called again
590 if (txBuffer.size() > 0)
592 else
593 abort();
594}
595
597 QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
598{
599 Q_Q(QBluetoothSocket);
600 delete readNotifier;
601 readNotifier = nullptr;
603 connectWriteNotifier = nullptr;
604
605 socketType = socketType_;
606 if (socket != -1)
608
609 socket = socketDescriptor;
610
611 // ensure that O_NONBLOCK is set on new connections.
612 int flags = fcntl(socket, F_GETFL, 0);
613 if (!(flags & O_NONBLOCK))
614 fcntl(socket, F_SETFL, flags | O_NONBLOCK);
615
617 QObject::connect(readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_readNotify()));
619 QObject::connect(connectWriteNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_writeNotify()));
620
621 q->setOpenMode(openMode);
622 q->setSocketState(socketState);
623
624 return true;
625}
626
631
636
641
643
644#include "moc_qbluetoothsocket_bluez_p.cpp"
bdaddr_t bdaddr
#define QPRIVATELINEARBUFFER_BUFFERSIZE
QMap< QDBusObjectPath, InterfaceList > ManagedObjectList
QT_BEGIN_NAMESPACE void initializeBluez5()
#define htobs(d)
#define BT_SECURITY_LOW
#define BTPROTO_RFCOMM
#define BT_SECURITY
#define SOL_BLUETOOTH
#define BT_SECURITY_MEDIUM
#define BTPROTO_L2CAP
#define BT_SECURITY_HIGH
IOBluetoothDevice * device
\inmodule QtBluetooth
\inmodule QtBluetooth
\inmodule QtBluetooth
\inmodule QtBluetooth
Protocol
This enum describes the socket protocol used by the service.
QBluetoothSocket::OpenMode openMode
QBluetooth::SecurityFlags secFlags
QBluetoothServiceInfo::Protocol socketType
QBluetoothSocket::SocketState state
qint64 writeData(const char *data, qint64 maxSize) override
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override
QBluetoothAddress peerAddress() const override
qint64 readData(char *data, qint64 maxSize) override
void connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode) override
QBluetoothAddress localAddress() const override
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType, QBluetoothSocket::SocketState socketState=QBluetoothSocket::SocketState::ConnectedState, QBluetoothSocket::OpenMode openMode=QBluetoothSocket::ReadWrite) override
void connectToServiceHelper(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode) override
\inmodule QtBluetooth
SocketState
This enum describes the state of the Bluetooth socket.
\inmodule QtBluetooth
static QDBusConnection systemBus()
Returns a QDBusConnection object opened with the system bus.
Definition qmap.h:187
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
qsizetype read(char *target, qsizetype size)
void ungetBlock(const char *block, qsizetype size)
void chop(qsizetype size)
char * reserve(qsizetype size)
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
\inmodule QtCore
\inmodule QtCore
void setEnabled(bool)
If enable is true, the notifier is enabled; otherwise the notifier is disabled.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
T value() const &
Definition qvariant.h:516
static bool readFromDevice(QIODevice *device, QJsonArray *allMetaObjects)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ QueuedConnection
static void convertAddress(const quint64 from, quint8(&to)[6])
#define Q_FUNC_INFO
static qint64 qt_safe_write(int fd, const void *data, qint64 len)
#define QT_CLOSE
EGLOutputPortEXT port
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbitfield flags
GLenum const void * addr
GLuint GLuint64EXT address
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
#define emit
unsigned short quint16
Definition qtypes.h:48
unsigned long long quint64
Definition qtypes.h:61
long long qint64
Definition qtypes.h:60
ReturnedValue read(const char *data)
QNetworkAccessManager manager
QNetworkReply * reply
char * toString(const MyType &t)
[31]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
unsigned short l2_psm
quint8 rc_channel