|
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 #include "ss_roles.h" |
|
21 |
|
22 #include <e32base.h> |
|
23 #include <ss_glob.h> |
|
24 #include <comms-infras/ss_log.h> |
|
25 #include <es_ini.h> |
|
26 #include <cfthread.h> |
|
27 #include <rsshared.h> // logging tags |
|
28 #include "ss_subconn.h" |
|
29 #include <comms-infras/ss_tiermanagerutils.h> |
|
30 #include <ss_sock.h> |
|
31 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
32 #include <es_sock_internal.h> |
|
33 #endif |
|
34 #include "SS_rslv.H" |
|
35 #include "SS_conn.H" |
|
36 #include <comms-infras/ss_subconnprov.h> |
|
37 #include <comms-infras/ss_connprov.h> |
|
38 #include <comms-infras/ss_sapshim.h> |
|
39 #include <comms-infras/idquerynetmsg.h> |
|
40 |
|
41 #include <comms-infras/nifprvar.h> //for KNifEntireConnectionSubConnectionId |
|
42 #include <elements/responsemsg.h> //CResponseMsg |
|
43 #include "ss_connectionsession.h" |
|
44 #include "ss_flowrequest.h" |
|
45 #include "ss_msgs.h" |
|
46 #include <ecom/ecom.h> |
|
47 #include <ecom/implementationproxy.h> |
|
48 |
|
49 #include "ss_connectionserver.h" |
|
50 #include "ss_tierthreadmap.h" |
|
51 |
|
52 #include <comms-infras/ss_nodemessages_internal_esock.h> |
|
53 #ifdef SYMBIAN_ZERO_COPY_NETWORKING |
|
54 #include <comms-infras/commsbufpondop.h> |
|
55 #else |
|
56 #include <es_mbman.h> |
|
57 #endif // SYMBIAN_ZERO_COPY_NETWORKING |
|
58 |
|
59 |
|
60 |
|
61 #ifdef _DEBUG |
|
62 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
63 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
64 _LIT(KSpecAssert_ESockSSocks_rls, "ESockSSocks_rls."); |
|
65 #endif |
|
66 |
|
67 using ESock::MProviderSelector; |
|
68 using ESock::ISelectionNotify; |
|
69 |
|
70 #define MSG_PRM(prmIndex) (prmIndex) |
|
71 using namespace NetInterfaces; |
|
72 |
|
73 using namespace NetInterfaces; |
|
74 using namespace ESock; |
|
75 using namespace Messages; |
|
76 using namespace Den; |
|
77 using namespace CommsFW; |
|
78 |
|
79 #include <cs_subconparams.h> |
|
80 |
|
81 |
|
82 |
|
83 // |
|
84 // CPlayer |
|
85 // |
|
86 |
|
87 CPlayer* CPlayer::NewL(CWorkerThread* aOwnerThread, TPlayerRole aPlayerRole) |
|
88 { |
|
89 CPlayer* self = new(ELeave) CPlayer(aOwnerThread, aPlayerRole); |
|
90 return self; |
|
91 } |
|
92 |
|
93 /** |
|
94 The Player destructor doesn't have much to do as a lot of the cleanup is done during the |
|
95 normal shutdown routines. Here the Player merely deletes all sub-sessions it owns. |
|
96 */ |
|
97 CPlayer::~CPlayer() |
|
98 { |
|
99 // The object container is stored as a packed array, so working backwards through it avoids invalidating |
|
100 // the iterator when removing entries (and as a bonus is more efficient) |
|
101 LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::~CPlayer()"))); |
|
102 iTransferBuffer.Close(); |
|
103 } |
|
104 |
|
105 CPlayer::CPlayer(CWorkerThread* aOwnerThread, TPlayerRole aPlayerRole) |
|
106 : CCommonPlayer(aOwnerThread, aPlayerRole) |
|
107 { |
|
108 LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::CPlayer()"))); |
|
109 } |
|
110 |
|
111 CSockSubSession* CPlayer::SubSession(const Den::TSubSessionUniqueId& aSubSessionUniqueId) const |
|
112 { |
|
113 return static_cast<CSockSubSession*>(CCommonPlayer::SubSession(aSubSessionUniqueId)); |
|
114 } |
|
115 |
|
116 CSockSession* CPlayer::CurrentSession() const |
|
117 { |
|
118 return static_cast<CSockSession*>(CCommonPlayer::Session()); |
|
119 } |
|
120 |
|
121 CWorkerThread& CPlayer::WorkerThread() const |
|
122 { |
|
123 return static_cast<CWorkerThread&>(CCommonPlayer::WorkerThread()); |
|
124 } |
|
125 |
|
126 /** |
|
127 Check whether the Player is ready to shut down and if so, tells the owning Worker Thread |
|
128 */ |
|
129 TBool CPlayer::IsPlayerShutdownComplete() |
|
130 { |
|
131 CSockManData* globals = SockManGlobals::Get(); |
|
132 // Basic reason: we have no subsessions or protocol families remaining open |
|
133 TBool shutdownComplete = globals->iNumFamilies == 0; |
|
134 LOG_STMT(TBool dataThreadShutdownPending = EFalse;) |
|
135 if(shutdownComplete) |
|
136 { |
|
137 // But it could be that we're providing management services and have a data thread still bound; if so we hold-off from shutdown |
|
138 // until the data thread completes its own shutdown. Being relatively dumb it certainly can't survive without us. |
|
139 if(!HasDataPlane() && !SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane)).IsNull()) |
|
140 { |
|
141 shutdownComplete = EFalse; |
|
142 LOG_STMT(dataThreadShutdownPending = ETrue;) |
|
143 } |
|
144 } |
|
145 |
|
146 LOG(ESockLog::Printf(KESockBootingTag, _L8("CPlayer::MaybeSetPlayerShutdownComplete(), shutdownComplete = %d [#subSess=%d, numFam=%d, dataPending=%d]"), |
|
147 shutdownComplete, SubSessions().Count(), globals->iNumFamilies, dataThreadShutdownPending) ); |
|
148 |
|
149 if(globals->iNumFamilies) |
|
150 { |
|
151 // Help them figure out what (might be) blocking shutdown |
|
152 #ifdef __FLOG_ACTIVE |
|
153 TProtocolManagerLogger::LogLoadedInfo(); |
|
154 #endif |
|
155 } |
|
156 |
|
157 return shutdownComplete; |
|
158 } |
|
159 |
|
160 /** |
|
161 Called directly by the PitBoss to get protocol information. |
|
162 @note Index is 1-based for legacy reasons. |
|
163 */ |
|
164 TInt CPlayer::ProtocolInfo(TUint aIndex, TProtocolDesc& aProtocol) |
|
165 { |
|
166 // This could be optimised, eg to remember the last found position in case caller is iterating from 1..n protocols (since the |
|
167 // code here also iterates that gives O2 complexity). However, it is likely that this is a seldom-used function |
|
168 if((aIndex > SockManGlobals()->iNumProtocols) || aIndex<1) |
|
169 { |
|
170 return KErrNotSupported; |
|
171 } |
|
172 |
|
173 // Simply iterate along the queue aIndex times |
|
174 TSglQueIter<CProtocolRef> i(*SockManGlobals()->iProtocols); |
|
175 |
|
176 while(--aIndex) |
|
177 { |
|
178 i++; |
|
179 } |
|
180 |
|
181 aProtocol=((CProtocolRef*)i)->Info(); |
|
182 |
|
183 return KErrNone; |
|
184 } |
|
185 |
|
186 /** |
|
187 Write a handle back to Ptr3 of the current message |
|
188 */ |
|
189 TInt CPlayer::WriteSubSessionHandle(TInt aHandle) |
|
190 { |
|
191 TPckgC<TInt> pH(aHandle); |
|
192 return SafeMessage().Write(MSG_PRM(3),pH); |
|
193 } |
|
194 |
|
195 void CPlayer::CommsApiExtBindIfaceL(const RMessage2& aMessage, CSockSubSession& aSubSession) |
|
196 { |
|
197 aSubSession.CommsApiExtBindIfaceL(aMessage); |
|
198 } |
|
199 |
|
200 void CPlayer::CommsApiExtIfaceSendReceiveL(const RMessage2& aMessage, CSockSubSession& aSubSession) |
|
201 { |
|
202 aSubSession.CommsApiExtIfaceSendReceiveL(aMessage); |
|
203 } |
|
204 |
|
205 void CPlayer::CloseExtensionInterface(const RMessage2& aMessage, CSockSubSession& aSubSession) |
|
206 { |
|
207 aSubSession.CloseExtensionInterface(aMessage); |
|
208 } |
|
209 |
|
210 /** |
|
211 Called from a socket to delete it |
|
212 Removing a socket has the side effect of Close()ing it. |
|
213 */ |
|
214 void CPlayer::DeleteSocket(CSocket& aSocket) |
|
215 { |
|
216 aSocket.InitiateDestruction(); |
|
217 } |
|
218 |
|
219 |
|
220 |
|
221 MShimControlClient* CPlayer::CSubConnectionProviderFromHandleL(ESock::CConnection& /*aConnection*/, TSubConnectionUniqueId /*aSubConnectionUniqueId*/) |
|
222 {//this is a very link shim specific function to send a message to the shim connection provider factory |
|
223 LOG( ESockLog::Printf(_L("CPlayer %08x:\tCSubConnectionProviderFromHandleL() KErrNotReady"), this) ); |
|
224 User::Leave(KErrNotReady); |
|
225 return NULL; |
|
226 } |
|
227 |
|
228 /** |
|
229 Process the client message forwarded from the Dealer. For subsession-Close commands |
|
230 the Dealer provides the subsession pointer explicitly as it has already been removed from |
|
231 the index. |
|
232 */ |
|
233 void CPlayer::DoProcessMessageL(const RSafeMessage& aMessage, Den::CWorkerSubSession* aSubSession) |
|
234 { |
|
235 LOG( |
|
236 TBuf8<64> messBuf; |
|
237 ESockLog::IPCMessName((TSockMess) aMessage.Function(), messBuf); |
|
238 ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tProcessMessageL: session=%08x, subsess=%08x, Message(%08x) [%S]"), Session(), aSubSession, aMessage.Handle(), &messBuf); |
|
239 ); |
|
240 |
|
241 switch (aMessage.Function()) |
|
242 { |
|
243 case ESoCreateNull: |
|
244 { |
|
245 TInt dummyHandle; |
|
246 NewSocketL(ETrue, dummyHandle); |
|
247 break; |
|
248 } |
|
249 |
|
250 // case ESSNumProtocols: |
|
251 // NumProtocols(); |
|
252 // break; |
|
253 case ESSProtocolInfo: |
|
254 ProtocolInfo(); |
|
255 break; |
|
256 |
|
257 case ESSProtocolInfoByName: |
|
258 ProtocolInfoByName(); |
|
259 break; |
|
260 |
|
261 case ESSProtocolStart: |
|
262 LoadProtocolL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2()); |
|
263 break; |
|
264 |
|
265 case ESSProtocolStop: |
|
266 UnLoadProtocolL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2()); |
|
267 break; |
|
268 |
|
269 // socket messages |
|
270 case ESoCreate: |
|
271 NewSocketDefaultL(); |
|
272 break; |
|
273 |
|
274 case ESoCreateWithConnection: |
|
275 NewSocketWithConnectionL(); |
|
276 break; |
|
277 |
|
278 case ESoCreateWithSubConnection: |
|
279 NewSocketWithSubConnectionL(); |
|
280 break; |
|
281 |
|
282 case ESoTransfer: |
|
283 __ASSERT_DEBUG(aSubSession->Type().iType == TCFSubSessInfo::ESocket, User::Panic(KSpecAssert_ESockSSocks_rls, 2)); // Dealer does all of the validation for us |
|
284 TransferSocketL(static_cast<CSocket*>(aSubSession)); |
|
285 break; |
|
286 |
|
287 // Host resolver message types |
|
288 case EHRCreate: |
|
289 NewHostResolverDefaultL(aMessage.Int0(),aMessage.Int1()); |
|
290 break; |
|
291 |
|
292 case EHRCreateWithConnection: |
|
293 NewHostResolverWithConnectionL(aMessage.Int0(),aMessage.Int1(), aMessage.Int2()); |
|
294 break; |
|
295 |
|
296 // Service resolver message types |
|
297 case ESRCreate: |
|
298 NewServiceResolverL(aMessage.Int0(),aMessage.Int1(),aMessage.Int2()); |
|
299 break; |
|
300 |
|
301 // Net database message types |
|
302 case ENDCreate: |
|
303 NewNetDatabaseL(aMessage.Int0(),aMessage.Int1()); |
|
304 break; |
|
305 |
|
306 // Connection Messages |
|
307 case ECNCreate: |
|
308 { |
|
309 NewConnectionL(); |
|
310 break; |
|
311 } |
|
312 case ECNCreateWithName: |
|
313 { |
|
314 NewConnectionWithNameL(static_cast<CSockSubSession*>(aSubSession)); |
|
315 break; |
|
316 } |
|
317 /* |
|
318 case ESCPSStop: |
|
319 case ESCPSProgressNotification: |
|
320 case ESCPSCancelProgressNotification: |
|
321 case ESCPSDataTransferred: |
|
322 case ESCPSDataTransferredCancel: |
|
323 case ESCPSDataSentNotificationRequest: |
|
324 case ESCPSDataSentNotificationCancel: |
|
325 case ESCPSDataReceivedNotificationRequest: |
|
326 case ESCPSDataReceivedNotificationCancel: |
|
327 case ESCPSIsSubConnectionActiveRequest: |
|
328 case ESCPSIsSubConnectionActiveCancel: |
|
329 case ESCPSGetSubConnectionInfo: |
|
330 { |
|
331 __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 3)); |
|
332 ESock::CConnection* cn = static_cast<ESock::CConnection*>(aSubSession); |
|
333 TSubConnectionUniqueId subConnectionUniqueId = aMessage.Function() != ESCPSGetSubConnectionInfo ? static_cast<TSubConnectionUniqueId>(aMessage.Int0()) : KNifEntireConnectionSubConnectionId; |
|
334 MShimControlClient* sc = CSubConnectionProviderFromHandleL(*cn, subConnectionUniqueId); |
|
335 if (!sc) |
|
336 { |
|
337 LOG( ESockLog::Printf(_L("CPlayer %08x:\tProcessMessageL() ESCPS...... KErrNotReady"), this) ); |
|
338 User::Leave(KErrNotReady); |
|
339 } |
|
340 __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocks_rls, 4)); |
|
341 //@TODO service RConnection sub-connection oriented calls |
|
342 //iComplete = CSubConnection::ServiceL(*sc,aMessage); |
|
343 |
|
344 break; |
|
345 } |
|
346 */ |
|
347 case ESCCreate: |
|
348 { |
|
349 LOG( ESockLog::Printf(KESockSubConnectionTag, _L8("CSubConnection %08x\tESCCreate aMessage %08x"), this, &SafeMessage()) ); |
|
350 ESock::CSubConnection* sc = NewSubConnectionWithConnectionL(); |
|
351 __ASSERT_DEBUG(sc, User::Panic(KSpecAssert_ESockSSocks_rls, 5)); |
|
352 //If successful, the ownership of the RMessage2 is taken by the activity, otherwise completed on leave |
|
353 //The activity also takes ownership of the CSubConnection for the duration of the activity for cleanup purposes |
|
354 sc->CMMSockSubSession::ReceivedL(ESCCreate, ESock::TCFInternalEsock::TSubSess(ESCCreate,SafeMessage()).CRef()); |
|
355 break; |
|
356 } |
|
357 |
|
358 case ECommsApiExtBindIface: |
|
359 __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 6)); |
|
360 CommsApiExtBindIfaceL(aMessage, static_cast<CSockSubSession&>(*aSubSession)); |
|
361 break; |
|
362 |
|
363 case ECommsApiExtIfaceSend: |
|
364 case ECommsApiExtIfaceSendReceive: |
|
365 __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 7)); |
|
366 CommsApiExtIfaceSendReceiveL(aMessage, static_cast<CSockSubSession&>(*aSubSession)); |
|
367 break; |
|
368 |
|
369 case ECommsApiExtIfaceClose: |
|
370 { |
|
371 CloseExtensionInterface(aMessage, static_cast<CSockSubSession&>(*aSubSession)); |
|
372 break; |
|
373 } |
|
374 |
|
375 default: |
|
376 __ASSERT_DEBUG(aSubSession, User::Panic(KSpecAssert_ESockSSocks_rls, 8)); |
|
377 |
|
378 aSubSession->ProcessMessageL(); |
|
379 |
|
380 break; |
|
381 } |
|
382 |
|
383 // Message handlers can change the state of the iMessage if they want to hold onto the message. |
|
384 // They can also write a return value to iReturn. |
|
385 if (iComplete) |
|
386 { |
|
387 LOG(ESockLog::Printf(KESockServerTag, _L8("CPlayer:\tProcessMessageL, session=%08x, RMessage2::Complete (%08x) with %d."), Session(), aMessage.Handle(), iReturn) ); |
|
388 aMessage.Complete(Return()); |
|
389 } |
|
390 |
|
391 //This is a normal return so we do no longer need the reference |
|
392 SetSession(NULL); |
|
393 } |
|
394 |
|
395 /** |
|
396 Get info for a protocol by index. |
|
397 */ |
|
398 void CPlayer::ProtocolInfo() |
|
399 { |
|
400 TProtocolDesc prot; |
|
401 TInt ret=0; |
|
402 TInt localIndex = static_cast<CPitBoss&>(PitBoss()).GetLocalProtocolIndex(SafeMessage().Int1()); |
|
403 if((ret=ProtocolInfo(localIndex,prot))==KErrNone) |
|
404 { |
|
405 TPckgC<TProtocolDesc> p(prot); |
|
406 ret = SafeMessage().Write(MSG_PRM(0),p); |
|
407 } |
|
408 SetReturn(ret); |
|
409 } |
|
410 |
|
411 /** |
|
412 Get protocol info by name. |
|
413 */ |
|
414 void CPlayer::ProtocolInfoByName() |
|
415 { |
|
416 TProtocolName name; |
|
417 TServerProtocolDesc prot; |
|
418 TInt ret=0; |
|
419 |
|
420 ret = SafeMessage().Read(MSG_PRM(1),name); |
|
421 |
|
422 if((ret=ProtocolInfo(name, prot))==KErrNone) |
|
423 { |
|
424 TPckgC<TProtocolDesc> p(prot); |
|
425 ret = SafeMessage().Write(MSG_PRM(0),p); |
|
426 } |
|
427 SetReturn(ret); |
|
428 } |
|
429 |
|
430 /** |
|
431 Find a protocol by name - no wildcard support. |
|
432 */ |
|
433 TInt CPlayer::ProtocolInfo(const TDesC &aName, TServerProtocolDesc &aProtocol) |
|
434 { |
|
435 TSglQueIter<CProtocolRef> i(*SockManGlobals::Get()->iProtocols); |
|
436 |
|
437 // Run the queue looking for a match. |
|
438 do |
|
439 { |
|
440 if(((CProtocolRef *)i)->Info().iName.CompareF(aName)==0) |
|
441 { |
|
442 aProtocol=((CProtocolRef*)i)->Info(); |
|
443 return KErrNone; |
|
444 } |
|
445 i++; |
|
446 } |
|
447 while((CProtocolRef *)i); |
|
448 |
|
449 return KErrNotFound; |
|
450 } |
|
451 |
|
452 |
|
453 /** |
|
454 The socket reference is the object name preceded by the Worker's id and a space. This is |
|
455 intended as an opaque cookie for use with socket transfer. |
|
456 */ |
|
457 void CPlayer::TransferSocketL(CSocket* aSocket) |
|
458 { |
|
459 __ASSERT_DEBUG(&aSocket->Player() == this, User::Panic(KSpecAssert_ESockSSocks_rls, 9)); |
|
460 |
|
461 TInt id; |
|
462 TInt ret; |
|
463 |
|
464 { |
|
465 ProtocolManager::TransferSocketL(aSocket, this); |
|
466 aSocket->CancelAll(); |
|
467 |
|
468 CurrentSession()->SubSessions().Lock(); |
|
469 |
|
470 ret = PitBoss().AddSubSession(aSocket, CurrentSession(), id); |
|
471 aSocket->SetUniqueId(PitBoss().NextSubSessionUniqueId()); |
|
472 |
|
473 CurrentSession()->SubSessions().Unlock(); |
|
474 } |
|
475 |
|
476 if(ret == KErrNone) |
|
477 { |
|
478 { |
|
479 aSocket->Session()->SubSessions().Lock(); |
|
480 |
|
481 // Remove from original session |
|
482 CSubSessionIx& srcSubSessions = aSocket->Session()->SubSessions(); |
|
483 TInt oldIndex; |
|
484 VERIFY_RESULT(srcSubSessions.Find(aSocket, oldIndex), KErrNone); |
|
485 PitBoss().RemoveSubSession(oldIndex, static_cast<CSockSession*>(aSocket->Session())); |
|
486 |
|
487 aSocket->Session()->SubSessions().Unlock(); |
|
488 } |
|
489 |
|
490 aSocket->SetSessionProxy(NULL); |
|
491 aSocket->SetSession(CurrentSession()); |
|
492 aSocket->SetSessionProxy(CurrentSessionProxyL()); |
|
493 ret = WriteSubSessionHandle(id); |
|
494 if (ret != KErrNone) |
|
495 { |
|
496 aSocket->InitiateDestruction(); // this should leave socket (almost) dead; we're not trying to reverse the transfer |
|
497 } |
|
498 if(ret == KErrNone && aSocket->RequiresOwnerInfo()) |
|
499 { |
|
500 // store information about the client that created this socket |
|
501 aSocket->StoreOwnerInfo(); |
|
502 aSocket->CommunicateOwner(); |
|
503 } |
|
504 } |
|
505 if(ret != KErrNone) |
|
506 { |
|
507 User::Leave(ret); |
|
508 } |
|
509 } |
|
510 |
|
511 /** |
|
512 Create a new empty socket to be used for accept. |
|
513 We need to make empty sockets just to get a valid handle to accept into. |
|
514 */ |
|
515 CSocket* CPlayer::NewSocketL(TBool aCompleteClientRequest, TInt& aHandle) |
|
516 { |
|
517 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer::NewSocketL(null sock)")) ); |
|
518 |
|
519 CSocket *sp = NULL; |
|
520 TInt ret; |
|
521 |
|
522 { |
|
523 |
|
524 // Create a new socket and add it our list of subsessions |
|
525 sp = CSocket::NewLC( |
|
526 NULL, |
|
527 CurrentSession(), |
|
528 this, |
|
529 0, |
|
530 PitBoss().NextSubSessionUniqueId(), |
|
531 KUndefinedSockType); |
|
532 |
|
533 SubSessions().AppendL(sp); |
|
534 CleanupStack::Pop(); |
|
535 |
|
536 // Now add the new socket, itself a subsession, to the global store |
|
537 CurrentSession()->SubSessions().Lock(); |
|
538 ret = PitBoss().AddSubSession(sp, CurrentSession(), aHandle); |
|
539 if(ret == KErrNone) |
|
540 { |
|
541 if(aCompleteClientRequest) |
|
542 { |
|
543 ret = WriteSubSessionHandle(aHandle); |
|
544 } |
|
545 if(ret != KErrNone) |
|
546 { |
|
547 PitBoss().RemoveSubSession(aHandle, CurrentSession()); |
|
548 } |
|
549 } |
|
550 |
|
551 CurrentSession()->SubSessions().Unlock(); |
|
552 } |
|
553 |
|
554 if(ret != KErrNone) |
|
555 { |
|
556 sp->InitiateDestruction(); |
|
557 User::Leave(ret); |
|
558 } |
|
559 |
|
560 return sp; |
|
561 } |
|
562 |
|
563 /** |
|
564 Create a new socket on this session for normal Open. The Player adds the new socket to |
|
565 the session owned by the dealer (uses explicitly locked access). |
|
566 */ |
|
567 CSocket* CPlayer::NewSocketL(TUint aAddrFamily, TUint aSocketType, TUint aProtocol) |
|
568 { |
|
569 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketL(family=%d, type=%d, protocol=%d"), aAddrFamily, aSocketType, aProtocol) ); |
|
570 |
|
571 CSocket* sp = NULL; |
|
572 TInt ret; |
|
573 |
|
574 { |
|
575 |
|
576 // Look up the protocol for which we are creating a socket |
|
577 CProtocolRef* protocolReference = ProtocolManager::FindProtocolL(aAddrFamily, aSocketType, aProtocol); |
|
578 |
|
579 // Create a new socket and add it our list of subsessions |
|
580 sp = CSocket::NewLC( |
|
581 &(protocolReference->Info()), |
|
582 CurrentSession(), |
|
583 this, |
|
584 protocolReference->Protocol(), |
|
585 PitBoss().NextSubSessionUniqueId(), |
|
586 aSocketType); |
|
587 |
|
588 SubSessions().AppendL(sp); |
|
589 CleanupStack::Pop(); |
|
590 |
|
591 CurrentSession()->SubSessions().Lock(); |
|
592 TInt id; |
|
593 ret = PitBoss().AddSubSession(sp, CurrentSession(), id); |
|
594 if(ret == KErrNone) |
|
595 { |
|
596 ret = WriteSubSessionHandle(id); |
|
597 if(ret != KErrNone) |
|
598 { |
|
599 // V1 ESock didn't remove after failure, but did for the other overload of NewSocketL(). |
|
600 // Believed to have been in error |
|
601 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
602 } |
|
603 } |
|
604 |
|
605 CurrentSession()->SubSessions().Unlock(); |
|
606 } |
|
607 |
|
608 if(sp->RequiresOwnerInfo()) |
|
609 { |
|
610 // store information about the client that created this socket, to |
|
611 // communicate to the flow once we're bound |
|
612 sp->StoreOwnerInfo(); |
|
613 } |
|
614 |
|
615 if(ret != KErrNone) |
|
616 { |
|
617 sp->InitiateDestruction(); |
|
618 User::Leave(ret); |
|
619 } |
|
620 |
|
621 return sp; |
|
622 } |
|
623 |
|
624 /** |
|
625 Create a new socket on this session for normal Open. The Player adds the new socket to |
|
626 the session owned by the dealer (uses explicitly locked access). |
|
627 */ |
|
628 void CPlayer::NewSocketDefaultL() |
|
629 { |
|
630 TUint aAddrFamily = SafeMessage().Int0(); |
|
631 TUint aSocketType = SafeMessage().Int1(); |
|
632 TUint aProtocol = SafeMessage().Int2(); |
|
633 |
|
634 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketDefaultL(family=%d, type=%d, protocol=%d"), aAddrFamily, aSocketType, aProtocol) ); |
|
635 CSocket* s = NewSocketL(aAddrFamily, aSocketType, aProtocol); |
|
636 |
|
637 TFlowParams flowParams( |
|
638 aAddrFamily, |
|
639 aSocketType, |
|
640 aProtocol, |
|
641 TFlowParams::EImplicit, |
|
642 CurrentSessionProxyL()); |
|
643 |
|
644 //requesting a lower flow by throwing a self-dispatcher (TCFImplicitFlowRequest) through the |
|
645 //fence (onto the control plane). TCFImplicitFlowRequest assumes no preexiting stack (hence implicit) |
|
646 //and it will select and start a suitable stack based on the default access point. |
|
647 //That stack will be interrogated for a suitable flow (flowParams), which will be returned back |
|
648 //to the sender (socket) with TBindTo |
|
649 RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender |
|
650 SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread |
|
651 TCFImplicitFlowRequest(s->UniqueId(), flowParams)); |
|
652 |
|
653 s->SetFlowRequestPending(ETrue); |
|
654 s->AdoptFlowRequestMessage(SafeMessage()); |
|
655 |
|
656 DontCompleteCurrentRequest(); |
|
657 } |
|
658 |
|
659 /** |
|
660 Create a new socket on this session for normal Open |
|
661 */ |
|
662 void CPlayer::NewSocketWithConnectionL() |
|
663 { |
|
664 // If we don't host the data plane then the request was forwarded to us to determine which data thread shall create the socket |
|
665 if(!HasDataPlane()) |
|
666 { |
|
667 Messages::TNodeId flowFC = SockManGlobals()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane)); |
|
668 __ASSERT_DEBUG(!flowFC.IsNull(), User::Panic(KSpecAssert_ESockSSocks_rls, 10)); |
|
669 TPlayerForwardRequestMsg msg(SafeMessage(), TPlayerForwardRequestMsg::NormalCreationFlag()); |
|
670 WorkerThread().PostMessage(flowFC.Thread(), msg); |
|
671 DontCompleteCurrentRequest(); |
|
672 return; |
|
673 } |
|
674 |
|
675 TPckgBuf<TSockOpen> argPkg; |
|
676 SafeMessage().ReadL(MSG_PRM(0),argPkg); |
|
677 |
|
678 //!!PS remember the race conditions in case someone closes connection in control thread |
|
679 //(Lock on the sub-session queue should persist over the code accessing cn* |
|
680 CSocket* s = NewSocketL(argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol); |
|
681 |
|
682 // Send the flow request message to the connection plane |
|
683 TFlowParams flowParams( |
|
684 argPkg().iAddrFamily, |
|
685 argPkg().iSockType, |
|
686 argPkg().iProtocol, |
|
687 TFlowParams::EExplicitConnection, |
|
688 CurrentSessionProxyL()); |
|
689 |
|
690 //requesting a lower flow by throwing a self-dispatcher (TCFConnFlowRequest) through the |
|
691 //fence (onto the control plane). TCFConnFlowRequest will interrogate the connection (argPkg().iHandle) |
|
692 //for its default subconnection and the subconnection for a suitable (flowParams) flow. |
|
693 //The flow will be returned back to the sender (socket) with TBindTo. |
|
694 RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender |
|
695 SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EConnPlane)), //phoney recipient - we only care the recipient is on the control plane, so that this message will be dispatched on a correct thread. |
|
696 TCFConnFlowRequest(s->UniqueId(), *CurrentSession(), argPkg().iHandle, flowParams)); |
|
697 |
|
698 s->SetFlowRequestPending(ETrue); |
|
699 s->AdoptFlowRequestMessage(SafeMessage()); |
|
700 |
|
701 DontCompleteCurrentRequest(); |
|
702 } |
|
703 |
|
704 /** |
|
705 Create a new socket on this session for normal Open. |
|
706 */ |
|
707 void CPlayer::NewSocketWithSubConnectionL() |
|
708 { |
|
709 // If we don't host the data plane then the request was forwarded to us to determine which data thread shall create the socket |
|
710 if(!HasDataPlane()) |
|
711 { |
|
712 Messages::TNodeId flowFC = SockManGlobals()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EDataPlane)); |
|
713 __ASSERT_DEBUG(!flowFC.IsNull(), User::Panic(KSpecAssert_ESockSSocks_rls, 11)); |
|
714 TPlayerForwardRequestMsg msg(SafeMessage(), TPlayerForwardRequestMsg::NormalCreationFlag()); |
|
715 WorkerThread().PostMessage(flowFC.Thread(), msg); |
|
716 DontCompleteCurrentRequest(); |
|
717 return; |
|
718 } |
|
719 |
|
720 TPckgBuf<TSockOpen> argPkg; |
|
721 SafeMessage().ReadL(MSG_PRM(0),argPkg); |
|
722 |
|
723 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CPlayer:\tNewSocketWithSubConnectionL(family=%d, type=%d, protocol=%d"), argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol) ); |
|
724 CSocket* s = NewSocketL(argPkg().iAddrFamily, argPkg().iSockType, argPkg().iProtocol); |
|
725 |
|
726 // Send the flow request message to the connection plane |
|
727 TFlowParams flowParams( |
|
728 argPkg().iAddrFamily, |
|
729 argPkg().iSockType, |
|
730 argPkg().iProtocol, |
|
731 TFlowParams::EExplicitSubConnection, |
|
732 CurrentSessionProxyL()); |
|
733 |
|
734 //requesting a lower flow by throwing a self-dispatcher (TCFSubConnFlowRequest) through the |
|
735 //fence (onto the control plane). TCFConnFlowRequest will interrogate the subconnection (argPkg().iHandle) |
|
736 //for a suitable (flowParams) flow. The flow will be returned back to the sender (socket) with TBindTo. |
|
737 RClientInterface::OpenPostMessageClose(s->Id(), //socket is the sender |
|
738 SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ESubConnPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread |
|
739 TCFSubConnFlowRequest(s->UniqueId(), *CurrentSession(), argPkg().iHandle, flowParams)); |
|
740 |
|
741 s->SetFlowRequestPending(ETrue); |
|
742 s->AdoptFlowRequestMessage(SafeMessage()); |
|
743 |
|
744 DontCompleteCurrentRequest(); |
|
745 } |
|
746 |
|
747 /** |
|
748 Create a new host resolver for this session. |
|
749 */ |
|
750 CHostResolver* CPlayer::NewHostResolverL(TUint anAddrFamily,TUint aProtocol) |
|
751 { |
|
752 CHostResolver* h = NULL; |
|
753 TInt ret; |
|
754 |
|
755 { |
|
756 |
|
757 h=ProtocolManager::NewHostResolverL(anAddrFamily,aProtocol, this, PitBoss().NextSubSessionUniqueId()); |
|
758 |
|
759 TInt id; |
|
760 CurrentSession()->SubSessions().Lock(); |
|
761 ret = PitBoss().AddSubSession(h, CurrentSession(), id); |
|
762 if(ret == KErrNone) |
|
763 { |
|
764 ret = WriteSubSessionHandle(id); |
|
765 if(ret != KErrNone) |
|
766 { |
|
767 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
768 } |
|
769 } |
|
770 CurrentSession()->SubSessions().Unlock(); |
|
771 } |
|
772 |
|
773 if(ret != KErrNone) |
|
774 { |
|
775 h->InitiateDestruction(); |
|
776 User::Leave(ret); |
|
777 } |
|
778 |
|
779 if(h->RequiresOwnerInfo()) |
|
780 { |
|
781 // store information about the client that created this host resolver |
|
782 h->StoreOwnerInfo(); |
|
783 } |
|
784 |
|
785 return (h); |
|
786 } |
|
787 |
|
788 /** |
|
789 Create a new host resolver for this session. |
|
790 */ |
|
791 void CPlayer::NewHostResolverDefaultL(TUint aAddrFamily,TUint aProtocol) |
|
792 { |
|
793 CHostResolver* h = NewHostResolverL(aAddrFamily, aProtocol); |
|
794 |
|
795 // Send the flow parameters to the tier manager plane |
|
796 TFlowParams flowParams( |
|
797 aAddrFamily, |
|
798 KUndefinedSockType, |
|
799 aProtocol, |
|
800 TFlowParams::EImplicit, |
|
801 CurrentSessionProxyL(), |
|
802 EFalse); |
|
803 |
|
804 //requesting a lower flow by throwing a self-dispatcher (TCFImplicitFlowRequest) through the |
|
805 //fence (onto the control plane). TCFImplicitFlowRequest assumes no preexiting stack (hence implicit) |
|
806 //and it will select and start a suitable stack based on the default access point. |
|
807 //That stack will be interrogated for a suitable flow (flowParams), which will be returned back |
|
808 //to the sender (host resolver) with TBindTo |
|
809 RClientInterface::OpenPostMessageClose(h->Id(), //socket is the sender |
|
810 SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::ETierMgrPlane)), //phoney recipient - we only care the recipient is on the control plane so that this message is dispatched on the correct thread |
|
811 TCFImplicitFlowRequest(h->UniqueId(), flowParams)); |
|
812 |
|
813 h->SetFlowRequestPending(ETrue); |
|
814 h->AdoptFlowRequestMessage(SafeMessage()); |
|
815 |
|
816 DontCompleteCurrentRequest(); |
|
817 } |
|
818 |
|
819 /** |
|
820 Create a new host resolver for this session. |
|
821 */ |
|
822 void CPlayer::NewHostResolverWithConnectionL(TUint aAddrFamily, TUint aProtocol, TInt aHandle) |
|
823 { |
|
824 CHostResolver* h = NewHostResolverL(aAddrFamily, aProtocol); |
|
825 |
|
826 // Send the flow parameters to the tier manager plane |
|
827 TFlowParams flowParams( |
|
828 aAddrFamily, |
|
829 KUndefinedSockType, |
|
830 aProtocol, |
|
831 TFlowParams::EExplicitConnection, |
|
832 CurrentSessionProxyL(), |
|
833 EFalse); |
|
834 |
|
835 //requesting a lower flow by throwing a self-dispatcher (TCFConnFlowRequest) through the |
|
836 //fence (onto the control plane). TCFConnFlowRequest will interrogate the connection (aHandle) |
|
837 //for its default subconnection and the subconnection for a suitable (flowParams) flow. |
|
838 //The flow will be returned back to the sender (socket) with TBindTo. |
|
839 RClientInterface::OpenPostMessageClose(h->Id(), //socket is the sender |
|
840 SockManGlobals::Get()->GetPlaneFC(TCFPlayerRole(TCFPlayerRole::EConnPlane)), //phoney recipient - we only care the recipient is on the control plane, so that this message will be dispatched on a correct thread. |
|
841 TCFConnFlowRequest(h->UniqueId(), *CurrentSession(), aHandle, flowParams)); |
|
842 |
|
843 h->SetFlowRequestPending(ETrue); |
|
844 h->AdoptFlowRequestMessage(SafeMessage()); |
|
845 |
|
846 DontCompleteCurrentRequest(); |
|
847 } |
|
848 |
|
849 |
|
850 /** |
|
851 Create a new service resolver for this session. |
|
852 */ |
|
853 void CPlayer::NewServiceResolverL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol) |
|
854 { |
|
855 CServiceResolver* r = NULL; |
|
856 TInt ret; |
|
857 |
|
858 { |
|
859 |
|
860 r=ProtocolManager::NewServiceResolverL(anAddrFamily, aSocketType, aProtocol, this, PitBoss().NextSubSessionUniqueId()); |
|
861 |
|
862 TInt id; |
|
863 CurrentSession()->SubSessions().Lock(); |
|
864 ret = PitBoss().AddSubSession(r, CurrentSession(), id); |
|
865 if(ret == KErrNone) |
|
866 { |
|
867 ret = WriteSubSessionHandle(id); |
|
868 if(ret != KErrNone) |
|
869 { |
|
870 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
871 } |
|
872 } |
|
873 CurrentSession()->SubSessions().Unlock(); |
|
874 } |
|
875 |
|
876 if (ret != KErrNone) |
|
877 { |
|
878 delete r; |
|
879 User::Leave(ret); |
|
880 } |
|
881 } |
|
882 |
|
883 /** |
|
884 Create a new net database for this session. |
|
885 */ |
|
886 void CPlayer::NewNetDatabaseL(TUint anAddrFamily,TUint aProtocol) |
|
887 { |
|
888 CNetDatabase* n = NULL; |
|
889 TInt ret; |
|
890 |
|
891 { |
|
892 |
|
893 n=ProtocolManager::NewNetDatabaseL(anAddrFamily, aProtocol, this, PitBoss().NextSubSessionUniqueId()); |
|
894 |
|
895 TInt id; |
|
896 CurrentSession()->SubSessions().Lock(); |
|
897 ret = PitBoss().AddSubSession(n, CurrentSession(), id); |
|
898 if(ret == KErrNone) |
|
899 { |
|
900 ret = WriteSubSessionHandle(id); |
|
901 if(ret != KErrNone) |
|
902 { |
|
903 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
904 } |
|
905 } |
|
906 |
|
907 CurrentSession()->SubSessions().Unlock(); |
|
908 } |
|
909 |
|
910 if (ret!=KErrNone) |
|
911 { |
|
912 delete n; |
|
913 User::Leave(ret); |
|
914 } |
|
915 } |
|
916 |
|
917 /** |
|
918 Create a new socket on this session for normal Open. |
|
919 */ |
|
920 CSubConnection* CPlayer::NewSubConnectionWithConnectionL() |
|
921 { |
|
922 TPckgBuf<TSubConnOpen> argPkg; |
|
923 SafeMessage().ReadL(MSG_PRM(0),argPkg); |
|
924 |
|
925 ESock::CConnection* cn=static_cast<CSockSession*>(CurrentSession())->CConnectionFromHandle(argPkg().iHandle); |
|
926 if (!cn) |
|
927 { |
|
928 PanicClient(KESockClientPanic, ESockBadHandle); |
|
929 return NULL; |
|
930 } |
|
931 |
|
932 if (!cn->ServiceProvider()) |
|
933 { |
|
934 LOG( ESockLog::Printf(_L("CPlayer %08x:\tNewSubConnectionWithConnectionL() KErrNotReady"), this) ); |
|
935 User::Leave(KErrNotReady); |
|
936 } |
|
937 |
|
938 return NewSubConnectionL(*cn); |
|
939 } |
|
940 |
|
941 /** |
|
942 Create a new sub-connection for this session. |
|
943 */ |
|
944 CSubConnection* CPlayer::NewSubConnectionL(ESock::CConnection& aConnection) |
|
945 { |
|
946 ESock::CSubConnection* subconn = NULL; |
|
947 TInt ret; |
|
948 |
|
949 { |
|
950 |
|
951 subconn = ESock::CSubConnection::NewL(aConnection, this, PitBoss().NextSubSessionUniqueId()); |
|
952 ret = SubSessions().Append(subconn); |
|
953 if(ret == KErrNone) |
|
954 { |
|
955 CurrentSession()->SubSessions().Lock(); |
|
956 TInt id; |
|
957 TInt ret = PitBoss().AddSubSession(subconn, CurrentSession(), id); |
|
958 if(ret == KErrNone) |
|
959 { |
|
960 ret = WriteSubSessionHandle(id); |
|
961 if(ret != KErrNone) |
|
962 { |
|
963 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
964 } |
|
965 } |
|
966 CurrentSession()->SubSessions().Unlock(); |
|
967 } |
|
968 |
|
969 } |
|
970 |
|
971 if (ret!=KErrNone) |
|
972 { |
|
973 delete subconn; |
|
974 User::Leave(ret); |
|
975 } |
|
976 |
|
977 return subconn; |
|
978 } |
|
979 |
|
980 void CPlayer::NewConnectionL() |
|
981 { |
|
982 TUint family = SafeMessage().Int0(); |
|
983 TUid tierId = TierManagerUtils::MapTierIdsL(TUid::Uid(family), 0); |
|
984 ESock::CConnection* conn = ESock::CConnection::NewLC(static_cast<CSockSession*>(CurrentSession()), this, tierId, PitBoss().NextSubSessionUniqueId()); |
|
985 SetupNewConnectionL(conn); |
|
986 CleanupStack::Pop(conn); |
|
987 } |
|
988 |
|
989 void CPlayer::NewConnectionWithNameL(CSockSubSession* aSubSession) |
|
990 { |
|
991 // The passed subsession is the original to base the creation off |
|
992 __ASSERT_DEBUG(aSubSession->Type().iType == TCFSubSessInfo::EConnection, User::Panic(KSpecAssert_ESockSSocks_rls, 12)); // Dealer does all of the validation for us |
|
993 |
|
994 CConnection& origConn = static_cast<CConnection&>(*aSubSession); |
|
995 // Police the clone open request against the security policy stored applied to the original RConnection |
|
996 User::LeaveIfError(origConn.CheckCloneOpenPolicy(SafeMessage())); |
|
997 ESock::CConnection* conn = ESock::CConnection::NewLC(static_cast<CSockSession*>(CurrentSession()), this, origConn, PitBoss().NextSubSessionUniqueId()); |
|
998 SetupNewConnectionL(conn); |
|
999 CleanupStack::Pop(conn); |
|
1000 } |
|
1001 |
|
1002 /** |
|
1003 Handle creation of a new connection for this session |
|
1004 */ |
|
1005 void CPlayer::SetupNewConnectionL(CConnection* aConn) |
|
1006 { |
|
1007 TInt ret; |
|
1008 |
|
1009 { |
|
1010 |
|
1011 SubSessions().AppendL(aConn); |
|
1012 TInt id; |
|
1013 CurrentSession()->SubSessions().Lock(); |
|
1014 ret = PitBoss().AddSubSession(aConn, CurrentSession(), id); |
|
1015 if(ret == KErrNone) |
|
1016 { |
|
1017 ret = WriteSubSessionHandle(id); |
|
1018 if(ret != KErrNone) |
|
1019 { |
|
1020 PitBoss().RemoveSubSession(id, CurrentSession()); |
|
1021 } |
|
1022 } |
|
1023 |
|
1024 CurrentSession()->SubSessions().Unlock(); |
|
1025 } |
|
1026 |
|
1027 if(ret!=KErrNone) |
|
1028 { |
|
1029 User::Leave(ret); |
|
1030 } |
|
1031 |
|
1032 // store information about the client that created this connection |
|
1033 // note that CConnections should always store their owner info |
|
1034 aConn->StoreOwnerInfo(); |
|
1035 } |
|
1036 |
|
1037 CCommonSessionProxy* CPlayer::DoCreateSessionProxyL(CWorkerSession* aSession) |
|
1038 { |
|
1039 return CSockSessionProxy::NewL(aSession, *this); |
|
1040 } |
|
1041 |
|
1042 void CPlayer::LoadProtocolL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol) |
|
1043 { |
|
1044 ProtocolManager::LoadProtocolL(anAddrFamily,aSocketType,aProtocol,this); |
|
1045 } |
|
1046 |
|
1047 /** |
|
1048 Find the protocol, check it is not referenced and delete it |
|
1049 */ |
|
1050 void CPlayer::UnLoadProtocolL(TUint anAddrFamily,TUint aSocketType,TUint aProtocol) |
|
1051 { |
|
1052 ProtocolManager::UnLoadProtocolL(anAddrFamily, aSocketType, aProtocol,this); |
|
1053 } |
|
1054 |
|
1055 /** Provides a sizeable buffer for strictly temporary use, eg within current stack frame: there's only one buffer |
|
1056 * and no protocol for returning so shared use can't be detected: the intended use is for transferring data to/from |
|
1057 * a client. |
|
1058 * @return pointer to a buffer of at least the requested size, or NULL if this proves impossible |
|
1059 */ |
|
1060 TDes8* CPlayer::BorrowTemporaryBuffer(TInt aSize) |
|
1061 { |
|
1062 if(iTransferBuffer.Size() < aSize) |
|
1063 { |
|
1064 if(iTransferBuffer.ReAlloc(aSize) != KErrNone) |
|
1065 { |
|
1066 return NULL; |
|
1067 } |
|
1068 } |
|
1069 iTransferBuffer.SetMax(); // indicate whole of buffer available when used for MBuf CopyOut() - in general overwrite not append is expected since it's a temporary buffer |
|
1070 return &iTransferBuffer; |
|
1071 } |
|
1072 |
|
1073 |
|
1074 #ifdef _DEBUG |
|
1075 TBool CPlayer::RunPostBootChecks() |
|
1076 { |
|
1077 CWorkerThread& owner = WorkerThread(); |
|
1078 if(owner.DefaultOptimalDealer()) |
|
1079 { |
|
1080 // Now that booting is completed verify that all protocols can be created via this dealer, ie that |
|
1081 // our worker thread is bound to all of the necessary players |
|
1082 TWorkerId host; |
|
1083 for(TInt idx = 1; owner.PitBoss().GetWorkerForProtocol(idx, host); ++idx) |
|
1084 { |
|
1085 if(!owner.PeerReachable(host)) |
|
1086 { |
|
1087 RDebug::Printf("ERROR worker %d is DefaultOptimalDealer but can't reach worker #%d for protocol #%d", owner.WorkerId(), host, idx); |
|
1088 LOG(ESockLog::Printf(KESockBootingTag, _L("ERROR worker %d is DefaultOptimalDealer but can't reach worker #%d for protocol #%d"), owner.WorkerId(), host, idx)); |
|
1089 Panic(EMisconfigured); |
|
1090 } |
|
1091 } |
|
1092 } |
|
1093 return ETrue; |
|
1094 } |
|
1095 #endif |
|
1096 |
|
1097 // |
|
1098 // CSockSessionProxy |
|
1099 // |
|
1100 CSockSessionProxy* CSockSessionProxy::NewL(CWorkerSession* aSockSession, CPlayer& aPlayer) |
|
1101 { |
|
1102 CSockSessionProxy* self = new(ELeave) CSockSessionProxy(aSockSession, aPlayer); |
|
1103 CleanupStack::PushL(self); |
|
1104 self->ConstructL(); |
|
1105 CleanupStack::Pop(self); |
|
1106 return self; |
|
1107 } |
|
1108 |
|
1109 CSockSessionProxy::CSockSessionProxy(CWorkerSession* aSockSession, CPlayer& aPlayer) |
|
1110 : CCommonSessionProxy(aSockSession, aPlayer) |
|
1111 { |
|
1112 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\tCSockSessionProxy(), iSockSession %08x"), this, Session()) ); |
|
1113 } |
|
1114 |
|
1115 void CSockSessionProxy::ConstructL() |
|
1116 { |
|
1117 iProtocols=new(ELeave) CArrayFixFlat<CProtocolBase *>(16); |
|
1118 } |
|
1119 |
|
1120 CSockSessionProxy::~CSockSessionProxy() |
|
1121 { |
|
1122 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\t~CSockSessionProxy(), iSockSession %08x"), this, Session()) ); |
|
1123 if(iProtocols) |
|
1124 { |
|
1125 for (TInt i=0;i<iProtocols->Count();i++) |
|
1126 { |
|
1127 LOG( |
|
1128 CProtocolBase* p = iProtocols->operator[](i); |
|
1129 const TDesC& tag(p->Tag()); |
|
1130 ESockLog::Printf(KESockSessDetailTag, _L("CSockSessionProxy %08x:\t~CSockSessionProxy(): closing protocol %08x '%S'"), this, p, &tag) |
|
1131 ); |
|
1132 |
|
1133 iProtocols->operator[](i)->Close(); |
|
1134 } |
|
1135 iProtocols->Delete(0,iProtocols->Count()); |
|
1136 delete iProtocols; |
|
1137 } |
|
1138 } |
|
1139 |
|
1140 void CSockSessionProxy::AddProtocolL(CProtocolBase* aProtocol) |
|
1141 { |
|
1142 LOG( |
|
1143 const TDesC& tag(aProtocol->Tag()); |
|
1144 ESockLog::Printf(KESockSessDetailTag, _L("CSockSessionProxy %08x:\tAddProtocolL(aProtocol %08x '%S'), iSockSession %08x"), this, aProtocol, &tag, Session()); |
|
1145 ); |
|
1146 for(TInt i=0;i<iProtocols->Count();i++) |
|
1147 { |
|
1148 if (iProtocols->operator[](i)==aProtocol) |
|
1149 { |
|
1150 return; |
|
1151 } |
|
1152 } |
|
1153 |
|
1154 iProtocols->AppendL(aProtocol); |
|
1155 aProtocol->Open(); |
|
1156 } |
|
1157 |
|
1158 void CSockSessionProxy::RemoveProtocolL(CProtocolBase* aProtocol) |
|
1159 { |
|
1160 LOG(ESockLog::Printf(KESockSessDetailTag, _L8("CSockSessionProxy %08x:\tRemoveProtocolL(), iSockSession %08x"), this, Session()) ); |
|
1161 |
|
1162 CProtocolBase* p=0; |
|
1163 TInt j; |
|
1164 for(j=0;j<iProtocols->Count();j++) |
|
1165 { |
|
1166 if (iProtocols->operator[](j)==aProtocol) |
|
1167 { |
|
1168 p=iProtocols->operator[](j); |
|
1169 break; |
|
1170 } |
|
1171 } |
|
1172 if(!p) |
|
1173 { |
|
1174 User::Leave(KErrNotFound); |
|
1175 } |
|
1176 |
|
1177 // in the absence of checking this protocol is not specifically referenced |
|
1178 // check no resources are referenced |
|
1179 if(Session()->SubSessions().ActiveCount()) |
|
1180 { |
|
1181 User::Leave(KErrInUse); |
|
1182 } |
|
1183 |
|
1184 p->Close(); |
|
1185 iProtocols->Delete(j); |
|
1186 iProtocols->Compress(); |
|
1187 } |
|
1188 |
|
1189 // |
|
1190 // CPitBoss |
|
1191 // |
|
1192 |
|
1193 CPitBoss* CPitBoss::NewL(CWorkerThread* aOwnerThread) |
|
1194 { |
|
1195 CPitBoss* self = new(ELeave) CPitBoss(aOwnerThread); |
|
1196 CleanupStack::PushL(self); |
|
1197 self->ConstructL(); |
|
1198 CleanupStack::Pop(self); |
|
1199 return self; |
|
1200 } |
|
1201 |
|
1202 CPitBoss::~CPitBoss() |
|
1203 { |
|
1204 // Delete the list of removed protocols |
|
1205 TProtocolPairing* pair = iDeadPairHead; |
|
1206 while(pair) |
|
1207 { |
|
1208 TProtocolPairing* nextPair = pair->iNextDead; |
|
1209 delete pair; |
|
1210 pair = nextPair; |
|
1211 } |
|
1212 pair = iProtocolPairHead; |
|
1213 while(pair) |
|
1214 { |
|
1215 TProtocolPairing* nextPair = pair->iNextPair; |
|
1216 delete pair; |
|
1217 pair = nextPair; |
|
1218 } |
|
1219 delete iCompleteEskList; |
|
1220 } |
|
1221 |
|
1222 |
|
1223 CPitBoss::CPitBoss(CWorkerThread* aOwnerThread) |
|
1224 : CCommonPitBoss(aOwnerThread) |
|
1225 { |
|
1226 } |
|
1227 |
|
1228 void CPitBoss::ConstructL() |
|
1229 { |
|
1230 iCompleteEskList = new(ELeave) CommsFW::COwnEntryList(6); |
|
1231 iCompleteEskList->UniqueWildScanAcrossDrivesL(KEsockIniFileDir, KEsockWildCard); |
|
1232 CommsFW::COwnEntryList *noBackupEskList = new(ELeave) CommsFW::COwnEntryList(32); |
|
1233 CleanupStack::PushL(noBackupEskList); |
|
1234 noBackupEskList->UniqueWildScanAcrossDrivesL(KEsockNoBackupDir, KEsockWildCard); |
|
1235 iCompleteEskList->AddL(*noBackupEskList); |
|
1236 iPropertyKey=RootServer::KUidC32StartPropertyKey; |
|
1237 CleanupStack::PopAndDestroy(noBackupEskList); |
|
1238 CCommonPitBoss::ConstructL(); |
|
1239 } |
|
1240 |
|
1241 TBool CPitBoss::GetWorkerForProtocol(TUint aAddrFamily, TUint aSockType, TUint aProtocol, TWorkerId& aWorker) const |
|
1242 { |
|
1243 #ifdef _DEBUG |
|
1244 aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value |
|
1245 #endif |
|
1246 TProtocolPairing* pair = FindProtocolPairing(aAddrFamily, aSockType, aProtocol); |
|
1247 if(pair) |
|
1248 { |
|
1249 aWorker = pair->iWorkerId; |
|
1250 return aWorker != TWorkerThreadPublicInfo::ENullWorkerId; |
|
1251 } |
|
1252 return EFalse; |
|
1253 } |
|
1254 |
|
1255 void CPitBoss::DoFreeWorkerReferences(TWorkerId aWorkerId) |
|
1256 { |
|
1257 LOG(ESockLog::Printf(_L("CPitBoss::DoFreeWorkerReferences(%d)"), aWorkerId) ); |
|
1258 #if defined _DEBUG && !defined(ESOCKV3_TEMPORARY_PAIN_RELIEF) |
|
1259 // The RootServer normally checks the heap for leaks when the module unloads |
|
1260 // but for ESOCK modules this is commonly too early, since the PitBoss holds |
|
1261 // its reference open until the cleanup completes. Hence here we check for |
|
1262 // remaining allocations if we hold the last reference and if no thread |
|
1263 // which used it died involuntarily |
|
1264 RCFSharedHeap& heap = static_cast<RCFSharedHeap&>(*WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iHeap); |
|
1265 TInt leakCount = heap.Count(); // make it accessible for conditional breakpoints |
|
1266 LOG(ESockLog::Printf(_L8("~~~CPitBoss::FreeWorkerReferences heap(%08x).AccessCount()==%d, cell count=%d"), (TUint) &heap, heap.AccessCount(), leakCount)); |
|
1267 if(!iForsakenHeapList.IsForsaken(&heap)) |
|
1268 { |
|
1269 if(heap.AccessCount() <= 2) // Oddity: where does the other count come from, ie why not "1" when RS has already closed? And who does close it later? |
|
1270 { |
|
1271 if(leakCount > 0) |
|
1272 { |
|
1273 LOG(ESockLog::Printf(_L8("(log recorded under tags \"%S\" \"%S\" - you may need to enable these)"), &RootServer::KLogSubSysRSModule, &RootServer::KLogRSLeakTag)); |
|
1274 heap.LogAllocatedCells(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag); |
|
1275 |
|
1276 RProperty pubsub; |
|
1277 TInt res = pubsub.Attach(RootServer::KUidCommsProcess, RootServer::KUidCommsModuleLeakCounter); |
|
1278 //No nead for cleanup stack, cannot leave before Close |
|
1279 if (res == KErrNone) |
|
1280 { |
|
1281 TInt count; |
|
1282 res =pubsub.Get(count); |
|
1283 if (res == KErrNone) |
|
1284 { |
|
1285 count += heap.Count(); |
|
1286 res =pubsub.Set(count); |
|
1287 } |
|
1288 } |
|
1289 pubsub.Close(); |
|
1290 if (res != KErrNone) |
|
1291 { |
|
1292 __CFLOG_1(RootServer::KLogSubSysRSModule, RootServer::KLogRSLeakTag, _L8("Unable to report leaks. Error: %d"), res); |
|
1293 } |
|
1294 // As much as anything this log line is here to make it apparent that the breakpoint above was hit |
|
1295 LOG(ESockLog::Printf(_L8("--- end of leaked cell log"))); |
|
1296 } |
|
1297 } |
|
1298 } |
|
1299 |
|
1300 #else |
|
1301 // Preventing unused variable warnings. |
|
1302 (void)aWorkerId; |
|
1303 #endif |
|
1304 } |
|
1305 |
|
1306 TBool CPitBoss::GetWorkerForProtocol(TUint aIndex, TWorkerId& aWorker) const |
|
1307 { |
|
1308 #ifdef _DEBUG |
|
1309 aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value |
|
1310 #endif |
|
1311 if (aIndex == 0) |
|
1312 { |
|
1313 return EFalse; // protocol indices are 1-based |
|
1314 } |
|
1315 |
|
1316 /* Move pointer to protocol@index or end of list */ |
|
1317 TProtocolPairing* pair = iProtocolPairHead; |
|
1318 TUint i = 1; |
|
1319 while(pair) |
|
1320 { |
|
1321 // This function only exists to support the client ability to retrieve a protocol by index, and they're only |
|
1322 // interested in externally accessible protocols. So we skip magic ones. See also CPitBoss::GetNumProtocols() |
|
1323 if(pair->iSockType < KReservedSockTypesBase) |
|
1324 { |
|
1325 if(i == aIndex) |
|
1326 { |
|
1327 break; |
|
1328 } |
|
1329 ++i; |
|
1330 } |
|
1331 pair = pair->iNextPair; |
|
1332 } |
|
1333 |
|
1334 if(pair) |
|
1335 { |
|
1336 aWorker = pair->iWorkerId; |
|
1337 return aWorker != TWorkerThreadPublicInfo::ENullWorkerId; |
|
1338 } |
|
1339 return EFalse; |
|
1340 } |
|
1341 |
|
1342 TBool CPitBoss::GetWorkerForProtocolByName(const TProtocolName& aName, TWorkerId& aWorker) const |
|
1343 { |
|
1344 #ifdef _DEBUG |
|
1345 aWorker = TWorkerThreadPublicInfo::ENullWorkerId; // ensure arg is polluted, lest caller ignore return value |
|
1346 #endif |
|
1347 for(TProtocolPairing* pair = iProtocolPairHead; pair != NULL; pair = pair->iNextPair) |
|
1348 { |
|
1349 // Match the name (case insensitive) |
|
1350 if(aName.CompareF(pair->iName) == 0) |
|
1351 { |
|
1352 aWorker = pair->iWorkerId; |
|
1353 return aWorker != TWorkerThreadPublicInfo::ENullWorkerId; |
|
1354 } |
|
1355 } |
|
1356 return EFalse; |
|
1357 } |
|
1358 |
|
1359 /** |
|
1360 Return worker which can accept a NULL Socket. Default favours a specific worker, but |
|
1361 if it is not installed return the first real worker in the list. This algorithmn could change |
|
1362 or default selection be made configurable. |
|
1363 @param aWorker Id of the worker which can accept a NULL socket. Unchanged if none found. |
|
1364 */ |
|
1365 TBool CPitBoss::GetWorkerForNullSocket(TWorkerId& aWorker) const |
|
1366 { |
|
1367 TBool found=EFalse; |
|
1368 //First check if SMS WAP Worker is available by looking up heap pointer |
|
1369 if(WorkerDataGlobals().WorkerPresent(TCFWorkerThreadPublicInfo::ESmsWapPlayerThread)) |
|
1370 { |
|
1371 aWorker=TCFWorkerThreadPublicInfo::ESmsWapPlayerThread; |
|
1372 found=ETrue; |
|
1373 } |
|
1374 else if(iProtocolPairHead && iProtocolPairHead->iWorkerId>0) // Take first worker in list |
|
1375 { |
|
1376 // Scan for the first valid worker (not all entries are for real protocols and some have null worker ids) |
|
1377 for(TProtocolPairing* pair = iProtocolPairHead; !found && pair != NULL; pair = pair->iNextPair) |
|
1378 { |
|
1379 if(pair->iWorkerId != TWorkerThreadPublicInfo::ENullWorkerId) |
|
1380 { |
|
1381 aWorker = pair->iWorkerId; |
|
1382 found = ETrue; |
|
1383 } |
|
1384 } |
|
1385 } |
|
1386 return found; |
|
1387 } |
|
1388 |
|
1389 /** |
|
1390 Return the number of known protocols. Counts by walking through the short list, so |
|
1391 not a super fast operation but very rarely called. Implement threadsafe (if needed) counters |
|
1392 on a rainy day. |
|
1393 */ |
|
1394 TUint CPitBoss::GetNumProtocols() |
|
1395 { |
|
1396 TUint num=0; |
|
1397 // Count pairings that represent real protocols. The top range of sock types are reserved for internal trickery |
|
1398 for(TProtocolPairing* pair = iProtocolPairHead; pair!=NULL; pair=pair->iNextPair) |
|
1399 { |
|
1400 if(pair->iSockType < KReservedSockTypesBase) |
|
1401 { |
|
1402 num++; |
|
1403 } |
|
1404 } |
|
1405 return num; |
|
1406 } |
|
1407 |
|
1408 |
|
1409 TBool CPitBoss::GetWorkerForTier(TInt aTierId, TWorkerId& aWorker) const |
|
1410 { |
|
1411 return GetWorkerForProtocol(KTierEntryProxyAddrFam, KTierEntryProxySockType, aTierId, aWorker); |
|
1412 } |
|
1413 |
|
1414 |
|
1415 /** |
|
1416 Lookup a entry with the specified characteristics in the list of protocol pairings. |
|
1417 @see CPitBoss::TProtocolPairing |
|
1418 */ |
|
1419 CPitBoss::TProtocolPairing* CPitBoss::FindProtocolPairing(TUint aAddrFamily, TUint aSockType, TUint aProtocol) const |
|
1420 { |
|
1421 TProtocolPairing* pair = iProtocolPairHead; |
|
1422 while(pair) |
|
1423 { |
|
1424 if(pair->iAddrFamily == aAddrFamily && |
|
1425 (pair->iSockType == KUndefinedSockType || aSockType == KUndefinedSockType || pair->iSockType == aSockType) && |
|
1426 (pair->iProtocol == KUndefinedProtocol || aProtocol == KUndefinedProtocol || pair->iProtocol == aProtocol)) |
|
1427 { |
|
1428 LOG( ESockLog::Printf(KESockSessDetailTag, _L("CPitBoss::FindProtocolPairing() - [aAddrFamily=%08x] [aSockType=%08x] [aProtocol=%08x] found '%S' W%d"), |
|
1429 aAddrFamily, aSockType, aProtocol, &pair->iName, pair->iWorkerId)); |
|
1430 return pair; |
|
1431 } |
|
1432 pair = pair->iNextPair; |
|
1433 } |
|
1434 |
|
1435 LOG( ESockLog::Printf(KESockSessDetailTag, _L("CPitBoss::FindProtocolPairing() - [aAddrFamily=%08x] [aSockType=%08x] [aProtocol=%08x] - no match"), |
|
1436 aAddrFamily, aSockType, aProtocol)); |
|
1437 return NULL; |
|
1438 } |
|
1439 |
|
1440 /** |
|
1441 Given session preferences, see if the Player supporting those protocol |
|
1442 characteristics has its own Dealer. |
|
1443 */ |
|
1444 TBool CPitBoss::FindOptimalDealer(const TSessionPref& aPref, CCommonWorkerDealer*& aDealer) |
|
1445 { |
|
1446 TBool found=EFalse; |
|
1447 if(aPref.iAddrFamily == KUndefinedAddressFamily && aPref.iProtocol == KUndefinedProtocol) |
|
1448 { |
|
1449 // Client is asking for the default optimal dealer - if this isn't (yet) known then we quickly fail the request rather than possibly |
|
1450 // waiting for boot to complete, which might disrupt carefully tuned boot orders - we're better off foregoing the mild optimisation |
|
1451 if(iDefaultOptimalDealer != Den::TWorkerThreadPublicInfo::EMainThread) |
|
1452 { |
|
1453 found = CCommonPitBoss::FindOptimalDealer(iDefaultOptimalDealer, aDealer); |
|
1454 } |
|
1455 } |
|
1456 else |
|
1457 { |
|
1458 const TProtocolPairing* pair=FindProtocolPairing(aPref.iAddrFamily, KUndefinedSockType, aPref.iProtocol); |
|
1459 if(pair) |
|
1460 { |
|
1461 found = CCommonPitBoss::FindOptimalDealer(pair->iWorkerId, aDealer); |
|
1462 } |
|
1463 } |
|
1464 return found; |
|
1465 } |
|
1466 |
|
1467 CPitBoss::TProtocolPairingOwner::TProtocolPairingOwner() |
|
1468 : iHead(NULL) |
|
1469 { |
|
1470 } |
|
1471 |
|
1472 void CPitBoss::TProtocolPairingOwner::Append(TProtocolPairing* aNode) |
|
1473 { |
|
1474 if(iHead == NULL) |
|
1475 { |
|
1476 iHead = aNode; |
|
1477 } |
|
1478 else |
|
1479 { |
|
1480 TProtocolPairing* curr = iHead; |
|
1481 TProtocolPairing* prev; |
|
1482 do |
|
1483 { |
|
1484 prev = curr; |
|
1485 curr = curr->iNextPair; |
|
1486 } |
|
1487 while(curr != NULL); |
|
1488 prev->iNextPair = aNode; |
|
1489 } |
|
1490 } |
|
1491 |
|
1492 void CPitBoss::TProtocolPairingOwner::Release() |
|
1493 { |
|
1494 TProtocolPairing* curr = iHead; |
|
1495 while(curr != NULL) |
|
1496 { |
|
1497 TProtocolPairing* next = curr->iNextPair; |
|
1498 delete curr; |
|
1499 curr = next; |
|
1500 } |
|
1501 iHead = NULL; |
|
1502 } |
|
1503 |
|
1504 |
|
1505 void CPitBoss::AddProtocolToListL(TUint aAddrFamily, TUint aSockType, TUint aProtocol, const TProtocolName& aName, TWorkerId aWorker, TProtocolPairingOwner& aList) |
|
1506 { |
|
1507 TProtocolPairing* pair = new(ELeave) TProtocolPairing; |
|
1508 pair->iAddrFamily = aAddrFamily; |
|
1509 pair->iSockType = aSockType; |
|
1510 pair->iProtocol = aProtocol; |
|
1511 pair->iName = aName; |
|
1512 pair->iWorkerId = aWorker; |
|
1513 pair->iNextDead = NULL; |
|
1514 pair->iNextPair = NULL; |
|
1515 aList.Append(pair); |
|
1516 } |
|
1517 |
|
1518 void CPitBoss::IncorporateProtocolListL(TProtocolPairingOwner& aList) |
|
1519 { |
|
1520 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss::IncorporateProtocolList(%08x)"), &aList) ); |
|
1521 // Only safe from the main thread; thread race below |
|
1522 __ASSERT_DEBUG(iOwnerThread->IsMainThread(), User::Panic(KSpecAssert_ESockSSocks_rls, 14)); |
|
1523 |
|
1524 #ifdef _DEBUG |
|
1525 // In UDEB check whether any pair entry already exists - if so that's a serious config mistake and we panic the miscreant diagnostically |
|
1526 // In UREL we just ignore this possibility and let things limp on as best they can |
|
1527 TProtocolPairing* curr = aList.iHead; |
|
1528 while(curr != NULL) |
|
1529 { |
|
1530 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Adding protocol %S [fam,sock,prot]=[%x,%x,%x] for W%d"), &curr->iName, curr->iAddrFamily, curr->iSockType, curr->iProtocol, curr->iWorkerId) ); |
|
1531 TProtocolPairing* existing = FindProtocolPairing(curr->iAddrFamily, curr->iSockType, curr->iProtocol); |
|
1532 if(existing) |
|
1533 { |
|
1534 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: already present as protocol %S for W%d"), &existing->iName, existing->iWorkerId) ); |
|
1535 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Killing misconfigured W%d. To fix this look at the lists of .ESK files logged earlier for the two workers and ensure only one loads the protocol"), curr->iWorkerId) ); |
|
1536 WorkerDataGlobals().PanicWorker(curr->iWorkerId, KESockProtocolPanic, ECorruptIniData); |
|
1537 User::Leave(KErrAlreadyExists); |
|
1538 } |
|
1539 curr = curr->iNextPair; |
|
1540 } |
|
1541 #endif |
|
1542 aList.Append(iProtocolPairHead); |
|
1543 NETWORKING_ATOMIC(iProtocolPairHead = aList.iHead); // atomic write of new ptr is guaranteed; it's ok to link it in before the worker ids are set |
|
1544 // as any competing protocol lookups will politely fail |
|
1545 } |
|
1546 |
|
1547 |
|
1548 /** |
|
1549 When a worker thread dies (e.g. during shutdown) the PitBoss will discover and use this method to |
|
1550 remove the protocol pairings for that particular worker. |
|
1551 */ |
|
1552 void CPitBoss::RemoveProtocolPairingsForWorker(TWorkerId aWorkerId) |
|
1553 { |
|
1554 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss::RemoveProtocolPairingsForWorker(%d)"), aWorkerId) ); |
|
1555 TProtocolPairing* pair = iProtocolPairHead; |
|
1556 TProtocolPairing* prevLive = NULL; |
|
1557 while(pair) |
|
1558 { |
|
1559 if(pair->iWorkerId == aWorkerId) |
|
1560 { |
|
1561 LOG(ESockLog::Printf(KESockBootingTag, _L("CPitBoss: Removing protocol %S [fam,sock,prot]=[%x,%x,%x] for W%d"), &pair->iName, pair->iAddrFamily, pair->iSockType, pair->iProtocol, pair->iWorkerId) ); |
|
1562 if(prevLive) |
|
1563 { |
|
1564 NETWORKING_ATOMIC(prevLive->iNextPair = pair->iNextPair); // atomic write of new ptr is guaranteed |
|
1565 } |
|
1566 else |
|
1567 { |
|
1568 NETWORKING_ATOMIC(iProtocolPairHead = pair->iNextPair); // atomic write of new ptr is guaranteed |
|
1569 } |
|
1570 pair->iNextDead = iDeadPairHead; |
|
1571 NETWORKING_ATOMIC(iDeadPairHead = pair); // atomic write of new ptr is guaranteed |
|
1572 } |
|
1573 else |
|
1574 { |
|
1575 prevLive = pair; |
|
1576 } |
|
1577 pair = pair->iNextPair; |
|
1578 } |
|
1579 } |
|
1580 |
|
1581 void CPitBoss::AddTierPairingToListL(TInt aTierUid, const TDesC& aTierName, TWorkerId aWorker, TProtocolPairingOwner& aList) |
|
1582 { |
|
1583 AddProtocolToListL(KTierEntryProxyAddrFam, KTierEntryProxySockType, aTierUid, aTierName, aWorker, aList); |
|
1584 } |
|
1585 |
|
1586 const CommsFW::COwnEntryList* CPitBoss::GetCompleteList() |
|
1587 { |
|
1588 return iCompleteEskList; |
|
1589 } |
|
1590 |
|
1591 /** |
|
1592 Used during binding when the PitBoss receives a introduction response message from a worker. |
|
1593 The PitBoss will set-up housekeeping datastructures for the worker and add the supported |
|
1594 protocols to its list of protocol pairings. |
|
1595 @see TWorkerMsg::EMainIntroductionResp |
|
1596 */ |
|
1597 void CPitBoss::DoProcessWorkerIntroductionL(const TWorkerIntroductionMsg& aMsg) |
|
1598 { |
|
1599 // Now populate the protocol pairing list |
|
1600 TProtocolPairingOwner pairList; |
|
1601 CleanupReleasePushL(pairList); |
|
1602 const TWorkerThreadPublicInfo& msgInfo = aMsg.WorkerInfo(); |
|
1603 CPlayer* player=static_cast<CPlayer*>(GetPlayer(aMsg)); |
|
1604 |
|
1605 if(player) |
|
1606 { |
|
1607 TProtocolDesc prot; |
|
1608 for(TUint protNum = 1; player->ProtocolInfo(protNum, prot) == KErrNone; ++protNum) |
|
1609 { |
|
1610 AddProtocolToListL(prot.iAddrFamily, prot.iSockType, prot.iProtocol, prot.iName, msgInfo.iWorkerId, pairList); |
|
1611 } |
|
1612 |
|
1613 // Add proxy protocol pairings for any special roles |
|
1614 if(player->HasTierResolver()) |
|
1615 { |
|
1616 #ifdef _DEBUG |
|
1617 TWorkerId alternateTierResolverWorker; |
|
1618 __ASSERT_DEBUG(!GetWorkerForPlayerRole(KPlayerRoleTierResolver, alternateTierResolverWorker), User::Panic(KSpecAssert_ESockSSocks_rls, 15)); |
|
1619 #endif |
|
1620 _LIT(KTierResolverDesc, "TierResolver"); |
|
1621 AddPlayerRolePairingL(KPlayerRoleTierResolver, KTierResolverDesc, msgInfo.iWorkerId, pairList); |
|
1622 } |
|
1623 } |
|
1624 IncorporateProtocolListL(pairList); |
|
1625 CleanupStack::Pop(&pairList); |
|
1626 |
|
1627 TBuf8<TWorkerIntroductionMsg::KMaxIntroductionInfoSize> introInfo; |
|
1628 aMsg.IntroductionInfo(introInfo); |
|
1629 TPckgBuf<TBool> defaultOptDealer; |
|
1630 defaultOptDealer.Copy(introInfo.LeftTPtr(defaultOptDealer.MaxSize())); |
|
1631 if(defaultOptDealer()) |
|
1632 { |
|
1633 if(iDefaultOptimalDealer == Den::TWorkerThreadPublicInfo::EMainThread) |
|
1634 { |
|
1635 iDefaultOptimalDealer = msgInfo.iWorkerId; |
|
1636 } |
|
1637 else |
|
1638 { |
|
1639 LOG(ESockLog::Printf(KESockBootingTag, _L("ERROR worker %d claiming DefaultOptimalDealer after worker %d already did so"), msgInfo.iWorkerId, iDefaultOptimalDealer)); |
|
1640 #ifdef _DEBUG |
|
1641 RDebug::Printf("ERROR worker %d claiming DefaultOptimalDealer after worker %d already did so", msgInfo.iWorkerId, iDefaultOptimalDealer); |
|
1642 Panic(EMisconfigured); |
|
1643 #endif |
|
1644 } |
|
1645 } |
|
1646 } |
|
1647 |
|
1648 /** |
|
1649 The PitBoss monitors the Comms Configurator sequence level and when the core components |
|
1650 have been configured (this includes ESock) this method is called to delete any data structures |
|
1651 used only during startup of ESock. |
|
1652 @see CConfigurationLevelMonitor |
|
1653 @see CPitBoss::iPendingIntroResponses |
|
1654 */ |
|
1655 void CPitBoss::DoOnCPMsConfigured() |
|
1656 { |
|
1657 // We can now delete the shared ESK data and enable simulated failure for the main thread (if configured) |
|
1658 if(iPendingIntroResponses == 0) |
|
1659 { |
|
1660 delete iCompleteEskList; |
|
1661 iCompleteEskList = NULL; |
|
1662 } |
|
1663 if(iLoadTierMappingPhase == EDealerRequest) |
|
1664 { |
|
1665 // Was awaiting boot completion to find the tier resolver |
|
1666 SendLoadTierMappingRequest(); |
|
1667 } |
|
1668 } |
|
1669 |
|
1670 /** |
|
1671 If a worker dies the PitBoss will call this method. It will clean up the housekeeping datastructures |
|
1672 related to the worker and it will spawn the RedShirt thread which will try to delete the workers own |
|
1673 data structures. It is a best effort attempt that doesn't guarantee to free up all the dead workers memory |
|
1674 and the RedShirt could be PANICed by the kernel, which is why a short lived seperate thread is doing it. |
|
1675 */ |
|
1676 void CPitBoss::DoOnPeerDeath(TWorkerId aWorkerId) |
|
1677 { |
|
1678 // If worker ran a Player all its protocol pairings are now dead. We can't know whether the thread actually |
|
1679 // did run a Player as (presuming it exited cleanly) it cleaned up, but it's adequately cheap & a rare case |
|
1680 RemoveProtocolPairingsForWorker(aWorkerId); |
|
1681 } |
|
1682 |
|
1683 struct ESockThreadStartupInfo |
|
1684 { |
|
1685 #ifdef SYMBIAN_ZERO_COPY_NETWORKING |
|
1686 RCommsBufPond iCommsBufPond; |
|
1687 #else |
|
1688 CMBufManager* iMBufManager; |
|
1689 #endif // SYMBIAN_ZERO_COPY_NETWORKING |
|
1690 |
|
1691 TAny* iModuleArgs; |
|
1692 __CFLOG_STMT(CCFLogIf* iCFLogIf;) |
|
1693 }; |
|
1694 |
|
1695 TInt RESockCleanupThreadFunction(TAny* aStartupInfo) |
|
1696 /** |
|
1697 Intermediate function which masquerades as the main thread function in order to |
|
1698 perform some specific actions for the new thread in the correct context before |
|
1699 calling the new thread's actual main thread function. |
|
1700 The thread must be resumed after being created or the startup info structure |
|
1701 cannot be deleted by the thread and will be leaked |
|
1702 @param aStartupInfo structure containing pointers to MBufMger and CFlog. |
|
1703 @see RCFThread::ThreadStartupInfo |
|
1704 @internalComponent |
|
1705 */ |
|
1706 { |
|
1707 ESockThreadStartupInfo* startInfo = reinterpret_cast<ESockThreadStartupInfo*>(aStartupInfo); |
|
1708 #ifdef SYMBIAN_ZERO_COPY_NETWORKING |
|
1709 TCommsBufPondTLSOp tls(startInfo->iCommsBufPond); |
|
1710 tls.Set(); |
|
1711 #else |
|
1712 startInfo->iMBufManager->SetContext(); |
|
1713 #endif // SYMBIAN_ZERO_COPY_NETWORKING |
|
1714 |
|
1715 |
|
1716 __CFLOG_STMT( startInfo->iCFLogIf->SetContext(); ) |
|
1717 __CFLOG_OPEN; |
|
1718 |
|
1719 TInt result = CCommonWorkerThread::PostMortemCleanupThreadEntry(startInfo->iModuleArgs); |
|
1720 |
|
1721 __CFLOG_CLOSE; |
|
1722 delete startInfo; |
|
1723 |
|
1724 return result; |
|
1725 }; |
|
1726 |
|
1727 TInt CPitBoss::DoCreateRedShirt(RThread& aRedShirt, CommsFW::TWorkerId aWorkerId, Den::CCommonWorkerThread& aDeadWorker) |
|
1728 { |
|
1729 // Get the heap to assign to the red shirt thread and switch to it so we |
|
1730 // can allocate the thread startup info structure. |
|
1731 RAllocator* heap = WorkerDataGlobals().GetWorkerGlobals(aWorkerId)->iHeap; |
|
1732 RHeap* prevHeap = User::SwitchHeap(heap); |
|
1733 |
|
1734 // We must not pass the thread a structure allocated on the stack because it |
|
1735 // will go out of scope before the caller calls RThread::Resume so we create |
|
1736 // it dynamically in the thread's heap. |
|
1737 // The thread is responsible for deleting the structure when it no longer |
|
1738 // needs it. For this reason, if the thread is successfully created the |
|
1739 // caller MUST resume the thread and allow it to run or else it will be |
|
1740 // leaked. |
|
1741 ESockThreadStartupInfo* startupInfo = new ESockThreadStartupInfo; |
|
1742 User::SwitchHeap(prevHeap); |
|
1743 |
|
1744 TInt err = KErrNone; |
|
1745 |
|
1746 if( startupInfo ) |
|
1747 { |
|
1748 startupInfo->iModuleArgs = &aDeadWorker; |
|
1749 #ifdef SYMBIAN_ZERO_COPY_NETWORKING |
|
1750 startupInfo->iCommsBufPond = TCommsBufPondTLSOp::Get(); |
|
1751 if(startupInfo->iCommsBufPond.IsNull()) |
|
1752 { |
|
1753 err = KErrNotFound; |
|
1754 } |
|
1755 #else |
|
1756 startupInfo->iMBufManager = CMBufManager::Context(); |
|
1757 if(startupInfo->iMBufManager == NULL) |
|
1758 { |
|
1759 err = KErrNotFound; |
|
1760 } |
|
1761 #endif // SYMBIAN_ZERO_COPY_NETWORKING |
|
1762 |
|
1763 // Check to make sure the logger is available. |
|
1764 #ifdef __CFLOG_ACTIVE |
|
1765 else |
|
1766 { |
|
1767 __CFLOG_STMT(startupInfo->iCFLogIf = CCFLogIf::Context()); |
|
1768 if(!startupInfo->iCFLogIf) |
|
1769 { |
|
1770 RDebug::Print( _L( "RCFThread::Create - the log interface was not found. This normally means that the logging version of commsfw.dll has been mixed with a stub version of cflog.dll. See CommsDebugUtility How-To Document FAQ section for details on enabling logging in a release build." )); |
|
1771 |
|
1772 err = KErrNotFound; |
|
1773 } |
|
1774 } |
|
1775 #endif |
|
1776 |
|
1777 if(err == KErrNone) |
|
1778 { |
|
1779 err = aRedShirt.Create(KNullDesC, RESockCleanupThreadFunction, 8192, static_cast<RHeap*>(heap), startupInfo); |
|
1780 } |
|
1781 // If any error occured, delete the startup info structure. |
|
1782 if(err != KErrNone) |
|
1783 { |
|
1784 prevHeap = User::SwitchHeap(heap); |
|
1785 delete startupInfo; |
|
1786 User::SwitchHeap(prevHeap); |
|
1787 } |
|
1788 } |
|
1789 else |
|
1790 { |
|
1791 err = KErrNoMemory; |
|
1792 CleanupStack::Pop(startupInfo); |
|
1793 } |
|
1794 |
|
1795 return err; |
|
1796 } |
|
1797 |
|
1798 /** |
|
1799 Converts pit boss's protocol index to the local index |
|
1800 The pit boss maintains a global list of protocols while each worker thread |
|
1801 maintains its own list. Obviously the local list is shorter than the global list |
|
1802 This function takes the Pitboss list index and comes back with one that is |
|
1803 applicable to the local list |
|
1804 @param aPitBossIndex the index to the pit boss's protocol list NB starts at 1 |
|
1805 @returns the index to the worker thread's list of protocols, -1 if not found |
|
1806 */ |
|
1807 TInt CPitBoss::GetLocalProtocolIndex(TInt aPitBossIndex) const |
|
1808 { |
|
1809 __ASSERT_DEBUG(aPitBossIndex > 0, User::Panic(KSpecAssert_ESockSSocks_rls, 16)); |
|
1810 TInt workers[TWorkerThreadPublicInfo::EMaxWorkerThreadId]; |
|
1811 Mem::FillZ(workers,sizeof(workers)); |
|
1812 |
|
1813 TInt lastBox = 0; |
|
1814 TProtocolPairing* pair = iProtocolPairHead; |
|
1815 |
|
1816 TInt i = 0; |
|
1817 while(i < aPitBossIndex) |
|
1818 { |
|
1819 __ASSERT_DEBUG(pair, User::Panic(KSpecAssert_ESockSSocks_rls, 17)); |
|
1820 if(pair->iSockType < KReservedSockTypesBase) |
|
1821 { |
|
1822 lastBox = pair->iWorkerId - 1; |
|
1823 __ASSERT_DEBUG(lastBox < TWorkerThreadPublicInfo::EMaxWorkerThreadId, User::Panic(KSpecAssert_ESockSSocks_rls, 18)); |
|
1824 ++(workers[lastBox]); |
|
1825 ++i; |
|
1826 } |
|
1827 pair = pair->iNextPair; |
|
1828 } |
|
1829 |
|
1830 TInt ret = workers[lastBox]; |
|
1831 return ret > 0 ? ret : -1; |
|
1832 } |
|
1833 |
|
1834 void CPitBoss::RequestLoadTierMapping() |
|
1835 { |
|
1836 if(iLoadTierMappingPhase == EStart) |
|
1837 { |
|
1838 if(ModuleConfigurationComplete()) |
|
1839 { |
|
1840 SendLoadTierMappingRequest(); |
|
1841 } |
|
1842 else |
|
1843 { |
|
1844 iLoadTierMappingPhase = EDealerRequest; |
|
1845 } |
|
1846 } |
|
1847 } |
|
1848 |
|
1849 void CPitBoss::SendLoadTierMappingRequest() |
|
1850 { |
|
1851 TWorkerId worker; |
|
1852 if(GetWorkerForPlayerRole(KPlayerRoleTierResolver, worker)) |
|
1853 { |
|
1854 TWorkerLoadTierMappings msg; |
|
1855 WorkerThread().PostMessage(worker, msg); |
|
1856 iLoadTierMappingPhase = EResolverRequested; |
|
1857 } |
|
1858 else |
|
1859 { |
|
1860 LOG(ESockLog::Printf(_L8("CPitBoss::SendLoadTierMappingRequest() *** NO TIER RESOLVER CONFIGURED *** "))); |
|
1861 __ASSERT_DEBUG(0, Panic(EMisconfigured)); // configuration is so broken that leaving user in ignorance is probably unhelpful |
|
1862 TRAP_IGNORE(OnTierMappingLoadedL(NULL, TWorkerThreadPublicInfo::ENullWorkerId)); // without the resolver's help all we can do is fail the tier requests |
|
1863 } |
|
1864 } |
|
1865 |
|
1866 void CPitBoss::PopulateAndAddProtocolPairListL(TProtocolName& tierDesc, RTierThreadMap* map) |
|
1867 { |
|
1868 TProtocolPairingOwner pairList; |
|
1869 CleanupReleasePushL(pairList); |
|
1870 |
|
1871 for(TInt i = map->Count() - 1; i >=0; --i) |
|
1872 { |
|
1873 const TTierMapEntry& entry = (*map)[i]; |
|
1874 |
|
1875 #ifdef _DEBUG |
|
1876 tierDesc.Format(_L("#!#! Tier %08x"), entry.iUid); // make protocol pairing record self-descriptive for debugging |
|
1877 #endif |
|
1878 AddTierPairingToListL(entry.iUid, tierDesc, entry.iWorker, pairList); |
|
1879 } |
|
1880 IncorporateProtocolListL(pairList); |
|
1881 |
|
1882 CleanupStack::Pop(&pairList); |
|
1883 } |
|
1884 |
|
1885 void CPitBoss::OnTierMappingLoadedL(const TWorkerTierMappingsLoaded* aMappingMsg, TWorkerId aSenderId) |
|
1886 { |
|
1887 __ASSERT_DEBUG(iLoadTierMappingPhase == EResolverRequested, User::Panic(KSpecAssert_ESockSSocks_rls, 19)); |
|
1888 TProtocolName tierDesc; |
|
1889 |
|
1890 LOG(TInt numAdded = (aMappingMsg && aMappingMsg->TierMap())? aMappingMsg->TierMap()->Count(): 0); |
|
1891 if (aMappingMsg && aMappingMsg->TierMap()) |
|
1892 { |
|
1893 RTierThreadMap* map = const_cast<RTierThreadMap*>(aMappingMsg->TierMap()); |
|
1894 |
|
1895 TRAPD(err, PopulateAndAddProtocolPairListL(tierDesc, map)); |
|
1896 |
|
1897 // THeapSwitcher is not leave-safe and must be destroyed by going out of scope only. |
|
1898 // Our leave implementation does not guarantee that stack objects will be destroyed |
|
1899 // during a leave and although the current ARM implementation does do this because it |
|
1900 // uses the C++ exception handling mechanism internally, x86gcc does not support this. |
|
1901 { |
|
1902 THeapSwitcher switcher(*this, aSenderId); |
|
1903 |
|
1904 map->Close(); |
|
1905 delete map; |
|
1906 } |
|
1907 |
|
1908 if (err) |
|
1909 { |
|
1910 User::Leave(err); |
|
1911 } |
|
1912 } |
|
1913 |
|
1914 iLoadTierMappingPhase = EComplete; |
|
1915 |
|
1916 LOG(ESockLog::Printf(_L8("CPitBoss::OnTierMappingLoadedL() - %d tier entries added"), numAdded)); |
|
1917 // And tell all of the workers that tier mappings are ready for digestion |
|
1918 BroadcastConfigurationComplete(ETierMapping); |
|
1919 } |
|
1920 |