// 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:
// Defines the avdtp signalling channel
// Signalling channel - not a transport channel by type, but called "signalling channel" as it maps very
// clearly onto that defined in the AVDTP specification
// There is at most one signalling channel for a remote device.  Many applications can use the signalling
// channel via the multiplexing of signalling sessions.
// The signalling channel is given a logical channel (l2cap shannel) to run on from the logical channel factory
// The signalling channels responsibilities are:
// - offer signalling protocol send primitives
// - offer incoming signalling protocol indications to all the attached signalling sessions
// - provide a mechanism to patch up deficiencies in the specification (eg providing SEIDs in protocol confirms
// to signalling sessions that call send primitives
// All signalling sessions on a listening signalling channel become connected once the listening channel is
// connected. 
// All signalling sessions on a listening signalling channel are transfered to the new connected
// signalling channel upon the completion of an active open. The listening signalling channel is
// left to continue listening. New sessions attached to it will not be connected to the existing 
// channel.
// The signalling channel does not parse incoming messages. Incoming data from the logical channel is
// given to the incoming message.  The incoming message builds and parses itself.
// The signalling message then calls the Handle methods on the signalling channel which liases with the
// signalling sessions.
// 
//

#ifndef AVDTPSIGNALLINGCHANNEL_H
#define AVDTPSIGNALLINGCHANNEL_H

#include <es_prot.h>
#include "avdtpSignallingMessages.h"
#include "avdtpLogicalChannelFactory.h"
#include "avdtpSEPCache.h"
#include "avdtpAllocators.h"

class CAvdtpProtocol;
class XAvdtpSignalReceiver;
class RMBufChain;
class CSignallingTransaction;

static const TInt KAvdtpReleaseAcceptPriority = CActive::EPriorityHigh;
#ifdef _OOM_TEST
static const TInt KAvdtpSignallingChannelIdleTimeout = 800;
#else
static const TInt KAvdtpSignallingChannelIdleTimeout = 3000000; // 3s
#endif

NONSHARABLE_CLASS(CSignallingChannel) : public CBase, public MSocketNotify, public XLogicalChannelFactoryClient
/**
Relatively stateless entity - driven mainly by GC
Provides primitives that accord with spec, but parameterised and initiated by
GC and Avdtp[Signalling]SAPs.
*/
	{
friend class CAvdtpProtocol; // for queing
friend class CAvdtpInboundSignallingMessage; //for SendingRejects

public:
	static CSignallingChannel* NewL(CAvdtpProtocol& aProtocol,
									CLogicalChannelFactory& aChannelFactory,
									const TBTDevAddr& aRemoteAddr);
									
	static CSignallingChannel* NewLC(CAvdtpProtocol& aProtocol,
									 CLogicalChannelFactory& aChannelFactory,
									 const TBTDevAddr& aRemoteAddr);

	TInt AttachSignallingUser(XAvdtpSignalReceiver& aReceiver);
	void DetachSignallingUser(XAvdtpSignalReceiver& aReceiver);
	void CancelTransactions(XAvdtpSignalReceiver& aUser);
	void RemoveTransaction(CSignallingTransaction& aTransaction);

	TBTDevAddr RemoteAddress(); // intentional signature
	inline TBool IsListening() const;
	
// for this remote (this class models "Connection-local" stuff in spec too)	
	inline TTCIDManager& TCIDManager();
	inline TTSIDManager& TSIDManager();
// Service Primitives 

// Signalling sessions provide a reference to themselves so that we can do some muxing
// 	their details can form the basis of the AVDTP TransactionLabel.
//	as we can bind the caller (SAP) address with the TransLabel
//	see CSignallingTransaction
// we can't do away with Attaching/Detaching of SAPs as that is required
// to signal when this object is ready

// INT primitives
	TInt SendDiscoverSEPs(XAvdtpSignalReceiver& aReceiver);
	TInt SendGetCapabilities(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	TInt SendSetConfiguration(XAvdtpSignalReceiver& aReceiver, TSEID aINTSEID, TSEID aACPSEID, const RBuf8& aConfiguration);
	TInt SendRelease(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	TInt SendAbort(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	TInt SendStartStream(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	TInt SendSuspendStream(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	TInt SendSecurityControl(XAvdtpSignalReceiver& aReceiver, 
									    TSEID aACPSEID,
									    const TDesC8& aSecurityData);
	TInt SendReconfigure(XAvdtpSignalReceiver& aReceiver,
										  TSEID aACPSEID,
										  const RBuf8& aConfiguration);

	TInt SendOpenStream(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID);
	

// Upcall primitives from packet parsing - bit like XAvdtpSignalReceiver, but more params
	
	// confirms
	void DiscoverConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, const TAvdtpInternalDiscoverConfirm* const aConfirm);
	void GetCapsConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, const HBufC8* aCapsDataAsProtocol = NULL);
	void SetConfigConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, TAvdtpServiceCategory aErrorCategory);
	void ReleaseConfirm(TAvdtpTransactionLabel aLabel, TInt aResult);
	void GetConfigConfirm(TAvdtpTransactionLabel aLabel, TInt aResult);
	void ReconfigConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, TAvdtpServiceCategory aErrorCategory);
	void OpenConfirm(TAvdtpTransactionLabel aLabel, TInt aResult);
	void StartConfirm(TAvdtpTransactionLabel aLabel, TInt aResult);
	void AbortConfirm(TAvdtpTransactionLabel aLabel); // no error
	void SuspendConfirm(TAvdtpTransactionLabel aLabel, TInt aResult);
	void SecurityControlConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, const TDesC8& aResponseData);

	// indications
	void DiscoverIndication(TAvdtpTransactionLabel aLabel);	
	void GetCapsIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void SetConfigIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID,
							  TSEID aINTSEID, RBuf8& aConfigData);
	void GetConfigIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void ReconfigIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID, RBuf8& aConfigData);
	void OpenIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void StartIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void ReleaseIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void SuspendIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void AbortIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID);
	void SecurityControlIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID, const HBufC8* aSecurityData);
	
	
	TInt SendSetConfigurationAccept(TAvdtpTransactionLabel aLabel);
	TInt SendSetConfigurationReject(TAvdtpTransactionLabel aLabel, TBluetoothAvDistributionError aResult,
									  TAvdtpServiceCategory aCategory);

	TInt SendReconfigureAccept(TAvdtpTransactionLabel aLabel);	
	TInt SendReconfigureReject(TAvdtpTransactionLabel aLabel, TBluetoothAvDistributionError aResult,
									  TAvdtpServiceCategory aCategory);

	TInt SendStartAccept(TAvdtpTransactionLabel aLabel);
	TInt SendStartReject(TAvdtpTransactionLabel aLabel,TBluetoothAvDistributionError aResult, TSEID aBadSEID);
	TInt SendSuspendAccept(TAvdtpTransactionLabel aLabel);
	TInt SendSuspendReject(TAvdtpTransactionLabel aLabel,TBluetoothAvDistributionError aResult, TSEID aBadSEID);
	
	TInt SendSecurityControlAccept(TAvdtpTransactionLabel aLabel, const TDesC8* aOptionalData = NULL);
	TInt SendSecurityControlReject(TAvdtpTransactionLabel aLabel, TBluetoothAvDistributionError aResult);

	TInt SendReleaseAccept(TAvdtpTransactionLabel aLabel);
	
