summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothsocket_osx.mm
diff options
context:
space:
mode:
authorTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-09-10 12:54:18 +0200
committerTimur Pocheptsov <Timur.Pocheptsov@digia.com>2014-09-26 15:41:09 +0200
commitd1d77c8210ecf7a89a81dad69d21b91e06bf129e (patch)
tree94d7b91c64478720eee9c9afd82acfc496c383e1 /src/bluetooth/qbluetoothsocket_osx.mm
parentc1aabdba2e839ba525a4918eebfbf6fbbe96d34d (diff)
Port QBluetoothSocket to OS X.
Implement QBluetoothSocket using IOBluetooth framework on OS X (will implement Qt's API as close as possible with a given Apple's API). Update 0: add (empty for now) delegate classes (L2CAP/RFCOMM). Update 1: add service discovery (called doDeviceDiscovery though). Update 2: implement the public class' logic (QBluetoothSocket, connectToService). Update 3: more public logic implemented (since it's easy :) ) Update 4: L2CAP delegate - initial logic. Update 5: connectToService - L2CAP "socket". Update 6: fix pivate header files. Update 7: fix dependency after the previous patch was merged. Update 8: writeData - initial version for L2CAP. Update 9: since RFCOM/L2CAP delegates have the same interface, no need in duplicating the same class - add a "generic" ChannelDelegate instead. Update 10: more RFCOMM logic. Update 11: function to build a service description from QBluetoothServiceInfo (to be registered on SDP server). Update 12: QBluetoothSocket::close/abort. Update 13: Create a dictioinary out of QBluetoothServiceInfo to register a service. Update 14: Add service registration. Update 15: Convert attributes (sequences and 'scalars') from QBluetoothServiceInfor into NSDictionary. Update 16: Update QBluetoothServiceInfo with a real PSM/ChannelID after a service was registered. Update 17: Move a private class (bluetooth socket) into the separate private header file (to make it visible for bluetooth_server_osx) Update 18: Add an interface to create a bluetooth socket (private class) from a channel, reported by a notification (found by a listening server). Update 19: Fix an invalid assert - any state (Inactive/ServiceDiscovery/DeviceDiscovery) is possible, not only Inactive. Implement the missing 'readData' and 'writeData' for RFCOMM. Set SDP query as non-active after query finished. Temporary (!) workaround - can not invokeMethod on a private socket (d_ptr). Update 20: When creating a socket wrapper from an incoming notification/channel, set: socket type + channel's delegate. Change-Id: Idd6d5478597206ed759f49e282baed948d105ddf Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
Diffstat (limited to 'src/bluetooth/qbluetoothsocket_osx.mm')
-rw-r--r--src/bluetooth/qbluetoothsocket_osx.mm735
1 files changed, 735 insertions, 0 deletions
diff --git a/src/bluetooth/qbluetoothsocket_osx.mm b/src/bluetooth/qbluetoothsocket_osx.mm
new file mode 100644
index 00000000..d248d85a
--- /dev/null
+++ b/src/bluetooth/qbluetoothsocket_osx.mm
@@ -0,0 +1,735 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtBluetooth module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothservicediscoveryagent.h"
+#include "qbluetoothsocket_osx_p.h"
+#include "qbluetoothlocaldevice.h"
+#include "qbluetoothdeviceinfo.h"
+#include "osx/osxbtutility_p.h"
+#include "qbluetoothsocket.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmetaobject.h>
+
+#include <algorithm>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+QBluetoothSocketPrivate::QBluetoothSocketPrivate()
+ : q_ptr(Q_NULLPTR),
+ writeChunk(std::numeric_limits<UInt16>::max()),
+ openMode(QIODevice::ReadWrite), // That's what is set in public class' ctors.
+ state(QBluetoothSocket::UnconnectedState),
+ socketType(QBluetoothServiceInfo::UnknownProtocol),
+ socketError(QBluetoothSocket::NoSocketError),
+ isConnecting(false)
+{
+}
+
+QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
+{
+ // "Empty" dtor to make a shared pointer happy (parametrized with
+ // incomplete type in the header file).
+}
+
+void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, quint16 port,
+ QIODevice::OpenMode openMode)
+{
+ // We have readwrite channels with IOBluetooth's channels.
+ Q_UNUSED(openMode)
+
+ Q_ASSERT_X(state == QBluetoothSocket::ServiceLookupState
+ || state == QBluetoothSocket::UnconnectedState,
+ "connectToService()", "invalid state");
+
+ socketError = QBluetoothSocket::NoSocketError;
+ errorString.clear();
+ buffer.clear();
+ txBuffer.clear();
+
+ IOReturn status = kIOReturnError;
+ // Set socket state on q_ptr will emit a signal,
+ // we'd like to avoid any signal until this function completes.
+ const QBluetoothSocket::SocketState oldState = state;
+ // To prevent other connectToService calls (from QBluetoothSocket):
+ // and also avoid signals in delegate callbacks.
+ state = QBluetoothSocket::ConnectingState;
+ // We're still inside this function:
+ isConnecting = true;
+
+ if (socketType == QBluetoothServiceInfo::RfcommProtocol) {
+ rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this]);
+ if (rfcommChannel)
+ status = [rfcommChannel connectAsyncToDevice:address withChannelID:port];
+ else
+ status = kIOReturnNoMemory;
+ } else if (socketType == QBluetoothServiceInfo::L2capProtocol) {
+ l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this]);
+ if (l2capChannel)
+ status = [l2capChannel connectAsyncToDevice:address withPSM:port];
+ else
+ status = kIOReturnNoMemory;
+ }
+
+ // We're probably still connecting, but at least are leaving this function:
+ isConnecting = false;
+
+ // QBluetoothSocket will change the state and also emit
+ // a signal later if required.
+
+ if (status != kIOReturnSuccess) {// That's a simple case.
+ state = oldState;
+ errorString = OSXBluetooth::qt_error_string(status);
+ q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+
+ if (state == QBluetoothSocket::ConnectedState
+ && socketError == QBluetoothSocket::NoSocketError) {
+ //We got it before switched into connecting state!
+ state = oldState;
+ q_ptr->setSocketState(QBluetoothSocket::ConnectedState);
+ emit q_ptr->connected();
+ // TODO: check if we ... already have some data to read
+ // and emit a signal!
+ } else if (socketError == QBluetoothSocket::NoSocketError) {
+ state = oldState;
+ q_ptr->setSocketState(QBluetoothSocket::ConnectingState);
+ } else {
+ state = oldState;
+ q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ }
+}
+
+void QBluetoothSocketPrivate::close()
+{
+ // Can never be called while we're in connectToService:
+ Q_ASSERT_X(!isConnecting, "close()", "internal inconsistency - "
+ "still in connectToService()");
+
+ // Only go through closing if the socket was fully opened
+ if (state == QBluetoothSocket::ConnectedState)
+ q_ptr->setSocketState(QBluetoothSocket::ClosingState);
+
+ if (!txBuffer.size())
+ abort();
+}
+
+void QBluetoothSocketPrivate::abort()
+{
+ // Can never be called while we're in connectToService:
+ Q_ASSERT_X(!isConnecting, "abort()", "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
+ || socketType == QBluetoothServiceInfo::RfcommProtocol,
+ "_q_writeNotify()", "invalid socket type");
+ Q_ASSERT_X(l2capChannel || rfcommChannel, "_q_writeNotify()",
+ "invalid socket (no open channel)");
+ Q_ASSERT_X(q_ptr, "_q_writeNotify()", "invalid q_ptr (null)");
+
+ if (txBuffer.size()) {
+ const bool isL2CAP = socketType == QBluetoothServiceInfo::L2capProtocol;
+ writeChunk.resize(isL2CAP ? std::numeric_limits<UInt16>::max() :
+ [rfcommChannel getMTU]);
+
+ const int size = txBuffer.read(writeChunk.data(), writeChunk.size());
+ IOReturn status = kIOReturnError;
+ if (!isL2CAP)
+ status = [rfcommChannel writeAsync:writeChunk.data() length:UInt16(size)];
+ else
+ status = [l2capChannel writeAsync:writeChunk.data() length:UInt16(size)];
+
+ if (status != kIOReturnSuccess) {
+ errorString = QBluetoothSocket::tr("Network Error");
+ q_ptr->setSocketError(QBluetoothSocket::NetworkError);
+ return;
+ } else {
+ emit q_ptr->bytesWritten(size);
+ }
+ }
+
+ if (!txBuffer.size() && state == QBluetoothSocket::ClosingState)
+ close();
+}
+
+bool QBluetoothSocketPrivate::setChannel(IOBluetoothRFCOMMChannel *channel)
+{
+ // 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).
+
+ // It must be a newborn socket!
+ Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
+ && state == QBluetoothSocket::UnconnectedState && !rfcommChannel && !l2capChannel,
+ "QBluetoothSocketPrivate::setChannel()", "unexpected socket state");
+
+ rfcommChannel.reset([[ObjCRFCOMMChannel alloc] initWithDelegate:this channel:channel]);
+ if (rfcommChannel) {// We do not handle errors, up to an external user.
+ state = QBluetoothSocket::ConnectedState;
+ socketType = QBluetoothServiceInfo::RfcommProtocol;
+ }
+
+ return rfcommChannel;
+}
+
+bool QBluetoothSocketPrivate::setChannel(IOBluetoothL2CAPChannel *channel)
+{
+ // 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).
+
+ // It must be a newborn socket!
+ Q_ASSERT_X(socketError == QBluetoothSocket::NoSocketError
+ && state == QBluetoothSocket::UnconnectedState && !l2capChannel && !rfcommChannel,
+ "QBluetoothSocketPrivate::setChannel()", "unexpected socket state");
+
+ l2capChannel.reset([[ObjCL2CAPChannel alloc] initWithDelegate:this channel:channel]);
+ if (l2capChannel) {// We do not handle errors, up to an external user.
+ state = QBluetoothSocket::ConnectedState;
+ socketType = QBluetoothServiceInfo::L2capProtocol;
+ }
+
+ return l2capChannel;
+}
+
+
+void QBluetoothSocketPrivate::setChannelError(IOReturn errorCode)
+{
+ Q_UNUSED(errorCode)
+
+ Q_ASSERT_X(q_ptr, "setChannelError()", "invalid q_ptr (null)");
+
+ if (isConnecting) {
+ // The delegate's method was called while we are still in
+ // connectToService ... will emit a moment later.
+ socketError = QBluetoothSocket::UnknownSocketError;
+ } else {
+ q_ptr->setSocketError(QBluetoothSocket::UnknownSocketError);
+ }
+}
+
+void QBluetoothSocketPrivate::channelOpenComplete()
+{
+ Q_ASSERT_X(q_ptr, "channelOpenComplete()", "invalid q_ptr (null)");
+
+ if (!isConnecting) {
+ q_ptr->setSocketState(QBluetoothSocket::ConnectedState);
+ emit q_ptr->connected();
+ } else {
+ state = QBluetoothSocket::ConnectedState;
+ // We are still in connectToService, it'll care
+ // about signals!
+ }
+}
+
+void QBluetoothSocketPrivate::readChannelData(void *data, std::size_t size)
+{
+ Q_ASSERT_X(data, "readChannelData()", "invalid data (null)");
+ Q_ASSERT_X(size, "readChannelData()", "invalid data size (0)");
+ Q_ASSERT_X(q_ptr, "readChannelData()", "invalid q_ptr (null)");
+
+ const char *src = static_cast<char *>(data);
+ char *dst = buffer.reserve(size);
+ std::copy(src, src + size, dst);
+
+ if (!isConnecting) {
+ // If we're still in connectToService, do not emit.
+ emit q_ptr->readyRead();
+ } // else connectToService must check and emit readyRead!
+}
+
+void QBluetoothSocketPrivate::writeComplete()
+{
+ _q_writeNotify();
+}
+
+qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
+{
+ Q_ASSERT_X(data, "writeData()", "invalid data (null)");
+ Q_ASSERT_X(maxSize > 0, "writeData()", "invalid data size");
+
+ if (state != QBluetoothSocket::ConnectedState) {
+ errorString = tr("Cannot write while not connected");
+ q_ptr->setSocketError(QBluetoothSocket::OperationError);
+ return -1;
+ }
+
+ // We do not have a real socket API under the hood,
+ // IOBluetoothL2CAPChannel buffered (writeAsync).
+
+ const bool isEmpty = !txBuffer.size();
+ if (!txBuffer.size())// TODO: find a workaround for this.
+ ;//QMetaObject::invokeMethod(this, "_q_writeNotify", Qt::QueuedConnection);
+
+ char *dst = txBuffer.reserve(maxSize);
+ std::copy(data, data + maxSize, dst);
+
+ if (isEmpty)
+ _q_writeNotify();
+
+ 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(QIODevice::ReadWrite);
+}
+
+QBluetoothSocket::QBluetoothSocket(QObject *parent)
+ : QIODevice(parent),
+ d_ptr(new QBluetoothSocketPrivate)
+{
+ d_ptr->q_ptr = this;
+ setOpenMode(QIODevice::ReadWrite);
+}
+
+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)
+{
+ if (state() != UnconnectedState && state() != ServiceLookupState) {
+ qCWarning(QT_BT_OSX) << "QBluetoothSocket::connectToService() called on a busy socket";
+ d_ptr->errorString = tr("Trying to connect while connection is in progress");
+ setSocketError(OperationError);
+ return;
+ }
+
+ setOpenMode(openMode);
+
+ 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)
+{
+ if (state() != QBluetoothSocket::UnconnectedState) {
+ qCWarning(QT_BT_OSX) << "QBluetoothSocket::connectToService() called on a busy socket";
+ d_ptr->errorString = tr("Trying to connect while connection is 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)
+{
+ if (state() != QBluetoothSocket::UnconnectedState) {
+ qCWarning(QT_BT_OSX) << "QBluetoothSocket::connectToService() called on a busy socket";
+ d_ptr->errorString = tr("Trying to connect while connection is 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) << "QBluetoothSocket::setSocketState(), "
+ "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)
+{
+ 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(), "doDeviceDiscovery()",
+ "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 = tr("Service cannot be found");
+ setSocketState(UnconnectedState);
+ setSocketError(ServiceNotFoundError);
+}
+
+void QBluetoothSocket::abort()
+{
+ if (state() == UnconnectedState)
+ return;
+
+ d_ptr->abort();
+
+ setSocketState(QBluetoothSocket::UnconnectedState);
+ 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 = tr("Invalid data/data size");
+ setSocketError(QBluetoothSocket::OperationError);
+ return -1;
+ }
+
+ return d_ptr->writeData(data, maxSize);
+}
+
+qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
+{
+ if (state != QBluetoothSocket::ConnectedState) {
+ errorString = tr("Cannot read while not connected");
+ 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;
+
+ setSocketState(ClosingState);
+
+ d_ptr->close();
+
+ setSocketState(UnconnectedState);
+ 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;
+}
+
+#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::ServiceNotFoundError:
+ debug << "QBluetoothSocket::ServiceNotFoundError";
+ break;
+ case QBluetoothSocket::NetworkError:
+ debug << "QBluetoothSocket::NetworkError";
+ 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