remotecontrol/remotecontrolfw/server/src/targetsession.cpp
author hgs
Wed, 13 Oct 2010 16:20:29 +0300
changeset 51 20ac952a623c
permissions -rw-r--r--
201040_02

// Copyright (c) 2010 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:
//

#include <bluetooth/logger.h>
#include <remcon/remconifdetails.h>
#include "messagequeue.h"
#include "remconmessage.h"
#include "remconserver.h"
#include "server.h"
#include "targetsession.h"
#include "utils.h"

#ifdef __FLOG_ACTIVE
_LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER);
#endif

#ifdef _DEBUG
PANICCATEGORY("tgsession");
#endif

CRemConTargetSession* CRemConTargetSession::NewL(CRemConTargetClientProcess& aClientProcess,
	CRemConServer& aServer,
	CBearerManager& aBearerManager,
	TUint aId)
	{
	LOG_STATIC_FUNC;
	CRemConTargetSession* self = new(ELeave) CRemConTargetSession(aClientProcess, aServer, aBearerManager, aId);
	CleanupStack::PushL(self);
	self->ConstructL();
	CLEANUPSTACK_POP1(self);
	return self;
	}

CRemConTargetSession::~CRemConTargetSession()
	{
	LOG_FUNC;

	// Tell the client process representation we've gone away- it may start its shutdown timer.
	iClientProcess.TargetSessionClosed(*this);
	}

CRemConTargetSession::CRemConTargetSession(CRemConTargetClientProcess& aClientProcess,
	CRemConServer& aServer, 
	CBearerManager& aBearerManager,
	TUint aId)
	: CRemConSession(aServer, aBearerManager, aId),
	iClientProcess(aClientProcess)
	{
	LOG_FUNC;
	}

void CRemConTargetSession::ConstructL()
	{
	LOG_FUNC;

	BaseConstructL(iClientProcess.ClientInfo());

	// Tell the client process representation about us (this will in turn inform the server).
	LEAVEIFERRORL(iClientProcess.TargetSessionOpened(*this));
	
	// Set our pointer into the connection history at the current/'Last' item.
	// Can't do this til we've told the server we exist
	iServer.SetConnectionHistoryPointer(Id());
	}

TBool CRemConTargetSession::SupportedMessage(const CRemConMessage& aMsg) const
	{
	LOG_FUNC;

	// Return true if the message is for an interface supported by this session
	return InterfaceSupported(aMsg.InterfaceUid());
	}

TBool CRemConTargetSession::InterfaceSupported(TUid aInterfaceUid) const
	{
	LOG_FUNC;
	LOG2(_L("\taInterfaceUid = 0x%08x, iInterestedAPIs = %d"), aInterfaceUid, iInterestedAPIs);

	TBool result = iInterestedAPIs ? (FindInterfaceByUid(aInterfaceUid) != NULL) : EFalse;

	LOG1(_L("result = %d"), result);
	return result;
	}

void CRemConTargetSession::SetPlayerType(const RMessage2& aMessage)
	{
	LOG_FUNC;
	
	TInt err = aMessage.GetDesLength(1);
	if (err >= 0)
		{
		TPlayerTypeInformation playerType;
		RBuf8 playerName;
	
		TRAP(err, GetPlayerTypeAndNameL(aMessage, playerType, playerName));

		if (err == KErrBadDescriptor)
			{
			PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
			playerName.Close();
			return;
			}
		else if (err == KErrArgument)
			{
			PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
			playerName.Close();
			return;			
			}
		else if (err == KErrNone)
			{
			// If player type is not set, then update iClientProcess with information.
			// If player type is already set, then dont allow this to be changed for the client (panic the client if the information is different).
			if (!iClientProcess.HasPlayerInformation())
				{
				TRAP(err, iClientProcess.SetPlayerInformationL(playerType, playerName));
				}
			else if (!iClientProcess.PlayerInformationMatches(playerType, playerName))
				{
				PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicPlayerInfoAlreadySet);
				playerName.Close();
				return;
				}
			}

		playerName.Close();
		}
	else if (err == KErrBadDescriptor)
		{	
		// The additional parameters are optional (i.e. old target clients won't provide them).
		err = KErrNone;
		}
	
	CompleteClient(aMessage, err);
	}

CRemConMessage* CRemConTargetSession::DoPrepareSendMessageL(const RMessage2& aMessage)
	{
	LOG_FUNC;

	// Get the data the client wants to send.
	TUid interfaceUid;
	TUint operationId;

	TRemConMessageSubType messageSubType;
	RBuf8 sendDes;
	if (!DoGetSendInfoLC(aMessage, interfaceUid, operationId, messageSubType, sendDes))
		{
		// DoGetSendInfoLC() panicked the message
		return NULL;	
		}

	CRemConMessage* msg = NULL;
	
	LOG(_L("\tTARGET send"));

	msg = CRemConMessage::NewL(
		TRemConAddress(), // we don't know which remotes it's going to yet
		ERemConResponse, // targets can only send responses
		messageSubType,
		interfaceUid,
		operationId,
		sendDes, // msg takes ownership
		iClientProcess.Id(), // session id to match this response against the originating command
		0, // transaction id not yet known
		ETrue);
	CLEANUPSTACK_POP1(&sendDes); // now owned by msg
	
	return msg;
	}

