diff options
author | Alex Blasche <alexander.blasche@theqtcompany.com> | 2016-05-25 16:49:57 +0200 |
---|---|---|
committer | Alex Blasche <alexander.blasche@theqtcompany.com> | 2016-06-08 09:40:55 +0000 |
commit | be8c8951744558070d72665f111909fb32b70d4f (patch) | |
tree | 2bddf1521626c06f2a34399a933179c40ab062f2 | |
parent | f59d75eb8b161be9c58d1fe534afa2fa08cf4382 (diff) | |
download | qtconnectivity-be8c8951744558070d72665f111909fb32b70d4f.tar.gz |
Bluez5: Run SDP on target devices which do not support public scans
PUBLIC_BROWSE_GROUP scans are not always supported. In such cases
more targeted service scans are to be used. This patch modifies
QBluetoothServiceDiscoveryAgent such that when a uuid filter
is set targeted service scans are used rather than generic
PUBLIC_BROWSE_GROUP ones.
QBluetoothSocket always scans with an applied uuid filter and
therefore directly benefits from the patch.
Change-Id: I94997d2cf8f70fa7db5422d78c8bfdbe2aa1dbbc
Task-number: QTBUG-53041
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@theqtcompany.com>
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp | 10 | ||||
-rw-r--r-- | src/tools/sdpscanner/main.cpp | 106 |
2 files changed, 99 insertions, 17 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp index e24ee802..716d80be 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp +++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp @@ -214,15 +214,23 @@ void QBluetoothServiceDiscoveryAgentPrivate::runExternalSdpScan( sdpScannerProcess = new QProcess(q); sdpScannerProcess->setReadChannel(QProcess::StandardOutput); + if (QT_BT_BLUEZ().isDebugEnabled()) + sdpScannerProcess->setProcessChannelMode(QProcess::ForwardedErrorChannel); sdpScannerProcess->setProgram(fileInfo.canonicalFilePath()); q->connect(sdpScannerProcess, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(_q_sdpScannerDone(int,QProcess::ExitStatus))); - } QStringList arguments; arguments << remoteAddress.toString() << localAddress.toString(); + // No filter implies PUBLIC_BROWSE_GROUP based SDP scan + if (!uuidFilter.isEmpty()) { + arguments << QLatin1String("-u"); // cmd line option for list of uuids + foreach (const QBluetoothUuid& uuid, uuidFilter) + arguments << uuid.toString(); + } + sdpScannerProcess->setArguments(arguments); sdpScannerProcess->start(); } diff --git a/src/tools/sdpscanner/main.cpp b/src/tools/sdpscanner/main.cpp index 50870651..d7188880 100644 --- a/src/tools/sdpscanner/main.cpp +++ b/src/tools/sdpscanner/main.cpp @@ -34,6 +34,7 @@ #include <QtCore/QByteArray> #include <QtCore/QDebug> #include <stdio.h> +#include <string> #include <bluetooth/bluetooth.h> #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> @@ -46,11 +47,14 @@ void usage() { fprintf(stderr, "Usage:\n"); - fprintf(stderr, "\tsdpscanner <remote bdaddr> <local bdaddr> [Options]\n\n"); + fprintf(stderr, "\tsdpscanner <remote bdaddr> <local bdaddr> [Options] ({uuids})\n\n"); fprintf(stderr, "Performs an SDP scan on remote device, using the SDP server\n" "represented by the local Bluetooth device.\n\n" "Options:\n" - " -p Show scan results in human-readable form\n"); + " -p Show scan results in human-readable form\n" + " -u [list of uuids] List of uuids which should be scanned for.\n" + " Each uuid must be enclosed in {}.\n" + " If the list is empty PUBLIC_BROWSE_GROUP scan is used.\n"); } #define BUFFER_SIZE 1024 @@ -269,6 +273,7 @@ int main(int argc, char **argv) } bool showHumanReadable = false; + std::vector<std::string> targetServices; for (int i = 3; i < argc; i++) { if (argv[i][0] != '-') { @@ -281,12 +286,56 @@ int main(int argc, char **argv) case 'p': showHumanReadable = true; break; + case 'u': + i++; + + for ( ; i < argc && argv[i][0] == '{'; i++) + targetServices.push_back(argv[i]); + + i--; // outer loop increments again + break; default: fprintf(stderr, "Wrong argument: %s\n", argv[i]); usage(); return RETURN_USAGE; + } + } + std::vector<uuid_t> uuids; + for (std::vector<std::string>::const_iterator iter = targetServices.cbegin(); + iter != targetServices.cend(); ++iter) { + + uint128_t temp128; + uint16_t field1, field2, field3, field5; + uint32_t field0, field4; + + fprintf(stderr, "Target scan for %s\n", (*iter).c_str()); + if (sscanf((*iter).c_str(), "{%08x-%04hx-%04hx-%04hx-%08x%04hx}", &field0, + &field1, &field2, &field3, &field4, &field5) != 6) { + fprintf(stderr, "Skipping invalid uuid: %s\n", ((*iter).c_str())); + continue; } + + // we need uuid_t conversion based on + // http://www.spinics.net/lists/linux-bluetooth/msg20356.html + field0 = htonl(field0); + field4 = htonl(field4); + field1 = htons(field1); + field2 = htons(field2); + field3 = htons(field3); + field5 = htons(field5); + + uint8_t* temp = (uint8_t*) &temp128; + memcpy(&temp[0], &field0, 4); + memcpy(&temp[4], &field1, 2); + memcpy(&temp[6], &field2, 2); + memcpy(&temp[8], &field3, 2); + memcpy(&temp[10], &field4, 4); + memcpy(&temp[14], &field5, 2); + + uuid_t sdpUuid; + sdp_uuid128_create(&sdpUuid, &temp128); + uuids.push_back(sdpUuid); } sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY); @@ -301,27 +350,52 @@ int main(int argc, char **argv) } // set the filter for service matches - uuid_t publicBrowseGroupUuid; - sdp_uuid16_create(&publicBrowseGroupUuid, PUBLIC_BROWSE_GROUP); - sdp_list_t *serviceFilter; - serviceFilter = sdp_list_append(0, &publicBrowseGroupUuid); + if (uuids.empty()) { + fprintf(stderr, "Using PUBLIC_BROWSE_GROUP for SDP search\n"); + uuid_t publicBrowseGroupUuid; + sdp_uuid16_create(&publicBrowseGroupUuid, PUBLIC_BROWSE_GROUP); + uuids.push_back(publicBrowseGroupUuid); + } uint32_t attributeRange = 0x0000ffff; //all attributes sdp_list_t *attributes; attributes = sdp_list_append(0, &attributeRange); - sdp_list_t *sdpResults, *previous; - result = sdp_service_search_attr_req(session, serviceFilter, + sdp_list_t *sdpResults, *sdpIter; + sdp_list_t *totalResults = NULL; + sdp_list_t* serviceFilter; + + for (uint i = 0; i < uuids.size(); ++i) { + serviceFilter = sdp_list_append(0, &uuids[i]); + result = sdp_service_search_attr_req(session, serviceFilter, SDP_ATTR_REQ_RANGE, attributes, &sdpResults); - sdp_list_free(attributes, 0); - sdp_list_free(serviceFilter, 0); + sdp_list_free(serviceFilter, 0); + if (result != 0) { + fprintf(stderr, "sdp_service_search_attr_req failed\n"); + sdp_list_free(attributes, 0); + sdp_close(session); + return RETURN_SDP_ERROR; + } - if (result != 0) { - fprintf(stderr, "sdp_service_search_attr_req failed\n"); - sdp_close(session); - return RETURN_SDP_ERROR; + if (!sdpResults) + continue; + + if (!totalResults) { + totalResults = sdpResults; + sdpIter = totalResults; + } else { + // attach each new result list to the end of totalResults + sdpIter->next = sdpResults; + } + + while (sdpIter->next) // skip to end of list + sdpIter = sdpIter->next; } + sdp_list_free(attributes, 0); + + // start XML generation from the front + sdpResults = totalResults; QByteArray total; while (sdpResults) { @@ -330,9 +404,9 @@ int main(int argc, char **argv) const QByteArray xml = parseSdpRecord(record); total += xml; - previous = sdpResults; + sdpIter = sdpResults; sdpResults = sdpResults->next; - free(previous); + free(sdpIter); sdp_record_free(record); } |