datacommsserver/esockserver/ssock/ss_thread.cpp
changeset 0 dfb7c4ff071f
child 1 21d2ab05f085
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 <ss_std.h>
       
    22 #include <ss_glob.h>
       
    23 #include <comms-infras/ss_roles.h>
       
    24 #include "ss_msgs.h"
       
    25 #include <es_ini.h>
       
    26 #include <comms-infras/ss_log.h>
       
    27 #include <ecom/ecom.h>
       
    28 #include <ss_protprov.h>
       
    29 #include <comms-infras/idquerynetmsg.h> //just to get Uids
       
    30 #include <comms-infras/ss_tiermanagerutils.h>
       
    31 #include <metadatabase.h> //CMDBSession
       
    32 #include <elements/cftransportmsg.h>
       
    33 #include <elements/nm_address_internal.h>
       
    34 #include <elements/sd_msgs.h>
       
    35 #include "sd_rootserverchannelhandler.h"
       
    36 #include "ss_connectionserver.h"
       
    37 #include <comms-infras/ss_common.h>
       
    38 #include <comms-infras/ss_tiermanager.h>
       
    39 #include <cfforwardmsg.h>
       
    40 #include "ss_tierthreadmap.h"
       
    41 
       
    42 
       
    43 #ifdef _DEBUG
       
    44 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
       
    45 // (if it could happen through user error then you should give it an explicit, documented, category + code)
       
    46 _LIT(KSpecAssert_ESockSSocks_thrd, "ESockSSocks_thrd");
       
    47 #endif
       
    48 
       
    49 using namespace CommsFW;
       
    50 using namespace ESock;
       
    51 using namespace Messages;
       
    52 using namespace Den;
       
    53 
       
    54 //
       
    55 // CWorkerThread class definitions
       
    56 //
       
    57 
       
    58 
       
    59 CWorkerThread* CWorkerThread::NewL(TCFModuleInfo* aModuleInfo)
       
    60 	{
       
    61 	CleanupStack::PushL(TCleanupItem(CCommonWorkerThread::DeleteHBufC8, aModuleInfo->iIniData));
       
    62 	CWorkerThread* self = new (ELeave) CWorkerThread;
       
    63 	CleanupStack::PushL(self);
       
    64 	self->ConstructL(aModuleInfo);
       
    65 	CleanupStack::Pop(self);
       
    66 	CleanupStack::PopAndDestroy();	// aModuleInfo->iIniData
       
    67 	return self;
       
    68 	}
       
    69 
       
    70 CWorkerThread::CWorkerThread()
       
    71 :	CCommonWorkerThread(),
       
    72 	iEskMaskList(KEskMaskListGranularity)
       
    73 	{
       
    74 	}
       
    75 
       
    76 CWorkerThread::~CWorkerThread()
       
    77 	{
       
    78 	iTransportUsers.Shutdown(EFalse);
       
    79 	iEskMaskList.Close();
       
    80 	}
       
    81 
       
    82 CPlayer* CWorkerThread::Player() const
       
    83 	{
       
    84 	return static_cast<CPlayer*>(CCommonWorkerThread::Player());
       
    85 	}
       
    86 
       
    87 CPitBoss& CWorkerThread::PitBoss() const
       
    88 	{
       
    89 	return static_cast<CPitBoss&>(CCommonWorkerThread::PitBoss());
       
    90 	}
       
    91 
       
    92 /**
       
    93 The worker thread secondary construction will create the relevant Player/Dealer
       
    94 instances needed as well as the channel handler to the Root Server. If and only if it
       
    95 is the main thread it will also create the PitBoss.
       
    96 @note If it has a Dealer and is not the main thread it is a WorkerDealer.
       
    97 */
       
    98 TInt SocketServerShutDownCb(TAny*)
       
    99 	{
       
   100 	SocketServer::ShutDown();
       
   101 	return KErrNone;
       
   102 	}
       
   103 
       
   104 void CWorkerThread::ConstructL(TCFModuleInfo* aModuleInfo)
       
   105 	{
       
   106 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ConstructL Determining roles")));
       
   107 	CCommonWorkerThread::ConstructL(*aModuleInfo, *Den::CShutdownWatchDog::NewL(this, TCallBack(SocketServerShutDownCb, NULL)));
       
   108 
       
   109 #ifdef ESOCK_HOME_THREAD_CHECK_ENABLED
       
   110 	iOwnThread = RThread().Id();
       
   111 #endif
       
   112 
       
   113 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ConstructL Init SockManGlobals")));
       
   114 	iSockManGlobals = CSockManData::NewL(*iGlobals, this);
       
   115 
       
   116 	SocketServer::InitL(this);
       
   117 
       
   118 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ConstructL Init ProtocolManager")));
       
   119 	ProtocolManager::InitL();
       
   120 
       
   121 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ConstructL Done Init ProtocolManager")));
       
   122 
       
   123 	if(iPlayer)
       
   124 		{
       
   125 		SockManGlobals()->InstallFactoryContainersL();
       
   126 		}
       
   127 
       
   128 	LOG(ESockLog::Printf(_L("CWorkerThread::ConstructL Done")));
       
   129 	}
       
   130 
       
   131 /** Will read the .ESK masks from the inidata, to determine which .ESK files to load. */
       
   132 void CWorkerThread::DoDeterminePlayerRoleL(HBufC8* aIniData, Den::TPlayerRole& aPlayerRole)
       
   133 	{
       
   134 	_LIT8(KEskMaskLabel, "EskMask");
       
   135 	_LIT8(KEskMaskLabelNumFormat, "EskMask%d");
       
   136 	_LIT8(KPlayerRoleLabel, "PlayerRole");
       
   137 
       
   138 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::DetermineRoleL building .ESK mask list.")));
       
   139 	TPtrC8 currentEskMaskPtr;
       
   140 	TBuf8<KEskMaskLabelLength> currentEskMask;
       
   141 	currentEskMask.Format(KEskMaskLabel);
       
   142 	TEskMask currentMaskEntry;
       
   143 	TInt i=0;
       
   144 	do
       
   145 		{
       
   146 		if(GetVarFromIniData(*aIniData, KNullDesC8, currentEskMask, currentEskMaskPtr))
       
   147 			{
       
   148 			LOG(ESockLog::Printf(KESockBootingTag, _L8("Found EskMask under heading [IniData]: %S"), &currentEskMaskPtr));
       
   149 			// Sanity check length
       
   150 			if(currentEskMaskPtr.Length()>KMaxEskMaskLength)
       
   151 				{
       
   152 				LOG(ESockLog::Printf(KESockBootingTag, _L8("EskMask%d under heading [IniData] contains value of more than %d characters"), i, KMaxEskMaskLength));
       
   153 #ifdef _DEBUG
       
   154 				Panic(ECorruptIniData);
       
   155 #endif
       
   156 				// leave if ini data corrup rather than panic unless debug
       
   157 				User::Leave(KErrCorrupt);
       
   158 				}
       
   159 			// Add entry to list of EskMasks
       
   160 			currentMaskEntry.Copy(currentEskMaskPtr);
       
   161 			iEskMaskList.AppendL(currentMaskEntry);
       
   162 			}
       
   163 		else
       
   164 			{
       
   165 			/* If first iteration and nothing found in "EskMask" it is a critical error.
       
   166 			For EskMask0..max it is merely cause for breaking the loop */
       
   167 			if(i==0)
       
   168 				{
       
   169 				LOG(ESockLog::Printf(KESockBootingTag, _L("EskMask under heading [IniData] not found")));
       
   170 				// leave if ini data corruprather than panic unless debug
       
   171 #ifdef _DEBUG
       
   172 				Panic(ECorruptIniData);
       
   173 #endif
       
   174 				User::Leave(KErrCorrupt);
       
   175 				}
       
   176 			else
       
   177 				{
       
   178 				/* Break out of loop, if we didnt find EskMask<n> no reason to waste
       
   179 				time searching for EskMask<n+1> */
       
   180 				LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::DetermineRoleL No more ESK masks found.")));
       
   181 				break;
       
   182 				}
       
   183 			}
       
   184 		// Getting ready for next one
       
   185 		++i;
       
   186 		currentEskMask.Format(KEskMaskLabelNumFormat, i);
       
   187 		}
       
   188 	while(i<KEskMaskLabelMax);
       
   189 
       
   190 	TInt playerRole = (iWorkerId == TCFWorkerThreadPublicInfo::EIpPlayerThread)?		// defaults for legacy configurations
       
   191 		(TCFPlayerRole::EDataPlane | TCFPlayerRole::ESubConnPlane | TCFPlayerRole::EConnPlane | TCFPlayerRole::EMetaConnPlane | TCFPlayerRole::ETierMgrPlane | TCFPlayerRole::ETierResolver | TCFPlayerRole::EPrePlanarArchitecture):
       
   192 		(TCFPlayerRole::EDataPlane | TCFPlayerRole::ESubConnPlane | TCFPlayerRole::EConnPlane | TCFPlayerRole::EMetaConnPlane | TCFPlayerRole::ETierMgrPlane | TCFPlayerRole::EPrePlanarArchitecture);
       
   193 	if(GetVarFromIniData(*aIniData, KNullDesC8, KPlayerRoleLabel, playerRole))
       
   194 		{
       
   195 		if((playerRole != 0) &&
       
   196 			((playerRole & ~(TCFPlayerRole::EDataPlane | TCFPlayerRole::ESubConnPlane | TCFPlayerRole::EConnPlane | TCFPlayerRole::EMetaConnPlane | TCFPlayerRole::ETierMgrPlane | TCFPlayerRole::ETierResolver)) == 0))	// no unknown flags
       
   197 			{
       
   198 			}
       
   199 		else
       
   200 			{
       
   201 			LOG(ESockLog::Printf(KESockBootingTag, _L("PlayerType=%04x - unsupported type (must be OR of TPlayerRole flags or unspecified for legacy"), playerRole));
       
   202 #ifdef _DEBUG
       
   203 			Panic(ECorruptIniData);
       
   204 #endif
       
   205 			// leave if ini data corrupt rather than panic if not debug
       
   206 			User::Leave(KErrCorrupt);
       
   207 			}
       
   208 		}
       
   209 	aPlayerRole = TCFPlayerRole(playerRole, aPlayerRole.Kindex());
       
   210 	}
       
   211 
       
   212 CCommonPitBoss* CWorkerThread::DoCreatePitBossL(CCommonWorkerThread* aWorkerThread)
       
   213 	{
       
   214 	return CPitBoss::NewL(static_cast<CWorkerThread*>(aWorkerThread));
       
   215 	}
       
   216 
       
   217 CCommonPlayer* CWorkerThread::DoCreatePlayerL(CCommonWorkerThread* aWorkerThread,TPlayerRole aPlayerRole)
       
   218 	{
       
   219 	CPlayer* player = CPlayer::NewL(static_cast<CWorkerThread*>(aWorkerThread),aPlayerRole);
       
   220 //	CleanupStack::PushL(player);
       
   221 //	CleanupStack::Pop(player);
       
   222 	return player;
       
   223 	}
       
   224 
       
   225 CCommonDealer* CWorkerThread::DoCreateDealerL(CCommonWorkerThread* aWorkerThread, Den::TPlayerRole aPlayerRole)
       
   226 	{
       
   227 	CCommonDealer* dealer = NULL;
       
   228 	if (aPlayerRole.HasRole(TCFPlayerRole::ETierResolver))
       
   229 		{
       
   230 		CConnectionServer* cs = CConnectionServer::NewL(static_cast<CWorkerThread*>(aWorkerThread));
       
   231 		CleanupStack::PushL(cs);
       
   232 		dealer = CCommonDealer::NewL(cs);
       
   233 		CleanupStack::Pop(cs);
       
   234 		cs->SetDealer(dealer);
       
   235 		}
       
   236 	else
       
   237 		{
       
   238 		CSocketServer* ss = CSocketServer::NewL(static_cast<CWorkerThread*>(aWorkerThread));
       
   239 		CleanupStack::PushL(ss);
       
   240 
       
   241 		if (IsMainThread())
       
   242 			{
       
   243 			dealer = CCommonDealer::NewL(ss);
       
   244 			}
       
   245 		else
       
   246 			{
       
   247 			dealer = CCommonWorkerDealer::NewL(ss);
       
   248 			}
       
   249 		CleanupStack::Pop(ss);
       
   250 		ss->SetDealer(dealer);
       
   251 		}
       
   252 	return dealer;
       
   253 	}
       
   254 
       
   255 /**
       
   256 Takes the total list of .ESK files and generates a new local list containing only the file names
       
   257 matching the .ESK list for this worker. Then creates a new ini data instance with the local list to be
       
   258 used by the protocol manager for initialisation.
       
   259 @see CESockIniData
       
   260 */
       
   261 void CWorkerThread::ProcessMatchingEskFilesL(const COwnEntryList* aEskFiles)
       
   262 	{
       
   263 	LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ProcessMatchingEskFilesL: %d files"), aEskFiles->Count()));
       
   264 	TInt i;
       
   265 	for(i=0;i<iEskMaskList.Count();i++)
       
   266 		{
       
   267 		LOG(ESockLog::Printf(KESockBootingTag, _L("CWorkerThread::ProcessMatchingEskFilesL: mask %S"), &iEskMaskList[i]));
       
   268 		}
       
   269 
       
   270 	// The Gordian Knot of global data remains only half slashed... Also future work may eliminate the sharing of iEskData
       
   271 	// through this, rather than PitBoss()?
       
   272 	CESockIniData** iniData = &SockManGlobals::Get()->iEskData;
       
   273 	delete *iniData;
       
   274 	*iniData = NULL;
       
   275 	// Build a private, filtered copy of the total set of ESK files
       
   276 	CommsFW::COwnEntryList* ownEskFiles = new(ELeave) COwnEntryList(6);
       
   277 	CleanupStack::PushL(ownEskFiles);
       
   278 
       
   279 	TParse parsed;
       
   280 	const TInt cnt = aEskFiles->Count();
       
   281 	for(i = 0; i < cnt; ++i)
       
   282 		{
       
   283 		const COwnEntryList::TOwnEntry& entry = aEskFiles->operator[](i);
       
   284 		parsed.Set(entry.iName, NULL, NULL);
       
   285 		TPtrC nameAndExt = parsed.NameAndExt();
       
   286 		for(TInt j=0; j<iEskMaskList.Count(); ++j)
       
   287 			{
       
   288 			if(nameAndExt.MatchF(iEskMaskList[j]) >= 0)
       
   289 				{
       
   290 				LOG(ESockLog::Printf(KESockBootingTag, _L("- matched %S"), &entry.iName));
       
   291 				ownEskFiles->AddL(entry);
       
   292 				break; // Stop inner loop
       
   293 				}
       
   294 			}
       
   295 		}
       
   296 	iEskMaskList.Close();
       
   297 	LOG(ESockLog::Printf(KESockBootingTag, _L8("CWorkerThread::ProcessMatchingEskFilesL: %d files matched"), ownEskFiles->Count()));
       
   298 	if(ownEskFiles->Count() == 0 && (!iPlayer || static_cast<CPlayer*>(iPlayer)->HasDataPlane()))
       
   299 		{
       
   300 		// Threads with data planes must have one or more matching ESK files (otherwise
       
   301 		// they have no function and surely result from configuration errors)
       
   302 		User::Leave(KErrCorrupt);
       
   303 		}
       
   304 	// The ini data processing lives in the global protocol manager, for legacy reasons
       
   305 	*iniData = CESockIniData::NewL(ownEskFiles);
       
   306 
       
   307 	CleanupStack::Pop(ownEskFiles);
       
   308 	delete ownEskFiles;
       
   309 	if (iPlayer)
       
   310 		{
       
   311 		if(static_cast<CPlayer*>(iPlayer)->HasDataPlane())
       
   312 			{
       
   313 			ProtocolManager::ProcessIniDataL();
       
   314 			}
       
   315 		}
       
   316 	}
       
   317 
       
   318 void CWorkerThread::DoProcessWorkerIntroductionL(const TWorkerIntroductionMsg& aMsg)
       
   319 	{
       
   320 	TBuf8<TWorkerIntroductionMsg::KMaxIntroductionInfoSize> eskFilesList;
       
   321 	aMsg.IntroductionInfo(eskFilesList);
       
   322 	CommsFW::COwnEntryList* const* eskFiles = reinterpret_cast<CommsFW::COwnEntryList* const*>(eskFilesList.Ptr());
       
   323 	TRAPD(ret, ProcessMatchingEskFilesL(*eskFiles));
       
   324 
       
   325 	if (ret != KErrNone)
       
   326 		{
       
   327 		LOG(ESockLog::Printf(KESockBootingTag, _L("ERROR %d processing Esk files"), ret));
       
   328 	#ifdef _DEBUG
       
   329 		RDebug::Printf("CWorkerThread::DoProcessWorkerIntroductionL ERROR %d processing Esk files", ret);
       
   330 		Panic(EMisconfigured);
       
   331 	#endif
       
   332 		// Leave if problem with EskFiles instead of panic unless debug
       
   333 		User::Leave(KErrCorrupt);
       
   334 		}
       
   335 	}
       
   336 
       
   337 void CWorkerThread::DoFillIntroMessage(TWorkerId /*aPeerId*/, TWorkerIntroductionMsg& aIntroMsg)
       
   338 	{
       
   339 	if(IsMainThread())
       
   340 		{
       
   341 		const CommsFW::COwnEntryList* eskList = PitBoss().GetCompleteList();
       
   342 		TPtrC8 ptr((TUint8*)&eskList, sizeof(TAny*)); //Yes, pointer to pointer
       
   343 		aIntroMsg.SetIntroductionInfo(ptr);
       
   344 		}
       
   345 	else
       
   346 		{
       
   347 		TPckg<TBool> defaultOptDealer(DefaultOptimalDealer());
       
   348 		aIntroMsg.SetIntroductionInfo(defaultOptDealer);
       
   349 	}
       
   350 	}
       
   351 
       
   352 /**
       
   353 Deals with binding requests from the Root Server. Note that although the Root Server allows
       
   354 multiple identical bindings ESock does not allow this and will panic if the binding already exists.
       
   355 Bindings are expressed in ESock by worker transport objects stored in an array. Since all sub-module
       
   356 names are unique across all ESock instances (they are the individual owning worker ID converted to text)
       
   357 they can be used here. I.e. the remote end sub-module is converted back to int and used to insert the
       
   358 CWorkerTransport into an array in the position corresponding to the remote end sub-module name/number.
       
   359 As for responding to the bind request there are two cases:
       
   360     -# This worker is a "peer Player: Immediately introduce ourselves, including cookies
       
   361 	-# This worker is the Main thread: Wait to receive its introduction message, which carries the ESK file list.
       
   362 @see CWorkerTransport
       
   363 */
       
   364 void CWorkerThread::CFBindMessageReceived(const TCFBindMsg& aMsg)
       
   365 	{
       
   366     __CFLOG_SMADDR2(( KESockComponentTag, KESockServerTag, _L8("W%d: CFBindMessageReceived %S <=> %S"),
       
   367 		WorkerId(),
       
   368 		&aMsg.SubModule1()->Printable(__FullModName1),
       
   369 		&aMsg.SubModule2()->Printable(__FullModName2) ));
       
   370 	TWorkerId bindId;
       
   371 	TInt err = DecodePeerId(aMsg.SubModule1(), aMsg.SubModule2(), bindId);
       
   372 	__ASSERT_DEBUG(bindId <=  TWorkerThreadPublicInfo::EMaxWorkerThreadId, User::Panic(KSpecAssert_ESockSSocks_thrd, 1));
       
   373 	if(err == KErrNone)
       
   374 		{
       
   375 		if(iTransport->PeerReachable(bindId))
       
   376 			{
       
   377 			LOG(ESockLog::Printf(_L8("%d Already exists. Error in configuration of cmi files"),bindId));
       
   378 			Panic(EDuplicateWorkerId); //Must panic b/c the new module will be left in a half bound state and will tend to get out of hand
       
   379 			}
       
   380 		else
       
   381 			{
       
   382 			err = iTransport->EstablishTransportToPeer(bindId, aMsg.ChannelInput(), aMsg.ChannelOutput());
       
   383 			if(err == KErrNone)
       
   384 				{
       
   385 				iTransport->SetLastRequestIdConcerningPeer(bindId, aMsg.Identifier());
       
   386 
       
   387 				// If we're binding to the main thread then wait for its intro, with the all-important ESK file list
       
   388 				if(bindId != TWorkerThreadPublicInfo::EMainThread)
       
   389 					{
       
   390 					SendIntroMessage(aMsg.SubModule2()->Module(), bindId);
       
   391 
       
   392 					// If we have a player then follow up with a bucket of our own cookies (always a good way to make friends
       
   393 					// with the new neighbour...). Only "planar architecture" configurations share their cookies; this allows
       
   394 					// bindings between legacy threads for purposes of Dealer -> Player forwarding only.
       
   395 					// @TODO - either we stop forwarding from optimal Dealers to Players or we have to add of indicating which
       
   396 					// bindings are for sharing planes and which are for simply forwarding requests. Probably we should do the
       
   397 					// former - if someone asks for "optimal IP data" then why should they be able to send SMS from that session?
       
   398 					Messages::TNodeId dataFC;
       
   399 					Messages::TNodeId subConnFC;
       
   400 					Messages::TNodeId connFC;
       
   401 					Messages::TNodeId metaConnFC;
       
   402 					Messages::TNodeId tierManagerFC;
       
   403 					if(Player())
       
   404 						{
       
   405 						const TPlayerRole& role = Player()->PlayerRole();
       
   406 						if(!role.HasRole(TCFPlayerRole::EPrePlanarArchitecture))
       
   407 							{
       
   408 							// It's safe to simply copy the cookies we know of here - we cannot yet have learnt of any others so they must be ours
       
   409 							CSockManData* globs = Player()->SockManGlobals();
       
   410 							if(role.HasRole(TCFPlayerRole::EDataPlane))
       
   411 								{
       
   412 								dataFC = globs->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane));
       
   413 								}
       
   414 							if(role.HasRole(TCFPlayerRole::ESubConnPlane))
       
   415 								{
       
   416 								subConnFC = globs->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ESubConnPlane));
       
   417 								}
       
   418 							if(role.HasRole(TCFPlayerRole::EConnPlane))
       
   419 								{
       
   420 								connFC = globs->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EConnPlane));
       
   421 								}
       
   422 							if(role.HasRole(TCFPlayerRole::EMetaConnPlane))
       
   423 								{
       
   424 								metaConnFC = globs->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EMetaConnPlane));
       
   425 								}
       
   426 							if(role.HasRole(TCFPlayerRole::ETierMgrPlane))
       
   427 								{
       
   428 								tierManagerFC = globs->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane));
       
   429 								}
       
   430 							}
       
   431 						}
       
   432 
       
   433                     NM_LOG_START_BLOCK(KESockComponentTag, _L8("PeerIntro"));
       
   434                     NM_LOG((KESockComponentTag, _L8("CFBindMessageReceived(): Sending Cookies to peer #%d "), bindId));
       
   435                     NM_LOG_ADDRESS_EXT(KESockComponentTag, dataFC, _L8("dataFC: "));
       
   436                     NM_LOG_ADDRESS_EXT(KESockComponentTag, subConnFC, _L8("scFC: "));
       
   437                     NM_LOG_ADDRESS_EXT(KESockComponentTag, connFC, _L8("cnFC: "));
       
   438                     NM_LOG_ADDRESS_EXT(KESockComponentTag, metaConnFC, _L8("mcFC: "));
       
   439                     NM_LOG_ADDRESS_EXT(KESockComponentTag, tierManagerFC, _L8("tmFC: "));
       
   440 				    NM_LOG_END_BLOCK(KESockComponentTag, _L8("PeerIntro"));
       
   441 					TWorkerCookiesMsg cookieMsg(dataFC, subConnFC, connFC, metaConnFC, tierManagerFC);
       
   442 					PostMessage(bindId, cookieMsg);
       
   443 
       
   444 					if(!IsMainThread())
       
   445 						{
       
   446 						if(Player()->HasConnPlane())
       
   447 							{
       
   448 							SendObjectBrokerIntroductionMessage(bindId);
       
   449 							}
       
   450 						}
       
   451 					}
       
   452 				}
       
   453 			}
       
   454 		}
       
   455 	/* Main dealer only completes when it has received the introduction response messages from peers,
       
   456 	dumb players respond immediately. */
       
   457 	if(err!=KErrNone || !IsMainThread())
       
   458 		{
       
   459 		TCFBindCompleteMsg respMsg(aMsg.Identifier(), err);
       
   460 		VERIFY_RESULT(iChannelHandler->Send(respMsg), KErrNone);
       
   461 		}
       
   462 	}
       
   463 
       
   464 
       
   465 void CWorkerThread::SendObjectBrokerIntroductionMessage(const CommsFW::TWorkerId& aPeerId)
       
   466 	{
       
   467 	// Share our central object broker node with a worker
       
   468 	__ASSERT_DEBUG(Player(), User::Panic(KSpecAssert_ESockSSocks_thrd, 2));
       
   469 	__ASSERT_DEBUG(Player()->HasConnPlane(), User::Panic(KSpecAssert_ESockSSocks_thrd, 3));
       
   470 	TBrokerIntroductionMsg brokerIntroMsg(SockManGlobals()->iCommsFactoryContainerBroker);
       
   471 	PostMessage(aPeerId, brokerIntroMsg);
       
   472 	}
       
   473 
       
   474 void CWorkerThread::DoCompleteUnbinding(CommsFW::TWorkerId aWorker)
       
   475 	{
       
   476 	TCFPlayerRole ourRole(TCFPlayerRole::EAllPlanes | TCFPlayerRole::ETierResolver);
       
   477 	TPlaneUnboundMsg unboundMsg(ourRole);
       
   478 	PostMessage(aWorker, unboundMsg);
       
   479 
       
   480 	CSockManData* globs = SockManGlobals();
       
   481 	globs->iFCMap.DropFCOfPeer(TCFPlayerRole(TCFPlayerRole::EAllPlanes), aWorker);
       
   482 
       
   483 	CommsFW::TCFUnbindCompleteMsg respMsg(iTransport->LastRequestIdConcerningPeer(aWorker), KErrNone);
       
   484 	iTransport->DropTransportToPeer(aWorker);
       
   485 	VERIFY_RESULT(iChannelHandler->Send(respMsg), KErrNone);
       
   486 	}
       
   487 
       
   488 /**
       
   489 It is possible for client applications outside of the Comms Process to send messages to
       
   490 an ESock Worker thread. This is done through the Root Server SendMessage method.
       
   491 The message is received by the destination ESock Worker in the CFMessageForward member,
       
   492 which will deal with it accordingly.
       
   493 Supported message type is TCFMessageType::EFactoryMsg destined for one or more
       
   494 CProtocolFamilyFactoryBase instances from globals->iProtocolFamilyFactories. ESock will
       
   495 traverse through this list and deliver (by calling SendMessage()) the message content to
       
   496 every instance present there.
       
   497 The message content for such a message sent to an ESock Worker is required to be based on
       
   498 the CNetMessage class.
       
   499 @note Completion of the client request the responsibility of the recipient.
       
   500 @see RRootServ::SendMessage
       
   501 */
       
   502 void CWorkerThread::CFMessageForward(const CommsFW::TCFForwardMsg& aMessage)
       
   503 	{
       
   504 	const RMessage2& msg = aMessage.Msg();
       
   505 	if ( !SockManGlobals::Get()->iProtocolFamilyFactories )
       
   506 		{
       
   507 		msg.Complete( KErrNotReady );
       
   508 		return;
       
   509 		}
       
   510 	TInt len = msg.GetDesLength(2);
       
   511 	SMetaDataECom* pInstance = NULL;
       
   512 
       
   513 	TInt nErr=KErrArgument;
       
   514 
       
   515 	TPtr8 pDataPtr(0,0);
       
   516 	RBuf8 buf;
       
   517 
       
   518 	if( len >= 0 )
       
   519 		{
       
   520 		nErr = buf.Create( len );
       
   521 		if ( nErr == KErrNone )
       
   522 			{
       
   523 			pDataPtr.Set( const_cast<TUint8*>(buf.Ptr()), 0, buf.MaxLength() );
       
   524 			nErr = msg.Read( 2, pDataPtr );
       
   525 			}
       
   526 		if ( nErr == KErrNone )
       
   527 			{
       
   528 			TPtrC8 ptr(pDataPtr);
       
   529 			TRAP
       
   530 				(nErr,
       
   531 				pInstance = SMetaDataECom::LoadL( ptr )
       
   532 				)
       
   533 			}
       
   534 		}
       
   535 
       
   536 	if ( nErr == KErrNone )
       
   537 		{
       
   538 		if ( !pInstance->IsTypeOf( STypeId::CreateSTypeId( NetMessages::KInterfaceUid, NetMessages::EMessageAny ) ) )
       
   539 			{
       
   540 			nErr = KErrArgument;
       
   541 			}
       
   542 		else
       
   543 			{
       
   544 			NetMessages::CMessage* pNetMessage = static_cast<NetMessages::CMessage*>(pInstance);
       
   545 			switch ( msg.Int1() )
       
   546 				{
       
   547 			case /*TCFMessageType::*/EFactoryMsg:
       
   548 				{
       
   549 				TInt nIndex = 0;
       
   550 				nErr = KErrNotSupported;
       
   551 				ESock::CProtocolFamilyFactoryBase* pFactory = SockManGlobals::Get()->iProtocolFamilyFactories->Get( nIndex++ );
       
   552 				while ( pFactory != NULL )
       
   553 					{
       
   554 					if ( (nErr = pFactory->SendMessage( *pNetMessage )) != KErrNotSupported )
       
   555 						{
       
   556 						break;
       
   557 						}
       
   558 					pFactory = SockManGlobals::Get()->iProtocolFamilyFactories->Get( nIndex++ );
       
   559 					}
       
   560 				pDataPtr.Zero();
       
   561 				if(nErr == KErrNone)
       
   562 					{
       
   563 					nErr = pNetMessage->Store( pDataPtr );
       
   564 					}
       
   565 				if ( nErr == KErrNone )
       
   566 					{
       
   567 					nErr = msg.Write( 2, pDataPtr );
       
   568 					}
       
   569 				break;
       
   570 				}
       
   571 			default:
       
   572 				nErr = KErrArgument;
       
   573 				break;
       
   574 				}
       
   575 			}
       
   576 		}
       
   577 	buf.Close();
       
   578 	delete pInstance;
       
   579 	msg.Complete( nErr );
       
   580 	}
       
   581 
       
   582 void CWorkerThread::MaybeIncorporateFCL(const TPlayerRole& aPlane, const Messages::TNodeId& aPeerId)
       
   583 	{
       
   584 	CSockManData* globals = SockManGlobals();
       
   585 
       
   586 	if(!aPeerId.IsNull())
       
   587 		{
       
   588 		TNodeId ourId(globals->GetPlaneFC(aPlane));
       
   589 		if(!ourId.IsNull() && Player() && !Player()->HasDataPlane())
       
   590 			{
       
   591 			// We're meeting a peer with a role that we either have or have already acquired. This is acceptable for a data plane being bound to multiple control
       
   592 			// planes since modern session flows will be associated a conn or subconn, but in other cases is an error because of the need for explicit resolution
       
   593 			// it presents (eg would become "the correction SubConn plane for Conn X" rather than simply "the SubConn plane bound to current Conn Plane"
       
   594 			LOG(ESockLog::Printf(KESockBootingTag, _L8("WARNING: Worker thread %d being bound also has FC for plane 0x%x"), aPeerId.Thread(), aPlane.Role()));
       
   595 
       
   596 #ifdef _DEBUG
       
   597             // If this stings you see DEF109193, and speak to ThomasG, BarryA, or PeterSau
       
   598             Panic(EAmbigiousRoles);
       
   599 #endif
       
   600 			// Leave if problem with config instead of panic unless debug
       
   601             User::Leave(KErrCorrupt);	// no benefit to specific error; unlikely to be visible in UREL (no logging, debugging)
       
   602             return;
       
   603 			}
       
   604 
       
   605 		// The addition may fail if we're a multiply-bound data thread, as described above. This is harmless
       
   606 		TInt err = globals->iFCMap.AddPlaneFC(aPlane, aPeerId);
       
   607 
       
   608 		// Add the factory to our central factory container object broker (if we are hosting it)
       
   609 		if(Player()->HasConnPlane() && (err == KErrNone))
       
   610 			{
       
   611 			// Must have installed our broker already
       
   612 			__ASSERT_DEBUG(globals->iCommsFactoryContainerBrokerSingleton, User::Panic(KSpecAssert_ESockSSocks_thrd, 4));
       
   613 
       
   614 			// Can only have one factory container from each unique player role (plane)
       
   615 			__ASSERT_DEBUG(0 == globals->iCommsFactoryContainerBrokerSingleton->CountClients<TDefaultClientMatchPolicy>(aPlane), User::Panic(KSpecAssert_ESockSSocks_thrd, 5));
       
   616 
       
   617 			// Add the factory container to our broker's list
       
   618 			globals->iCommsFactoryContainerBrokerSingleton->AddClientL(aPeerId, aPlane);
       
   619 			}
       
   620 		}
       
   621 	}
       
   622 
       
   623 
       
   624 /**
       
   625 Deal with incoming messages from other workers. If the message is not a known type it might
       
   626 be a generic transport message and an attempt to use a transporthandler ECOM plugin is made.
       
   627 */
       
   628 TBool CWorkerThread::DoDispatchL(const CommsFW::TCFMessage& aMessage, CommsFW::TWorkerId aSenderId)
       
   629 	{
       
   630 	switch(aMessage.Code())
       
   631 		{
       
   632 		case TWorkerMsg::EWorkerCookies:
       
   633 			{
       
   634 			LOG(ESockLog::Printf(_L("PeerWorkerMessageReceived(%d). EWorkerCookies"), aSenderId));
       
   635 			const TWorkerCookiesMsg& msg = reinterpret_cast<const TWorkerCookiesMsg&>(aMessage);
       
   636 
       
   637 			if(aSenderId != TWorkerThreadPublicInfo::EMainThread && !IsMainThread())
       
   638 				{
       
   639 				// Not the PitBoss meeting us - if we're not the PitBoss then it should be a peer Player with some cookies to share
       
   640 				// For any given plane the rules are:
       
   641 				//	(1) if our Player has that role itself then we simply ignore their cookie (if any)
       
   642 				//	(2) if our Player lacks the role but we've already bound to a peer which does then its a config error
       
   643 				// The rules are driven by the need to avoid ambiguity in the coupling of planes, a subconn doesn't need (or have)
       
   644 				// the ability to specify which SubConnflowFC will create a flow for it. So it's either its own thread (if it implements
       
   645 				// the role) or the one & only peer bound to it which implements this. We don't support ideas like "the first peer" because
       
   646 				// that depends upon the startup ordering of the RootServer and although that is well-defined and user controllable it seems
       
   647 				// likely to be seen as unhelpfully complex and a source of mysterious config errors (eg BT data thread being asked to
       
   648 				// create a UDP flow)
       
   649 				TUint32 localRole = Player()? Player()->PlayerRole().Role() : TCFPlayerRole::EUnknown;
       
   650 				if ((localRole & (TCFPlayerRole::EAllPlanes | TCFPlayerRole::ETierResolver)) != TCFPlayerRole::ETierResolver)
       
   651 					{
       
   652 					// This is presuming that the tier resolver is running in its own thread
       
   653 					// and should not learn the roles from peers
       
   654 					MaybeIncorporateFCL(TCFPlayerRole(TCFPlayerRole::EDataPlane), msg.DataPlaneFC());
       
   655 					MaybeIncorporateFCL(TCFPlayerRole(TCFPlayerRole::ESubConnPlane), msg.SubConnPlaneFC());
       
   656 					MaybeIncorporateFCL(TCFPlayerRole(TCFPlayerRole::EConnPlane), msg.ConnPlaneFC());
       
   657 					MaybeIncorporateFCL(TCFPlayerRole(TCFPlayerRole::EMetaConnPlane), msg.MetaConnPlaneFC());
       
   658 					}
       
   659 
       
   660 	            // For the benefit of the connection server the tier resolver is allowed
       
   661 	            // to learn about the tier managers.
       
   662 				MaybeIncorporateFCL(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane), msg.TierManagerFC());
       
   663 				}
       
   664 			break;
       
   665 			}
       
   666 
       
   667 		case TWorkerMsg::EBrokerIntroduction:
       
   668 			{
       
   669 			__ASSERT_DEBUG(Player(), User::Panic(KSpecAssert_ESockSSocks_thrd, 6));
       
   670 
       
   671 			// The tier resolver is virtually friends with everyone and so not a candidate for learning
       
   672 			// about a technology specific singleton like the object broker
       
   673 			if(!Player()->HasTierResolver() && !Player()->HasDataPlane())
       
   674 				{
       
   675 				CSockManData* globals = SockManGlobals();
       
   676 				const TBrokerIntroductionMsg& msg = reinterpret_cast<const TBrokerIntroductionMsg&>(aMessage);
       
   677 
       
   678 				// If we don't already have our own broker then accept the one being introduced
       
   679 				if(globals->iCommsFactoryContainerBroker == TNodeId::NullId())
       
   680 					{
       
   681 					globals->iCommsFactoryContainerBroker = msg.BrokerId();
       
   682 					}
       
   683 				}
       
   684 			break;
       
   685 			}
       
   686 
       
   687 		case TWorkerMsg::ELoadTierMappings:
       
   688 			{
       
   689 			if(IsMainThread())
       
   690 				{
       
   691 				static_cast<CPitBoss&>(PitBoss()).RequestLoadTierMapping();
       
   692 				}
       
   693 			else
       
   694 				{
       
   695 				__ASSERT_DEBUG(Player(), User::Panic(KSpecAssert_ESockSSocks_thrd, 7));
       
   696 				__ASSERT_DEBUG(static_cast<CPlayer*>(Player())->HasTierResolver(), User::Panic(KSpecAssert_ESockSSocks_thrd, 8));
       
   697 
       
   698 				RTierThreadMap* map = NULL;
       
   699                 TRAPD(err,
       
   700 				    CommsDat::CMDBSession* dbs = CommsDat::CMDBSession::NewLC(KCDVersion1_1);
       
   701                     map = TierManagerUtils::BuildTierThreadMappingL(*dbs);
       
   702                     CleanupStack::PopAndDestroy(dbs);
       
   703                     );
       
   704                 (void) err;
       
   705                 LOG(ESockLog::Printf(_L8("CWorkerThread:\tDoDispatch, ELoadTierMappings err=%d, %d mappings"), err, map? map->Count(): 0));
       
   706 
       
   707 				TWorkerTierMappingsLoaded respMsg(map);
       
   708 				PostMessage(aSenderId, respMsg);
       
   709 				}
       
   710 			break;
       
   711 			}
       
   712 
       
   713 		case TWorkerMsg::ETierMappingsLoaded:
       
   714 			{
       
   715 			__ASSERT_DEBUG(IsMainThread(), User::Panic(KSpecAssert_ESockSSocks_thrd, 9));
       
   716 			static_cast<CPitBoss&>(PitBoss()).OnTierMappingLoadedL(&reinterpret_cast<const TWorkerTierMappingsLoaded&>(aMessage), aSenderId);
       
   717 			break;
       
   718 			}
       
   719 		case TWorkerMsg::EPlaneUnbound:
       
   720 			{
       
   721 			const TPlaneUnboundMsg& msg(reinterpret_cast<const TPlaneUnboundMsg&>(aMessage));
       
   722 			LOG(ESockLog::Printf(_L("PeerWorkerMessageReceived(%d). EPlaneUnbound (planes=0x%04x)"), aSenderId, msg.PlayerRole().Role()));
       
   723 			CSockManData* globs = SockManGlobals();
       
   724 			globs->iFCMap.DropFCOfPeer(msg.PlayerRole(), aSenderId);
       
   725 	//		MaybeCompleteUnbinding(aSenderId);
       
   726 			MaybeTriggerThreadShutdownCallback();
       
   727 			break;
       
   728 			}
       
   729 		LOG( //This "case" is only for logging, it is properly forwarded in the CCommonWorkerThread
       
   730 		case TPlayerMsg::EForwardRequest:
       
   731 			{
       
   732 			TPlayerForwardRequestMsg fwdReqMsg(reinterpret_cast<const TPlayerForwardRequestMsg&>(aMessage));
       
   733 			TBuf8<64> messBuf;
       
   734 			ESockLog::IPCMessName((TSockMess) fwdReqMsg.SafeMessage().Function(), messBuf);
       
   735 			ESockLog::Printf(KESockSessDetailTag, _L8("PeerWorkerMessageReceived(%d). EForwardRequest(%S)"), aSenderId, &messBuf);
       
   736 			break;
       
   737 			}
       
   738 		);
       
   739 		default:
       
   740 			{
       
   741 			// If it isn't an internal message then it should be a TWorkerTransportMsg for a plugin
       
   742 			const TWorkerTransportMsg& msg = reinterpret_cast<const TWorkerTransportMsg&>(aMessage);
       
   743 			const RThread& peerThread = PitBoss().RThreadRef(aSenderId);
       
   744 			TRequestWrapper request(msg.Status(), EFalse);
       
   745 			request.SetPeerThread(peerThread);
       
   746 			TransportMessageReceived(msg, request, aSenderId);
       
   747 			}
       
   748 		}
       
   749 
       
   750 	return ETrue; //We always process the message (TransportMessageReceived() may panic if not recognised)
       
   751 	}
       
   752 
       
   753 /**
       
   754 This override ensures we do not check an ECNCreate message to see if the subsession is orphaned - the subsession
       
   755 pointer is reused to hold a tier ID rather than a pointer.
       
   756 @see CPlayer::ProcessMessageL
       
   757 */
       
   758 void CWorkerThread::OnDispatchLeave(const CommsFW::TCFMessage& aMessage, CommsFW::TWorkerId aSenderId, TInt aError)
       
   759 	{
       
   760 	__ASSERT_DEBUG(aError!=KErrNone, User::Panic(KSpecAssert_ESockSSocks_thrd, 10));
       
   761 	switch(aMessage.Code())
       
   762 		{
       
   763         case TPlayerMsg::EForwardRequest:
       
   764             {
       
   765             if(aError != KErrBadDescriptor)
       
   766                 {
       
   767                 TPlayerForwardRequestMsg fwdReqMsg(reinterpret_cast<const TPlayerForwardRequestMsg&>(aMessage));
       
   768                 // Should we also test Message().IsNull(). Should be no aliasing of it now?
       
   769                 LOG(ESockLog::Printf(_L8("CWorkerThread:\tOnDispatchLeave, Complete message(%08x) with %d."), fwdReqMsg.SafeMessage().Handle(), aError));
       
   770                 __ASSERT_DEBUG(Player(), User::Panic(KSpecAssert_ESockSSocks_thrd, 11));
       
   771                 if (Player()->ShouldCompleteCurrentRequest())
       
   772                     {
       
   773                     fwdReqMsg.SafeMessage().Complete(aError);
       
   774                     }
       
   775                 }
       
   776             }
       
   777             break;
       
   778 
       
   779         default:
       
   780             CCommonWorkerThread::OnDispatchLeave(aMessage, aSenderId, aError);
       
   781 		}
       
   782 	}
       
   783 
       
   784 /**
       
   785 Attempt to locate and create a new transportuser (using ECOM).
       
   786 @leave KErrNotFound
       
   787 @leave KErrNoMemory
       
   788 */
       
   789 void CWorkerThread::CreateTransportUserL(TTransportUser& aTemplateUser)
       
   790 	{
       
   791 	aTemplateUser.iUserStorage = new(ELeave) TTransportUserStorage;
       
   792 	TTransportReceiverFactoryArgs factoryArgs(aTemplateUser.iUserStorage, WorkerId());
       
   793 	aTemplateUser.iUser = reinterpret_cast<CWorkerTransportReceiver*>(REComSession::CreateImplementationL(TUid::Uid(aTemplateUser.iInterfaceId), aTemplateUser.iDtorId, &factoryArgs));
       
   794 	TInt ret = iTransportUsers.InsertInOrder(aTemplateUser, TLinearOrder<TTransportUser>(TTransportUser::Compare));
       
   795 	if(ret != KErrNone)
       
   796 		{
       
   797 		REComSession::DestroyedImplementation(aTemplateUser.iDtorId);
       
   798 		delete aTemplateUser.iUser;
       
   799 		User::Leave(ret);
       
   800 		}
       
   801 	}
       
   802 
       
   803 /**
       
   804 Given a transport message try to look up its code in the list of loaded ECOM plugins. If this doesnt
       
   805 work ask ECOM whether it has any plugins supporting this interface ID.
       
   806 */
       
   807 TInt CWorkerThread::TransportMessageReceived(const TWorkerTransportMsg& aMessage, TRequestWrapper& aRequestWrapper, TWorkerId aWorkerId)
       
   808 	{
       
   809 	// A message other than the private ESOCKSVR ones was received. Its id should be that of a plugin which will process it
       
   810 	TTransportUser user;
       
   811 	user.iInterfaceId = aMessage.Code();
       
   812 	TInt ret = iTransportUsers.FindInOrder(user, TLinearOrder<TTransportUser>(TTransportUser::Compare));
       
   813 	if(ret == KErrNotFound)
       
   814 		{
       
   815 		TRAP(ret, CreateTransportUserL(user));
       
   816 		if(ret == KErrNone)
       
   817 			{
       
   818 			user.iUser->ProcessMessage(aMessage, aRequestWrapper, *user.iUserStorage, aWorkerId);
       
   819 			}
       
   820 		else
       
   821 			{
       
   822 			delete user.iUserStorage;
       
   823 			if(ret != KErrNoMemory)
       
   824 				{
       
   825 				// Message was neither an internal one nor a loadable plugin. Asserting is helpful here
       
   826 				LOG(ESockLog::Printf(_L("UNKNOWN: Transport message #%d (#%08x)"), aMessage.Code(), aMessage.Code()));
       
   827 				__ASSERT_DEBUG(0, User::Panic(KSpecAssert_ESockSSocks_thrd, 12));
       
   828 				}
       
   829 			aRequestWrapper.RequestComplete(ret);
       
   830 			}
       
   831 		}
       
   832 	else
       
   833 		{
       
   834 		const TTransportUser& refUser = iTransportUsers[ret];
       
   835 		refUser.iUser->ProcessMessage(aMessage, aRequestWrapper, *refUser.iUserStorage, aWorkerId);
       
   836 		}
       
   837 	return ret;
       
   838 	}
       
   839 
       
   840 
       
   841 void CWorkerThread::DoPostMortemCleanup()
       
   842 	{
       
   843 	// First cleanup any transport users - these are more important than clients since they
       
   844 	// may have peer threads blocked on them
       
   845 	iTransportUsers.Shutdown(ETrue);
       
   846 	}
       
   847 
       
   848 void CWorkerThread::DoSetShuttingDown()
       
   849 	{
       
   850 	SockManGlobals::Get()->iShutdownGracefully = ETrue;
       
   851 	}
       
   852 
       
   853 /**
       
   854 Given address family and socket type will locate the sender object for the worker thread
       
   855 hosting the protocol. If it is the same worker as the current one, returns the self sender,
       
   856 which use direct calls instead of channels for processing messages, otherwise return the
       
   857 appropriate CWorkerTransport.
       
   858 Although an exported function it is only allowed to call it from the context of an ESock worker thread.
       
   859 It is mainly for use by plugins.
       
   860 @see CWorkerTransport
       
   861 @see TWorkerTransportSelfSender
       
   862 */
       
   863 EXPORT_C TInt CWorkerThread::CookieForProtocol(TUint aAddrFamily, TUint aSockType, TUint aProtocol, Messages::TRuntimeCtxId& aCookie)
       
   864 	{
       
   865 	CWorkerThread* selfWorker = SockManGlobals::Get()->SelfWorker();
       
   866 	__ASSERT_DEBUG(selfWorker, User::Panic(KSpecAssert_ESockSSocks_thrd, 13));	// calling this function from other than a ESOCK Worker thread cannot work
       
   867 	if(selfWorker)
       
   868 		{
       
   869 		TWorkerId workerId;
       
   870 		if(selfWorker->PitBoss().GetWorkerForProtocol(aAddrFamily, aSockType, aProtocol, workerId))
       
   871 			{
       
   872 			if(selfWorker->Transport()->PeerReachable(workerId))
       
   873 				{
       
   874 				Messages::TRuntimeCtxIdOp(aCookie).Set(0, workerId);
       
   875 				return KErrNone;
       
   876 				}
       
   877 			}
       
   878 		}
       
   879 	return KErrBadName;
       
   880 	}
       
   881 
       
   882 /**
       
   883 Given protocol name will locate the sender object for the worker thread
       
   884 hosting the protocol. If it is the same worker as the current one, returns the self sender,
       
   885 which use direct calls instead of channels for processing messages, otherwise return the
       
   886 appropriate CWorkerTransport.
       
   887 Although an exported function it is only allowed to call it from the context of an ESock worker thread.
       
   888 It is mainly for use by plugins.
       
   889 @see CWorkerTransport
       
   890 @see TWorkerTransportSelfSender
       
   891 */
       
   892 EXPORT_C TInt CWorkerThread::CookieForProtocolByName(const TProtocolName& aName, Messages::TRuntimeCtxId& aCookie)
       
   893 	{
       
   894 	CWorkerThread* selfWorker = SockManGlobals::Get()->SelfWorker();
       
   895 	__ASSERT_DEBUG(selfWorker, User::Panic(KSpecAssert_ESockSSocks_thrd, 14));	// calling this function from other than a ESOCK Worker thread cannot work
       
   896 	if(selfWorker)
       
   897 		{
       
   898 		TWorkerId workerId;
       
   899 		if(selfWorker->PitBoss().GetWorkerForProtocolByName(aName, workerId))
       
   900 			{
       
   901 			if(selfWorker->Transport()->PeerReachable(workerId))
       
   902 				{
       
   903 				Messages::TRuntimeCtxIdOp(aCookie).Set(0, workerId);
       
   904 				return KErrNone;
       
   905 				}
       
   906 			}
       
   907 		}
       
   908 	return KErrNotFound;
       
   909 	}
       
   910 
       
   911 /**
       
   912 Given Worker ID will locate the sender object for the worker thread
       
   913 hosting the protocol. If it is the same worker as the current one, returns the self sender,
       
   914 which use direct calls instead of channels for processing messages, otherwise return the
       
   915 appropriate CWorkerTransport.
       
   916 Although an exported function it is only allowed to call it from the context of an ESock worker thread.
       
   917 It is mainly for use by plugins.
       
   918 @see CWorkerTransport
       
   919 @see TWorkerTransportSelfSender
       
   920 */
       
   921 EXPORT_C TInt CWorkerThread::CookieForWorkerId(TWorkerId aWorkerId, Messages::TRuntimeCtxId& aCookie)
       
   922 	{
       
   923 	CWorkerThread* selfWorker = SockManGlobals::Get()->SelfWorker();
       
   924 	__ASSERT_DEBUG(selfWorker, User::Panic(KSpecAssert_ESockSSocks_thrd, 15));	// calling this function from other than a ESOCK Worker thread cannot work
       
   925 	if(selfWorker)
       
   926 		{
       
   927 		if(selfWorker->Transport()->PeerReachable(aWorkerId))
       
   928 			{
       
   929 			Messages::TRuntimeCtxIdOp(aCookie).Set(0, aWorkerId);
       
   930 			return KErrNone;
       
   931 			}
       
   932 		}
       
   933 	return KErrNotSupported;
       
   934 	}
       
   935 
       
   936 EXPORT_C TBool CWorkerThread::ResolveWorkerNameToId(const TDesC8& aWorkerName, TWorkerId& aWorkerId)
       
   937 	{
       
   938 	CSockManData* globs = SockManGlobals::Get();
       
   939 	__ASSERT_DEBUG(globs, User::Panic(KSpecAssert_ESockSSocks_thrd, 16));
       
   940 	return globs->SelfWorker()->PitBoss().ResolveWorkerNameToId(aWorkerName, aWorkerId);
       
   941 	}
       
   942 
       
   943 /**
       
   944 Use SockManGlobals in thread local storage (TLS) to retrieve WorkerID of the current worker thread.
       
   945 */
       
   946 EXPORT_C TInt CWorkerThread::CurrentWorkerId(TWorkerId& aWorkerId)
       
   947 	{
       
   948 	CWorkerThread* selfWorker = SockManGlobals::Get()->SelfWorker();
       
   949 	__ASSERT_DEBUG(selfWorker, User::Panic(KSpecAssert_ESockSSocks_thrd, 17));	// calling this function from other than a ESOCK Worker thread cannot work
       
   950 	if(selfWorker)
       
   951 		{
       
   952 		aWorkerId = selfWorker->WorkerId();
       
   953 		return KErrNone;
       
   954 		}
       
   955 	return KErrNotSupported;
       
   956 	}
       
   957 
       
   958 //
       
   959 // CWorkerThread::RTransportUsers
       
   960 //
       
   961 
       
   962 /** Notify all active transport user ECOM plugins of shutdown. */
       
   963 void CWorkerThread::RTransportUsers::Shutdown(TBool aAlreadyDead)
       
   964 	{
       
   965 	for(TInt idx = Count() - 1; idx >= 0; --idx)
       
   966 		{
       
   967 		TTransportUser& user = operator[](idx);
       
   968 		user.iUser->Shutdown(aAlreadyDead, *user.iUserStorage);
       
   969 		if(!aAlreadyDead)
       
   970 			{
       
   971 			REComSession::DestroyedImplementation(user.iDtorId);
       
   972 			delete user.iUser;
       
   973 			delete user.iUserStorage;
       
   974 			}
       
   975 		}
       
   976 	Close();
       
   977 	}
       
   978 
       
   979 /** Notify all active transport user ECOM plugins that a thread have died. */
       
   980 void CWorkerThread::RTransportUsers::NotifyPeerDeath(TWorkerId aPeer)
       
   981 	{
       
   982 	for(TInt idx = Count() - 1; idx >= 0; --idx)
       
   983 		{
       
   984 		TTransportUser& user = operator[](idx);
       
   985 		user.iUser->OnPeerDeath(aPeer, *user.iUserStorage);
       
   986 		}
       
   987 	}
       
   988 
       
   989 //
       
   990 // TRequestWrapper
       
   991 //
       
   992 
       
   993 EXPORT_C TRequestWrapper::TRequestWrapper()
       
   994 : iStatus(NULL),
       
   995   iPeerThread(NULL),
       
   996   iSyncLocalCall(EFalse)
       
   997 	{
       
   998 	}
       
   999 
       
  1000 EXPORT_C TRequestWrapper::TRequestWrapper(TRequestStatus& aStatus, TBool aSyncLocalCall)
       
  1001 : iStatus(&aStatus),
       
  1002   iPeerThread(NULL),
       
  1003   iSyncLocalCall(aSyncLocalCall)
       
  1004 	{
       
  1005 	}
       
  1006 
       
  1007 /**
       
  1008 Complete the request in a way relevant to the context:
       
  1009     -# If within the same thread, just set the status member as value is later used further up in the call stack.
       
  1010 	-# If within other thread, use "real" completion function to signal status/thread semaphore.
       
  1011 */
       
  1012 EXPORT_C void TRequestWrapper::RequestComplete(TInt aReason)
       
  1013 	{
       
  1014 	if(iSyncLocalCall)
       
  1015 		{
       
  1016 		LOG(ESockLog::Printf(KESockSessDetailTag, _L8("TRequestWrapper::RequestComplete() %08x = %d (local, synchronous)"), iStatus, aReason));
       
  1017 		// Don't need to complete request since it's a synchronous call down within
       
  1018 		// the requesting thread, which isn't waiting for the return
       
  1019 		__ASSERT_DEBUG(iStatus, User::Panic(KSpecAssert_ESockSSocks_thrd, 18));	// no valid case for completing twice
       
  1020 		*iStatus = aReason;
       
  1021 		iStatus = NULL;
       
  1022 		}
       
  1023 	else
       
  1024 		{
       
  1025 		LOG(ESockLog::Printf(KESockSessDetailTag, _L8("TRequestWrapper::RequestComplete() %08x = %d (requester tid = %x)"), iStatus, aReason, static_cast<TUint>(iPeerThread->Id())));
       
  1026 		iPeerThread->RequestComplete(iStatus, aReason);
       
  1027 		}
       
  1028 	}
       
  1029 
       
  1030 //
       
  1031 // TTransportUser
       
  1032 //
       
  1033 TInt TTransportUser::Compare(const TTransportUser& aLHS, const TTransportUser& aRHS)
       
  1034 	{
       
  1035 	if(aLHS.iInterfaceId < aRHS.iInterfaceId)
       
  1036 		{
       
  1037 		return -1;
       
  1038 		}
       
  1039 	else if(aLHS.iInterfaceId > aRHS.iInterfaceId)
       
  1040 		{
       
  1041 		return 1;
       
  1042 		}
       
  1043 	return 0;
       
  1044 	}
       
  1045 
       
  1046 /**
       
  1047 The socket server thread. This is where control will resume when the RootServer starts an
       
  1048 ESock instance.
       
  1049 This function creates the worker thread object and starts the active scheduler.
       
  1050 */
       
  1051 EXPORT_C TInt CWorkerThread::ThreadEntrypoint(TAny* aArg)
       
  1052 	{
       
  1053 #if defined (__EPOC32__)
       
  1054 	// Ensure that our thread has a handle on this library.
       
  1055 	RLibrary sockLib;
       
  1056 	__ASSERT_ALWAYS(sockLib.Load(ESOCK_SERVER_LIB_NAME)==KErrNone, Fault(ESvrStartServer));
       
  1057 #endif
       
  1058 
       
  1059 	CTrapCleanup* tc=CTrapCleanup::New();
       
  1060 	if (!tc)
       
  1061 		{
       
  1062 		return KErrNoMemory;
       
  1063 		}
       
  1064 
       
  1065 	CSocketScheduler* ss = CSocketScheduler::New();
       
  1066 
       
  1067 	TCFModuleInfo* moduleInfo = static_cast<TCFModuleInfo*>(aArg);
       
  1068 
       
  1069 	/* We instantiate our CWorkerThread here, but it is deleted through the
       
  1070 	destruction of SockManGlobals by the CShutdownWatchdog. */
       
  1071 	TRAPD(res, CWorkerThread::NewL(moduleInfo));
       
  1072 	if(res != KErrNone)
       
  1073 		{
       
  1074 		return res;
       
  1075 		}
       
  1076 
       
  1077 	RThread::Rendezvous(KErrNone);
       
  1078 	CActiveScheduler::Start();
       
  1079 
       
  1080 	/**
       
  1081 	   This is deleted here because the globals can theoretically be used
       
  1082 	   at any time up until when the active scheduler stops */
       
  1083 	CSockManData* globals=SockManGlobals::Get();
       
  1084 	delete globals;
       
  1085 	globals = NULL;
       
  1086 
       
  1087 	REComSession::FinalClose();
       
  1088 
       
  1089 	TInt returncode=KErrNone;
       
  1090 
       
  1091 	delete tc;
       
  1092 	delete ss;
       
  1093 	return returncode;
       
  1094 	}
       
  1095 
       
  1096