summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothsocket_symbian.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bluetooth/qbluetoothsocket_symbian.cpp')
-rw-r--r--src/bluetooth/qbluetoothsocket_symbian.cpp591
1 files changed, 591 insertions, 0 deletions
diff --git a/src/bluetooth/qbluetoothsocket_symbian.cpp b/src/bluetooth/qbluetoothsocket_symbian.cpp
new file mode 100644
index 00000000..d17a6f5c
--- /dev/null
+++ b/src/bluetooth/qbluetoothsocket_symbian.cpp
@@ -0,0 +1,591 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbluetoothsocket_p.h"
+#include "qbluetoothsocket.h"
+#include "qbluetoothlocaldevice_p.h"
+#include "symbian/utils_symbian_p.h"
+
+#include <QCoreApplication>
+
+#include <QDebug>
+
+#include <limits.h>
+#include <bt_sock.h>
+#include <es_sock.h>
+
+Q_GLOBAL_STATIC(QSocketServerPrivate, getSocketServer)
+
+QBluetoothSocketPrivate::QBluetoothSocketPrivate()
+ : socket(0)
+ , socketType(QBluetoothSocket::UnknownSocketType)
+ , state(QBluetoothSocket::UnconnectedState)
+ , readNotifier(0)
+ , connectWriteNotifier(0)
+ , discoveryAgent(0)
+ , iSocket(0)
+ , rxDescriptor(0, 0)
+ , txDescriptor(0, 0)
+ , recvMTU(0)
+ , txMTU(0)
+ , transmitting(false)
+ , writeSize(0)
+{
+}
+
+QBluetoothSocketPrivate::~QBluetoothSocketPrivate()
+{
+ delete iSocket;
+}
+
+void QBluetoothSocketPrivate::connectToService(const QBluetoothAddress &address, quint16 port, QIODevice::OpenMode openMode)
+{
+ Q_Q(QBluetoothSocket);
+ Q_UNUSED(openMode);
+
+ TBTSockAddr a;
+
+ if(address.isNull())
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ return;
+ }
+ TInt err = KErrNone;
+ a.SetPort(port);
+ // Trap TBTDevAddr constructor which may panic
+ TRAP(err, a.SetBTAddr(TBTDevAddr(address.toUInt64())));
+ if(err == KErrNone)
+ err = iSocket->Connect(a);
+ if (err == KErrNone) {
+ q->setSocketState(QBluetoothSocket::ConnectingState);
+ } else {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ }
+}
+
+bool QBluetoothSocketPrivate::ensureNativeSocket(QBluetoothSocket::SocketType type)
+{
+ if (iSocket) {
+ if (socketType == type)
+ {
+ return true;
+ }
+ else
+ {
+ delete iSocket;
+ iSocket = 0;
+ }
+ }
+
+ socketType = type;
+
+ switch (type) {
+ case QBluetoothSocket::L2capSocket: {
+ TRAPD(err, iSocket = CBluetoothSocket::NewL(*this, getSocketServer()->socketServer, _L("L2CAP")));
+ Q_UNUSED(err);
+ break;
+ }
+ case QBluetoothSocket::RfcommSocket: {
+ TRAPD(err, iSocket = CBluetoothSocket::NewL(*this, getSocketServer()->socketServer, _L("RFCOMM")));
+ Q_UNUSED(err);
+ break;
+ }
+ default:
+ iSocket = 0;
+ }
+
+ if (iSocket)
+ return true;
+ else
+ return false;
+}
+
+bool QBluetoothSocketPrivate::ensureBlankNativeSocket(QBluetoothSocket::SocketType type)
+{
+ if (iSocket) {
+ delete iSocket;
+ iSocket = 0;
+ }
+ socketType = type;
+ TRAPD(err, iSocket = CBluetoothSocket::NewL(*this, getSocketServer()->socketServer));
+ Q_UNUSED(err);
+ if(iSocket)
+ return true;
+ else
+ return false;
+}
+
+void QBluetoothSocketPrivate::startReceive()
+{
+ Q_Q(QBluetoothSocket);
+ if (!iSocket || state != QBluetoothSocket::ConnectedState) {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ TInt err = iSocket->GetOpt(KL2CAPInboundMTU, KSolBtL2CAP, recvMTU);
+ if(err != KErrNone)
+ {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ err = iSocket->GetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, txMTU);
+ if(err != KErrNone)
+ {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ bufPtr = buffer.reserve(recvMTU);
+ // enable automatic power saving mode
+ iSocket->SetAutomaticSniffMode(ETrue);
+ // enable link down and link error notifications for proper disconnection
+ err = iSocket->ActivateBasebandEventNotifier(ENotifyPhysicalLinkDown |ENotifyPhysicalLinkError );
+ if(err != KErrNone)
+ {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ receive();
+}
+
+void QBluetoothSocketPrivate::receive()
+{
+ Q_Q(QBluetoothSocket);
+ TInt err = KErrNone;
+
+ if(!iSocket || bufPtr == 0 || recvMTU == 0 || socketType < 0 || state != QBluetoothSocket::ConnectedState)
+ {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+
+ TRAP(err, rxDescriptor.Set(reinterpret_cast<unsigned char *>(bufPtr), 0,recvMTU));
+ if(err != KErrNone)
+ {
+ emit q->error(QBluetoothSocket::UnknownSocketError);
+ return;
+ }
+ if (socketType == QBluetoothSocket::RfcommSocket) {
+ // cancel any pending recv operation
+ iSocket->CancelRecv();
+ err = iSocket->RecvOneOrMore(rxDescriptor, 0, rxLength);
+ if (err != KErrNone) {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ }
+ } else if (socketType == QBluetoothSocket::L2capSocket) {
+ // cancel any pending read operation
+ iSocket->CancelRead();
+ err = iSocket->Read(rxDescriptor);
+ if (err != KErrNone) {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ }
+ }
+ }
+
+void QBluetoothSocketPrivate::HandleAcceptCompleteL(TInt aErr)
+{
+ qDebug() << __PRETTY_FUNCTION__ << ">> aErr=" << aErr;
+ Q_Q(QBluetoothSocket);
+ if(aErr != KErrNone)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ return;
+ }
+ emit q->connected();
+}
+
+void QBluetoothSocketPrivate::HandleActivateBasebandEventNotifierCompleteL(TInt aErr, TBTBasebandEventNotification& aEventNotification)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+ Q_Q(QBluetoothSocket);
+ if(aErr != KErrNone)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ }
+ if(ENotifyPhysicalLinkDown & aEventNotification.EventType() || ENotifyPhysicalLinkError & aEventNotification.EventType())
+ {
+ q->setSocketState(QBluetoothSocket::ClosingState);
+ emit q->disconnected();
+ }
+}
+
+void QBluetoothSocketPrivate::HandleConnectCompleteL(TInt aErr)
+{
+ qDebug() << __PRETTY_FUNCTION__ << ">> aErr=" << aErr;
+ Q_Q(QBluetoothSocket);
+ if (aErr == KErrNone) {
+ q->setSocketState(QBluetoothSocket::ConnectedState);
+
+ emit q->connected();
+
+ startReceive();
+ } else {
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+
+ switch (aErr) {
+ case KErrCouldNotConnect:
+ socketError = QBluetoothSocket::ConnectionRefusedError;
+ break;
+ default:
+ qDebug() << __PRETTY_FUNCTION__ << aErr;
+ socketError = QBluetoothSocket::UnknownSocketError;
+ }
+ emit q->error(socketError);
+ }
+}
+
+void QBluetoothSocketPrivate::HandleIoctlCompleteL(TInt aErr)
+{
+ qDebug() << __PRETTY_FUNCTION__;
+ Q_Q(QBluetoothSocket);
+ if(aErr != KErrNone)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ }
+}
+
+void QBluetoothSocketPrivate::HandleReceiveCompleteL(TInt aErr)
+{
+ Q_Q(QBluetoothSocket);
+ if (aErr == KErrNone) {
+ if(buffer.size() == 0)
+ bufPtr = buffer.reserve(recvMTU);
+ if(bufPtr <= 0)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ return;
+ }
+ buffer.chop(recvMTU - rxDescriptor.Length());
+ emit q->readyRead();
+ } else {
+ // ignore disconnection it will be handled in baseband notification
+ if(aErr != KErrDisconnected)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ writeSize = 0;
+ emit q->error(socketError);
+ }
+ }
+}
+
+void QBluetoothSocketPrivate::HandleSendCompleteL(TInt aErr)
+{
+ Q_Q(QBluetoothSocket);
+ transmitting = false;
+ if (aErr == KErrNone) {
+ txArray.remove(0, writeSize);
+ emit q->bytesWritten(writeSize);
+ if (state == QBluetoothSocket::ClosingState)
+ {
+ writeSize = 0;
+ q->close();
+ }
+ else
+ {
+ if(!tryToSend())
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ writeSize = 0;
+ emit q->error(socketError);
+ }
+ }
+ } else {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ writeSize = 0;
+ emit q->error(socketError);
+ }
+}
+
+void QBluetoothSocketPrivate::HandleShutdownCompleteL(TInt aErr)
+{
+ Q_Q(QBluetoothSocket);
+ // It doesn't matter if aErr is KErrNone or something else
+ // we consider the socket to be closed.
+ q->setSocketState(QBluetoothSocket::UnconnectedState);
+ transmitting = false;
+ writeSize = 0;
+ iSocket->AsyncDelete();
+ emit q->disconnected();
+}
+
+QSocketServerPrivate::QSocketServerPrivate()
+{
+ /* connect to socket server */
+ TInt result = socketServer.Connect();
+ if (result != KErrNone) {
+ qWarning("%s: RSocketServ.Connect() failed with error %d", __PRETTY_FUNCTION__, result);
+ return;
+ }
+}
+
+QSocketServerPrivate::~QSocketServerPrivate()
+{
+ if (socketServer.Handle() != 0)
+ socketServer.Close();
+}
+
+QString QBluetoothSocketPrivate::localName() const
+{
+ return QBluetoothLocalDevicePrivate::name();
+}
+
+QBluetoothAddress QBluetoothSocketPrivate::localAddress() const
+{
+ TBTSockAddr address;
+ if(!iSocket)
+ {
+ // need to return something anyway
+ return QBluetoothAddress();
+ }
+ iSocket->LocalName(address);
+ return qTBTDevAddrToQBluetoothAddress(address.BTAddr());
+}
+
+quint16 QBluetoothSocketPrivate::localPort() const
+{
+ if(!iSocket)
+ {
+ // need to return something anyway
+ return 0;
+ }
+ return iSocket->LocalPort();
+}
+
+QString QBluetoothSocketPrivate::peerName() const
+{
+ RHostResolver resolver;
+
+ if(getSocketServer()->socketServer.Handle()== 0 || !iSocket || state != QBluetoothSocket::ConnectedState )
+ {
+ // need to return something anyway
+ return QString();
+ }
+ TInt err = resolver.Open(getSocketServer()->socketServer, KBTAddrFamily, KBTLinkManager);
+ if (err==KErrNone)
+ {
+ TNameEntry nameEntry;
+ TBTSockAddr sockAddr;
+ iSocket->RemoteName(sockAddr);
+ TInquirySockAddr address(sockAddr);
+ address.SetBTAddr(sockAddr.BTAddr());
+ address.SetAction(KHostResName|KHostResIgnoreCache); // ignore name stored in cache
+ err = resolver.GetByAddress(address, nameEntry);
+ if(err == KErrNone)
+ {
+ TNameRecord name = nameEntry();
+ QString qString((QChar*)name.iName.Ptr(),name.iName.Length());
+ m_peerName = qString;
+ }
+ }
+ resolver.Close();
+
+ if(err != KErrNone)
+ {
+ // What is best? return an empty string or return the MAC address?
+ // In Symbian if we can't get the remote name we usually replace it with the MAC address
+ // but since Bluez implementation return an empty string we do the same here.
+ return QString();
+ }
+
+ return m_peerName;
+}
+
+QBluetoothAddress QBluetoothSocketPrivate::peerAddress() const
+{
+ TBTSockAddr address;
+ if(!iSocket)
+ {
+ // need to return something anyway
+ return QBluetoothAddress();
+ }
+ iSocket->RemoteName(address);
+ return qTBTDevAddrToQBluetoothAddress(address.BTAddr());
+}
+
+quint16 QBluetoothSocketPrivate::peerPort() const
+{
+ TBTSockAddr address;
+ if(!iSocket)
+ {
+ // need to return something anyway
+ return 0;
+ }
+ iSocket->RemoteName(address);
+ return address.Port();
+}
+
+void QBluetoothSocketPrivate::close()
+{
+ Q_Q(QBluetoothSocket);
+ if(!iSocket || (state != QBluetoothSocket::ConnectedState && state != QBluetoothSocket::ListeningState))
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ return;
+ }
+ iSocket->CancelBasebandEventNotifier();
+ q->setSocketState(QBluetoothSocket::ClosingState);
+ iSocket->Shutdown(RSocket::ENormal);
+}
+
+void QBluetoothSocketPrivate::abort()
+{
+ Q_Q(QBluetoothSocket);
+ if(!iSocket)
+ {
+ socketError = QBluetoothSocket::UnknownSocketError;
+ emit q->error(socketError);
+ return;
+ }
+ iSocket->CancelWrite();
+ transmitting = false;
+ writeSize = 0;
+ iSocket->CancelBasebandEventNotifier();
+ iSocket->Shutdown(RSocket::EImmediate);
+ // force active object to run and shutdown socket.
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
+}
+
+qint64 QBluetoothSocketPrivate::readData(char *data, qint64 maxSize)
+{
+ Q_Q(QBluetoothSocket);
+ if(data == 0 || maxSize <= 0)
+ {
+ return -1;
+ }
+ qint64 size = buffer.read(data, maxSize);
+ QMetaObject::invokeMethod(q, "_q_startReceive", Qt::QueuedConnection);
+ return size;
+}
+
+qint64 QBluetoothSocketPrivate::writeData(const char *data, qint64 maxSize)
+{
+ if(!iSocket || data == 0 || maxSize <= 0 || txMTU <= 0) {
+ return -1;
+ }
+ if (!txArray.isEmpty())
+ {
+ txArray.append(QByteArray(data, maxSize));
+ }
+ else
+ {
+ txArray = QByteArray(data, maxSize);
+ }
+ // we try to send the data to the remote device
+ if(tryToSend())
+ {
+ // Warning : It doesn't mean the data have been sent
+ // to the remote device, it means that the data was
+ // at least stored in a local buffer.
+ return maxSize;
+ }
+ else
+ {
+ writeSize = 0;
+ return -1;
+ }
+}
+
+void QBluetoothSocketPrivate::_q_readNotify()
+{
+}
+
+void QBluetoothSocketPrivate::_q_writeNotify()
+{
+
+}
+
+bool QBluetoothSocketPrivate::setSocketDescriptor(int socketDescriptor, QBluetoothSocket::SocketType socketType,
+ QBluetoothSocket::SocketState socketState, QBluetoothSocket::OpenMode openMode)
+{
+ Q_UNUSED(socketDescriptor);
+ Q_UNUSED(socketType);
+ Q_UNUSED(socketState);
+ Q_UNUSED(openMode);
+ return false;
+}
+
+void QBluetoothSocketPrivate::_q_startReceive()
+{
+ receive();
+}
+
+qint64 QBluetoothSocketPrivate::bytesAvailable() const
+{
+ return buffer.size();
+}
+
+bool QBluetoothSocketPrivate::tryToSend()
+{
+ if(txArray.isEmpty())
+ return true;
+
+ if(transmitting)
+ return transmitting;
+
+ // we cannot write more than txMTU otherwise the extra data will just be lost
+ TInt dataLen = qMin(txArray.length(),txMTU);
+
+ TRAPD(err, txDescriptor.Set(reinterpret_cast<const unsigned char *>(txArray.constData()),dataLen));
+ if(err != KErrNone)
+ {
+ transmitting = false;
+ }
+ else
+ {
+ err = iSocket->Write(txDescriptor);
+ if (err != KErrNone)
+ {
+ transmitting = false;
+ }
+ writeSize = dataLen;
+ transmitting = true;
+ }
+ return transmitting;
+}
+