serialserver/c32serialserver/SCOMM/cs_thread.cpp
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 // Copyright (c) 2005-2009 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 "cs_thread.h"
       
    22 #include "C32LOG.H"
       
    23 #include "CS_STD.H"
       
    24 #include "cs_roles.h"
       
    25 #include "cs_msgs.h"
       
    26 #include "cs_glob.h"
       
    27 #include <elements/nm_address_internal.h>
       
    28 
       
    29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    30 #include <cflog.h>
       
    31 #endif
       
    32 
       
    33 #include <elements/cftransportmsg.h>
       
    34 
       
    35 using namespace CommsFW;
       
    36 
       
    37 #ifndef KLogSubSysSerComms
       
    38 __CFLOG_STMT(_LIT8(KLogSubSysSerComms, "SerComms");)
       
    39 #endif
       
    40 
       
    41 //
       
    42 //	CC32WorkerThread class definitions
       
    43 //
       
    44 
       
    45 CC32WorkerThread* CC32WorkerThread::NewL(TCFModuleInfo* aModuleInfo)
       
    46 	{
       
    47 	CleanupStack::PushL(TCleanupItem(DeleteHBufC8, aModuleInfo->iIniData));	
       
    48 	CC32WorkerThread* self = new (ELeave) CC32WorkerThread;
       
    49 	CleanupStack::PushL(self);
       
    50 	self->ConstructL(aModuleInfo);
       
    51 	CleanupStack::Pop(self);
       
    52 	CleanupStack::PopAndDestroy();	// aModuleInfo->iIniData	
       
    53 	return self;
       
    54 	}
       
    55 
       
    56 CC32WorkerThread::CC32WorkerThread()
       
    57 #ifdef _DEBUG  
       
    58    : iFailType(RAllocator::ENone)
       
    59 #endif
       
    60 	{
       
    61 	}
       
    62 
       
    63 /**
       
    64 The worker thread secondary construction will create the relevant Player/Dealer
       
    65 instances needed as well as the channel handler to the Root Server. If and only if it
       
    66 is the main thread it will also create the PitBoss.
       
    67 @note If it has a Dealer and is not the main thread it is a WorkerDealer.
       
    68 */
       
    69 void CC32WorkerThread::ConstructL(TCFModuleInfo* aModuleInfo)
       
    70 	{
       
    71 	TBool isDealer;
       
    72 	TBool isPlayer;
       
    73 	__CFLOG_OPEN;
       
    74 	C32LOG1(KC32Bootup,_L8("CC32WorkerThread::ConstructL Determining roles"));
       
    75 	DetermineRoleL(*aModuleInfo->iIniData, isDealer, isPlayer);
       
    76 
       
    77 	iWorkerRegister = CC32WorkerRegister::NewL(WorkerId(), NULL);
       
    78 	iTransport = CCommsTransport::NewL(*iWorkerRegister, NULL, NULL);
       
    79 	iTransport->RegisterLegacyInterface(this);
       
    80 
       
    81 	// initglobals allocates on heap and stores pointer in TLS, so
       
    82 	// requires special cleanup if we leave beyond here - handled in RunC32Thread
       
    83 	C32GlobalUtil::InitC32GlobalsL(this);
       
    84 	
       
    85 #ifdef _DEBUG
       
    86   	if(aModuleInfo->iIniData!=NULL)
       
    87   		{
       
    88 	  	// Support for simulated heap allocation failures: place "AllocFail= type rate" in .CMI file
       
    89 	  	// where:
       
    90 	  	//	type == ERandom, ETrueRandom, EDeterministic, EFailNext
       
    91 	  	//	rate == rate/chance of failure
       
    92 	  	// See RAllocator documentation for details. Best to set this for the heap owner only, since the
       
    93 	  	// last one processed will determine function for all heap users & it could get confusing.
       
    94 	  	_LIT8(KAllocFailLabel, "AllocFail");
       
    95 	  	TPtrC8 allocFail;
       
    96 	  	if(GetVarFromIniData(*(aModuleInfo->iIniData), KNullDesC8, KAllocFailLabel, allocFail))
       
    97 	  		{
       
    98 	  		TLex8 lex(allocFail);
       
    99 	  		TPtrC8 failTypeTok = lex.NextToken();
       
   100 	  		const struct 
       
   101 	  			{ 
       
   102 	  			const TText8* iLabel;
       
   103 	  			RAllocator::TAllocFail iType;
       
   104 	  			} failModes[] = 
       
   105 	  			{	
       
   106 	  				{ _S8("ERandom"), RAllocator::ERandom },
       
   107 	  				{ _S8("ETrueRandom"), RAllocator::ETrueRandom },
       
   108 	  				{ _S8("EDeterministic"), RAllocator::EDeterministic },
       
   109 	  				{ _S8("EFailNext"), RAllocator::EFailNext }
       
   110 	  			};
       
   111 	  		TInt i;
       
   112 	  		for(i = sizeof(failModes) / sizeof(failModes[0]) - 1; i >= 0; --i)
       
   113 	  			{
       
   114 	  			if(TPtrC8(failModes[i].iLabel).CompareF(failTypeTok) == 0)
       
   115 	  				{
       
   116 	  				break;
       
   117 	  				}
       
   118 	  			}
       
   119 	  		TInt rate = 0;
       
   120 	  		lex.SkipSpace();
       
   121 	  		if(i < 0 || lex.Val(rate) != KErrNone)
       
   122 	  			{
       
   123 	  			// Already in Debug mode so just log and panic
       
   124 	  			C32LOG1(KC32Bootup, _L("Panic - Corrupt Ini data - AllocFail param"));
       
   125 	  			Fault(EBadIniData);
       
   126 	  			}
       
   127 	  		iFailType = failModes[i].iType;
       
   128 	  		iFailRate = rate;
       
   129 	  		}
       
   130 	  
       
   131 	  	/* 
       
   132 	  	For debug builds, ensure that the array inside the cleanup stack will never
       
   133 	  	need to allocate any memory. This aids checking for leaked cells across a
       
   134 	  	sequence of calls that is heap-balanced.
       
   135 	  	*/
       
   136 	  		{
       
   137 	  		const TInt KStretchExtent = 10;
       
   138 	  		TRAP_IGNORE( 
       
   139 	  			for(TInt i = 0; i < KStretchExtent; i++)
       
   140 	  				{
       
   141 	  				CleanupStack::PushL((TAny*)1);
       
   142 	  				}
       
   143 	  			CleanupStack::Pop(KStretchExtent);
       
   144 	  			)
       
   145 	  		}
       
   146 
       
   147   		}
       
   148 #endif	// _DEBUG
       
   149 	
       
   150 	if(isDealer)
       
   151 		{
       
   152 		if(IsMainThread())
       
   153 			{
       
   154 			C32LOG(KC32Bootup, _L8("I am the Main Thread. Creating Dealer."));
       
   155 			iDealer = CC32Dealer::NewL(this,*(aModuleInfo->iIniData));
       
   156 			if(iDealer->ThreadManager())
       
   157 				{
       
   158 				if(iDealer->ThreadManager()->DefaultThread() == KMainThreadId)
       
   159 					{
       
   160 					/*
       
   161 					The default thread which loads unlisted CSYs is the dealer/main thread (workerId=0),
       
   162 					this isn't	normal in a multi-threaded configuration, but can happen due to 
       
   163 					1. BAD configuration (would fault in debug builds to signal a corrupt configuration, but not in release)
       
   164 					2. CMI files with no C32SerComms group field in it.
       
   165 					3. CSYList=* field present in IniData section of dealer/main thread (workerId=0) [valid, but discouraged in multi-threaded conf]
       
   166 					*/
       
   167 					C32LOG(KC32Warning,_L8("Dealer is default thread for loading unlisted CSYs! A BAD configuration perhaps ?"));
       
   168 					isPlayer=ETrue;
       
   169 					}
       
   170 				}
       
   171 			}
       
   172 		}
       
   173 	else
       
   174 		{
       
   175 		SetDealerShutdownComplete(ETrue);
       
   176 		}
       
   177 
       
   178 	if(isPlayer)
       
   179 		{
       
   180 		C32LOG1(KC32Bootup, _L8("I am a Player, creating instance."));
       
   181 		iPlayer = CC32Player::NewL(this);
       
   182 		}
       
   183 	else
       
   184 		{
       
   185 		SetPlayerShutdownComplete(ETrue);
       
   186 		}
       
   187 
       
   188 
       
   189 	// Start listening for binds, etc, from the RS
       
   190 	C32LOG1(KC32Bootup, _L8("CC32WorkerThread::ConstructL Init RS ChannelHandler"));
       
   191 	iChannelHandler = CCommChannelHandler::NewL(aModuleInfo->iRxQueues, aModuleInfo->iTxQueues, this);
       
   192 	C32LOG1(KC32Bootup, _L8("CC32WorkerThread::ConstructL Done"));
       
   193 	}
       
   194 
       
   195 CC32WorkerThread::~CC32WorkerThread()
       
   196 	{
       
   197 	C32LOG2(KC32Shutdown, _L8("CC32WorkerThread(%08x)::~CC32WorkerThread()"), this);
       
   198 	delete iTransport;
       
   199 	delete iChannelHandler;
       
   200 	delete iPlayer;
       
   201 	if(IsMainThread())
       
   202 		{
       
   203 		delete iDealer;
       
   204 		}
       
   205 	delete iWorkerRegister;
       
   206 	C32LOG2(KC32Shutdown, _L8("CC32WorkerThread(%08x)::~CC32WorkerThread() complete"), this);
       
   207 	__CFLOG_CLOSE;
       
   208 	}
       
   209 
       
   210 /** Determine from inidata whether this worker is Dealer, Player or both. */
       
   211 void CC32WorkerThread::DetermineRoleL(const TDesC8& aIniData, TBool &aIsDealer, TBool &aIsPlayer)
       
   212 	{
       
   213 	aIsDealer = EFalse;
       
   214 	aIsPlayer = EFalse;
       
   215 	// BC when No IniData present, this CPM is both Dealer and Player
       
   216 	if(&aIniData==NULL)
       
   217 		{
       
   218 		aIsDealer = ETrue;
       
   219 		aIsPlayer = ETrue;
       
   220 		}
       
   221 	else
       
   222 		{
       
   223 		TPtrC8 roleValue;
       
   224 		// Role missing - Dealer
       
   225 		if (!GetVarFromIniData(aIniData, KNullDesC8, KRoleLabel, roleValue))
       
   226 			{
       
   227 			aIsDealer = ETrue;
       
   228 			}
       
   229 		else
       
   230 			{
       
   231 			// Role present - player
       
   232 			if (roleValue.CompareF(KPlayerRole)==0)
       
   233 				{
       
   234 				aIsPlayer = ETrue;
       
   235 				}
       
   236 			// Role present - dealer
       
   237 			else if (roleValue.CompareF(KDealerRole)==0)
       
   238 				{
       
   239 				aIsDealer = ETrue;
       
   240 				}
       
   241 			// Role present - invalid arg
       
   242 			else
       
   243 				{
       
   244 				C32LOG2(KC32Warning, _L8("Invalid Role in [IniData] section: %S"),&roleValue);
       
   245 				__ASSERT_DEBUG(0,Fault(EBadIniData));
       
   246 				}
       
   247 			}
       
   248 
       
   249 		// WorkerId missing
       
   250 		TPtrC8 workerIdValue;
       
   251 		if(!GetVarFromIniData(aIniData, KNullDesC8, KWorkerIdLabel, workerIdValue))
       
   252 			{
       
   253 			C32LOG1(KC32Warning, _L8("Corrupt [IniData]: WorkerId missing."));
       
   254 			__ASSERT_DEBUG(0,Fault(EBadIniData));
       
   255 			// leave if ini data corrupt rather than panic unless debug 
       
   256 			User::Leave(KErrCorrupt);		
       
   257 			}
       
   258 
       
   259 		User::LeaveIfError(ConvertVal(workerIdValue, iWorkerId));
       
   260 		// check for boundary values for WorkerId
       
   261 		if(iWorkerId > TC32WorkerThreadPublicInfo::EMaxWorkerThreadId)
       
   262 			{
       
   263 			C32LOG2(KC32Warning, _L8("Corrupt [IniData]: Invalid WorkerId: %d"),iWorkerId);
       
   264 			__ASSERT_DEBUG(0,Fault(EBadIniData));
       
   265 			// leave if ini data corrup rather than panic if not debug
       
   266 			User::Leave(KErrCorrupt);
       
   267 			}
       
   268 
       
   269 		if(iWorkerId == TC32WorkerThreadPublicInfo::EMainThread && aIsDealer == EFalse)
       
   270 			{
       
   271 			C32LOG1(KC32Warning, _L8("Worker Id zero with no dealer role. overriding"));
       
   272 			aIsDealer = ETrue;
       
   273 			}
       
   274 
       
   275 		// CSYList present - Player
       
   276 		TPtrC8 csyListValue;
       
   277 		if(GetVarFromIniData(aIniData, KNullDesC8, KCSYListLabel, csyListValue))
       
   278 			{
       
   279 			aIsPlayer = ETrue;
       
   280 			}
       
   281 		}	// End of else block [if(aIniData==NULL)]
       
   282 	}
       
   283 
       
   284 
       
   285 
       
   286 /**
       
   287 Check that our end sub-module address is correctly named: the sub-module name must be numeric and match our worker id.
       
   288 */
       
   289 TInt CC32WorkerThread::DecodePeerId(const TCFSubModuleAddress* aSubModule1, const TCFSubModuleAddress* aSubModule2, TWorkerId& aPeerId)
       
   290 	{
       
   291 	TInt err = KErrNone;
       
   292 	if(ConvertVal(aSubModule1->SubModule(), aPeerId) != KErrNone || aPeerId != WorkerId())
       
   293 		{
       
   294 		err = KErrCorrupt;	
       
   295 		}
       
   296 	else 
       
   297 		{
       
   298 		if(ConvertVal(aSubModule2->SubModule(), aPeerId) != KErrNone || 
       
   299 			aPeerId > TC32WorkerThreadPublicInfo::EMaxWorkerThreadId)
       
   300 			{
       
   301 			err = KErrCorrupt;	
       
   302 			}
       
   303 		}
       
   304 	return err;
       
   305 	}
       
   306 
       
   307 
       
   308 /**
       
   309 Deals with binding requests from the Root Server. Note that although the Root Server allows
       
   310 multiple identical bindings C32 does not allow this and will panic if the binding already exists.
       
   311 Bindings are expressed in C32 by CCommsTransport. Since all sub-module
       
   312 names are unique across all C32 instances (they are the individual owning worker ID converted to text)
       
   313 they can be used here. I.e. the remote end sub-module is converted back to int and used to insert the
       
   314 CCommsTransport into an array in the position corresponding to the remote end sub-module name/number.
       
   315 As for responding to the bind request there are two cases:
       
   316     -# This worker is a "dumb" Player: Send bind response immediately.
       
   317 	-# This worker is the Main thread: Send introduction messages to remote end and 
       
   318 	postpone bind response until introduction response messages have arrived back.
       
   319 @see CCommsTransport
       
   320 */
       
   321 void CC32WorkerThread::CFBindMessageReceived(const TCFBindMsg& aMsg)
       
   322 	{
       
   323     __CFLOG_SMADDR2(( KLogSubSysSerComms, KLogSubSysSerComms, _L8("W%d: CFBindMessageReceived %S <=> %S"),
       
   324 		WorkerId(),
       
   325 		&aMsg.SubModule1()->Printable(__FullModName1), 
       
   326 		&aMsg.SubModule2()->Printable(__FullModName2) ));
       
   327 	TWorkerId bindId;
       
   328 	TInt err = DecodePeerId(aMsg.SubModule1(), aMsg.SubModule2(), bindId);
       
   329 	ASSERT(bindId <=  TC32WorkerThreadPublicInfo::EMaxWorkerThreadId);
       
   330 	if(err == KErrNone)
       
   331 		{
       
   332 		if(iTransport->PeerReachable(bindId))
       
   333 			{
       
   334 			C32LOG2(KC32Bootup, _L("%d Already exists. Error in configuration of cmi files"),bindId);
       
   335 			//Must panic b/c the new module will be left in a half bound state and will tend to get out of hand
       
   336 			__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransInvalidWorkerId));
       
   337 			}
       
   338 		else
       
   339 			{
       
   340 			err = iTransport->EstablishTransportToPeer(bindId, aMsg.ChannelInput(), aMsg.ChannelOutput());
       
   341 			// Main thread introduces itself; workers wait passively for this
       
   342 			if(err == KErrNone)
       
   343 				{
       
   344 				iTransport->SetLastRequestIdConcerningPeer(bindId, aMsg.Identifier());
       
   345 				if(IsMainThread())
       
   346 					{
       
   347 					C32LOG1(KC32Bootup, _L("Sending Introduction Message to Worker"));
       
   348 					DealerByRef().SendIntroductionToWorker(bindId);
       
   349 					}
       
   350 				}
       
   351 			}
       
   352 		}
       
   353 	/* Main dealer only completes when it has received the introduction response messages from peers,
       
   354 	dumb players respond immediately. */
       
   355 	if(err!=KErrNone || !IsMainThread())
       
   356 		{
       
   357 		TCFBindCompleteMsg respMsg(aMsg.Identifier(), err);
       
   358 		VERIFY_RESULT(iChannelHandler->Send(respMsg), KErrNone);
       
   359 		}
       
   360 	}
       
   361 
       
   362 void CC32WorkerThread::SetDealerShutdownComplete(TBool aComplete)
       
   363 	{
       
   364 	// Backsliding not permitted; cannot step back to !complete
       
   365 	if(aComplete)
       
   366 		{
       
   367 		iDealerShutdownComplete = aComplete;
       
   368 		MaybeCompleteUnbindings();
       
   369 		}
       
   370 	}
       
   371 
       
   372 void CC32WorkerThread::SetPlayerShutdownComplete(TBool aComplete)
       
   373 	{
       
   374 	// Backsliding not permitted; cannot step back to !complete
       
   375 	if(aComplete)
       
   376 		{
       
   377 		iPlayerShutdownComplete = aComplete;
       
   378 		MaybeCompleteUnbindings();
       
   379 		}
       
   380 	}
       
   381 
       
   382 /** 
       
   383 The unbind requests are only responded to once the channel is presumed to be idle:
       
   384    - for Dealers this means no sessions remain with subsessions on that Player
       
   385    - for Players this means no subsessions remain for that Dealer
       
   386 So the peer handler is marked as pending unbind but the unbind response is not sent back
       
   387 until both Dealer and Player (if any) confirm idleness, which has to be checked whenever
       
   388 closing sessions or subsessions. 
       
   389 Perhaps this could/should switch to using ref counts?
       
   390 Once unbind is pending the Dealer refrains from creating any new subsessions which use it.
       
   391 @see CC32WorkerThread::MaybeCompleteUnbinding
       
   392 */
       
   393 void CC32WorkerThread::CFUnbindMessageReceived(const TCFUnbindMsg& aMsg)
       
   394 	{
       
   395 	// Mark the peer handler as unbinding
       
   396     __CFLOG_SMADDR2(( KLogSubSysSerComms, KLogSubSysSerComms, _L8("W%d: CFUnbindMessageReceived %S <=> %S"),
       
   397 		WorkerId(),
       
   398 		&aMsg.SubModule1()->Printable(__FullModName1), 
       
   399 		&aMsg.SubModule2()->Printable(__FullModName2) ));
       
   400 
       
   401 	TWorkerId unbindId;
       
   402 	TInt err = DecodePeerId(aMsg.SubModule1(), aMsg.SubModule2(), unbindId);
       
   403 	if(err == KErrNone && !iTransport->PeerReachable(unbindId))
       
   404 		{
       
   405 		__ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); // shouldn't happen, but could possibly by race with thread panicked in shutdown?
       
   406 		err = KErrNotFound;	
       
   407 		}
       
   408 	if(err == KErrNone)
       
   409 		{
       
   410 		iTransport->SetLastRequestIdConcerningPeer(unbindId, aMsg.Identifier());
       
   411 		iTransport->SetDropTransportPending(unbindId, ETrue);
       
   412 		MaybeCompleteUnbinding(unbindId);
       
   413 		}
       
   414 	else
       
   415 		{
       
   416 		TCFUnbindCompleteMsg respMsg(aMsg.Identifier(), err);
       
   417 		VERIFY_RESULT(iChannelHandler->Send(respMsg), KErrNone);
       
   418 		}
       
   419 	}
       
   420 
       
   421 /** 
       
   422 Can be called at any time, will poll all peer handlers for unbind "readiness" and make sure
       
   423 they complete the unbind if possible. 
       
   424 @see CC32WorkerThread::MaybeCompleteUnbinding
       
   425 */
       
   426 void CC32WorkerThread::MaybeCompleteUnbindings()
       
   427 	{
       
   428 	if(iProlongBindingLife == 0)
       
   429 		{
       
   430 		for(TWorkerId player = TC32WorkerThreadPublicInfo::EMainThread; player <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; ++player)
       
   431 			{
       
   432 			MaybeCompleteUnbinding(player);
       
   433 			}
       
   434 		}
       
   435 	}
       
   436 
       
   437 /** 
       
   438 If the peer handler have been marked for unbind check whether local Dealer/Player is ready to 
       
   439 unbind from this particular worker. If so, deletes handler and send unbind response to Root Server. 
       
   440 @see CC32Dealer::CanUnbindFromWorker
       
   441 @see CC32Player::CanUnbindFromWorker
       
   442 @see TCFUnbindCompleteMsg
       
   443 */
       
   444 void CC32WorkerThread::MaybeCompleteUnbinding(TWorkerId aWorker)
       
   445 	{
       
   446 	if(iTransport->PeerReachable(aWorker) && iTransport->IsDropTransportPending(aWorker))
       
   447 		{
       
   448 		if(!Dealer() || Dealer()->CanUnbindFromWorker(aWorker))
       
   449 			{
       
   450 			if(!Player() || Player()->CanUnbindFromWorker(aWorker))
       
   451 				{
       
   452 				C32LOG2(KC32Bootup, _L("CC32WorkerThread::MaybeCompleteUnbinding(%d) - dropping transport & unbinding"), aWorker);
       
   453 				TCFUnbindCompleteMsg respMsg(iTransport->LastRequestIdConcerningPeer(aWorker), KErrNone);
       
   454 				iTransport->DropTransportToPeer(aWorker);
       
   455 				VERIFY_RESULT(iChannelHandler->Send(respMsg), KErrNone);
       
   456 				}
       
   457 			}
       
   458 		}
       
   459 	}
       
   460 
       
   461 /** 
       
   462 A shutdown message can be of several types:
       
   463     -# EImmediate: We shutdown immediately even if leaking resources, although doing a best effort to cleanup. However, SymbianOS doesnt allow the server to gracefully terminate sessions so certain things cant be cleaned up.
       
   464 	-# EOptional: Ignored.
       
   465 	-# EGraceful: The module only unloads once no resources remain, which means for the Dealer no sessions and for the Player no subsessions. The shutdown request arrives after the unbind requests.
       
   466 @see CommsFW::TCFShutdownMsg
       
   467 @see CommsFW::TCFShutdownType
       
   468 @see CC32Dealer::ProcessShutdownRequest
       
   469 @see CC32Player::ProcessShutdownRequest
       
   470 @see CC32WorkerThread::SetShuttingDown
       
   471 @see CC32WorkerThread::MaybeTriggerThreadShutdownCallback
       
   472 */
       
   473 void CC32WorkerThread::CFShutdownMessageReceived(const CommsFW::TCFShutdownMsg& aMsg)
       
   474 	{
       
   475 	const CommsFW::TCFShutdownType type = aMsg.Type();
       
   476 	C32LOG2(KC32Shutdown, _L("CFShutdownMessageReceived(%d)"), type);
       
   477 
       
   478 	if(EOptional == type)
       
   479 		{
       
   480 		C32LOG1(KC32Shutdown, _L("Type is EOptional: ignoring"));
       
   481 		return;
       
   482 		}
       
   483 	else if(EImmediate == type)
       
   484 		{
       
   485 		C32LOG1(KC32Shutdown, _L("Type is EImmediate"));
       
   486 		DealerByRef().SetImmediateShutdownPresent();
       
   487 		}
       
   488 
       
   489 	SetShuttingDown();
       
   490 
       
   491 	if(Dealer())
       
   492 		{
       
   493 		Dealer()->ProcessShutdownRequest(type);
       
   494 		}
       
   495 	if(Player())
       
   496 		{
       
   497 		Player()->ProcessShutdownRequest(type);
       
   498 		}
       
   499 
       
   500 	MaybeTriggerThreadShutdownCallback();
       
   501 	}
       
   502 
       
   503 void CC32WorkerThread::PostMessage(TWorkerId aWorkerId, TCFMessage& aMessage)
       
   504 	{
       
   505 	TCFLegacyMessagePacker::PackForPostage(aWorkerId, aMessage);
       
   506 	iTransport->PostMessage(aMessage);
       
   507 	}
       
   508 
       
   509 /** 
       
   510 Deal with incoming messages from other workers.
       
   511 */
       
   512 void CC32WorkerThread::DispatchL(const TCFMessage& aMessage, TWorkerId aSenderId)
       
   513 	{
       
   514 	switch(aMessage.Code())
       
   515 		{
       
   516 	case TC32WorkerMsg::EMainIntroduction:
       
   517 		{
       
   518 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). EMainIntroduction"), aSenderId);
       
   519 		ASSERT(!IsMainThread());
       
   520 		const TC32WorkerMainIntroductionMsg& msg = reinterpret_cast<const TC32WorkerMainIntroductionMsg&>(aMessage);
       
   521 		iDealer = msg.Dealer();
       
   522 		iWorkerRegister->SetGlobalThreadRegister(&iDealer->WorkerDataGlobals());
       
   523 		TC32WorkerThreadPublicInfo info;
       
   524 		info.Init(WorkerId(), aSenderId == TC32WorkerThreadPublicInfo::EMainThread);
       
   525 		info.iWorker = this;
       
   526 		TC32WorkerMainIntroductionRespMsg respMsg(info);
       
   527 #ifdef _DEBUG
       
   528   		respMsg.SetFailType(iFailType);
       
   529   		respMsg.SetFailRate(iFailRate);
       
   530 #endif
       
   531 		PostMessage(aSenderId, respMsg);
       
   532 		break;
       
   533 		}
       
   534 	case TC32WorkerMsg::EMainIntroductionResp:
       
   535 		{
       
   536 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). EMainIntroductionResp"), aSenderId);
       
   537 		ASSERT(IsMainThread());
       
   538 		const TC32WorkerMainIntroductionRespMsg& msg = reinterpret_cast<const TC32WorkerMainIntroductionRespMsg&>(aMessage);
       
   539 		DealerByRef().ProcessWorkerIntroductionResponse(msg);
       
   540 
       
   541 		/* In contrast with the players, who send their bind response immediately to the RootServer, 
       
   542 		the Main dealer has deferred sending the bind response until it has initialised the protocols 
       
   543 		signalled in the introduction response message. This ultimately ensures that the configurator 
       
   544 		only increments the sequence level when all protocols are actually initialised. */
       
   545 		TCFBindCompleteMsg bindresp(iTransport->LastRequestIdConcerningPeer(aSenderId), KErrNone);
       
   546 		VERIFY_RESULT(iChannelHandler->Send(bindresp), KErrNone);
       
   547 		iTransport->SetLastRequestIdConcerningPeer(aSenderId, TCFCommsMessageId::KNullMessageId);
       
   548 		// delete cpmLoader
       
   549 		DealerByRef().DeleteCPMLoader(aSenderId);
       
   550 		break;
       
   551 		}
       
   552 
       
   553 	case TC32PlayerMsg::EForwardRequest:
       
   554 		{
       
   555 		ASSERT(Player());
       
   556 		TC32PlayerForwardRequestMsg fwdReqMsg(reinterpret_cast<const TC32PlayerForwardRequestMsg&>(aMessage));
       
   557 		C32LOG2(KC32CommsTrspMsg, _L8("DispatchL(%d). EForwardRequest "), aSenderId);
       
   558 		Player()->ProcessMessageL(fwdReqMsg.Message(), fwdReqMsg.SubSession());
       
   559 		break;
       
   560 		}
       
   561 	case TC32PlayerMsg::ESessionClose:
       
   562 		{
       
   563 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). ESessionClose"), aSenderId);
       
   564 		CC32Player* player = Player();
       
   565 		ASSERT(player);
       
   566 		const TC32PlayerSessionCloseMsg& sessionCloseMsg = reinterpret_cast<const TC32PlayerSessionCloseMsg&>(aMessage);
       
   567 		/* Only do something if the message is within the deadline and we're sure 
       
   568 		   the session pointer is safe to use */
       
   569 		TTime time;
       
   570 		time.HomeTime();
       
   571 		if(time.Int64()<=sessionCloseMsg.SessionCloseDeadline())
       
   572 			{
       
   573 			IncProlongBindingLife();
       
   574 			player->CloseSession(sessionCloseMsg.Session());
       
   575 			TC32PlayerSessionCloseRespMsg sessionCloseRespMsg(WorkerId(), sessionCloseMsg);
       
   576 			PostMessage(aSenderId, sessionCloseRespMsg);
       
   577 			DecProlongBindingLife();
       
   578 			if(ShuttingDown())
       
   579 				{
       
   580 				player->MaybeSetPlayerShutdownComplete(EFalse);
       
   581 				MaybeTriggerThreadShutdownCallback();
       
   582 				}
       
   583 			}
       
   584 		break;
       
   585 		}
       
   586 	case TC32PlayerMsg::ESessionCloseResp:
       
   587 		{
       
   588 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). ESessionCloseResp"), aSenderId);
       
   589 		ASSERT(IsMainThread());
       
   590 		const TC32PlayerSessionCloseRespMsg& msg = reinterpret_cast<const TC32PlayerSessionCloseRespMsg&>(aMessage);
       
   591 		ASSERT(msg.Session());
       
   592 	
       
   593 		/* Only do something if the message is within the deadline and we're sure 
       
   594 		   the session pointer is safe to use */
       
   595 		TTime time;
       
   596 		time.HomeTime();
       
   597 		if(time.Int64()<=msg.SessionCloseDeadline())
       
   598 			{
       
   599 			CCommSession* session = msg.Session();
       
   600 			session->SessionCloseResp(msg.WorkerId());
       
   601 			if(session->IsDisconnectListEmpty())
       
   602 				{
       
   603 				// Deleting the session may allow the binding to be removed, which will
       
   604 				// cause the channel handler to be deleted
       
   605 				Dealer()->DeleteSession(session);
       
   606 				}
       
   607 			}
       
   608 		break;
       
   609 		}
       
   610 	case TC32PlayerMsg::ELoadCommModuleMsg:
       
   611 		{
       
   612 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). ELoadCommModuleMsg"), aSenderId);
       
   613 		ASSERT(Player());
       
   614 		TC32PlayerLoadCommModuleMsg msg(reinterpret_cast<const TC32PlayerLoadCommModuleMsg&>(aMessage));
       
   615 		// make function call to player here
       
   616 		Player()->LoadCommModule(msg.Message());
       
   617 		break;
       
   618 		}
       
   619 	case TC32PlayerMsg::ELoadCommModuleSuccessResp:
       
   620 		{
       
   621 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). ELoadCommModuleResp"), aSenderId);
       
   622 		ASSERT(IsMainThread());
       
   623 		TC32PlayerLoadCommModuleSuccessResp msg(reinterpret_cast<const TC32PlayerLoadCommModuleSuccessResp&>(aMessage));
       
   624 		// update CC32ThreadManager with CSerial*, portprefix and csyfilename for the csy loaded successfully
       
   625 		// portprefix is retrieved using CSerial* (by switching heap if necessary) and csyfilename is obtained 
       
   626 		// from message, after dealer after updating ThreadManager complete message with KErrNone, to emilinate 
       
   627 		// possible race condition of player completing message and subsequent port open rerquest reaching 
       
   628 		// ThreadManager before dealer gets a chance to update ThreadManager
       
   629 		Dealer()->ProcessLoadCommModuleSuccessResponse(msg.Message(), msg.SerialPtr());
       
   630 		break;
       
   631 		}
       
   632 	case TC32PlayerMsg::ELoadCommModuleFailureResp:
       
   633 		{
       
   634 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). ELoadCommModuleFailureResp"), aSenderId);
       
   635 		ASSERT(IsMainThread());
       
   636 		const TC32PlayerLoadCommModuleFailureResp msg(reinterpret_cast<const TC32PlayerLoadCommModuleFailureResp&>(aMessage));
       
   637 		// remove CSY from session CSY container and de-allocate memory for this csy in ThreadManager as load failed
       
   638 		Dealer()->ProcessLoadCommModuleFailureResponse(msg.Message(), msg.FailureReason());
       
   639 		break;
       
   640 		}
       
   641 	case TC32PlayerMsg::EUnLoadCommModuleMsg:
       
   642 		{
       
   643 		C32LOG2(KC32Detail, _L("DispatchL(%d). EUnLoadCommModuleMsg"), aSenderId);
       
   644 		ASSERT(Player());
       
   645 		TC32PlayerUnLoadCommModuleMsg msg(reinterpret_cast<const TC32PlayerUnLoadCommModuleMsg&>(aMessage));
       
   646 		Player()->ProcessUnLoadCommModuleMsg(msg.SerialPtr());
       
   647 		break;
       
   648 		}
       
   649 	case TC32PlayerMsg::EGetPortInfoMsg:
       
   650 		{
       
   651 		C32LOG2(KC32CommsTrspMsg, _L("DispatchL(%d). EGetPortInfoMsg"), aSenderId);
       
   652 		ASSERT(Player());
       
   653 		TC32PlayerGetPortInfoMsg msg(reinterpret_cast<const TC32PlayerGetPortInfoMsg&>(aMessage));
       
   654 		// make function call to player here
       
   655 		Player()->PortInfo(msg.Message(), msg.SerialPtr());
       
   656 		break;
       
   657 		}
       
   658 	default:
       
   659 		{
       
   660 		C32LOG1(KC32Warning, _L("Unknown Transport message received. Do Nothing"));
       
   661 		break;
       
   662 		}
       
   663 
       
   664 		}
       
   665 	}
       
   666 
       
   667 /**
       
   668 The ProcessMessageL function which takes care of incoming messages doesnt TRAP anything,
       
   669 instead we count on dealing with failures here in the RunError. This simplifies the
       
   670 ProcessMessageL function and avoids the cost of another TRAP
       
   671 @see CC32Player::ProcessMessageL
       
   672 */
       
   673 void CC32WorkerThread::OnDispatchLeave(const TCFMessage& aMessage, TWorkerId /*aSenderId*/, TInt aError)
       
   674 	{
       
   675 	C32LOG3(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave- Dispatch Left!! for message %x with error %d"),&aMessage,aError);
       
   676 	switch(aMessage.Code())
       
   677 		{
       
   678 		case TC32PlayerMsg::EForwardRequest:
       
   679 			{
       
   680 			TC32PlayerForwardRequestMsg fwdReqMsg(reinterpret_cast<const TC32PlayerForwardRequestMsg&>(aMessage));
       
   681 			if(aError != KErrNone && aError != KErrBadDescriptor) 
       
   682 				{   
       
   683 				fwdReqMsg.Message().Complete(aError); 
       
   684 		        C32LOG1(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave, EForwardRequest - completing message."));
       
   685 				}
       
   686 			break;
       
   687 			}
       
   688 		case TC32PlayerMsg::ELoadCommModuleMsg:
       
   689 			{
       
   690 			TC32PlayerLoadCommModuleMsg loadMsg(reinterpret_cast<const TC32PlayerLoadCommModuleMsg&>(aMessage));
       
   691 			if(aError != KErrNone && aError != KErrBadDescriptor) 
       
   692 				{   
       
   693 				loadMsg.Message().Complete(aError); 
       
   694 		        C32LOG1(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave, ELoadCommModuleMsg - completing message."));
       
   695 				}
       
   696 			break;
       
   697 			}
       
   698 		case TC32PlayerMsg::ELoadCommModuleSuccessResp:
       
   699 			{
       
   700 			TC32PlayerLoadCommModuleSuccessResp loadSuccessMsg(reinterpret_cast<const TC32PlayerLoadCommModuleSuccessResp&>(aMessage));
       
   701 			if(aError != KErrNone && aError != KErrBadDescriptor) 
       
   702 				{   
       
   703 				loadSuccessMsg.Message().Complete(aError); 
       
   704 		        C32LOG1(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave, ELoadCommModuleSuccessResp - completing message."));
       
   705 				}
       
   706 			break;
       
   707 			}
       
   708 		case TC32PlayerMsg::ELoadCommModuleFailureResp:
       
   709 			{
       
   710 			TC32PlayerLoadCommModuleFailureResp loadFailMsg(reinterpret_cast<const TC32PlayerLoadCommModuleFailureResp&>(aMessage));
       
   711 			if(aError != KErrNone && aError != KErrBadDescriptor) 
       
   712 				{   
       
   713 				loadFailMsg.Message().Complete(aError); 
       
   714 		        C32LOG1(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave, ELoadCommModuleFailureResp - completing message."));
       
   715 				}
       
   716 			break;
       
   717 			}
       
   718 		case TC32PlayerMsg::EGetPortInfoMsg:
       
   719 			{
       
   720 			TC32PlayerGetPortInfoMsg portInfoMsg(reinterpret_cast<const TC32PlayerGetPortInfoMsg&>(aMessage));
       
   721 			if(aError != KErrNone && aError != KErrBadDescriptor) 
       
   722 				{   
       
   723 				portInfoMsg.Message().Complete(aError); 
       
   724 		        C32LOG1(KC32Warning,_L8("CC32WorkerThread::OnDispatchLeave, EGetPortInfoMsg - completing message."));
       
   725 				}
       
   726 			break;
       
   727 			}
       
   728 		}
       
   729 	}
       
   730 
       
   731 
       
   732 TBool CC32WorkerThread::ShuttingDown() const
       
   733 	{
       
   734 	return iWorkerShuttingDown;
       
   735 	}
       
   736 
       
   737 void CC32WorkerThread::SetShuttingDown()
       
   738 	{
       
   739 	iWorkerShuttingDown = ETrue;
       
   740 	}
       
   741 
       
   742 void CC32WorkerThread::SessionShutdownComplete()
       
   743 	{
       
   744 	if(IsMainThread())
       
   745 		{
       
   746 		DealerByRef().SessionShutdownComplete();
       
   747 		}
       
   748 	else
       
   749 		{
       
   750 		TriggerThreadShutdownCallback();
       
   751 		}
       
   752 	}
       
   753 
       
   754 void CC32WorkerThread::TriggerThreadShutdownCallback()
       
   755 	{
       
   756 	C32LOG1(KC32Shutdown, _L("CC32WorkerThread::TriggerThreadShutdownCallback()") );
       
   757 	CC32DataInTls()->iShutdownWatchDog->Shutdown();
       
   758 	}
       
   759 
       
   760 void CC32WorkerThread::MaybeTriggerThreadShutdownCallback()
       
   761 	{
       
   762 	if(!ShuttingDown())
       
   763 		{
       
   764 		return;
       
   765 		}
       
   766 	TBool doTrigger = DealerByRef().TestImmediateShutdownPresent();
       
   767 	C32LOG4(KC32Shutdown, _L("MaybeTriggerThreadShutdownCallback() - immediate=%d, dealerComplete=%d, playerComplete=%d"), 
       
   768 		doTrigger, DealerShutdownComplete(), PlayerShutdownComplete());
       
   769 	if(!doTrigger && DealerShutdownComplete())
       
   770 		{
       
   771 		if(!PlayerShutdownComplete() && Player())
       
   772 			{
       
   773 			Player()->MaybeSetPlayerShutdownComplete(EFalse);
       
   774 			}
       
   775 		if(PlayerShutdownComplete())
       
   776 			{
       
   777 			// Check if all bindings have gone
       
   778 			doTrigger = ETrue;
       
   779 			for(TWorkerId player = TC32WorkerThreadPublicInfo::EMainThread; player <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; ++player)
       
   780 				{
       
   781 				if(player != WorkerId() && iTransport->PeerReachable(player))
       
   782 					{
       
   783 					C32LOG2(KC32Bootup, _L("MaybeTriggerThreadShutdownCallback() - peer %d binding remains"), player);
       
   784 					doTrigger = EFalse;
       
   785 					break;
       
   786 					}
       
   787 				}
       
   788 			}
       
   789 		}
       
   790 	if(doTrigger)
       
   791 		{
       
   792 		if(WorkerId() == TC32WorkerThreadPublicInfo::EMainThread)
       
   793 			{
       
   794 			DealerByRef().ShutdownIfReady();
       
   795 			}
       
   796 		else
       
   797 			{
       
   798 			TriggerThreadShutdownCallback();
       
   799 			}
       
   800 		}
       
   801 	}
       
   802 
       
   803 
       
   804 
       
   805 LOCAL_C void LoadDeviceDrivers(void)
       
   806 /**
       
   807  * On the target, load all the EUART LDDs and PDDs that can be found
       
   808  */
       
   809 	{
       
   810 #if defined (__EPOC32__)
       
   811 	//Load Pdd's
       
   812 	_LIT(CommPddName, "EUART");
       
   813 	_LIT(CommPddName0, "EUART0");
       
   814 	_LIT(CommPddName1, "EUART1");
       
   815 	_LIT(CommPddName2, "EUART2");
       
   816 	_LIT(CommPddName3, "EUART3");
       
   817 	_LIT(CommPddName4, "EUART4");
       
   818 	_LIT(CommPddName5, "EUART5");
       
   819 	_LIT(CommPddName6, "EUART6");
       
   820 	_LIT(CommPddName7, "EUART7");
       
   821 	_LIT(CommPddName8, "EUART8");
       
   822 	_LIT(CommPddName9, "EUART9");
       
   823 	User::LoadPhysicalDevice(CommPddName);
       
   824 	User::LoadPhysicalDevice(CommPddName0);
       
   825 	User::LoadPhysicalDevice(CommPddName1);
       
   826 	User::LoadPhysicalDevice(CommPddName2);
       
   827 	User::LoadPhysicalDevice(CommPddName3);
       
   828 	User::LoadPhysicalDevice(CommPddName4);
       
   829 	User::LoadPhysicalDevice(CommPddName5);
       
   830 	User::LoadPhysicalDevice(CommPddName6);
       
   831 	User::LoadPhysicalDevice(CommPddName7);
       
   832 	User::LoadPhysicalDevice(CommPddName8);
       
   833 	User::LoadPhysicalDevice(CommPddName9);
       
   834 	
       
   835 	// Load logical device driver
       
   836 	_LIT(CommLddName, "ECOMM.LDD");
       
   837 	User::LoadLogicalDevice(CommLddName);
       
   838 #endif // #ifdef __EPOC32__
       
   839 	}
       
   840 
       
   841 
       
   842 void CC32WorkerThread::DeleteHBufC8(TAny* aHBufC)
       
   843 	{
       
   844 	delete static_cast<HBufC8*>(aHBufC);
       
   845 	}
       
   846 
       
   847 
       
   848 /**
       
   849 The C32 thread. This is where control will resume when the RootServer starts a C32 instance.
       
   850 This function creates the worker thread object and starts the active scheduler.
       
   851 */
       
   852 EXPORT_C TInt CC32WorkerThread::ThreadEntryPoint(TAny* aArg)
       
   853 	{
       
   854 	return RunC32Thread(static_cast<TCFModuleInfo*>(aArg));
       
   855 	}
       
   856 
       
   857 EXPORT_C TInt CC32WorkerThread::RunC32Thread(TCFModuleInfo* aArg)
       
   858 /**
       
   859  * The comm server thread.
       
   860  */
       
   861 	{	
       
   862 	CTrapCleanup* tc=CTrapCleanup::New();
       
   863 	if (!tc)
       
   864 		{
       
   865 		return KErrNoMemory;
       
   866 		}
       
   867 		
       
   868 	LoadDeviceDrivers();
       
   869 
       
   870 	CCommScheduler* cs = CCommScheduler::New();
       
   871 
       
   872 	TCFModuleInfo* moduleInfo = aArg;
       
   873 	
       
   874 	TRAPD(res, CC32WorkerThread::NewL(moduleInfo)); // takes ownership of aArg and eventually deletes
       
   875 	
       
   876 	if(res != KErrNone)
       
   877 		{
       
   878 		// memory added to the TLS won't have been deleted since it isn't referred to be the cleanupstack
       
   879 		// due to it being deemed to be "owned" by the thread via the TLS. So we delete it here
       
   880 		CTLSRedirector* tls = CRedirectorInTls();
       
   881 		if (tls != NULL)
       
   882 			{
       
   883 			// The CC32Data destructor does not own any data that it points to, so does not delete the data,
       
   884 			// So we have to delete watchdog directly
       
   885 			
       
   886 			CC32Data* globals = CC32DataInTls();
       
   887 			if (globals != NULL)
       
   888 				{
       
   889 				delete globals->iShutdownWatchDog;
       
   890 				}
       
   891 			delete tls;
       
   892 			Dll::SetTls(NULL); // so that logger sees it is gone
       
   893 			}
       
   894 
       
   895 		delete cs;
       
   896 		delete tc;
       
   897 		
       
   898 		return res;
       
   899 		}
       
   900 
       
   901 	RThread::Rendezvous(KErrNone);
       
   902 		
       
   903 	CActiveScheduler::Start();
       
   904 	
       
   905 	delete cs;
       
   906 	delete tc;	
       
   907 		
       
   908 	return KErrNone;
       
   909 	}
       
   910 
       
   911 
       
   912 //
       
   913 // CCommChannelHandler class definitions
       
   914 //
       
   915 CCommChannelHandler::CCommChannelHandler(CC32WorkerThread* aWorkerThread)
       
   916 : CCFModuleChannelHandler(CActive::EPriorityStandard),
       
   917   iWorkerThread(aWorkerThread)
       
   918 	{
       
   919 	}
       
   920 
       
   921 CCommChannelHandler* CCommChannelHandler::NewL(RCFChannel::TMsgQueues aRxQueues,
       
   922 																   RCFChannel::TMsgQueues aTxQueues, 
       
   923 																   CC32WorkerThread* aWorkerThread)
       
   924 	{
       
   925 	CCommChannelHandler* pHandler = new (ELeave) CCommChannelHandler(aWorkerThread);
       
   926 	CleanupStack::PushL(pHandler);
       
   927 	pHandler->ConstructL(aRxQueues, aTxQueues);
       
   928 	CleanupStack::Pop(pHandler);
       
   929 	return pHandler;
       
   930 	}
       
   931 
       
   932 TInt CCommChannelHandler::Send(const CommsFW::TCFMessage &aMessage)
       
   933 	{
       
   934 	return inherited::Send(aMessage);
       
   935 	}
       
   936 
       
   937 
       
   938 /**
       
   939 This will be called by the handler when a shutdown message have been received from
       
   940 the Root Server. Delegating the call to the Worker Thread.
       
   941 */
       
   942 void CCommChannelHandler::CFMessageShutdown(const TCFShutdownMsg& aMessage)
       
   943 	{
       
   944 	iWorkerThread->CFShutdownMessageReceived(aMessage);
       
   945 	}
       
   946 
       
   947 /**
       
   948 This will be called by the handler when a Discovery message have been received from
       
   949 the Root Server. It will send a response, telling the Root Server that it has a single
       
   950 sub-module/binding point which is named after the WorkerID.
       
   951 As each Worker has a unique ID each worker thus also has a unique sub-module name to bind to,
       
   952 which potentially allows for simpler handling code and easy to interpret logs.
       
   953 */
       
   954 void CCommChannelHandler::CFMessageDiscover(const TCFDiscoverMsg& aMessage)
       
   955 	{
       
   956 	ASSERT(aMessage.Size() > 0);
       
   957 	TBuf8<4> subname;
       
   958 	_LIT8(subconst, "%d");
       
   959 	subname.Format(subconst, iWorkerThread->WorkerId());
       
   960 	aMessage.SubModuleNames()->Copy(subname);
       
   961 	TCFDiscoverRespMsg respMsg(aMessage.Identifier(), 1, EFalse);
       
   962 	VERIFY_RESULT(Send(respMsg), KErrNone);
       
   963 	}
       
   964 
       
   965 /** 
       
   966 This will be called by the handler when a Bind message have been received from 
       
   967 the Root Server. Delegating the call to the Worker Thread.
       
   968 */
       
   969 void CCommChannelHandler::CFMessageBind(const TCFBindMsg& aMessage)
       
   970 	{
       
   971 	iWorkerThread->CFBindMessageReceived(aMessage);
       
   972 	}
       
   973 
       
   974 /**
       
   975 This will be called by the handler when a Unbind message have has received from
       
   976 the Root Server. Delegating the call to the Worker Thread.
       
   977 */
       
   978 void CCommChannelHandler::CFMessageUnbind(const TCFUnbindMsg& aMessage)
       
   979 	{
       
   980 	iWorkerThread->CFUnbindMessageReceived(aMessage);
       
   981 	}
       
   982 
       
   983