// non-spec stuff
	TInt GetData(RMBufChain& aData, TUint aOptions, TSockAddr* anAddr=NULL);
	virtual void NewData(TUint aCount);
	
// async stuff
	void StartTryToSendCallback();
	void CancelTryToSendCallback();
	static TInt TryToSendCallback(TAny *aSigCh); //the static one we have to register
	TInt TryToSendCallback(); //on this Signalling Channel
private:	
// from MSocketNotify - transport (rather than packet) upcalls
	virtual void CanSend();
	virtual void ConnectComplete();
	virtual void ConnectComplete(const TDesC8& aConnectData);
    virtual void ConnectComplete(CServProviderBase& aSSP);
	virtual void ConnectComplete(CServProviderBase& aSSP,const TDesC8& aConnectData);
	virtual void CanClose(TDelete aDelete=EDelete);
	virtual void CanClose(const TDesC8& aDisconnectData,TDelete aDelete=EDelete);
	virtual void Disconnect(void);
	virtual void Disconnect(TDesC8& aDisconnectData);
	virtual void IoctlComplete(TDesC8 *aBuf);
	virtual void Error(TInt anError,TUint anOperationMask=EErrorAllOperations);
	virtual void NoBearer(const TDesC8& /*aConnectionInfo*/);
	virtual void Bearer(const TDesC8& aConnectionInfo);
	static TInt TryToClose(TAny* aSignallingChannel);

private:
// from MLogicalChannelFactoryClient
	void LogicalChannelFactoryRequestComplete(TLogicalChannelFactoryTicket aTicket, TInt aErr);
