bluetooth/btstack/avdtp/avdtpTransportSession.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avdtp/avdtpTransportSession.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,496 @@
+// Copyright (c) 2003-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:
+// Implements the avdtp transport session base class
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include <bluetoothav.h>
+#include "avdtpTransportSession.h"
+#include "avdtp.h"
+#include "avdtpsap.h"
+#include "avdtpStream.h"
+#include "avdtpSignallingChannel.h"
+#include "avdtputil.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
+#endif
+
+CTransportSession::CTransportSession(CAvdtpProtocol& aProtocol,
+									 CAvdtpSAP& aSAP,
+									 TAvdtpTransportSessionType aSessionType)
+: iSAP(aSAP), iProtocol(aProtocol), iSAPShutdown(ENone)
+	{
+	LOG_FUNC
+	iAddress.SetSession(aSessionType);
+	}
+
+CTransportSession::~CTransportSession()
+	{
+	LOG_FUNC
+	}
+	
+void CTransportSession::ConstructL()
+	{
+	LOG_FUNC
+	// put any common stuff here
+	}
+
+void CTransportSession::FastShutdown()
+	{
+	LOG_FUNC
+	// just note whether we need to tell sap later or now to close
+	iSAP.DetachSession();
+	
+	iSAPShutdown = EImmediate;
+	// and proceed normally - we now own ourselves...
+	DoShutdown();
+	}
+	
+void CTransportSession::Shutdown()
+	{
+	LOG_FUNC
+	iSAPShutdown = ENormal;
+	// and proceed normally - we now own ourselves...
+	DoShutdown();
+	}
+	
+TInt CTransportSession::GetOption(TUint /*aLevel*/, TUint /*aName*/, TDes8& /*aOption*/) const
+	{
+	LOG_FUNC
+	return KErrNotSupported;
+	}
+	
+TInt CTransportSession::SetOption(TUint /*aLevel*/, TUint /*aName*/, const TDesC8& /*aOption*/)
+	{
+	LOG_FUNC
+	return KErrNotSupported;
+	}
+	
+void CTransportSession::Start()
+	{
+	LOG_FUNC
+	//gulp
+	}
+	
+void CTransportSession::Ioctl(TUint /*aLevel*/, TUint /*aName*/, const TDesC8* /*aOption*/)
+	{
+	LOG_FUNC
+	// default is to error as not supported
+	iSAP.Error(KErrNotSupported);
+	}
+	
+void CTransportSession::CancelIoctl(TUint /*aLevel*/, TUint /*aName*/)
+	{
+	LOG_FUNC
+	// do nothing
+	}
+
+/**
+Stream says this session is ready
+Record the address we're serving and tell user
+*/
+void CTransportSession::Ready(const TBTDevAddr& aRemoteDev)
+	{
+	LOG_FUNC
+	iAddress.SetBTAddr(aRemoteDev);
+	iSAP.Ready();
+	}
+	
+	
+void CTransportSession::LocalName(TAvdtpSockAddr& aAddr) const
+	{
+	LOG_FUNC
+	// in this current design, local=remote
+	RemName(aAddr);
+	}
+	
+void CTransportSession::RemName(TAvdtpSockAddr& aAddr) const
+	{
+	LOG_FUNC
+	// in this current design, local=remote
+	aAddr = iAddress;
+	}
+	
+TInt CTransportSession::SetLocalName(TAvdtpSockAddr& aAddr)
+	{
+	LOG_FUNC
+	// in this current design, local=remote
+	return SetRemoteName(aAddr);
+	}
+	
+TInt CTransportSession::SetRemoteName(TAvdtpSockAddr& aAddr)
+	{
+	LOG_FUNC
+	// can't trample of session type - that's immutable
+	aAddr.SetSession(SessionType());
+	iAddress = aAddr;
+	return KErrNone;
+	}
+	
+	
+RPacketPool::RPacketPool()
+	{
+	LOG_FUNC
+	}
+
+TInt RPacketPool::Create(TUint aSize, TBool aBalk)
+	{
+	LOG_FUNC
+	LOG2(_L("Creating packet pool, size %d, balk %d"), aSize, aBalk);
+	__ASSERT_DEBUG(iPool.Count()==0, Panic(EAvdtpTransportSessionPacketPoolNotZeroSize));
+	iNewestIndex=0;
+	TInt res = AllocatePool(aSize);
+	if (res==KErrNone)
+		{
+		iBalk=aBalk;
+		}
+	return res;
+	}
+
+TInt RPacketPool::AllocatePool(TUint aSize)
+	{
+	LOG_FUNC
+	TRAPD(err,AllocatePoolL(aSize));	
+	return err;
+	}
+
+void RPacketPool::AllocatePoolL(TUint aSize)
+	{
+	LOG_FUNC
+	// allocates the size requested or fails
+	for (TUint count = 0; count<aSize; count++)
+		{
+		CreateEntryL();
+		}
+	}
+
+/**
+Add a chain into the pool. Wrapping if necessary.  Cannot fail since the creation preallocated the chains.
+*Can* return an error though if wrap would occur 
+*/
+TInt RPacketPool::Add(RMBufChain& aChain, TInt& aWrappedChainSize)
+	{
+	LOG_FUNC
+	TInt res = KErrNone;
+	if (iNewestIndex==(iPool.Count()-1) && !iBalk)
+		{
+		LOG(_L("No balking allowed, and no space - return KErrAvdtpPacketPoolBalk"));
+		// last position filled, but balking not allowed, return error
+		res = KErrAvdtpPacketPoolBalk;
+		}
+	else if (iNewestIndex==(iPool.Count()))
+		{
+		LOG(_L("Balking allowed, and no space - wrapping"));
+		// can wrap
+		__ASSERT_DEBUG(iBalk, Panic(EAvdtpTransportSessionPacketBalkingNotSet));
+		iNewestIndex=0;
+		}
+	if (res==KErrNone)
+		{
+		// if we've wrapped the chain in the array needs destroying
+		RMBufChain& inPool = iPool[iNewestIndex];
+		
+		if (!inPool.IsEmpty())
+			{
+			// The size of the chain dropped
+			aWrappedChainSize = inPool.Length();
+			inPool.Free();
+			}
+			
+		LOG2(_L("Taking ownership of Chain. NewestIndex=%d, OldestIndex=%d"), iNewestIndex, OldestIndex())
+		inPool.Assign(aChain);
+
+		// move newest index, and check where oldest index is now
+		if (++iNewestIndex == iOldestIndex)
+			{
+			// wrapped (in terms of age rather than array bounds)
+			iOldestIndex = iNewestIndex-1;
+			// might have wrapped that off (nb this is a TUint hence logic)
+			if (iOldestIndex>Count()-1)
+				{
+				iOldestIndex = Count()-1;
+				}
+			}		
+		}
+	return res;
+	}
+	
+TInt RPacketPool::OldestIndex() const
+	{
+	LOG_FUNC
+	// if balking, one in front of the newest index (modulo poolsize). else zeroth
+	return iOldestIndex;
+	}
+	
+TInt RPacketPool::Remove(RMBufChain& aReturnedMBufChain)
+	{
+	LOG_FUNC
+	LOG(_L("Removing oldest packet"));
+	// return the oldest chain to the client
+	aReturnedMBufChain.Assign(iPool[OldestIndex()]);
+	// move the oldestindex on, modulo poolsize
+	++iOldestIndex;
+	iOldestIndex %= iPool.Count();
+	LOG1(_L("Oldest packet index = %d"), OldestIndex());
+	return KErrNone;
+	}
+	
+void RPacketPool::Close()
+	{
+	LOG_FUNC
+	while (iPool.Count())
+		{
+		// delete the head entry each time
+		DestroyEntry(0);
+		}
+	iPool.Close();
+	}
+
+void RPacketPool::DestroyEntry(TUint aIndex)
+	{
+	LOG_FUNC
+	iPool[aIndex].Free();
+	iPool.Remove(aIndex);
+	}
+
+void RPacketPool::CreateEntryL()
+	{
+	LOG_FUNC
+	RMBufChain chain;
+	// don't need to alloc the chains as the entries claim ownership of inbound ones
+	TInt err = iPool.Append(chain);
+	if (err!=KErrNone)
+		{
+		chain.Free();
+		User::Leave(err);
+		}
+	}
+	
+TInt RPacketPool::Resize(TUint aSize)
+	{
+	LOG_FUNC
+	TInt res = KErrNone;
+	// try to grow/shrink the pool
+	if (aSize<iPool.Count())
+		{
+		LOG1(_L("Reducing pool to %d entries"), aSize);
+		// throw away any packets (whatever age) if we need to
+		for (TUint index = iPool.Count()-1;index>=(aSize-1);index--)
+			{
+			DestroyEntry(index);
+			}
+		}
+	else if (aSize > iPool.Count())
+		{
+		LOG1(_L("Growing pool to %d entries"), aSize);
+		// grow if possible
+		for (TUint index=0;index<(aSize-iPool.Count());index++)
+			{
+			TRAP(res,CreateEntryL());
+			}
+		}
+	if (res==KErrNone)
+		{
+		LOG(_L("Resize sucessful"));
+		iOldestIndex = 0;
+		iNewestIndex = iOldestIndex;
+		}
+	return res;
+	}
+
+CUserPlaneTransportSession::CUserPlaneTransportSession(CAvdtpProtocol& aProtocol,
+					  CAvdtpSAP& aSAP,
+					  TAvdtpTransportSessionType aType,
+					  CAVStream& aStream)
+: CTransportSession(aProtocol,aSAP, aType), iStream(&aStream)
+	{
+	LOG_FUNC
+	SetSEID(iStream->RemoteSEID());
+	};
+	
+
+void CUserPlaneTransportSession::ConstructL()
+	{
+	LOG_FUNC
+	// acquire TSID from stream or by ourselves
+	iStream->GetTSID(iTSID, SessionType());
+	// we don't need a TSID if not muxing
+	}
+
+
+TInt CUserPlaneTransportSession::ActiveOpen()
+	{
+	// check for race - between an ACP stream establishment, and GAVDP attaching
+	// sessions, the stream may have been released... so check if still there
+	// if so, forward active open to derivers
+	TAvdtpSockAddr addr;
+	RemName(addr);
+	
+	return iProtocol.FindStream(addr) ? DoActiveOpen() : KErrDisconnected;
+	}
+	
+
+void CUserPlaneTransportSession::ReceivePacketLost()
+	{
+	// Default impl.  No action taken.
+	}
+
+void CUserPlaneTransportSession::NewData(RMBufChain& aChain)
+	{
+	LOG_FUNC
+	
+	if (EImmediate != iSAPShutdown)
+		{
+		TInt wrapped; // Used to indicate if packet pool wrapped around
+		TInt poolErr = iReceivePool.Add(aChain, wrapped);
+		if (poolErr==KErrNone)
+			{
+			iSAP.NewData(1);
+			}
+		else
+			{
+			// The data can't be added to the revc pool.  Free the chain
+			// and notify the base session (i.e., media, reporting, recovery)
+			// that a data packet has been dropped.
+			aChain.Free();
+			ReceivePacketLost();
+			}
+		}
+	else 
+		{
+		//Fast Shutdown in progress, do not pass any more data to the socket.
+		//therefore free the chain.
+		aChain.Free();
+		}
+	}
+
+TInt CUserPlaneTransportSession::GetData(RMBufChain& aData)
+	{
+	LOG_FUNC
+	// fetch from pool
+	return iReceivePool.Remove(aData);
+	}
+
+
+/**
+we handle the channelerror, rather than the channel
+as we do not want to necessarily abandon ALL *streams* to the same remote
+just because one channel errored
+*/
+void CUserPlaneTransportSession::ChannelError(TInt aError)
+	{
+	LOG_FUNC
+	if (iStream)
+		{
+		// this transport session is a user-plane one
+		__ASSERT_DEBUG(SessionType()!=ESignalling, Panic(EAvdtpBadTransportSessionUpcallFromTransportChannel));
+		iStream->NotifyUserPlaneTransportSessionsError(this, aError);
+		iStream = NULL;
+		LeaveTransportChannel();
+		}
+	// else the stream has gone from an earlier Release, and we're still here for client
+	}
+	
+void CUserPlaneTransportSession::StreamError(TInt aError)
+	{
+	LOG_FUNC
+	if (iStream)
+		{
+		iStream->ClearSession(*this);//this will cause the iSession pointer in the stream to be null'd
+		}
+	// backcall from stream - default is to unbind and pass onto SAP
+	iStream = NULL;
+	if (iSAPShutdown!=EImmediate)
+		{
+		iSAP.Error(aError);
+		iSAP.SessionDisconnect();
+		}
+	LeaveTransportChannel();
+	}
+	
+
+void CUserPlaneTransportSession::DoShutdown()
+	{
+	LOG_FUNC
+	if (iStream)
+		{
+		// remove ourselves from the stream
+		iStream->DropSession(SessionType(), *this);
+		iStream = NULL;
+		}
+	else
+		{
+		/* If we don't have a stream pointer, then the logical channel underneath
+		us has gone away, and we've just been detached from the socket, so we need
+		to delete ourself */
+		StreamReleased();
+		}
+	}
+
+/*
+Called from stream after Release has completed
+*/
+void CUserPlaneTransportSession::StreamReleased()
+	{
+	LOG_FUNC
+	LeaveTransportChannel();
+
+	switch (iSAPShutdown)
+		{
+		case ENormal:	
+		iSAP.CanClose();
+		break;
+		
+		case EImmediate:
+		delete this;
+		break;
+		
+		case ENone:
+		iStream = NULL;
+		iSAP.SessionDisconnect();
+		break;
+		}
+	}
+
+void CUserPlaneTransportSession::LeaveTransportChannel()
+	{
+	LOG_FUNC
+	if (iTransportChannel)
+		{
+		// he session is now removed from the stream
+		// time to detach from the channel
+		iTransportChannel->DetachTransportSession(*this, SessionType());
+		iTransportChannel = NULL;
+		}
+	}
+
+
+CUserPlaneTransportSession::~CUserPlaneTransportSession()
+	{
+	LOG_FUNC
+	if (iStream)
+		{
+		iStream->ClearSession(*this);//this will cause the iSession pointer in the stream to be null'd
+		}
+	iTSID.Close();
+	iSendPool.Close();
+	iReceivePool.Close();
+	}