--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/remotecontrol/remotecontrolfw/client/intermediate/src/interfaceselector.cpp Wed Oct 13 16:20:29 2010 +0300
@@ -0,0 +1,1057 @@
+// Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include <remconinterfaceselector.h>
+#include <remcon/remconinterfacebase.h>
+#include <remconerrorobserver.h>
+#include <remcon/remconinterfacefeatures.h>
+#include <remcon/remconifdetails.h>
+#include <s32mem.h>
+#include "bulkreceiver.h"
+#include "receiver.h"
+#include "remconclient.h"
+#include "remconbulkclient.h"
+#include "utils.h"
+
+
+const TInt KMaxSharedThreadHeapSize = 0x0400;
+
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCON_IF_SEL);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("ifsel");
+#endif
+
+#define RCIS_VERBOSE_PANIC(code) \
+ { \
+ LOG1(_L("Panicking with RemConIfSel / %d"), code); \
+ User::Panic(KRemConIfSelPanicCat, code); \
+ }
+
+#define RCIS_VERBOSE_ASSERT(cond, code) \
+ { \
+ if ( !(cond) ) \
+ { \
+ RCIS_VERBOSE_PANIC(code); \
+ } \
+ }
+
+void CloseDeleteAndNull(TAny* aPtr)
+ {
+ RRemCon** sessionPtrPtr = static_cast<RRemCon**>(aPtr);
+ RRemCon* session = *sessionPtrPtr;
+ session->Close();
+ delete session;
+ *sessionPtrPtr = NULL;
+ }
+
+void CleanupCloseDeleteAndNullPushL(RRemCon** aSession)
+ {
+ TCleanupItem item(CloseDeleteAndNull, aSession);
+ CleanupStack::PushL(item);
+ }
+
+EXPORT_C CRemConInterfaceSelector* CRemConInterfaceSelector::NewL()
+ {
+ CONNECT_LOGGER
+ LOG_STATIC_FUNC
+
+ CRemConInterfaceSelector* ifSel = new(ELeave) CRemConInterfaceSelector;
+ CleanupStack::PushL(ifSel);
+ ifSel->ConstructL();
+ CleanupStack::Pop(ifSel);
+ return ifSel;
+ }
+
+void CRemConInterfaceSelector::ConstructL()
+ {
+ iSharedThreadHeap = UserHeap::ChunkHeap(NULL, 0, KMaxSharedThreadHeapSize);
+ if(!iSharedThreadHeap)
+ {
+ LEAVEL(KErrNoMemory);
+ }
+ iBulkCleanupCall = new(ELeave) RSpecificThreadCallBack;
+ TCallBack bulkCleanupCb(StaticBulkCleanup, this);
+ LEAVEIFERRORL(iBulkCleanupCall->Create(bulkCleanupCb, CActive::EPriorityStandard));
+
+ // allocate in the shared objects heap.
+ RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
+ CleanupSwitchHeapPushL(*currentHeap);
+ {
+ iInterfaces = CRemConInterfaceDetailsArray::NewL();
+ }
+ CleanupStack::PopAndDestroy(currentHeap);
+
+ RNestableLock* lock = new (ELeave) RNestableLock;
+ CleanupStack::PushL(lock);
+ LEAVEIFERRORL(lock->CreateLocal());
+ CleanupStack::Pop(lock);
+ iLock = lock;
+ }
+
+CRemConInterfaceSelector::CRemConInterfaceSelector()
+ {
+ LOG_FUNC
+ iTargetReceiver = NULL;
+ }
+
+EXPORT_C CRemConInterfaceSelector::~CRemConInterfaceSelector()
+ {
+ LOG_FUNC
+
+ // The easy one... (i.e. non-bulk interfaces)
+ for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
+ {
+ CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
+ ASSERT_DEBUG(details);
+ if(!details->IsBulk())
+ {
+ CRemConInterfaceBase* interface = details->Interface();
+ details->Interface() = NULL;
+ delete interface;
+ }
+ }
+
+ // The tricky one...
+ // we have to use the thread specific cleanup because they have to
+ // cancel some objects...
+ TInt err = iBulkCleanupCall->CallBack();
+ if(err == KErrDied)
+ {
+ // If the other thread is dead then we cannot cleanly cleanup
+ // but if the heap is shared then we should be ok.
+ if(iBulkHeap == &User::Heap())
+ {
+ BulkCleanup();
+ }
+ }
+
+ // Finally tidy-up shared thread objects.
+ RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
+ {
+ delete iInterfaces;
+ }
+ User::SwitchHeap(currentHeap);
+
+
+ delete iTargetReceiver;
+ delete iControllerReceiver;
+ // delete iBulkReceiver; // This is done in the bulk thread cleanup.
+
+ if(iControllerSession)
+ {
+ iControllerSession->Close();
+ delete iControllerSession;
+ }
+
+ if(iTargetSession)
+ {
+ iTargetSession->Close();
+ delete iTargetSession;
+ }
+
+ // iBulkSession.Close(); // This is done in the bulk thread cleanup.
+
+ iBulkCleanupCall->Close();
+ delete iBulkCleanupCall;
+
+ iSharedThreadHeap->Close();
+
+ iBulkThread.Close();
+
+ iLock->Wait();
+ iLock->Close();
+ delete iLock;
+
+ CLOSE_LOGGER
+ }
+
+TInt CRemConInterfaceSelector::StaticBulkCleanup(TAny* aSelf)
+ {
+ LOG_STATIC_FUNC
+ reinterpret_cast<CRemConInterfaceSelector*>(aSelf)->BulkCleanup();
+ return KErrNone;
+ }
+
+void CRemConInterfaceSelector::BulkCleanup()
+ {
+ LOG_FUNC
+ CBulkReceiver* recv = iBulkReceiver;
+ iBulkReceiver = NULL;
+ delete recv;
+ if(RThread().Id() == iBulkThread.Id() && iBulkSession)
+ {
+ iBulkSession->Close();
+ delete iBulkSession;
+ iBulkSession = NULL;
+ }
+ for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
+ {
+ CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
+ ASSERT_DEBUG(details);
+ if(details->IsBulk())
+ {
+ CRemConInterfaceBase* interface = details->Interface();
+ details->Interface() = NULL;
+ delete interface;
+ }
+ }
+ }
+
+void CRemConInterfaceSelector::EstablishBulkThreadBindingL()
+ {
+ LOG_FUNC
+ if(iBulkHeap)
+ {
+ // Already bound
+ RCIS_VERBOSE_ASSERT(RThread().Id() == iBulkThread.Id(), ERemConIfSelMultipleBulkInterfaceThreads);
+ }
+ else
+ {
+ // Create Binding.
+ LEAVEIFERRORL(iBulkThread.Duplicate(RThread()));
+ CleanupClosePushL(iBulkThread);
+ LEAVEIFERRORL(iBulkCleanupCall->Start());
+ iBulkReceiver = CBulkReceiver::NewL(*this);
+ iBulkHeap = &User::Heap();
+ CleanupStack::Pop(&iBulkThread);
+ }
+
+ }
+
+void CRemConInterfaceSelector::RegisterInterfaceCommonL(CRemConInterfaceBase& aInterface, const TDesC8& aFeatures)
+ {
+ LOG_FUNC
+
+ const TBool bulkIf = aInterface.Bulk();
+ if(bulkIf)
+ {
+ EstablishBulkThreadBindingL();
+ }
+
+ // Check an instance of the same interface (same interface UID and type)
+ // has not already been added.
+ const TUint count = iInterfaces->Array().Count();
+ for(TUint ii=0; ii<count; ++ii)
+ {
+ CRemConInterfaceBase* const iface = iInterfaces->Array()[ii]->Interface();
+ RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
+ RCIS_VERBOSE_ASSERT( (iface->InterfaceUid() != aInterface.InterfaceUid()) || (iface->Type() != aInterface.Type()),
+ ERemConIfSelInterfaceOfThatTypeAlreadyRegistered);
+ }
+
+ // Registration of interfaces should occur before we try to use any of
+ // them.
+ RCIS_VERBOSE_ASSERT(!TargetOpened() && !ControllerOpened(), ERemConIfSelTardyInterfaceRegistration);
+
+ iLock->Wait(); // critical session
+ RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
+ CleanupSwitchHeapPushL(*currentHeap);
+ {
+ CRemConInterfaceDetails* details = CRemConInterfaceDetails::NewLC(aInterface.InterfaceUid(), aInterface.Type(), bulkIf, &aInterface, aFeatures);
+ iInterfaces->AppendL(details);
+ CleanupStack::Pop(details);
+ }
+ CleanupStack::PopAndDestroy(currentHeap);
+ iLock->Signal(); // end of critical session
+
+ // The interface has been appended OK, so adjust iMaxDataLength.
+ const TUint interfaceMaxLength = aInterface.MaxLength();
+ if(!bulkIf && interfaceMaxLength > iControlMaxDataLength)
+ {
+ iControlMaxDataLength = interfaceMaxLength;
+ }
+ else if(bulkIf && interfaceMaxLength > iBulkMaxDataLength)
+ {
+ iBulkMaxDataLength = interfaceMaxLength;
+ }
+ }
+
+EXPORT_C void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface)
+ {
+ LOG_FUNC
+
+ RegisterInterfaceCommonL(aInterface, KNullDesC8);
+ }
+
+void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface, RRemConInterfaceFeatures& aRemConInterfaceFeatures)
+ {
+ LOG_FUNC
+
+ RegisterInterfaceCommonL(aInterface, aRemConInterfaceFeatures.SupportedOperations());
+ }
+
+EXPORT_C void CRemConInterfaceSelector::RegisterErrorObserver(MRemConErrorObserver* aObserver)
+ {
+ LOG_FUNC
+ LOG1(_L("\taObserver = 0x%08x"), aObserver);
+
+ iErrorObserver = aObserver;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::OpenControllerL()
+ {
+ LOG_FUNC
+
+ // An attempt to open a controller session when one is already open
+ // is an exceptional condition.
+ if (ControllerOpened())
+ {
+ LEAVEL(KErrInUse);
+ }
+
+ // NB We don't enforce that there are some interfaces registered here
+ // because the client might be connecting just to watch connection
+ // statuses.
+
+ iControllerSession = new(ELeave)RRemConController();
+ LEAVEIFERRORL(iControllerSession->Connect());
+ CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iControllerSession));
+
+ RegisterInterestedApisL(ERemConClientTypeController);
+
+ // Now there's a session to receive on, start the receiver.
+ RCIS_VERBOSE_ASSERT(!iControllerReceiver, ERemConIfSelInternalError);
+ iControllerReceiver = CReceiver::NewL(*iControllerSession, *this, iControlMaxDataLength, ERemConClientTypeController);
+ CleanupStack::Pop(&iControllerSession);
+ }
+
+void CRemConInterfaceSelector::RegisterInterestedApisL(TRemConClientType aType)
+ {
+ LOG_FUNC
+
+ TBool target = CRemConInterfaceBase::Target(aType);
+
+ // First get the size of the data we are going to pass to the server.
+ RCountSizeWriteStream counter;
+ iInterfaces->ExternalizeL(counter, aType);
+ TInt size = counter.Size();
+ counter.Close();
+
+ // Create a suitable size buffer.
+ RBuf8 ipcBuf;
+ ipcBuf.CreateL(size);
+ ipcBuf.CleanupClosePushL();
+
+ // Encode the interface details into the buffer.
+ RDesWriteStream ipcStream(ipcBuf);
+ iInterfaces->ExternalizeL(ipcStream, aType);
+ ipcStream.CommitL();
+ ipcStream.Close();
+
+ // Inform the correct session about the interfaces
+ if(!target)
+ {
+ LEAVEIFERRORL(iControllerSession->RegisterInterestedAPIs(ipcBuf));
+ }
+ else
+ {
+ LEAVEIFERRORL(iTargetSession->RegisterInterestedAPIs(ipcBuf));
+ }
+
+ CleanupStack::PopAndDestroy(&ipcBuf);
+ }
+
+void CRemConInterfaceSelector::OpenTargetCommonL()
+ {
+ LOG_FUNC
+
+ // NB We don't enforce that there are some interfaces registered here
+ // because the client might be connecting just to watch connection
+ // statuses.
+ CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iTargetSession));
+
+ RegisterInterestedApisL(ERemConClientTypeTarget);
+
+ // Now we are finished with the features, so we can release some memory.
+ RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
+ {
+ for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
+ {
+ CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
+ ASSERT_DEBUG(details);
+ details->DeleteFeatures();
+ }
+ }
+ User::SwitchHeap(currentHeap);
+
+ // Now there's a session to receive on, start the receiver.
+ RCIS_VERBOSE_ASSERT(!iTargetReceiver, ERemConIfSelInternalError);
+ iTargetReceiver = CReceiver::NewL(*iTargetSession, *this, iControlMaxDataLength, ERemConClientTypeTarget);
+ CleanupDeleteAndNullPushL(iTargetReceiver);
+
+ if(iBulkReceiver)
+ {
+ // We delegate the call to the thread the receiver is running
+ // in - waiting until it has completed (with success or error).
+ iBulkReceiver->WaitUntilConnectedL();
+ }
+
+ CleanupStack::Pop(2, &iTargetSession); // iTargetReceiver, iTargetSession
+ }
+
+EXPORT_C void CRemConInterfaceSelector::OpenTargetL()
+ {
+ LOG_FUNC
+
+ // An attempt to open a target session when one is already open
+ // is an exceptional condition.
+ if (TargetOpened())
+ {
+ LEAVEL(KErrInUse);
+ }
+
+ iTargetSession = new(ELeave)RRemConTarget();
+ TInt err = iTargetSession->Connect();
+ if(err == KErrNone)
+ {
+ OpenTargetCommonL();
+ }
+ else
+ {
+ delete iTargetSession;
+ iTargetSession = NULL;
+ LEAVEL(err);
+ }
+ }
+
+/**
+This should be run from the thread in which the bulk interfaces are to run.
+*/
+void CRemConInterfaceSelector::BulkSessionConnectL()
+ {
+ LOG_FUNC
+
+ RRemConBulk* bulkSession = new(ELeave)RRemConBulk;
+ CleanupStack::PushL(bulkSession);
+ LEAVEIFERRORL(bulkSession->Connect());
+ CleanupClosePushL(*bulkSession);
+ RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError);
+ iBulkReceiver->InitialiseL(*bulkSession, iBulkMaxDataLength);
+ CleanupStack::Pop(2, bulkSession);
+ iBulkSession = bulkSession;
+ }
+
+/**
+Opens a target session to RemCon.
+
+If any bulk interfaces have been registered on this interface selector the
+the thread in which the first bulk interface was created must be ready to run and
+not blocked waiting for the completion of this function. Failure to do so will lead
+to deadlock.
+
+@param aPlayerType The type of player
+@param aPlayerSubType The sub-type of the player
+@param aPlayerName The name of the player
+@leave KErrInUse If a target session is already open.
+*/
+EXPORT_C void CRemConInterfaceSelector::OpenTargetL(TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aPlayerName)
+ {
+ LOG_FUNC
+
+ // An attempt to open a target session when one is already open
+ // is an exceptional condition.
+ if (TargetOpened())
+ {
+ LEAVEL(KErrInUse);
+ }
+
+ iTargetSession = new(ELeave)RRemConTarget();
+ TInt err = iTargetSession->Connect(aPlayerType,aPlayerSubType,aPlayerName);
+ if(err == KErrNone)
+ {
+ OpenTargetCommonL();
+ }
+ else
+ {
+ delete iTargetSession;
+ iTargetSession = NULL;
+ LEAVEL(err);
+ }
+ }
+
+EXPORT_C TBool CRemConInterfaceSelector::ControllerOpened() const
+ {
+ ASSERT_DEBUG((iControllerSession && iControllerSession->Handle()) || !iControllerSession);
+ return iControllerSession ? ETrue : EFalse;
+ }
+
+EXPORT_C TBool CRemConInterfaceSelector::TargetOpened() const
+ {
+ ASSERT_DEBUG((iTargetSession && iTargetSession->Handle()) || !iTargetSession);
+ return iTargetSession ? ETrue : EFalse;
+ }
+
+TBool CRemConInterfaceSelector::BulkOpened() const
+ {
+ ASSERT_DEBUG((iBulkSession && iBulkSession->Handle()) || !iBulkSession);
+ return iBulkSession ? ETrue : EFalse;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::GoConnectionOrientedL(const TRemConAddress& aConnection)
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ LEAVEIFERRORL(iControllerSession->GoConnectionOriented(aConnection));
+
+ // Store the address. This means that if the server dies we know all
+ // we need to to return the existing sessions to usability without
+ // troubling the app.
+ iAddress = aConnection;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::GoConnectionlessL()
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ LEAVEIFERRORL(iControllerSession->GoConnectionless());
+
+ // Unset any stored address, so we know we are connectionless.
+ iAddress.BearerUid() = KNullUid;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::ConnectBearer(TRequestStatus& aStat)
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ iControllerSession->ConnectBearer(aStat);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::ConnectBearerCancel()
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ //Ignore Return code because
+ // a) It'll mostly be other than KErrNone because the server has terminated, in which
+ // case the original async request will have completed with the error anyway!
+ // b) It's meaningless to the client whatever the return code is.
+ (void)iControllerSession->ConnectBearerCancel();
+
+ return KErrNone;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::DisconnectBearer(TRequestStatus& aStat)
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ iControllerSession->DisconnectBearer(aStat);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::DisconnectBearerCancel()
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+
+ //See CRemConInterfaceSelector::ConnectBearerCancel() for comment
+ (void)iControllerSession->DisconnectBearerCancel();
+
+ return KErrNone;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TUint& aNumRemotes,
+ TRemConMessageType aMsgType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aMsgType, ERemConMessageDefault, aData);
+ }
+
+EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TUint& aNumRemotes,
+ TRemConMessageType aMsgType,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ switch ( aMsgType )
+ {
+ case ERemConCommand:
+ case ERemConNotifyCommand:
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+ iControllerSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData);
+ break;
+
+ case ERemConResponse:
+ RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
+ iTargetSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData);
+ break;
+
+ default:
+ RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
+ break;
+ }
+ }
+
+/**
+Sends a notify command to the remote device.
+
+@see CRemConInterfaceSelector::Send()
+*/
+EXPORT_C void CRemConInterfaceSelector::SendNotify(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageType aMsgType,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+ if (aMsgType == ERemConNotifyCommand)
+ {
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+ iControllerSession->SendNotify(aStatus, aInterfaceUid, aOperationId, aSubType, aData);
+ }
+ else
+ {
+ RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
+ }
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable(
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageType aMsgType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ return SendUnreliable(aInterfaceUid, aOperationId, aMsgType, ERemConMessageDefault, aData);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable(
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageType aMsgType,
+ TRemConMessageSubType aSubType,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ TInt ret = KErrNone;
+
+ switch ( aMsgType )
+ {
+ case ERemConCommand:
+ case ERemConNotifyCommand:
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+ ret = iControllerSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData);
+ break;
+
+ case ERemConResponse:
+ RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
+ ret = iTargetSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData);
+ break;
+
+ default:
+ RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
+ break;
+ }
+ return ret;
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::SendCancel(TRemConMessageType aMsgType)
+ {
+ LOG_FUNC
+
+ switch ( aMsgType )
+ {
+ case ERemConCommand:
+ case ERemConNotifyCommand:
+ RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
+ //See CRemConInterfaceSelector::ConnectBearerCancel() for comment
+ (void)iControllerSession->SendCancel();
+ break;
+
+ case ERemConResponse:
+ RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
+ //See CRemConInterfaceSelector::ConnectBearerCancel() for comment
+ (void)iTargetSession->SendCancel();
+ break;
+
+ default:
+ RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
+ break;
+ }
+
+ return KErrNone;
+ }
+
+EXPORT_C void CRemConInterfaceSelector::SendBulk(TRequestStatus& aStatus,
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ // Panic as Target Session, because bulkness is transparent to client
+ RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
+ iBulkSession->Send(aStatus, aInterfaceUid, aOperationId, aData);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::SendBulkUnreliable(
+ TUid aInterfaceUid,
+ TUint aOperationId,
+ const TDesC8& aData)
+ {
+ LOG_FUNC
+
+ // Panic as Target Session, because bulkness is transparent to client
+ RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
+ return iBulkSession->SendUnreliable(aInterfaceUid, aOperationId, aData);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::SendBulkCancel()
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
+ //See CRemConInterfaceSelector::ConnectBearerCancel() for comment
+ (void)iBulkSession->SendCancel();
+
+ return KErrNone;
+ }
+
+void CRemConInterfaceSelector::ReceiveComplete(TUid aInterfaceUid,
+ TUint aOperationId,
+ TRemConMessageSubType aMsgSubType,
+ const TRemConAddress& aRemoteAddress,
+ const TDesC8& aData,
+ TRemConClientType aType)
+ {
+ LOG_FUNC
+ LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid);
+ LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
+ LOG1(_L("\taRemoteAddress.BearerUid = 0x%08x"), aRemoteAddress.BearerUid());
+
+ const TUint count = iInterfaces->Array().Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConInterfaceDetails* const details = iInterfaces->Array()[ii];
+ ASSERT_DEBUG(details);
+ CRemConInterfaceBase* const iface = details->Interface();
+ RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
+
+ if ( iface->InterfaceUid() == aInterfaceUid
+ && iface->Type() == aType )
+ {
+ ASSERT_DEBUG(!details->IsBulk());
+ MRemConInterfaceIf3* interfaceIf3 = reinterpret_cast<MRemConInterfaceIf3*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf3)));
+ if (interfaceIf3)
+ {
+ interfaceIf3->MrcibNewMessage(aOperationId, aData, aMsgSubType, aRemoteAddress);
+ break;
+ }
+ MRemConInterfaceIf2* interfaceIf2 = reinterpret_cast<MRemConInterfaceIf2*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf2)));
+ if (interfaceIf2)
+ {
+ interfaceIf2->MrcibNewMessage(aOperationId, aData, aMsgSubType);
+ break;
+ }
+ MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1)));
+ RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation);
+ interfaceIf->MrcibNewMessage(aOperationId, aData);
+ break;
+ }
+ }
+ }
+
+void CRemConInterfaceSelector::BulkReceiveComplete(TUid aInterfaceUid, TUint aOperationId, const TDesC8& aData)
+ {
+ LOG_FUNC
+ LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid);
+ LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
+
+ const TUint count = iInterfaces->Array().Count();
+ for ( TUint ii = 0 ; ii < count ; ++ii )
+ {
+ CRemConInterfaceDetails* const details = iInterfaces->Array()[ii];
+ ASSERT_DEBUG(details);
+ CRemConInterfaceBase* const iface = details->Interface();
+ RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
+
+ if(details->IsBulk() && iface->InterfaceUid() == aInterfaceUid)
+ {
+ MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1)));
+ RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation);
+ interfaceIf->MrcibNewMessage(aOperationId, aData);
+ }
+ }
+ }
+
+void CRemConInterfaceSelector::Error(TInt aError)
+ {
+ LOG_FUNC
+ LOG1(_L("\taError = %d"), aError);
+ LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver);
+
+ if(aError == KErrServerTerminated)
+ {
+ // Initially try and deal with server death in a way that is
+ // transparent to the app.
+ TInt err = TryToReconnect();
+ LOG1(_L("\tTryToReconnect error = %d"), err);
+
+ // If we fail inform any registered app. Unregistered apps
+ // just take the risk that they may not realise the server has
+ // died if it errors on a receive.
+ if(err && iErrorObserver)
+ {
+ iErrorObserver->MrceoError(KErrServerTerminated);
+ }
+ }
+ }
+
+void CRemConInterfaceSelector::BulkError(TInt aError)
+ {
+ LOG_FUNC
+ LOG1(_L("\taError = %d"), aError);
+ LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver);
+
+ if(aError == KErrServerTerminated)
+ {
+ // Initially try and deal with server death in a way that is
+ // transparent to the app.
+ TInt err = TryToReconnectBulk();
+ LOG1(_L("\tTryToReconnectBulk error = %d"), err);
+
+ // If we fail inform any registered app. Unregistered apps
+ // just take the risk that they may not realise the server has
+ // died if it errors on a receive.
+ if(err && iErrorObserver)
+ {
+ iErrorObserver->MrceoError(KErrServerTerminated);
+ }
+ }
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::GetConnections(TSglQue<TRemConAddress>& aConnections)
+ {
+ LOG_FUNC
+
+ // It doesn't matter which session we use for this.
+ RRemCon* sess = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession);
+ AssertSession(sess, ERemConIfSelNoSession);
+
+ return sess->GetConnections(aConnections);
+ }
+
+EXPORT_C void CRemConInterfaceSelector::NotifyConnectionsChange(TRequestStatus& aStatus)
+ {
+ LOG_FUNC
+
+ // It doesn't matter which session we use for this.
+ iNotificationSession = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession);
+ AssertSession(iNotificationSession, ERemConIfSelNoSession);
+
+ iNotificationSession->NotifyConnectionsChange(aStatus);
+ }
+
+EXPORT_C TInt CRemConInterfaceSelector::NotifyConnectionsChangeCancel()
+ {
+ LOG_FUNC
+
+ // Get the session we used for posting the original notification. It won't
+ // have gone away in the meantime as that only happens when 'this' is
+ // destroyed, but the client may call this without ever having called the
+ // original notification.
+ AssertSession(iNotificationSession, ERemConIfSelNoSession);
+
+ //See CRemConInterfaceSelector::ConnectBearerCancel() for comment
+ (void)iNotificationSession->NotifyConnectionsChangeCancel();
+
+ return KErrNone;
+ }
+
+void CRemConInterfaceSelector::AssertSession(RRemCon* aSess, TInt aPanicCode) const
+ {
+ LOG_FUNC
+
+ RCIS_VERBOSE_ASSERT(aSess && aSess->Handle(), aPanicCode);
+ }
+
+/**
+Resurrects sessions in case of server death.
+
+For the target and controller session we try to open a new
+session. If this succeeds we can then set the old session
+to point to the new one after closing our old defunct
+session.
+
+On success we are left with happy functioning handles.
+On failure we are left with defunct handles, which are still
+valid but will complete all requests with KErrServerTerminated.
+
+This means that we won't cause an application to get a bad handle
+panic if it hasn't done anything wrong.
+*/
+TInt CRemConInterfaceSelector::TryToReconnect()
+ {
+ LOG_FUNC
+
+ // Always want to stop receiving. The receiver itself should stop issuing
+ // further receives on completion, but we only want to have the error function
+ // called once, so Cancel() receivers in case we had both.
+ if(TargetOpened())
+ {
+ RCIS_VERBOSE_ASSERT(iTargetReceiver, ERemConIfSelInternalError);
+ iTargetReceiver->Cancel();
+ }
+
+ if(ControllerOpened())
+ {
+ RCIS_VERBOSE_ASSERT(iControllerReceiver, ERemConIfSelInternalError);
+ iControllerReceiver->Cancel();
+ }
+
+ // Now try and create new sessions. We do all the failable work first
+ // so we aren't left in a half alive situation.
+ TInt err = KErrNone;
+ RRemConTarget newTarget;
+ RRemConController newController;
+
+ if(TargetOpened())
+ {
+ // See if we can kick RemCon back into life
+ err = newTarget.Connect();
+ }
+
+ if(!err && ControllerOpened())
+ {
+ // See if we can kick RemCon back into life
+ err = newController.Connect();
+
+ if(!err && !iAddress.IsNull())
+ {
+ // If an address is set the session was connection oriented,
+ // resurrect that now.
+ err = newController.GoConnectionOriented(iAddress);
+ }
+ }
+
+ if(!err)
+ {
+ // RemCon lives! Set our sessions to be the nice new ones.
+ if(TargetOpened())
+ {
+ iTargetSession->Close();
+ iTargetSession->SetHandle(newTarget.Handle());
+ iTargetReceiver->Receive();
+ }
+
+ if(ControllerOpened())
+ {
+ iControllerSession->Close();
+ iControllerSession->SetHandle(newController.Handle());
+ iControllerReceiver->Receive();
+ }
+ }
+ else
+ {
+ // We may not have successfully opened these, but it's safe to
+ // close them anyway.
+ newTarget.Close();
+ newController.Close();
+ }
+
+ return err;
+ }
+
+
+
+/**
+Resurrects bulk sessions in case of server death.
+
+For the bulk session we try to open a new
+session. If this succeeds we can then set the old session
+to point to the new one after closing our old defunct
+session.
+
+On success we are left with happy functioning handles.
+On failure we are left with defunct handles, which are still
+valid but will complete all requests with KErrServerTerminated.
+
+This means that we won't cause an application to get a bad handle
+panic if it hasn't done anything wrong.
+*/
+TInt CRemConInterfaceSelector::TryToReconnectBulk()
+ {
+ LOG_FUNC
+
+ // Always want to stop receiving. The receiver itself should stop issuing
+ // further receives on completion, but we only want to have the error function
+ // called once, so Cancel() receivers in case we had both.
+ if(BulkOpened())
+ {
+ RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError);
+ iBulkReceiver->Cancel();
+ }
+
+ // Now try and create new sessions. We do all the failable work first
+ // so we aren't left in a half alive situation.
+ TInt err = KErrNone;
+ RRemConBulk newBulk;
+
+ if(BulkOpened())
+ {
+ // See if we can kick RemCon back into life
+ err = newBulk.Connect();
+ }
+
+ if(err == KErrNone)
+ {
+ // RemCon lives! Set our session to be the nice new one.
+ if(BulkOpened())
+ {
+ iBulkSession->Close();
+ iBulkSession->SetHandle(newBulk.Handle());
+ iBulkReceiver->Receive();
+ }
+ }
+ else
+ {
+ // We may not have successfully opened this, but it's safe to
+ // close it anyway.
+ newBulk.Close();
+ }
+
+ return err;
+ }
+