--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testexecfw/statsrv/device/source/statapi/src/stat_bt.cpp Mon Mar 08 15:03:44 2010 +0800
@@ -0,0 +1,695 @@
+/*
+* Copyright (c) 2005-2009 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:
+*
+*/
+
+
+
+/********************************************************************************
+ *
+ * System Includes
+ *
+ *******************************************************************************/
+#include <in_sock.h>
+#include <e32std.h>
+
+/********************************************************************************
+ *
+ * Local Includes
+ *
+ *******************************************************************************/
+#include "assert.h"
+#include "ntoh.h"
+#include "Stat_bt.h"
+#include "../../../../common/inc/SerialPacketSize.h"
+
+/********************************************************************************
+ *
+ * Macro functions
+ *
+ ********************************************************************************/
+#define NOTISDISCONNECTING(s) (((s) != EDisconnectingData) && ((s) != EDisconnectingListen) && ((s) != EDisconnected) && ((s) != EDisconnectingUnregister))
+#define STANDARDBUFVALUE 4
+
+/********************************************************************************
+ *
+ * CStatTransportBT -- Constructor
+ *
+ *******************************************************************************/
+CStatTransportBT *CStatTransportBT::NewL( void )
+{
+ CStatTransportBT *self = new (ELeave) CStatTransportBT();
+ CleanupStack::PushL(self);
+ self->ConstructL( );
+ CleanupStack::Pop();
+ return self;
+}
+
+CStatTransportBT::CStatTransportBT() : CActive(EPriorityStandard)
+{
+}
+
+void CStatTransportBT::ConstructL( void )
+{
+ // add this to active scheduler
+ CActiveScheduler::Add(this);
+
+ // initialise all params
+
+ iWrCommandData = NULL;
+ iRecvBuffer = NULL;
+ iRecvBufferPtr = NULL;
+ iTransport = NULL;
+ iBTTransportStatus = EIdle;
+ iBTTransportDisconnectStatusBeforeUnregister = EIdle;
+ iRWStatus = ENoRW;
+
+ iMaxPacketSize = KMaxBluetoothPacketSize;
+}
+
+CStatTransportBT::~CStatTransportBT()
+{
+ // this will call cancel and remove the active object -- this will call cancel
+ Deque();
+
+ // cleanup the sockets
+ switch( iBTTransportStatus ) {
+
+ case EIdle:
+ case EInitialised:
+ case EDisconnected:
+ case EError:
+ break;
+
+ case EConnected:
+ iDataSocket.Shutdown( RSocket::EImmediate, iStatus );
+ /* fall through */
+
+ case EConnecting:
+ iDataSocket.Close();
+ iListenSocket.Shutdown( RSocket::EImmediate, iStatus );
+ iListenSocket.Close();
+ iSocketServ.Close();
+ break;
+
+ case EDisconnectingData:
+ case EDisconnectingListen:
+ ;
+ break;
+ default:
+ break;
+ }
+
+ if( iWrCommandData )
+ {
+ delete iWrCommandData;
+ iWrCommandData = NULL;
+ }
+
+ if( iRecvBuffer )
+ {
+ delete iRecvBuffer;
+ iRecvBuffer = NULL;
+ }
+
+ if( iRecvBufferPtr )
+ {
+ delete iRecvBufferPtr;
+ iRecvBufferPtr = NULL;
+ }
+}
+
+/********************************************************************************
+ *
+ * CStatTransportBT -- MStatApiTransport
+ *
+ *******************************************************************************/
+TInt CStatTransportBT::InitialiseL( MNotifyStatTransport *aTransport )
+{
+ // save the transport interface
+ iTransport = aTransport;
+
+ // everything here is done in connect
+ iBTTransportStatus = EInitialised;
+ iRecHandle = NULL;
+ return KSTErrSuccess;
+}
+
+TInt CStatTransportBT::Release( void )
+{
+ // release has nothing to do (disconnecting unregister is in here in case the original connection failed)
+ asserte( (iBTTransportStatus == EDisconnected) || (iBTTransportStatus == EInitialised) || (iBTTransportStatus == EDisconnectingUnregister) );
+ iBTTransportStatus = EIdle;
+ return KSTErrSuccess;
+}
+
+//Register with the Security Manager then goes on and does other stuff in the RunL
+TInt CStatTransportBT::ConnectL( TDesC* /*aRemoteHost*/ )
+{
+ // make sure we are in the correct state
+ asserte( iBTTransportStatus == EInitialised );
+
+
+ // update the state
+ iBTTransportStatus = EConnectingRegisterMgr;
+
+ // Force a call to RunL instead of waiting for a call back (CAcitve) after registering
+ // with the security manager as in V1
+ SetActive();
+ TRequestStatus* status=&iStatus;
+ User::RequestComplete(status,KErrNone);
+ // tell the client to wait for an asynchronous response
+ return KSTErrAsynchronous;
+}
+
+TInt CStatTransportBT::StartSocketL()
+{
+ TUint error;
+
+ //make sure we are in the correct state
+ asserte( iBTTransportStatus == EConnectingRegisterMgr );
+
+ // connect to the socket server (as we are the receiver and not the initiator), create a socket, bind, listen, accept
+ User::LeaveIfError( iSocketServ.Connect() );
+
+ //now select the protocol to use (RFCOMM (serial emulation - boo. Problems with demultiplexing if 1 generic serial port is used for multiple BT connections) or L2CAP)
+ TProtocolDesc pInfo;
+ User::LeaveIfError( iSocketServ.FindProtocol(_L("RFCOMM"),pInfo ) );
+
+ //open the listener socket
+ User::LeaveIfError( iListenSocket.Open(iSocketServ, pInfo.iAddrFamily, pInfo.iSockType, pInfo.iProtocol) );
+
+
+ // RFComm Socket
+ TRfcommSockAddr addr;
+
+ // Get First available server channel
+ addr.SetPort(KRfcommPassiveAutoBind);
+
+ // Set the service security
+ //Set user defined EPOC TUid to internally represent the service
+ iServiceSecurity.SetUid( TUid::Uid( 0x1234 ) );
+
+ //Define security requirements
+ iServiceSecurity.SetAuthentication( EFalse );
+ iServiceSecurity.SetEncryption( EFalse );
+ iServiceSecurity.SetAuthorisation( EFalse );
+ addr.SetSecurity(iServiceSecurity);
+
+ //bind
+ User::LeaveIfError( iListenSocket.Bind( addr ) );
+
+ // Get the assigned port
+ iPort=iListenSocket.LocalPort();
+
+ // register with the SDP database
+ error = RegWithSDPDatabaseL();
+
+ if( error != KSTErrSuccess )
+ {
+ iTransport->HandleError( error, (void*)iStatus.Int() );
+ return KSTErrGeneralFailure;
+ }
+
+ //listen
+ User::LeaveIfError( iListenSocket.Listen( KLittleStatBTListenQueue ) );
+
+ // create a blank socket which is used as the data socket
+ User::LeaveIfError( iDataSocket.Open(iSocketServ) );
+
+ // everything should now be set up, we just wait for a stat connection
+ asserte( !IsActive() );
+ iListenSocket.Accept( iDataSocket, iStatus );
+ SetActive();
+ return KSTErrSuccess;
+}
+
+//------------------------------------------------------------------------------
+
+TInt CStatTransportBT::Disconnect( void )
+{
+ // must be connected
+ asserte( (iBTTransportStatus == EInitialised) ||
+ (iBTTransportStatus == EConnected) ||
+ (iBTTransportStatus == EConnectingSockets) ||
+ (iBTTransportStatus == EDisconnectingData) ||
+ (iBTTransportStatus == EDisconnectingListen) ||
+ (iBTTransportStatus == EConnectingRegisterMgr) );
+
+ // cancel any pending ops
+ Cancel();
+
+ iBTTransportDisconnectStatusBeforeUnregister = iBTTransportStatus;
+ iBTTransportStatus = EDisconnectingUnregister;
+
+ // Force call to RunL instead of waiting for a return from unregistring security service as in bluetooth V1
+ SetActive();
+ TRequestStatus* iDisconnectStatus=&iStatus;
+ User::RequestComplete(iDisconnectStatus,KErrNone);
+
+ return KSTErrAsynchronous;
+}
+
+TInt CStatTransportBT::RequestSend( TDesC8 *aData, const TUint aDataLength )
+{
+ // make sure the state is correct
+ asserte( iBTTransportStatus == EConnected );
+ asserte( iRWStatus == ENoRW );
+ iRWStatus = EWritePending;
+
+ // copy the data to members to local members
+ if( aDataLength > 0 )
+ {
+ if( iWrCommandData && ( aDataLength != static_cast<TUint>(iWrCommandData->Length( )) ) )
+ {
+ delete iWrCommandData;
+ iWrCommandData = NULL;
+ }
+
+ if( ! iWrCommandData )
+ {
+ iWrCommandData = HBufC8::New( aDataLength );
+
+ if( ! iWrCommandData )
+ {
+ User::Leave(KErrNoMemory);
+ }
+ }
+
+ TPtr8 dataPointer( iWrCommandData->Des() );
+ dataPointer.Copy( aData->Ptr(), aDataLength );
+ }
+
+ // do the send
+ asserte( !IsActive() );
+ asserte( (unsigned)aData->Length() == aDataLength );
+ iDataSocket.Write( *iWrCommandData, iStatus );
+ SetActive();
+
+ // tell the caller to wait for an asynchronous response
+ return KSTErrAsynchronous;
+}
+
+TInt CStatTransportBT::RequestReceive( TUint aByteCount )
+{
+ // ensure that there are no reads in progress
+ asserte( iBTTransportStatus == EConnected );
+ asserte( !IsActive() );
+ asserte( iRWStatus == ENoRW );
+ iRWStatus = EReadPending;
+
+ asserte( aByteCount <= static_cast<TUint>(iMaxPacketSize) );
+ asserte( !IsActive() );
+
+ if( iRecvBuffer && ( aByteCount != static_cast<TUint>(iRecvBuffer->Length( )) ) )
+ {
+ delete iRecvBuffer;
+ iRecvBuffer = NULL;
+ delete iRecvBufferPtr;
+ iRecvBufferPtr = NULL;
+ }
+
+ if( ! iRecvBuffer )
+ {
+ iRecvBuffer = HBufC8::New( aByteCount );
+
+ if( ! iRecvBuffer )
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+ iRecvBufferPtr = new TPtr8(
+ const_cast<unsigned char*>(iRecvBuffer->Ptr( )),
+ aByteCount, aByteCount );
+
+ if( ! iRecvBufferPtr )
+ {
+ User::Leave(KErrNoMemory);
+ }
+
+#ifdef _DEBUG
+ // Check the size of the pointer is the same
+ // as the size of the buffer.
+ TInt length = iRecvBufferPtr->Length( );
+ length = 0; // Extra likne to remove compiler warning.
+#endif // def _DEBUG
+ }
+
+ iDataSocket.Read( *iRecvBufferPtr, iStatus );
+ SetActive();
+
+ // return to the caller
+ return KSTErrAsynchronous;
+}
+
+TText8 *CStatTransportBT::Error( void )
+{
+ return NULL;
+}
+
+TInt CStatTransportBT::GetPacketSize()
+{
+ // The packet size is configured when we initialise the port.
+ return iMaxPacketSize;
+}
+
+
+//Register it in the SDP database - determine attribs, construct the record and then add attribs to new record
+TInt CStatTransportBT::RegWithSDPDatabaseL( void )
+{
+ asserte( iBTTransportStatus == EConnectingRegisterMgr );
+
+ //Connect and open to the session and the DB
+ //User::LeaveIfError( iSdpSession.Connect() );
+
+ TInt ret2;
+ ret2 = iSdpSession.Connect();
+
+ if(ret2!=KErrNone)
+ {
+ User::Leave(ret2);
+ }
+
+ User::LeaveIfError( iSdpDatabaseSession.Open( iSdpSession ) );
+ TBuf8<STANDARDBUFVALUE> value1;
+
+ TBuf8<STANDARDBUFVALUE> value2;
+ CSdpAttrValue* attrVal = 0;
+ CSdpAttrValueDES* attrValDES = 0;
+
+ //initialise
+ value1.FillZ(STANDARDBUFVALUE);
+ value2.FillZ(STANDARDBUFVALUE);
+
+ // Set Attr 1 (service class list) to list with UUID = 0x1101 (serial port)
+ iSdpDatabaseSession.CreateServiceRecordL(TUUID(0x1101), iRecHandle);
+
+ // Set Service name
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdBasePrimaryLanguage +
+ KSdpAttrIdOffsetServiceName,
+ _L("STATAPI") );
+
+ // Set Service description
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdBasePrimaryLanguage +
+ KSdpAttrIdOffsetServiceDescription,
+ _L("Symbian Test Automation Tool using Serial BT") );
+
+ attrVal = CSdpAttrValueString::NewStringL( _L8( "Test Solutions Dept Symbian Ltd." ) );
+ CleanupStack::PushL(attrVal);
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdBasePrimaryLanguage +
+ KSdpAttrIdOffsetProviderName, *attrVal);
+ CleanupStack::PopAndDestroy(); //attrVal
+ attrVal = 0;
+
+ // Set Attr 2 (service record state) to 0
+ attrVal = CSdpAttrValueUint::NewUintL(value1);
+ CleanupStack::PushL(attrVal);
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdServiceRecordState, *attrVal);
+ CleanupStack::PopAndDestroy(); //attrVal
+ attrVal = 0;
+
+ // Set attr 4 (protocol list) to RFCOMM
+ //initialise
+ TBuf8<1> serverChannel;
+ serverChannel.FillZ(1);
+ serverChannel[0] = (unsigned char)iPort;
+
+ attrValDES = CSdpAttrValueDES::NewDESL(0);
+ CleanupStack::PushL(attrValDES);
+
+ attrValDES->StartListL()
+ ->BuildDESL()->StartListL()
+ ->BuildUUIDL( TUUID( TUint16( 0x0003 ) ) ) // RFCOMM
+ ->BuildUintL( serverChannel ) //Channel ID = 3 (listening port)
+ ->EndListL()
+ ->EndListL();
+
+ //update attr 4
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdProtocolDescriptorList, *attrValDES);
+ CleanupStack::PopAndDestroy(); //attrValDES
+ attrValDES = 0;
+
+ // Set Attr 5 (browse group list) to list with one UUID
+ // 0x1101 (serial port class)
+ // this should be updated with other service classes when other services are added.
+ attrValDES = CSdpAttrValueDES::NewDESL(0);
+ CleanupStack::PushL(attrValDES);
+
+ attrValDES->StartListL()
+ ->BuildUUIDL( TUUID( 0x1002 ) )
+ ->EndListL();
+
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdBrowseGroupList, *attrValDES);
+ CleanupStack::PopAndDestroy();
+ attrValDES = 0;
+
+ // Set Attr 0x006 (language base)
+ value1.FillZ(4);
+ value1[2] = 0x65;
+ value1[3] = 0x6e;
+ TBuf8<STANDARDBUFVALUE> val2;
+ TBuf8<STANDARDBUFVALUE> val3;
+ val2.FillZ(STANDARDBUFVALUE);
+ val3.FillZ(STANDARDBUFVALUE);
+ val2[3] = 0x6a;
+ val3[2] = 0x01;
+
+ attrValDES = CSdpAttrValueDES::NewDESL(0);
+ CleanupStack::PushL(attrValDES);
+
+ attrValDES->StartListL()
+ ->BuildUintL( value1 ) // speka de english
+ ->BuildUintL( val2 ) // UTF-8
+ ->BuildUintL( val3 ) // language base
+ ->EndListL();
+
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdLanguageBaseAttributeIDList, *attrValDES);
+ CleanupStack::PopAndDestroy();
+ attrValDES = 0;
+
+ // Set Attr 0x007 (time to live) to 600 (0x258) seconds (10 minutes)
+ //initialise buffer
+ value1.FillZ(4);
+ value1[2]=2;
+ value1[3]=0x58;
+
+ attrVal = CSdpAttrValueUint::NewUintL( value1 );
+ CleanupStack::PushL( attrVal );
+ iSdpDatabaseSession.UpdateAttributeL( iRecHandle, KSdpAttrIdServiceInfoTimeToLive, *attrVal );
+ CleanupStack::PopAndDestroy(); //attrVal
+ attrVal = 0;
+
+ //Set Attr 0x08 (availability) to 0xff - fully available - not in use
+ //initialise
+ TBuf8<1> val4;
+ val4.FillZ(1);
+ val4[0]=0xff;
+
+ attrVal = CSdpAttrValueUint::NewUintL(val4);
+ CleanupStack::PushL(attrVal);
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdServiceAvailability, *attrVal);
+ CleanupStack::PopAndDestroy(); //attrVal
+ attrVal = 0;
+
+ //Set Attr 0x201 (service database state) to 0
+ //initialise
+ value1.FillZ(4);
+
+ attrVal = CSdpAttrValueUint::NewUintL(value1);
+ CleanupStack::PushL(attrVal);
+ iSdpDatabaseSession.UpdateAttributeL(iRecHandle, KSdpAttrIdSdpServerServiceDatabaseState, *attrVal);
+ CleanupStack::PopAndDestroy(); //attrVal
+ attrVal = 0;
+
+ return KSTErrSuccess;
+}
+
+/********************************************************************************
+ *
+ * CStatTransportBT -- Active Object
+ *
+ *******************************************************************************/
+void CStatTransportBT::RunL( void )
+{
+ TInt error = KErrNone;
+
+ // if there was an error during connecting then tell the engine this
+ if( (iBTTransportStatus == EConnectingSockets) && (iStatus != KErrNone) ) {
+
+ iTransport->HandleError( KSTErrConnectFailure, (void*)iStatus.Int() );
+ return;
+ }
+
+ // the other end have disconnected. just cleanup the resource by calling Disconnect function.
+ if(iStatus == KErrDisconnected && iBTTransportStatus == EConnected) {
+
+ Disconnect();
+ return;
+ }
+
+ // if there was any other error then also tell the engine about it
+ if( (iStatus != KErrNone) && NOTISDISCONNECTING(iBTTransportStatus) ) {
+
+ iTransport->HandleError( KSTErrGeneralFailure, (void*)iStatus.Int() );
+ return;
+ }
+
+ // Now we are registered with the security manager, reg with the SDP
+ if( iBTTransportStatus == EConnectingRegisterMgr )
+ {
+ // start the socket and make it listen (async call)
+ error = StartSocketL();
+ if( error != KSTErrSuccess )
+ {
+ iTransport->HandleError( error, (void*)iStatus.Int() );
+ return;
+ }
+
+ iBTTransportStatus = EConnectingSockets;
+ return;
+ }
+
+ // We are now connected
+ if( iBTTransportStatus == EConnectingSockets )
+ {
+ iBTTransportStatus = EConnected;
+ iTransport->HandleConnect( KErrNone );
+ return;
+ }
+
+ // handle unregister service
+ if( iBTTransportStatus == EDisconnectingUnregister ) {
+ HandleAsyncDisconnect();
+ return;
+ }
+
+ // handle shutdown data socket
+ if( iBTTransportStatus == EDisconnectingData ) {
+ iDataSocket.Close();
+ iListenSocket.Shutdown( RSocket::ENormal, iStatus );
+ SetActive();
+ iBTTransportStatus = EDisconnectingListen;
+ return;
+ }
+
+ // handle shutdown listen
+ if( iBTTransportStatus == EDisconnectingListen ) {
+ iListenSocket.Close();
+ iBTTransportStatus = EDisconnected;
+ iSocketServ.Close();
+ iTransport->HandleDisconnect( KErrNone );
+ return;
+ }
+
+ // if we are writing then notify of the write
+ if( iRWStatus == EWritePending ) {
+ iRWStatus = ENoRW;
+ asserte( iWrCommandData != NULL );
+ iTransport->HandleSend( KErrNone );
+ return;
+ }
+
+ // if we are reading then notify of the read
+ if( iRWStatus == EReadPending ) {
+ iRWStatus = ENoRW;
+ TInt length = iRecvBufferPtr->Length( );
+ iTransport->HandleReceive( KErrNone, iRecvBufferPtr, length );
+ return;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void CStatTransportBT::DoCancel( void )
+{
+ // if we are connecting then cancel the connect() call
+ if( iBTTransportStatus == EConnectingSockets )
+ {
+ iListenSocket.CancelAccept();
+ }
+
+ if( iRWStatus == EReadPending )
+ {
+ iDataSocket.CancelRead();
+ }
+
+ if( iRWStatus == EWritePending )
+ {
+ iDataSocket.CancelWrite();
+ }
+
+ iRWStatus = ENoRW;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Handle async disconnect is called by the RunL when we get a successful response
+// to the unregister service request. We can now shutdown the transport normally,
+// but we have to know which state it had reached.
+//
+//------------------------------------------------------------------------------
+void CStatTransportBT::HandleAsyncDisconnect( void )
+{
+ TInt tv = KErrNone;
+
+ if(iRecHandle != NULL)
+ {
+ //Close the SDP database objects and delete the record
+ TRAP( tv, iSdpDatabaseSession.DeleteRecordL( iRecHandle) );
+ if( tv != KErrNone )
+ {
+ _LIT(KErrDelRecord,"An error occured while deleting the SDP record.");
+
+ iTransport->HandleInfo(&KErrDelRecord);
+ }
+ }
+
+ iSdpDatabaseSession.Close();
+ iSdpSession.Close();
+ iRecHandle = NULL;
+
+ // clean up the sockets depending on the state
+ switch( iBTTransportDisconnectStatusBeforeUnregister ) {
+
+ case EConnected:
+ iDataSocket.Shutdown( RSocket::ENormal, iStatus );
+ SetActive();
+ iBTTransportStatus = EDisconnectingData;
+ break;
+
+ case EConnecting:
+ case EDisconnectingData:
+ iDataSocket.Close();
+ iListenSocket.Shutdown( RSocket::ENormal, iStatus );
+ SetActive();
+ iBTTransportStatus = EDisconnectingListen;
+ break;
+
+ case EInitialised:
+ case EDisconnectingListen:
+ case EConnectingRegisterMgr:
+ // initialised may mean that ConnectL threw an error -- so close the resources
+ iDataSocket.Close();
+ iListenSocket.Close();
+ iSocketServ.Close();
+ iTransport->HandleDisconnect( KErrNone );
+ break;
+
+ default:
+ ;
+ }
+}
+