bluetooth/btcomm/src/states.cpp
changeset 0 29b1cd4cb562
child 13 20fda83a6398
child 17 907b2fb7aa8e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btcomm/src/states.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1788 @@
+// Copyright (c) 1997-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:
+// BTComm state machine state implementation.
+// 
+//
+
+#include <bluetooth/logger.h>
+#include <cs_port.h>
+#include "btcomm.h"
+#include "btstate.h"
+#include "btcommactive.h"
+#include <bt_sock.h>
+#include "sdpkey.h"
+#include "sdpclientcsy.h"
+#include <e32test.h>
+#include <btmanclient.h>
+#include "btcommutil.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_BT_COMM);
+#endif
+
+#define BAD_BTCOMM_EVENT PanicInState(EBTCommBadEventForThisState);
+
+
+
+TBTPortState::TBTPortState(CBTPortStateFactory* aParent)
+	: iFactory(aParent)
+/**
+	TBTPortState c'tor.
+	TBTPortState is the abstract base class that all CSY state
+	objects inherit from.  However, it is not a 'C' class but 
+	a 'T' class which is slightly bogus but the best way to 
+	implement the base state for the pattern.
+**/
+	{
+	LOG_FUNC
+	}
+
+TBTPortState::~TBTPortState()
+	{
+	LOG_FUNC
+	}
+
+/**
+Calls the appropriate panic function to encode the panic
+code with the current state identifier.
+@param aPanic The panic code that the state is panicking with.
+*/
+void TBTPortState::PanicInState(TBTCommPanic aPanic) const
+	{
+	LOG_FUNC
+	BTCommUtil::Panic(aPanic, iFactory->StateIndex(this));
+	}
+
+//		***** Default state *****
+
+TBTPortDefaultState::TBTPortDefaultState(CBTPortStateFactory* aParent) 
+	: TBTPortState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortDefaultState::~TBTPortDefaultState()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortDefaultState::Open(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::Close(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::Read(CBTPortProxy* /*aContext*/,TAny* /*aPtr*/,TInt /*aLength*/)
+/**
+	TBTPortDefaultState Read.
+**/
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::Write(CBTPortProxy* /*aContext*/,TAny* /*aPtr*/,TInt /*aLength*/)
+/**
+	TBTPortDefaultState Write.
+**/
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::ReadCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::WriteCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::DoRunL(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::DoCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::DoLockedAction(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::DoWriteCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortDefaultState::DoReadCompleted(CBTPortProxy* /*aContext*/,TInt aError) 
+	{ 
+	// because we managed to get reopened before destruction 
+	// and this event sources from the reader's request completing 
+	// after a read cancel was issued from the closing. 
+	LOG_FUNC
+	if(aError==KErrCancel) {return;}  
+
+	BAD_BTCOMM_EVENT 
+	} 
+
+
+void TBTPortDefaultState::Error(CBTPortProxy* aContext,TInt aError)
+/**
+	This will call each state's error loging and move the CSY to the error state.
+*/
+	{
+	LOG_FUNC
+	LogStateError(aContext,aError);
+	aContext->iLastError=aError; // record this before we lose context
+	aContext->MoveToErrorState();
+	}
+
+
+// ****** Common Pre-Connection I/O Base State  *****
+
+TBTPortCommonBaseState::TBTPortCommonBaseState(CBTPortStateFactory* aParent)
+	:TBTPortDefaultState(aParent)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortCommonBaseState::Read(CBTPortProxy* aContext,TAny* aPtr, TInt aLength)
+	{
+	LOG_FUNC
+
+	if(aLength)
+		{
+		aContext->iClientReadPtr=aPtr;
+		aContext->iClientReadLength=aLength;
+		aContext->iClientRemainderToRead=aLength;
+#ifdef _DEBUG
+	aContext->iReadsPending++;
+#endif
+		}
+	else
+		{
+		//zero length read, complete it immediately
+		aContext->iPort->ReadCompleted(KErrNone);
+		}
+	}
+
+void TBTPortCommonBaseState::Write(CBTPortProxy* aContext,TAny* aPtr, TInt aLength)
+	{
+	LOG_FUNC
+
+	aContext->iClientWritePtr=aPtr;
+	aContext->iClientWriteLength=aLength;
+	aContext->iClientLengthWrittenSoFar=aLength;
+	}
+
+void TBTPortCommonBaseState::WriteCancel(CBTPortProxy* aContext)
+/**
+	Cancel initial Write if there was one or do nothing.
+*/
+	{
+	LOG_FUNC
+
+	if(aContext->iClientWritePtr)
+		{
+		aContext->iClientWritePtr=NULL;
+		aContext->iClientWriteLength=0;
+		aContext->iClientLengthWrittenSoFar=0;
+		aContext->iPort->WriteCompleted(KErrCancel);
+		}
+	}
+
+void TBTPortCommonBaseState::ReadCancel(CBTPortProxy* aContext)
+/**
+	Cancel initial Read if there was one or do nothing.
+*/
+	{
+	LOG_FUNC
+
+	if(aContext->iClientReadPtr)
+		{
+		aContext->iClientReadPtr=NULL;
+		aContext->iClientReadLength=0;
+		aContext->iClientRemainderToRead=0;
+#ifdef _DEBUG
+		aContext->iReadsPending--;
+#endif
+		aContext->iPort->ReadCompleted(KErrCancel);
+		}
+	}
+
+void TBTPortCommonBaseState::Close(CBTPortProxy* aContext)
+	{
+	LOG_FUNC
+
+	aContext->StopReader();
+
+	//check to see if we had any client requests cached and cancel them
+	if(aContext->iClientReadPtr)
+		{
+		ReadCancel(aContext);
+		}	
+	if(aContext->iClientWritePtr)
+		{
+		WriteCancel(aContext);
+		}
+
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing));
+	}
+
+//		***** Idle state *****
+
+TBTPortStateIdle::TBTPortStateIdle(CBTPortStateFactory* aParent)
+	:TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateIdle::~TBTPortStateIdle()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateIdle::Open(CBTPortProxy* aContext)
+/**
+	This function is the entry point for the BT CSY state machine.
+	The first thing we will do is to pretend we opened a BTCOMM connection.
+	The reason for this is to avoid any deadlock across the C32-ESock-ETel 
+	trilogy.
+  **/
+	{
+	LOG_FUNC
+	aContext->CancelShutDownTimer(); // just in case we were going down before this call
+	}
+
+void TBTPortStateIdle::Close(CBTPortProxy* aContext)
+/**
+	A call to this method will cancel any pending requests.
+	It will also cancel any transition to any other state.
+  */	
+	{
+	LOG_FUNC
+	
+	aContext->Cancel();// any transition
+
+	//check to see if we had any client requests cached and cancel them
+	ReadCancel(aContext);	
+	WriteCancel(aContext);
+	}
+
+
+void TBTPortStateIdle::Read(CBTPortProxy* aContext,TAny* aPtr,TInt aLength)
+/**
+	Caches the Read() for completion after the connection is setup, starts the protocol and state machine.
+*/
+	{
+	LOG_FUNC
+	LOG(_L("**TBTPortStateIdle::Read -- Queueing one**"));
+	TBTPortCommonBaseState::Read(aContext,aPtr,aLength);
+	// Connect to ESock
+	SockServConnect(aContext);
+	}
+
+void TBTPortStateIdle::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength)
+/**
+	Caches the Write() for completion after the connection is setup, starts the protocol and state machine.
+*/
+	{
+	LOG_FUNC
+	LOG(_L("**TBTPortStateIdle::Write -- Queueing one**"));
+	TBTPortCommonBaseState::Write(aContext,aPtr,aLength);
+	// Connect to ESock
+	SockServConnect(aContext);
+	}
+
+
+void TBTPortStateIdle::DoRunL(CBTPortProxy* /*aContext*/)
+/**
+	Will be called only after we  decided to close in the Discovering state.
+	This is a NoOp method.
+ */
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateIdle::SockServConnect(CBTPortProxy* aContext)
+/**
+	Makes an asynchronous attempt to connect to ESock and moves to the next state.
+**/
+	{
+	LOG_FUNC
+	aContext->iSockServConnector->SockServConnect(aContext->iStatus);
+	
+	// now move to the next state where we pre-load the protocol
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::ELoadingProtocol));
+	aContext->SetActive();
+	}
+
+void TBTPortStateIdle::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+	
+//		***** Loading Protocol state *****
+
+TBTPortStateLoadingProtocol::TBTPortStateLoadingProtocol(CBTPortStateFactory* aParent)
+	:TBTPortCommonBaseState(aParent), iClosePending(EFalse)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateLoadingProtocol::~TBTPortStateLoadingProtocol()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateLoadingProtocol::Read(CBTPortProxy* aContext,TAny* aPtr, TInt aLength)
+	{
+	LOG_FUNC
+
+	// Cache the read ready for when our connection is up. 
+	if(aLength)
+		{
+		aContext->iClientReadPtr=aPtr;
+		aContext->iClientReadLength=aLength;
+		aContext->iClientRemainderToRead=aLength;
+#ifdef _DEBUG
+	aContext->iReadsPending++;
+#endif
+		}
+	else
+		{
+		//zero length read, complete it immediately
+		aContext->iPort->ReadCompleted(KErrNone);
+		}
+
+	// If we were planning on closing this reopens us - we've cached the read as
+	// normal, just unset the close pending flag and we can carry on setting up
+	// the connection as normal.
+	if(!iClosePending)
+		{
+		iClosePending = EFalse;
+		}
+	}
+
+void TBTPortStateLoadingProtocol::Write(CBTPortProxy* aContext,TAny* aPtr, TInt aLength)
+	{
+	LOG_FUNC
+	
+	// Cache the write ready for when our connection is up.  
+	aContext->iClientWritePtr=aPtr;
+	aContext->iClientWriteLength=aLength;
+	aContext->iClientLengthWrittenSoFar=aLength;
+	
+	// If we were planning on closing this reopens us - we've cached the write as
+	// normal, just unset the close pending flag and we can carry on setting up
+	// the connection as normal.
+	if(iClosePending)
+		{
+		iClosePending = EFalse;
+		}
+	}
+
+void TBTPortStateLoadingProtocol::Close(CBTPortProxy* aContext)
+/**
+	A call to this method will cancel any pending requests.
+	It will also cancel any transition to any other state.
+  */	
+	{
+	LOG_FUNC
+	
+	// If we're in this state our connection attempt on ESock hasn't
+	// completed yet.  We can't transition to the closing state yet 
+	// because we don't have the handle for our ESock session which 
+	// we need to close.  When the connection request completes we'll 
+	// do the transition, unless there's a Read or Write before then, 
+	// when we'll allow the connection set up to continue.
+	
+	//check to see if we had any client requests cached and cancel them
+	ReadCancel(aContext);	
+	WriteCancel(aContext);
+	
+	// Set the flag so we know where to go when the Esock connect has
+	// completed
+	iClosePending = ETrue;
+	}
+
+void TBTPortStateLoadingProtocol::DoRunL(CBTPortProxy* aContext)
+/**
+	Will be called only after we  decided to close in the Discovering state.
+	This is a NoOp method.
+ */
+	{
+	LOG_FUNC
+	
+	if (aContext->iStatus != KErrNone)
+		{
+		Error(aContext, aContext->iStatus.Int());	// couldn't connect to esock
+		return;
+		}
+		
+	// If we're waiting for the ESock handle to allow us to close, transition
+	// to the closing state now, otherwise continue connection set up.
+	if(iClosePending)
+		{
+		aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing));
+		aContext->SetActive();
+		TRequestStatus* pStatus = &(aContext->iStatus);
+		User::RequestComplete(pStatus, KErrNone);
+		
+		// Reset this incase we come back through the state machine later
+		iClosePending = EFalse;
+		}
+	else
+		{
+		StartProtocol(aContext);
+		}
+	}
+
+void TBTPortStateLoadingProtocol::StartProtocol(CBTPortProxy* aContext)
+/**
+	Makes an asynchronous attempt to invoke RSocketServ::StartProtocol() and moves to the next state.
+**/
+	{
+	LOG_FUNC
+    // now async load Bluetooth RFComm protocol to stop comm port open thread lock.
+	RSocketServ &sockServ = aContext->iSockServ;
+	LOG1(_L("TBTPortStateLoadingProtocol::Start L2CAP Protocol OK, iSockServ=0x%x"),sockServ.Handle());
+    sockServ.StartProtocol(KBTAddrFamily,KSockSeqPacket,KL2CAP,aContext->iStatus);
+	// now move to the next state were the results will be handled
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EDiscovering));
+	aContext->SetActive();
+	}
+
+void TBTPortStateLoadingProtocol::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+//		***** Discovering state *****
+
+TBTPortStateDiscovering::TBTPortStateDiscovering(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateDiscovering::~TBTPortStateDiscovering()
+	{
+	LOG_FUNC
+	}
+
+
+void TBTPortStateDiscovering::DoRunL(CBTPortProxy* aContext)
+/**
+	Find-out the port's corresponding device and settings.
+	This is done by looking at the registry default settings for this 
+	BTComm port. 
+**/
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// could not start Bluetooth protocol 
+		// must error here so that the user notices this
+		Error(aContext,ret);
+		LOG(_L(" Could not load Bluetooth protocol !"));		
+		// do tidy up here
+		return;
+		}
+	else
+		{// we have successfully started Bluetooth, lets discover the settings for this port
+		aContext->iDefaultService.SetPort(aContext->iPortNo);
+		ret=aContext->iPortSettings.Get(aContext->iDefaultService); 
+		
+		if(ret!=KErrNone)
+			{
+			LOG(_L(" Could not find default device !"));		
+			Error(aContext,ret);
+			return;
+			}
+		aContext->iBdaddr=aContext->iDefaultService.BDAddr();
+				
+		// In the context of RFCOMM, at this stage, we would be looking
+		// to do an SDP service search query on the remote RFCOMM service
+		// which means opening an SDP sap first which is a synchronous 
+		// action so has to be done as a locked action.
+		aContext->StartLocker();
+		}
+	}
+
+void TBTPortStateDiscovering::DoLockedAction(CBTPortProxy* aContext)
+/**
+	Do an SDP query for the remote service port number as a synchronous (locked) action.
+	At this point we have locked the session.  We now need to open
+	our NetDB and then follow that with our async state change action 
+	which is an SDP query.
+**/
+	{
+	LOG_FUNC
+	// need to open the netdb, fire off an async SDP Connect Query
+	// and then do the state transition.
+	RNetDatabase& netdb=aContext->iNetDatabase;
+	RSocketServ ss=aContext->iSockServ;
+	// note this needs to be a reference.
+	TInt ret=netdb.Open(ss,KBTAddrFamily,KSDP);
+	// sync action completed ok - now stop locker.
+	aContext->StopLocker();
+	if (ret!=KErrNone)	
+		{
+		Error(aContext,ret);
+		return;
+		}
+
+	// if NetDB was opened ok make a note of it for cleanup on closing state
+	aContext->SetNetDbInUse();
+	
+	// now queue async action and move into next state
+	// which is an SDP connect query on remote RFCOMM service.
+	TSDPConnectQuery connQ;
+	connQ.iQueryType = KSDPConnectQuery;
+	connQ.iAddr = aContext->iBdaddr;
+	aContext->iSDPRequest.Copy(TSDPConnectBuf(connQ));
+	aContext->iSDPResult.SetMax();
+	netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus);
+	aContext->SetActive();
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPConnected));
+	}
+
+void TBTPortStateDiscovering::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+/**
+	TBTPortStateDiscovering Error.
+	Reaching this error means that we haven't found a device.
+**/
+	{
+	LOG_FUNC
+	}
+
+//		***** SDP Connected state *****
+
+TBTPortStateSDPConnected::TBTPortStateSDPConnected(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateSDPConnected::~TBTPortStateSDPConnected()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateSDPConnected::DoRunL(CBTPortProxy* aContext)
+/**
+	Entry at this call signals that the SDP connection query has completed.  
+	We now need to check the remote port number to connect to before 
+	invoking the locker to handle the opening of the port proxy's socket.
+**/
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// didn't manage to succeed with SDP Connect query.
+		Error(aContext,ret);
+		LOG(_L("CSY: Could not connect to remote SDP server !"));
+		return;
+		}
+	// we have successfully found the remote SDP server.
+	RNetDatabase& netdb=aContext->iNetDatabase;
+		
+	// here we create the SDP service search query. 
+	TSDPServiceSearchKey key;
+	key.iQueryType = KSDPServiceQuery;
+	key.iMaxCount = 20;
+	key.iUUID = aContext->iDefaultService.UUID();
+
+	key.iStateLength = 0;
+
+	aContext->iSDPRequest.Copy(TSDPServiceSearchKeyBuf(key));
+	aContext->iSDPServRecordHandle.SetMax(); 
+	netdb.Query(aContext->iSDPRequest,aContext->iSDPServRecordHandle,aContext->iStatus);
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPServiceQuery));
+	aContext->SetActive();		
+	}
+
+void TBTPortStateSDPConnected::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+/**
+	Reaching this error means that we haven't found a remote device
+	with the right service level on it.  ie. the SDP/IAS query failed.
+**/
+	{
+	LOG_FUNC
+	}
+
+
+//      ***** SDP Service Retrieved State *****
+
+TBTPortStateSDPServiceQuery::TBTPortStateSDPServiceQuery(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateSDPServiceQuery::~TBTPortStateSDPServiceQuery()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateSDPServiceQuery::DoRunL(CBTPortProxy* aContext)
+	{
+	LOG_FUNC
+	// we have completed the SDP service search query
+	// get number of record handles in this response
+	TInt ret=aContext->iStatus.Int();
+
+	if (ret!=KErrNone)
+		{// could not start Bluetooth protocol 
+		// must error here so that the user notices this
+		Error(aContext,ret);
+		LOG(_L("SDPService query - error."));		
+		// do tidy up here
+		return;
+		}
+	else
+		{
+		
+		iFactory->iSDPServRecordHandleCount=BigEndian::Get16(&aContext->iSDPServRecordHandle[2]);
+		if (!iFactory->iSDPServRecordHandleCount)
+			{// this is an error - found no matching service records.
+			Error(aContext,KErrNotFound);
+			return;
+			}
+		if (iFactory->iSDPServRecordHandleCount*4 > aContext->iSDPServRecordHandle.Length() - 5)
+			{// this is a check on the length of the response.			
+			Error(aContext,KErrUnknown);
+			LOG2(_L("Bad length field %d on results length %d"), 
+				iFactory->iSDPServRecordHandleCount*4,aContext->iSDPServRecordHandle.Length());
+			return;
+			}
+			
+		LOG(_L("\nFound Service records for UUID 0x03\n")); //add the number of records found
+			
+		//now retrieve the ServiceClassIDList from the first ServiceRecordHandle
+		RNetDatabase& netdb=aContext->iNetDatabase;
+
+		TSDPAttributeKey key;
+		key.iQueryType = KSDPAttributeQuery;
+		// suck out the first service record handle.
+		iFactory->iExtractedHandleCount = 1;
+		key.iServiceRecordHandle = BigEndian::Get32(&aContext->iSDPServRecordHandle[4]);
+		key.iMaxLength = 200;
+		key.iRange = EFalse;
+		key.iAttribute = KSdpAttrIdServiceClassIDList; 
+		key.iStateLength = 0;
+		aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key));
+		aContext->iSDPResult.SetMax();
+		// Now go away and do the SDP attribute request query
+		netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus);
+		aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPServiceIDListRetrieved));		
+		aContext->SetActive();
+		}
+	}
+
+void TBTPortStateSDPServiceQuery::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+/**
+	Reaching this error means that we haven't found a remote device
+	with the right service level on it.  ie. the SDP query failed.
+**/
+	{
+	LOG_FUNC
+	}
+
+
+
+//      ***** SDP Service ID List Retrieved State *****
+
+TBTPortStateServiceIDListRetrieved::TBTPortStateServiceIDListRetrieved(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+
+TBTPortStateServiceIDListRetrieved::~TBTPortStateServiceIDListRetrieved()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateServiceIDListRetrieved::DoRunL(CBTPortProxy* aContext)
+	{
+	LOG_FUNC
+
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// could not start Bluetooth protocol 
+		// must error here so that the user notices this
+		Error(aContext,ret);
+		LOG(_L("Service ID List error."));		
+		// do tidy up here
+		return;
+		}
+	else
+		{
+		RNetDatabase& netdb=aContext->iNetDatabase;
+
+		const TInt KRspAttributeCountSize = 2;
+		const TInt KContStateHeader = 1;
+
+		LOG(_L("Successful Attribute query!!\r\nHere's the result....\n"));
+		FTRACE(FHex(aContext->iSDPResult));
+
+		if (aContext->iSDPResult.Length() < KRspAttributeCountSize+KContStateHeader)
+			{
+			Error(aContext,KErrNotSupported);
+			LOG1(_L("Result is far too short at %d bytes\r\n"),aContext->iSDPResult.Length());
+			return;
+			}
+		// suck out the byte count
+		TUint16 bytecount=BigEndian::Get16(&aContext->iSDPResult[0]);
+		if (aContext->iSDPResult.Length() < KRspAttributeCountSize+bytecount+KContStateHeader)
+			{
+			Error(aContext,KErrNotSupported);
+			return;
+			}
+		if (aContext->iSDPResult[KRspAttributeCountSize+bytecount]!=0)
+			{// continuation state to deal with
+			// fixme - do something here!
+			Error(aContext,KErrNotSupported);
+			LOG(_L("Continuation state to deal with in SDP attr query response!!\r\n"));
+			return;
+			}
+
+		//check for the expected UUID in the ServiceIDList
+
+		CRFCommClass* builder=CRFCommClass::NewL(aContext->iDefaultService.UUID());
+		CleanupStack::PushL(builder);
+		CElementParser* parser = CElementParser::NewL(builder);
+		CleanupStack::PushL(parser);
+		//Parsing simple attribute list
+		TRAPD(err, parser->ParseElementsL(aContext->iSDPResult.Mid(KRspAttributeCountSize,bytecount)));
+		if (err)
+			{
+			LOG1(_L("Parser left with error %d\n"),err);
+			Error(aContext,err);
+			return;
+			}
+			
+		TBool getProtocolDesc = builder->InService();
+		CleanupStack::PopAndDestroy(2);
+
+		TSDPAttributeKey key;
+		key.iMaxLength = 200;
+		key.iRange = EFalse;
+		key.iStateLength = 0;
+		key.iQueryType = KSDPAttributeQuery;
+		
+		aContext->iSDPResult.Zero();
+		aContext->iSDPResult.SetMax();
+
+		if (getProtocolDesc)
+			{
+			LOG(_L("**UUID found in ServiceClassIDList, moving on to getting Protocol Desc **"));
+
+
+			// suck out the next service record handle.
+			//if there are still some Handles left
+			key.iServiceRecordHandle = BigEndian::Get32(&aContext->
+												iSDPServRecordHandle[4*iFactory->iExtractedHandleCount]); //this handle
+			key.iAttribute = KSdpAttrIdProtocolDescriptorList; 
+			aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key));
+			// Now go away and do the SDP attribute request query
+			// i.e search for the first service record, to find what protocols are supported
+			netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus);
+			aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPAttribListRetrieved));		
+			aContext->SetActive();
+			}
+		else if ( iFactory->iExtractedHandleCount < (iFactory->iSDPServRecordHandleCount) )
+			{
+			LOG(_L("**UUID not found in ServiceClassIDList, inquire of next ServiceRecordHandle  **"));
+
+			// suck out the next service record handle.
+			//if there are still some Handles left
+			iFactory->iExtractedHandleCount++;
+			key.iServiceRecordHandle = BigEndian::Get32(&aContext->
+												iSDPServRecordHandle[4*iFactory->iExtractedHandleCount]); //next handle
+			key.iAttribute = KSdpAttrIdServiceClassIDList; 
+			aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key));
+			// Now go away and do the SDP attribute request query
+			netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus);
+			//state is remaining unchanged so no need to call aContext->SetState()
+			aContext->SetActive();
+			
+			}
+		else //UUID has not been found & there are no more ServiceRecordHandles 
+			{
+			LOG(_L("**UUID not found and no ServiceRecordHandles left **"));
+			Error(aContext,KErrNotFound);
+			}
+		}
+	}
+
+
+void TBTPortStateServiceIDListRetrieved::LogStateError(CBTPortProxy* /*aContext*/, TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+
+//      ***** SDP Attribute List Retrieved State *****
+
+TBTPortStateSDPAttributeListRetrieved::TBTPortStateSDPAttributeListRetrieved(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateSDPAttributeListRetrieved::~TBTPortStateSDPAttributeListRetrieved()
+	{
+	LOG_FUNC
+	}
+
+
+void TBTPortStateSDPAttributeListRetrieved::DoRunL(CBTPortProxy* aContext)
+/**
+	The SDP attribute request query completed and here we parse the results.
+*/
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// could not start Bluetooth protocol 
+		// must error here so that the user notices this
+		Error(aContext,ret);
+		LOG(_L("AttributeListRetrieved - error."));		
+		// do tidy up here
+		return;
+		}
+	else
+		{	
+		const TInt KContStateHeader = 1;
+		const TInt KRspAttributeCountSize = 2;
+
+		if (aContext->iSDPResult.Length() < KRspAttributeCountSize+KContStateHeader)
+			{
+			Error(aContext,KErrNotSupported);
+			LOG1(_L("Result is far too short at %d bytes\r\n"),aContext->iSDPResult.Length());
+			return;
+			}
+		// suck out the byte count
+		TUint16 bytecount=BigEndian::Get16(&aContext->iSDPResult[0]);
+		if (aContext->iSDPResult.Length() < KRspAttributeCountSize+bytecount+KContStateHeader)
+			{
+			Error(aContext,KErrNotSupported);
+			return;
+			}
+		if (aContext->iSDPResult[KRspAttributeCountSize+bytecount]!=0)
+			{// continuation state to deal with
+			// fixme - do something here!
+			Error(aContext,KErrNotSupported);
+			LOG(_L("Continuation state to deal with in SDP attr query response!!\r\n"));
+			return;
+			}
+		LOG(_L("Successful Attribute query!!\r\nHere's the result....\n"));
+		FTRACE(FHex(aContext->iSDPResult));
+				
+		// Parse the attribute list
+				
+		CRFCommAttribs* builder=CRFCommAttribs::NewL(NULL);
+		CleanupStack::PushL(builder);
+		CElementParser* parser = CElementParser::NewL(builder);
+		CleanupStack::PushL(parser);
+		//Parsing simple attribute list
+		TUint rem=0;
+
+		TRAPD(err,rem=parser->ParseElementsL(aContext->iSDPResult.Mid(KRspAttributeCountSize,bytecount)));
+		if (err)
+			{
+			LOG1(_L("Parser left with error %d\n"),err);
+			Error(aContext,err);
+			// cleanup since the leave/error does not get propagated and we return.
+			CleanupStack::PopAndDestroy(2);
+			return;
+			}
+		else
+			{
+			LOG1(_L("Parser returned %d\n"),rem);
+			}
+			
+		(void)(rem != KMaxTUint); // keep the compiler happy by taking rem as an r-value in urel
+				
+		// get the remote rfcomm port number to connect to.
+
+		err = builder->GetRFCommPort(aContext->iRemoteRfcommPortNumber); // channel number
+		if (err != KErrNone)
+			{
+			LOG1(_L("Error %d determining RFCOMM server channel\n"), err);
+			Error(aContext,err);
+			}
+
+		CleanupStack::PopAndDestroy(2);  // getting rid of parser and builder.
+
+		// do an RFCOMM connect on the remote RFCOMM port
+		// which means opening the socket first which is a synchronous 
+		// action so has to be done as a locked action.
+		aContext->StartLocker();
+		}
+	}
+
+void TBTPortStateSDPAttributeListRetrieved::DoLockedAction(CBTPortProxy* aContext)
+/**
+	Get a locked connection to the Socket server/RFComm and attempt a connection to the remote RFComm port.
+**/
+	{
+	LOG_FUNC
+	
+	TPckgBuf<TUint8> aSig;
+	RSocket& sock=aContext->iSocket;
+	RSocketServ ss=aContext->iSockServ;
+	// note this needs to be a reference.
+	TInt ret=sock.Open(ss,KBTAddrFamily,KSockStream,KRFCOMM);
+	if (ret!=KErrNone)
+		{
+		Error(aContext,ret);
+		LOG(_L("**TBTPortStateSDPAttributeListRetrieved could NOT open RFComm socket connection **"));
+		return;
+		}
+	aSig = KModemSignalDV; // KModemSignalRTC and KModemSignalRTR have been turned off
+	sock.SetOpt(KRFCOMMErrOnMSC, KSolBtRFCOMM, aSig);
+	// sync action completed ok - now stop locker.
+	aContext->StopLocker();
+	// now queue async action and move into next state
+	// which is an RFComm connect on remote port.
+	aContext->iAddr.SetBTAddr(aContext->iBdaddr);
+	aContext->iAddr.SetPort(aContext->iRemoteRfcommPortNumber);
+
+	TBTServiceSecurity security;
+	security.SetAuthentication(aContext->iDefaultService.IsSecuritySet()); // note: does this need to be updated to be SSP aware?
+
+	TBool doEncrypt = aContext->iDefaultService.IsEncryptionSet();
+	security.SetEncryption(doEncrypt);
+
+	aContext->iAddr.SetSecurity(security);
+
+	sock.Connect(aContext->iAddr, aContext->iStatus);
+	aContext->SetActive();	
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EConnecting));
+	}
+
+
+void TBTPortStateSDPAttributeListRetrieved::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+/**
+	Signals a problem with the retrieval of the remote SDP attribute List.
+**/
+	{
+	LOG_FUNC
+	}
+
+
+//		***** Connecting state *****
+
+TBTPortStateConnecting::TBTPortStateConnecting(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateConnecting::~TBTPortStateConnecting()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateConnecting::DoRunL(CBTPortProxy* aContext)
+/**
+	At this point we have finally got our connection response.
+	If successful then we are in the open state and can begin
+	to freely handle reads and writes.  The only state transition 
+	that can take us away from the open state is a close.
+**/
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// didn't manage to succeed with connect.
+		Error(aContext,ret);
+		LOG(_L("Didn't manage to succeed with connect"));
+		return;
+		}
+	else
+		{// we have successfully connected!!!!
+		// so we can transition to the open state.
+		// first we check if we have any queued writes
+		// to do and we also queue a read.
+		if (aContext->iClientWritePtr)
+			{
+			if (aContext->iClientWriteLength>KBTCOMMSendBufferLength)
+				{
+				aContext->iClientLengthWrittenSoFar=KBTCOMMSendBufferLength;
+				aContext->iMoreSendsToCome=ETrue;
+				}
+			//else see TBTPortStateConnecting::Write(..)
+
+			TPtr8& sendptr=aContext->iSendBufPtr;
+			sendptr.SetLength(0);
+			TPtr8 ptr((TUint8*)sendptr.Ptr(),0,aContext->iClientLengthWrittenSoFar);
+			if(aContext->iClientLengthWrittenSoFar>0)
+				{ // to avoid panicing on zero length write to from client
+				aContext->iPort->IPCRead(aContext->iClientWritePtr,ptr,0);
+				}
+			sendptr.Append(ptr);
+			aContext->iSendBufPtr.SetLength(aContext->iClientLengthWrittenSoFar);
+			aContext->StartWriter();
+			}
+
+		if((aContext->iClientReadLength==0)&&(aContext->iClientReadPtr))
+			{// someone asked for a zero length read
+			aContext->iPort->ReadCompleted(KErrNone);
+			}
+		aContext->StartReader();
+		aContext->SetState(iFactory->GetState(CBTPortStateFactory::EOpen));
+		}
+	}
+
+void TBTPortStateConnecting::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+/**
+	TBTPortStateConnecting Error.
+	At this point our RFComm connect has failed for some reason.
+**/
+	{
+	LOG_FUNC
+	}
+
+//		***** Open state *****
+
+TBTPortStateOpen::TBTPortStateOpen(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent) 
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateOpen::~TBTPortStateOpen()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateOpen::Close(CBTPortProxy* aContext)
+/**
+	TBTPortStateOpen Close.
+	This function is called when the user has invoked a Close on
+	the CSY session.
+	It will stop the reader and begin the shutdown and close of the socket
+	session.
+**/
+	{
+	LOG_FUNC
+	
+	aContext->StopReader();
+
+	// the close() call is a direct call to C32 from the client (in ESock probably)
+	// thus can pre-empt both DoLockedAction() and DoRunL(). Consequently
+	// if someone issued a WriteCancel(), just before the call
+	// this needs to be serviced within a DoLockedAction. But since Shutdown
+	// starts here, this will not be needed. Therefore we will NOT stop the locker
+	// here and will check wether a cancel is pending in the Closing state's
+	// DoLockedAction().
+
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing));
+	aContext->SetActive();
+	TRequestStatus* pStatus = &(aContext->iStatus);
+	User::RequestComplete(pStatus, KErrNone); 
+	}
+
+void TBTPortStateOpen::Read(CBTPortProxy* aContext,TAny* aPtr,TInt aLength)
+/**
+	The client side has requested that a read call be completed.  
+	Moreover if the reader (for the socket reads) was stoped it 
+	will be restarted from here if the low watermark for the CBTPortProxy
+	read-in circular buffer was reached.
+**/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	aContext->iReadsPending++;
+#endif
+
+	aContext->iClientReadPtr=aPtr;
+	aContext->iClientReadLength=aLength;
+	aContext->iClientRemainderToRead=aLength;
+	aContext->iClientWriteOffset=0; // to indicate the offset in the buf 
+									// for the first write back to client
+	if(aLength)
+		{
+		// need to check if there's anything in the circular buffer.
+		HandleIPCWriteToClient(aContext);
+		}
+	else
+		{
+		aContext->iPort->ReadCompleted(KErrNone);
+		}
+	// unfortunately the state has to decide whether the reader should be 
+	// kicked into action again or not, because there are states like the 
+	// Idle one where this is irrelevant.
+	if(aContext->ReadInBufferLowWatermarkReached())
+		{
+		// and the reader was previously stoped
+		if(!aContext->iPortReader->IsReading())
+			{
+			aContext->StartReader();
+			}
+		}
+	}
+
+void TBTPortStateOpen::DoReadCompleted(CBTPortProxy* aContext,TInt aError)
+/**
+	New data arrived from the socket to C32	
+	This method is called by the CBTportProxy when new data arrive 
+	from the socket.
+
+	This function first needs to see if there's anything that needs to 
+	be written client side.  HandleIPCWriteToClient() does the actual 
+	work of invoking the c32 IPCWrite.  
+
+	Then it checks to see if more reads to the socket should be queued or
+	whether the CBTPortProxy read-in buffer is filling up.
+**/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	aContext->iReadsPending--;
+#endif
+
+	if ((aError!=KErrNone)&&(aError!=KErrCancel))
+		{// we need to break out of here without requeueing the reader.
+		aContext->iPort->ReadCompleted(aError);
+		return;
+		}
+	if (aContext->iClientReadPtr)
+		{// we have a read queued - 
+		// need to see if we can do IPCWrite client side
+		HandleIPCWriteToClient(aContext);
+		}
+
+	// check to see if we've reached or surpased our watermark
+	if(aContext->ReadInBufferHighWatermarkReached())
+		{
+		aContext->StopReader();
+		return;
+		} 
+	// else
+	aContext->StartReader();
+
+	}
+
+void TBTPortStateOpen::HandleIPCWriteToClient(CBTPortProxy* aContext)
+/**
+	This function works out how much of the circular buffer to write back to the client. 
+	The c32 ReadCompleted() function is only invoked when the complete read has been done.
+**/
+	{
+	LOG_FUNC
+	TInt dataLenInBuf=aContext->iCircularReadBuf->Count();
+	if (dataLenInBuf==0)
+		{
+		return; //nothing to do
+		}
+
+	TInt bytesToCopy=0;
+	TPtr8& readptr=aContext->iReadBufPtr; // incoming data buffer
+	readptr.SetLength(0);
+	TUint8* ptr=CONST_CAST(TUint8*,(readptr.Ptr()));
+	TInt clientMaxLen=aContext->iClientReadLength;
+
+	// This should cover terminated reads, plain reads and some read one 
+	// or more cases		
+	if(dataLenInBuf>=clientMaxLen)		
+		{
+		// complete if possible any terminated reads for both larger or smaller 
+		// client buffers than ours
+		if(aContext->iTerminatedReads)
+			{ // try to find the terminated string
+			// bytesToCopy here can be greater than the clientMaxLen
+			// or can be -1 so we have to check
+			bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm);
+			if((bytesToCopy>clientMaxLen) || (bytesToCopy == KErrNotFound))
+				{
+				bytesToCopy=clientMaxLen;
+				}
+			// else the terminated reads complete with no terminator because 
+			// the client buffer can be filled completely.
+			}
+		else
+			{
+			// The plain reads where the client has a smaller buffer should 
+			// complete here for the same reason.
+			// Read one or more would complete anyway for this case.
+			bytesToCopy=clientMaxLen;
+			}
+		}
+	// This should cover Receive one or more for the rest of the cases
+
+	//will allow the full coverage of the high watermark case even if we do not do bounded reads
+//#define BTCOMM_TEST_HIGH_WATERMARK
+#ifndef BTCOMM_TEST_HIGH_WATERMARK
+	else if(aContext->iClientReadOneOrMore)
+		{
+		// if we reached this point it means that datLenInBuf<clientMaxLen
+		bytesToCopy=dataLenInBuf;			
+		}
+#endif
+	// Our client can handle lots of data, more than we can
+	else if(KBTCOMMCircularBufferLength<clientMaxLen)
+		{		
+		if(aContext->iClientRemainderToRead<=dataLenInBuf)
+			{ // then this is the last chunk of a multi write to client
+			if(aContext->iTerminatedReads)
+				{ // try to find the terminated string
+				// bytesToCopy here can be -1 
+				// hence we have to check
+				bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm);
+				if(bytesToCopy==KErrNotFound)
+					{// ternminator was requested but not found... what the heck
+					bytesToCopy=aContext->iClientRemainderToRead;
+					}
+				}
+			else
+				{
+				// this is the last chunk to be read for this client read
+				// write as much as needed to the client
+				bytesToCopy=aContext->iClientRemainderToRead;
+				}
+			}
+		else if(aContext->ReadInBufferHighWatermarkReached()) // to minimise IPC
+			{ 
+			if(aContext->iTerminatedReads)
+				{ // try to find the terminated string
+				// bytesToCopy here can be -1 
+				// hence we have to check
+				bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm);
+				if(bytesToCopy==KErrNotFound)
+					{// terminator was not found... but
+					// we have almost filled our buffer; write what we've got to the client
+					bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,dataLenInBuf);
+					__ASSERT_DEBUG(bytesToCopy==dataLenInBuf,PanicInState(EBTCommOpenStateWriteToClientPossibleLossOfData));
+					
+					// fill their buf as much as we can and continue
+					readptr.SetLength(bytesToCopy);
+					TInt offset=aContext->iClientWriteOffset;
+					aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset);
+					aContext->iClientRemainderToRead-=bytesToCopy;
+					aContext->iClientWriteOffset+=bytesToCopy; // offset for next write to client
+					return;	//our work is done wait for the next 
+					}
+				// else the terminator was found hence copy data up to the 
+				// terminator and complete the read 
+				}
+			else // if no terminated reads were requested but the high watermark was reached
+				{
+				// copy what we have across and keep track of the offset
+				bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,dataLenInBuf);
+				__ASSERT_DEBUG(bytesToCopy==dataLenInBuf,PanicInState(EBTCommOpenStateWriteToClientPossibleLossOfData));
+					
+				// fill their buf as much as we can and continue
+				readptr.SetLength(bytesToCopy);
+				TInt offset=aContext->iClientWriteOffset;
+				aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset);
+				aContext->iClientRemainderToRead-=bytesToCopy;
+				aContext->iClientWriteOffset+=bytesToCopy; // offset for next write to client
+				return;	//our work is done wait for the next
+				}
+			} //matches else if(aContext->ReadInBufferHighWatermarkReached())
+		// if the high watermark was not reached but we do terminated reads  
+#ifndef BTCOMM_TEST_HIGH_WATERMARK 
+		else if (aContext->iTerminatedReads) 
+			{
+			bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm);
+			}
+#endif
+		}
+	// complete if possible any terminated reads for smaller 
+	// client buffers than ours
+	else if(aContext->iTerminatedReads)
+		{ // try to find the terminated string
+		// bytesToCopy here cannot be greater than the clientMaxLen
+		bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm);
+		}	
+
+	if(bytesToCopy>KErrNone) 
+		{
+		// do the copy to the client buffer
+		TInt offset=aContext->iClientWriteOffset;
+		readptr.SetLength(bytesToCopy);
+		bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,bytesToCopy);
+		aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset);
+	
+		// reset the offsets and counters and complete the read
+		aContext->iClientReadLength=0;
+		aContext->iClientReadPtr=0;
+		aContext->iClientRemainderToRead=0;
+		aContext->iClientWriteOffset=0;  
+		
+		aContext->iPort->ReadCompleted(KErrNone);
+		}
+	}
+
+void TBTPortStateOpen::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength)
+/**
+	TBTPortState Open.
+	Store the client side ptr and length and then signal
+	start write immediately.
+**/
+	{
+	LOG_FUNC
+	// this is again due to the fact that we have to be asynchronous to avoid 
+	// deadlocks with (mostly ESock) other comms components.
+	if(aContext->IsWriteCancelPending())
+		{
+		aContext->iPort->WriteCompleted(KErrNotReady);
+		//aContext->DoWriteCancel(); a deadlock example !
+		return;
+		}
+
+	LOG(_L("**TBTPortStateOpen::Write**"));
+	aContext->iClientWritePtr=aPtr;
+	aContext->iClientWriteLength=aLength;
+	aContext->iClientLengthWrittenSoFar=aLength;
+
+	if (aLength>KBTCOMMSendBufferLength)
+		{
+		aContext->iClientLengthWrittenSoFar=KBTCOMMSendBufferLength;
+		aContext->iMoreSendsToCome=ETrue;
+		}
+	TPtr8& sendptr=aContext->iSendBufPtr;
+	sendptr.SetLength(0);
+	// now read the client side data
+	TPtr8 ptr((TUint8*)sendptr.Ptr(),0,aContext->iClientLengthWrittenSoFar);
+	aContext->iPort->IPCRead(aPtr,ptr,0);
+
+	sendptr.Append(ptr);
+	aContext->iSendBufPtr.SetLength(aContext->iClientLengthWrittenSoFar);
+	aContext->StartWriter();
+	}
+
+void TBTPortStateOpen::DoWriteCompleted(CBTPortProxy* aContext,TInt aError)
+/**
+	TBTPortStateOpen DoWriteCompleted.	
+	If there is no error here, at this point the write 
+	has successfully completed and
+	can be signalled complete back to the client code.
+**/
+	{
+	LOG_FUNC
+	if (aContext->iMoreSendsToCome)
+		{// we need to keep going 
+		LOG(_L("**TBTPortStateOpen::DoWriteCompleted - more to come**"));
+
+		TInt lentowrite=aContext->iClientWriteLength-aContext->iClientLengthWrittenSoFar;
+		TInt lensofar=aContext->iClientLengthWrittenSoFar;
+		if (lentowrite>KBTCOMMSendBufferLength)
+			{// still more to come
+			lentowrite=KBTCOMMSendBufferLength;
+			aContext->iClientLengthWrittenSoFar+=KBTCOMMSendBufferLength;
+			aContext->iMoreSendsToCome=ETrue;
+			}
+		else
+			{
+			aContext->iClientLengthWrittenSoFar+=lentowrite;
+			aContext->iMoreSendsToCome=EFalse;
+			}
+		TPtr8 sendptr=aContext->iSendBufPtr;
+		sendptr.SetLength(0);
+		// read the client side data
+		TPtr8 ptr((TUint8*)sendptr.Ptr(),0,lentowrite);
+		aContext->iPort->IPCRead(aContext->iClientWritePtr,ptr,lensofar);
+		
+		sendptr.Append(ptr);
+		aContext->iSendBufPtr.SetLength(lentowrite);
+		aContext->StartWriter();
+		}
+	else
+		{// we have finished - can signal to client and 0 the client stuff.
+		LOG(_L("**TBTPortStateOpen::DoWriteCompleted - finished**"));
+		aContext->iMoreSendsToCome=EFalse;
+		aContext->iClientLengthWrittenSoFar=0;
+		aContext->iClientWritePtr=0;                 
+		aContext->iClientWriteLength=0;
+		aContext->iPort->WriteCompleted(aError);
+		}
+	}
+
+void TBTPortStateOpen::WriteCancel(CBTPortProxy* aContext)
+/**
+	It will complete the cancelation to the client and then request it from the server.
+*/
+	{
+	LOG_FUNC
+	// do say yes you cancelled and then cancel if necessary
+	aContext->iPort->WriteCompleted(KErrCancel);
+	aContext->SetWriteCancelPending();
+	aContext->StartLocker();
+	}
+
+void TBTPortStateOpen::ReadCancel(CBTPortProxy* aContext)
+/**
+	It will complete the cancelation to the client.
+*/
+	{
+	LOG_FUNC
+#ifdef _DEBUG
+	aContext->iReadsPending--;
+#endif
+	// do say yes you cancelled and then cancel if necessary
+	aContext->iPort->ReadCompleted(KErrCancel);
+	// Read Cancel does not need to be propagated to the underlying socket
+	// since CSY has a ring buffer which is filled with inbound data regardless
+	// of what the upper app is up to with its RComm
+	}
+
+void TBTPortStateOpen::DoLockedAction(CBTPortProxy* aContext)
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)	
+		{
+		aContext->StopLocker();
+		Error(aContext,ret);
+		return;
+		}
+	if(aContext->IsWriteCancelPending())
+		{
+		aContext->DoWriteCancel(); // the locked action for which we came in here
+		}
+	else //default handle - stray event must be caught
+		{
+		((TBTPortDefaultState*)this)->DoLockedAction(aContext);
+		}
+	aContext->StopLocker();
+	//NOTE: we remain in this state
+	}
+
+void TBTPortStateOpen::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+//		***** Closing state *****
+
+TBTPortStateClosing::TBTPortStateClosing(CBTPortStateFactory* aParent)
+	: TBTPortCommonBaseState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortStateClosing::~TBTPortStateClosing()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateClosing::Close(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateClosing::Read(CBTPortProxy* aContext, TAny* aPtr,TInt aLength)
+/**
+	Read in this state indirectly calls the DoLockedAction to get out and in the state machine again.
+	This is done because of the huge window of opportunity for race conditions
+	while the async timer is ticking before shutdown. Since we need the 
+	shutdown timer for the closing to be async (to avoid deadlocks with Etel etc), 
+	hence we should close the socket etc and transfer the Read() to the
+	Idle state.
+*/
+	{
+	LOG_FUNC
+	
+	LOG(_L("**TBTPortStateClosing Canceling the shutdown timer **"));
+	aContext->CancelShutDownTimer();
+	
+	// cache the read
+	aContext->iClientReadPtr=aPtr;
+	aContext->iClientReadLength=aLength;
+	aContext->iClientRemainderToRead=aLength;
+	// close sockets resolver etc	
+	aContext->StartLocker(); // next call is to our DoLockedAction(..);	
+	// we now know that someone re-opened us while going down so...
+	// transfer the call
+	}
+
+void TBTPortStateClosing::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength)
+/**
+	Write in this state indirectly calls the DoLockedAction to get out and in the state machine again.
+	This is done because of the huge window of opportunity for race conditions
+	while the async timer is ticking before shutdown. Since we need the 
+	shutdown timer for the closing to be async (to avoid deadlocks with Etel etc), 
+	hence we should close the socket etc and transfer the write() to the
+	Idle state.
+*/
+	{
+	LOG_FUNC
+
+	LOG(_L("**TBTPortStateClosing Canceling the shutdown timer **"));
+	aContext->CancelShutDownTimer();
+
+	// cache the write
+	aContext->iClientWritePtr=aPtr;
+	aContext->iClientWriteLength=aLength;
+	aContext->iClientLengthWrittenSoFar=aLength;
+	
+	// close sockets resolver etc
+	//next call is in our DoLockedAction(..);
+	aContext->StartLocker();
+	// we now know that someone re-opened us while going down so...
+	// transfer the call
+	}
+
+void TBTPortStateClosing::DoRunL(CBTPortProxy* aContext)
+/**
+	At this point our socket shutdown has returned.
+	We can now close down the host resolver, netdb and finally
+	the session to the socket server itself.  These are all 
+	synchronous actions so must be handled by the locker.
+
+	But we need to defer the actual completion of the final closing for later
+	in order to give some time for other components like Etel to close first.
+	Note the values used here are arbitrary and should be considered a 
+	hacked fix :-(.
+
+  	NOTE: the next transition is in TBTPortStateClosing::DoLockedAction 
+	      unless the shutdown timer is cancelled by a new read or write 
+**/
+	{
+	LOG_FUNC
+	TInt ret=aContext->iStatus.Int();
+	if (ret!=KErrNone)
+		{// didn't manage to succeed with socket shutdown somehow.
+		LOG(_L("**TBTPortStateClosing Closing with an error !**"));
+		aContext->StartShutdownTimerL();// this will eventually call aContext->StartLocker()
+		}
+	else
+		{// we have successfully shutdown the socket.
+		aContext->StartShutdownTimerL();// this will eventually call aContext->StartLocker()		
+		}
+	//NOTE: the next transition is in TBTPortStateClosing::DoLockedAction 
+	//      unless the shutdown timer is cancelled by a new read or write     
+	}
+
+void TBTPortStateClosing::DoLockedAction(CBTPortProxy* aContext)
+/**
+	TBTPortStateClosing DoLockedAction.
+	At this point we have obtained the lock hence we are able to undertake
+	the locked actions.
+	This method should be called indirectly by the shutdown timer or due to
+	a previous WriteCancel call at the open state, followed by a 
+	Close() call ( which brought as here in this state).
+**/
+	{
+	LOG_FUNC
+	if(aContext->IsWriteCancelPending())
+		{
+		LOG(_L("**TBTPortStateClosing::DoLockedAction -- Servicing Write cancelations first**"));
+		aContext->DoWriteCancel(); // the locked action for which we came in here
+		aContext->StopLocker();
+		return;
+		}
+		
+	if(aContext->IsNetDbInUse())
+		{
+		// we need this in the case of cancelation before the netdb.Open()
+		// because the kernel will panic us if it doesn't find the session
+		RNetDatabase& netdb=aContext->iNetDatabase;
+		netdb.Cancel();
+		netdb.Close();
+		aContext->SetNetDbNotInUse();
+		LOG(_L("**TBTPortStateClosing, NetDB session clean-up done **"));
+		}
+
+	// the following immediate shutdown will not stiff C32 and is needed for 
+	// the next close to be possible in ESock without it being blocked waiting
+	// for the protocol SAP to be cleaned
+	//
+	// This shutdown will cause any outstanding socket ops to be cancelled so
+	// we can safely call aContext->Cancel() afterwards.
+	if(aContext->iSocket.SubSessionHandle())
+		{// Make sure we had managed to open the socket connection before we arriveed here		
+		aContext->iSocket.Shutdown(RSocket::EImmediate,aContext->iStatus);
+		User::WaitForRequest(aContext->iStatus); 
+		}
+		
+	// Do BT CSY specific locked action.
+  	aContext->iSocket.Close();
+
+	// We can only make synch calls to ESock from within the locker, otherwise 
+	// we risk deadlock.  This means we can't put any Cancel()s that may end
+	// up in ESock in the port proxy's DoCancel() unless we guarantee that Cancel()
+	// can only be called from within the locker.  Instead we ensure we've done
+	// all the necessary cancelling before calling Cancel().
+	aContext->Cancel();
+   
+
+	// We should never transition to the closing state whilst waiting for
+	// an ESock connection, unless I've bugged the state machine.
+	__ASSERT_DEBUG(!aContext->iSockServConnector->IsActive(), PanicInState(EBTCommCloseWhileWaitingForSockServHandle));
+
+   	if(aContext->iSockServ.Handle())
+   		{
+  		aContext->iSockServ.Close();
+   		}
+   	aContext->StopLocker();	// sync actions completed ok - now stop locker.
+
+	// we do this just before destruction, just in case someone has reopened us
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EIdle));
+	// UGLY
+	aContext->DestructContext(); // will not do anything if we got reopened
+	}
+
+void TBTPortStateClosing::DoWriteCompleted(CBTPortProxy * /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateClosing::DoReadCompleted(CBTPortProxy * /*aContext*/, TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortStateClosing::LogStateError(CBTPortProxy * /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+
+// Error State
+
+TBTPortErrorState::TBTPortErrorState(CBTPortStateFactory* aParent) 
+	: TBTPortState(aParent)
+	{
+	LOG_FUNC
+	}
+
+TBTPortErrorState::~TBTPortErrorState()
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::Open(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::Read(CBTPortProxy* aContext,TAny* /*aPtr*/,TInt /*aLength*/)
+/**
+	Notify the client about this recent error.
+*/	
+	{
+	LOG_FUNC
+	aContext->iPort->ReadCompleted(aContext->iLastError);
+	}
+
+void TBTPortErrorState::Write(CBTPortProxy* aContext,TAny* /*aPtr*/,TInt /*aLength*/)
+/**
+	Notify the client about this recent error.
+*/	
+	{
+	LOG_FUNC
+	aContext->iPort->WriteCompleted(aContext->iLastError);
+	}
+
+void TBTPortErrorState::Close(CBTPortProxy* aContext)
+	{
+	LOG_FUNC
+	aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing));
+		
+	// check to see if the error came before we managed to do the locked action 
+	// ..and cancel the pending locked action then
+	if(aContext->IsLockerOn()) 
+		{            
+		aContext->StopLocker();
+		}
+	aContext->SetActive();
+	TRequestStatus* pStatus = &(aContext->iStatus);
+	User::RequestComplete(pStatus, KErrNone); 
+	}
+
+void TBTPortErrorState::DoRunL(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::DoCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::WriteCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::ReadCancel(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::DoLockedAction(CBTPortProxy* /*aContext*/)
+	{
+	LOG_FUNC
+	BAD_BTCOMM_EVENT
+	}
+
+void TBTPortErrorState::DoWriteCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::DoReadCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/)
+	{
+	LOG_FUNC
+	}
+
+void TBTPortErrorState::Error(CBTPortProxy* aContext,TInt aError)
+/**
+	Error will be the first method to be called in entering this state.
+	So here Error will check to see if there are any Queued reads, which 
+	it will immediately complete.
+	
+	This should only be called on moving from any other state to the error 
+	state and not otherwise.
+ */
+	{
+	LOG_FUNC
+	if (aContext->iClientReadPtr)
+		{ // this means that a read was queued already so we need to signal 
+		  // the error immediately
+		aContext->iPort->ReadCompleted(aError);		
+		}
+	if (aContext->iClientWritePtr)
+		{ // same for write
+		aContext->iPort->WriteCompleted(aError);
+		}
+	}
+