private:
	CSignallingChannel(CAvdtpProtocol& aProtocol, CLogicalChannelFactory& aChannelFactory, const TBTDevAddr& aRemoteAddr);
	TInt EnqueueMessage(CSignallingTransaction& aTok);
	void ConstructL();
	void RemoveTransactions(XAvdtpSignalReceiver& aUser);
	void PacketSent(CSignallingTransaction& aToken);
	void ObtainMTU();
	void ConfigConfirm(TAvdtpTransactionLabel aLabel,
							  TInt aResult,
							  TAvdtpServiceCategory aCategory,
							  TBool aReconfigure);
	
	CSignallingTransaction* PrepareSignallingCommand(XAvdtpSignalReceiver& aReceiver, TAvdtpMessage aMessage);
	CSignallingTransaction* PrepareSignallingResponse(TAvdtpMessageType aMessageType, TAvdtpMessage aMessage, TAvdtpTransactionLabel aLabel);
	CSignallingTransaction* PrepareSignallingPacket(TAvdtpMessageType aMessageType, TAvdtpMessage aMessage);
	
	
	CSignallingTransaction* FindTransaction(TAvdtpTransactionLabel aLabel);
	void HandleSignallingCommand(CAvdtpSignallingMessage& aSigMessage);
	
	void CheckOutboundQueue();
	void ServiceOutboundQueue();
	
	inline void SetBlocked(TBool aBlocked);
	inline TBool Blocked() const;
	
	~CSignallingChannel(); //only this can delete this
	inline const TDblQue<XAvdtpSignalReceiver>& Users() const;

// PDU operations not available for external use
	TInt SendAccept(TAvdtpTransactionLabel aLabel, TAvdtpMessage aMessage, const TDesC8* aOptionalData = NULL);
	
	TInt SendReject(TAvdtpTransactionLabel aLabel,
					TAvdtpMessage aMessage,
					TBluetoothAvDistributionError aError,
					const TDesC8* aRejectionData = NULL);
	void QueIdleTimer();
	void ErrorPermanentUsers(TInt aError);
	void ErrorServiceRequesters(TInt aError);
	TBool CheckSignal(const CSignallingTransaction& aToken, TAvdtpMessage aSignal) const;
	void CancelIdleTimer();
	TBool IsIdle() const;
	void IdledD();

private:
	CAvdtpProtocol&				iProtocol;	
	CLogicalChannelFactory&		iLogicalChannelFactory;
	CServProviderBase*			iBearer;
	TDblQueLink					iProtocolQLink;
	TDblQue<XAvdtpSignalReceiver> iPermanentUsers;
	TDblQue<CSignallingTransaction>	iTransactions;
	TInt						iBearerMTU;
	
	/**
	this value is either the intended remote or the actual one
	whereas RemoteAddress() returns 0 if the connection is not actually in place
	*/
	TBTDevAddr					iRemoteAddress;
	TTransactionLabelManager	iLabelGen;

	/**
	There is always one and only one incoming message [can be empty]
	*/
	CAvdtpInboundSignallingMessage		iInboundMessage;

	/**
	Messages being prepared by their Signalling Sessions.
	NB: this que will need to be purged of messages owned by a SS
	when it detaches (do we want to limit how many messages a SS can
	be preparing at once?)
	*/
	TDblQue<CAvdtpOutboundSignallingMessage>	iDraftMessages;
	
	/**
	Messages sitting in our outbound queue
	*/
	TDblQue<CAvdtpOutboundSignallingMessage>	iQueuedMessages;	
	
	/**
	The fragments which have been prepared from a message plucked
	off the outbound que (and fragmented according to the MTU of
	the L2CAP channel).  Only flushed if an ABORT appears in the
	queue for the _same_SEP_ [subtle, see AVDTP spec pp62].
	*/
	RMBufChain					iOutgoingSignallingMessage;
	TBool						iMoreFrags;
	CSignallingTransaction*		iCurrentTransaction;
	
	TBool						iBlocked;
	
	CAsyncCallBack*				iTryToSendCallback; // sig msgs sent asynchronously
	
// these managers are "Connection-local" in spec, hence this class owns them
	TTCIDManager				iTCIDManager;
	TTSIDManager				iTSIDManager;

	TDeltaTimerEntry iIdleTimerEntry; 	 //< Disconnection idle timer
	TBool			 iIdleTimerActive;	//< Is Idle timer running.
	
	TLogicalChannelFactoryTicket iLogicalChannelRequest; // for passive request for now
	};
	
inline TTCIDManager& CSignallingChannel::TCIDManager()
	{
	return iTCIDManager;
	}
	
inline TTSIDManager& CSignallingChannel::TSIDManager()
	{
	return iTSIDManager;	
	}

inline TBool CSignallingChannel::Blocked() const
	{
	return iBlocked;
	}

inline void CSignallingChannel::SetBlocked(TBool aBlocked)
	{
	iBlocked=aBlocked;
	}

inline const TDblQue<XAvdtpSignalReceiver>& CSignallingChannel::Users() const
	{
	return iPermanentUsers;
	}

inline TBool CSignallingChannel::IsListening() const
	{
	return iRemoteAddress==TBTDevAddr(0);
	}
	
#endif //AVDTPSIGNALLINGCHANNEL_H

