summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothserviceinfo_osx.mm
diff options
context:
space:
mode:
authorTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-09-10 12:54:18 +0200
committerTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-09-26 15:41:09 +0200
commitd1d77c8210ecf7a89a81dad69d21b91e06bf129e (patch)
tree94d7b91c64478720eee9c9afd82acfc496c383e1 /src/bluetooth/qbluetoothserviceinfo_osx.mm
parentc1aabdba2e839ba525a4918eebfbf6fbbe96d34d (diff)
Port QBluetoothSocket to OS X.
Implement QBluetoothSocket using IOBluetooth framework on OS X (will implement Qt's API as close as possible with a given Apple's API). Update 0: add (empty for now) delegate classes (L2CAP/RFCOMM). Update 1: add service discovery (called doDeviceDiscovery though). Update 2: implement the public class' logic (QBluetoothSocket, connectToService). Update 3: more public logic implemented (since it's easy :) ) Update 4: L2CAP delegate - initial logic. Update 5: connectToService - L2CAP "socket". Update 6: fix pivate header files. Update 7: fix dependency after the previous patch was merged. Update 8: writeData - initial version for L2CAP. Update 9: since RFCOM/L2CAP delegates have the same interface, no need in duplicating the same class - add a "generic" ChannelDelegate instead. Update 10: more RFCOMM logic. Update 11: function to build a service description from QBluetoothServiceInfo (to be registered on SDP server). Update 12: QBluetoothSocket::close/abort. Update 13: Create a dictioinary out of QBluetoothServiceInfo to register a service. Update 14: Add service registration. Update 15: Convert attributes (sequences and 'scalars') from QBluetoothServiceInfor into NSDictionary. Update 16: Update QBluetoothServiceInfo with a real PSM/ChannelID after a service was registered. Update 17: Move a private class (bluetooth socket) into the separate private header file (to make it visible for bluetooth_server_osx) Update 18: Add an interface to create a bluetooth socket (private class) from a channel, reported by a notification (found by a listening server). Update 19: Fix an invalid assert - any state (Inactive/ServiceDiscovery/DeviceDiscovery) is possible, not only Inactive. Implement the missing 'readData' and 'writeData' for RFCOMM. Set SDP query as non-active after query finished. Temporary (!) workaround - can not invokeMethod on a private socket (d_ptr). Update 20: When creating a socket wrapper from an incoming notification/channel, set: socket type + channel's delegate. Change-Id: Idd6d5478597206ed759f49e282baed948d105ddf Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
Diffstat (limited to 'src/bluetooth/qbluetoothserviceinfo_osx.mm')
-rw-r--r--src/bluetooth/qbluetoothserviceinfo_osx.mm106
1 files changed, 101 insertions, 5 deletions
diff --git a/src/bluetooth/qbluetoothserviceinfo_osx.mm b/src/bluetooth/qbluetoothserviceinfo_osx.mm
index b8463a52..621aab35 100644
--- a/src/bluetooth/qbluetoothserviceinfo_osx.mm
+++ b/src/bluetooth/qbluetoothserviceinfo_osx.mm
@@ -39,19 +39,26 @@
**
****************************************************************************/
+#include "osx/osxbtservicerecord_p.h"
#include "qbluetoothserviceinfo.h"
#include "qbluetoothdeviceinfo.h"
+#include "osx/osxbtutility_p.h"
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qglobal.h>
#include <QtCore/qmap.h>
#include <QtCore/qurl.h>
+// Import, it's Objective-C header (no inclusion guards).
+#import <IOBluetooth/objc/IOBluetoothSDPServiceRecord.h>
+
QT_BEGIN_NAMESPACE
class QBluetoothServiceInfoPrivate
{
public:
- QBluetoothServiceInfoPrivate();
+ QBluetoothServiceInfoPrivate(QBluetoothServiceInfo *q);
~QBluetoothServiceInfoPrivate();
bool registerService(const QBluetoothAddress &localAdapter = QBluetoothAddress());
@@ -65,29 +72,118 @@ public:
QBluetoothServiceInfo::Sequence protocolDescriptor(QBluetoothUuid::ProtocolUuid protocol) const;
int serverChannel() const;
+
+private:
+ QBluetoothServiceInfo *q_ptr;
+ bool registered;
+
+ typedef OSXBluetooth::ObjCScopedPointer<IOBluetoothSDPServiceRecord> SDPRecord;
+ SDPRecord serviceRecord;
};
-QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate()
+QBluetoothServiceInfoPrivate::QBluetoothServiceInfoPrivate(QBluetoothServiceInfo *q)
+ : q_ptr(q),
+ registered(false)
{
+ Q_ASSERT_X(q, "QBluetoothServiceInfoPrivate()", "invalid q_ptr (null)");
}
QBluetoothServiceInfoPrivate::~QBluetoothServiceInfoPrivate()
{
+ // TODO: should it unregister?
}
bool QBluetoothServiceInfoPrivate::registerService(const QBluetoothAddress &localAdapter)
{
Q_UNUSED(localAdapter)
- return false;
+
+ if (registered)
+ return false;
+
+ Q_ASSERT_X(!serviceRecord, "QBluetoothServiceInfoPrivate::registerService()",
+ "not registered, but serviceRecord is not nil");
+
+ // TODO: create a service description (as NSDictionary) and add to the
+ // local SDP server via IOBluetoothSDPServiceRecord and its methods.
+ using namespace OSXBluetooth;
+
+ ObjCStrongReference<NSMutableDictionary>
+ serviceDict(iobluetooth_service_dictionary(*q_ptr));
+
+ if (!serviceDict) {
+ qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), "
+ "failed to create a service dictionary";
+ return false;
+ }
+
+ serviceRecord.reset([[IOBluetoothSDPServiceRecord
+ publishedServiceRecordWithDictionary:serviceDict] retain]);
+
+ if (!serviceRecord) {
+ qCWarning(QT_BT_OSX) << "QBluetoothServiceInfoPrivate::registerService(), "
+ "failed to create register a service record";
+ return false;
+ }
+
+ QBluetoothServiceInfo::Sequence protocolDescriptorList;
+ bool updatePDL = false;
+
+ if (q_ptr->socketProtocol() == QBluetoothServiceInfo::L2capProtocol) {
+ //
+ BluetoothL2CAPPSM psm = 0;
+ if ([serviceRecord getL2CAPPSM:&psm] == kIOReturnSuccess) {
+ if (psm != q_ptr->protocolServiceMultiplexer()) {
+ // Update with a real PSM assigned by IOBluetooth!
+ updatePDL = true;
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocol << QVariant::fromValue(qint16(psm));
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ }
+ }
+ } else if (q_ptr->socketProtocol() == QBluetoothServiceInfo::RfcommProtocol) {
+ //
+ BluetoothRFCOMMChannelID channelID = 0;
+ if ([serviceRecord getRFCOMMChannelID:&channelID] == kIOReturnSuccess) {
+ if (channelID != q_ptr->serverChannel()) {
+ updatePDL = true;
+ QBluetoothServiceInfo::Sequence protocol;
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap));
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ protocol.clear();
+ protocol << QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm))
+ << QVariant::fromValue(quint8(channelID));
+ protocolDescriptorList.append(QVariant::fromValue(protocol));
+ }
+ }
+ }
+
+ if (updatePDL)
+ q_ptr->setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList, protocolDescriptorList);
+
+ // TODO - check ServiceRecordHandle + error handling - if we failed to obtain a port.
+
+ registered = true;
+
+ return true;
}
bool QBluetoothServiceInfoPrivate::isRegistered() const
{
- return false;
+ return registered;
}
bool QBluetoothServiceInfoPrivate::unregisterService()
{
+ if (!registered)
+ return false;
+
+ Q_ASSERT_X(serviceRecord, "QBluetoothServiceInfoPrivate::unregisterService()",
+ "service registered, but serviceRecord is nil");
+
+ [serviceRecord removeServiceRecord];
+ serviceRecord.reset(nil);
+
return false;
}
@@ -107,7 +203,7 @@ bool QBluetoothServiceInfo::unregisterService()
}
QBluetoothServiceInfo::QBluetoothServiceInfo()
- : d_ptr(QSharedPointer<QBluetoothServiceInfoPrivate>(new QBluetoothServiceInfoPrivate))
+ : d_ptr(QSharedPointer<QBluetoothServiceInfoPrivate>(new QBluetoothServiceInfoPrivate(this)))
{
}