QBluetoothSocket - deduplicate the code (macOS)

Implement the proper interface from QBluetoothSocketBasePrivate,
remove a dummy base class. Remove all public API from
qbluetoothsocket_osx.mm and re-use the code in qbluetoothsocket.cpp.
The code generally is the same, a bit of re-hashin/deletion.

Task-number: QTBUG-75348
Change-Id: I0034dfd283daf9d51775d8f9551b85d2d436aa85
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
This commit is contained in:
Timur Pocheptsov 2019-07-04 16:13:44 +02:00
parent de3e8e85cc
commit c1286c3a34
14 changed files with 369 additions and 775 deletions

View File

@ -176,8 +176,6 @@ qtConfig(bluez) {
SOURCES -= qbluetoothserviceinfo.cpp
SOURCES -= qbluetoothservicediscoveryagent.cpp
SOURCES -= qbluetoothsocket.cpp
SOURCES -= qbluetoothsocketbase.cpp
} else:ios|tvos {
DEFINES += QT_IOS_BLUETOOTH
LIBS_PRIVATE += -framework Foundation -framework CoreBluetooth

View File

@ -20,7 +20,6 @@ CONFIG(osx) {
osx/osxbtsdpinquiry_p.h \
osx/osxbtrfcommchannel_p.h \
osx/osxbtl2capchannel_p.h \
osx/osxbtchanneldelegate_p.h \
osx/osxbtservicerecord_p.h \
osx/osxbtsocketlistener_p.h \
osx/osxbtobexsession_p.h \
@ -37,7 +36,6 @@ CONFIG(osx) {
osx/osxbtsdpinquiry.mm \
osx/osxbtrfcommchannel.mm \
osx/osxbtl2capchannel.mm \
osx/osxbtchanneldelegate.mm \
osx/osxbtservicerecord.mm \
osx/osxbtsocketlistener.mm \
osx/osxbtobexsession.mm \

View File

@ -1,52 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "osxbtchanneldelegate_p.h"
QT_BEGIN_NAMESPACE
namespace OSXBluetooth {
ChannelDelegate::~ChannelDelegate()
{
}
}
QT_END_NAMESPACE

View File

@ -1,79 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef OSXBTCHANNELDELEGATE_P_H
#define OSXBTCHANNELDELEGATE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qglobal.h>
#include <IOKit/IOReturn.h>
QT_BEGIN_NAMESPACE
namespace OSXBluetooth {
class ChannelDelegate
{
public:
virtual ~ChannelDelegate();
virtual void setChannelError(IOReturn errorCode) = 0;
virtual void channelOpenComplete() = 0;
virtual void channelClosed() = 0;
virtual void readChannelData(void *data, std::size_t size) = 0;
virtual void writeComplete() = 0;
};
}
QT_END_NAMESPACE
#endif

View File

@ -37,10 +37,10 @@
**
****************************************************************************/
#include "osxbtchanneldelegate_p.h"
#include "osxbtl2capchannel_p.h"
#include "qbluetoothaddress.h"
#include "osxbtutility_p.h"
#include "btdelegates_p.h"
#include <QtCore/qloggingcategory.h>
#include <QtCore/qdebug.h>
@ -49,13 +49,13 @@ QT_USE_NAMESPACE
@implementation QT_MANGLE_NAMESPACE(OSXBTL2CAPChannel)
{
QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *delegate;
QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
IOBluetoothDevice *device;
IOBluetoothL2CAPChannel *channel;
bool connected;
}
- (id)initWithDelegate:(OSXBluetooth::ChannelDelegate *)aDelegate
- (id)initWithDelegate:(DarwinBluetooth::ChannelDelegate *)aDelegate
{
Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
@ -69,7 +69,7 @@ QT_USE_NAMESPACE
return self;
}
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth::ChannelDelegate) *)aDelegate
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::ChannelDelegate) *)aDelegate
channel:(IOBluetoothL2CAPChannel *)aChannel
{
// This type of channel does not require connect, it's created with

View File

@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
class QBluetoothAddress;
namespace OSXBluetooth {
namespace DarwinBluetooth {
class ChannelDelegate;
@ -73,8 +73,8 @@ QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(OSXBTL2CAPChannel) : NSObject<IOBluetoothL2CAPChannelDelegate>
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *)aDelegate;
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *)aDelegate
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *)aDelegate;
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *)aDelegate
channel:(IOBluetoothL2CAPChannel *)aChannel;
- (void)dealloc;

View File

