bluetooth/btstack/avdtp/avdtpTransportSession.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements the avdtp transport session base class
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20  @internalComponent
       
    21 */
       
    22 
       
    23 #include <bluetooth/logger.h>
       
    24 #include <bluetoothav.h>
       
    25 #include "avdtpTransportSession.h"
       
    26 #include "avdtp.h"
       
    27 #include "avdtpsap.h"
       
    28 #include "avdtpStream.h"
       
    29 #include "avdtpSignallingChannel.h"
       
    30 #include "avdtputil.h"
       
    31 
       
    32 #ifdef __FLOG_ACTIVE
       
    33 _LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
       
    34 #endif
       
    35 
       
    36 CTransportSession::CTransportSession(CAvdtpProtocol& aProtocol,
       
    37 									 CAvdtpSAP& aSAP,
       
    38 									 TAvdtpTransportSessionType aSessionType)
       
    39 : iSAP(aSAP), iProtocol(aProtocol), iSAPShutdown(ENone)
       
    40 	{
       
    41 	LOG_FUNC
       
    42 	iAddress.SetSession(aSessionType);
       
    43 	}
       
    44 
       
    45 CTransportSession::~CTransportSession()
       
    46 	{
       
    47 	LOG_FUNC
       
    48 	}
       
    49 	
       
    50 void CTransportSession::ConstructL()
       
    51 	{
       
    52 	LOG_FUNC
       
    53 	// put any common stuff here
       
    54 	}
       
    55 
       
    56 void CTransportSession::FastShutdown()
       
    57 	{
       
    58 	LOG_FUNC
       
    59 	// just note whether we need to tell sap later or now to close
       
    60 	iSAP.DetachSession();
       
    61 	
       
    62 	iSAPShutdown = EImmediate;
       
    63 	// and proceed normally - we now own ourselves...
       
    64 	DoShutdown();
       
    65 	}
       
    66 	
       
    67 void CTransportSession::Shutdown()
       
    68 	{
       
    69 	LOG_FUNC
       
    70 	iSAPShutdown = ENormal;
       
    71 	// and proceed normally - we now own ourselves...
       
    72 	DoShutdown();
       
    73 	}
       
    74 	
       
    75 TInt CTransportSession::GetOption(TUint /*aLevel*/, TUint /*aName*/, TDes8& /*aOption*/) const
       
    76 	{
       
    77 	LOG_FUNC
       
    78 	return KErrNotSupported;
       
    79 	}
       
    80 	
       
    81 TInt CTransportSession::SetOption(TUint /*aLevel*/, TUint /*aName*/, const TDesC8& /*aOption*/)
       
    82 	{
       
    83 	LOG_FUNC
       
    84 	return KErrNotSupported;
       
    85 	}
       
    86 	
       
    87 void CTransportSession::Start()
       
    88 	{
       
    89 	LOG_FUNC
       
    90 	//gulp
       
    91 	}
       
    92 	
       
    93 void CTransportSession::Ioctl(TUint /*aLevel*/, TUint /*aName*/, const TDesC8* /*aOption*/)
       
    94 	{
       
    95 	LOG_FUNC
       
    96 	// default is to error as not supported
       
    97 	iSAP.Error(KErrNotSupported);
       
    98 	}
       
    99 	
       
   100 void CTransportSession::CancelIoctl(TUint /*aLevel*/, TUint /*aName*/)
       
   101 	{
       
   102 	LOG_FUNC
       
   103 	// do nothing
       
   104 	}
       
   105 
       
   106 /**
       
   107 Stream says this session is ready
       
   108 Record the address we're serving and tell user
       
   109 */
       
   110 void CTransportSession::Ready(const TBTDevAddr& aRemoteDev)
       
   111 	{
       
   112 	LOG_FUNC
       
   113 	iAddress.SetBTAddr(aRemoteDev);
       
   114 	iSAP.Ready();
       
   115 	}
       
   116 	
       
   117 	
       
   118 void CTransportSession::LocalName(TAvdtpSockAddr& aAddr) const
       
   119 	{
       
   120 	LOG_FUNC
       
   121 	// in this current design, local=remote
       
   122 	RemName(aAddr);
       
   123 	}
       
   124 	
       
   125 void CTransportSession::RemName(TAvdtpSockAddr& aAddr) const
       
   126 	{
       
   127 	LOG_FUNC
       
   128 	// in this current design, local=remote
       
   129 	aAddr = iAddress;
       
   130 	}
       
   131 	
       
   132 TInt CTransportSession::SetLocalName(TAvdtpSockAddr& aAddr)
       
   133 	{
       
   134 	LOG_FUNC
       
   135 	// in this current design, local=remote
       
   136 	return SetRemoteName(aAddr);
       
   137 	}
       
   138 	
       
   139 TInt CTransportSession::SetRemoteName(TAvdtpSockAddr& aAddr)
       
   140 	{
       
   141 	LOG_FUNC
       
   142 	// can't trample of session type - that's immutable
       
   143 	aAddr.SetSession(SessionType());
       
   144 	iAddress = aAddr;
       
   145 	return KErrNone;
       
   146 	}
       
   147 	
       
   148 	
       
   149 RPacketPool::RPacketPool()
       
   150 	{
       
   151 	LOG_FUNC
       
   152 	}
       
   153 
       
   154 TInt RPacketPool::Create(TUint aSize, TBool aBalk)
       
   155 	{
       
   156 	LOG_FUNC
       
   157 	LOG2(_L("Creating packet pool, size %d, balk %d"), aSize, aBalk);
       
   158 	__ASSERT_DEBUG(iPool.Count()==0, Panic(EAvdtpTransportSessionPacketPoolNotZeroSize));
       
   159 	iNewestIndex=0;
       
   160 	TInt res = AllocatePool(aSize);
       
   161 	if (res==KErrNone)
       
   162 		{
       
   163 		iBalk=aBalk;
       
   164 		}
       
   165 	return res;
       
   166 	}
       
   167 
       
   168 TInt RPacketPool::AllocatePool(TUint aSize)
       
   169 	{
       
   170 	LOG_FUNC
       
   171 	TRAPD(err,AllocatePoolL(aSize));	
       
   172 	return err;
       
   173 	}
       
   174 
       
   175 void RPacketPool::AllocatePoolL(TUint aSize)
       
   176 	{
       
   177 	LOG_FUNC
       
   178 	// allocates the size requested or fails
       
   179 	for (TUint count = 0; count<aSize; count++)
       
   180 		{
       
   181 		CreateEntryL();
       
   182 		}
       
   183 	}
       
   184 
       
   185 /**
       
   186 Add a chain into the pool. Wrapping if necessary.  Cannot fail since the creation preallocated the chains.
       
   187 *Can* return an error though if wrap would occur 
       
   188 */
       
   189 TInt RPacketPool::Add(RMBufChain& aChain, TInt& aWrappedChainSize)
       
   190 	{
       
   191 	LOG_FUNC
       
   192 	TInt res = KErrNone;
       
   193 	if (iNewestIndex==(iPool.Count()-1) && !iBalk)
       
   194 		{
       
   195 		LOG(_L("No balking allowed, and no space - return KErrAvdtpPacketPoolBalk"));
       
   196 		// last position filled, but balking not allowed, return error
       
   197 		res = KErrAvdtpPacketPoolBalk;
       
   198 		}
       
   199 	else if (iNewestIndex==(iPool.Count()))
       
   200 		{
       
   201 		LOG(_L("Balking allowed, and no space - wrapping"));
       
   202 		// can wrap
       
   203 		__ASSERT_DEBUG(iBalk, Panic(EAvdtpTransportSessionPacketBalkingNotSet));
       
   204 		iNewestIndex=0;
       
   205 		}
       
   206 	if (res==KErrNone)
       
   207 		{
       
   208 		// if we've wrapped the chain in the array needs destroying
       
   209 		RMBufChain& inPool = iPool[iNewestIndex];
       
   210 		
       
   211 		if (!inPool.IsEmpty())
       
   212 			{
       
   213 			// The size of the chain dropped
       
   214 			aWrappedChainSize = inPool.Length();
       
   215 			inPool.Free();
       
   216 			}
       
   217 			
       
   218 		LOG2(_L("Taking ownership of Chain. NewestIndex=%d, OldestIndex=%d"), iNewestIndex, OldestIndex())
       
   219 		inPool.Assign(aChain);
       
   220 
       
   221 		// move newest index, and check where oldest index is now
       
   222 		if (++iNewestIndex == iOldestIndex)
       
   223 			{
       
   224 			// wrapped (in terms of age rather than array bounds)
       
   225 			iOldestIndex = iNewestIndex-1;
       
   226 			// might have wrapped that off (nb this is a TUint hence logic)
       
   227 			if (iOldestIndex>Count()-1)
       
   228 				{
       
   229 				iOldestIndex = Count()-1;
       
   230 				}
       
   231 			}		
       
   232 		}
       
   233 	return res;
       
   234 	}
       
   235 	
       
   236 TInt RPacketPool::OldestIndex() const
       
   237 	{
       
   238 	LOG_FUNC
       
   239 	// if balking, one in front of the newest index (modulo poolsize). else zeroth
       
   240 	return iOldestIndex;
       
   241 	}
       
   242 	
       
   243 TInt RPacketPool::Remove(RMBufChain& aReturnedMBufChain)
       
   244 	{
       
   245 	LOG_FUNC
       
   246 	LOG(_L("Removing oldest packet"));
       
   247 	// return the oldest chain to the client
       
   248 	aReturnedMBufChain.Assign(iPool[OldestIndex()]);
       
   249 	// move the oldestindex on, modulo poolsize
       
   250 	++iOldestIndex;
       
   251 	iOldestIndex %= iPool.Count();
       
   252 	LOG1(_L("Oldest packet index = %d"), OldestIndex());
       
   253 	return KErrNone;
       
   254 	}
       
   255 	
       
   256 void RPacketPool::Close()
       
   257 	{
       
   258 	LOG_FUNC
       
   259 	while (iPool.Count())
       
   260 		{
       
   261 		// delete the head entry each time
       
   262 		DestroyEntry(0);
       
   263 		}
       
   264 	iPool.Close();
       
   265 	}
       
   266 
       
   267 void RPacketPool::DestroyEntry(TUint aIndex)
       
   268 	{
       
   269 	LOG_FUNC
       
   270 	iPool[aIndex].Free();
       
   271 	iPool.Remove(aIndex);
       
   272 	}
       
   273 
       
   274 void RPacketPool::CreateEntryL()
       
   275 	{
       
   276 	LOG_FUNC
       
   277 	RMBufChain chain;
       
   278 	// don't need to alloc the chains as the entries claim ownership of inbound ones
       
   279 	TInt err = iPool.Append(chain);
       
   280 	if (err!=KErrNone)
       
   281 		{
       
   282 		chain.Free();
       
   283 		User::Leave(err);
       
   284 		}
       
   285 	}
       
   286 	
       
   287 TInt RPacketPool::Resize(TUint aSize)
       
   288 	{
       
   289 	LOG_FUNC
       
   290 	TInt res = KErrNone;
       
   291 	// try to grow/shrink the pool
       
   292 	if (aSize<iPool.Count())
       
   293 		{
       
   294 		LOG1(_L("Reducing pool to %d entries"), aSize);
       
   295 		// throw away any packets (whatever age) if we need to
       
   296 		for (TUint index = iPool.Count()-1;index>=(aSize-1);index--)
       
   297 			{
       
   298 			DestroyEntry(index);
       
   299 			}
       
   300 		}
       
   301 	else if (aSize > iPool.Count())
       
   302 		{
       
   303 		LOG1(_L("Growing pool to %d entries"), aSize);
       
   304 		// grow if possible
       
   305 		for (TUint index=0;index<(aSize-iPool.Count());index++)
       
   306 			{
       
   307 			TRAP(res,CreateEntryL());
       
   308 			}
       
   309 		}
       
   310 	if (res==KErrNone)
       
   311 		{
       
   312 		LOG(_L("Resize sucessful"));
       
   313 		iOldestIndex = 0;
       
   314 		iNewestIndex = iOldestIndex;
       
   315 		}
       
   316 	return res;
       
   317 	}
       
   318 
       
   319 CUserPlaneTransportSession::CUserPlaneTransportSession(CAvdtpProtocol& aProtocol,
       
   320 					  CAvdtpSAP& aSAP,
       
   321 					  TAvdtpTransportSessionType aType,
       
   322 					  CAVStream& aStream)
       
   323 : CTransportSession(aProtocol,aSAP, aType), iStream(&aStream)
       
   324 	{
       
   325 	LOG_FUNC
       
   326 	SetSEID(iStream->RemoteSEID());
       
   327 	};
       
   328 	
       
   329 
       
   330 void CUserPlaneTransportSession::ConstructL()
       
   331 	{
       
   332 	LOG_FUNC
       
   333 	// acquire TSID from stream or by ourselves
       
   334 	iStream->GetTSID(iTSID, SessionType());
       
   335 	// we don't need a TSID if not muxing
       
   336 	}
       
   337 
       
   338 
       
   339 TInt CUserPlaneTransportSession::ActiveOpen()
       
   340 	{
       
   341 	// check for race - between an ACP stream establishment, and GAVDP attaching
       
   342 	// sessions, the stream may have been released... so check if still there
       
   343 	// if so, forward active open to derivers
       
   344 	TAvdtpSockAddr addr;
       
   345 	RemName(addr);
       
   346 	
       
   347 	return iProtocol.FindStream(addr) ? DoActiveOpen() : KErrDisconnected;
       
   348 	}
       
   349 	
       
   350 
       
   351 void CUserPlaneTransportSession::ReceivePacketLost()
       
   352 	{
       
   353 	// Default impl.  No action taken.
       
   354 	}
       
   355 
       
   356 void CUserPlaneTransportSession::NewData(RMBufChain& aChain)
       
   357 	{
       
   358 	LOG_FUNC
       
   359 	
       
   360 	if (EImmediate != iSAPShutdown)
       
   361 		{
       
   362 		TInt wrapped; // Used to indicate if packet pool wrapped around
       
   363 		TInt poolErr = iReceivePool.Add(aChain, wrapped);
       
   364 		if (poolErr==KErrNone)
       
   365 			{
       
   366 			iSAP.NewData(1);
       
   367 			}
       
   368 		else
       
   369 			{
       
   370 			// The data can't be added to the revc pool.  Free the chain
       
   371 			// and notify the base session (i.e., media, reporting, recovery)
       
   372 			// that a data packet has been dropped.
       
   373 			aChain.Free();
       
   374 			ReceivePacketLost();
       
   375 			}
       
   376 		}
       
   377 	else 
       
   378 		{
       
   379 		//Fast Shutdown in progress, do not pass any more data to the socket.
       
   380 		//therefore free the chain.
       
   381 		aChain.Free();
       
   382 		}
       
   383 	}
       
   384 
       
   385 TInt CUserPlaneTransportSession::GetData(RMBufChain& aData)
       
   386 	{
       
   387 	LOG_FUNC
       
   388 	// fetch from pool
       
   389 	return iReceivePool.Remove(aData);
       
   390 	}
       
   391 
       
   392 
       
   393 /**
       
   394 we handle the channelerror, rather than the channel
       
   395 as we do not want to necessarily abandon ALL *streams* to the same remote
       
   396 just because one channel errored
       
   397 */
       
   398 void CUserPlaneTransportSession::ChannelError(TInt aError)
       
   399 	{
       
   400 	LOG_FUNC
       
   401 	if (iStream)
       
   402 		{
       
   403 		// this transport session is a user-plane one
       
   404 		__ASSERT_DEBUG(SessionType()!=ESignalling, Panic(EAvdtpBadTransportSessionUpcallFromTransportChannel));
       
   405 		iStream->NotifyUserPlaneTransportSessionsError(this, aError);
       
   406 		iStream = NULL;
       
   407 		LeaveTransportChannel();
       
   408 		}
       
   409 	// else the stream has gone from an earlier Release, and we're still here for client
       
   410 	}
       
   411 	
       
   412 void CUserPlaneTransportSession::StreamError(TInt aError)
       
   413 	{
       
   414 	LOG_FUNC
       
   415 	if (iStream)
       
   416 		{
       
   417 		iStream->ClearSession(*this);//this will cause the iSession pointer in the stream to be null'd
       
   418 		}
       
   419 	// backcall from stream - default is to unbind and pass onto SAP
       
   420 	iStream = NULL;
       
   421 	if (iSAPShutdown!=EImmediate)
       
   422 		{
       
   423 		iSAP.Error(aError);
       
   424 		iSAP.SessionDisconnect();
       
   425 		}
       
   426 	LeaveTransportChannel();
       
   427 	}
       
   428 	
       
   429 
       
   430 void CUserPlaneTransportSession::DoShutdown()
       
   431 	{
       
   432 	LOG_FUNC
       
   433 	if (iStream)
       
   434 		{
       
   435 		// remove ourselves from the stream
       
   436 		iStream->DropSession(SessionType(), *this);
       
   437 		iStream = NULL;
       
   438 		}
       
   439 	else
       
   440 		{
       
   441 		/* If we don't have a stream pointer, then the logical channel underneath
       
   442 		us has gone away, and we've just been detached from the socket, so we need
       
   443 		to delete ourself */
       
   444 		StreamReleased();
       
   445 		}
       
   446 	}
       
   447 
       
   448 /*
       
   449 Called from stream after Release has completed
       
   450 */
       
   451 void CUserPlaneTransportSession::StreamReleased()
       
   452 	{
       
   453 	LOG_FUNC
       
   454 	LeaveTransportChannel();
       
   455 
       
   456 	switch (iSAPShutdown)
       
   457 		{
       
   458 		case ENormal:	
       
   459 		iSAP.CanClose();
       
   460 		break;
       
   461 		
       
   462 		case EImmediate:
       
   463 		delete this;
       
   464 		break;
       
   465 		
       
   466 		case ENone:
       
   467 		iStream = NULL;
       
   468 		iSAP.SessionDisconnect();
       
   469 		break;
       
   470 		}
       
   471 	}
       
   472 
       
   473 void CUserPlaneTransportSession::LeaveTransportChannel()
       
   474 	{
       
   475 	LOG_FUNC
       
   476 	if (iTransportChannel)
       
   477 		{
       
   478 		// he session is now removed from the stream
       
   479 		// time to detach from the channel
       
   480 		iTransportChannel->DetachTransportSession(*this, SessionType());
       
   481 		iTransportChannel = NULL;
       
   482 		}
       
   483 	}
       
   484 
       
   485 
       
   486 CUserPlaneTransportSession::~CUserPlaneTransportSession()
       
   487 	{
       
   488 	LOG_FUNC
       
   489 	if (iStream)
       
   490 		{
       
   491 		iStream->ClearSession(*this);//this will cause the iSession pointer in the stream to be null'd
       
   492 		}
       
   493 	iTSID.Close();
       
   494 	iSendPool.Close();
       
   495 	iReceivePool.Close();
       
   496 	}