|
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"), ¤tEskMaskPtr)); |
|
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 |