@ -37,22 +37,22 @@
**
****************************************************************************/
#include "osxbtchanneldelegate_p.h"
#include "osxbtrfcommchannel_p.h"
#include "qbluetoothaddress.h"
#include "osxbtutility_p.h"
#include "btdelegates_p.h"
QT_USE_NAMESPACE
@implementation QT_MANGLE_NAMESPACE(OSXBTRFCOMMChannel)
{
QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *delegate;
QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
IOBluetoothDevice *device;
IOBluetoothRFCOMMChannel *channel;
bool connected;
}
- (id)initWithDelegate:(OSXBluetooth::ChannelDelegate *)aDelegate
- (id)initWithDelegate:(DarwinBluetooth::ChannelDelegate *)aDelegate
{
Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
@ -66,7 +66,7 @@ QT_USE_NAMESPACE
return self;
}
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth::ChannelDelegate) *)aDelegate
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::ChannelDelegate) *)aDelegate
channel:(IOBluetoothRFCOMMChannel *)aChannel
{
// This type of channel does not require connect, it's created with

View File

@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
class QBluetoothAddress;
namespace OSXBluetooth {
namespace DarwinBluetooth {
class ChannelDelegate;
@ -73,8 +73,8 @@ QT_END_NAMESPACE
@interface QT_MANGLE_NAMESPACE(OSXBTRFCOMMChannel) : NSObject<IOBluetoothRFCOMMChannelDelegate>
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *)aDelegate;
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(OSXBluetooth)::ChannelDelegate *)aDelegate
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *)aDelegate;
- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *)aDelegate
channel:(IOBluetoothRFCOMMChannel *)aChannel;
- (void)dealloc;

View File

@ -389,10 +389,10 @@ QBluetoothSocket *QBluetoothServer::nextPendingConnection()
d_ptr->pendingConnections.pop_front();
if (d_ptr->serverType == ServiceInfo::RfcommProtocol) {
if (!newSocket->d_ptr->setChannel(channel.getAs<IOBluetoothRFCOMMChannel>()))
if (!static_cast<QBluetoothSocketPrivate *>(newSocket->d_ptr)->setRFCOMChannel(channel.getAs<IOBluetoothRFCOMMChannel>()))
return nullptr;
} else {
if (!newSocket->d_ptr->setChannel(channel.getAs<IOBluetoothL2CAPChannel>()))
if (!static_cast<QBluetoothSocketPrivate *>(newSocket->d_ptr)->setL2CAPChannel(channel.getAs<IOBluetoothL2CAPChannel>()))
return nullptr;
}

View File

