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:
parent
de3e8e85cc
commit
c1286c3a34
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue