summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bluetooth/bluetooth.pro2
-rw-r--r--src/bluetooth/bluez/bluez.pri17
-rw-r--r--src/bluetooth/bluez/bluez5_helper.cpp190
-rw-r--r--src/bluetooth/bluez/bluez5_helper_p.h2
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h87
-rw-r--r--src/bluetooth/bluez/objectmanager_p.h5
-rw-r--r--src/bluetooth/doc/qtbluetooth.qdocconf1
-rw-r--r--src/bluetooth/qbluetoothserver.cpp2
-rw-r--r--src/bluetooth/qbluetoothserver_bluez.cpp5
-rw-r--r--src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp99
-rw-r--r--src/bluetooth/qbluetoothsocket_android.cpp17
-rw-r--r--src/bluetooth/qbluetoothsocket_bluez.cpp5
-rw-r--r--src/nfc/doc/qtnfc.qdocconf1
-rw-r--r--src/src.pro4
-rw-r--r--src/tools/sdpscanner/main.cpp332
-rw-r--r--src/tools/sdpscanner/sdpscanner.pro24
-rw-r--r--tests/bttestui/btlocaldevice.cpp26
-rw-r--r--tests/bttestui/btlocaldevice.h1
-rw-r--r--tests/bttestui/main.qml5
19 files changed, 533 insertions, 292 deletions
diff --git a/src/bluetooth/bluetooth.pro b/src/bluetooth/bluetooth.pro
index 15b840e2..719d7ed5 100644
--- a/src/bluetooth/bluetooth.pro
+++ b/src/bluetooth/bluetooth.pro
@@ -100,8 +100,6 @@ config_bluez:qtHaveModule(dbus) {
qlowenergycontroller_p.cpp
}
- CONFIG += link_pkgconfig
- PKGCONFIG_PRIVATE += bluez
} else:CONFIG(blackberry) {
DEFINES += QT_QNX_BLUETOOTH
diff --git a/src/bluetooth/bluez/bluez.pri b/src/bluetooth/bluez/bluez.pri
index 851949d2..be5a02a7 100644
--- a/src/bluetooth/bluez/bluez.pri
+++ b/src/bluetooth/bluez/bluez.pri
@@ -1,16 +1,3 @@
-linux-*: {
- # bluetooth.h is not standards compliant
- contains(QMAKE_CXXFLAGS, -std=c++0x) {
- QMAKE_CXXFLAGS -= -std=c++0x
- QMAKE_CXXFLAGS += -std=gnu++0x
- CONFIG -= c++11
- }
- c++11 {
- CONFIG -= c++11
- QMAKE_CXXFLAGS += -std=gnu++0x
- }
-}
-
HEADERS += bluez/manager_p.h \
bluez/adapter_p.h \
bluez/device_p.h \
@@ -29,8 +16,8 @@ HEADERS += bluez/manager_p.h \
bluez/profile1_p.h \
bluez/obex_client1_bluez5_p.h \
bluez/obex_objectpush1_bluez5_p.h \
- bluez/obex_transfer1_bluez5_p.h
-
+ bluez/obex_transfer1_bluez5_p.h \
+ bluez/bluez_data_p.h
SOURCES += bluez/manager.cpp \
bluez/adapter.cpp \
diff --git a/src/bluetooth/bluez/bluez5_helper.cpp b/src/bluetooth/bluez/bluez5_helper.cpp
index 18ab22b1..4e810d55 100644
--- a/src/bluetooth/bluez/bluez5_helper.cpp
+++ b/src/bluetooth/bluez/bluez5_helper.cpp
@@ -46,7 +46,6 @@
#include "objectmanager_p.h"
#include "properties_p.h"
#include "adapter1_bluez5_p.h"
-#include <bluetooth/sdp_lib.h>
QT_BEGIN_NAMESPACE
@@ -270,194 +269,6 @@ void QtBluezDiscoveryManager::removeAdapterFromMonitoring(const QString &dbusPat
emit discoveryInterrupted(dbusPath);
}
-#define BUFFER_SIZE 1024
-
-static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &xmlOutput)
-{
- if (!data)
- return;
-
- const int length = indentation*2 + 1;
- QByteArray indentString(length, ' ');
-
- char snBuffer[BUFFER_SIZE];
-
- xmlOutput.append(indentString);
-
- // deal with every dtd type
- switch (data->dtd) {
- case SDP_DATA_NIL:
- xmlOutput.append("<nil/>\n");
- break;
- case SDP_UINT8:
- qsnprintf(snBuffer, BUFFER_SIZE, "<uint8 value=\"0x%02x\"/>\n", data->val.uint8);
- xmlOutput.append(snBuffer);
- break;
- case SDP_UINT16:
- qsnprintf(snBuffer, BUFFER_SIZE, "<uint16 value=\"0x%04x\"/>\n", data->val.uint16);
- xmlOutput.append(snBuffer);
- break;
- case SDP_UINT32:
- qsnprintf(snBuffer, BUFFER_SIZE, "<uint32 value=\"0x%08x\"/>\n", data->val.uint32);
- xmlOutput.append(snBuffer);
- break;
- case SDP_UINT64:
- qsnprintf(snBuffer, BUFFER_SIZE, "<uint64 value=\"0x%016x\"/>\n", data->val.uint64);
- xmlOutput.append(snBuffer);
- break;
- case SDP_UINT128:
- xmlOutput.append("<uint128 value=\"0x");
- for (int i = 0; i < 16; i++)
- ::sprintf(&snBuffer[i * 2], "%02x", data->val.uint128.data[i]);
- xmlOutput.append(snBuffer);
- xmlOutput.append("\"/>\n");
- break;
- case SDP_INT8:
- qsnprintf(snBuffer, BUFFER_SIZE, "<int8 value=\"%d\"/>/n", data->val.int8);
- xmlOutput.append(snBuffer);
- break;
- case SDP_INT16:
- qsnprintf(snBuffer, BUFFER_SIZE, "<int16 value=\"%d\"/>/n", data->val.int16);
- xmlOutput.append(snBuffer);
- break;
- case SDP_INT32:
- qsnprintf(snBuffer, BUFFER_SIZE, "<int32 value=\"%d\"/>/n", data->val.int32);
- xmlOutput.append(snBuffer);
- break;
- case SDP_INT64:
- qsnprintf(snBuffer, BUFFER_SIZE, "<int64 value=\"%d\"/>/n", data->val.int64);
- xmlOutput.append(snBuffer);
- break;
- case SDP_INT128:
- xmlOutput.append("<int128 value=\"0x");
- for (int i = 0; i < 16; i++)
- ::sprintf(&snBuffer[i * 2], "%02x", data->val.int128.data[i]);
- xmlOutput.append(snBuffer);
- xmlOutput.append("\"/>\n");
- break;
- case SDP_UUID_UNSPEC:
- break;
- case SDP_UUID16:
- case SDP_UUID32:
- xmlOutput.append("<uuid value=\"0x");
- sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
- xmlOutput.append(snBuffer);
- xmlOutput.append("\"/>\n");
- break;
- case SDP_UUID128:
- xmlOutput.append("<uuid value=\"");
- sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
- xmlOutput.append(snBuffer);
- xmlOutput.append("\"/>\n");
- break;
- case SDP_TEXT_STR_UNSPEC:
- break;
- case SDP_TEXT_STR8:
- case SDP_TEXT_STR16:
- case SDP_TEXT_STR32:
- {
- xmlOutput.append("<text ");
- QByteArray text = QByteArray::fromRawData(data->val.str, data->unitSize);
-
- bool hasNonPrintableChar = false;
- for (int i = 0; i < text.count() && !hasNonPrintableChar; i++) {
- if (!isprint(text[i])) {
- hasNonPrintableChar = true;
- break;
- }
- }
-
- if (hasNonPrintableChar) {
- xmlOutput.append("encoding=\"hex\" value=\"");
- xmlOutput.append(text.toHex());
- } else {
- text.replace("&", "&amp");
- text.replace("<", "&lt");
- text.replace(">", "&gt");
- text.replace("\"", "&quot");
-
- xmlOutput.append("value=\"");
- xmlOutput.append(text);
- }
-
- xmlOutput.append("\"/>\n");
- break;
- }
- case SDP_BOOL:
- if (data->val.uint8)
- xmlOutput.append("<boolean value=\"true\"/>\n");
- else
- xmlOutput.append("<boolean value=\"false\"/>\n");
- break;
- case SDP_SEQ_UNSPEC:
- break;
- case SDP_SEQ8:
- case SDP_SEQ16:
- case SDP_SEQ32:
- xmlOutput.append("<sequence>\n");
- parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
- xmlOutput.append(indentString);
- xmlOutput.append("</sequence>\n");
- break;
- case SDP_ALT_UNSPEC:
- break;
- case SDP_ALT8:
- case SDP_ALT16:
- case SDP_ALT32:
- xmlOutput.append("<alternate>\n");
- parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
- xmlOutput.append(indentString);
- xmlOutput.append("</alternate>\n");
- break;
- case SDP_URL_STR_UNSPEC:
- break;
- case SDP_URL_STR8:
- case SDP_URL_STR16:
- case SDP_URL_STR32:
- strncpy(snBuffer, data->val.str, data->unitSize - 1);
- xmlOutput.append("<url value=\"");
- xmlOutput.append(snBuffer);
- xmlOutput.append("\"/>\n");
- break;
- default:
- qDebug(QT_BT_BLUEZ) << "Unknown dtd type";
- }
-
- parseAttributeValues(data->next, indentation, xmlOutput);
-}
-
-static void parseAttribute(void *value, void *extraData)
-{
- sdp_data_t *data = (sdp_data_t *) value;
- QByteArray *xmlOutput = static_cast<QByteArray *>(extraData);
-
- char buffer[BUFFER_SIZE];
-
- ::qsnprintf(buffer, BUFFER_SIZE, " <attribute id=\"0x%04x\">\n", data->attrId);
- xmlOutput->append(buffer);
-
- parseAttributeValues(data, 2, *xmlOutput);
-
- xmlOutput->append(" </attribute>\n");
-}
-
-// the resulting xml output is based on the already used xml parser
-QByteArray parseSdpRecord(sdp_record_t *record)
-{
- if (!record || !record->attrlist)
- return QByteArray();
-
- QByteArray xmlOutput;
-
- xmlOutput.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<record>\n");
-
- sdp_list_foreach(record->attrlist, parseAttribute, &xmlOutput);
- xmlOutput.append("</record>");
-
- return xmlOutput;
-}
-
-
/*!
Finds the path for the local adapter with \a wantedAddress or an empty string
if no local adapter with the given address can be found.
@@ -517,5 +328,4 @@ QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok =
return QString(); // nothing matching found
}
-
QT_END_NAMESPACE
diff --git a/src/bluetooth/bluez/bluez5_helper_p.h b/src/bluetooth/bluez/bluez5_helper_p.h
index 36595f9c..4bec440e 100644
--- a/src/bluetooth/bluez/bluez5_helper_p.h
+++ b/src/bluetooth/bluez/bluez5_helper_p.h
@@ -44,7 +44,6 @@
#include <QtCore/QObject>
#include <QtDBus/QtDBus>
-#include <bluetooth/sdp.h>
#include <QtBluetooth/QBluetoothAddress>
typedef QMap<QString, QVariantMap> InterfaceList;
@@ -57,7 +56,6 @@ QT_BEGIN_NAMESPACE
bool isBluez5();
-QByteArray parseSdpRecord(sdp_record_t *record);
QString findAdapterForAddress(const QBluetoothAddress &wantedAddress, bool *ok);
class QtBluezDiscoveryManagerPrivate;
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h
new file mode 100644
index 00000000..822f53b9
--- /dev/null
+++ b/src/bluetooth/bluez/bluez_data_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BLUEZ_DATA_P_H
+#define BLUEZ_DATA_P_H
+
+#include <QtCore/qglobal.h>
+#include <sys/socket.h>
+
+#define BTPROTO_L2CAP 0
+#define BTPROTO_RFCOMM 3
+
+#define SOL_L2CAP 6
+#define SOL_RFCOMM 18
+
+#define RFCOMM_LM 0x03
+
+#define RFCOMM_LM_AUTH 0x0002
+#define RFCOMM_LM_ENCRYPT 0x0004
+#define RFCOMM_LM_TRUSTED 0x0008
+#define RFCOMM_LM_SECURE 0x0020
+
+#define L2CAP_LM 0x03
+#define L2CAP_LM_AUTH 0x0002
+#define L2CAP_LM_ENCRYPT 0x0004
+#define L2CAP_LM_TRUSTED 0x0008
+#define L2CAP_LM_SECURE 0x0020
+
+// Bluetooth address
+typedef struct {
+ quint8 b[6];
+} __attribute__((packed)) bdaddr_t;
+
+// L2CP socket
+struct sockaddr_l2 {
+ sa_family_t l2_family;
+ unsigned short l2_psm;
+ bdaddr_t l2_bdaddr;
+ unsigned short l2_cid;
+};
+
+// RFCOMM socket
+struct sockaddr_rc {
+ sa_family_t rc_family;
+ bdaddr_t rc_bdaddr;
+ quint8 rc_channel;
+};
+
+#endif // BLUEZ_DATA_P_H
diff --git a/src/bluetooth/bluez/objectmanager_p.h b/src/bluetooth/bluez/objectmanager_p.h
index 6acf3d6d..5ecde487 100644
--- a/src/bluetooth/bluez/objectmanager_p.h
+++ b/src/bluetooth/bluez/objectmanager_p.h
@@ -19,6 +19,11 @@
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
+
+/* Temporary hack to merge branches until Bluez headers are removed
+ * from bluez5_helpers_p.h.
+ */
+#define NO_BLUEZ_INCLUDES
#include "bluez5_helper_p.h"
/*
diff --git a/src/bluetooth/doc/qtbluetooth.qdocconf b/src/bluetooth/doc/qtbluetooth.qdocconf
index 171310cb..52061d7e 100644
--- a/src/bluetooth/doc/qtbluetooth.qdocconf
+++ b/src/bluetooth/doc/qtbluetooth.qdocconf
@@ -2,7 +2,6 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtBluetooth
description = Qt Bluetooth Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = bluetooth
diff --git a/src/bluetooth/qbluetoothserver.cpp b/src/bluetooth/qbluetoothserver.cpp
index 8665e33e..3123b032 100644
--- a/src/bluetooth/qbluetoothserver.cpp
+++ b/src/bluetooth/qbluetoothserver.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
diff --git a/src/bluetooth/qbluetoothserver_bluez.cpp b/src/bluetooth/qbluetoothserver_bluez.cpp
index e5967f7a..4532e570 100644
--- a/src/bluetooth/qbluetoothserver_bluez.cpp
+++ b/src/bluetooth/qbluetoothserver_bluez.cpp
@@ -43,14 +43,11 @@
#include "qbluetoothserver_p.h"
#include "qbluetoothsocket.h"
#include "qbluetoothlocaldevice.h"
+#include "bluez/bluez_data_p.h"
#include <QtCore/QLoggingCategory>
#include <QtCore/QSocketNotifier>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/l2cap.h>
-
#include <errno.h>
QT_BEGIN_NAMESPACE
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
index 1d7a6327..2f2f26d8 100644
--- a/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
+++ b/src/bluetooth/qbluetoothservicediscoveryagent_bluez.cpp
@@ -50,11 +50,10 @@
#include "bluez/objectmanager_p.h"
#include "bluez/adapter1_bluez5_p.h"
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
+#include <QtCore/QFile>
+#include <QtCore/QLibraryInfo>
#include <QtCore/QLoggingCategory>
+#include <QtCore/QProcess>
#include <QtDBus/QDBusPendingCallWatcher>
#include <QtConcurrent/QtConcurrentRun>
@@ -205,76 +204,53 @@ void QBluetoothServiceDiscoveryAgentPrivate::startBluez5(const QBluetoothAddress
/*
* This function runs in a different thread. We need to be very careful what we
* access from here. That's why invokeMethod is used below.
+ *
+ * src/tools/sdpscanner performs an SDP scan. This is
+ * done out-of-process to avoid license issues. At this stage Bluez uses GPLv2.
*/
void QBluetoothServiceDiscoveryAgentPrivate::runSdpScan(
const QBluetoothAddress &remoteAddress, const QBluetoothAddress localAddress)
{
Q_Q(QBluetoothServiceDiscoveryAgent);
- // connect to SDP server
- bdaddr_t local, remote;
- convertAddress(localAddress.toUInt64(), local.b);
- convertAddress(remoteAddress.toUInt64(), remote.b);
-
- /* We use singleshot timer below because this function runs in a different
- * thread than the rest of this class.
- */
-
- sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
- // try one more time if first attempt fails
- if (!session)
- session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
+ const QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath);
- qCDebug(QT_BT_BLUEZ) << "SDP for" << remoteAddress.toString() << session << qt_error_string(errno);
- if (!session) {
- if (singleDevice) {
- // was sole device without result -> error
- QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
+ QFileInfo fileInfo(binPath, QStringLiteral("sdpscanner"));
+ if (!fileInfo.exists() || !fileInfo.isExecutable()) {
+ QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
QBluetoothServiceDiscoveryAgent::InputOutputError),
Q_ARG(QString,
- QBluetoothServiceDiscoveryAgent::tr("Unable to access device")),
+ QBluetoothServiceDiscoveryAgent::tr("Unable to find sdpscanner")),
Q_ARG(QStringList, QStringList()));
- } else {
- // go to next device
- QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
- Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
- QBluetoothServiceDiscoveryAgent::NoError),
- Q_ARG(QString, QString()),
- Q_ARG(QStringList, QStringList()));
- }
-
+ qCWarning(QT_BT_BLUEZ) << "Cannot find sdpscanner:"
+ << fileInfo.canonicalFilePath();
return;
}
+ QStringList arguments;
+ arguments << remoteAddress.toString() << localAddress.toString();
- // set the filter for service matches
- uuid_t publicBrowseGroupUuid;
- sdp_uuid16_create(&publicBrowseGroupUuid, QBluetoothUuid::PublicBrowseGroup);
- sdp_list_t *serviceFilter;
- serviceFilter = sdp_list_append(0, &publicBrowseGroupUuid);
-
- uint32_t attributeRange = 0x0000ffff; //all attributes
- sdp_list_t *attributes;
- attributes = sdp_list_append(0, &attributeRange);
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
+ process.setReadChannel(QProcess::StandardOutput);
+ process.start(fileInfo.canonicalFilePath(), arguments);
+ process.waitForFinished();
- sdp_list_t* sdpResults;
- int result = sdp_service_search_attr_req(session, serviceFilter, SDP_ATTR_REQ_RANGE,
- attributes, &sdpResults);
- sdp_list_free(attributes, 0);
- sdp_list_free(serviceFilter, 0);
-
- if (result != 0) {
- qCDebug(QT_BT_BLUEZ) << "SDP search failed" << qt_error_string(errno);
- sdp_close(session);
+ if (process.exitStatus() != QProcess::NormalExit
+ || process.exitCode() != 0) {
+ qCWarning(QT_BT_BLUEZ) << "SDP scan failure"
+ << process.exitStatus() << process.exitCode()
+ << remoteAddress;
if (singleDevice) {
QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
QBluetoothServiceDiscoveryAgent::InputOutputError),
Q_ARG(QString,
- QBluetoothServiceDiscoveryAgent::tr("Unable to access device")),
+ QBluetoothServiceDiscoveryAgent::tr("Unable to perform SDP scan")),
Q_ARG(QStringList, QStringList()));
} else {
+ // go to next device
QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
QBluetoothServiceDiscoveryAgent::NoError),
@@ -284,23 +260,20 @@ void QBluetoothServiceDiscoveryAgentPrivate::runSdpScan(
return;
}
- qCDebug(QT_BT_BLUEZ) << "SDP search a success. Iterating results" << sdpResults;
QStringList xmlRecords;
- // process the results
- for ( ; sdpResults; sdpResults = sdpResults->next) {
- sdp_record_t *record = (sdp_record_t *) sdpResults->data;
+ int size, index = 0;
+ const QByteArray output = QByteArray::fromBase64(process.readAll());
+ const char *data = output.constData();
- QByteArray xml = parseSdpRecord(record);
- if (xml.isEmpty())
- continue;
-
- //qDebug() << xml;
- xmlRecords.append(QString::fromUtf8(xml));
+ // separate the individial SDP records
+ // each record starts with 4 byte size indicator
+ while (index < output.size()) {
+ memcpy(&size, &data[index], sizeof(int));
+ xmlRecords.append(QString::fromUtf8(output.mid(index+sizeof(int), size)));
+ index += sizeof(int) + size;
}
- sdp_close(session);
-
QMetaObject::invokeMethod(q, "_q_finishSdpScan", Qt::QueuedConnection,
Q_ARG(QBluetoothServiceDiscoveryAgent::Error,
QBluetoothServiceDiscoveryAgent::NoError),
diff --git a/src/bluetooth/qbluetoothsocket_android.cpp b/src/bluetooth/qbluetoothsocket_android.cpp
index f2969da8..d499b6ad 100644
--- a/src/bluetooth/qbluetoothsocket_android.cpp
+++ b/src/bluetooth/qbluetoothsocket_android.cpp
@@ -98,6 +98,8 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr
Q_Q(QBluetoothSocket);
Q_UNUSED(openMode);
+ qCDebug(QT_BT_ANDROID) << "connectToServiceConc()" << address.toString() << uuid.toString();
+
if (!adapter.isValid()) {
qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
errorString = QBluetoothSocket::tr("Device does not support Bluetooth");
@@ -157,7 +159,7 @@ void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &addr
}
socketObject.callMethod<void>("connect");
- if (env->ExceptionCheck() || socketObject.callMethod<jboolean>("isConnected") == JNI_FALSE) {
+ if (env->ExceptionCheck()) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
@@ -383,14 +385,11 @@ void QBluetoothSocketPrivate::inputThreadError(int errorCode)
//cleanup internal objects
//if it was call to local close()/abort() the objects are cleaned up already
- bool stillConnected = socketObject.callMethod<jboolean>("isConnected");
- if (stillConnected) {
- QAndroidJniEnvironment env;
- socketObject.callMethod<void>("close");
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
+ QAndroidJniEnvironment env;
+ socketObject.callMethod<void>("close");
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
}
inputStream = outputStream = remoteDevice = socketObject = QAndroidJniObject();
diff --git a/src/bluetooth/qbluetoothsocket_bluez.cpp b/src/bluetooth/qbluetoothsocket_bluez.cpp
index b046998a..1807a225 100644
--- a/src/bluetooth/qbluetoothsocket_bluez.cpp
+++ b/src/bluetooth/qbluetoothsocket_bluez.cpp
@@ -45,16 +45,13 @@
#include "bluez/manager_p.h"
#include "bluez/adapter_p.h"
#include "bluez/device_p.h"
-#include "bluez/bluez5_helper_p.h"
#include "bluez/objectmanager_p.h"
#include <QtBluetooth/QBluetoothLocalDevice>
+#include "bluez/bluez_data_p.h"
#include <qplatformdefs.h>
#include <QtCore/QLoggingCategory>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/l2cap.h>
#include <errno.h>
#include <unistd.h>
diff --git a/src/nfc/doc/qtnfc.qdocconf b/src/nfc/doc/qtnfc.qdocconf
index 2d5b0ef5..61ed15b6 100644
--- a/src/nfc/doc/qtnfc.qdocconf
+++ b/src/nfc/doc/qtnfc.qdocconf
@@ -2,7 +2,6 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtNfc
description = Qt NFC Reference Documentation
-url = http://qt-project.org/doc/qt-$QT_VER
version = $QT_VERSION
examplesinstallpath = nfc
diff --git a/src/src.pro b/src/src.pro
index e017d34b..c5585757 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -17,3 +17,7 @@ qtHaveModule(quick) {
imports.depends += bluetooth nfc
SUBDIRS += imports
}
+
+config_bluez:qtHaveModule(dbus) {
+ SUBDIRS += tools/sdpscanner
+}
diff --git a/src/tools/sdpscanner/main.cpp b/src/tools/sdpscanner/main.cpp
new file mode 100644
index 00000000..39624976
--- /dev/null
+++ b/src/tools/sdpscanner/main.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <stdio.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#define RETURN_SUCCESS 0
+#define RETURN_USAGE 1
+#define RETURN_INVALPARAM 2
+#define RETURN_SDP_ERROR 3
+
+void usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\tsdpscanner <remote bdaddr> <local bdaddr>\n\n");
+ fprintf(stderr, "Performs an SDP scan on remote device, using the SDP server\n"
+ "represented by the local Bluetooth device.\n");
+}
+
+#define BUFFER_SIZE 1024
+
+static void parseAttributeValues(sdp_data_t *data, int indentation, QByteArray &xmlOutput)
+{
+ if (!data)
+ return;
+
+ const int length = indentation*2 + 1;
+ QByteArray indentString(length, ' ');
+
+ char snBuffer[BUFFER_SIZE];
+
+ xmlOutput.append(indentString);
+
+ // deal with every dtd type
+ switch (data->dtd) {
+ case SDP_DATA_NIL:
+ xmlOutput.append("<nil/>\n");
+ break;
+ case SDP_UINT8:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint8 value=\"0x%02x\"/>\n", data->val.uint8);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT16:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint16 value=\"0x%04x\"/>\n", data->val.uint16);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT32:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint32 value=\"0x%08x\"/>\n", data->val.uint32);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT64:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<uint64 value=\"0x%016x\"/>\n", data->val.uint64);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_UINT128:
+ xmlOutput.append("<uint128 value=\"0x");
+ for (int i = 0; i < 16; i++)
+ ::sprintf(&snBuffer[i * 2], "%02x", data->val.uint128.data[i]);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_INT8:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int8 value=\"%d\"/>/n", data->val.int8);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT16:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int16 value=\"%d\"/>/n", data->val.int16);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT32:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int32 value=\"%d\"/>/n", data->val.int32);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT64:
+ qsnprintf(snBuffer, BUFFER_SIZE, "<int64 value=\"%d\"/>/n", data->val.int64);
+ xmlOutput.append(snBuffer);
+ break;
+ case SDP_INT128:
+ xmlOutput.append("<int128 value=\"0x");
+ for (int i = 0; i < 16; i++)
+ ::sprintf(&snBuffer[i * 2], "%02x", data->val.int128.data[i]);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_UUID_UNSPEC:
+ break;
+ case SDP_UUID16:
+ case SDP_UUID32:
+ xmlOutput.append("<uuid value=\"0x");
+ sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_UUID128:
+ xmlOutput.append("<uuid value=\"");
+ sdp_uuid2strn(&(data->val.uuid), snBuffer, BUFFER_SIZE);
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ case SDP_TEXT_STR_UNSPEC:
+ break;
+ case SDP_TEXT_STR8:
+ case SDP_TEXT_STR16:
+ case SDP_TEXT_STR32:
+ {
+ xmlOutput.append("<text ");
+ QByteArray text = QByteArray::fromRawData(data->val.str, data->unitSize);
+
+ bool hasNonPrintableChar = false;
+ for (int i = 0; i < text.count() && !hasNonPrintableChar; i++) {
+ if (!isprint(text[i])) {
+ hasNonPrintableChar = true;
+ break;
+ }
+ }
+
+ if (hasNonPrintableChar) {
+ xmlOutput.append("encoding=\"hex\" value=\"");
+ xmlOutput.append(text.toHex());
+ } else {
+ text.replace("&", "&amp");
+ text.replace("<", "&lt");
+ text.replace(">", "&gt");
+ text.replace("\"", "&quot");
+
+ xmlOutput.append("value=\"");
+ xmlOutput.append(text);
+ }
+
+ xmlOutput.append("\"/>\n");
+ break;
+ }
+ case SDP_BOOL:
+ if (data->val.uint8)
+ xmlOutput.append("<boolean value=\"true\"/>\n");
+ else
+ xmlOutput.append("<boolean value=\"false\"/>\n");
+ break;
+ case SDP_SEQ_UNSPEC:
+ break;
+ case SDP_SEQ8:
+ case SDP_SEQ16:
+ case SDP_SEQ32:
+ xmlOutput.append("<sequence>\n");
+ parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
+ xmlOutput.append(indentString);
+ xmlOutput.append("</sequence>\n");
+ break;
+ case SDP_ALT_UNSPEC:
+ break;
+ case SDP_ALT8:
+ case SDP_ALT16:
+ case SDP_ALT32:
+ xmlOutput.append("<alternate>\n");
+ parseAttributeValues(data->val.dataseq, indentation + 1, xmlOutput);
+ xmlOutput.append(indentString);
+ xmlOutput.append("</alternate>\n");
+ break;
+ case SDP_URL_STR_UNSPEC:
+ break;
+ case SDP_URL_STR8:
+ case SDP_URL_STR16:
+ case SDP_URL_STR32:
+ strncpy(snBuffer, data->val.str, data->unitSize - 1);
+ xmlOutput.append("<url value=\"");
+ xmlOutput.append(snBuffer);
+ xmlOutput.append("\"/>\n");
+ break;
+ default:
+ fprintf(stderr, "Unknown dtd type\n");
+ }
+
+ parseAttributeValues(data->next, indentation, xmlOutput);
+}
+
+static void parseAttribute(void *value, void *extraData)
+{
+ sdp_data_t *data = (sdp_data_t *) value;
+ QByteArray *xmlOutput = static_cast<QByteArray *>(extraData);
+
+ char buffer[BUFFER_SIZE];
+
+ ::qsnprintf(buffer, BUFFER_SIZE, " <attribute id=\"0x%04x\">\n", data->attrId);
+ xmlOutput->append(buffer);
+
+ parseAttributeValues(data, 2, *xmlOutput);
+
+ xmlOutput->append(" </attribute>\n");
+}
+
+// the resulting xml output is based on the already used xml parser
+QByteArray parseSdpRecord(sdp_record_t *record)
+{
+ if (!record || !record->attrlist)
+ return QByteArray();
+
+ QByteArray xmlOutput;
+
+ xmlOutput.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<record>\n");
+
+ sdp_list_foreach(record->attrlist, parseAttribute, &xmlOutput);
+ xmlOutput.append("</record>");
+
+ return xmlOutput;
+}
+
+
+int main(int argc, char **argv)
+{
+ if (argc != 3) {
+ usage();
+ return RETURN_USAGE;
+ }
+
+ fprintf(stderr, "SDP for %s %s\n", argv[1], argv[2]);
+
+ bdaddr_t remote;
+ bdaddr_t local;
+ int result = str2ba(argv[1], &remote);
+ if (result < 0) {
+ fprintf(stderr, "Invalid remote address: %s\n", argv[1]);
+ return RETURN_INVALPARAM;
+ }
+
+ result = str2ba(argv[2], &local);
+ if (result < 0) {
+ fprintf(stderr, "Invalid local address: %s\n", argv[2]);
+ return RETURN_INVALPARAM;
+ }
+
+ sdp_session_t *session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
+ if (!session) {
+ //try one more time if first time failed
+ session = sdp_connect( &local, &remote, SDP_RETRY_IF_BUSY);
+ }
+
+ if (!session) {
+ fprintf(stderr, "Cannot establish sdp session\n");
+ return RETURN_SDP_ERROR;
+ }
+
+ // 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);
+
+ 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_ATTR_REQ_RANGE,
+ attributes, &sdpResults);
+ sdp_list_free(attributes, 0);
+ sdp_list_free(serviceFilter, 0);
+
+ if (result != 0) {
+ fprintf(stderr, "sdp_service_search_attr_req failed\n");
+ sdp_close(session);
+ return RETURN_SDP_ERROR;
+ }
+
+ char sizeField[sizeof(int)];
+ while (sdpResults) {
+ sdp_record_t *record = (sdp_record_t *) sdpResults->data;
+
+ QByteArray xml = parseSdpRecord(record);
+ if (xml.isEmpty())
+ continue;
+
+ //endianness doesn't matter since same machine
+ int sz = xml.size();
+ memcpy(&sizeField, &sz, sizeof(int));
+ xml.prepend(QByteArray(sizeField, sizeof(int)));
+
+ printf("%s", xml.toBase64().constData());
+
+ previous = sdpResults;
+ sdpResults = sdpResults->next;
+ free(previous);
+ sdp_record_free(record);
+
+ }
+
+ sdp_close(session);
+
+ return RETURN_SUCCESS;
+}
diff --git a/src/tools/sdpscanner/sdpscanner.pro b/src/tools/sdpscanner/sdpscanner.pro
new file mode 100644
index 00000000..6bf0a96c
--- /dev/null
+++ b/src/tools/sdpscanner/sdpscanner.pro
@@ -0,0 +1,24 @@
+TEMPLATE = app
+TARGET = sdpscanner
+
+QT = core
+
+SOURCES = main.cpp
+
+CONFIG += link_pkgconfig
+PKGCONFIG_PRIVATE += bluez
+
+load(qt_tool)
+
+linux-*: {
+ # bluetooth.h is not standards compliant
+ contains(QMAKE_CXXFLAGS, -std=c++0x) {
+ QMAKE_CXXFLAGS -= -std=c++0x
+ QMAKE_CXXFLAGS += -std=gnu++0x
+ CONFIG -= c++11
+ }
+ c++11 {
+ CONFIG -= c++11
+ QMAKE_CXXFLAGS += -std=gnu++0x
+ }
+}
diff --git a/tests/bttestui/btlocaldevice.cpp b/tests/bttestui/btlocaldevice.cpp
index df23c859..6b7027d0 100644
--- a/tests/bttestui/btlocaldevice.cpp
+++ b/tests/bttestui/btlocaldevice.cpp
@@ -268,6 +268,8 @@ void BtLocalDevice::stopDiscovery()
void BtLocalDevice::startServiceDiscovery(bool isMinimalDiscovery)
{
if (serviceAgent) {
+ serviceAgent->setRemoteAddress(QBluetoothAddress());
+
qDebug() << "###### Starting service discovery process";
serviceAgent->start(isMinimalDiscovery
? QBluetoothServiceDiscoveryAgent::MinimalDiscovery
@@ -275,6 +277,24 @@ void BtLocalDevice::startServiceDiscovery(bool isMinimalDiscovery)
}
}
+void BtLocalDevice::startTargettedServiceDiscovery()
+{
+ if (serviceAgent) {
+ const QBluetoothAddress baddr(BTCHAT_DEVICE_ADDR);
+ qDebug() << "###### Starting service discovery on"
+ << baddr.toString();
+ if (baddr.isNull())
+ return;
+
+ if (!serviceAgent->setRemoteAddress(baddr)) {
+ qWarning() << "###### Cannot set remote address. Aborting";
+ return;
+ }
+
+ serviceAgent->start();
+ }
+}
+
void BtLocalDevice::stopServiceDiscovery()
{
if (serviceAgent) {
@@ -409,6 +429,12 @@ void BtLocalDevice::abortSocket()
qDebug() << "###### Disconnecting socket";
socket->abort();
}
+
+ if (!serverSockets.isEmpty()) {
+ qDebug() << "###### Closing server sockets";
+ foreach (QBluetoothSocket *s, serverSockets)
+ s->abort();
+ }
}
void BtLocalDevice::socketConnected()
diff --git a/tests/bttestui/btlocaldevice.h b/tests/bttestui/btlocaldevice.h
index a9571ecc..a0c020cc 100644
--- a/tests/bttestui/btlocaldevice.h
+++ b/tests/bttestui/btlocaldevice.h
@@ -87,6 +87,7 @@ public slots:
//QBluetoothServiceDiscoveryAgent
void startServiceDiscovery(bool isMinimalDiscovery);
+ void startTargettedServiceDiscovery();
void stopServiceDiscovery();
void serviceDiscovered(const QBluetoothServiceInfo &info);
void leServiceDiscovered(const QLowEnergyServiceInfo &leInfo);
diff --git a/tests/bttestui/main.qml b/tests/bttestui/main.qml
index d53aa4e1..93d943f2 100644
--- a/tests/bttestui/main.qml
+++ b/tests/bttestui/main.qml
@@ -168,6 +168,11 @@ Rectangle {
onClicked: device.startServiceDiscovery(false)
}
Button {
+ id: startRemoteSDiscBtn
+ buttonText: "StartRemSDisc"
+ onClicked: device.startTargettedServiceDiscovery()
+ }
+ Button {
buttonText: "StopSDisc"
onClicked: device.stopServiceDiscovery();
}