@ -47,6 +47,8 @@
#include "qbluetoothsocket_android_p.h"
#elif defined(QT_WINRT_BLUETOOTH)
#include "qbluetoothsocket_winrt_p.h"
#elif defined(QT_OSX_BLUETOOTH)
#include "qbluetoothsocket_osx_p.h"
#else
#include "qbluetoothsocket_dummy_p.h"
#endif
@ -267,6 +269,8 @@ static QBluetoothSocketBasePrivate *createSocketPrivate()
return new QBluetoothSocketPrivateAndroid();
#elif defined(QT_WINRT_BLUETOOTH)
return new QBluetoothSocketPrivateWinRT();
#elif defined(QT_OSX_BLUETOOTH)
return new QBluetoothSocketPrivate();
#else
return new QBluetoothSocketPrivateDummy();
#endif
@ -513,6 +517,9 @@ QString QBluetoothSocket::errorString() const
*/
void QBluetoothSocket::setPreferredSecurityFlags(QBluetooth::SecurityFlags flags)
{
#ifdef QT_OSX_BLUETOOTH
return; // not supported on macOS.
#endif
Q_D(QBluetoothSocketBase);
if (d->secFlags != flags)
d->secFlags = flags;
@ -534,8 +541,13 @@ void QBluetoothSocket::setPreferredSecurityFlags(QBluetooth::SecurityFlags flags
*/
QBluetooth::SecurityFlags QBluetoothSocket::preferredSecurityFlags() const
{
#if QT_OSX_BLUETOOTH
// not supported on macOS - platform always uses encryption
return QBluetooth::Secure;
#else
Q_D(const QBluetoothSocketBase);
return d->secFlags;
#endif // QT_OSX_BLUETOOTH
}
/*!
@ -559,6 +571,9 @@ void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state)
emit disconnected();
}
if(state == ListeningState){
#ifdef QT_OSX_BLUETOOTH
qCWarning(QT_BT) << "listening socket is not supported by IOBluetooth";
#endif
// TODO: look at this, is this really correct?
// if we're a listening socket we can't handle connects?
if (d->readNotifier) {

View File

@ -52,21 +52,14 @@
QT_BEGIN_NAMESPACE
#ifndef QT_OSX_BLUETOOTH
class QBluetoothSocketBasePrivate;
#else
class QBluetoothSocketPrivate;
#endif
class Q_BLUETOOTH_EXPORT QBluetoothSocket : public QIODevice
{
Q_OBJECT
#ifndef QT_OSX_BLUETOOTH
Q_DECLARE_PRIVATE(QBluetoothSocketBase)
#else
Q_DECLARE_PRIVATE(QBluetoothSocket)
#endif
Q_DECLARE_PRIVATE(QBluetoothSocketBase)
friend class QBluetoothServer;
friend class QBluetoothServerPrivate;
@ -187,11 +180,8 @@ protected:
QBluetoothServiceInfo::Protocol socketType,
QObject *parent = nullptr);
#endif
#ifndef QT_OSX_BLUETOOTH
QBluetoothSocketBasePrivate *d_ptr;
#else
QBluetoothSocketPrivate *d_ptr;
#endif
private:
friend class QLowEnergyControllerPrivateBluez;

View File

@ -43,6 +43,9 @@
// dependencies problem.
#include "qbluetoothsocketbase_p.h"
#include "qbluetoothsocket_osx_p.h"
#include "osx/osxbtrfcommchannel_p.h"
#include "osx/osxbtl2capchannel_p.h"
#include "qbluetoothlocaldevice.h"
#include "qbluetoothdeviceinfo.h"
#include "osx/osxbtutility_p.h"
@ -57,30 +60,294 @@
QT_BEGIN_NAMESPACE
namespace {
using DarwinBluetooth::RetainPolicy;
using ObjCL2CAPChannel = QT_MANGLE_NAMESPACE(OSXBTL2CAPChannel);
using ObjCRFCOMMChannel = QT_MANGLE_NAMESPACE(OSXBTRFCOMMChannel);
} // unnamed namespace
QBluetoothSocketPrivate::QBluetoothSocketPrivate()
: writeChunk(std::numeric_limits<UInt16>::max()),
openMode(QIODevice::NotOpen), // That's what is set in public class' ctors.
state(QBluetoothSocket::UnconnectedState),
socketType(QBluetoothServiceInfo::UnknownProtocol),
socketError(QBluetoothSocket::NoSocketError),
isConnecting(false)
: writeChunk(std::numeric_limits<UInt16>::max())
{
q_ptr = nullptr;
}
QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
{
// "Empty" dtor to make a shared pointer happy (parametrized with
// incomplete type in the header file).
}
bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothServiceInfo::Protocol type)
{
// For now - very simplistic, we don't call it in this file, public class
// only calls it in a ctor, setting the protocol RFCOMM (in case of Android)
// or, indeed, doing, socket-related initialization in BlueZ backend.
Q_ASSERT(socketType == QBluetoothServiceInfo::UnknownProtocol);
socketType = type;
return type != QBluetoothServiceInfo::UnknownProtocol;
}
QString QBluetoothSocketPrivate::localName() const
{
const QBluetoothLocalDevice device;
return device.name();
}
QBluetoothAddress QBluetoothSocketPrivate::localAddress() const
{
const QBluetoothLocalDevice device;
return device.address();
}
quint16 QBluetoothSocketPrivate::localPort() const
{
return 0;
}
QString QBluetoothSocketPrivate::peerName() const
{
QT_BT_MAC_AUTORELEASEPOOL;
NSString *nsName = nil;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
nsName = [rfcommChannel.getAs<ObjCRFCOMMChannel>() peerName];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
nsName = [l2capChannel.getAs<ObjCL2CAPChannel>() peerName];
}
if (nsName)
return QString::fromNSString(nsName);
return QString();
}
QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
{
BluetoothDeviceAddress addr = {};
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
addr = [rfcommChannel.getAs<ObjCRFCOMMChannel>() peerAddress];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
addr = [l2capChannel.getAs<ObjCL2CAPChannel>() peerAddress];
}
return OSXBluetooth::qt_address(&addr);
}
quint16 QBluetoothSocketPrivate::peerPort() const
{
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
return [rfcommChannel.getAs<ObjCRFCOMMChannel>() getChannelID];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
return [l2capChannel.getAs<ObjCL2CAPChannel>() getPSM];
}
return 0;
}
void QBluetoothSocketPrivate::abort()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
"still in connectToService()");
if (socketType == QBluetoothServiceInfo::RfcommProtocol)
rfcommChannel.reset();
else if (socketType == QBluetoothServiceInfo::L2capProtocol)
l2capChannel.reset();
Q_ASSERT(q_ptr);
q_ptr->setSocketState(QBluetoothSocket::UnconnectedState);
emit q_ptr->readChannelFinished();
emit q_ptr->disconnected();
}
void QBluetoothSocketPrivate::close()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
"still in connectToService()");
if (!txBuffer.size())
abort();
}
qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
{
Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
Q_ASSERT_X(maxSize > 0, Q_FUNC_INFO, "invalid data size");
if (state != QBluetoothSocket::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOWRITE);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return -1;
}
// We do not have a real socket API under the hood,
// IOBluetoothL2CAPChannel is buffered (writeAsync).
if (!txBuffer.size())
QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection);
char *dst = txBuffer.reserve(int(maxSize));
std::copy(data, data + maxSize, dst);
return maxSize;
}
qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
{
if (!data)
return 0;
if (state != QBluetoothSocket::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOREAD);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return -1;
}
if (!buffer.isEmpty())
return buffer.read(data, int(maxSize));
return 0;
}
qint64 QBluetoothSocketPrivate::bytesAvailable() const
{
return buffer.size();
}
bool QBluetoothSocketPrivate::canReadLine() const
{
return buffer.canReadLine();
}
qint64 QBluetoothSocketPrivate::bytesToWrite() const
{
return txBuffer.size();
}
bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
QBluetoothSocket::SocketState socketState, QIODevice::OpenMode openMode)
{
Q_UNUSED(socketDescriptor)
Q_UNUSED(socketType)
Q_UNUSED(socketState)
Q_UNUSED(openMode)
qCWarning(QT_BT_OSX) << "setting a socket descriptor is not supported by IOBluetooth";
// Noop on macOS.
return true;
}
void QBluetoothSocketPrivate::connectToServiceHelper(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode openMode)
{
Q_UNUSED(address)
Q_UNUSED(port)
Q_UNUSED(openMode)
}
void QBluetoothSocketPrivate::connectToService(const QBluetoothServiceInfo &service, QIODevice::OpenMode openMode)
{
Q_ASSERT(q_ptr);
OSXBluetooth::qt_test_iobluetooth_runloop();
if (state!= QBluetoothSocket::UnconnectedState && state != QBluetoothSocket::ServiceLookupState) {
qCWarning(QT_BT_OSX) << "called on a busy socket";
errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return;
}
// Report this problem early, potentially avoid device discovery:
if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
socketType = service.socketProtocol();
if (service.protocolServiceMultiplexer() > 0) {
connectToService(service.device().address(),
quint16(service.protocolServiceMultiplexer()),
openMode);
} else if (service.serverChannel() > 0) {
connectToService(service.device().address(),
quint16(service.serverChannel()),
openMode);
} else {
// Try service discovery.
if (service.serviceUuid().isNull()) {
qCWarning(QT_BT_OSX) << "No port, no PSM, and no "
"UUID provided, unable to connect";
return;
}
q_ptr->doDeviceDiscovery(service, openMode);
}
}
void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
QIODevice::OpenMode openMode)
{
Q_ASSERT(q_ptr);
OSXBluetooth::qt_test_iobluetooth_runloop();
// Report this problem early, avoid device discovery:
if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
if (state != QBluetoothSocket::UnconnectedState) {
qCWarning(QT_BT_OSX) << "called on a busy socket";
errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return;
}
QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice);
QBluetoothServiceInfo service;
service.setDevice(device);
service.setServiceUuid(uuid);
q_ptr->doDeviceDiscovery(service, openMode);
}
void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode mode)
{
Q_ASSERT_X(state == QBluetoothSocket::ServiceLookupState
|| state == QBluetoothSocket::UnconnectedState,
Q_ASSERT(q_ptr);
OSXBluetooth::qt_test_iobluetooth_runloop();
if (socketType == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
q_ptr->setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
Q_ASSERT_X(state == QBluetoothSocket::ServiceLookupState || state == QBluetoothSocket::UnconnectedState,
Q_FUNC_INFO, "invalid state");
q_ptr->setOpenMode(mode);
socketError = QBluetoothSocket::NoSocketError;
errorString.clear();
buffer.clear();
@ -100,15 +367,15 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
openMode = mode;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this]);
rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
if (rfcommChannel)
status = [rfcommChannel connectAsyncToDevice:address withChannelID:port];
status = [rfcommChannel.getAs<ObjCRFCOMMChannel>() connectAsyncToDevice:address withChannelID:port];
else
status = kIOReturnNoMemory;
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this]);
l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
if (l2capChannel)
status = [l2capChannel connectAsyncToDevice:address withPSM:port];
status = [l2capChannel.getAs<ObjCL2CAPChannel>() connectAsyncToDevice:address withPSM:port];
else
status = kIOReturnNoMemory;
}
@ -148,84 +415,6 @@ void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address,
}
}
void QBluetoothSocketPrivate::close()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
"still in connectToService()");
if (!txBuffer.size())
abort();
}
void QBluetoothSocketPrivate::abort()
{
// Can never be called while we're in connectToService:
Q_ASSERT_X(!isConnecting, Q_FUNC_INFO, "internal inconsistency - "
"still in connectToService()");
if (socketType == QBluetoothServiceInfo::RfcommProtocol)
rfcommChannel.reset(nil);
else if (socketType == QBluetoothServiceInfo::L2capProtocol)
l2capChannel.reset(nil);
}
quint64 QBluetoothSocketPrivate::bytesAvailable() const
{
return buffer.size();
}
QString QBluetoothSocketPrivate::peerName() const
{
QT_BT_MAC_AUTORELEASEPOOL;
NSString *nsName = nil;
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
nsName = [rfcommChannel peerName];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
nsName = [l2capChannel peerName];
}
if (nsName)
return QString::fromNSString(nsName);
return QString();
}
QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
{
BluetoothDeviceAddress addr = {};
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
addr = [rfcommChannel peerAddress];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
addr = [l2capChannel peerAddress];
}
return OSXBluetooth::qt_address(&addr);
}
quint16 QBluetoothSocketPrivate::peerPort() const
{
if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
if (rfcommChannel)
return [rfcommChannel getChannelID];
} else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
if (l2capChannel)
return [l2capChannel getPSM];
}
return 0;
}
void QBluetoothSocketPrivate::_q_readNotify()
{
// Noop.
}
void QBluetoothSocketPrivate::_q_writeNotify()
{
Q_ASSERT_X(socketType == QBluetoothServiceInfo::L2capProtocol
@ -238,14 +427,14 @@ void QBluetoothSocketPrivate::_q_writeNotify()
if (txBuffer.size()) {
const bool isL2CAP = socketType == QBluetoothServiceInfo::L2capProtocol;
writeChunk.resize(isL2CAP ? std::numeric_limits<UInt16>::max() :
[rfcommChannel getMTU]);
[rfcommChannel.getAs<ObjCRFCOMMChannel>() getMTU]);
const int size = txBuffer.read(writeChunk.data(), writeChunk.size());
IOReturn status = kIOReturnError;
if (!isL2CAP)
status = [rfcommChannel writeAsync:writeChunk.data() length:UInt16(size)];
status = [rfcommChannel.getAs<ObjCRFCOMMChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
else
status = [l2capChannel writeAsync:writeChunk.data() length:UInt16(size)];
status = [l2capChannel.getAs<ObjCL2CAPChannel>() writeAsync:writeChunk.data() length:UInt16(size)];
if (status != kIOReturnSuccess) {
errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
@ -260,21 +449,22 @@ void QBluetoothSocketPrivate::_q_writeNotify()
close();
}
bool QBluetoothSocketPrivate::setChannel(IOBluetoothRFCOMMChannel *channel)
bool QBluetoothSocketPrivate::setRFCOMChannel(void *generic)
{
// A special case "constructor": on OS X we do not have a real listening socket,
// instead a bluetooth server "listens" for channel open notifications and
// creates (if asked by a user later) a "socket" object
// for this connection. This function initializes
// a "socket" from such an external channel (reported by a notification).
auto channel = static_cast<IOBluetoothRFCOMMChannel *>(generic);
// It must be a newborn socket!
Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
&& state == QBluetoothSocket::UnconnectedState && !rfcommChannel && !l2capChannel,
Q_FUNC_INFO, "unexpected socket state");
openMode = QIODevice::ReadWrite;
rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this channel:channel]);
rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this channel:channel],
RetainPolicy::noInitialRetain);
if (rfcommChannel) {// We do not handle errors, up to an external user.
q_ptr->setOpenMode(QIODevice::ReadWrite);
state = QBluetoothSocket::ConnectedState;
@ -284,13 +474,14 @@ bool QBluetoothSocketPrivate::setChannel(IOBluetoothRFCOMMChannel *channel)
return rfcommChannel;
}
bool QBluetoothSocketPrivate::setChannel(IOBluetoothL2CAPChannel *channel)
bool QBluetoothSocketPrivate::setL2CAPChannel(void *generic)
{
// A special case "constructor": on OS X we do not have a real listening socket,
// instead a bluetooth server "listens" for channel open notifications and
// creates (if asked by a user later) a "socket" object
// for this connection. This function initializes
// a "socket" from such an external channel (reported by a notification).
auto channel = static_cast<IOBluetoothL2CAPChannel *>(generic);
// It must be a newborn socket!
Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
@ -298,7 +489,7 @@ bool QBluetoothSocketPrivate::setChannel(IOBluetoothL2CAPChannel *channel)
Q_FUNC_INFO, "unexpected socket state");
openMode = QIODevice::ReadWrite;
l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this channel:channel]);
l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this channel:channel], RetainPolicy::noInitialRetain);
if (l2capChannel) {// We do not handle errors, up to an external user.
q_ptr->setOpenMode(QIODevice::ReadWrite);
state = QBluetoothSocket::ConnectedState;
@ -308,7 +499,6 @@ bool QBluetoothSocketPrivate::setChannel(IOBluetoothL2CAPChannel *channel)
return l2capChannel;
}
void QBluetoothSocketPrivate::setChannelError(IOReturn errorCode)
{
Q_UNUSED(errorCode)
@ -365,7 +555,7 @@ void QBluetoothSocketPrivate::readChannelData(void *data, std::size_t size)
Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
const char *src = static_cast<char *>(data);
char *dst = buffer.reserve(size);
char *dst = buffer.reserve(int(size));
std::copy(src, src + size, dst);
if (!isConnecting) {
@ -379,449 +569,4 @@ void QBluetoothSocketPrivate::writeComplete()
_q_writeNotify();
}
qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
{
Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
Q_ASSERT_X(maxSize > 0, Q_FUNC_INFO, "invalid data size");
if (state != QBluetoothSocket::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOWRITE);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return -1;
}
// We do not have a real socket API under the hood,
// IOBluetoothL2CAPChannel buffered (writeAsync).
if (!txBuffer.size())
QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection);
char *dst = txBuffer.reserve(maxSize);
std::copy(data, data + maxSize, dst);
return maxSize;
}
QBluetoothSocket::QBluetoothSocket(QBluetoothServiceInfo::Protocol socketType, QObject *parent)
: QIODevice(parent),
d_ptr(new QBluetoothSocketPrivate)
{
d_ptr->q_ptr = this;
d_ptr->socketType = socketType;
setOpenMode(NotOpen);
}
QBluetoothSocket::QBluetoothSocket(QObject *parent)
: QIODevice(parent),
d_ptr(new QBluetoothSocketPrivate)
{
d_ptr->q_ptr = this;
setOpenMode(NotOpen);
}
QBluetoothSocket::~QBluetoothSocket()
{
delete d_ptr;
}
bool QBluetoothSocket::isSequential() const
{
return true;
}
qint64 QBluetoothSocket::bytesAvailable() const
{
return QIODevice::bytesAvailable() + d_ptr->bytesAvailable();
}
qint64 QBluetoothSocket::bytesToWrite() const
{
return d_ptr->txBuffer.size();
}
void QBluetoothSocket::connectToService(const QBluetoothServiceInfo &service, OpenMode openMode)
{
OSXBluetooth::qt_test_iobluetooth_runloop();
if (state() != UnconnectedState && state() != ServiceLookupState) {
qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(OperationError);
return;
}
// Report this problem early, potentially avoid device discovery:
if (service.socketProtocol() == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
d_ptr->socketType = service.socketProtocol();
if (service.protocolServiceMultiplexer() > 0) {
d_ptr->connectToService(service.device().address(),
service.protocolServiceMultiplexer(),
openMode);
} else if (service.serverChannel() > 0) {
d_ptr->connectToService(service.device().address(),
service.serverChannel(), openMode);
} else {
// Try service discovery.
if (service.serviceUuid().isNull()) {
qCWarning(QT_BT_OSX) << "No port, no PSM, and no "
"UUID provided, unable to connect";
return;
}
doDeviceDiscovery(service, openMode);
}
}
void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
OpenMode openMode)
{
OSXBluetooth::qt_test_iobluetooth_runloop();
// Report this problem early, avoid device discovery:
if (socketType() == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
if (state() != QBluetoothSocket::UnconnectedState) {
qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(QBluetoothSocket::OperationError);
return;
}
QBluetoothDeviceInfo device(address, QString(), QBluetoothDeviceInfo::MiscellaneousDevice);
QBluetoothServiceInfo service;
service.setDevice(device);
service.setServiceUuid(uuid);
doDeviceDiscovery(service, openMode);
}
void QBluetoothSocket::connectToService(const QBluetoothAddress &address, quint16 port,
OpenMode openMode)
{
OSXBluetooth::qt_test_iobluetooth_runloop();
if (socketType() == QBluetoothServiceInfo::UnknownProtocol) {
qCWarning(QT_BT_OSX) << Q_FUNC_INFO << "cannot connect with 'UnknownProtocol' type";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_NETWORK_ERROR);
setSocketError(QBluetoothSocket::UnsupportedProtocolError);
return;
}
if (state() != QBluetoothSocket::UnconnectedState) {
qCWarning(QT_BT_OSX) << "called on a busy socket";
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_CONNECT_IN_PROGRESS);
setSocketError(OperationError);
return;
}
setOpenMode(openMode);
d_ptr->connectToService(address, port, openMode);
}
QBluetoothServiceInfo::Protocol QBluetoothSocket::socketType() const
{
return d_ptr->socketType;
}
QBluetoothSocket::SocketState QBluetoothSocket::state() const
{
return d_ptr->state;
}
QBluetoothSocket::SocketError QBluetoothSocket::error() const
{
return d_ptr->socketError;
}
QString QBluetoothSocket::errorString() const
{
return d_ptr->errorString;
}
void QBluetoothSocket::setSocketState(QBluetoothSocket::SocketState state)
{
const SocketState oldState = d_ptr->state;
d_ptr->state = state;
if (oldState != d_ptr->state)
emit stateChanged(state);
if (state == ListeningState) {
// We can register for L2CAP/RFCOMM open notifications,
// that's different from 'listen' and is implemented
// in QBluetoothServer.
qCWarning(QT_BT_OSX) << "listening sockets are not supported";
}
}
bool QBluetoothSocket::canReadLine() const
{
return d_ptr->buffer.canReadLine() || QIODevice::canReadLine();
}
void QBluetoothSocket::setSocketError(QBluetoothSocket::SocketError socketError)
{
d_ptr->socketError = socketError;
emit error(socketError);
}
void QBluetoothSocket::doDeviceDiscovery(const QBluetoothServiceInfo &service, OpenMode openMode)
{
OSXBluetooth::qt_test_iobluetooth_runloop();
setSocketState(ServiceLookupState);
if (d_ptr->discoveryAgent)
d_ptr->discoveryAgent->stop();
d_ptr->discoveryAgent.reset(new QBluetoothServiceDiscoveryAgent(this));
d_ptr->discoveryAgent->setRemoteAddress(service.device().address());
connect(d_ptr->discoveryAgent.data(), SIGNAL(serviceDiscovered(QBluetoothServiceInfo)),
this, SLOT(serviceDiscovered(QBluetoothServiceInfo)));
connect(d_ptr->discoveryAgent.data(), SIGNAL(finished()),
this, SLOT(discoveryFinished()));
d_ptr->openMode = openMode;
if (!service.serviceUuid().isNull())
d_ptr->discoveryAgent->setUuidFilter(service.serviceUuid());
if (!service.serviceClassUuids().isEmpty())
d_ptr->discoveryAgent->setUuidFilter(service.serviceClassUuids());
Q_ASSERT_X(!d_ptr->discoveryAgent->uuidFilter().isEmpty(), Q_FUNC_INFO,
"invalid service info");
d_ptr->discoveryAgent->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
}
void QBluetoothSocket::serviceDiscovered(const QBluetoothServiceInfo &service)
{
if (service.protocolServiceMultiplexer() != 0 || service.serverChannel() != 0) {
d_ptr->discoveryAgent->stop();
connectToService(service, d_ptr->openMode);
}
}
void QBluetoothSocket::discoveryFinished()
{
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_SERVICE_NOT_FOUND);
setSocketState(UnconnectedState);
setSocketError(ServiceNotFoundError);
}
void QBluetoothSocket::abort()
{
if (state() == UnconnectedState)
return;
setOpenMode(NotOpen);
if (state() == ServiceLookupState && d_ptr->discoveryAgent) {
d_ptr->discoveryAgent->disconnect();
d_ptr->discoveryAgent->stop();
d_ptr->discoveryAgent.reset();
}
setSocketState(QBluetoothSocket::ClosingState);
d_ptr->abort();
setSocketState(QBluetoothSocket::UnconnectedState);
emit readChannelFinished();
emit disconnected();
}
void QBluetoothSocket::disconnectFromService()
{
close();
}
QString QBluetoothSocket::localName() const
{
const QBluetoothLocalDevice device;
return device.name();
}
QBluetoothAddress QBluetoothSocket::localAddress() const
{
const QBluetoothLocalDevice device;
return device.address();
}
quint16 QBluetoothSocket::localPort() const
{
return 0;
}
QString QBluetoothSocket::peerName() const
{
return d_ptr->peerName();
}
QBluetoothAddress QBluetoothSocket::peerAddress() const
{
return d_ptr->peerAddress();
}
quint16 QBluetoothSocket::peerPort() const
{
return d_ptr->peerPort();
}
qint64 QBluetoothSocket::writeData(const char *data, qint64 maxSize)
{
if (!data || maxSize <= 0) {
d_ptr->errorString = QCoreApplication::translate(SOCKET, SOC_INVAL_DATASIZE);
setSocketError(QBluetoothSocket::OperationError);
return -1;
}
return d_ptr->writeData(data, maxSize);
}
qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
{
if (state != QBluetoothSocket::ConnectedState) {
errorString = QCoreApplication::translate(SOCKET, SOC_NOREAD);
q_ptr->setSocketError(QBluetoothSocket::OperationError);
return -1;
}
if (!buffer.isEmpty())
return buffer.read(data, maxSize);
return 0;
}
qint64 QBluetoothSocket::readData(char *data, qint64 maxSize)
{
return d_ptr->readData(data, maxSize);
}
void QBluetoothSocket::close()
{
if (state() == UnconnectedState)
return;
setOpenMode(NotOpen);
if (state() == ServiceLookupState && d_ptr->discoveryAgent) {
d_ptr->discoveryAgent->disconnect();
d_ptr->discoveryAgent->stop();
d_ptr->discoveryAgent.reset();
}
setSocketState(ClosingState);
d_ptr->close();
setSocketState(UnconnectedState);
emit readChannelFinished();
emit disconnected();
}
bool QBluetoothSocket::setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
SocketState socketState, OpenMode openMode)
{
Q_UNUSED(socketDescriptor)
Q_UNUSED(socketType)
Q_UNUSED(socketState)
Q_UNUSED(openMode)
// Noop on OS X.
return true;
}
int QBluetoothSocket::socketDescriptor() const
{
return -1;
}
/* not supported on OS X */
void QBluetoothSocket::setPreferredSecurityFlags(QBluetooth::SecurityFlags flags)
{
Q_UNUSED(flags)
}
/* not supported on OS X - platform always uses encryption */
QBluetooth::SecurityFlags QBluetoothSocket::preferredSecurityFlags() const
{
return QBluetooth::Secure;
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, QBluetoothSocket::SocketError error)
{
switch (error) {
case QBluetoothSocket::UnknownSocketError:
debug << "QBluetoothSocket::UnknownSocketError";
break;
case QBluetoothSocket::HostNotFoundError:
debug << "QBluetoothSocket::HostNotFoundError";
break;
case QBluetoothSocket::RemoteHostClosedError:
debug << "QBluetoothSocket::RemoteHostClosedError";
break;
case QBluetoothSocket::ServiceNotFoundError:
debug << "QBluetoothSocket::ServiceNotFoundError";
break;
case QBluetoothSocket::NetworkError:
debug << "QBluetoothSocket::NetworkError";
break;
case QBluetoothSocket::UnsupportedProtocolError:
debug << "QBluetoothSocket::UnsupportedProtocolError";
break;
default:
debug << "QBluetoothSocket::SocketError(" << (int)error << ")";
}
return debug;
}
QDebug operator<<(QDebug debug, QBluetoothSocket::SocketState state)
{
switch (state) {
case QBluetoothSocket::UnconnectedState:
debug << "QBluetoothSocket::UnconnectedState";
break;
case QBluetoothSocket::ConnectingState:
debug << "QBluetoothSocket::ConnectingState";
break;
case QBluetoothSocket::ConnectedState:
debug << "QBluetoothSocket::ConnectedState";
break;
case QBluetoothSocket::BoundState:
debug << "QBluetoothSocket::BoundState";
break;
case QBluetoothSocket::ClosingState:
debug << "QBluetoothSocket::ClosingState";
break;
case QBluetoothSocket::ListeningState:
debug << "QBluetoothSocket::ListeningState";
break;
case QBluetoothSocket::ServiceLookupState:
debug << "QBluetoothSocket::ServiceLookupState";
break;
default:
debug << "QBluetoothSocket::SocketState(" << (int)state << ")";
}
return debug;
}
#endif // QT_NO_DEBUG_STREAM
#include "moc_qbluetoothsocket.cpp"
QT_END_NAMESPACE

View File

@ -53,12 +53,11 @@
#ifdef QT_OSX_BLUETOOTH
#include "osx/osxbtchanneldelegate_p.h"
#include "osx/osxbtrfcommchannel_p.h"
#include "osx/osxbtl2capchannel_p.h"
#include "qbluetoothsocketbase_p.h"
#include "qbluetoothserviceinfo.h"
#include "osx/osxbtutility_p.h"
#include "osx/btdelegates_p.h"
#include "qbluetoothsocket.h"
#include "osx/btraii_p.h"
#ifndef QPRIVATELINEARBUFFER_BUFFERSIZE
#define QPRIVATELINEARBUFFER_BUFFERSIZE Q_INT64_C(16384)
@ -74,14 +73,11 @@
#include <QtCore/qstring.h>
#include <QtCore/qvector.h>
@class IOBluetoothRFCOMMChannel;
@class IOBluetoothL2CAPChannel;
QT_BEGIN_NAMESPACE
class QBluetoothAddress;
class QBluetoothSocketPrivate : public QBluetoothSocketBasePrivate, public OSXBluetooth::ChannelDelegate
class QBluetoothSocketPrivate : public QBluetoothSocketBasePrivate, public DarwinBluetooth::ChannelDelegate
{
friend class QBluetoothSocket;
friend class QBluetoothServer;
@ -90,25 +86,47 @@ public:
QBluetoothSocketPrivate();
~QBluetoothSocketPrivate();
//
bool ensureNativeSocket(QBluetoothServiceInfo::Protocol type) override;
QString localName() const override;
QBluetoothAddress localAddress() const override;
quint16 localPort() const override;
QString peerName() const override;
QBluetoothAddress peerAddress() const override;
quint16 peerPort() const override;
void abort() override;
void close() override;
qint64 writeData(const char *data, qint64 maxSize) override;
qint64 readData(char *data, qint64 maxSize) override;
qint64 bytesAvailable() const override;
bool canReadLine() const override;
qint64 bytesToWrite() const override;
bool setSocketDescriptor(int socketDescriptor, QBluetoothServiceInfo::Protocol socketType,
QBluetoothSocket::SocketState socketState,
QBluetoothSocket::OpenMode openMode) override;
void connectToServiceHelper(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode openMode) override;
void connectToService(const QBluetoothServiceInfo &service,
QIODevice::OpenMode openMode) override;
void connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid,
QIODevice::OpenMode openMode) override;
void connectToService(const QBluetoothAddress &address, quint16 port,
QIODevice::OpenMode openMode);
QIODevice::OpenMode openMode) override;
void close();
void abort();
quint64 bytesAvailable() const;
QString peerName() const;
QBluetoothAddress peerAddress() const;
quint16 peerPort() const;
void _q_readNotify();
void _q_writeNotify() override;
void _q_writeNotify();
private:
// Create a socket from an external source (without connectToService).
bool setChannel(IOBluetoothRFCOMMChannel *channel);
bool setChannel(IOBluetoothL2CAPChannel *channel);
bool setRFCOMChannel(void *channel);
bool setL2CAPChannel(void *channel);
// L2CAP and RFCOMM delegate
void setChannelError(IOReturn errorCode) override;
@ -117,33 +135,15 @@ private:
void readChannelData(void *data, std::size_t size) override;
void writeComplete() override;
qint64 writeData(const char *data, qint64 maxSize);
qint64 readData(char *data, qint64 maxSize);
QScopedPointer<QBluetoothServiceDiscoveryAgent> discoveryAgent;
QPrivateLinearBuffer buffer;
QPrivateLinearBuffer txBuffer;
QVector<char> writeChunk;
// Probably, not needed.
QIODevice::OpenMode openMode;
QBluetoothSocket::SocketState state;
QBluetoothServiceInfo::Protocol socketType;
QBluetoothSocket::SocketError socketError;
QString errorString;
typedef QT_MANGLE_NAMESPACE(OSXBTL2CAPChannel) ObjCL2CAPChannel;
typedef OSXBluetooth::ObjCScopedPointer<ObjCL2CAPChannel> L2CAPChannel;
using L2CAPChannel = DarwinBluetooth::ScopedPointer;
L2CAPChannel l2capChannel;
typedef QT_MANGLE_NAMESPACE(OSXBTRFCOMMChannel) ObjCRFCOMMChannel;
typedef OSXBluetooth::ObjCScopedPointer<ObjCRFCOMMChannel> RFCOMMChannel;
using RFCOMMChannel = L2CAPChannel;
RFCOMMChannel rfcommChannel;
// A trick to deal with channel open too fast (synchronously).
bool isConnecting;
bool isConnecting = false;
};
QT_END_NAMESPACE

View File

@ -89,7 +89,6 @@ QT_FORWARD_DECLARE_CLASS(QBluetoothServiceDiscoveryAgent)
QT_BEGIN_NAMESPACE
#ifndef QT_OSX_BLUETOOTH
class QBluetoothSocketBasePrivate : public QObject
{
Q_OBJECT
@ -198,26 +197,6 @@ static inline quint64 convertAddress(const quint8 (&from)[6], quint64 *to = null
return result;
}
#else // QT_OSX_BLUETOOTH
// QBluetoothSocketPrivate on macOS can not contain
// Q_OBJECT (moc does not parse Objective-C syntax).
// But QBluetoothSocket still requires QMetaObject::invokeMethod
// to work. Here's the trick:
class QBluetoothSocketBasePrivate : public QObject
{
// The most important part of it:
Q_OBJECT
public slots:
virtual void _q_writeNotify() = 0;
protected:
Q_DECLARE_PUBLIC(QBluetoothSocket)
QBluetoothSocket *q_ptr;
};
#endif // QT_OSX_BLUETOOTH
QT_END_NAMESPACE
#endif // QBLUETOOTHSOCKETBASE_P_H