--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avctp/avctpmuxerstates.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1193 @@
+// 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:
+// Implement the AVCTP Muxer state classes.
+// These are CAvctpMuxerStateFactory, TAvctpMuxerState (abstract) and its derived
+// classes
+// Together, these classes and the Muxer implement the State pattern
+// (GOF). The states themselves are implemented using the Flyweight
+// pattern. Each state is a Flyweight object, and CAvctpMuxerStateFactory
+// is manager of these objects. As a result of being a flyweight, no
+// state object may have state that can't be shared between all
+// possible users of the state (i.e. no per-Muxer state)
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+#include <bluetooth/logger.h>
+
+#include <es_prot.h>
+#include <es_mbuf.h>
+
+#include "avctpmuxerstates.h"
+#include "bt_subconn_levels.h"
+#include "Avctp.h"
+#include "avctpmuxer.h"
+#include "avctputils.h"
+#include "avctpconstants.h"
+#include "avctpPacketMgr.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVCTP);
+#endif
+
+using namespace SymbianAvctp;
+
+//
+// //
+// TAvctpMuxerState Implementation //
+// //
+//
+
+/**
+Default constructor.
+
+@internalComponent
+@param aFactory The Muxer state factory
+*/
+TAvctpMuxerState::TAvctpMuxerState(CAvctpMuxerStateFactory& aFactory)
+ : iFactory(aFactory)
+ {
+ LOG_FUNC
+ }
+
+/**
+Change a Muxer from one state to another.
+
+We Exit() the first state and then Enter() the second
+
+@internalComponent
+@param aTransport The Muxer whose state is to be changed
+@param aNewState The index for the new state the Muxer is to transition to
+*/
+void TAvctpMuxerState::ChangeState(CAvctpTransport& aTransport, CAvctpMuxerStateFactory::TAvctpMuxerStates aNewState) const
+ {
+ LOG_FUNC
+
+ aTransport.iState->Exit(aTransport);
+
+#ifdef __FLOG_ACTIVE
+ TAvctpMuxerState& state = iFactory.GetState(aNewState);
+#endif
+ LOG3(_L("Muxer 0x%08x : State %S -> %S"), &aTransport, &(aTransport.iState->iName), &(state.iName));
+
+ aTransport.iState = &iFactory.GetState(aNewState);
+ aTransport.iState->Enter(aTransport);
+ }
+
+/**
+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 TAvctpMuxerState::PanicInState(SymbianAvctp::TPanic aPanic) const
+ {
+ Panic(aPanic, iFactory.StateIndex(this));
+ }
+
+/**
+ Close the secondary l2cap channel with or without notifying clients.
+ @param aTransport the transport the state is related to
+ @param aNotifyClient if it's ETrue clients are notified.
+ */
+void TAvctpMuxerState::ShutDownSecondarySap(CAvctpTransport& aTransport, TBool aNotifyClient) const
+ {
+ LOG_FUNC
+
+ CServProviderBase* sap = aTransport.iChannelSAPs[KAvctpSecondaryChannel];
+ if (sap)
+ {
+ sap->Shutdown(CServProviderBase::EImmediate);
+ delete sap;
+ sap = NULL;
+ aTransport.iChannelSAPs[KAvctpSecondaryChannel] = NULL;
+ if (aNotifyClient)
+ {
+ aTransport.NotifyLinkDown(aTransport.iRemoteAddr, KAvctpSecondaryChannel);
+ }
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+ }
+ }
+
+/**
+Default state entry function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpMuxerState::Enter(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ }
+
+/**
+Default state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpMuxerState::Exit(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ }
+
+
+/**
+Default Muxer IsIdle
+
+The muxer is asking its state to determine whether it's idle.
+
+@internalComponent
+@param aTransport The Muxer which is idle
+*/
+TBool TAvctpMuxerState::IsIdle(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ TBool hasData = aTransport.HasDataToSend();
+ TBool pidCount = aTransport.ClientCount();
+ LOG1(_L("Is Idle: %d"), (!hasData && pidCount == 0));
+ return (!hasData && pidCount == 0);
+ }
+
+/**
+Default Muxer IdleTimerExpired
+
+This is a confirmation that the muxer isn't wanted and so should go
+to the closed state and die.
+
+ @internalComponent
+ @param aTransport The Muxer which is idle
+*/
+void TAvctpMuxerState::IdleTimerExpired(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+/**
+ Default Muxer State Start (outgoing) function.
+
+ We've been asked to start a connection to the specified address
+ The default is to assume that nothing needs to be done.
+
+ @internalComponent
+ @param aTransport The Muxer which is to start up
+ @param aAddr The remote address to start up
+ @return System wide error code
+*/
+TInt TAvctpMuxerState::Start(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, TUint16 /*aClientId*/) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aAddr != TBTDevAddr(0) && aTransport.DevAddr() == aAddr, PanicInState(EWrongBTAddress));
+ (void)aAddr;
+ (void)aTransport;
+ return KErrNone;
+ }
+
+/**
+ Default Muxer State Start (incoming) function.
+
+ We've been asked to start a connection using the given L2CAP sap
+ However, this is only valid when we're in the Closed state so
+ panic
+
+ @internalComponent
+ @param aTransport The Muxer which is to start up
+ @param aL2CAPConSAP The existing connection
+ @return System wide error code
+*/
+TInt TAvctpMuxerState::StartIncoming(CAvctpTransport& /*aTransport*/, const TBTDevAddr& /*aAddr*/, CServProviderBase* /*aL2CAPConSAP*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ return KErrNone;
+ }
+
+TInt TAvctpMuxerState::AddSecondChannel(CAvctpTransport& /*aTransport*/, CServProviderBase& /*aSAP*/) const
+ {
+ LOG_FUNC
+ return KErrNotReady;
+ }
+
+void TAvctpMuxerState::RemoveSecondChannel(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ }
+
+TInt TAvctpMuxerState::SecondChannelRemoved(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ return KErrNotReady;
+ }
+
+/**
+ Default Muxer State CancelConnectRequest function.
+
+ This is called when a control client wants to cancel a connection to a particular PID.
+ The connection will actually only be cancelled if there are no remaining control
+ clients for this connection.
+
+ @internalComponent
+ @param aTransport The Muxer which is affected
+*/
+TInt TAvctpMuxerState::CancelConnectRequest(CAvctpTransport& /*aTransport*/, TUint16 /*aClientId*/) const
+ {
+ LOG_FUNC
+ return KErrNotReady;
+ }
+
+
+/**
+Default Muxer Shutdown function.
+
+ @internalComponent
+ @param aTransport The Muxer which is to shutdown
+*/
+void TAvctpMuxerState::Shutdown(CAvctpTransport& /*aTransport*/, TInt /*aError*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+/**
+Default Muxer Disconnect function.
+
+ @internalComponent
+ @param aTransport The Muxer whose L2CAP link has just gone down
+*/
+void TAvctpMuxerState::Disconnect(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+/**
+Default Muxer ConnectComplete function.
+
+ @internalComponent
+ @param aTransport The Muxer whose L2CAP connection has just come up
+*/
+void TAvctpMuxerState::ConnectComplete(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+/**
+Default Muxer Error function
+
+ @internalComponent
+ @param aTransport The Muxer which has just received an error from it's channel sap
+ @param anError The error
+ @param anOperationMask The effected operation
+*/
+void TAvctpMuxerState::Error(CAvctpTransport& /*aTransport*/, TInt /*aError*/,TUint /*aOperationMask*/, TInt /*aChannel*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+/**
+Default Muxer new data function
+
+ @internalComponent
+ @param aTransport The Muxer which has received the notification of new data.
+*/
+TInt TAvctpMuxerState::NewData(CAvctpTransport& /*aTransport*/, TUint /*aMtu*/, TInt /*aChannel*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ return KErrNone;
+ }
+
+/**
+Default Muxer can send function
+
+ @internalComponent
+ @param aTransport The Muxer which can now send
+*/
+void TAvctpMuxerState::CanSend(CAvctpTransport& /*aTransport*/,TInt /*aChannel*/) const
+ {
+ LOG_FUNC
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+//
+// //
+// Implementation of TAvctpStateClosed. //
+// //
+//
+
+/**
+Default constructor
+
+ @internalComponent
+ @param aFactory The Muxer state factory
+*/
+TAvctpStateClosed::TAvctpStateClosed(CAvctpMuxerStateFactory& aFactory)
+ : TAvctpMuxerState(aFactory)
+
+ {
+ LOG_FUNC
+
+ STATENAME("Closed");
+ }
+
+/**
+Closed state entry function.
+
+This is only called on re-entering the Closed state, so we're not needed so delete ourselves
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateClosed::Enter(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ delete &aTransport;
+ }
+
+/**
+Closed state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateClosed::Exit(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ __ASSERT_ALWAYS(aTransport.DevAddr() != TBTDevAddr(0), PanicInState(ENullTBTDevAddr));
+ }
+
+/**
+Closed Muxer IdleTimerExpired
+
+The idle timer should only expire in a non closed state so panic
+if we get it in this state.
+
+ @internalComponent
+ @param aTransport The Muxer which is idle
+*/
+void TAvctpStateClosed::IdleTimerExpired(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+
+/**
+ Closed Muxer State Start (outgoing) function.
+
+ This function asks us to start a connection to the specified address
+
+ @internalComponent
+ @param aTransport The Muxer which is to start up
+ @param aAddr The remote address to start up
+ @return System wide error code
+*/
+TInt TAvctpStateClosed::Start(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, TUint16 /*aClientId*/) const
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(aTransport.DevAddr() == TBTDevAddr(0), PanicInState(ETBTDevAddrNotNull));
+
+ TInt ret = KErrNone;
+ if (aAddr != TBTDevAddr(0))
+ {
+ // New this up just in time.
+ TRAP(ret, aTransport.iChannelSAPs[KAvctpPrimaryChannel] = aTransport.iProtocol.LowerProtocol()->NewSAPL(KSockSeqPacket));
+ if (ret == KErrNone)
+ {
+ aTransport.AssignToDevice(aAddr);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::ELinkPending);
+ }
+ }
+ else
+ {
+ // do nothing - stay closed
+ ret = KErrNone;
+ }
+
+ if (ret != KErrNone)
+ {
+ delete &aTransport;
+ }
+ return ret;
+ }
+
+/**
+ Closed Muxer State Start (incoming) function.
+
+ We've been asked to start a connection using the given L2CAP sap
+
+ @internalComponent
+ @param aTransport The Muxer which is to start up
+ @param aL2CAPConSAP The existing connection
+ @return System wide error code
+*/
+TInt TAvctpStateClosed::StartIncoming(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, CServProviderBase* aL2CAPConSAP) const
+ {
+ LOG_FUNC
+
+ TInt ret = SymbianAvctp::KErrBadAddress;
+
+ // If the following is not true we'll Kern-Exec 3 anyway so assert always
+ __ASSERT_ALWAYS(aL2CAPConSAP, PanicInState(ENullLowerProtocolSap));
+ __ASSERT_DEBUG(aTransport.DevAddr() == TBTDevAddr(0), PanicInState(ETBTDevAddrNotNull));
+
+ if (aAddr != TBTDevAddr(0))
+ {
+ aTransport.AssignToDevice(aAddr);
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel] = aL2CAPConSAP;
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetNotify(&aTransport);
+
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel]->Start();
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+ ret = KErrNone;
+ }
+ // else covered by ret
+
+ if (ret != KErrNone)
+ {
+ delete &aTransport;
+ }
+ return ret;
+ }
+
+//
+// //
+// Implementation of void TAvctpStateLinkPending //
+// //
+// Represents a muxer waiting for the L2CAP link to be created. //
+// //
+//
+
+/**
+Default constructor
+
+ @internalComponent
+ @param aFactory The Muxer state factory
+*/
+TAvctpStateLinkPending::TAvctpStateLinkPending(CAvctpMuxerStateFactory& aFactory)
+ : TAvctpMuxerState(aFactory)
+
+ {
+ LOG_FUNC
+ STATENAME("LinkPending");
+ }
+
+/**
+Link Pending state entry function.
+
+We request the lower protocol SAP to bring up the link.
+
+@internalComponent
+@param aTransport The Muxer which is waiting for a link
+*/
+void TAvctpStateLinkPending::Enter(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ __ASSERT_ALWAYS(aTransport.iChannelSAPs[KAvctpPrimaryChannel], PanicInState(ENullLowerProtocolSap));
+
+ aTransport.DequeIdleTimer();
+ // we become the socket for iChannelsSAPs[0]
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetNotify(&aTransport);
+
+ TL2CAPSockAddr addr;
+ addr.SetBTAddr(aTransport.DevAddr());
+ addr.SetPort(KAVCTP);
+
+ // the security settings are:
+ // (though see :Preauthorise() for the authentication exceptions due to avdtp authentication)
+ TBTServiceSecurity sec;
+ sec.SetAuthentication(KOutboundAuthenticationDefault);
+ sec.SetAuthorisation(KOutboundAuthoristationDefault);
+ sec.SetEncryption(KOutboundEncryptionDefault);
+ sec.SetDenied(EFalse);
+ sec.SetUid(KAvctpServiceUid);
+ addr.SetSecurity(sec);
+
+ TInt err = aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetRemName(addr);
+ __ASSERT_DEBUG(!err, PanicInState(EErrorSettingAddress));
+
+ // Bring up the L2CAP link
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel]->ActiveOpen();
+ }
+
+// TAvctpStateLinkPending::Exit - we'd lke to call aTransport.CheckForIdle(0) but cause
+// in this state IsIdle always returns EFalse that's not possible. Hence do the
+// CheckForIdle in the Enter of the next state currently Open or Closed.
+
+
+
+
+/**
+Link Pending Muxer IsIdle
+
+The muxer is asking it's state to determine whether it's idle. Cause the link is pending
+we can't be idle whatever happens.
+
+Note that this means we must call CheckForIdle on aTransport on entering the next state.
+
+ @internalComponent
+ @param aTransport The Muxer which is idle
+*/
+TBool TAvctpStateLinkPending::IsIdle(CAvctpTransport& /*aTransport*/) const
+ {
+ LOG_FUNC
+ return EFalse;
+ }
+
+/**
+ Link Pending Muxer State CancelConnnectRequest function.
+
+ This is called when a control client wants to cancel a connection to a particular PID.
+ The connection will actually only be cancelled if there are no remaining control
+ clients for this connection.
+
+ This function just removes the saplinksmgr on aPid from the list of control
+ clients since it no longer is interested in this remote device and shouldn't
+ receive any more events related to it.
+
+ @internalComponent
+ @param aTransport The Muxer which is affected
+ @param aPid The pid to cancel the connection too
+*/
+TInt TAvctpStateLinkPending::CancelConnectRequest(CAvctpTransport& /*aTransport*/, TUint16 /*aClientId*/) const
+ {
+ LOG_FUNC
+ return KErrNotSupported;
+ }
+
+
+/**
+Link Pending Muxer ConnectComplete function.
+
+This is the successful result of a connection attempt to a remote device.
+(A incoming connection wouldn't have resulted in a BearerConnectComplete on the
+protocol instead)
+
+ @internalComponent
+ @param aTransport The Muxer whose L2CAP connection has just come up
+*/
+void TAvctpStateLinkPending::ConnectComplete(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+ aTransport.NotifyLinkUp(aTransport.iRemoteAddr);
+ }
+
+/**
+Link Pending Muxer Error function
+
+This is called after some kind of error in the lower protocol Sap.
+
+ @internalComponent
+ @param aTransport The Muxer which has just received an error from it's iChannelsSAPs[0]
+ @param anError The error
+ @param anOperationMask The effected operation
+*/
+void TAvctpStateLinkPending::Error(CAvctpTransport& aTransport, TInt aError,TUint aOperationMask, TInt aChannel) const
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+
+ if (aOperationMask & (MSocketNotify::EErrorFatal |
+ MSocketNotify::EErrorConnect |
+ MSocketNotify::EErrorClose |
+ MSocketNotify::EErrorAllOperations))
+ {
+ // The connect failed, so we'd better go to the Closed state
+ // and tell clients what's happened.
+ // Notifications are made before changing the state because the Enter() method of the Close state
+ // delete the transport, so we can't call anything after changing the state.
+
+ aTransport.NotifyLinkError(aError, aChannel == KAvctpSecondaryChannel);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+ else if (aOperationMask & (MSocketNotify::EErrorSend |
+ MSocketNotify::EErrorRecv |
+ MSocketNotify::EErrorIoctl))
+ {
+ // Since the connection isn't up, we shouldn't be getting a send or recv error
+ // nor do we currently support ioctls in the muxer so:
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+ }
+
+//
+// //
+// Implementation of state TAvctpStateOpen //
+// //
+// This represents a fully connected Muxer that can send and receive data //
+// //
+//
+
+/**
+Default constructor
+
+ @internalComponent
+ @param aFactory The Muxer state factory
+*/
+TAvctpStateOpen::TAvctpStateOpen(CAvctpMuxerStateFactory& aFactory)
+ : TAvctpMuxerState(aFactory)
+
+ {
+ LOG_FUNC
+ STATENAME("Open");
+ }
+
+/**
+Open state entry function.
+
+In case a Avctp Sap asked to send data we need to signal them that they can now send
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateOpen::Enter(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ aTransport.SetClearToSend(KAvctpPrimaryChannel); //only first channel is open so far
+ aTransport.PacketMgr().CanSend(KAvctpPrimaryChannel);
+
+ // for stereo headset usecase, pre-authorise device for AVDTP
+ aTransport.iProtocol.SetPreauthorisation(aTransport.iRemoteAddr, ETrue);
+ }
+
+/**
+Open state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateOpen::Exit(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ // for stereo headset usecase, de-pre-authorise device for AVDTP
+ aTransport.iProtocol.SetPreauthorisation(aTransport.iRemoteAddr, EFalse);
+ }
+
+
+/**
+ Open Muxer State Start (outgoing) function.
+
+ We've been asked to start a connection to the specified address
+ The connection is already up so immediately send a ConnectCfm event
+
+ @internalComponent
+ @param aTransport The Muxer which is to start up
+ @param aAddr The remote address to start up
+ @return System wide error code
+*/
+TInt TAvctpStateOpen::Start(CAvctpTransport& aTransport, const TBTDevAddr& __DEBUG_ONLY(aAddr), TUint16 aClientId) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aAddr != TBTDevAddr(0) && aTransport.DevAddr() == aAddr, PanicInState(EWrongBTAddress));
+
+ aTransport.NotifyAttachConfirm(aClientId, KErrNone, EFalse);
+ return KErrNone;
+ }
+
+
+/**
+Open Muxer Shutdown function.
+
+This function allows the muxer to be shutdown irrespective of whether
+it is idle. This is intended to be used to punish a remote device that
+has done something naughty.
+
+Notify all clients of the problem and go to the closed state.
+
+ @internalComponent
+ @param aTransport The Muxer which is sending data
+*/
+void TAvctpStateOpen::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+ {
+ LOG_FUNC
+
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+
+/**
+Open Muxer Disconnect function.
+
+This is the result of a remote device disconnecting from us.
+Let all interested parties know.
+
+ @internalComponent
+ @param aTransport The Muxer whose L2CAP link has just gone down
+*/
+void TAvctpStateOpen::Disconnect(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+/**
+Open Muxer Error function
+
+This is called after some kind of error in the lower protocol Sap.
+
+ @internalComponent
+ @param aTransport The Muxer which has just received an error from it's channel sap
+ @param anError The error
+ @param anOperationMask The affected operation
+*/
+void TAvctpStateOpen::Error(CAvctpTransport& aTransport, TInt aError,TUint aOperationMask, TInt aChannel) const
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+
+ if (aOperationMask & (MSocketNotify::EErrorRecv |
+ MSocketNotify::EErrorSend))
+ {
+ // the packet mgr is only interested in data plane errors
+ aTransport.PacketMgr().SignalMuxerError(aError, aOperationMask);
+ }
+
+ if (aOperationMask & (MSocketNotify::EErrorFatal |
+ MSocketNotify::EErrorClose |
+ MSocketNotify::EErrorAllOperations))
+ {
+ // The connection has gone down so we inform our control clients of this fact
+ aTransport.NotifyLinkDown(aTransport.iAddress, aChannel, aError);
+ }
+ else if (aOperationMask & (MSocketNotify::EErrorConnect |
+ MSocketNotify::EErrorIoctl))
+ {
+ // Since the connection is already up, we shouldn't be getting a connect error
+ // nor do we currently support ioctls
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+TInt TAvctpStateOpen::AddSecondChannel(CAvctpTransport& aTransport, CServProviderBase& aSAP) const
+ {
+ LOG_FUNC
+ // can bind socket to SAP now
+ aTransport.BindSecondaryChannelSap(aSAP);
+
+ // see if it is connected or not
+ TL2CAPSockAddr addr;
+ aSAP.RemName(addr);
+
+ if (addr.BTAddr()==TBTDevAddr(0))
+ {
+ addr.SetBTAddr(aTransport.iRemoteAddr);
+ addr.SetPort(KAvctpSecondChannelPSM);
+
+ // the security settings are:
+ // (though see :Preauthorise() for the authentication exceptions due to avdtp authentication)
+ TBTServiceSecurity sec;
+ sec.SetAuthentication(KSecondaryChannelAuthenticationDefault);
+ sec.SetAuthorisation(KSecondaryChannelAuthoristationDefault);
+ sec.SetEncryption(KOutboundEncryptionDefault);
+ sec.SetDenied(EFalse);
+ sec.SetUid(KAvctpServiceUid);
+ addr.SetSecurity(sec);
+
+ TInt err = aTransport.iChannelSAPs[KAvctpSecondaryChannel]->SetRemName(addr);
+ __ASSERT_DEBUG(err == KErrNone, PanicInState(ESetRemNameError));
+
+ const TUint KDefaultMtu = 335;
+
+ TPckgBuf<TL2CapConfig> config;
+ config().SetMaxTransmitUnitSize(KAvctpSecondaryChannelInboundMTU);
+ config().SetMinMTU(KDefaultMtu);
+ config().SetMaxReceiveUnitSize(KAvctpSecondaryChannelInboundMTU);
+ config().SetMinMRU(KDefaultMtu);
+
+ err = aTransport.iChannelSAPs[KAvctpSecondaryChannel]->SetOption(KSolBtL2CAP, KL2CAPUpdateChannelConfig, config);
+ __ASSERT_DEBUG(err == KErrNone, Panic(ESetOptionError));
+
+ aTransport.iChannelSAPs[KAvctpSecondaryChannel]->ActiveOpen();
+ ChangeState(aTransport, CAvctpMuxerStateFactory::ESecondLinkPending);
+ }
+ else
+ {
+ aTransport.iChannelSAPs[KAvctpSecondaryChannel]->Start();
+ aTransport.SetClearToSend(KAvctpSecondaryChannel);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EFullyOpen);
+ aTransport.NotifyLinkUp(addr.BTAddr(), ETrue);
+ }
+ return KErrNone;
+ }
+
+/**
+Open Muxer new data function
+
+The lower protocol sap has notified the muxer of new data that is
+waiting for retrieval.
+
+This is called once for each new packet of data that L2CAP has notified the muxer of.
+We get to the data by calling GetData on the lower protocol SAP
+and give the resulting data to the Avctp Protocol, letting it workout who wants it.
+
+This assumes a packet interface from L2CAP.
+
+ @internalComponent
+ @param aTransport The Muxer which has received the notification of new data.
+ @param aMtu The length of the data packet to be read.
+*/
+TInt TAvctpStateOpen::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aChannel==KAvctpPrimaryChannel, PanicInState(EUnexpectedMuxerEvent));
+ __ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+
+ TInt err = KErrNone;
+ // Read data into the buffer
+ // the transport feeds us synchronously for first channel
+ RMBufChain inboundFragment;
+ TInt dataAvailable = aTransport.iChannelSAPs[KAvctpPrimaryChannel]->GetData(inboundFragment, aMtu, 0);
+ if (dataAvailable > 0)
+ {
+ err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+
+ //NewData() only returns an error in the case where the data header gave a parse error.
+ //In this case the muxer is shutdown, so the remaining packets cannot be read.
+ //In the case where NewData() failed to pass on onwnership, an attempt should be made
+ //to read remaining packets, so no error is returned.
+ if(err != KErrNone)
+ {
+ inboundFragment.Free();
+ }
+ }
+ else if (dataAvailable < KErrNone) // some error occurred reading the data. shutdown the muxer and report the error
+ {
+ aTransport.Shutdown(dataAvailable);
+ inboundFragment.Free();
+ err = KErrMuxerShutDown;
+ }
+ // otherwise, no data available
+ return err;
+ }
+
+/**
+Open Muxer can send function
+
+This is called after a blocked Write on the lower protocol SAP. This is a notification
+that the lower protocol SAP is ready to receive more data.
+
+ @internalComponent
+ @param aTransport The Muxer which can now send
+*/
+void TAvctpStateOpen::CanSend(CAvctpTransport& aTransport, TInt aChannel) const
+ {
+ LOG_FUNC
+
+ aTransport.SetClearToSend(aChannel);
+ aTransport.PacketMgr().CanSend(aChannel);
+ }
+
+TAvctpStateFullyOpen::TAvctpStateFullyOpen(CAvctpMuxerStateFactory& aFactory)
+:TAvctpStateOpen(aFactory)
+ {
+ LOG_FUNC
+ STATENAME("FullyOpen");
+ }
+
+void TAvctpStateFullyOpen::Enter(CAvctpTransport& aTransport) const
+ {
+ // should check the sap psm really
+ aTransport.SetClearToSend(KAvctpSecondaryChannel);
+ aTransport.PacketMgr().CanSend(KAvctpSecondaryChannel);
+ }
+
+/**
+ The method is defined and left empty on purpose (because this class derives from TAvctpStateOpen
+ but we don't wont its method to be called.
+ */
+void TAvctpStateFullyOpen::Exit(CAvctpTransport& /*aTransport*/) const
+ {
+ }
+
+void TAvctpStateFullyOpen::Error(CAvctpTransport& aTransport, TInt aError, TUint aErrorMask, TInt aChannel) const
+ {
+ LOG_FUNC
+
+ if (aErrorMask & (MSocketNotify::EErrorRecv |
+ MSocketNotify::EErrorSend))
+ {
+ // the packet mgr is only interested in data plane errors
+ aTransport.PacketMgr().SignalMuxerError(aError, aErrorMask);
+ }
+
+ if (aErrorMask & (MSocketNotify::EErrorFatal |
+ MSocketNotify::EErrorClose |
+ MSocketNotify::EErrorAllOperations))
+ {
+ // The connection has gone down so we inform our control clients of this fact
+ aTransport.NotifyLinkDown(aTransport.iAddress, aChannel, aError);
+ }
+ else if (aErrorMask & (MSocketNotify::EErrorConnect |
+ MSocketNotify::EErrorIoctl))
+ {
+ // Since the connection is already up, we shouldn't be getting a connect error
+ // nor do we currently support ioctls
+ PanicInState(EUnexpectedMuxerEvent);
+ }
+ ChangeState(aTransport, aChannel == KAvctpSecondaryChannel ? CAvctpMuxerStateFactory::EOpen : CAvctpMuxerStateFactory::EClosed);
+ }
+
+void TAvctpStateFullyOpen::Disconnect(CAvctpTransport& aTransport) const
+ {
+ aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+void TAvctpStateFullyOpen::CanSend(CAvctpTransport& aTransport,TInt aChannel) const
+ {
+ aTransport.SetClearToSend(aChannel);
+ aTransport.PacketMgr().CanSend(aChannel);
+ }
+
+TInt TAvctpStateFullyOpen::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+ {
+ RMBufChain inboundFragment;
+ __ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+ aTransport.iChannelSAPs[aChannel]->GetData(inboundFragment, aMtu, 0);
+
+ TInt err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+
+ if(err != KErrNone)
+ {
+ inboundFragment.Free();
+ }
+ return err;
+ }
+
+TInt TAvctpStateFullyOpen::Start(CAvctpTransport& aTransport, const TBTDevAddr& /*aAddr*/, TUint16 aClientId) const
+ {
+ aTransport.NotifyAttachConfirm(aClientId, KErrNone, EFalse);
+ return KErrNone;
+ }
+
+void TAvctpStateFullyOpen::RemoveSecondChannel(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ // shutdown secondary channel without notifying clients (second param is EFalse)
+ ShutDownSecondarySap(aTransport, EFalse);
+ }
+
+TInt TAvctpStateFullyOpen::SecondChannelRemoved(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ // shutdown secondary channel notifying clients (second param is ETrue)
+ ShutDownSecondarySap(aTransport, ETrue);
+ return KErrNone;
+ }
+
+void TAvctpStateFullyOpen::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+ {
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+
+/**
+ The method is declared and left empty on purpose (because this class derives from TAvctpStateOpen
+ but we don't wont its method to be called.
+ */
+void TAvctpStateSecondChannelPending::Enter(CAvctpTransport& /*aTransport*/) const
+ {
+ }
+
+/**
+ The method is declared and left empty on purpose (because this class derives from TAvctpStateOpen
+ but we don't wont its method to be called.
+ */
+void TAvctpStateSecondChannelPending::Exit(CAvctpTransport& /*aTransport*/) const
+ {
+ }
+
+void TAvctpStateSecondChannelPending::Error(CAvctpTransport& aTransport, TInt aError, TUint /*aErrorMask*/, TInt aChannel) const
+ {
+ aTransport.NotifyLinkError(aError, aChannel == KAvctpSecondaryChannel);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+ }
+
+TAvctpStateSecondChannelPending::TAvctpStateSecondChannelPending(CAvctpMuxerStateFactory& aFactory)
+:TAvctpStateOpen(aFactory)
+ {
+ LOG_FUNC
+ STATENAME("SecondLinkPending");
+ }
+
+void TAvctpStateSecondChannelPending::ConnectComplete(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ aTransport.NotifyLinkUp(aTransport.iRemoteAddr, ETrue);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EFullyOpen);
+ }
+
+void TAvctpStateSecondChannelPending::Disconnect(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+
+ // In this state there is at least one outstanding ioctl on the secondary ctrl sap that
+ // we must complete
+
+ aTransport.NotifyAttachConfirm(KErrMuxerShutDown, ETrue);
+ aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr);
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+void TAvctpStateSecondChannelPending::CanSend(CAvctpTransport& aTransport, TInt __DEBUG_ONLY(aChannel)) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+ aTransport.SetClearToSend(KAvctpPrimaryChannel);
+ aTransport.PacketMgr().CanSend(KAvctpPrimaryChannel);
+ }
+
+TInt TAvctpStateSecondChannelPending::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aChannel==KAvctpPrimaryChannel, PanicInState(EUnexpectedMuxerEvent));
+ __ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+
+ // Read data into the buffer
+ // the transport feeds us synchronously for first channel
+ RMBufChain inboundFragment;
+ aTransport.iChannelSAPs[KAvctpPrimaryChannel]->GetData(inboundFragment, aMtu, 0);
+
+ TInt err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+
+ //NewData() only returns an error in the case where the data header gave a parse error.
+ //In this case the muxer is shutdown, so the remaining packets cannot be read.
+ //In the case where NewData() failed to pass on onwnership, an attempt should be made
+ //to read remaining packets, so no error is returned.
+ if(err != KErrNone)
+ {
+ inboundFragment.Free();
+ }
+ return err;
+ }
+
+TInt TAvctpStateSecondChannelPending::Start(CAvctpTransport& /*aTransport*/, const TBTDevAddr& /*aAddr*/, TUint16 /*aClientId*/) const
+ {
+ return KErrNotReady;
+ }
+
+void TAvctpStateSecondChannelPending::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+ {
+ LOG_FUNC
+ ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+ }
+
+void TAvctpStateSecondChannelPending::RemoveSecondChannel(CAvctpTransport& aTransport) const
+ {
+ LOG_FUNC
+ // shutdown secondary channel without notifying clients (second param is EFalse)
+ ShutDownSecondarySap(aTransport, EFalse);
+ }
+//
+// //
+// CAvctpMuxerStateFactory implementation //
+// //
+//
+
+/**
+Default constructor
+
+ @internalComponent
+*/
+CAvctpMuxerStateFactory::CAvctpMuxerStateFactory()
+ {
+ LOG_FUNC
+ }
+
+/**
+Destructor to free resources.
+
+Delete all our lightweight states
+
+ @internalComponent
+*/
+CAvctpMuxerStateFactory::~CAvctpMuxerStateFactory()
+ {
+ LOG_FUNC
+
+ iStates.DeleteAll();
+ }
+
+/**
+Static factory factory function (think about it... ;-)
+
+Creates an array of lightweight states for Muxers
+
+ @internalComponent
+ @leave KErrNoMemory if the CAvctpMuxerStateFactory object could not be created
+ @return A pointer to the new state factory
+*/
+CAvctpMuxerStateFactory* CAvctpMuxerStateFactory::NewL()
+ {
+ LOG_STATIC_FUNC
+
+ CAvctpMuxerStateFactory* factory = new(ELeave) CAvctpMuxerStateFactory();
+ CleanupStack::PushL(factory);
+
+ // Create all the new states
+ factory->iStates[EClosed] = new(ELeave) TAvctpStateClosed(*factory);
+ factory->iStates[ELinkPending] = new(ELeave) TAvctpStateLinkPending(*factory);
+ factory->iStates[EOpen] = new(ELeave) TAvctpStateOpen(*factory);
+ factory->iStates[ESecondLinkPending] = new(ELeave) TAvctpStateSecondChannelPending(*factory);
+ factory->iStates[EFullyOpen] = new(ELeave) TAvctpStateFullyOpen(*factory);
+
+ CleanupStack::Pop(factory);
+ return factory;
+ }
+
+/**
+Utility function to get a lightweight state
+
+ @internalComponent
+ @param aState Index to the state required
+ @return A lightweight Muxer state
+*/
+TAvctpMuxerState& CAvctpMuxerStateFactory::GetState(const TAvctpMuxerStates aState) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aState != EMaxStates, Panic(EAvctpMuxerStateOutOfBounds));
+ return *iStates[aState];
+ }
+
+TInt CAvctpMuxerStateFactory::StateIndex(const TAvctpMuxerState* aState) const
+ {
+ TInt state;
+ for (state = 0; state < EMaxStates; state++)
+ {
+ if (iStates[state] == aState)
+ {
+ return state;
+ }
+ }
+
+ return KUnknownState;
+ }