1/****************************************************************************
2**
3** Copyright (C) 2016 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:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "btlocaldevice.h"
30#include <QDebug>
31#include <QTimer>
32#ifdef Q_OS_ANDROID
33#include <QtAndroidExtras/QtAndroid>
34#endif
35#include <QtBluetooth/QBluetoothServiceInfo>
36
37#define BTCHAT_DEVICE_ADDR "00:15:83:38:17:C3"
38
39//same uuid as examples/bluetooth/btchat
40//the reverse UUID is only used on Android to counter
41//https://issuetracker.google.com/issues/37076498 (tracked via QTBUG-61392)
42#define TEST_SERVICE_UUID "e8e10f95-1a70-4b27-9ccf-02010264e9c8"
43#define TEST_REVERSE_SERVICE_UUID "c8e96402-0102-cf9c-274b-701a950fe1e8"
44
45#define SOCKET_PROTOCOL QBluetoothServiceInfo::RfcommProtocol
46//#define SOCKET_PROTOCOL QBluetoothServiceInfo::L2capProtocol
47
48BtLocalDevice::BtLocalDevice(QObject *parent) :
49 QObject(parent), securityFlags(QBluetooth::NoSecurity)
50{
51 localDevice = new QBluetoothLocalDevice(this);
52 connect(sender: localDevice, signal: &QBluetoothLocalDevice::error,
53 receiver: this, slot: &BtLocalDevice::error);
54 connect(sender: localDevice, signal: &QBluetoothLocalDevice::hostModeStateChanged,
55 receiver: this, slot: &BtLocalDevice::hostModeStateChanged);
56 connect(sender: localDevice, signal: &QBluetoothLocalDevice::pairingFinished,
57 receiver: this, slot: &BtLocalDevice::pairingFinished);
58 connect(sender: localDevice, signal: &QBluetoothLocalDevice::deviceConnected,
59 receiver: this, slot: &BtLocalDevice::connected);
60 connect(sender: localDevice, signal: &QBluetoothLocalDevice::deviceDisconnected,
61 receiver: this, slot: &BtLocalDevice::disconnected);
62 connect(sender: localDevice, signal: &QBluetoothLocalDevice::pairingDisplayConfirmation,
63 receiver: this, slot: &BtLocalDevice::pairingDisplayConfirmation);
64 connect(sender: localDevice, signal: &QBluetoothLocalDevice::pairingDisplayPinCode,
65 receiver: this, slot: &BtLocalDevice::pairingDisplayPinCode);
66
67 if (localDevice->isValid()) {
68 deviceAgent = new QBluetoothDeviceDiscoveryAgent(this);
69 connect(sender: deviceAgent, signal: &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
70 receiver: this, slot: &BtLocalDevice::deviceDiscovered);
71 connect(sender: deviceAgent, signal: &QBluetoothDeviceDiscoveryAgent::finished,
72 receiver: this, slot: &BtLocalDevice::discoveryFinished);
73 connect(sender: deviceAgent, signal: QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(ptr: &QBluetoothDeviceDiscoveryAgent::error),
74 receiver: this, slot: &BtLocalDevice::discoveryError);
75 connect(sender: deviceAgent, signal: &QBluetoothDeviceDiscoveryAgent::canceled,
76 receiver: this, slot: &BtLocalDevice::discoveryCanceled);
77
78 serviceAgent = new QBluetoothServiceDiscoveryAgent(this);
79 connect(sender: serviceAgent, signal: &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
80 receiver: this, slot: &BtLocalDevice::serviceDiscovered);
81 connect(sender: serviceAgent, signal: &QBluetoothServiceDiscoveryAgent::finished,
82 receiver: this, slot: &BtLocalDevice::serviceDiscoveryFinished);
83 connect(sender: serviceAgent, signal: &QBluetoothServiceDiscoveryAgent::canceled,
84 receiver: this, slot: &BtLocalDevice::serviceDiscoveryCanceled);
85 connect(sender: serviceAgent, signal: QOverload<QBluetoothServiceDiscoveryAgent::Error>::of(ptr: &QBluetoothServiceDiscoveryAgent::error),
86 receiver: this, slot: &BtLocalDevice::serviceDiscoveryError);
87
88 socket = new QBluetoothSocket(SOCKET_PROTOCOL, this);
89 connect(sender: socket, signal: &QBluetoothSocket::stateChanged,
90 receiver: this, slot: &BtLocalDevice::socketStateChanged);
91 connect(sender: socket, signal: QOverload<QBluetoothSocket::SocketError>::of(ptr: &QBluetoothSocket::error),
92 receiver: this, slot: &BtLocalDevice::socketError);
93 connect(sender: socket, signal: &QBluetoothSocket::connected, receiver: this, slot: &BtLocalDevice::socketConnected);
94 connect(sender: socket, signal: &QBluetoothSocket::disconnected, receiver: this, slot: &BtLocalDevice::socketDisconnected);
95 connect(sender: socket, signal: &QIODevice::readyRead, receiver: this, slot: &BtLocalDevice::readData);
96 connect(sender: socket, signal: &QBluetoothSocket::bytesWritten, context: this, slot: [](qint64 bytesWritten){
97 qDebug() << "Bytes Written to Client socket:" << bytesWritten;
98 });
99 setSecFlags(static_cast<int>(socket->preferredSecurityFlags()));
100
101 server = new QBluetoothServer(SOCKET_PROTOCOL, this);
102 connect(sender: server, signal: &QBluetoothServer::newConnection, receiver: this, slot: &BtLocalDevice::serverNewConnection);
103 connect(sender: server, signal: QOverload<QBluetoothServer::Error>::of(ptr: &QBluetoothServer::error),
104 receiver: this, slot: &BtLocalDevice::serverError);
105 } else {
106 deviceAgent = nullptr;
107 serviceAgent = nullptr;
108 socket = nullptr;
109 server = nullptr;
110 }
111}
112
113BtLocalDevice::~BtLocalDevice()
114{
115 while (!serverSockets.isEmpty())
116 {
117 QBluetoothSocket* s = serverSockets.takeFirst();
118 s->abort();
119 s->deleteLater();
120 }
121}
122
123int BtLocalDevice::secFlags() const
124{
125 return static_cast<int>(securityFlags);
126}
127
128void BtLocalDevice::setSecFlags(int newFlags)
129{
130 QBluetooth::SecurityFlags fl(newFlags);
131
132 if (securityFlags != fl) {
133 securityFlags = fl;
134 emit secFlagsChanged();
135 }
136}
137
138QString BtLocalDevice::hostMode() const
139{
140 switch (localDevice->hostMode()) {
141 case QBluetoothLocalDevice::HostDiscoverable:
142 return QStringLiteral("HostMode: Discoverable");
143 case QBluetoothLocalDevice::HostConnectable:
144 return QStringLiteral("HostMode: Connectable");
145 case QBluetoothLocalDevice::HostDiscoverableLimitedInquiry:
146 return QStringLiteral("HostMode: DiscoverableLimit");
147 case QBluetoothLocalDevice::HostPoweredOff:
148 return QStringLiteral("HostMode: Powered Off");
149 }
150
151 return QStringLiteral("HostMode: <None>");
152}
153
154void BtLocalDevice::setHostMode(int newMode)
155{
156 localDevice->setHostMode(static_cast<QBluetoothLocalDevice::HostMode>(newMode));
157}
158
159void BtLocalDevice::requestPairingUpdate(bool isPairing)
160{
161 QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
162 if (baddr.isNull())
163 return;
164
165
166
167 if (isPairing) {
168 //toggle between authorized and non-authorized pairing to achieve better
169 //level of testing
170 static short pairing = 0;
171 if ((pairing%2) == 1)
172 localDevice->requestPairing(address: baddr, pairing: QBluetoothLocalDevice::Paired);
173 else
174 localDevice->requestPairing(address: baddr, pairing: QBluetoothLocalDevice::AuthorizedPaired);
175 pairing++;
176 } else {
177 localDevice->requestPairing(address: baddr, pairing: QBluetoothLocalDevice::Unpaired);
178 }
179
180 for (int i = 0; i < foundTestServers.count(); i++) {
181 if (isPairing)
182 localDevice->requestPairing(address: foundTestServers.at(i).device().address(),
183 pairing: QBluetoothLocalDevice::Paired);
184 else
185 localDevice->requestPairing(address: foundTestServers.at(i).device().address(),
186 pairing: QBluetoothLocalDevice::Unpaired);
187 }
188}
189
190void BtLocalDevice::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing)
191{
192 qDebug() << "(Un)Pairing finished" << address.toString() << pairing;
193}
194
195void BtLocalDevice::connected(const QBluetoothAddress &addr)
196{
197 qDebug() << "Newly connected device" << addr.toString();
198}
199
200void BtLocalDevice::disconnected(const QBluetoothAddress &addr)
201{
202 qDebug() << "Newly disconnected device" << addr.toString();
203}
204
205void BtLocalDevice::pairingDisplayConfirmation(const QBluetoothAddress &address, const QString &pin)
206{
207 qDebug() << "PairingDisplayConfirmation" << address << pin;
208 QTimer::singleShot(msec: 3000, receiver: this, SLOT(confirmPairing()));
209}
210
211void BtLocalDevice::pairingDisplayPinCode(const QBluetoothAddress &address, const QString &pin)
212{
213 qDebug() << "PairingDisplayPinCode" << address << pin;
214}
215
216void BtLocalDevice::confirmPairing()
217{
218 static bool confirm = false;
219 confirm = !confirm; //toggle
220 qDebug() << "######" << "Sending pairing confirmation: " << confirm;
221 localDevice->pairingConfirmation(confirmation: confirm);
222}
223
224void BtLocalDevice::cycleSecurityFlags()
225{
226 if (securityFlags.testFlag(flag: QBluetooth::Secure))
227 setSecFlags(QBluetooth::NoSecurity);
228 else if (securityFlags.testFlag(flag: QBluetooth::Encryption))
229 setSecFlags(secFlags() | QBluetooth::Secure);
230 else if (securityFlags.testFlag(flag: QBluetooth::Authentication))
231 setSecFlags(secFlags() | QBluetooth::Encryption);
232 else if (securityFlags.testFlag(flag: QBluetooth::Authorization))
233 setSecFlags(secFlags() | QBluetooth::Authentication);
234 else
235 setSecFlags(secFlags() | QBluetooth::Authorization);
236}
237
238void BtLocalDevice::deviceDiscovered(const QBluetoothDeviceInfo &info)
239{
240 QString services;
241 if (info.serviceClasses() & QBluetoothDeviceInfo::PositioningService)
242 services += "Position|";
243 if (info.serviceClasses() & QBluetoothDeviceInfo::NetworkingService)
244 services += "Network|";
245 if (info.serviceClasses() & QBluetoothDeviceInfo::RenderingService)
246 services += "Rendering|";
247 if (info.serviceClasses() & QBluetoothDeviceInfo::CapturingService)
248 services += "Capturing|";
249 if (info.serviceClasses() & QBluetoothDeviceInfo::ObjectTransferService)
250 services += "ObjectTra|";
251 if (info.serviceClasses() & QBluetoothDeviceInfo::AudioService)
252 services += "Audio|";
253 if (info.serviceClasses() & QBluetoothDeviceInfo::TelephonyService)
254 services += "Telephony|";
255 if (info.serviceClasses() & QBluetoothDeviceInfo::InformationService)
256 services += "Information|";
257
258 services.truncate(pos: services.length()-1); //cut last '/'
259
260 qDebug() << "Found new device: " << info.name() << info.isValid() << info.address().toString()
261 << info.rssi() << info.majorDeviceClass()
262 << info.minorDeviceClass() << services;
263
264}
265
266void BtLocalDevice::discoveryFinished()
267{
268 qDebug() << "###### Device Discovery Finished";
269}
270
271void BtLocalDevice::discoveryCanceled()
272{
273 qDebug() << "###### Device Discovery Canceled";
274}
275
276void BtLocalDevice::discoveryError(QBluetoothDeviceDiscoveryAgent::Error error)
277{
278 auto *client = qobject_cast<QBluetoothDeviceDiscoveryAgent *>(object: sender());
279 if (!client)
280 return;
281 qDebug() << "###### Device Discovery Error:" << error << (client ? client->errorString() : QString());
282}
283
284void BtLocalDevice::startDiscovery()
285{
286 if (deviceAgent) {
287 qDebug() << "###### Starting device discovery process";
288 deviceAgent->start(method: QBluetoothDeviceDiscoveryAgent::ClassicMethod);
289 }
290}
291
292void BtLocalDevice::stopDiscovery()
293{
294 if (deviceAgent) {
295 qDebug() << "Stopping device discovery process";
296 deviceAgent->stop();
297 }
298}
299
300void BtLocalDevice::startServiceDiscovery(bool isMinimalDiscovery)
301{
302 if (serviceAgent) {
303 serviceAgent->setRemoteAddress(QBluetoothAddress());
304
305 qDebug() << "###### Starting service discovery process";
306 serviceAgent->start(mode: isMinimalDiscovery
307 ? QBluetoothServiceDiscoveryAgent::MinimalDiscovery
308 : QBluetoothServiceDiscoveryAgent::FullDiscovery);
309 }
310}
311
312void BtLocalDevice::startTargettedServiceDiscovery()
313{
314 if (serviceAgent) {
315 const QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
316 qDebug() << "###### Starting service discovery on"
317 << baddr.toString();
318 if (baddr.isNull())
319 return;
320
321 if (!serviceAgent->setRemoteAddress(baddr)) {
322 qWarning() << "###### Cannot set remote address. Aborting";
323 return;
324 }
325
326 serviceAgent->start();
327 }
328}
329
330void BtLocalDevice::stopServiceDiscovery()
331{
332 if (serviceAgent) {
333 qDebug() << "Stopping service discovery process";
334 serviceAgent->stop();
335 }
336}
337
338void BtLocalDevice::serviceDiscovered(const QBluetoothServiceInfo &info)
339{
340 QStringList classIds;
341 const QList<QBluetoothUuid> uuids = info.serviceClassUuids();
342 for (const QBluetoothUuid &uuid : uuids)
343 classIds.append(t: uuid.toString());
344 qDebug() << "$$ Found new service" << info.device().address().toString()
345 << info.serviceUuid() << info.serviceName() << info.serviceDescription() << classIds;
346
347 bool matchingService =
348 (info.serviceUuid() == QBluetoothUuid(QString(TEST_SERVICE_UUID)));
349#ifdef Q_OS_ANDROID
350 if (QtAndroid::androidSdkVersion() >= 23) //bug introduced by Android 6.0.1
351 matchingService = matchingService
352 || (info.serviceUuid() == QBluetoothUuid(QString(TEST_REVERSE_SERVICE_UUID)));
353#endif
354
355 if (matchingService
356 || info.serviceClassUuids().contains(t: QBluetoothUuid(QString(TEST_SERVICE_UUID))))
357 {
358 //This is here to detect the test server for SPP testing later on
359 bool alreadyKnown = false;
360 for (const QBluetoothServiceInfo& found : qAsConst(t&: foundTestServers)) {
361 if (found.device().address() == info.device().address()) {
362 alreadyKnown = true;
363 break;
364 }
365 }
366
367 if (!alreadyKnown) {
368 foundTestServers.append(t: info);
369 qDebug() << "@@@@@@@@ Adding:" << info.device().address().toString();
370 }
371 }
372}
373
374void BtLocalDevice::serviceDiscoveryFinished()
375{
376 qDebug() << "###### Service Discovery Finished";
377}
378
379void BtLocalDevice::serviceDiscoveryCanceled()
380{
381 qDebug() << "###### Service Discovery Canceled";
382}
383
384void BtLocalDevice::serviceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error error)
385{
386 auto *client = qobject_cast<QBluetoothServiceDiscoveryAgent *>(object: sender());
387 if (!client)
388 return;
389 qDebug() << "###### Service Discovery Error:" << error << (client ? client->errorString() : QString());
390}
391
392void BtLocalDevice::dumpServiceDiscovery()
393{
394 if (deviceAgent) {
395 qDebug() << "Device Discovery active:" << deviceAgent->isActive();
396 qDebug() << "Error:" << deviceAgent->error() << deviceAgent->errorString();
397 const QList<QBluetoothDeviceInfo> list = deviceAgent->discoveredDevices();
398 qDebug() << "Discovered Devices:" << list.count();
399
400 for (const QBluetoothDeviceInfo &info : list)
401 qDebug() << info.name() << info.address().toString() << info.rssi();
402 }
403 if (serviceAgent) {
404 qDebug() << "Service Discovery active:" << serviceAgent->isActive();
405 qDebug() << "Error:" << serviceAgent->error() << serviceAgent->errorString();
406 const QList<QBluetoothServiceInfo> list = serviceAgent->discoveredServices();
407 qDebug() << "Discovered Services:" << list.count();
408
409 for (const QBluetoothServiceInfo &i : list) {
410 qDebug() << i.device().address().toString() << i.device().name() << i.serviceName();
411 }
412
413 qDebug() << "###### TestServer offered by:";
414 for (const QBluetoothServiceInfo& found : qAsConst(t&: foundTestServers)) {
415 qDebug() << found.device().name() << found.device().address().toString();
416 }
417 }
418}
419
420void BtLocalDevice::connectToService()
421{
422 if (socket) {
423 if (socket->preferredSecurityFlags() != securityFlags)
424 socket->setPreferredSecurityFlags(securityFlags);
425 socket->connectToService(address: QBluetoothAddress(BTCHAT_DEVICE_ADDR),uuid: QBluetoothUuid(QString(TEST_SERVICE_UUID)));
426 }
427}
428
429void BtLocalDevice::connectToServiceViaSearch()
430{
431 if (socket) {
432 qDebug() << "###### Connecting to service socket";
433 if (!foundTestServers.isEmpty()) {
434 if (socket->preferredSecurityFlags() != securityFlags)
435 socket->setPreferredSecurityFlags(securityFlags);
436
437 QBluetoothServiceInfo info = foundTestServers.at(i: 0);
438 socket->connectToService(service: info);
439 } else {
440 qWarning() << "Perform search for test service before triggering this function";
441 }
442 }
443}
444
445void BtLocalDevice::disconnectToService()
446{
447 if (socket) {
448 qDebug() << "###### Disconnecting socket";
449 socket->disconnectFromService();
450 }
451}
452
453void BtLocalDevice::closeSocket()
454{
455 if (socket) {
456 qDebug() << "###### Closing socket";
457 socket->close();
458 }
459
460 if (!serverSockets.isEmpty()) {
461 qDebug() << "###### Closing server sockets";
462 for (QBluetoothSocket *s : serverSockets)
463 s->close();
464 }
465}
466
467void BtLocalDevice::abortSocket()
468{
469 if (socket) {
470 qDebug() << "###### Disconnecting socket";
471 socket->abort();
472 }
473
474 if (!serverSockets.isEmpty()) {
475 qDebug() << "###### Closing server sockets";
476 for (QBluetoothSocket *s : serverSockets)
477 s->abort();
478 }
479}
480
481void BtLocalDevice::socketConnected()
482{
483 qDebug() << "###### Socket connected";
484}
485
486void BtLocalDevice::socketDisconnected()
487{
488 qDebug() << "###### Socket disconnected";
489}
490
491void BtLocalDevice::socketError(QBluetoothSocket::SocketError error)
492{
493 auto *client = qobject_cast<QBluetoothSocket *>(object: sender());
494
495 qDebug() << "###### Socket error" << error << (client ? client->errorString() : QString());
496}
497
498void BtLocalDevice::socketStateChanged(QBluetoothSocket::SocketState state)
499{
500 qDebug() << "###### Socket state" << state;
501 emit socketStateUpdate(foobar: static_cast<int>(state));
502}
503
504void BtLocalDevice::dumpSocketInformation()
505{
506 if (socket) {
507 qDebug() << "*******************************";
508 qDebug() << "Local info (addr, name, port):" << socket->localAddress().toString()
509 << socket->localName() << socket->localPort();
510 qDebug() << "Peer Info (adr, name, port):" << socket->peerAddress().toString()
511 << socket->peerName() << socket->peerPort();
512 qDebug() << "socket type:" << socket->socketType();
513 qDebug() << "socket state:" << socket->state();
514 qDebug() << "socket bytesAvailable()" << socket->bytesAvailable();
515 QString tmp;
516 switch (socket->error()) {
517 case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
518 case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
519 case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
520 case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
521 case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
522 //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
523 case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
524 default: tmp+= "Undefined"; break;
525 }
526
527 qDebug() << "socket error:" << tmp << socket->errorString();
528 } else {
529 qDebug() << "No valid socket existing";
530 }
531}
532
533void BtLocalDevice::writeData()
534{
535 const char * testData = "ABCABC\n";
536 if (socket && socket->state() == QBluetoothSocket::ConnectedState) {
537 socket->write(data: testData);
538 }
539 for (QBluetoothSocket* client : serverSockets) {
540 client->write(data: testData);
541 }
542}
543
544void BtLocalDevice::readData()
545{
546 if (socket) {
547 while (socket->canReadLine()) {
548 QByteArray line = socket->readLine().trimmed();
549 qDebug() << ">> peer(" << socket->peerName() << socket->peerAddress()
550 << socket->peerPort() << ") local("
551 << socket->localName() << socket->localAddress() << socket->localPort()
552 << ")>>" << QString::fromUtf8(str: line.constData(), size: line.length());
553 }
554 }
555}
556
557void BtLocalDevice::serverError(QBluetoothServer::Error error)
558{
559 qDebug() << "###### Server socket error" << error;
560}
561
562void BtLocalDevice::serverListenPort()
563{
564 if (server && localDevice) {
565 if (server->isListening() || serviceInfo.isRegistered()) {
566 qDebug() << "###### Already listening" << serviceInfo.isRegistered();
567 return;
568 }
569
570 if (server->securityFlags() != securityFlags) {
571 qDebug() << "###### Setting security policy on server socket" << securityFlags;
572 server->setSecurityFlags(securityFlags);
573 }
574
575 qDebug() << "###### Start listening via port";
576 bool ret = server->listen(address: localDevice->address());
577 qDebug() << "###### Listening(Expecting TRUE):" << ret;
578
579 if (!ret)
580 return;
581
582 QBluetoothServiceInfo::Sequence profileSequence;
583 QBluetoothServiceInfo::Sequence classId;
584 classId << QVariant::fromValue(value: QBluetoothUuid(QBluetoothUuid::SerialPort));
585 classId << QVariant::fromValue(value: quint16(0x100));
586 profileSequence.append(t: QVariant::fromValue(value: classId));
587 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::BluetoothProfileDescriptorList,
588 value: profileSequence);
589
590 classId.clear();
591 classId << QVariant::fromValue(value: QBluetoothUuid(QString(TEST_SERVICE_UUID)));
592 classId << QVariant::fromValue(value: QBluetoothUuid(QBluetoothUuid::SerialPort));
593 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::ServiceClassIds, value: classId);
594
595 // Service name, description and provider
596 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::ServiceName, value: tr(s: "Bt Chat Server"));
597 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::ServiceDescription,
598 value: tr(s: "Example bluetooth chat server"));
599 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::ServiceProvider, value: tr(s: "qt-project.org"));
600
601 // Service UUID set
602 serviceInfo.setServiceUuid(QBluetoothUuid(QString(TEST_SERVICE_UUID)));
603
604
605 // Service Discoverability
606 QBluetoothServiceInfo::Sequence browseSequence;
607 browseSequence << QVariant::fromValue(value: QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup));
608 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::BrowseGroupList, value: browseSequence);
609
610 // Protocol descriptor list
611 QBluetoothServiceInfo::Sequence protocolDescriptorList;
612 QBluetoothServiceInfo::Sequence protocol;
613 protocol << QVariant::fromValue(value: QBluetoothUuid(QBluetoothUuid::L2cap));
614 if (server->serverType() == QBluetoothServiceInfo::L2capProtocol)
615 protocol << QVariant::fromValue(value: server->serverPort());
616 protocolDescriptorList.append(t: QVariant::fromValue(value: protocol));
617
618 if (server->serverType() == QBluetoothServiceInfo::RfcommProtocol) {
619 protocol.clear();
620 protocol << QVariant::fromValue(value: QBluetoothUuid(QBluetoothUuid::Rfcomm))
621 << QVariant::fromValue(value: quint8(server->serverPort()));
622 protocolDescriptorList.append(t: QVariant::fromValue(value: protocol));
623 }
624 serviceInfo.setAttribute(attributeId: QBluetoothServiceInfo::ProtocolDescriptorList,
625 value: protocolDescriptorList);
626
627 //Register service
628 qDebug() << "###### Registering service on" << localDevice->address().toString() << server->serverPort();
629 bool result = serviceInfo.registerService(localAdapter: localDevice->address());
630 if (!result) {
631 server->close();
632 qDebug() << "###### Reverting registration due to SDP failure.";
633 }
634 }
635
636}
637
638void BtLocalDevice::serverListenUuid()
639{
640 if (server) {
641 if (server->isListening() || serviceInfo.isRegistered()) {
642 qDebug() << "###### Already listening" << serviceInfo.isRegistered();
643 return;
644 }
645
646 if (server->securityFlags() != securityFlags) {
647 qDebug() << "###### Setting security policy on server socket" << securityFlags;
648 server->setSecurityFlags(securityFlags);
649 }
650
651 qDebug() << "###### Start listening via UUID";
652 serviceInfo = server->listen(uuid: QBluetoothUuid(QString(TEST_SERVICE_UUID)), serviceName: tr(s: "Bt Chat Server"));
653 qDebug() << "###### Listening(Expecting TRUE, TRUE):" << serviceInfo.isRegistered() << serviceInfo.isValid();
654 }
655}
656
657void BtLocalDevice::serverClose()
658{
659 if (server) {
660 qDebug() << "###### Closing Server socket";
661 if (serviceInfo.isRegistered())
662 serviceInfo.unregisterService();
663 server->close();
664 }
665}
666
667void BtLocalDevice::serverNewConnection()
668{
669 qDebug() << "###### New incoming server connection, pending:" << server->hasPendingConnections();
670 if (!server->hasPendingConnections()) {
671 qDebug() << "FAIL: expected pending server connection";
672 return;
673 }
674 QBluetoothSocket *client = server->nextPendingConnection();
675 if (!client) {
676 qDebug() << "FAIL: Cannot obtain pending server connection";
677 return;
678 }
679
680 client->setParent(this);
681 connect(sender: client, signal: &QBluetoothSocket::disconnected, receiver: this, slot: &BtLocalDevice::clientSocketDisconnected);
682 connect(sender: client, signal: &QIODevice::readyRead, receiver: this, slot: &BtLocalDevice::clientSocketReadyRead);
683 connect(sender: client, signal: &QBluetoothSocket::stateChanged,
684 receiver: this, slot: &BtLocalDevice::socketStateChanged);
685 connect(sender: client, signal: QOverload<QBluetoothSocket::SocketError>::of(ptr: &QBluetoothSocket::error),
686 receiver: this, slot: &BtLocalDevice::socketError);
687 connect(sender: client, signal: &QBluetoothSocket::connected, receiver: this, slot: &BtLocalDevice::socketConnected);
688 connect(sender: client, signal: &QBluetoothSocket::bytesWritten, context: this, slot: [](qint64 bytesWritten){
689 qDebug() << "Bytes Written to Server socket:" << bytesWritten;
690 });
691 serverSockets.append(t: client);
692}
693
694void BtLocalDevice::clientSocketDisconnected()
695{
696 auto *client = qobject_cast<QBluetoothSocket *>(object: sender());
697 if (!client)
698 return;
699
700 qDebug() << "######" << "Removing server socket connection";
701
702 serverSockets.removeOne(t: client);
703 client->deleteLater();
704}
705
706
707void BtLocalDevice::clientSocketReadyRead()
708{
709 auto *socket = qobject_cast<QBluetoothSocket *>(object: sender());
710 if (!socket)
711 return;
712
713 while (socket->canReadLine()) {
714 const QByteArray line = socket->readLine().trimmed();
715 QString lineString = QString::fromUtf8(str: line.constData(), size: line.length());
716 qDebug() << ">>(" << server->serverAddress() << server->serverPort() <<")>>"
717 << lineString;
718
719 //when using the tst_QBluetoothSocket we echo received text back
720 //Any line starting with "Echo:" will be echoed
721 if (lineString.startsWith(QStringLiteral("Echo:"))) {
722 qDebug() << "Assuming tst_qbluetoothsocket as client. Echoing back.";
723 lineString += QLatin1Char('\n');
724 socket->write(data: lineString.toUtf8());
725 }
726 }
727}
728
729
730void BtLocalDevice::dumpServerInformation()
731{
732 static QBluetooth::SecurityFlags secFlag = QBluetooth::Authentication;
733 if (server) {
734 qDebug() << "*******************************";
735 qDebug() << "server port:" <<server->serverPort()
736 << "type:" << server->serverType()
737 << "address:" << server->serverAddress().toString();
738 qDebug() << "error:" << server->error();
739 qDebug() << "listening:" << server->isListening()
740 << "hasPending:" << server->hasPendingConnections()
741 << "maxPending:" << server->maxPendingConnections();
742 qDebug() << "security:" << server->securityFlags() << "Togling security flag";
743 if (secFlag == QBluetooth::Authentication)
744 secFlag = QBluetooth::Encryption;
745 else
746 secFlag = QBluetooth::Authentication;
747
748 //server->setSecurityFlags(secFlag);
749
750 for (const QBluetoothSocket *client : qAsConst(t&: serverSockets)) {
751 qDebug() << "##" << client->localAddress().toString()
752 << client->localName() << client->localPort();
753 qDebug() << "##" << client->peerAddress().toString()
754 << client->peerName() << client->peerPort();
755 qDebug() << client->socketType() << client->state();
756 qDebug() << "Pending bytes: " << client->bytesAvailable();
757 QString tmp;
758 switch (client->error()) {
759 case QBluetoothSocket::NoSocketError: tmp += "NoSocketError"; break;
760 case QBluetoothSocket::UnknownSocketError: tmp += "UnknownSocketError"; break;
761 case QBluetoothSocket::HostNotFoundError: tmp += "HostNotFoundError"; break;
762 case QBluetoothSocket::ServiceNotFoundError: tmp += "ServiceNotFound"; break;
763 case QBluetoothSocket::NetworkError: tmp += "NetworkError"; break;
764 case QBluetoothSocket::UnsupportedProtocolError: tmp += "UnsupportedProtocolError"; break;
765 //case QBluetoothSocket::OperationError: tmp+= "OperationError"; break;
766 default: tmp += QString::number(static_cast<int>(client->error())); break;
767 }
768
769 qDebug() << "socket error:" << tmp << client->errorString();
770 }
771 }
772}
773
774void BtLocalDevice::dumpInformation()
775{
776 qDebug() << "###### default local device";
777 dumpLocalDevice(dev: localDevice);
778 const QList<QBluetoothHostInfo> list = QBluetoothLocalDevice::allDevices();
779 qDebug() << "Found local devices: " << list.count();
780 for (const QBluetoothHostInfo &info : list) {
781 qDebug() << " " << info.address().toString() << " " <<info.name();
782 }
783
784 QBluetoothAddress address(QStringLiteral("11:22:33:44:55:66"));
785 QBluetoothLocalDevice temp(address);
786 qDebug() << "###### 11:22:33:44:55:66 address valid:" << !address.isNull();
787 dumpLocalDevice(dev: &temp);
788
789 QBluetoothAddress address2;
790 QBluetoothLocalDevice temp2(address2);
791 qDebug() << "###### 00:00:00:00:00:00 address valid:" << !address2.isNull();
792 dumpLocalDevice(dev: &temp2);
793
794 const QBluetoothAddress BB(BTCHAT_DEVICE_ADDR);
795 qDebug() << "###### Bonding state with" << QString(BTCHAT_DEVICE_ADDR) << ":" << localDevice->pairingStatus(address: BB);
796 qDebug() << "###### Bonding state with" << address2.toString() << ": " << localDevice->pairingStatus(address: address2);
797 qDebug() << "###### Bonding state with" << address.toString() << ": " << localDevice->pairingStatus(address);
798
799 qDebug() << "###### Connected Devices";
800 const QList<QBluetoothAddress> connectedDevices = localDevice->connectedDevices();
801 for (const QBluetoothAddress &addr : connectedDevices)
802 qDebug() << " " << addr.toString();
803
804 qDebug() << "###### Discovered Devices";
805 if (deviceAgent) {
806 const QList<QBluetoothDeviceInfo> devices = deviceAgent->discoveredDevices();
807 for (const QBluetoothDeviceInfo &info : devices) {
808 deviceDiscovered(info);
809 }
810 }
811
812 QBluetoothDeviceDiscoveryAgent invalidAgent(QBluetoothAddress("11:22:33:44:55:66"));
813 invalidAgent.start();
814 qDebug() << "######" << "Testing device discovery agent constructor with invalid address";
815 qDebug() << "######" << (invalidAgent.error() == QBluetoothDeviceDiscoveryAgent::InvalidBluetoothAdapterError)
816 << "(Expected: true)";
817 QBluetoothDeviceDiscoveryAgent validAgent(localDevice->address());
818 validAgent.start();
819 qDebug() << "######" << (validAgent.error() == QBluetoothDeviceDiscoveryAgent::NoError) << "(Expected: true)";
820
821 QBluetoothServiceDiscoveryAgent invalidSAgent(QBluetoothAddress("11:22:33:44:55:66"));
822 invalidSAgent.start();
823 qDebug() << "######" << "Testing service discovery agent constructor with invalid address";
824 qDebug() << "######" << (invalidSAgent.error() == QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError)
825 << "(Expected: true)";
826 QBluetoothServiceDiscoveryAgent validSAgent(localDevice->address());
827 validSAgent.start();
828 qDebug() << "######" << (validSAgent.error() == QBluetoothServiceDiscoveryAgent::NoError) << "(Expected: true)";
829}
830
831void BtLocalDevice::powerOn()
832{
833 qDebug() << "Powering on";
834 localDevice->powerOn();
835}
836
837void BtLocalDevice::reset()
838{
839 emit error(error: static_cast<QBluetoothLocalDevice::Error>(1000));
840 if (serviceAgent) {
841 serviceAgent->clear();
842 }
843 foundTestServers.clear();
844}
845
846void BtLocalDevice::dumpLocalDevice(QBluetoothLocalDevice *dev)
847{
848 qDebug() << " Valid: " << dev->isValid();
849 qDebug() << " Name" << dev->name();
850 qDebug() << " Address" << dev->address().toString();
851 qDebug() << " HostMode" << dev->hostMode();
852}
853

source code of qtconnectivity/tests/bttestui/btlocaldevice.cpp