diff -r 000000000000 -r 4e1aa6a622a0 accessoryservices/remotecontrolfw/server/src/session.cpp --- /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 +#include +#include +#include +#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(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 (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 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 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 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 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& 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& 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 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& 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; ixArray()[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 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(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 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& aUids) + { + LOG_FUNC + ASSERT_DEBUG(iInterestedAPIs); + TInt err = KErrNone; + + aUids.Reset(); + TInt count = iInterestedAPIs->Array().Count(); + for(TInt i=0; (iArray()[i]; + ASSERT_DEBUG(details); + err = aUids.Append(details->Uid()); + } + + return err; + } + +TInt CRemConSession::SupportedBulkInterfaces(RArray& aUids) + { + LOG_FUNC + ASSERT_DEBUG(iInterestedAPIs); + TInt err = KErrNone; + + aUids.Reset(); + TInt count = iInterestedAPIs->Array().Count(); + for(TInt i=0; (iArray()[i]; + ASSERT_DEBUG(details); + if(details->IsBulk()) + { + err = aUids.Append(details->Uid()); + } + } + + return err; + } + +TInt CRemConSession::SupportedOperations(TUid aInterfaceUid, RArray& 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; ixArray()[ix]; + ASSERT_DEBUG(details); + if(details->Uid() == aUid) + { + return details; + } + } + return NULL; + } + +