void CRemConTargetSession::SendUnreliable(const RMessage2& aMessage)
	{
	LOG_FUNC;

	// Check we've had our features set...
	if (!ClientAvailable())
		{
		PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet);
		return;
		}

	CRemConMessage* msg = NULL;
	TRAPD(err, msg = DoCreateUnreliableMessageL(aMessage));
	CompleteClient(aMessage, err);
	if (err == KErrNone)
		{
		ASSERT_DEBUG(iSendQueue);
		if (iSending || !iSendQueue->IsEmpty())
			{
			iSendQueue->Append(*msg);
			}
		else
			{
			SendToServer(*msg);
			}
		}
	}

CRemConMessage* CRemConTargetSession::DoCreateUnreliableMessageL(const RMessage2& aMessage)
	{
	LOG_FUNC;

	// Get the data the client wants to send.
	TUid interfaceUid;
	TUint operationId;
	TRemConMessageSubType messageSubType;
	RBuf8 sendDes;
	DoGetSendInfoLC(aMessage, interfaceUid, operationId, messageSubType, sendDes);

	// Before we ask the server to send, we must set our ClientInfo 
	// correctly so the TSP can get information about the client. 
	iClientInfo.Message() = aMessage;

	CRemConMessage* msg = NULL;
	
	LOG(_L("\tTARGET send"));

	msg = CRemConMessage::NewL(
		TRemConAddress(), // we don't know which remotes it's going to yet
		ERemConResponse, // targets can only send responses
		messageSubType,
		interfaceUid,
		operationId,
		sendDes, // msg takes ownership
		iClientProcess.Id(), // session id to match this response against the originating command
		0, // transaction id not yet known
		EFalse);
	CLEANUPSTACK_POP1(&sendDes); // now owned by msg

	return msg;
	}

void CRemConTargetSession::DoSendCancel()
	{
	LOG_FUNC;

	// We do not cancel any pending response messages, so don't need
	// to notify the server here.

	NumRemotesToTry() = 0;
	iSendError = KErrCancel;
	CompleteSend();
	}

void CRemConTargetSession::RegisterInterestedAPIs(const RMessage2& aMessage)
	{
	LOG_FUNC;
	
	// Check we haven't had our features set yet
	if (ClientAvailable())
		{
		PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet);
		return;
		}

	CRemConInterfaceDetailsArray* interfaces = NULL;
	TRAPD(err, interfaces = ExtractInterestedAPIsL(aMessage));
	
	if(err == KErrNone)
		{
		// Ensure that none of these interfaces have already been registered by the client.
		// Also note if bulk server is required.
		TInt count = interfaces->Array().Count();
		TBool bulkServerRequired = EFalse;
		for (TInt ix=0; ix < count; ++ix)
			{
			CRemConInterfaceDetails* details = interfaces->Array()[ix];
			ASSERT_DEBUG(details);
			if (iClientProcess.IsInterfaceTypeRegisteredByAnotherSession(*this, details->Uid()))
				{
				// Destroy new interfaces and panic client.
				delete interfaces;
				PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientInterfaceAlreadyRegistered);
				return;
				}
			else if (details->IsBulk())
				{
				bulkServerRequired = ETrue;
				}
			}
	
		// Interfaces are OK, notify server if bulk server is required.
		iInterestedAPIs = interfaces;
		iClientProcess.InterfacesRegistered();
		if (bulkServerRequired)
			{
			iServer.BulkServerRequired();
			}
		}
	else
		{
		ASSERT_DEBUG(interfaces == NULL);
		}
	
	CompleteClient(aMessage, err);
	}

void CRemConTargetSession::SendToServer(CRemConMessage& aMsg)
	{
	LOG_FUNC;
	
	// Set our completion members.
	NumRemotes() = 0;
	NumRemotesToTry() = 0;
	SendError() = KErrNone;

	
	iSending = (aMsg.IsReliableSend()) ? ESendingReliable: ESendingUnreliable;

	iServer.SendResponse(aMsg, iClientProcess);
	}

void CRemConTargetSession::DoReceive()
	{
	// Request messages from the server on behalf of the client.
	// If there's anything waiting to be given to us, iClientProcess will call 
	// back to us with it.
	iServer.ReceiveRequest(iClientProcess);
	}