diff -r e8e63152f320 -r 2a9601315dfc javaextensions/bluetooth/bluetoothcommons/src.s60/bluetoothclientconnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaextensions/bluetooth/bluetoothcommons/src.s60/bluetoothclientconnection.cpp Mon May 03 12:27:20 2010 +0300 @@ -0,0 +1,614 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include + +#include "logger.h" +#include "fs_methodcall.h" +#include "functionserver.h" +#include "javasymbianoslayer.h" + +#include "bluetoothfunctionserver.h" +#include "bluetoothclientconnection.h" +#include + +using namespace std; + +using namespace java::util; +using namespace java::bluetooth; + +OS_EXPORT BluetoothClientConnection::BluetoothClientConnection +(BluetoothFunctionServer* server): + mServer(server), + mShutdownNotifyMonitor(NULL), + mReadNotifyMonitor(NULL), + mBuffer(NULL, 0), + mSendNotifyMonitor(NULL), + mNegotiatedReceiveMtu(0), + mNegotiatedTransmitMtu(0), + mRemoteBTAddr(0), + mConnectNotifyMonitor(NULL), + mMakeJavaCallbackOnRead(EFalse), + mReadPending(EFalse), + mBufferInitialized(EFalse) +{ + JELOG2(EJavaBluetooth); +} + +OS_EXPORT BluetoothClientConnection::BluetoothClientConnection +(CBluetoothSocket* aSocket, BluetoothFunctionServer* aServer): + mServer(aServer), + mSocket(aSocket), + mShutdownNotifyMonitor(NULL), + mReadNotifyMonitor(NULL), + mBuffer(NULL, 0), + mSendNotifyMonitor(NULL), + mNegotiatedReceiveMtu(0), + mNegotiatedTransmitMtu(0), + mRemoteBTAddr(0), + mMakeJavaCallbackOnRead(EFalse), + mReadPending(EFalse), + mBufferInitialized(EFalse) +{ + JELOG2(EJavaBluetooth); +} + +OS_EXPORT BluetoothClientConnection::~BluetoothClientConnection() +{ + JELOG2(EJavaBluetooth); + + CloseFs(); + delete mReadNotifyMonitor; + delete mSendNotifyMonitor; + delete mShutdownNotifyMonitor; + if (mBufferInitialized) + { + delete mBuffer.Ptr(); + } +} + +// NOTE: +// TO be called by server objects doing accept and open. +// To be called always in Function server context +// Must be called only after connection has been successfully established +OS_EXPORT void BluetoothClientConnection::initialize(int protocol, + TInt64 aRemoteAddr, int aReceiveMtu, int aTransmitMtu) +{ + JELOG2(EJavaBluetooth); + // Set CBluetoothSocket to notify this object on events. + mSocket->SetNotifier(*this); + mProtocol = protocol; + mRemoteBTAddr = aRemoteAddr; + mNegotiatedReceiveMtu = aReceiveMtu; + mNegotiatedTransmitMtu = aTransmitMtu; + + // Because of this call, we must call initialize in FS context + ReceiveData(); +} + +OS_EXPORT int BluetoothClientConnection::init(int protocol) +{ + JELOG2(EJavaBluetooth); + TRAPD(result, CallMethodL(this, &BluetoothClientConnection::InitL, + protocol, mServer)); + return result; +} + +/** + * Should be called in FunctionServer Context before any method of this class is called + * Look at bluetoothconsts.h for constants: + * PROTOCOL_L2CAP for L2CAP & PROTOCOL_RFCOMM for RFCOMM + */ +void BluetoothClientConnection::InitL(TInt protocol) +{ + JELOG2(EJavaBluetooth); + //Connect to SocketServer + User::LeaveIfError(mSocketServ.Connect()); + User::LeaveIfError(mSocketServ.ShareAuto()); + TProtocolDesc pdesc; + + if (PROTOCOL_L2CAP == protocol) + { + User::LeaveIfError(mSocketServ.FindProtocol(KL2CAPDesC(), pdesc)); + mSocket = CBluetoothSocket::NewL(*this, mSocketServ, pdesc.iSockType, + KL2CAP); + } + else + { + User::LeaveIfError(mSocketServ.FindProtocol(KRFCOMMDesC(), pdesc)); + mSocket = CBluetoothSocket::NewL(*this, mSocketServ, pdesc.iSockType, + KRFCOMM); + } + mProtocol = protocol; +} + +OS_EXPORT void BluetoothClientConnection::close() +{ + if (NULL == mShutdownNotifyMonitor) + { + mShutdownNotifyMonitor = Monitor::createMonitor(); + } + CallMethod(this, &BluetoothClientConnection::CloseFs, mServer); + mShutdownNotifyMonitor->wait(); + delete mSocket; + mSocket = 0; +} + +void BluetoothClientConnection::CloseFs() +{ + JELOG2(EJavaBluetooth); + if (mSocket) + { + mMakeJavaCallbackOnRead = EFalse; + mSocket->CancelAll(); + mSocket->Shutdown(RSocket::EImmediate); + } +} + +/** + * Calls ReceiveData in FunctionServer Context and allocates + * memory needed and assigns to inBuf + */ +OS_EXPORT int BluetoothClientConnection::receive(char* &inBuf) +{ + JELOG2(EJavaBluetooth); + // This receive must read the data already buffered and return the data. + // For L2CAP the size of internal buffer should be the same as the + // negotiated receive mtu. + // For RFCOMM, it must be the same as java side buffer. + // receive never blocks. + + int returnValue = mReadStatus; + if (KErrNone == mReadStatus) + { + //Assign output parameter. + int dataRead = mBuffer.Length(); + + inBuf = new char[dataRead + 1]; + memcpy(inBuf, mBuffer.Ptr(), dataRead); + inBuf[dataRead] = 0; + + LOG1(EJavaBluetooth, EInfo, + " BluetoothClientConnection::receive: Length of inBuf: %d", + strlen((inBuf))); + LOG1(EJavaBluetooth, EInfo, + "- BluetoothClientConnection::receive: Length: %d", dataRead); + returnValue = dataRead; + } + else + { + if (KErrEof == mReadStatus) + { + LOG(EJavaBluetooth, EInfo, + "- BluetoothClientConnection::receive: EOF"); + returnValue = 0; + } + else if (KErrDisconnected == mReadStatus) + { + ELOG(EJavaBluetooth, + "- BluetoothClientConnection::receive Disconnected"); + return returnValue; + } + } + + // Trigger next read before returning. + CallMethod(mReadStatus, this, &BluetoothClientConnection::ReceiveData, + mServer); + // IF we reach here, it means that something got messed up :) + return returnValue; +} + +OS_EXPORT void BluetoothClientConnection::registerCallback(JNIEnv* aJni, + jobject peer) +{ + JELOG2(EJavaBluetooth); + if (!(mServer->attachedToVm())) + { + LOG(EJavaBluetooth, EInfo, + "+ BluetoothClientConnection::registerCallback Attaching to VM." + " Should be called only in case of Push"); + mServer->attach(aJni, peer); + } + mMakeJavaCallbackOnRead = ETrue; + + jclass peerClass = aJni->GetObjectClass(peer); + mReadCompleteCallback = aJni->GetMethodID(peerClass, + "receiveCompleteCallback", "(J)V"); +} + +void BluetoothClientConnection::makeReadCompleteCallback() +{ + JELOG2(EJavaBluetooth); + JNIEnv* jni = mServer->getValidJniEnv(); + jobject peer = mServer->getPeer(); + + (*jni).CallVoidMethod(peer, mReadCompleteCallback, + reinterpret_cast(this)); + + mMakeJavaCallbackOnRead = EFalse; +} + +//Should be called in FunctionServer context. +TInt BluetoothClientConnection::ReceiveData() +{ + JELOG2(EJavaBluetooth); + + if (!mBufferInitialized) + { + TUint8 *tempBuf = NULL; + int length = 512; + if (PROTOCOL_L2CAP == mProtocol) + { + length = mNegotiatedReceiveMtu; + tempBuf = new TUint8[length]; + } + else + { + tempBuf = new TUint8[length]; + // NOTE: Size of this buffer should be the same as that specifie in BluetoothStreamer. + } + mBuffer.Set(tempBuf, 0, length); + mBufferInitialized = ETrue; + } + + TInt error = 0; + + //RecvOneOrMore does not block until the whole buffer is filled. + //Returns as soon as some data is available. + if (PROTOCOL_L2CAP == mProtocol) + { + // mBuffer should be the same as the negotiated MTU value. + error = mSocket->Read(mBuffer); + } + else + { + LOG1( + EJavaBluetooth, + EInfo, + " BluetoothClientConnection::ReceiveData on RFCOMM Length: %d", + mBuffer.MaxSize()); + error = mSocket->RecvOneOrMore(mBuffer, 0, mSockXfrLength); + } + + if (KErrNone == error) + { + mReadPending = true; + } + + LOG1(EJavaBluetooth, EInfo, + "- BluetoothClientConnection::ReceiveData Err:%d", error); + return error; +} + +/** + * Sends data by calling SendData in Function Server context. + * Blocks until send is complete. + */ +OS_EXPORT int BluetoothClientConnection::send(const char* data, int length) +{ + JELOG2(EJavaBluetooth); + LOG1(EJavaBluetooth, EInfo, " BluetoothClientConnection::send: Data Length: %d ", + length); + + if (KErrDisconnected == mReadStatus) + { + ELOG(EJavaBluetooth, " BluetoothClientConnection::send Disconnected"); + return mReadStatus; + } + + if (NULL == data || 0 == length) + { + return 0; + } + + if (!mSendNotifyMonitor) + { + mSendNotifyMonitor = Monitor::createMonitor(); + } + + TPtr8 dataPtr((TUint8 *) data, length, length); + LOG1(EJavaBluetooth, EInfo, + " BluetoothClientConnection::send: Sending data length:%d", length); + + TInt error = 0; + CallMethod(error, this, &BluetoothClientConnection::SendData, dataPtr, + mServer); + + LOG(EJavaBluetooth, EInfo, + " BluetoothClientConnection::send: Waiting for data to come back"); + + if (KErrNone == error) + { + mSendNotifyMonitor->wait(); + } + else + { + return error; + } + + ELOG1(EJavaBluetooth, + "- BluetoothClientConnection::send: Sent status:%d", mWriteStatus); + + return mWriteStatus; +} + + +TInt BluetoothClientConnection::SendData(const TDesC8& aData) +{ + JELOG2(EJavaBluetooth); + return mSocket->Send(aData, 0); +} + +OS_EXPORT int BluetoothClientConnection::connect(long long aBtAddress, + int aChannel, bool aAuthenticate, bool aEncrypt, int aReceiveMTU, + int aTransmitMTU) +{ + JELOG2(EJavaBluetooth); + if (NULL == mConnectNotifyMonitor) + { + mConnectNotifyMonitor = Monitor::createMonitor(); + } + + TInt auth = (aAuthenticate) ? 1 : 0; + TInt enc = (aEncrypt) ? 1 : 0; + TInt64 btAddress = aBtAddress; + TInt channel = aChannel; + mRequestedRMtu = aReceiveMTU; + mRequestedTMtu = aTransmitMTU; + + TInt retVal = 0; + CallMethod(retVal, this, &BluetoothClientConnection::Connect, btAddress, + channel, auth, enc, mRequestedRMtu, mRequestedTMtu, mServer); + + if (0 == retVal) + { + mRemoteBTAddr = aBtAddress; + // Will be notified by HandleConnectCompleteL() + mConnectNotifyMonitor->wait(); + return mConnectError; + } + + return retVal; +} + +TInt BluetoothClientConnection::Connect(TInt64 btAddress, TInt channel, + TInt authenticate, TInt encrypt, TInt receiveMTU, TInt transmitMTU) +{ + JELOG2(EJavaBluetooth); + LOG3( + EJavaBluetooth, + EInfo, + " BluetoothClientConnection::Connect: Channel %d, RMTU: %d TMTU %d", + channel, receiveMTU, transmitMTU); + LOG1(EJavaBluetooth, EInfo, " BluetoothClientConnection::Connect %lX", + btAddress); + LOG(EJavaBluetooth, EInfo, + " BluetoothClientConnection::Connect: Applying Settings"); + + TBTDevAddr btDeviceAddress(btAddress); + TBTSockAddr btsockaddr; + btsockaddr.SetBTAddr(btDeviceAddress); + btsockaddr.SetPort(channel); + + // Set security + TBTServiceSecurity secSettings; + if (authenticate == EFalse) + secSettings.SetAuthentication(EFalse); + else + secSettings.SetAuthentication(ETrue); + + if (encrypt == EFalse) + secSettings.SetEncryption(EFalse); + else + secSettings.SetEncryption(ETrue); + // Attach the security settings. + btsockaddr.SetSecurity(secSettings); + + if (PROTOCOL_L2CAP == mProtocol) + { + TL2CapConfigPkg options; + + if (receiveMTU >= KL2MinMTU) + options().SetMaxReceiveUnitSize(receiveMTU); + else + options().SetMaxReceiveUnitSize(DEFAULT_MTU); + + if (transmitMTU >= KL2MinMTU) + options().SetMaxTransmitUnitSize(transmitMTU); + + mSocket->SetOpt(KL2CAPUpdateChannelConfig, KSolBtL2CAP, options); + } + + // Will be set once handle connect complete is called. + mConnectError = 0; + LOG(EJavaBluetooth, EInfo, + " BluetoothClientConnection::StartListenerL: Connecting to Server"); + int error = mSocket->Connect(btsockaddr); + return error; +} + +OS_EXPORT int BluetoothClientConnection::getTransmitMTU() +{ + return mNegotiatedTransmitMtu; +} + +OS_EXPORT int BluetoothClientConnection::getReceiveMTU() +{ + return mNegotiatedReceiveMtu; +} + +OS_EXPORT long long BluetoothClientConnection::getRemoteAddress() +{ + JELOG2(EJavaBluetooth); + + if (mRemoteBTAddr) + { + return mRemoteBTAddr; + } + + return -1; +} + +OS_EXPORT long BluetoothClientConnection::available() +{ + JELOG2(EJavaBluetooth); + if (KErrDisconnected == mReadStatus) + { + ELOG(EJavaBluetooth, + " BluetoothClientConnection::available Disconnected"); + return mReadStatus; + } + + if (mReadPending) + { + return 0; + } + else + { + return mBuffer.Length(); + } +} + +//------------------------------------------------------------------------------ +// Methods from MBluetoothSocketNotifier to handle Bluetooth Events +//------------------------------------------------------------------------------ + +//Notification of an accept complete event +void BluetoothClientConnection::HandleAcceptCompleteL(TInt /*err*/) +{ + LOG1(EJavaBluetooth, EInfo, + "+ BluetoothClientConnection::HandleAcceptCompleteL %s", + "WARNING: Nothing to handle in this event !!"); +} + +// Notification of a baseband event +void BluetoothClientConnection::HandleActivateBasebandEventNotifierCompleteL( + TInt /*aErr*/, TBTBasebandEventNotification& /*aEventNotification*/) +{ + LOG1( + EJavaBluetooth, + EInfo, + "+ BluetoothClientConnection::HandleActivateBasebandEventNotifierCompleteL %s", + "WARNING: Nothing to handle in this event !!"); +} + +//Notification of a connection complete event +void BluetoothClientConnection::HandleConnectCompleteL(TInt err) +{ + JELOG2(EJavaBluetooth); + mConnectError = err; + LOG1(EJavaBluetooth, EInfo, + " BluetoothClientConnection::HandleConnectCompleteL: %d", err); + + if (KErrNone == mConnectError && PROTOCOL_L2CAP == mProtocol) + { + mSocket->GetOpt(KL2CAPInboundMTU, KSolBtL2CAP, mNegotiatedReceiveMtu); + mSocket->GetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, + mNegotiatedTransmitMtu); + + LOG1( + EJavaBluetooth, + EInfo, + " BluetoothClientConnection::HandleConnectCompleteL Negotiate Rx %d", + mNegotiatedReceiveMtu); + LOG1( + EJavaBluetooth, + EInfo, + " BluetoothClientConnection::HandleConnectCompleteL Negotiate Tx %d", + mNegotiatedTransmitMtu); + + } + mConnectNotifyMonitor->notify(); + + if (KErrNone == mConnectError) + { + // Start to fetch data immediately. + ReceiveData(); + } +} + +//Notification of a ioctl complete event +void BluetoothClientConnection::HandleIoctlCompleteL(TInt /*err*/) +{ + LOG1(EJavaBluetooth, EInfo, + "+ BluetoothClientConnection::HandleIoctlCompleteL %s", + "WARNING: Nothing to handle in this event !!"); +} + +//Notification of a receive complete event +void BluetoothClientConnection::HandleReceiveCompleteL(TInt err) +{ + JELOG2(EJavaBluetooth); + mReadStatus = 0; + + // Here following operations are performed. + // 1. Store receive status. + // 2. Store amount of data read. + // 3. Change flag to not receiving. + + if (err != KErrNone) + { + ELOG1( + EJavaBluetooth, + " BluetoothClientConnection::HandleReceiveCompleteL: Error: %d", + err); + mReadStatus = err; + } + else + { + LOG1( + EJavaBluetooth, + EInfo, + " BluetoothClientConnection::HandleReceiveCompleteL: EWaiting Length: %d", + mBuffer.Length()); + } + if (mMakeJavaCallbackOnRead) + { + LOG(EJavaBluetooth, EInfo, + " BluetoothClientConnection::HandleReceiveCompleteL: Calling java"); + makeReadCompleteCallback(); + } + mReadPending = EFalse; + +} + +//Notification of a send complete event +void BluetoothClientConnection::HandleSendCompleteL(TInt err) +{ + JELOG2(EJavaBluetooth); + LOG1(EJavaBluetooth, EInfo, + " BluetoothClientConnection::HandleSendCompleteL %d: ", err); + mWriteStatus = 0; + if (err != KErrNone) + { + mWriteStatus = err; + } + mSendNotifyMonitor->notify(); +} + +//Notification of a shutdown complete event +void BluetoothClientConnection::HandleShutdownCompleteL(TInt /*err*/) +{ +// LOG1(EJavaBluetooth, EInfo, +// "+ BluetoothClientConnection::HandleShutdownCompleteL Err:%d", err); + + mShutdownNotifyMonitor->notify(); +} +