remotecontrol/remotecontrolfw/client/intermediate/src/interfaceselector.cpp
changeset 51 20ac952a623c
equal deleted inserted replaced
48:22de2e391156 51:20ac952a623c
       
     1 // Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <bluetooth/logger.h>
       
    22 #include <remconinterfaceselector.h>
       
    23 #include <remcon/remconinterfacebase.h>
       
    24 #include <remconerrorobserver.h>
       
    25 #include <remcon/remconinterfacefeatures.h>
       
    26 #include <remcon/remconifdetails.h>
       
    27 #include <s32mem.h>
       
    28 #include "bulkreceiver.h"
       
    29 #include "receiver.h"
       
    30 #include "remconclient.h"
       
    31 #include "remconbulkclient.h"
       
    32 #include "utils.h"
       
    33 
       
    34 
       
    35 const TInt KMaxSharedThreadHeapSize = 0x0400;
       
    36 
       
    37 
       
    38 #ifdef __FLOG_ACTIVE
       
    39 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_IF_SEL);
       
    40 #endif
       
    41 
       
    42 #ifdef _DEBUG
       
    43 PANICCATEGORY("ifsel");
       
    44 #endif
       
    45 
       
    46 #define RCIS_VERBOSE_PANIC(code) \
       
    47 	{ \
       
    48 	LOG1(_L("Panicking with RemConIfSel / %d"), code); \
       
    49 	User::Panic(KRemConIfSelPanicCat, code); \
       
    50 	}
       
    51 
       
    52 #define RCIS_VERBOSE_ASSERT(cond, code) \
       
    53 	{ \
       
    54 	if ( !(cond) ) \
       
    55 		{ \
       
    56 		RCIS_VERBOSE_PANIC(code); \
       
    57 		} \
       
    58 	}
       
    59 
       
    60 void CloseDeleteAndNull(TAny* aPtr)
       
    61 	{
       
    62 	RRemCon** sessionPtrPtr = static_cast<RRemCon**>(aPtr);
       
    63 	RRemCon* session = *sessionPtrPtr;
       
    64 	session->Close();
       
    65 	delete session;
       
    66 	*sessionPtrPtr = NULL;
       
    67 	}
       
    68 
       
    69 void CleanupCloseDeleteAndNullPushL(RRemCon** aSession)
       
    70 	{
       
    71 	TCleanupItem item(CloseDeleteAndNull, aSession);
       
    72 	CleanupStack::PushL(item);	
       
    73 	}
       
    74 
       
    75 EXPORT_C CRemConInterfaceSelector* CRemConInterfaceSelector::NewL()
       
    76 	{
       
    77 	CONNECT_LOGGER
       
    78 	LOG_STATIC_FUNC
       
    79 
       
    80 	CRemConInterfaceSelector* ifSel = new(ELeave) CRemConInterfaceSelector;
       
    81 	CleanupStack::PushL(ifSel);
       
    82 	ifSel->ConstructL();
       
    83 	CleanupStack::Pop(ifSel);
       
    84 	return ifSel;
       
    85 	}
       
    86 
       
    87 void CRemConInterfaceSelector::ConstructL()
       
    88 	{
       
    89 	iSharedThreadHeap = UserHeap::ChunkHeap(NULL, 0, KMaxSharedThreadHeapSize);
       
    90 	if(!iSharedThreadHeap)
       
    91 		{
       
    92 		LEAVEL(KErrNoMemory);
       
    93 		}
       
    94 	iBulkCleanupCall = new(ELeave) RSpecificThreadCallBack;
       
    95 	TCallBack bulkCleanupCb(StaticBulkCleanup, this);
       
    96 	LEAVEIFERRORL(iBulkCleanupCall->Create(bulkCleanupCb, CActive::EPriorityStandard));
       
    97 	
       
    98 	// allocate in the shared objects heap.
       
    99 	RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
       
   100 	CleanupSwitchHeapPushL(*currentHeap);
       
   101 		{
       
   102 		iInterfaces = CRemConInterfaceDetailsArray::NewL();
       
   103 		}
       
   104 	CleanupStack::PopAndDestroy(currentHeap);
       
   105 	
       
   106 	RNestableLock* lock = new (ELeave) RNestableLock;
       
   107     CleanupStack::PushL(lock);
       
   108 	LEAVEIFERRORL(lock->CreateLocal());
       
   109 	CleanupStack::Pop(lock);
       
   110 	iLock = lock;
       
   111 	}
       
   112 
       
   113 CRemConInterfaceSelector::CRemConInterfaceSelector()
       
   114 	{
       
   115 	LOG_FUNC
       
   116 	iTargetReceiver = NULL;
       
   117 	}
       
   118 
       
   119 EXPORT_C CRemConInterfaceSelector::~CRemConInterfaceSelector()
       
   120 	{
       
   121 	LOG_FUNC
       
   122 	
       
   123 	// The easy one... (i.e. non-bulk interfaces)
       
   124 	for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
       
   125 		{
       
   126 		CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
       
   127 		ASSERT_DEBUG(details);
       
   128 		if(!details->IsBulk())
       
   129 			{
       
   130 			CRemConInterfaceBase* interface = details->Interface();
       
   131 			details->Interface() = NULL;
       
   132 			delete interface;
       
   133 			}
       
   134 		}
       
   135 	
       
   136 	// The tricky one...
       
   137 	// we have to use the thread specific cleanup because they have to 
       
   138 	// cancel some objects...
       
   139 	TInt err = iBulkCleanupCall->CallBack();
       
   140 	if(err == KErrDied)
       
   141 		{
       
   142 		// If the other thread is dead then we cannot cleanly cleanup
       
   143 		// but if the heap is shared then we should be ok.
       
   144 		if(iBulkHeap == &User::Heap())
       
   145 			{
       
   146 			BulkCleanup();
       
   147 			}
       
   148 		}
       
   149 	
       
   150 	// Finally tidy-up shared thread objects.
       
   151 	RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
       
   152 		{
       
   153 		delete iInterfaces;
       
   154 		}
       
   155 	User::SwitchHeap(currentHeap);
       
   156 
       
   157 	
       
   158 	delete iTargetReceiver;
       
   159 	delete iControllerReceiver;
       
   160 	// delete iBulkReceiver; // This is done in the bulk thread cleanup.
       
   161 
       
   162 	if(iControllerSession)
       
   163 		{
       
   164 		iControllerSession->Close();
       
   165 		delete iControllerSession;
       
   166 		}
       
   167 
       
   168 	if(iTargetSession)
       
   169 		{
       
   170 		iTargetSession->Close();
       
   171 		delete iTargetSession;
       
   172 		}
       
   173 
       
   174 	// iBulkSession.Close(); // This is done in the bulk thread cleanup.
       
   175 
       
   176 	iBulkCleanupCall->Close();
       
   177 	delete iBulkCleanupCall;
       
   178 	
       
   179 	iSharedThreadHeap->Close();
       
   180 	
       
   181 	iBulkThread.Close();
       
   182 
       
   183 	iLock->Wait();
       
   184 	iLock->Close();
       
   185 	delete iLock;
       
   186 	
       
   187 	CLOSE_LOGGER
       
   188 	}
       
   189 
       
   190 TInt CRemConInterfaceSelector::StaticBulkCleanup(TAny* aSelf)
       
   191 	{
       
   192 	LOG_STATIC_FUNC
       
   193 	reinterpret_cast<CRemConInterfaceSelector*>(aSelf)->BulkCleanup();
       
   194 	return KErrNone;
       
   195 	}
       
   196 
       
   197 void CRemConInterfaceSelector::BulkCleanup()
       
   198 	{
       
   199 	LOG_FUNC
       
   200 	CBulkReceiver* recv = iBulkReceiver;
       
   201 	iBulkReceiver = NULL;
       
   202 	delete recv;
       
   203 	if(RThread().Id() == iBulkThread.Id() && iBulkSession)
       
   204 		{
       
   205 		iBulkSession->Close();
       
   206 		delete iBulkSession;
       
   207 		iBulkSession = NULL;
       
   208 		}
       
   209 	for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
       
   210 		{
       
   211 		CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
       
   212 		ASSERT_DEBUG(details);
       
   213 		if(details->IsBulk())
       
   214 			{
       
   215 			CRemConInterfaceBase* interface = details->Interface();
       
   216 			details->Interface() = NULL;
       
   217 			delete interface;
       
   218 			}
       
   219 		}
       
   220 	}
       
   221 
       
   222 void CRemConInterfaceSelector::EstablishBulkThreadBindingL()
       
   223 	{
       
   224 	LOG_FUNC
       
   225 	if(iBulkHeap)
       
   226 		{
       
   227 		// Already bound
       
   228 		RCIS_VERBOSE_ASSERT(RThread().Id() == iBulkThread.Id(), ERemConIfSelMultipleBulkInterfaceThreads);
       
   229 		}
       
   230 	else
       
   231 		{
       
   232 		// Create Binding.
       
   233 		LEAVEIFERRORL(iBulkThread.Duplicate(RThread()));
       
   234 		CleanupClosePushL(iBulkThread);
       
   235 		LEAVEIFERRORL(iBulkCleanupCall->Start());
       
   236 		iBulkReceiver = CBulkReceiver::NewL(*this);	
       
   237 		iBulkHeap = &User::Heap();
       
   238 		CleanupStack::Pop(&iBulkThread);
       
   239 		}
       
   240 	
       
   241 	}
       
   242 
       
   243 void CRemConInterfaceSelector::RegisterInterfaceCommonL(CRemConInterfaceBase& aInterface, const TDesC8& aFeatures)
       
   244 	{
       
   245 	LOG_FUNC
       
   246 	
       
   247 	const TBool bulkIf = aInterface.Bulk();
       
   248 	if(bulkIf)
       
   249 		{
       
   250 		EstablishBulkThreadBindingL();
       
   251 		}
       
   252 
       
   253 	// Check an instance of the same interface (same interface UID and type) 
       
   254 	// has not already been added.
       
   255 	const TUint count = iInterfaces->Array().Count();
       
   256 	for(TUint ii=0; ii<count; ++ii)
       
   257 		{
       
   258 		CRemConInterfaceBase* const iface = iInterfaces->Array()[ii]->Interface();
       
   259 		RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
       
   260 		RCIS_VERBOSE_ASSERT( (iface->InterfaceUid() != aInterface.InterfaceUid()) || (iface->Type() != aInterface.Type()), 
       
   261 			ERemConIfSelInterfaceOfThatTypeAlreadyRegistered);
       
   262 		}
       
   263 
       
   264 	// Registration of interfaces should occur before we try to use any of 
       
   265 	// them.
       
   266 	RCIS_VERBOSE_ASSERT(!TargetOpened() && !ControllerOpened(), ERemConIfSelTardyInterfaceRegistration);
       
   267 	
       
   268 	iLock->Wait();	// critical session
       
   269 	RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
       
   270 	CleanupSwitchHeapPushL(*currentHeap);
       
   271 		{
       
   272 		CRemConInterfaceDetails* details = CRemConInterfaceDetails::NewLC(aInterface.InterfaceUid(), aInterface.Type(), bulkIf, &aInterface, aFeatures);
       
   273 		iInterfaces->AppendL(details);
       
   274 		CleanupStack::Pop(details);
       
   275 		}
       
   276 	CleanupStack::PopAndDestroy(currentHeap);
       
   277 	iLock->Signal(); // end of critical session
       
   278 	
       
   279 	// The interface has been appended OK, so adjust iMaxDataLength.
       
   280 	const TUint interfaceMaxLength = aInterface.MaxLength();
       
   281 	if(!bulkIf && interfaceMaxLength > iControlMaxDataLength)
       
   282 		{
       
   283 		iControlMaxDataLength = interfaceMaxLength;
       
   284 		}
       
   285 	else if(bulkIf && interfaceMaxLength > iBulkMaxDataLength)
       
   286 		{
       
   287 		iBulkMaxDataLength = interfaceMaxLength;
       
   288 		}
       
   289 	}
       
   290 
       
   291 EXPORT_C void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface)
       
   292 	{
       
   293 	LOG_FUNC
       
   294 	
       
   295 	RegisterInterfaceCommonL(aInterface, KNullDesC8);
       
   296 	}
       
   297 
       
   298 void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface, RRemConInterfaceFeatures& aRemConInterfaceFeatures)
       
   299 	{
       
   300 	LOG_FUNC
       
   301 
       
   302 	RegisterInterfaceCommonL(aInterface, aRemConInterfaceFeatures.SupportedOperations());
       
   303 	}
       
   304 
       
   305 EXPORT_C void CRemConInterfaceSelector::RegisterErrorObserver(MRemConErrorObserver* aObserver)
       
   306 	{
       
   307 	LOG_FUNC
       
   308 	LOG1(_L("\taObserver = 0x%08x"), aObserver);
       
   309 	
       
   310 	iErrorObserver = aObserver;
       
   311 	}
       
   312 
       
   313 EXPORT_C void CRemConInterfaceSelector::OpenControllerL()
       
   314 	{
       
   315 	LOG_FUNC
       
   316 
       
   317 	// An attempt to open a controller session when one is already open 
       
   318 	// is an exceptional condition.
       
   319 	if (ControllerOpened())
       
   320 		{
       
   321 		LEAVEL(KErrInUse);
       
   322 		}
       
   323 
       
   324 	// NB We don't enforce that there are some interfaces registered here 
       
   325 	// because the client might be connecting just to watch connection 
       
   326 	// statuses.
       
   327 
       
   328 	iControllerSession = new(ELeave)RRemConController();
       
   329 	LEAVEIFERRORL(iControllerSession->Connect());
       
   330 	CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iControllerSession));
       
   331 	
       
   332 	RegisterInterestedApisL(ERemConClientTypeController);
       
   333 
       
   334 	// Now there's a session to receive on, start the receiver.
       
   335 	RCIS_VERBOSE_ASSERT(!iControllerReceiver, ERemConIfSelInternalError);
       
   336 	iControllerReceiver = CReceiver::NewL(*iControllerSession, *this, iControlMaxDataLength, ERemConClientTypeController);
       
   337 	CleanupStack::Pop(&iControllerSession);
       
   338 	}
       
   339 
       
   340 void CRemConInterfaceSelector::RegisterInterestedApisL(TRemConClientType aType)
       
   341 	{
       
   342 	LOG_FUNC
       
   343 
       
   344 	TBool target = CRemConInterfaceBase::Target(aType);
       
   345 	
       
   346 	// First get the size of the data we are going to pass to the server.
       
   347 	RCountSizeWriteStream counter;
       
   348 	iInterfaces->ExternalizeL(counter, aType);
       
   349 	TInt size = counter.Size();
       
   350 	counter.Close();
       
   351 	
       
   352 	// Create a suitable size buffer.
       
   353 	RBuf8 ipcBuf;
       
   354 	ipcBuf.CreateL(size);
       
   355 	ipcBuf.CleanupClosePushL();
       
   356 	
       
   357 	// Encode the interface details into the buffer.
       
   358 	RDesWriteStream ipcStream(ipcBuf);
       
   359 	iInterfaces->ExternalizeL(ipcStream, aType);
       
   360 	ipcStream.CommitL();
       
   361 	ipcStream.Close();
       
   362 	
       
   363 	// Inform the correct session about the interfaces
       
   364 	if(!target)
       
   365 		{
       
   366 		LEAVEIFERRORL(iControllerSession->RegisterInterestedAPIs(ipcBuf));
       
   367 		}
       
   368 	else
       
   369 		{	
       
   370 		LEAVEIFERRORL(iTargetSession->RegisterInterestedAPIs(ipcBuf));
       
   371 		}
       
   372 	
       
   373 	CleanupStack::PopAndDestroy(&ipcBuf);
       
   374 	}
       
   375 
       
   376 void CRemConInterfaceSelector::OpenTargetCommonL()
       
   377 	{
       
   378 	LOG_FUNC
       
   379 
       
   380 	// NB We don't enforce that there are some interfaces registered here 
       
   381 	// because the client might be connecting just to watch connection 
       
   382 	// statuses.
       
   383 	CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iTargetSession));
       
   384 
       
   385 	RegisterInterestedApisL(ERemConClientTypeTarget);
       
   386 	
       
   387 	// Now we are finished with the features, so we can release some memory.
       
   388 	RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap);
       
   389 		{
       
   390 		for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix)
       
   391 			{
       
   392 			CRemConInterfaceDetails* const details = iInterfaces->Array()[ix];
       
   393 			ASSERT_DEBUG(details);
       
   394 			details->DeleteFeatures();
       
   395 			}
       
   396 		}
       
   397 	User::SwitchHeap(currentHeap);
       
   398 	
       
   399 	// Now there's a session to receive on, start the receiver.
       
   400 	RCIS_VERBOSE_ASSERT(!iTargetReceiver, ERemConIfSelInternalError);
       
   401 	iTargetReceiver = CReceiver::NewL(*iTargetSession, *this, iControlMaxDataLength, ERemConClientTypeTarget);
       
   402 	CleanupDeleteAndNullPushL(iTargetReceiver);
       
   403 
       
   404 	if(iBulkReceiver)
       
   405 		{
       
   406 		// We delegate the call to the thread the receiver is running
       
   407 		// in - waiting until it has completed (with success or error).
       
   408 		iBulkReceiver->WaitUntilConnectedL();
       
   409 		}
       
   410 
       
   411 	CleanupStack::Pop(2, &iTargetSession); // iTargetReceiver, iTargetSession
       
   412 	}
       
   413 
       
   414 EXPORT_C void CRemConInterfaceSelector::OpenTargetL()
       
   415 	{
       
   416 	LOG_FUNC
       
   417 
       
   418 	// An attempt to open a target session when one is already open 
       
   419 	// is an exceptional condition.
       
   420 	if (TargetOpened())
       
   421 		{
       
   422 		LEAVEL(KErrInUse);
       
   423 		}
       
   424 	
       
   425 	iTargetSession = new(ELeave)RRemConTarget();
       
   426 	TInt err = iTargetSession->Connect();
       
   427 	if(err == KErrNone)
       
   428 		{
       
   429 		OpenTargetCommonL();
       
   430 		}
       
   431 	else
       
   432 		{
       
   433 		delete iTargetSession;
       
   434 		iTargetSession = NULL;
       
   435 		LEAVEL(err);
       
   436 		}
       
   437 	}
       
   438 
       
   439 /**
       
   440 This should be run from the thread in which the bulk interfaces are to run.
       
   441 */
       
   442 void CRemConInterfaceSelector::BulkSessionConnectL()
       
   443 	{
       
   444 	LOG_FUNC
       
   445 
       
   446 	RRemConBulk* bulkSession = new(ELeave)RRemConBulk;
       
   447 	CleanupStack::PushL(bulkSession);
       
   448 	LEAVEIFERRORL(bulkSession->Connect());
       
   449 	CleanupClosePushL(*bulkSession);
       
   450 	RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError);
       
   451 	iBulkReceiver->InitialiseL(*bulkSession, iBulkMaxDataLength);
       
   452 	CleanupStack::Pop(2, bulkSession);
       
   453 	iBulkSession = bulkSession;
       
   454 	}
       
   455 
       
   456 /**
       
   457 Opens a target session to RemCon.
       
   458 
       
   459 If any bulk interfaces have been registered on this interface selector the
       
   460 the thread in which the first bulk interface was created must be ready to run and
       
   461 not blocked waiting for the completion of this function.  Failure to do so will lead
       
   462 to deadlock.
       
   463 
       
   464 @param aPlayerType The type of player
       
   465 @param aPlayerSubType The sub-type of the player
       
   466 @param aPlayerName  The name of the player
       
   467 @leave KErrInUse If a target session is already open.
       
   468 */
       
   469 EXPORT_C void CRemConInterfaceSelector::OpenTargetL(TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aPlayerName)
       
   470 	{
       
   471 	LOG_FUNC
       
   472 
       
   473 	// An attempt to open a target session when one is already open 
       
   474 	// is an exceptional condition.
       
   475 	if (TargetOpened())
       
   476 		{
       
   477 		LEAVEL(KErrInUse);
       
   478 		}
       
   479 
       
   480 	iTargetSession = new(ELeave)RRemConTarget();
       
   481 	TInt err = iTargetSession->Connect(aPlayerType,aPlayerSubType,aPlayerName);
       
   482 	if(err == KErrNone)
       
   483 		{
       
   484 		OpenTargetCommonL();
       
   485 		}
       
   486 	else
       
   487 		{
       
   488 		delete iTargetSession;
       
   489 		iTargetSession = NULL;
       
   490 		LEAVEL(err);
       
   491 		}
       
   492 	}
       
   493 
       
   494 EXPORT_C TBool CRemConInterfaceSelector::ControllerOpened() const
       
   495 	{
       
   496 	ASSERT_DEBUG((iControllerSession && iControllerSession->Handle()) || !iControllerSession);
       
   497 	return iControllerSession ? ETrue : EFalse;
       
   498 	}
       
   499 
       
   500 EXPORT_C TBool CRemConInterfaceSelector::TargetOpened() const
       
   501 	{
       
   502 	ASSERT_DEBUG((iTargetSession && iTargetSession->Handle()) || !iTargetSession);
       
   503 	return iTargetSession ? ETrue : EFalse;
       
   504 	}
       
   505 
       
   506 TBool CRemConInterfaceSelector::BulkOpened() const
       
   507 	{
       
   508 	ASSERT_DEBUG((iBulkSession && iBulkSession->Handle()) || !iBulkSession);
       
   509 	return iBulkSession ? ETrue : EFalse;
       
   510 	}
       
   511 
       
   512 EXPORT_C void CRemConInterfaceSelector::GoConnectionOrientedL(const TRemConAddress& aConnection)
       
   513 	{
       
   514 	LOG_FUNC
       
   515 
       
   516 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   517 
       
   518 	LEAVEIFERRORL(iControllerSession->GoConnectionOriented(aConnection));
       
   519 	
       
   520 	// Store the address.  This means that if the server dies we know all
       
   521 	// we need to to return the existing sessions to usability without 
       
   522 	// troubling the app.
       
   523 	iAddress = aConnection;
       
   524 	}
       
   525 
       
   526 EXPORT_C void CRemConInterfaceSelector::GoConnectionlessL()
       
   527 	{
       
   528 	LOG_FUNC
       
   529 
       
   530 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   531 
       
   532 	LEAVEIFERRORL(iControllerSession->GoConnectionless());
       
   533 	
       
   534 	// Unset any stored address, so we know we are connectionless.
       
   535 	iAddress.BearerUid() = KNullUid;
       
   536 	}
       
   537 
       
   538 EXPORT_C void CRemConInterfaceSelector::ConnectBearer(TRequestStatus& aStat)
       
   539 	{
       
   540 	LOG_FUNC
       
   541 
       
   542 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   543 
       
   544 	iControllerSession->ConnectBearer(aStat);
       
   545 	}
       
   546 
       
   547 EXPORT_C TInt CRemConInterfaceSelector::ConnectBearerCancel()
       
   548 	{
       
   549 	LOG_FUNC
       
   550 
       
   551 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   552 
       
   553 	//Ignore Return code because
       
   554 	// a) It'll mostly be other than KErrNone because the server has terminated, in which
       
   555 	//    case the original async request will have completed with the error anyway!
       
   556 	// b) It's meaningless to the client whatever the return code is.
       
   557 	(void)iControllerSession->ConnectBearerCancel();
       
   558 	
       
   559 	return KErrNone;
       
   560 	}
       
   561 
       
   562 EXPORT_C void CRemConInterfaceSelector::DisconnectBearer(TRequestStatus& aStat)
       
   563 	{
       
   564 	LOG_FUNC
       
   565 
       
   566 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   567 
       
   568 	iControllerSession->DisconnectBearer(aStat);
       
   569 	}
       
   570 
       
   571 EXPORT_C TInt CRemConInterfaceSelector::DisconnectBearerCancel()
       
   572 	{
       
   573 	LOG_FUNC
       
   574 
       
   575 	RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   576 
       
   577 	//See CRemConInterfaceSelector::ConnectBearerCancel() for comment
       
   578 	(void)iControllerSession->DisconnectBearerCancel();
       
   579 
       
   580 	return KErrNone;
       
   581 	}
       
   582 
       
   583 EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus, 
       
   584 											 TUid aInterfaceUid, 
       
   585 											 TUint aOperationId, 
       
   586 											 TUint& aNumRemotes,
       
   587 											 TRemConMessageType aMsgType,
       
   588 											 const TDesC8& aData)
       
   589 	{
       
   590 	LOG_FUNC
       
   591 
       
   592 	Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aMsgType, ERemConMessageDefault, aData);
       
   593 	}
       
   594 
       
   595 EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus, 
       
   596 											 TUid aInterfaceUid, 
       
   597 											 TUint aOperationId, 
       
   598 											 TUint& aNumRemotes,
       
   599 											 TRemConMessageType aMsgType,
       
   600 											 TRemConMessageSubType aSubType,
       
   601 											 const TDesC8& aData)
       
   602 	{
       
   603 	LOG_FUNC
       
   604 	
       
   605 	switch ( aMsgType )
       
   606 		{
       
   607 	case ERemConCommand:
       
   608 	case ERemConNotifyCommand:
       
   609 		RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   610 		iControllerSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData);
       
   611 		break;
       
   612 		
       
   613 	case ERemConResponse:
       
   614 		RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
       
   615 		iTargetSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData);
       
   616 		break;
       
   617 		
       
   618 	default:
       
   619 		RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
       
   620 		break;
       
   621 		}
       
   622 	}
       
   623 
       
   624 /**
       
   625 Sends a notify command to the remote device.
       
   626 
       
   627 @see CRemConInterfaceSelector::Send()
       
   628 */
       
   629 EXPORT_C void CRemConInterfaceSelector::SendNotify(TRequestStatus& aStatus, 
       
   630 											 TUid aInterfaceUid, 
       
   631 											 TUint aOperationId, 
       
   632 											 TRemConMessageType aMsgType,
       
   633 											 TRemConMessageSubType aSubType,
       
   634 											 const TDesC8& aData)
       
   635 	{
       
   636 	LOG_FUNC
       
   637 	if (aMsgType == ERemConNotifyCommand)
       
   638 		{
       
   639 		RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   640 		iControllerSession->SendNotify(aStatus, aInterfaceUid, aOperationId, aSubType, aData);
       
   641 		}
       
   642 	else
       
   643 		{
       
   644 		RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
       
   645 		}
       
   646 	}
       
   647 
       
   648 EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable(
       
   649 											 TUid aInterfaceUid, 
       
   650 											 TUint aOperationId, 
       
   651 											 TRemConMessageType aMsgType,
       
   652 											 const TDesC8& aData)
       
   653 	{
       
   654 	LOG_FUNC
       
   655 	
       
   656 	return SendUnreliable(aInterfaceUid, aOperationId, aMsgType, ERemConMessageDefault, aData);
       
   657 	}
       
   658 
       
   659 EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable(
       
   660 											 TUid aInterfaceUid, 
       
   661 											 TUint aOperationId, 
       
   662 											 TRemConMessageType aMsgType,
       
   663 											 TRemConMessageSubType aSubType,
       
   664 											 const TDesC8& aData)
       
   665 	{
       
   666 	LOG_FUNC
       
   667 	
       
   668 	TInt ret = KErrNone;
       
   669 	
       
   670 	switch ( aMsgType )
       
   671 		{
       
   672 		case ERemConCommand:
       
   673 		case ERemConNotifyCommand:
       
   674 		RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   675 		ret = iControllerSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData);
       
   676 		break;
       
   677 		
       
   678 		case ERemConResponse:
       
   679 		RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
       
   680 		ret = iTargetSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData);
       
   681 		break;
       
   682 		
       
   683 		default:
       
   684 		RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
       
   685 		break;
       
   686 		}
       
   687 	return ret;
       
   688 	}
       
   689 
       
   690 EXPORT_C TInt CRemConInterfaceSelector::SendCancel(TRemConMessageType aMsgType)
       
   691 	{
       
   692 	LOG_FUNC
       
   693 
       
   694 	switch ( aMsgType )
       
   695 		{
       
   696 	case ERemConCommand:
       
   697 	case ERemConNotifyCommand:
       
   698 		RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession);
       
   699 		//See CRemConInterfaceSelector::ConnectBearerCancel() for comment
       
   700 		(void)iControllerSession->SendCancel();
       
   701 		break;
       
   702 
       
   703 	case ERemConResponse:
       
   704 		RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession);
       
   705 		//See CRemConInterfaceSelector::ConnectBearerCancel() for comment
       
   706 		(void)iTargetSession->SendCancel();
       
   707 		break;
       
   708 
       
   709 	default:
       
   710 		RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType);
       
   711 		break;
       
   712 		}
       
   713 
       
   714 	return KErrNone;
       
   715 	}
       
   716 
       
   717 EXPORT_C void CRemConInterfaceSelector::SendBulk(TRequestStatus& aStatus, 
       
   718 											 TUid aInterfaceUid, 
       
   719 											 TUint aOperationId, 
       
   720 											 const TDesC8& aData)
       
   721 	{
       
   722 	LOG_FUNC
       
   723 	
       
   724 	// Panic as Target Session, because bulkness is transparent to client
       
   725 	RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
       
   726 	iBulkSession->Send(aStatus, aInterfaceUid, aOperationId, aData);
       
   727 	}
       
   728 
       
   729 EXPORT_C TInt CRemConInterfaceSelector::SendBulkUnreliable(
       
   730 											TUid aInterfaceUid,
       
   731 											TUint aOperationId,
       
   732 											const TDesC8& aData)
       
   733 	{
       
   734 	LOG_FUNC
       
   735 	
       
   736 	// Panic as Target Session, because bulkness is transparent to client
       
   737 	RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
       
   738 	return iBulkSession->SendUnreliable(aInterfaceUid, aOperationId, aData);
       
   739 	}
       
   740 
       
   741 EXPORT_C TInt CRemConInterfaceSelector::SendBulkCancel()
       
   742 	{
       
   743 	LOG_FUNC
       
   744 
       
   745 	RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession);
       
   746 	//See CRemConInterfaceSelector::ConnectBearerCancel() for comment
       
   747 	(void)iBulkSession->SendCancel();
       
   748 
       
   749 	return KErrNone;
       
   750 	}
       
   751 
       
   752 void CRemConInterfaceSelector::ReceiveComplete(TUid aInterfaceUid, 
       
   753 		TUint aOperationId, 
       
   754 		TRemConMessageSubType aMsgSubType, 
       
   755 		const TRemConAddress& aRemoteAddress,
       
   756 		const TDesC8& aData, 
       
   757 		TRemConClientType aType)
       
   758 	{
       
   759 	LOG_FUNC
       
   760 	LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid);
       
   761 	LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
       
   762 	LOG1(_L("\taRemoteAddress.BearerUid = 0x%08x"), aRemoteAddress.BearerUid());
       
   763 	
       
   764 	const TUint count = iInterfaces->Array().Count();
       
   765 	for ( TUint ii = 0 ; ii < count ; ++ii )
       
   766 		{
       
   767 		CRemConInterfaceDetails* const details = iInterfaces->Array()[ii];
       
   768 		ASSERT_DEBUG(details);
       
   769 		CRemConInterfaceBase* const iface = details->Interface();
       
   770 		RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
       
   771 
       
   772 		if (	iface->InterfaceUid() == aInterfaceUid 
       
   773 			&&	iface->Type() == aType )
       
   774 			{
       
   775 			ASSERT_DEBUG(!details->IsBulk());
       
   776 			MRemConInterfaceIf3* interfaceIf3 = reinterpret_cast<MRemConInterfaceIf3*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf3)));
       
   777 			if (interfaceIf3)
       
   778 				{
       
   779 				interfaceIf3->MrcibNewMessage(aOperationId, aData, aMsgSubType, aRemoteAddress);
       
   780 				break;
       
   781 				}
       
   782 			MRemConInterfaceIf2* interfaceIf2 = reinterpret_cast<MRemConInterfaceIf2*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf2)));
       
   783 			if (interfaceIf2)
       
   784 				{
       
   785 				interfaceIf2->MrcibNewMessage(aOperationId, aData, aMsgSubType);
       
   786 				break;
       
   787 				}
       
   788 			MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1)));
       
   789 			RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation);
       
   790 			interfaceIf->MrcibNewMessage(aOperationId, aData);
       
   791 			break;
       
   792 			}
       
   793 		}
       
   794 	}
       
   795 
       
   796 void CRemConInterfaceSelector::BulkReceiveComplete(TUid aInterfaceUid, TUint aOperationId, const TDesC8& aData)
       
   797 	{
       
   798 	LOG_FUNC
       
   799 	LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid);
       
   800 	LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
       
   801 
       
   802 	const TUint count = iInterfaces->Array().Count();
       
   803 	for ( TUint ii = 0 ; ii < count ; ++ii )
       
   804 		{
       
   805 		CRemConInterfaceDetails* const details = iInterfaces->Array()[ii];
       
   806 		ASSERT_DEBUG(details);
       
   807 		CRemConInterfaceBase* const iface = details->Interface();
       
   808 		RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError);
       
   809 
       
   810 		if(details->IsBulk() && iface->InterfaceUid() == aInterfaceUid)
       
   811 			{
       
   812 			MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1)));
       
   813 			RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation);
       
   814 			interfaceIf->MrcibNewMessage(aOperationId, aData);
       
   815 			}
       
   816 		}
       
   817 	}
       
   818 
       
   819 void CRemConInterfaceSelector::Error(TInt aError)
       
   820 	{
       
   821 	LOG_FUNC
       
   822 	LOG1(_L("\taError = %d"), aError);
       
   823 	LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver);
       
   824 	
       
   825 	if(aError == KErrServerTerminated)
       
   826 		{
       
   827 		// Initially try and deal with server death in a way that is
       
   828 		// transparent to the app.
       
   829 		TInt err = TryToReconnect();
       
   830 		LOG1(_L("\tTryToReconnect error = %d"), err);
       
   831 	
       
   832 		// If we fail inform any registered app.  Unregistered apps
       
   833 		// just take the risk that they may not realise the server has
       
   834 		// died if it errors on a receive.
       
   835 		if(err && iErrorObserver)
       
   836 			{
       
   837 			iErrorObserver->MrceoError(KErrServerTerminated);
       
   838 			}
       
   839 		}
       
   840 	}
       
   841 
       
   842 void CRemConInterfaceSelector::BulkError(TInt aError)
       
   843 	{
       
   844 	LOG_FUNC
       
   845 	LOG1(_L("\taError = %d"), aError);
       
   846 	LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver);
       
   847 	
       
   848 	if(aError == KErrServerTerminated)
       
   849 		{
       
   850 		// Initially try and deal with server death in a way that is
       
   851 		// transparent to the app.
       
   852 		TInt err = TryToReconnectBulk();
       
   853 		LOG1(_L("\tTryToReconnectBulk error = %d"), err);
       
   854 	
       
   855 		// If we fail inform any registered app.  Unregistered apps
       
   856 		// just take the risk that they may not realise the server has
       
   857 		// died if it errors on a receive.
       
   858 		if(err && iErrorObserver)
       
   859 			{
       
   860 			iErrorObserver->MrceoError(KErrServerTerminated);
       
   861 			}
       
   862 		}
       
   863 	}
       
   864 
       
   865 EXPORT_C TInt CRemConInterfaceSelector::GetConnections(TSglQue<TRemConAddress>& aConnections)
       
   866 	{
       
   867 	LOG_FUNC
       
   868 
       
   869 	// It doesn't matter which session we use for this.
       
   870 	RRemCon* sess = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession);
       
   871 	AssertSession(sess, ERemConIfSelNoSession);
       
   872 
       
   873 	return sess->GetConnections(aConnections);
       
   874 	}
       
   875 
       
   876 EXPORT_C void CRemConInterfaceSelector::NotifyConnectionsChange(TRequestStatus& aStatus)
       
   877 	{
       
   878 	LOG_FUNC
       
   879 
       
   880 	// It doesn't matter which session we use for this.
       
   881 	iNotificationSession = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession);
       
   882 	AssertSession(iNotificationSession, ERemConIfSelNoSession);
       
   883 
       
   884 	iNotificationSession->NotifyConnectionsChange(aStatus);
       
   885 	}
       
   886 
       
   887 EXPORT_C TInt CRemConInterfaceSelector::NotifyConnectionsChangeCancel()
       
   888 	{
       
   889 	LOG_FUNC
       
   890 
       
   891 	// Get the session we used for posting the original notification. It won't 
       
   892 	// have gone away in the meantime as that only happens when 'this' is 
       
   893 	// destroyed, but the client may call this without ever having called the 
       
   894 	// original notification.
       
   895 	AssertSession(iNotificationSession, ERemConIfSelNoSession);
       
   896 
       
   897 	//See CRemConInterfaceSelector::ConnectBearerCancel() for comment
       
   898 	(void)iNotificationSession->NotifyConnectionsChangeCancel();
       
   899 
       
   900 	return KErrNone;
       
   901 	}
       
   902 
       
   903 void CRemConInterfaceSelector::AssertSession(RRemCon* aSess, TInt aPanicCode) const
       
   904 	{
       
   905 	LOG_FUNC
       
   906 
       
   907 	RCIS_VERBOSE_ASSERT(aSess && aSess->Handle(), aPanicCode);
       
   908 	}
       
   909 
       
   910 /** 
       
   911 Resurrects sessions in case of server death.
       
   912 
       
   913 For the target and controller session we try to open a new
       
   914 session.  If this succeeds we can then set the old session
       
   915 to point to the new one after closing our old defunct 
       
   916 session.
       
   917 
       
   918 On success we are left with happy functioning handles.
       
   919 On failure we are left with defunct handles, which are still 
       
   920 valid but will complete all requests with KErrServerTerminated.
       
   921 
       
   922 This means that we won't cause an application to get a bad handle
       
   923 panic if it hasn't done anything wrong.
       
   924 */
       
   925 TInt CRemConInterfaceSelector::TryToReconnect()
       
   926 	{
       
   927 	LOG_FUNC
       
   928 	
       
   929 	// Always want to stop receiving.  The receiver itself should stop issuing
       
   930 	// further receives on completion, but we only want to have the error function
       
   931 	// called once, so Cancel() receivers in case we had both.
       
   932 	if(TargetOpened())
       
   933 		{
       
   934 		RCIS_VERBOSE_ASSERT(iTargetReceiver, ERemConIfSelInternalError);
       
   935 		iTargetReceiver->Cancel();
       
   936 		}
       
   937 
       
   938 	if(ControllerOpened())
       
   939 		{
       
   940 		RCIS_VERBOSE_ASSERT(iControllerReceiver, ERemConIfSelInternalError);
       
   941 		iControllerReceiver->Cancel();
       
   942 		}
       
   943 		
       
   944 	// Now try and create new sessions.  We do all the failable work first
       
   945 	// so we aren't left in a half alive situation.		
       
   946 	TInt err = KErrNone;
       
   947 	RRemConTarget newTarget;
       
   948 	RRemConController newController;
       
   949 	
       
   950 	if(TargetOpened())
       
   951 		{
       
   952 		// See if we can kick RemCon back into life
       
   953 		err = newTarget.Connect();
       
   954 		}
       
   955 	
       
   956 	if(!err && ControllerOpened())
       
   957 		{		
       
   958 		// See if we can kick RemCon back into life
       
   959 		err = newController.Connect();
       
   960 		
       
   961 		if(!err && !iAddress.IsNull())
       
   962 			{	
       
   963 			// If an address is set the session was connection oriented, 
       
   964 			// resurrect that now.	
       
   965 			err = newController.GoConnectionOriented(iAddress);
       
   966 			}
       
   967 		}
       
   968 	
       
   969 	if(!err)
       
   970 		{
       
   971 		// RemCon lives!  Set our sessions to be the nice new ones.
       
   972 		if(TargetOpened())
       
   973 			{
       
   974 			iTargetSession->Close();
       
   975 			iTargetSession->SetHandle(newTarget.Handle());
       
   976 			iTargetReceiver->Receive();
       
   977 			}
       
   978 
       
   979 		if(ControllerOpened())
       
   980 			{
       
   981 			iControllerSession->Close();
       
   982 			iControllerSession->SetHandle(newController.Handle());
       
   983 			iControllerReceiver->Receive();
       
   984 			}
       
   985 		}
       
   986 	else
       
   987 		{
       
   988 		// We may not have successfully opened these, but it's safe to 
       
   989 		// close them anyway.
       
   990 		newTarget.Close();
       
   991 		newController.Close();
       
   992 		}
       
   993 	
       
   994 	return err;
       
   995 	}
       
   996 
       
   997 
       
   998 
       
   999 /** 
       
  1000 Resurrects bulk sessions in case of server death.
       
  1001 
       
  1002 For the bulk session we try to open a new
       
  1003 session.  If this succeeds we can then set the old session
       
  1004 to point to the new one after closing our old defunct 
       
  1005 session.
       
  1006 
       
  1007 On success we are left with happy functioning handles.
       
  1008 On failure we are left with defunct handles, which are still 
       
  1009 valid but will complete all requests with KErrServerTerminated.
       
  1010 
       
  1011 This means that we won't cause an application to get a bad handle
       
  1012 panic if it hasn't done anything wrong.
       
  1013 */
       
  1014 TInt CRemConInterfaceSelector::TryToReconnectBulk()
       
  1015 	{
       
  1016 	LOG_FUNC
       
  1017 	
       
  1018 	// Always want to stop receiving.  The receiver itself should stop issuing
       
  1019 	// further receives on completion, but we only want to have the error function
       
  1020 	// called once, so Cancel() receivers in case we had both.
       
  1021 	if(BulkOpened())
       
  1022 		{
       
  1023 		RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError);
       
  1024 		iBulkReceiver->Cancel();
       
  1025 		}
       
  1026 		
       
  1027 	// Now try and create new sessions.  We do all the failable work first
       
  1028 	// so we aren't left in a half alive situation.		
       
  1029 	TInt err = KErrNone;
       
  1030 	RRemConBulk newBulk;
       
  1031 	
       
  1032 	if(BulkOpened())
       
  1033 		{
       
  1034 		// See if we can kick RemCon back into life
       
  1035 		err = newBulk.Connect();
       
  1036 		}
       
  1037 	
       
  1038 	if(err == KErrNone)
       
  1039 		{
       
  1040 		// RemCon lives!  Set our session to be the nice new one.
       
  1041 		if(BulkOpened())
       
  1042 			{
       
  1043 			iBulkSession->Close();
       
  1044 			iBulkSession->SetHandle(newBulk.Handle());
       
  1045 			iBulkReceiver->Receive();
       
  1046 			}
       
  1047 		}
       
  1048 	else
       
  1049 		{
       
  1050 		// We may not have successfully opened this, but it's safe to 
       
  1051 		// close it anyway.
       
  1052 		newBulk.Close();
       
  1053 		}
       
  1054 	
       
  1055 	return err;
       
  1056 	}
       
  1057