--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/accessoryservices/remotecontrolfw/server/src/session.cpp Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,1814 @@
+// Copyright (c) 2004-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:
+// Remote Control session implementation.
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+#include "e32base.h"
+
+#include <bluetooth/logger.h>
+#include <remcon/remconbearerinterface.h>
+#include <remcon/remconifdetails.h>
+#include <s32mem.h>
+#include "utils.h"
+#include "server.h"
+#include "bearermanager.h"
+#include "remconmessage.h"
+#include "connections.h"
+#include "activehelper.h"
+#include "session.h"
+#include "messagequeue.h"
+#include "remconserver.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("session");
+#endif
+
+CRemConSession* CRemConSession::NewL(CRemConServer& aServer,
+ CBearerManager& aBearerManager,
+ const RMessage2& aMessage,
+ TUint aId)
+ {
+ LOG_STATIC_FUNC
+ CRemConSession* self = new(ELeave) CRemConSession(aServer, aBearerManager, aId);
+ CleanupStack::PushL(self);
+ self->ConstructL(aMessage);
+ CLEANUPSTACK_POP1(self);
+ return self;
+ }
+
+CRemConSession::CRemConSession(CRemConServer& aServer,
+ CBearerManager& aBearerManager,
+ TUint aId)
+ : iServer(aServer),
+ iBearerManager(aBearerManager),
+ iId(aId)
+ {
+ LOG_FUNC
+ }
+
+void CRemConSession::ConstructL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Get the client's process ID.
+ RThread thread;
+ LEAVEIFERRORL(aMessage.Client(thread));
+ CleanupClosePushL(thread);
+ RProcess process;
+ LEAVEIFERRORL(thread.Process(process));
+ iClientInfo.ProcessId() = process.Id();
+ process.Close();
+ iClientInfo.SecureId() = thread.SecureId();
+ CleanupStack::PopAndDestroy(&thread);
+
+ iSendQueue = CMessageQueue::NewL();
+
+ TCallBack cb(SendNextCb, this);
+
+ iSendNextCallBack = new(ELeave) CAsyncCallBack(cb, CActive::EPriorityStandard);
+
+ // Tell the server about us.
+ LEAVEIFERRORL(iServer.ClientOpened(*this));
+
+ // Set our pointer into the connection history at the current/'Last' item.
+ iServer.SetConnectionHistoryPointer(Id());
+
+ iPendingMsgProcessor = new (ELeave) CActiveHelper(*this);
+ }
+
+CRemConSession::~CRemConSession()
+ {
+ LOG(KNullDesC8);
+ LOG_FUNC;
+
+ delete iPendingMsgProcessor;
+ delete iSendNextCallBack;
+ delete iSendQueue;
+ // we will need to tell the server which bearer this used to be connected to
+ // this enables the server to not inform a bearer that is already connected
+ // that its been connected
+ // Tell the server we've gone away- it may start its shutdown timer.
+ iServer.ClientClosed(*this, iRemoteAddress.BearerUid());
+ delete iInterestedAPIs;
+ iPlayerName.Close();
+ }
+
+void CRemConSession::ServiceL(const RMessage2& aMessage)
+ {
+ LOG(KNullDesC8);
+ LOG_FUNC;
+ LOG1(_L("\taMessage.Function() = %d"), aMessage.Function());
+
+ // Switch on the IPC number and call a 'message handler'. Message handlers
+ // complete aMessage (either with Complete or Panic), or make a note of
+ // the message for later asynchronous completion.
+ // Message handlers should not leave- the server does not have an Error
+ // function.
+
+ switch ( aMessage.Function() )
+ {
+ // Heap failure testing APIs.
+ case ERemConDbgMarkHeap:
+#ifdef _DEBUG
+ LOG(_L("\tmark heap"));
+ __UHEAP_MARK;
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConDbgCheckHeap:
+#ifdef _DEBUG
+ LOG1(_L("\tcheck heap (expecting %d cells)"), aMessage.Int0());
+ __UHEAP_CHECK(aMessage.Int0());
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConDbgMarkEnd:
+#ifdef _DEBUG
+ LOG1(_L("\tmark end (expecting %d cells)"), aMessage.Int0());
+ __UHEAP_MARKENDC(aMessage.Int0());
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConDbgFailNext:
+#ifdef _DEBUG
+ {
+ LOG1(_L("\tfail next (simulating failure after %d allocation(s))"), aMessage.Int0());
+ if ( aMessage.Int0() == 0 )
+ {
+ __UHEAP_RESET;
+ }
+ else
+ {
+ __UHEAP_FAILNEXT(aMessage.Int0());
+ }
+ }
+#endif // _DEBUG
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConSetClientType:
+ SetClientType(aMessage);
+ // This is a sync API- check that the message has been completed.
+ // (NB We don't check the converse for async APIs because the message
+ // may have been panicked synchronously.)
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConGoConnectionOriented:
+ GoConnectionOriented(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConGoConnectionless:
+ GoConnectionless(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConConnectBearer:
+ ConnectBearer(aMessage);
+ break;
+
+ case ERemConConnectBearerCancel:
+ ConnectBearerCancel(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConDisconnectBearer:
+ DisconnectBearer(aMessage);
+ break;
+
+ case ERemConDisconnectBearerCancel:
+ DisconnectBearerCancel(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConSend:
+ Send(aMessage);
+ break;
+
+ case ERemConSendNotify:
+ SendNotify(aMessage);
+ break;
+
+ case ERemConSendUnreliable:
+ SendUnreliable(aMessage);
+ break;
+
+ case ERemConSendCancel:
+ SendCancel(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConReceive:
+ Receive(aMessage);
+ break;
+
+ case ERemConReceiveCancel:
+ ReceiveCancel(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConGetConnectionCount:
+ GetConnectionCount(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConGetConnections:
+ GetConnections(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConNotifyConnectionsChange:
+ NotifyConnectionsChange(aMessage);
+ break;
+
+ case ERemConNotifyConnectionsChangeCancel:
+ NotifyConnectionsChangeCancel(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ case ERemConRegisterInterestedAPIs:
+ RegisterInterestedAPIs(aMessage);
+ ASSERT_DEBUG(aMessage.IsNull());
+ break;
+
+ default:
+ // Unknown message
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
+ break;
+ }
+ }
+
+void CRemConSession::CompleteClient(const RMessage2& aMessage, TInt aError)
+ {
+ LOG1(_L("\tcompleting client message with %d"), aError);
+ TBool cleanClientInfoMessage = (iClientInfo.Message().Handle() == aMessage.Handle());
+ aMessage.Complete(aError);
+ if(cleanClientInfoMessage)
+ {
+ iClientInfo.Message() = RMessage2();
+ }
+ }
+
+void CRemConSession::SetClientType(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if ( iType != ERemConClientTypeUndefined )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeAlreadySet);
+ return;
+ }
+
+ const TRemConClientType type = static_cast<TRemConClientType>(aMessage.Int0());
+ LOG1(_L("\trequested (TRemConClientType) type = %d"), type);
+
+ TInt err = aMessage.GetDesLength(1);
+ if(err >= 0)
+ {
+ TRAP(err, DoSetClientTypeL(aMessage));
+ if(err == KErrBadDescriptor)
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+ }
+ else if(err == KErrBadDescriptor)
+ {
+ // The additional parameters are optional (i.e. old or controller clients won't provide them).
+ err = KErrNone;
+ }
+
+ if(err != KErrNone)
+ {
+ CompleteClient(aMessage, err);
+ }
+ else
+ {
+ switch ( type )
+ {
+ case ERemConClientTypeController:
+ iType = type;
+ CompleteClient(aMessage, KErrNone);
+ break;
+
+ case ERemConClientTypeTarget:
+ // Check that there aren't already any target clients with the
+ // same process ID.
+ if ( !iServer.TargetClientWithSameProcessId(iClientInfo.ProcessId()) )
+ {
+ iType = type;
+ CompleteClient(aMessage, KErrNone);
+ }
+ else
+ {
+ CompleteClient(aMessage, KErrInUse);
+ }
+ break;
+
+ default:
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ break;
+ }
+ }
+
+ if ( iType != ERemConClientTypeUndefined )
+ {
+ // The type got set, so tell the server, so it can tell the bearers if
+ // necessary.
+ iServer.ClientTypeSet(*this);
+ }
+ }
+
+void CRemConSession::DoSetClientTypeL(const RMessage2& aMessage)
+ {
+ // Retrieve the client type information
+ RBuf8 typeBuf;
+ typeBuf.CreateL(sizeof(TPlayerTypeInformation));
+ CleanupClosePushL(typeBuf);
+ aMessage.ReadL(1, typeBuf);
+
+ const TPlayerTypeInformation* Ptr = reinterpret_cast<const TPlayerTypeInformation*> (typeBuf.Ptr());
+ iPlayerType.iPlayerType = (*Ptr).iPlayerType;
+ iPlayerType.iPlayerSubType = (*Ptr).iPlayerSubType;
+ // Retrieve the client player name inforamtion
+ iPlayerName.CreateL(aMessage.Int2());
+ CleanupClosePushL(iPlayerName);
+ aMessage.ReadL(3, iPlayerName);
+ CleanupStack::Pop(&iPlayerName);
+
+ CleanupStack::PopAndDestroy(&typeBuf);
+ }
+void CRemConSession::GoConnectionOriented(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( !iRemoteAddress.IsNull() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicAlreadyConnectionOriented);
+ return;
+ }
+
+ if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() || iSendMsg.Handle())
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+ if (iSending != ENotSending)
+ {
+ DoSendCancel();
+ }
+ EmptySendQueue();
+
+ // Get the desired address from the message and check it.
+ const TUid uid = TUid::Uid(aMessage.Int0());
+ LOG1(_L("\tuid = 0x%08x"), uid);
+ // Check the requested bearer exists.
+ TBool bearerExists = iBearerManager.BearerExists(uid);
+ if ( !bearerExists)
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerPluginIncorrectInterface);
+ return;
+ }
+ // Check the bearer-specific part of the address.
+ TBuf8<TRemConAddress::KMaxAddrSize> buf;
+ TInt err = aMessage.Read(1, buf);
+ if ( err != KErrNone )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+
+ // Do security check- if this client won't be allowed to use the bearer
+ // then fail the request.
+ // NB This security check (repeated in debug at ConnectBearer and
+ // DisconnectBearer time) is all that stands between a connection-oriented
+ // client and the bearer, and is all the caps checking that RemCon does!
+ err = KErrPermissionDenied;
+ if ( iBearerManager.CheckPolicy(uid, aMessage) )
+ {
+ err = KErrNone;
+ }
+
+
+ // if alls well and we're connection oriented then set up as such
+ if (KErrNone == err)
+ {
+ // The client has passed all our checks- set our data member.
+ iRemoteAddress.BearerUid() = uid;
+ iRemoteAddress.Addr() = buf;
+ // tell the server
+ iServer.ClientGoConnectionOriented(*this,uid);
+ }
+
+ CompleteClient(aMessage, err);
+ }
+
+void CRemConSession::GoConnectionless(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( iRemoteAddress.IsNull() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented);
+ return;
+ }
+
+ if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() || iSendMsg.Handle())
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+
+ if (iSending != ENotSending)
+ {
+ DoSendCancel();
+ }
+ EmptySendQueue();
+
+ // we will need to tell the server which bearer this used to be connected to
+ // this enables the server to not inform a bearer that is already connected
+ // that its been connected
+ TUid oldUid = iRemoteAddress.BearerUid();
+
+ iRemoteAddress.BearerUid() = KNullUid;
+
+ // tell the server
+ iServer.ClientGoConnectionless(*this, oldUid);
+
+ CompleteClient(aMessage, KErrNone);
+ }
+
+void CRemConSession::ConnectBearer(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+
+ if ( iRemoteAddress.IsNull() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented);
+ return;
+ }
+
+ // Check the requested bearer exists.
+ TBool bearerExists = iBearerManager.BearerExists(iRemoteAddress.BearerUid());
+ // This check was done at GoConnectionOriented time.
+ ASSERT_DEBUG(bearerExists);
+ // So was this one.
+ ASSERT_DEBUG(iBearerManager.CheckPolicy(iRemoteAddress.BearerUid(), aMessage));
+
+ // Check the state of our given connection at the bearer level. If it is:
+ // -) disconnected request the connection to come up,
+ // -) connecting or disconnecting, add message to the queue of pending
+ // messages, and process it once connecting/disconnecting has been completed
+ // -) connected, complete the client's message,
+
+ TConnectionState conState;
+ conState = iServer.ConnectionState(iRemoteAddress);
+
+ if ( conState == EDisconnected )
+ {
+ // The bearer may indicate connection synchronously, so set this
+ // message _before_ we ask them
+ iConnectBearerMsg = aMessage;
+ TInt err = iBearerManager.Connect(iRemoteAddress);
+ if ( err != KErrNone )
+ {
+ CompleteClient(iConnectBearerMsg, err);
+ }
+ }
+ else if ( conState == EDisconnecting || conState == EConnecting )
+ {
+ if ( iPendingMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+ // Store the message, it will get processed later.
+ iPendingMsg = aMessage;
+ }
+ else // EConnected
+ {
+ CompleteClient(aMessage, KErrNone);
+ }
+
+ }
+
+void CRemConSession::ConnectBearerCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( iConnectBearerMsg.Handle() )
+ {
+ CompleteClient(iConnectBearerMsg, KErrCancel);
+ }
+ else if ( iPendingMsg.Handle() && ( iPendingMsg.Function() == ERemConConnectBearer ))
+ {
+ CompleteClient(iPendingMsg, KErrCancel);
+ }
+
+ CompleteClient(aMessage, KErrNone);
+ // At no point do we make any change to the processes going on underneath
+ // us- 'Cancel' APIs are just for cancelling interest in an async
+ // operation.
+ }
+
+void CRemConSession::DisconnectBearer(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( iDisconnectBearerMsg.Handle() || iConnectBearerMsg.Handle() || iSendMsg.Handle())
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+
+ if ( iRemoteAddress.IsNull() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented);
+ return;
+ }
+
+ if (iSending != ENotSending)
+ {
+ DoSendCancel();
+ }
+ EmptySendQueue();
+
+ // Check the requested bearer exists.
+ TBool bearerExists = iBearerManager.BearerExists(iRemoteAddress.BearerUid());
+ // This check was done at GoConnectionOriented time.
+ ASSERT_DEBUG(bearerExists);
+ // So was this one.
+ ASSERT_DEBUG(iBearerManager.CheckPolicy(iRemoteAddress.BearerUid(), aMessage));
+
+ // Check the state of the given connection. If it is:
+ // -) connected, request connection to go away,
+ // -) disconnected, compete the client's message,
+ // -) connecting or disconnecting, add message to the queue of pending
+ // messages, and process it once connecting/disconnecting has been completed
+
+ TInt err;
+ TConnectionState conState;
+ conState = iServer.ConnectionState(iRemoteAddress);
+
+ if ( conState == EConnected )
+ {
+ // The bearer may indicate disconnection synchronously, so set this
+ // message _before_ we ask them
+ iDisconnectBearerMsg = aMessage;
+ err = iBearerManager.Disconnect(iRemoteAddress);
+ if ( err != KErrNone )
+ {
+ CompleteClient(iDisconnectBearerMsg, err);
+ }
+ }
+ else if ( conState == EDisconnecting || conState == EConnecting )
+ {
+ if ( iPendingMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+ // Store the message, it will get processed later.
+ iPendingMsg = aMessage;
+ }
+ else //disconnected
+ {
+ CompleteClient(aMessage, KErrNone);
+ }
+ }
+
+void CRemConSession::DisconnectBearerCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( iType != ERemConClientTypeController )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadType);
+ return;
+ }
+
+ if ( iDisconnectBearerMsg.Handle() )
+ {
+ CompleteClient(iDisconnectBearerMsg, KErrCancel);
+ }
+ else if ( iPendingMsg.Handle() && (iPendingMsg.Function() == ERemConDisconnectBearer ))
+ {
+ CompleteClient(iPendingMsg, KErrCancel);
+ }
+
+ CompleteClient(aMessage, KErrNone);
+ }
+
+void CRemConSession::Send(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we're not already sending...
+ if ( iSendMsg.Handle())
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicSendAlreadyOutstanding);
+ return;
+ }
+
+ iSendMsg = aMessage;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // Check we don't have a disconnect outstanding- this makes no sense from
+ // a client viewpoint (they should cancel the disconnect first).
+ // [The client is allowed to have a connect request outstanding- the
+ // bearer manager makes sure a bearer-level connect is not posted on the
+ // same address twice.]
+ if ( iDisconnectBearerMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+
+ TRAPD(err, DoSendL(aMessage));
+ if ( err != KErrNone )
+ {
+ CompleteClient(aMessage, err);
+ }
+ }
+
+/**
+Sends a notify message to the remote device.
+
+This function is intended for the RemCon controller client to send a notify
+command to the remote device.
+*/
+void CRemConSession::SendNotify(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we're not already sending...
+ if ( iSendMsg.Handle())
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicSendAlreadyOutstanding);
+ return;
+ }
+
+ iSendMsg = aMessage;
+
+ // Check we've had our type set...
+ if (Type() != ERemConClientTypeController)
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // Check we don't have a disconnect outstanding- this makes no sense from
+ // a client viewpoint (they should cancel the disconnect first).
+ // [The client is allowed to have a connect request outstanding- the
+ // bearer manager makes sure a bearer-level connect is not posted on the
+ // same address twice.]
+ if ( iDisconnectBearerMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ return;
+ }
+
+ TRAPD(err, DoSendNotifyL(aMessage));
+ if ( err != KErrNone )
+ {
+ CompleteClient(aMessage, err);
+ }
+ }
+
+void CRemConSession::DoSendL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Get the data the client wants to send.
+ const TUid interfaceUid = TUid::Uid(aMessage.Int0());
+ LOG1(_L("\tinterfaceUid = 0x%08x"), interfaceUid);
+
+ if (aMessage.GetDesLengthL(1) != sizeof(TOperationInformation))
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+
+ TPckgBuf<TOperationInformation> opInfoPckg;
+
+ TInt err= aMessage.Read(
+ 1, // location of the descriptor in the client's message (as we expect them to have set it up)
+ opInfoPckg, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+
+ const TUint operationId = opInfoPckg().iOperationId;
+ LOG1(_L("\toperationId = 0x%02x"), operationId);
+
+ const TRemConMessageSubType messageSubType = opInfoPckg().iMessageSubType;
+ LOG1(_L("\tmessageSubType = 0x%02x"), messageSubType);
+
+
+ const TUint dataLength = (TUint)aMessage.GetDesLengthL(3);
+ LOG1(_L("\tdataLength = %d"), dataLength);
+
+ // If the client wanted to send some operation-associated data, read it
+ // from them.
+ RBuf8 sendDes;
+ if ( dataLength != 0 )
+ {
+ sendDes.CreateL(dataLength);
+ TInt err = aMessage.Read(
+ 3, // location of the descriptor in the client's message (as we expect them to have set it up)
+ sendDes, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+ // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client
+ // descriptor is a panicking offence for them, not an 'error the
+ // request' offence.
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ sendDes.Close();
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+ }
+ CleanupClosePushL(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;
+
+ // Examine the session type.
+ switch ( iType )
+ {
+ case ERemConClientTypeTarget:
+ {
+ 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
+ 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
+
+ }
+ break;
+
+ case ERemConClientTypeController:
+ {
+ LOG(_L("\tCONTROLLER send"));
+ if ( (messageSubType == ERemConNotifyCommandAwaitingInterim)
+ || (messageSubType == ERemConNotifyCommandAwaitingChanged)
+ )
+ {
+ LOG(_L("\terror, not allowed to use Send() to send notify command"));
+ CleanupStack::PopAndDestroy(&sendDes);
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
+ return;
+ }
+ else
+ {
+ msg = CRemConMessage::NewL(
+ iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP)
+ ERemConCommand,
+ messageSubType,
+ interfaceUid,
+ operationId,
+ sendDes, // msg takes ownership
+ Id(), // session id for when the response comes back
+ 0, // we let the bearer manager invent a new transaction id when the message gets to it
+ ETrue);
+ }
+ CLEANUPSTACK_POP1(&sendDes); // now owned by msg
+
+ }
+ break;
+
+ default:
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+
+ ASSERT_DEBUG(iSendQueue);
+ // We know msg is valid at this stage as the code would leave or panic earlier if msg was
+ // not set.
+ ASSERT_DEBUG(msg);
+
+ if (iSending != ENotSending || !iSendQueue->IsEmpty())
+ {
+ iSendQueue->Append(*msg);
+ }
+ else
+ {
+ // we know msg cannot be null here as said above.
+ SendToServer(*msg);
+ }
+ }
+
+/**
+@see CRemConSession::SendNotify
+*/
+void CRemConSession::DoSendNotifyL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Get the data the client wants to send.
+ const TUid interfaceUid = TUid::Uid(aMessage.Int0());
+ LOG1(_L("\tinterfaceUid = 0x%08x"), interfaceUid);
+
+ if (aMessage.GetDesLengthL(1) != sizeof(TOperationInformation))
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+
+ TPckgBuf<TOperationInformation> opInfoPckg;
+ TInt err= aMessage.Read(
+ 1, // location of the descriptor in the client's message (as we expect them to have set it up)
+ opInfoPckg, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+
+ const TUint operationId = opInfoPckg().iOperationId;
+ LOG1(_L("\toperationId = 0x%02x"), operationId);
+
+ const TRemConMessageSubType messageSubType = opInfoPckg().iMessageSubType;
+ LOG1(_L("\tmessageSubType = 0x%02x"), messageSubType);
+
+ const TUint dataLength = (TUint)aMessage.GetDesLengthL(2);
+ LOG1(_L("\tdataLength = %d"), dataLength);
+
+ // If the client wanted to send some operation-associated data, read it
+ // from them.
+ RBuf8 sendDes;
+ if ( dataLength != 0 )
+ {
+ sendDes.CreateL(dataLength);
+ TInt err = aMessage.Read(
+ 2, // location of the descriptor in the client's message (as we expect them to have set it up)
+ sendDes, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+ // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client
+ // descriptor is a panicking offence for them, not an 'error the
+ // request' offence.
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ sendDes.Close();
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+ }
+
+ // 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;
+
+ if (messageSubType != ERemConNotifyCommandAwaitingInterim)
+ {
+ sendDes.Close();
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
+ return;
+ }
+
+ CleanupClosePushL(sendDes);
+ msg = CRemConMessage::NewL(
+ iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP)
+ ERemConNotifyCommand,
+ messageSubType,
+ interfaceUid,
+ operationId,
+ sendDes, // msg takes ownership
+ Id(), // session id for when the response comes back
+ 0, // we let the bearer manager invent a new transaction id when the message gets to it
+ ETrue);
+ CLEANUPSTACK_POP1(&sendDes); // now owned by msg
+
+ LOG(_L("\tCONTROLLER send"));
+ ASSERT_DEBUG(iSendQueue);
+ if (iSending != ENotSending || !iSendQueue->IsEmpty())
+ {
+ iSendQueue->Append(*msg);
+ }
+ else
+ {
+ SendToServer(*msg);
+ }
+ }
+
+void CRemConSession::SendUnreliable(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // Check we don't have a disconnect outstanding- this makes no sense from
+ // a client viewpoint (they should cancel the disconnect first).
+ // [The client is allowed to have a connect request outstanding- the
+ // bearer manager makes sure a bearer-level connect is not posted on the
+ // same address twice.]
+ if ( iDisconnectBearerMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding);
+ 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* CRemConSession::DoCreateUnreliableMessageL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Get the data the client wants to send.
+ const TUid interfaceUid = TUid::Uid(aMessage.Int0());
+ LOG1(_L("\tinterfaceUid = 0x%08x"), interfaceUid);
+
+ if (aMessage.GetDesLengthL(1) != sizeof(TOperationInformation))
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ LEAVEL(KErrBadDescriptor);
+ }
+
+ TPckgBuf<TOperationInformation> opInfoPckg;
+
+ TInt err= aMessage.Read(
+ 1, // location of the descriptor in the client's message (as we expect them to have set it up)
+ opInfoPckg, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ LEAVEL(KErrBadDescriptor);
+ }
+
+ const TUint operationId = opInfoPckg().iOperationId;
+ LOG1(_L("\toperationId = 0x%02x"), operationId);
+
+ const TRemConMessageSubType messageSubType = opInfoPckg().iMessageSubType;
+ LOG1(_L("\tmessageSubType = 0x%02x"), messageSubType);
+
+
+ const TUint dataLength = (TUint)aMessage.GetDesLengthL(2);
+ LOG1(_L("\tdataLength = %d"), dataLength);
+
+ // If the client wanted to send some operation-associated data, read it
+ // from them.
+ RBuf8 sendDes;
+ if ( dataLength != 0 )
+ {
+ sendDes.CreateL(dataLength);
+ TInt err = aMessage.Read(
+ 2, // location of the descriptor in the client's message (as we expect them to have set it up)
+ sendDes, // descriptor to write to from client memory space
+ 0 // offset into our descriptor to put the client's data
+ );
+ // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client
+ // descriptor is a panicking offence for them, not an 'error the
+ // request' offence.
+ if ( err != KErrNone )
+ {
+ LOG1(_L("\taMessage.Read = %d"), err);
+ sendDes.Close();
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ LEAVEL(KErrBadDescriptor);
+ }
+ }
+ CleanupClosePushL(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;
+
+ // Examine the session type.
+ switch ( iType )
+ {
+ case ERemConClientTypeTarget:
+ {
+ 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
+ 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
+ break;
+ }
+
+ case ERemConClientTypeController:
+ {
+ LOG(_L("\tCONTROLLER send"));
+
+ // A client is not allowed to send an unreliable notify command.
+ if ( (messageSubType == ERemConNotifyCommandAwaitingInterim)
+ || (messageSubType == ERemConNotifyCommandAwaitingChanged)
+ )
+ {
+ LOG(_L8("\tNot allowed to send unreliable notify command"));
+ CleanupStack::PopAndDestroy(&sendDes);
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc);
+ LEAVEL(KErrBadDescriptor);
+ }
+
+ msg = CRemConMessage::NewL(
+ iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP)
+ ERemConCommand, // controllers can only send commands
+ messageSubType,
+ interfaceUid,
+ operationId,
+ sendDes, // msg takes ownership
+ Id(), // session id for when the response comes back
+ 0, // we let the bearer manager invent a new transaction id when the message gets to it
+ EFalse);
+ CLEANUPSTACK_POP1(&sendDes); // now owned by msg
+
+ }
+ break;
+
+ default:
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+
+ return msg;
+ }
+
+void CRemConSession::SendToServer(CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+
+ // Set our completion members.
+ NumRemotes() = 0;
+ NumRemotesToTry() = 0;
+ SendError() = KErrNone;
+
+
+ iSending = (aMsg.IsReliableSend()) ? ESendingReliable: ESendingUnreliable;
+ switch ( iType )
+ {
+ case ERemConClientTypeTarget:
+ {
+ iServer.SendResponse(aMsg, *this);
+ break;
+ }
+ case ERemConClientTypeController:
+ {
+ iServer.SendCommand(aMsg);
+ break;
+ }
+ default:
+ DEBUG_PANIC_LINENUM;
+ break;
+ }
+ }
+
+
+void CRemConSession::SendCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // See comments in ConnectBearerCancel.
+ if ( iSendMsg.Handle() )
+ {
+ DoSendCancel();
+ }
+
+ if (iSendMsg.Handle())
+ {
+ CRemConMessage* msg;
+ TBool first = ETrue;
+ ASSERT_DEBUG(iSendQueue);
+ TSglQueIter<CRemConMessage>& iter = iSendQueue->SetToFirst();
+ while ((msg = iter++) != NULL)
+ {
+ if (msg->IsReliableSend())
+ {
+ CompleteClient(iSendMsg, KErrCancel);
+ iSendQueue->RemoveAndDestroy(*msg);
+ if (first)
+ {
+ ASSERT_DEBUG(iSendNextCallBack);
+ iSendNextCallBack->Cancel();
+ }
+ break;
+ }
+ first = EFalse;
+ }
+ }
+
+ CompleteClient(aMessage, KErrNone);
+ }
+
+void CRemConSession::DoSendCancel()
+ {
+ LOG_FUNC;
+ // We must tell the server, and pull the CRemConMessage from the
+ // 'outgoing pending TSP' queue if it's on it. If the TSP is currently
+ // processing the CRemConMessage, we must tell it to stop before we
+ // can complete the RMessage2 iSendMsg- the TSP might still be
+ // dereferencing bits of it. (The TSP is given iSendMsg so it can
+ // access the client's secure ID and do a capability check.)
+ // NB This only matters for commands- responses don't go through the
+ // TSP.
+ // Not also that this processing *stops* this
+ // CRemConSession::SendCancel method from being the very simple 'I'm
+ // no longer interested in the completion of the asynchronous request'
+ // type of API it (and all cancels) should be. It actually does work
+ // as well. As long as this work is implemented _synchronously_, we
+ // should be OK.
+ iServer.SendCancel(*this);
+
+ NumRemotesToTry() = 0;
+ iSendError = KErrCancel;
+ CompleteSend();
+
+ }
+
+void CRemConSession::EmptySendQueue()
+ {
+ ASSERT_DEBUG(!iSendMsg.Handle())
+ ASSERT_DEBUG(iSendNextCallBack);
+ iSendNextCallBack->Cancel();
+ CRemConMessage* msg;
+ ASSERT_DEBUG(iSendQueue);
+ TSglQueIter<CRemConMessage>& iter = iSendQueue->SetToFirst();
+ while ((msg = iter++) != NULL)
+ {
+ iSendQueue->RemoveAndDestroy(*msg);
+ }
+ }
+
+void CRemConSession::Receive(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Messages are pushed from bearers, so we
+ // (a) do some sanity checking,
+ // (b) check the queue of incoming messages in case there's anything
+ // already waiting to be given to the client.
+
+ if ( iReceiveMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicReceiveAlreadyOutstanding);
+ return;
+ }
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ iReceiveMsg = aMessage;
+ // If there's anything waiting to be given to us, ReceiveRequest will call
+ // back to us with it.
+ iServer.ReceiveRequest(*this);
+ }
+
+void CRemConSession::ReceiveCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // See comments in ConnectBearerCancel.
+ if ( iReceiveMsg.Handle() )
+ {
+ CompleteClient(iReceiveMsg, KErrCancel);
+ }
+ CompleteClient(aMessage, KErrNone);
+ }
+
+void CRemConSession::GetConnectionCount(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // Get the answer to the question- the number of connections at the
+ // current point in time (i.e. the latest entry in the connection
+ // history).
+ const TUint connCount = iServer.Connections().Count();
+ LOG1(_L("\tconnCount = %d"), connCount);
+ TPckg<TUint> count(connCount);
+ TInt err = aMessage.Write(0, count);
+
+ // If the client was told the answer with no error, then remember the
+ // current point in the connection history, so that when the client asks
+ // for the connections themselves, we give them a consistent answer.
+ if ( err == KErrNone )
+ {
+ iServer.SetConnectionHistoryPointer(Id());
+ }
+ CompleteClient(aMessage, err);
+ }
+
+void CRemConSession::GetConnections(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // Get the array of connections at the point in the history we're
+ // interested in and write it back to the client. NB This is not
+ // necessarily the Last item in the history but the item that we were
+ // pointing at when GetConnectionCount was called.
+ const CConnections& conns = iServer.Connections(iId);
+ const TUint count = conns.Count();
+ LOG1(_L("\tcount = %d"), count);
+ RBuf8 buf;
+ TInt err = buf.Create(count * sizeof(TRemConAddress));
+ if ( err == KErrNone )
+ {
+ TSglQueIter<TRemConAddress>& iter = conns.SetToFirst();
+ TRemConAddress* addr;
+ while ( ( addr = iter++ ) != NULL )
+ {
+ buf.Append((TUint8*)addr, sizeof(TRemConAddress));
+ }
+
+ // Write back to the client...
+ err = aMessage.Write(0, buf);
+ buf.Close();
+ if ( err != KErrNone )
+ {
+ // We don't need to call SetConnectionHistoryPointer here because
+ // the server will do it when it cleans up the panicked client.
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor);
+ return;
+ }
+ }
+
+ // Whether or not there was an error, we're no longer interested in the
+ // history item we're currently registered as being interested in, so tell
+ // the server to bump up our pointer to the current (latest) one. NB This
+ // may in fact be the same record, if no connection changes have occurred
+ // since GetConnectionCount was called, but it's still important to give
+ // the server a chance to remove obsolete history records.
+ iServer.SetConnectionHistoryPointer(Id());
+ CompleteClient(aMessage, err);
+ }
+
+void CRemConSession::NotifyConnectionsChange(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Messages are pushed to us from bearers, so we don't need anything more
+ // than some sanity checking here.
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ if ( iNotifyConnectionsChangeMsg.Handle() )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicConnectionsNotificationAlreadyOutstanding);
+ }
+ else
+ {
+ iNotifyConnectionsChangeMsg = aMessage;
+ // Check the connection history for any more recent items than that we
+ // currently know about. If our pointer into the connection history
+ // isn't pointing at the 'current' item, we can complete the
+ // notification immediately and move the pointer up.
+ if ( !iServer.ConnectionHistoryPointerAtLatest(Id()) )
+ {
+ CompleteClient(iNotifyConnectionsChangeMsg, KErrNone);
+ iServer.SetConnectionHistoryPointer(Id());
+ }
+ }
+ }
+
+void CRemConSession::NotifyConnectionsChangeCancel(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ // Check we've had our type set...
+ if ( Type() != ERemConClientTypeController
+ && Type() != ERemConClientTypeTarget
+ )
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientTypeNotSet);
+ return;
+ }
+
+ // See comments in ConnectBearerCancel.
+ if ( iNotifyConnectionsChangeMsg.Handle() )
+ {
+ CompleteClient(iNotifyConnectionsChangeMsg, KErrCancel);
+ }
+ CompleteClient(aMessage, KErrNone);
+ }
+
+void CRemConSession::RegisterInterestedAPIs(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ if(iType == ERemConClientTypeUndefined)
+ {
+ PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicRegisterInterestedAPIsInNonTargetSession);
+ }
+
+ TRAPD(err, DoRegisterInterestedAPIsL(aMessage));
+
+ if(iType == ERemConClientTypeController)
+ {
+ iServer.ControllerClientAvailable();
+ }
+ else if(err == KErrNone) // must be target
+ {
+ iServer.TargetClientAvailable(*this);
+
+ TInt count = iInterestedAPIs->Array().Count();
+ for(TInt ix=0; ix<count; ++ix)
+ {
+ CRemConInterfaceDetails* details = iInterestedAPIs->Array()[ix];
+ ASSERT_DEBUG(details);
+ if(details->IsBulk())
+ {
+ iServer.BulkServerRequired();
+ break;
+ }
+ }
+ }
+
+ CompleteClient(aMessage, err);
+ }
+
+void CRemConSession::DoRegisterInterestedAPIsL(const RMessage2& aMessage)
+ {
+ LOG_FUNC;
+
+ RBuf8 buf;
+ buf.CreateL(aMessage.GetDesLengthL(0));
+ CleanupClosePushL(buf);
+
+ aMessage.ReadL(0, buf);
+ RDesReadStream ipcStream(buf);
+
+ iInterestedAPIs = CRemConInterfaceDetailsArray::InternalizeL(ipcStream);
+
+ ipcStream.Close();
+ CleanupStack::PopAndDestroy(&buf);
+ }
+
+void CRemConSession::CompleteConnect(const TRemConAddress& aAddr, TInt aError)
+ {
+ LOG_FUNC;
+ LOG2(_L("\taError = %d, aAddr.BearerUid = 0x%08x"), aError, aAddr.BearerUid());
+
+ LOG1(_L("\tiRemoteAddress.BearerUid = 0x%08x"), iRemoteAddress.BearerUid());
+ LOG1(_L("\tiConnectBearerMsg.Handle = %d"), iConnectBearerMsg.Handle());
+
+ if ( iRemoteAddress == aAddr )
+ {
+ if ( iConnectBearerMsg.Handle() )
+ {
+ // We are a session that has an outstanding request on this specific
+ // connection address.
+ CompleteClient(iConnectBearerMsg, aError);
+ }
+ else
+ {
+ // Connect bearer message is not valid.
+ // Check for pending messages.
+ CheckForPendingMsg();
+ }
+ }
+ }
+
+void CRemConSession::CompleteDisconnect(const TRemConAddress& aAddr, TInt aError)
+ {
+ LOG_FUNC;
+ LOG2(_L("\taError = %d, aAddr.BearerUid = 0x%08x"), aError, aAddr.BearerUid());
+
+ LOG1(_L("\tiRemoteAddress.BearerUid = 0x%08x"), iRemoteAddress.BearerUid());
+ LOG1(_L("\tiDisconnectBearerMsg.Handle = %d"), iDisconnectBearerMsg.Handle());
+
+ if ( iRemoteAddress == aAddr )
+ {
+ if ( iDisconnectBearerMsg.Handle() )
+ {
+ // We are a session that has an outstanding request on this specific
+ // connection address.
+ CompleteClient(iDisconnectBearerMsg, aError);
+ }
+ else
+ {
+ // Diconnect bearer message is not valid.
+ // Check for pending messages.
+ CheckForPendingMsg();
+ }
+
+ }
+ }
+
+void CRemConSession::ConnectionsChanged()
+ {
+ LOG_FUNC;
+
+ LOG1(_L("\tiNotifyConnectionsChangeMsg.Handle = %d"), iNotifyConnectionsChangeMsg.Handle());
+ if ( iNotifyConnectionsChangeMsg.Handle() )
+ {
+ // Set the connection history pointer to point to the latest item and then complete the
+ // NotifyConnectionChange request of the client.
+ iServer.SetConnectionHistoryPointer(Id());
+ CompleteClient(iNotifyConnectionsChangeMsg, KErrNone);
+ }
+ }
+
+void CRemConSession::CompleteSend()
+ {
+ LOG_FUNC;
+ LOG2(_L("\tiNumRemotes = %d, iSendError = %d"), iNumRemotes, iSendError);
+
+ ASSERT_DEBUG(NumRemotesToTry() == 0);
+ NumRemotesToTry() = -1;
+
+
+ if (iSending == ESendingReliable)
+ {
+ if ( iSendError == KErrNone )
+ {
+ TPckg<TUint> count(iNumRemotes);
+ // 2 is the slot in the client's message for the number of remotes the
+ // message got sent to.
+ iSendError = iSendMsg.Write(2, count);
+ }
+ CompleteClient(iSendMsg, iSendError);
+ }
+
+ ASSERT_DEBUG(iSendQueue);
+ if (!iSendQueue->IsEmpty())
+ {
+ ASSERT_DEBUG(iSendNextCallBack);
+ iSendNextCallBack->CallBack();
+ }
+ iSending = ENotSending;
+ }
+
+void CRemConSession::CompleteSendNotify()
+ {
+ LOG_FUNC;
+ LOG1(_L("\tiSendError = %d"), iSendError);
+
+ if (iSending == ESendingReliable)
+ {
+ CompleteClient(iSendMsg, iSendError);
+ }
+
+ ASSERT_DEBUG(iSendQueue);
+ if (!iSendQueue->IsEmpty())
+ {
+ ASSERT_DEBUG(iSendNextCallBack);
+ iSendNextCallBack->CallBack();
+ }
+ iSending = ENotSending;
+ }
+
+TInt CRemConSession::SendNextCb(TAny* aThis)
+ {
+ static_cast<CRemConSession*>(aThis)->DoSendNext();
+ return KErrNone;
+ }
+
+void CRemConSession::DoSendNext()
+ {
+ ASSERT_DEBUG(iSendQueue);
+ CRemConMessage& msg = iSendQueue->First();
+ iSendQueue->Remove(msg);
+ SendToServer(msg);
+ }
+
+void CRemConSession::PanicSend(TRemConClientPanic aCode)
+ {
+ LOG_FUNC;
+ LOG1(_L("\taCode = %d"), aCode);
+
+ PANIC_MSG(iSendMsg, KRemConClientPanicCat, aCode);
+ }
+
+TBool CRemConSession::SupportedMessage(const CRemConMessage& aMsg)
+ {
+ // Return true unless this is a command for an unsupported interface
+ return !(aMsg.MsgType() == ERemConCommand && !FindInterfaceByUid(aMsg.InterfaceUid()));
+ }
+
+TInt CRemConSession::WriteMessageToClient(const CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+
+ ASSERT_DEBUG(SupportedMessage(aMsg));
+ ASSERT_DEBUG(iReceiveMsg.Handle());
+ TRAPD(err, WriteMessageToClientL(aMsg));
+ CompleteClient(iReceiveMsg, err);
+
+ LOG1(_L("\terr = %d"), err);
+ return err;
+ }
+
+void CRemConSession::WriteMessageToClientL(const CRemConMessage& aMsg)
+ {
+ LOG_FUNC;
+
+ //check if our client is interested in this API
+ //Only need to check commands because it is safe to assume that we are interested
+ //in the response if we have sent out a command.
+ if(aMsg.MsgType() == ERemConCommand && !FindInterfaceByUid(aMsg.InterfaceUid()))
+ {
+ //The server will clean up the resource allocated for this msg
+ LEAVEL(KErrArgument);
+ }
+
+ // This logging code left in for maintenance.
+ //LOG1(_L("\t\tOperationData = \"%S\""), &aMsg.OperationData());
+
+ TRemConClientReceivePackage receivePackage;
+ receivePackage.iInterfaceUid = aMsg.InterfaceUid();
+ receivePackage.iOperationId = aMsg.OperationId();
+ receivePackage.iMessageSubType = aMsg.MsgSubType();
+ receivePackage.iRemoteAddress = aMsg.Addr();
+
+ TPckgC<TRemConClientReceivePackage> recPckg(receivePackage);
+ LEAVEIFERRORL(iReceiveMsg.Write(0, recPckg));
+
+ // Note that we do not panic the client if their descriptor is not
+ // big enough to hold the operation-specific data. If we did, then
+ // a buggy remote could take down a client of RemCon. Just error
+ // the client instead.
+ LEAVEIFERRORL(iReceiveMsg.Write(1, aMsg.OperationData()));
+ }
+
+void CRemConSession::CheckForPendingMsg() const
+ {
+ LOG_FUNC;
+ if (iPendingMsg.Handle())
+ {
+ ASSERT_DEBUG(iPendingMsgProcessor);
+ iPendingMsgProcessor->Complete();
+ }
+ }
+
+void CRemConSession::ProcessPendingMsgL()
+ {
+ LOG_FUNC;
+ if (!iPendingMsg.Handle())
+ {
+ // This means that the pending connect or disconnect message,
+ // has been cancelled by the time we got here.
+ // (It was cancelled between two following calls:
+ // iPendingMsgProcessor::Complete and iPendingMsgProcessor::RunL
+ return;
+ }
+
+ ServiceL(iPendingMsg);
+ if (iPendingMsg.Handle())
+ {
+ // This means that the pending msg has not been completed in ServiceL call.
+ // It was stored either in iConnectBearerMsg or iDisconnectBearerMsg member.
+ // This also means that this message is not "pending" any more
+ // (as processing of its copy has been started).
+ // However because the copy will get completed we need to
+ // clean iPendingMsg.iHandle here
+ // To supress coverity error for uninitialized use of 'emptyMsg' coverity annotations
+ // are used as the in-line default constructor of RMessage2 doesn't initialize all member variables.
+ // coverity[var_decl]
+ RMessage2 emptyMsg;
+ iPendingMsg = emptyMsg;
+ }
+ }
+
+
+TInt CRemConSession::SupportedInterfaces(RArray<TUid>& aUids)
+ {
+ LOG_FUNC
+ ASSERT_DEBUG(iInterestedAPIs);
+ TInt err = KErrNone;
+
+ aUids.Reset();
+ TInt count = iInterestedAPIs->Array().Count();
+ for(TInt i=0; (i<count) && (err == KErrNone); i++)
+ {
+ CRemConInterfaceDetails* details = iInterestedAPIs->Array()[i];
+ ASSERT_DEBUG(details);
+ err = aUids.Append(details->Uid());
+ }
+
+ return err;
+ }
+
+TInt CRemConSession::SupportedBulkInterfaces(RArray<TUid>& aUids)
+ {
+ LOG_FUNC
+ ASSERT_DEBUG(iInterestedAPIs);
+ TInt err = KErrNone;
+
+ aUids.Reset();
+ TInt count = iInterestedAPIs->Array().Count();
+ for(TInt i=0; (i<count) && (err == KErrNone); i++)
+ {
+ CRemConInterfaceDetails* details = iInterestedAPIs->Array()[i];
+ ASSERT_DEBUG(details);
+ if(details->IsBulk())
+ {
+ err = aUids.Append(details->Uid());
+ }
+ }
+
+ return err;
+ }
+
+TInt CRemConSession::SupportedOperations(TUid aInterfaceUid, RArray<TUint>& aOperations)
+ {
+ LOG_FUNC
+ TInt err = KErrNotSupported;
+ CRemConInterfaceDetails* details = FindInterfaceByUid(aInterfaceUid);
+
+ if(details)
+ {
+ TRAP(err, details->GetRemConInterfaceFeaturesL(aOperations));
+ }
+ return err;
+ }
+
+CRemConInterfaceDetails* CRemConSession::FindInterfaceByUid(TUid aUid) const
+ {
+ LOG_FUNC
+ ASSERT_DEBUG(iInterestedAPIs);
+ TInt count = iInterestedAPIs->Array().Count();
+ for(TInt ix=0; ix<count; ++ix)
+ {
+ CRemConInterfaceDetails* details = iInterestedAPIs->Array()[ix];
+ ASSERT_DEBUG(details);
+ if(details->Uid() == aUid)
+ {
+ return details;
+ }
+ }
+ return NULL;
+ }
+
+