|
1 // Copyright (c) 1997-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 * |
|
19 * Implements CCommSession, CCommSubSession |
|
20 */ |
|
21 |
|
22 #include "CS_STD.H" |
|
23 #include "C32LOG.H" |
|
24 #include "cs_thread.h" |
|
25 #include "cs_roles.h" |
|
26 #include "cs_msgs.h" |
|
27 #include "cs_glob.h" |
|
28 #include <comms-infras/c32startcli.h> |
|
29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
30 #include <c32comm_internal.h> |
|
31 #endif |
|
32 |
|
33 |
|
34 class CCommSubSession; |
|
35 |
|
36 void PanicClient(TInt aPanic, const RMessagePtr2& aMessage) |
|
37 { |
|
38 if(aMessage.Handle() != 0) |
|
39 { |
|
40 aMessage.Panic(KCommServerName(), aPanic); |
|
41 } |
|
42 } |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 TWorkerId CCommSession::WorkerId() const |
|
50 { |
|
51 return Dealer().WorkerId(); |
|
52 } |
|
53 |
|
54 |
|
55 /** |
|
56 @param aMessage IPC message received from client. |
|
57 @param aSubSess Subsession that needs to deal with this message. |
|
58 */ |
|
59 void CCommSession::ForwardMessageL(const RMessage2 &aMessage, CCommSubSession& aSubSess) |
|
60 { |
|
61 ForwardMessageL(aMessage, &aSubSess, aSubSess.Player().WorkerId()); |
|
62 } |
|
63 |
|
64 /** Determine whether to deal with message directly or to send it on a channel. |
|
65 @param aMessage IPC message received from client. |
|
66 @param aWorkerId Id of worker that can handle this message. |
|
67 */ |
|
68 void CCommSession::ForwardMessageL(const RMessage2& aMessage, CCommSubSession* aSS, TWorkerId aWorker) |
|
69 { |
|
70 ASSERT(aWorker <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId); |
|
71 |
|
72 CC32WorkerThread& owner = C32WorkerThread(); |
|
73 |
|
74 /** |
|
75 While forwarding the message to player, Add player to disconnect list. While closing the session |
|
76 the disconnect list is used and session close message is forwarded to player. Only when session |
|
77 close response is received, the session is destroyed. |
|
78 */ |
|
79 // If the Player is co-resident in this worker thread |
|
80 if(owner.WorkerId()==aWorker) |
|
81 { |
|
82 AddPlayerToDisconnectList(aWorker); |
|
83 owner.Player()->ProcessMessageL(aMessage, aSS); |
|
84 DontCompleteCurrentRequest(); |
|
85 } |
|
86 else if(owner.PeerReachable(aWorker)) // Forward to Player thread |
|
87 { |
|
88 AddPlayerToDisconnectList(aWorker); |
|
89 TC32PlayerForwardRequestMsg msg(aMessage, aSS); |
|
90 owner.PostMessage(aWorker, msg); |
|
91 DontCompleteCurrentRequest(); |
|
92 const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage); |
|
93 forwardedMsg.NullHandle(); |
|
94 } |
|
95 else |
|
96 { |
|
97 C32LOG1(KC32Warning, _L8("CCommSession::ForwardMessageL() Peer Thread Unreachable")); |
|
98 DontCompleteCurrentRequest(); |
|
99 __ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); |
|
100 } |
|
101 } |
|
102 |
|
103 void CCommSession::ServiceError(const RMessage2& aMessage, TInt aError) |
|
104 { |
|
105 if (aError==KErrBadDescriptor) |
|
106 { |
|
107 // this completes message as well so we have to handle it in ServiceL |
|
108 PanicClient(EBadDescriptor,aMessage); |
|
109 return; |
|
110 } |
|
111 C32LOG1(KC32Detail, _L8("CCommSession::ServiceError() ServiceL leave occured")); |
|
112 inherited::ServiceError(aMessage,aError); |
|
113 } |
|
114 |
|
115 void CCommSession::ServiceL(const RMessage2& aMessage) |
|
116 /** |
|
117 * Handle messages for this session. |
|
118 * |
|
119 * @param aMessage handle to the IPC message from the client |
|
120 */ |
|
121 { |
|
122 C32LOG5(KC32Detail,_L8("CCommSession::ServiceL(), Session : 0x%x, IPC: %d (%S). Message: %08x"), this, aMessage.Function(), &TC32Log::C32RequestStr(aMessage.Function()),aMessage.Handle()); |
|
123 iComplete = ETrue; |
|
124 const CC32WorkerThread& owner=C32WorkerThread(); |
|
125 CC32Dealer& c32Dealer = owner.DealerByRef(); |
|
126 |
|
127 if (c32Dealer.StartupFailed()) |
|
128 { |
|
129 SafeComplete(aMessage, KErrNotReady); |
|
130 return; |
|
131 } |
|
132 |
|
133 // TestImmediateShutdownPresent is only set when EImmediate shutdown is present, which is |
|
134 // used only in testing phase. |
|
135 if(c32Dealer.TestImmediateShutdownPresent()) |
|
136 { |
|
137 User::Leave(KErrServerTerminated); |
|
138 } |
|
139 |
|
140 if((aMessage.Function()==ECommOpen) |
|
141 || |
|
142 (aMessage.Function()==ECommOpenWhenAvailable)) |
|
143 { |
|
144 NewPortL(aMessage); |
|
145 return; |
|
146 } |
|
147 |
|
148 #if defined (_DEBUG) |
|
149 switch (aMessage.Function()) |
|
150 { |
|
151 case ECommDbgMarkHeap: |
|
152 __UHEAP_MARK; |
|
153 SafeComplete(aMessage, KErrNone); |
|
154 return; |
|
155 case ECommDbgCheckHeap: |
|
156 __UHEAP_CHECK(aMessage.Int0()); |
|
157 SafeComplete(aMessage, KErrNone); |
|
158 return; |
|
159 case ECommDbgMarkEnd: |
|
160 __UHEAP_MARKENDC(aMessage.Int0()); |
|
161 SafeComplete(aMessage, KErrNone); |
|
162 return; |
|
163 case ECommDbgFailNext: |
|
164 // We set the fail point for all heaps, rather than just the current Dealer. This could lead to a failure not related |
|
165 // directly to whatever the client test code is trying to exercise but it all helps find bugs |
|
166 c32Dealer.SetFailNextForAllHeaps(aMessage.Int0()); |
|
167 SafeComplete(aMessage, KErrNone); |
|
168 return; |
|
169 } |
|
170 #endif |
|
171 |
|
172 |
|
173 switch ((aMessage.Function())) |
|
174 { |
|
175 case ECommLoadCommModule: |
|
176 { |
|
177 TFileName fullCSYFilename; |
|
178 TInt ret = Read(0,aMessage,fullCSYFilename); |
|
179 if (ret != KErrNone) |
|
180 { |
|
181 C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule Read returned %d instead of KErrNone, cannot proceed"), ret); |
|
182 PanicClient(EBadDescriptor,aMessage); |
|
183 return; |
|
184 } |
|
185 |
|
186 ret = AddCSYExtension(fullCSYFilename,aMessage); |
|
187 if(ret != KErrNone) |
|
188 { |
|
189 C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule AddCSYExtension returned %d instead of KErrNone, cannot proceed"), ret); |
|
190 return; |
|
191 } |
|
192 |
|
193 CommsFW::TWorkerId worker; |
|
194 TBuf8<KMaxFileName> fileName8; |
|
195 fileName8.Copy(fullCSYFilename); |
|
196 |
|
197 TBool found = iThreadManager->FindThreadByFileName(fileName8, worker); |
|
198 if(!found) |
|
199 { |
|
200 worker = iThreadManager->iDefaultThreadIndex; |
|
201 } |
|
202 |
|
203 if(c32Dealer.WorkerExists(worker)) |
|
204 { |
|
205 LoadCommModuleL(aMessage,worker,!found,fullCSYFilename); |
|
206 } |
|
207 else |
|
208 { |
|
209 C32LOG2(KC32Dealer,_L8("ServiceL: LoadCommModule requires worker %d. This worker does not exist so starting"),worker); |
|
210 ret = c32Dealer.LoadCPMOnLoadCommModule(worker); |
|
211 if ((ret!=KErrNone) && (ret!=KErrInUse)) |
|
212 { |
|
213 // only likely return codes here are KErrNoMemory or KErrNotFound if |
|
214 // the RS server could not be found - which means system is probably in pretty bad state (ie, no memory) |
|
215 // luckily at this point there isn't anything to clean up! |
|
216 SafeComplete(aMessage,ret); |
|
217 } |
|
218 else |
|
219 { |
|
220 ret = c32Dealer.ParkRequest(this, aMessage); |
|
221 if(ret != KErrNone) |
|
222 { |
|
223 SafeComplete(aMessage, ret); |
|
224 } |
|
225 } |
|
226 } |
|
227 return; |
|
228 } |
|
229 case ECommCloseCommModule: |
|
230 CloseCommModuleL(aMessage); |
|
231 return; |
|
232 case ECommPortInfoByName: |
|
233 { |
|
234 TPortName name; |
|
235 TInt ret = Read(1,aMessage,name); |
|
236 if (ret != KErrNone) |
|
237 { |
|
238 C32LOG2(KC32Warning, _L8("ServiceL: LoadCommModule Read returned %d instead of KErrNone, cannot proceed"), ret); |
|
239 PanicClient(EBadDescriptor,aMessage); |
|
240 return; |
|
241 } |
|
242 PortInfoL(aMessage,name); |
|
243 return; |
|
244 } |
|
245 case ECommPortInfoByNumber: // original msg is not forwarded as global as aMessage.Int2() is not valid in player, instead CSerial* is wrapped in TC32PlayerGetPortInfoMsg |
|
246 PortInfo(aMessage,aMessage.Int2()); |
|
247 return; |
|
248 case ECommNumPorts: // get information from ThreadManager in dealer |
|
249 NumPorts(aMessage); |
|
250 return; |
|
251 case ECommStartServerThread: // KErrNotSupported |
|
252 C32LOG2(KC32Dealer, _L8("WARNING: deprecated function ECommStartServerThread called, CCommSession(%08x)"), this); |
|
253 SafeComplete(aMessage, KErrNotSupported); |
|
254 return; |
|
255 } |
|
256 |
|
257 // obtain subsession* from aMessage.Int3() |
|
258 CCommSubSession *p = SubSessionFromHandle(aMessage.Int3(), CCommSubSession::ECPort); |
|
259 |
|
260 if (aMessage.Function()==ECommClose) |
|
261 { |
|
262 if (p==NULL) // not a valid aMessage.Int3() |
|
263 { |
|
264 SafeComplete(aMessage, KErrBadHandle); |
|
265 return; |
|
266 } |
|
267 else |
|
268 { |
|
269 CloseSubSessionL(aMessage, CCommSubSession::ECPort); |
|
270 return; |
|
271 } |
|
272 } |
|
273 |
|
274 if (p==NULL) // not a valid aMessage.Int3() |
|
275 { |
|
276 PanicClient(EBadCommHandle, aMessage); |
|
277 return; |
|
278 } |
|
279 |
|
280 // Its OK to proceed with the dispatch of other requests |
|
281 switch (aMessage.Function()) |
|
282 { |
|
283 case ECommRead: |
|
284 case ECommReadCancel: |
|
285 case ECommQueryReceiveBuffer: |
|
286 case ECommResetBuffers: |
|
287 case ECommWrite: |
|
288 case ECommWriteCancel: |
|
289 case ECommBreak: |
|
290 case ECommBreakCancel: |
|
291 case ECommCancel: |
|
292 case ECommConfig: |
|
293 case ECommSetConfig: |
|
294 case ECommCaps: |
|
295 case ECommSetMode: |
|
296 case ECommGetMode: |
|
297 case ECommSignals: |
|
298 case ECommSetSignalsToMark: |
|
299 case ECommSetSignalsToSpace: |
|
300 case ECommReceiveBufferLength: |
|
301 case ECommSetReceiveBufferLength: |
|
302 case ECommSetAccess: |
|
303 case ECommOpenWhenAvailableCancel: |
|
304 #ifdef _DEBUG |
|
305 case ECommDebugState: |
|
306 #endif |
|
307 |
|
308 // Extensions to the CCommSession starts from here |
|
309 |
|
310 case ECommNotifySignals: |
|
311 case ECommNotifyFlowControl: |
|
312 case ECommNotifySignalsCancel: |
|
313 case ECommNotifyFlowControlCancel: |
|
314 case ECommGetFlowControl: |
|
315 case ECommNotifyConfigChange: |
|
316 case ECommNotifyConfigChangeCancel: |
|
317 case ECommNotifyBreak: |
|
318 case ECommNotifyBreakCancel: |
|
319 case ECommGetRole: |
|
320 case ECommNotifyDataAvailable: |
|
321 case ECommNotifyDataAvailableCancel: |
|
322 case ECommNotifyOutputEmpty: |
|
323 case ECommNotifyOutputEmptyCancel: |
|
324 ForwardMessageL(aMessage, *p); |
|
325 break; |
|
326 |
|
327 // Extensions to the CCommSession ends to here |
|
328 |
|
329 default: |
|
330 SafeComplete(aMessage, KErrNotSupported); |
|
331 break; |
|
332 |
|
333 } |
|
334 C32LOG(KC32Detail,_L8("CCommSession::ServiceL() end")); |
|
335 } |
|
336 |
|
337 TInt CCommSession::DisconnectPlayers() |
|
338 { |
|
339 return iDisconnectPlayers; |
|
340 } |
|
341 |
|
342 CCommSubSession* CCommSession::SubSessionFromHandle(TUint aHandle, CCommSubSession::TSubSessionType aType) const |
|
343 { |
|
344 iSubSessions.Lock(); |
|
345 CCommSubSession* subSess = iSubSessions.At(aHandle, aType); |
|
346 iSubSessions.Unlock(); |
|
347 return subSess; |
|
348 } |
|
349 |
|
350 CCommSession::CC32SessionCloseTimer::CC32SessionCloseTimer(CCommSession* aSession) |
|
351 : CTimer(EPriorityLow), |
|
352 iSession(aSession) |
|
353 { |
|
354 } |
|
355 |
|
356 CCommSession::CC32SessionCloseTimer* CCommSession::CC32SessionCloseTimer::NewL(CCommSession* aSession) |
|
357 { |
|
358 CC32SessionCloseTimer* self = new (ELeave) CCommSession::CC32SessionCloseTimer(aSession); |
|
359 CleanupStack::PushL(self); |
|
360 self->ConstructL(); |
|
361 CleanupStack::Pop(self); |
|
362 return self; |
|
363 } |
|
364 |
|
365 void CCommSession::CC32SessionCloseTimer::Start() |
|
366 { |
|
367 CActiveScheduler::Add(this); |
|
368 After(KC32SessionCloseDelay); |
|
369 } |
|
370 |
|
371 void CCommSession::CC32SessionCloseTimer::RunL() |
|
372 { |
|
373 Deque(); |
|
374 if(iStatus == KErrNone) |
|
375 { |
|
376 C32LOG3(KC32Detail, _L8("CCommSession::CC32SessionCloseTimer::RunL session = %08x, DisconnectList = %08x. Will panic in debug."), iSession, iSession->DisconnectPlayers()); |
|
377 |
|
378 // After sending a sessionclose message to the player the timeout is set and it is in the order |
|
379 // of seconds. IF the player doesn't respond (may be unloaded during shutdown, see below comment |
|
380 // about stackable csy) and we get to this place, it is a defect and we'd like to catch that in |
|
381 // debug mode. |
|
382 |
|
383 // NOTE FOR STACKABLE CSY WRITERS |
|
384 // The session from csy loading another csy was not closed properly and hence when shutdown was |
|
385 // commanded, player CPMs unload, while the session remains. When EDisconnect message is received |
|
386 // by the comms server from kernel, session close message is sent to player CPM which has already |
|
387 // been unloaded and thus this timer expires. Ensure that all sessions from within csy is closed |
|
388 // before shutdown is called |
|
389 |
|
390 ASSERT(0); |
|
391 |
|
392 CC32Dealer* dealer = const_cast<CC32Dealer*>(&iSession->Dealer()); |
|
393 dealer->DeleteSession(iSession); |
|
394 } |
|
395 } |
|
396 |
|
397 void CCommSession::AddPlayerToDisconnectList(TWorkerId aPlayerId) |
|
398 { |
|
399 __ASSERT_COMPILE(TC32WorkerThreadPublicInfo::EMaxWorkerThreadId < 32); // Using a TUint32 as a flag container |
|
400 ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId); |
|
401 __FLOG_STMT( |
|
402 if(!IsPlayerInDisconnectList(aPlayerId)) |
|
403 { |
|
404 C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tAddPlayerToDisconnectList(%d)"), this, aPlayerId ); |
|
405 } |
|
406 ) |
|
407 iDisconnectPlayers |= (1 << aPlayerId); |
|
408 } |
|
409 |
|
410 void CCommSession::RemovePlayerFromDisconnectList(TWorkerId aPlayerId) |
|
411 { |
|
412 ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId); |
|
413 __FLOG_STMT( |
|
414 if(IsPlayerInDisconnectList(aPlayerId)) |
|
415 { |
|
416 C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tRemovePlayerFromDisconnectList(%d)"), this, aPlayerId ); |
|
417 } |
|
418 ) |
|
419 iDisconnectPlayers &= ~(1 << aPlayerId); |
|
420 } |
|
421 |
|
422 TBool CCommSession::IsDisconnectListEmpty() const |
|
423 { |
|
424 C32LOG2(KC32Detail, _L8("CCommSession::IsDisconnectListEmpty %d "), iDisconnectPlayers ); |
|
425 return iDisconnectPlayers == 0; |
|
426 } |
|
427 |
|
428 TBool CCommSession::IsPlayerInDisconnectList(TWorkerId aPlayerId) const |
|
429 { |
|
430 // A potential optimisation for the future would be to actively check whether the player still has subsessions here, rather |
|
431 // than blinding sending the session close message |
|
432 ASSERT(aPlayerId <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId); |
|
433 return iDisconnectPlayers & (1 << aPlayerId); |
|
434 } |
|
435 |
|
436 void CCommSession::ForgetSubSession(CCommSession* aSelf, CCommSubSession* aSubSession, TInt aSubSessionHandle, TAny*) |
|
437 { |
|
438 (void) aSubSession; // suppress UREL warnings |
|
439 VERIFY_RESULT(aSelf->iSubSessions.Remove(aSubSessionHandle), aSubSession); |
|
440 } |
|
441 |
|
442 void CCommSession::CountSubSessions(CCommSession*, CCommSubSession*, TInt, TAny* aArg) |
|
443 { |
|
444 TInt* counter = reinterpret_cast<TInt*>(aArg); |
|
445 ++*counter; |
|
446 } |
|
447 |
|
448 CCommSession::CCommSession(CC32ThreadManager* aThreadManager) |
|
449 /** |
|
450 * C'Tor - must pass client to CSession |
|
451 * |
|
452 * @param aClient handle to the Clients thread |
|
453 * @param aPortManager pointer to th port manager |
|
454 */ |
|
455 :CSession2(), |
|
456 iThreadManager(aThreadManager) |
|
457 { |
|
458 C32GlobalUtil::NewSession(); // increment iNumSessions |
|
459 C32LOG1(KC32Detail, _L8("CCommSession::CCommSession()")); |
|
460 } |
|
461 |
|
462 CCommSession* CCommSession::NewL(CC32ThreadManager* aThreadManager) |
|
463 { |
|
464 CCommSession* self = new (ELeave) CCommSession(aThreadManager); |
|
465 CleanupStack::PushL(self); |
|
466 self->ConstructL(); |
|
467 CleanupStack::Pop(self); |
|
468 return self; |
|
469 } |
|
470 |
|
471 void CCommSession::ConstructL() |
|
472 { |
|
473 iSessionCloseTimer = CCommSession::CC32SessionCloseTimer::NewL(this); |
|
474 iSubSessions.InitialiseL(); // initialise CC32SubSessionIx |
|
475 } |
|
476 |
|
477 void CCommSession::CloseSubSessionL(const RMessage2& aMessage, CCommSubSession::TSubSessionType aType) |
|
478 { |
|
479 iSubSessions.Lock(); |
|
480 CCommSubSession* subSess = iSubSessions.At(aMessage.Int3(), aType); |
|
481 C32LOG5(KC32Detail, _L8("CCommSession(%08x):\tCloseSubSession(%08x, %d) - subSess %08x"), this, aMessage.Int3(), aType, subSess); |
|
482 ASSERT(subSess); |
|
483 iSubSessions.Unlock(); |
|
484 ForwardMessageL(aMessage, *subSess); |
|
485 } |
|
486 |
|
487 TInt CCommSession::AddCSYToSessionL(const TDesC& aCSYFileName, TBool& aIsDuplicate) |
|
488 { |
|
489 aIsDuplicate=EFalse; |
|
490 |
|
491 TInt k = 0; |
|
492 while (k < iCsyCon.Count() && !aIsDuplicate) |
|
493 { |
|
494 if (aCSYFileName.CompareF(*iCsyCon[k])==0) |
|
495 { |
|
496 aIsDuplicate=ETrue; |
|
497 } |
|
498 k++; |
|
499 } |
|
500 |
|
501 HBufC* name = aCSYFileName.AllocL(); |
|
502 return iCsyCon.Append(name); |
|
503 } |
|
504 |
|
505 TInt CCommSession::RemoveCSYFromSession(const TDesC& aCSYFileName, TBool& aIsLast) |
|
506 { |
|
507 TBool aFound=EFalse; |
|
508 TInt k = 0; |
|
509 while (k < iCsyCon.Count()) |
|
510 { |
|
511 if (iCsyCon[k]->CompareF(aCSYFileName)==0) |
|
512 { |
|
513 // coverity [dead_error_condition] aFound can be true on later iterations of the while loop |
|
514 if (aFound) |
|
515 { |
|
516 aIsLast=EFalse; |
|
517 } |
|
518 else |
|
519 { |
|
520 delete iCsyCon[k]; |
|
521 iCsyCon.Remove(k); |
|
522 aIsLast=ETrue; |
|
523 aFound=ETrue; |
|
524 return KErrNone; |
|
525 } |
|
526 } |
|
527 k++; |
|
528 } |
|
529 return KErrNotFound; |
|
530 } |
|
531 |
|
532 CC32WorkerThread& CCommSession::C32WorkerThread() const |
|
533 { |
|
534 return Dealer().WorkerThread(); |
|
535 } |
|
536 |
|
537 void CCommSession::LoadCommModuleL(const RMessage2& aMessage, CommsFW::TWorkerId aWorker, TBool aDefaulted, const TDesC& aFilename) |
|
538 /** |
|
539 Load a comm module |
|
540 We assume that the worker we need is loaded if we've come this far. |
|
541 aFilename - full filename of CSY |
|
542 aDefaulted - True if the supplied filename is for a CSY that is not known via CSYList values in CMI file. |
|
543 In this case aWorker will be the default thread |
|
544 */ |
|
545 { |
|
546 TBool isDuplicate; // used both for AddCSYToSessionL and RemoveCSYFromSession (where it is used as isLast) |
|
547 TInt ret; |
|
548 // Add csy to session, if present we still add csyfilename to session CSY container to keep accesscount but do not |
|
549 // forward message, (preserve legacy behaviour where c32 allowed multiple load attempts with KErrNone) |
|
550 ret = AddCSYToSessionL(aFilename,isDuplicate); |
|
551 if(ret != KErrNone) |
|
552 { |
|
553 C32LOG2(KC32Warning,_L8("CCommSession::LoadCommModuleL() failed to append CSY to csy container returned %d "), ret); |
|
554 SafeComplete(aMessage, ret); |
|
555 return; |
|
556 } |
|
557 // if no memory, or other error, return as such to client |
|
558 if (isDuplicate) |
|
559 { |
|
560 ret = iThreadManager->IncrementCountOnLoad(aFilename); // increment count for multiple load attempt |
|
561 __ASSERT_DEBUG(ret == KErrNone, Fault(EBadState,_L("CCommSession::LoadCommModuleL(): duplicate entry of CSY but not found in Thread Manager !"))); |
|
562 SafeComplete(aMessage,KErrNone); |
|
563 } |
|
564 else |
|
565 { |
|
566 if (aDefaulted) |
|
567 { |
|
568 C32LOG2(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S) not found in Threadmanager so adding"),&aFilename); |
|
569 // add csy record since it is unknown, probably after-marked csy |
|
570 TBuf8<KMaxFileName> fileName8; // huge stack usage, but no other way |
|
571 fileName8.Copy(aFilename); |
|
572 |
|
573 CCSYInfo* csyPtr = NULL; |
|
574 TRAP(ret,csyPtr = CCSYInfo::NewL(fileName8, aWorker)); |
|
575 if (ret==KErrNone) |
|
576 { |
|
577 ret = iThreadManager->iCSYList.Append(csyPtr); |
|
578 if (ret!=KErrNone) |
|
579 { |
|
580 // failed to add so undo and abort |
|
581 delete csyPtr; |
|
582 (void)RemoveCSYFromSession(aFilename,isDuplicate); |
|
583 SafeComplete(aMessage,ret); |
|
584 return; |
|
585 } |
|
586 } |
|
587 else |
|
588 { |
|
589 // probably OOM |
|
590 (void)RemoveCSYFromSession(aFilename,isDuplicate); |
|
591 SafeComplete(aMessage,ret); |
|
592 return; |
|
593 } |
|
594 } |
|
595 |
|
596 // if this module hasn't been loaded before, it won't have had its portname set. As |
|
597 // the portname could be quite long we need to allocate it now to its max size |
|
598 // since we can't afford to run out of memory after player responds with the portname after load. |
|
599 |
|
600 ret = iThreadManager->GrowCSYPortNameToMaximumIfNotLoaded(aFilename); |
|
601 |
|
602 if (ret == KErrNoMemory) |
|
603 { |
|
604 C32LOG2(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S).Ran out of memory growing portname - cleaning up"),&aFilename); |
|
605 (void)RemoveCSYFromSession(aFilename,isDuplicate); |
|
606 if (aDefaulted) |
|
607 { |
|
608 C32LOG3(KC32Dealer,_L("CCommSession::LoadCommModuleL(): CSY (%S), cleanup for abort: This was a newly-added default record (at index %d), so deleting"),&aFilename,iThreadManager->iCSYList.Count()-1); |
|
609 // we just appended csy record, so remove it |
|
610 delete iThreadManager->iCSYList[iThreadManager->iCSYList.Count()-1]; |
|
611 iThreadManager->iCSYList.Remove(iThreadManager->iCSYList.Count()-1); |
|
612 } |
|
613 SafeComplete(aMessage,ret); |
|
614 return; |
|
615 } |
|
616 else |
|
617 { |
|
618 __ASSERT_DEBUG(ret==KErrNone,Fault(EBadState,_L("CCommSession::LoadCommModuleL(): Panicking due to failure to grow CSY portname for unexpected reason: %d" ),ret)); |
|
619 } |
|
620 |
|
621 |
|
622 // entry for unlisted CSY created now, increment count for this CSY, count as in number of times its loaded |
|
623 ret = iThreadManager->IncrementCountOnLoad(aFilename); |
|
624 __ASSERT_DEBUG(ret==KErrNone,Fault(EBadState,_L("CCommSession::LoadCommModuleL(): Panicking due to failure to increment count for CSY: %d" ),ret)); |
|
625 |
|
626 // send Message to player |
|
627 CC32WorkerThread& owner = C32WorkerThread(); |
|
628 if(aWorker==TC32WorkerThreadPublicInfo::EMainThread) |
|
629 { |
|
630 // co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index |
|
631 AddPlayerToDisconnectList(aWorker); |
|
632 owner.Player()->LoadCommModule(aMessage); |
|
633 DontCompleteCurrentRequest(); |
|
634 } |
|
635 else if (owner.PeerReachable(aWorker)) |
|
636 { |
|
637 // send the message via transports wrapped in TC32PlayerLoadCommModuleMsg |
|
638 AddPlayerToDisconnectList(aWorker); |
|
639 TC32PlayerLoadCommModuleMsg respMsg(aMessage); |
|
640 owner.PostMessage(aWorker, respMsg); |
|
641 DontCompleteCurrentRequest(); |
|
642 const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage); |
|
643 forwardedMsg.NullHandle(); |
|
644 } |
|
645 else |
|
646 { |
|
647 C32LOG2(KC32Warning,_L8("CCommSession::LoadCommModuleL() Peer Thread Unreachable. RMessage2& = %08x. Will panic in debug"), aMessage.Handle()); |
|
648 DontCompleteCurrentRequest(); |
|
649 __ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); |
|
650 } |
|
651 |
|
652 } |
|
653 } |
|
654 |
|
655 void CCommSession::SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode) |
|
656 { |
|
657 if(iComplete) |
|
658 { |
|
659 ::SafeComplete(aMessage, aCompletionCode); |
|
660 } |
|
661 } |
|
662 |
|
663 void CCommSession::DontCompleteCurrentRequest() |
|
664 { |
|
665 iComplete = EFalse; |
|
666 } |
|
667 |
|
668 void CCommSession::CloseCommModuleL(const RMessage2& aMessage) |
|
669 /** |
|
670 * Close a comm module |
|
671 */ |
|
672 { |
|
673 TFullName name; // not a TPortName for backwards compat reasons |
|
674 Read(0,aMessage,name); |
|
675 |
|
676 TFileName csyfilename; |
|
677 TInt ret = iThreadManager->MapPortprefixToCSYFileName(name, csyfilename); // fill csyfilename |
|
678 if (ret!=KErrNone) |
|
679 { |
|
680 SafeComplete(aMessage, KErrNotFound); |
|
681 return; |
|
682 } |
|
683 |
|
684 TBool isLast; |
|
685 TInt res = RemoveCSYFromSession(csyfilename,isLast); // can return either KErrNone or KErrNotFound in case when csy is not found listed |
|
686 |
|
687 if (res==KErrNone) |
|
688 { |
|
689 // decrement the LoadCount for CSY |
|
690 iThreadManager->DecrementCountOnCSYUnLoad(csyfilename); |
|
691 if (isLast) |
|
692 { |
|
693 // if CSY is the last one for the session, then remove from session and forward mesage to player |
|
694 // unload message is forwarded "per session basis", so every session sends unload message to player, |
|
695 // if this csy was previously loaded by this session, unload message is sent to player either when |
|
696 // unloadcommmodule is explicitly called or when session is closed |
|
697 CommsFW::TWorkerId worker; |
|
698 TBuf8<KMaxFileName> fileName8; |
|
699 fileName8.Copy(csyfilename); |
|
700 |
|
701 __ASSERT_ALWAYS(iThreadManager->FindThreadByFileName(fileName8,worker),Fault(EBadState)); // find worker |
|
702 ForwardMessageL(aMessage, NULL, worker); |
|
703 } |
|
704 else |
|
705 { |
|
706 SafeComplete(aMessage, KErrNone); |
|
707 } |
|
708 } |
|
709 else |
|
710 { |
|
711 // old api used to just return and not panic during an attempt to unload a module not loaded |
|
712 // so we do too, altho we log to record this unsavoury behavior |
|
713 C32LOG(KC32Warning, _L8("CCommSession::CloseCommModuleL(), Attempt to Close an unloaded module. Continuing due to old API allowing this unadvised behavior.")); |
|
714 SafeComplete(aMessage, res); // res = KErrNotFound |
|
715 } |
|
716 |
|
717 } |
|
718 |
|
719 void CCommSession::PortInfoL(const RMessage2& aMessage,const TPortName& aName) |
|
720 /** |
|
721 * Write back the port info to the client for a specified port |
|
722 * |
|
723 * @param aName name of the port/filename to get information about |
|
724 */ |
|
725 { |
|
726 TWorkerId worker; |
|
727 if(iThreadManager->FindThreadOfActiveCSYByName(aName, worker)) |
|
728 { |
|
729 ForwardMessageL(aMessage, NULL, worker); |
|
730 } |
|
731 else |
|
732 { |
|
733 SafeComplete(aMessage, KErrNotFound); |
|
734 } |
|
735 } |
|
736 |
|
737 // PortInfo overload requires the CSerial* to be forwarded to player, as the |
|
738 // aMessage.Int2() has the global index which is not valid in player. |
|
739 void CCommSession::PortInfo(const RMessage2& aMessage,TInt aNumber) |
|
740 /** |
|
741 * Write back the port info to the client for a specified port |
|
742 * aNumber is the client supplied index of the CSY |
|
743 * @param aNumber number of the port to get information about |
|
744 */ |
|
745 { |
|
746 // check if the aNumber is sane i.e. within the # of CSYs loaded in C32 |
|
747 if (aNumber < 0) |
|
748 { |
|
749 SafeComplete(aMessage,KErrArgument); |
|
750 return; |
|
751 } |
|
752 |
|
753 TInt workerId = iThreadManager->FindThreadByGlobalIndex(aNumber); |
|
754 if (workerId == KErrNotFound) |
|
755 { |
|
756 SafeComplete(aMessage, KErrTooBig); // preserve old API behaviour |
|
757 } |
|
758 else |
|
759 { |
|
760 CC32WorkerThread& owner = C32WorkerThread(); |
|
761 CommsFW::TWorkerId thisworker = owner.WorkerId(); |
|
762 CSerial* s = iThreadManager->FindSerialObjectByGlobalIndex(aNumber); |
|
763 // Find Thread |
|
764 if(workerId==thisworker) |
|
765 { |
|
766 // co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index |
|
767 AddPlayerToDisconnectList(workerId); |
|
768 owner.Player()->PortInfo(aMessage, s); |
|
769 DontCompleteCurrentRequest(); |
|
770 } |
|
771 else if (owner.PeerReachable(workerId)) |
|
772 { |
|
773 // send the message via transports wrapped in TC32PlayerGetPortInfoMsg |
|
774 C32LOG4(KC32Dealer, _L8("CCommSession::PortInfo(aNumber) Sending Peer Thread %d request for info on CSerial %x which is for CSY at active idx %d"),workerId,s,aNumber); |
|
775 AddPlayerToDisconnectList(workerId); |
|
776 TC32PlayerGetPortInfoMsg respMsg(aMessage, s); |
|
777 owner.PostMessage(workerId, respMsg); |
|
778 DontCompleteCurrentRequest(); |
|
779 const RNullableMessage& forwardedMsg = static_cast<const RNullableMessage&>(aMessage); |
|
780 forwardedMsg.NullHandle(); |
|
781 } |
|
782 else |
|
783 { |
|
784 C32LOG2(KC32Warning, _L8("CCommSession::PortInfo(aNumber) Peer Thread %d Unreachable. Will panic in debug."),workerId); |
|
785 DontCompleteCurrentRequest(); |
|
786 __ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); |
|
787 } |
|
788 } |
|
789 } |
|
790 |
|
791 void CCommSession::NumPorts(const RMessage2& aMessage) |
|
792 /** |
|
793 * Write back the number of CSYs loaded to the client |
|
794 */ |
|
795 { |
|
796 // returns the number of CSYs loaded in all sessions |
|
797 TPckgBuf<TInt> num; |
|
798 |
|
799 TInt idx = 0; |
|
800 TInt count = 0; |
|
801 while (idx < iThreadManager->iCSYList.Count()) |
|
802 { |
|
803 if (iThreadManager->iCSYList[idx]->IsLoaded()) |
|
804 { |
|
805 count++; |
|
806 } |
|
807 idx++; |
|
808 } |
|
809 |
|
810 C32LOG2(KC32Detail, _L8("CCommSession::NumPorts = %d "), count); |
|
811 num() = count; |
|
812 Write(0,aMessage,num); |
|
813 SafeComplete(aMessage, KErrNone); |
|
814 } |
|
815 |
|
816 CCommSession::~CCommSession() |
|
817 /** |
|
818 * D'tor - clean up and go home. |
|
819 */ |
|
820 { |
|
821 C32LOG1(KC32Detail, _L8("CCommSession::~CCommSession()")); |
|
822 |
|
823 delete iSessionCloseTimer; |
|
824 |
|
825 iCsyCon.ResetAndDestroy(); // delete session CSY container |
|
826 |
|
827 C32GlobalUtil::SessionClosing(); // decrement iNumSessions |
|
828 |
|
829 } |
|
830 |
|
831 void CCommSession::ProcessSubSessions(TWorkerId aPeerId, TSubSessionProcessor aSubSessionProcessor, TAny* aPtr) |
|
832 { |
|
833 iSubSessions.Lock(); |
|
834 CC32SubSessionIx::TIter iter(iSubSessions); |
|
835 |
|
836 CCommSubSession* ss; |
|
837 TInt ssHandle; |
|
838 while((ss = iter.Next(ssHandle)) != NULL) |
|
839 { |
|
840 if(aPeerId == TC32WorkerThreadPublicInfo::ENullWorkerId || aPeerId == ss->Player().WorkerId()) |
|
841 { |
|
842 aSubSessionProcessor(this, ss, ssHandle, aPtr); |
|
843 } |
|
844 } |
|
845 iSubSessions.Unlock(); |
|
846 } |
|
847 |
|
848 void CCommSession::NewPortL(const RMessage2& aMessage) |
|
849 /** |
|
850 * Ask the port manager to open a port in the CSY which is then added |
|
851 * to this session's port list. If another session has already opened |
|
852 * the same port, the port manager will still give us a reference if |
|
853 * the port is not being used exclusively. |
|
854 * |
|
855 * @param aMessage handle to the IPC message from the client |
|
856 */ |
|
857 { |
|
858 C32LOG1(KC32Detail, _L8("CCommSession::NewPort()")); |
|
859 |
|
860 TFullName name; // not a TPortName for backwards compat reasons |
|
861 TUint port; |
|
862 TInt len; |
|
863 |
|
864 TInt ret = ExtractPortNameAndNumber(aMessage, name, port, len); |
|
865 if(ret != KErrNone) |
|
866 { |
|
867 C32LOG2(KC32Detail, _L8("CCommSession::NewPort() - returning KErrBadName to client. Offending portname was: %S"),&name); |
|
868 // Bad Handle, (session) dealer completes. |
|
869 // it would be nicer to complete with value of "ret", but as old C32 always completed with KErrBadName |
|
870 // it seems an easy way to reduce compatibility problems by continuing this |
|
871 SafeComplete(aMessage, KErrBadName); |
|
872 return; |
|
873 } |
|
874 else |
|
875 { |
|
876 // message details are valid, forward the message based on portname "COMM" |
|
877 // lookup in ThreadManager, fails if no port-prefix found (if RComm::Open called directly without loading the CSY) |
|
878 TWorkerId worker; |
|
879 if(iThreadManager->FindThreadByPortPrefix(TPtrC(name.Left(len)), worker)) |
|
880 { |
|
881 ForwardMessageL(aMessage, NULL, worker); |
|
882 } |
|
883 else |
|
884 { |
|
885 C32LOG2(KC32Dealer, _L("CCommSession::NewPort() - returning KErrNotFound to client due to no loaded CSY for supplied port: %S"),&name); |
|
886 SafeComplete(aMessage, KErrNotFound); |
|
887 } |
|
888 } |
|
889 } |
|
890 |
|
891 TInt CCommSession::ExtractPortNameAndNumber(const RMessagePtr2& aMessage, TDes& aPortName, TUint& aPortNumber, TInt& aLength) |
|
892 /** |
|
893 Extract the port name and number from RMessage |
|
894 aPortName on return is full name including double-colon and number. The length is not policed for compliance with |
|
895 TPortName type since this would break a backwards compatibility behaviour. |
|
896 aLength is length of the actual name part without the double-colon and port number. |
|
897 */ |
|
898 { |
|
899 Read(0,aMessage, aPortName); |
|
900 |
|
901 _LIT(KDoubleColon, "::"); |
|
902 aLength = aPortName.Find(KDoubleColon); |
|
903 if (aLength == KErrNotFound) |
|
904 { |
|
905 return KErrNotFound; |
|
906 } |
|
907 // extract the numeric value after :: |
|
908 TInt numPos = aLength + KDoubleColon.iTypeLength; |
|
909 if (numPos == aPortName.Length()) |
|
910 { |
|
911 C32LOG1(KC32Warning, _L("CCommSession::ExtractPortNameAndNumber() - no port number mentioned to open")); |
|
912 return KErrBadName; // kerrbadname preserves old c32 return code for this function |
|
913 } |
|
914 |
|
915 TPtrC numPtr(&aPortName[numPos], aPortName.Length() - numPos); |
|
916 TLex lexer(numPtr); |
|
917 TInt ret = lexer.Val(aPortNumber); |
|
918 |
|
919 return ret; |
|
920 } |
|
921 |
|
922 /** Sends SessionClosed to all no-resident players. Add self to Dealers list of disconnecting sessions. |
|
923 */ |
|
924 void CCommSession::Disconnect() |
|
925 { |
|
926 C32LOG2(KC32Detail, _L8("CCommSession(%08x):\tDisconnect()"), this ); |
|
927 |
|
928 // Remove all subsessions from the session, ie just as if the client had closed them all individually |
|
929 ProcessSubSessions(TC32WorkerThreadPublicInfo::ENullWorkerId, ForgetSubSession, NULL); |
|
930 |
|
931 CC32WorkerThread& owner = C32WorkerThread(); |
|
932 TWorkerId self = owner.WorkerId(); |
|
933 |
|
934 // remove any parked requests if any as this session is going down. |
|
935 owner.Dealer()->RemoveParkedRequestsOnSessionClose(this); |
|
936 |
|
937 // run thru our list of csys we've loaded for this session and remove each one |
|
938 // and send thru to player to unload each one. As the list allows duplicates, |
|
939 // we only send unload for each csy when its last ref for this session |
|
940 for(TInt i = iCsyCon.Count() -1; i >= 0; i--) |
|
941 { |
|
942 // find worker |
|
943 TWorkerId worker; |
|
944 TBuf8<KMaxFileName> fileName8; |
|
945 fileName8.Copy(*iCsyCon[i]); |
|
946 |
|
947 TBool found = iThreadManager->FindThreadByFileName(fileName8, worker); // TBool found is re-used for testing last csy in session CSY container |
|
948 __ASSERT_DEBUG(found, Fault(EBadState,_L("CCommSession::Disconnect: Csy not found in ThreadManager !"))); |
|
949 // find CSerial object |
|
950 CSerial* s = iThreadManager->GetSerialObjectFromCSYFileName(*iCsyCon[i]); |
|
951 #ifdef _DEBUG |
|
952 if (s == NULL) |
|
953 { |
|
954 #ifdef __FLOG_ACTIVE |
|
955 iThreadManager->DumpThreadInfoAndCSYLists(); |
|
956 #endif |
|
957 TPtrC csyFilename = *iCsyCon[i]; |
|
958 Fault(EBadState,_L("CCommSession::Disconnect: CSerial not found for CSY (%S) in ThreadManager !"),&csyFilename); |
|
959 } |
|
960 #endif |
|
961 |
|
962 TInt res = iThreadManager->DecrementCountOnCSYUnLoad(*iCsyCon[i]); |
|
963 |
|
964 TBool isLast; |
|
965 res = RemoveCSYFromSession((*iCsyCon[i]), isLast); |
|
966 // if its last entry for this csy in TCSYFileNameContainer, send the message to player |
|
967 if(res == KErrNone) |
|
968 { |
|
969 if(isLast) // last CSY in session CSY container - same TBool found re-used |
|
970 { |
|
971 if(worker==self) |
|
972 { |
|
973 // co-resident player, make direct function call, avoid ProcessMessageL(), as aMessage.Int2() points to global index |
|
974 owner.Player()->ProcessUnLoadCommModuleMsg(s); |
|
975 } |
|
976 else if (owner.PeerReachable(worker)) |
|
977 { |
|
978 // send the message via transports wrapped in TC32PlayerUnLoadCommModuleMsg |
|
979 TC32PlayerUnLoadCommModuleMsg respMsg(s); |
|
980 owner.PostMessage(worker, respMsg); |
|
981 } |
|
982 else |
|
983 { |
|
984 C32LOG2(KC32Warning, _L8("CCommSession::Disconnect() Peer Thread (%d) Unreachable. Will Panic in Debug"), worker); |
|
985 __ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); |
|
986 } |
|
987 } |
|
988 } |
|
989 } |
|
990 |
|
991 TTime time; |
|
992 time.HomeTime(); |
|
993 time+=TTimeIntervalMicroSeconds32(KC32SessionClosePlayerDeadline); |
|
994 for(TWorkerId player = TC32WorkerThreadPublicInfo::EMainThread; player <= TC32WorkerThreadPublicInfo::EMaxWorkerThreadId; ++player) |
|
995 { |
|
996 if(IsPlayerInDisconnectList(player)) |
|
997 { |
|
998 if(player == self) |
|
999 { |
|
1000 RemovePlayerFromDisconnectList(player); |
|
1001 owner.Player()->CloseSession(this); |
|
1002 } |
|
1003 else if(owner.PeerReachable(player)) |
|
1004 { |
|
1005 /* Sending closed session message to involved player, dont care if it times out. After this we just wait |
|
1006 anyway for a while and then obliterate it.*/ |
|
1007 C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tDisconnect() Sending SessionClose to W%d"), this, player); |
|
1008 TC32PlayerSessionCloseMsg msg(this, time.Int64()); |
|
1009 owner.PostMessage(player, msg); |
|
1010 } |
|
1011 else |
|
1012 { |
|
1013 C32LOG(KC32Warning,_L8("CCommSession::Disconnect: Peer not reachable. Will panic in debug.")); |
|
1014 __ASSERT_DEBUG(0, User::Panic(KCFTransportPanic, ECFTransAbsentWorker)); |
|
1015 } |
|
1016 } |
|
1017 } |
|
1018 if(!IsDisconnectListEmpty()) |
|
1019 { |
|
1020 C32LOG3(KC32Detail, _L8("CCommSession(%08x):\tDisconnect() Starting timer [discoList = 0x%x]"), this, iDisconnectPlayers ); |
|
1021 iSessionCloseTimer->Start(); |
|
1022 } |
|
1023 } |
|
1024 |
|
1025 void CCommSession::Disconnect(const RMessage2& aMessage) |
|
1026 { |
|
1027 iDisconnectMessage = aMessage; |
|
1028 C32LOG3(KC32Detail, _L("CCommSession(%08x):\tDisconnect(const RMessage2& = %08x)"), this, aMessage.Handle() ); |
|
1029 |
|
1030 Disconnect(); |
|
1031 |
|
1032 // If co-resident Player was only one then complete immediately |
|
1033 if(IsDisconnectListEmpty()) |
|
1034 { |
|
1035 C32LOG2(KC32Detail, _L8("CCommSession(%08x)::Disconnect(const RMessage2&) inherited disconnect"), this ); |
|
1036 inherited::Disconnect(aMessage); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 /** The player has handled the SessionClose message and has cleaned up */ |
|
1041 void CCommSession::SessionCloseResp(TWorkerId aPlayerId) |
|
1042 { |
|
1043 RemovePlayerFromDisconnectList(aPlayerId); |
|
1044 if(IsDisconnectListEmpty()) |
|
1045 { |
|
1046 C32LOG2(KC32Detail, _L8("CCommSession::SessionCloseResp(%08x), Stopping the timer"),this); |
|
1047 iSessionCloseTimer->Cancel(); |
|
1048 // Dealer()->DeleteSession(...) is called by the caller of this function after this |
|
1049 } |
|
1050 } |
|
1051 |
|
1052 |
|
1053 TInt CCommSession::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC8& aDes, TInt aOffset) |
|
1054 /** |
|
1055 * Write and kill the client if it leaves. |
|
1056 * |
|
1057 * Copies data from an 8 bit descriptor in the server address space to the client |
|
1058 * thread's address space. The target location must be a valid modifiable descriptor. |
|
1059 * Data is copied from the source descriptor to the specified offset position within |
|
1060 * the target descriptor data area. The length of data copied is the length of the |
|
1061 * source descriptor. The length of the target descriptor is set to the length of |
|
1062 * the source descriptor plus the value of the offset. |
|
1063 * |
|
1064 * @param aPtr A pointer to a valid address within the client thread's address space. |
|
1065 * The data type at this location must be a modifiable descriptor, i.e. aTDes8 type. |
|
1066 * @param aDes An 8 bit descriptor in the server address space. This is the source of the copy operation. |
|
1067 * @param aOffset The offset from the start of the target descriptor data area where copying is to begin. |
|
1068 * This value must be greater than or equal to zero. |
|
1069 * |
|
1070 * @panic This function will panic the client if the WriteL() leaves |
|
1071 */ |
|
1072 { |
|
1073 //C32LOG4(KC32Detail, _L8("CCommSession::Write() Data = (%s), Pos (%d) Offset (%d)"), aDes.Ptr(), aPos, aOffset); |
|
1074 |
|
1075 TInt ret = aMessage.Write(aPos, aDes, aOffset); |
|
1076 if (ret!=KErrNone) |
|
1077 { |
|
1078 PanicClient(EBadDescriptor,aMessage); |
|
1079 } |
|
1080 return ret; |
|
1081 } |
|
1082 |
|
1083 |
|
1084 TInt CCommSession::Read(TInt aPos, const RMessagePtr2& aMessage , TDes8& aDes, TInt aOffset) |
|
1085 /** |
|
1086 * Read and kill the client if it leaves. |
|
1087 * |
|
1088 * Copies data from the client thread's address space into an 8 bit descriptor |
|
1089 * in the server address space. The source data must be a valid descriptor. |
|
1090 * Data is copied from the specified offset position within the source descriptor |
|
1091 * data area. The length of data copied is the length of source descriptor data |
|
1092 * minus the offset value. If the offset value is greater than the length of the |
|
1093 * source descriptor, then no data is copied. The length of data copied is limited |
|
1094 * to the maximum length of the target descriptor. |
|
1095 * |
|
1096 * @param aPtr A pointer to a valid address within the client thread's address space. |
|
1097 * The data at this pointer must be a descriptor, i.e. a TDesC8 type. |
|
1098 * @param aDes An 8 bit descriptor in the server address space. This is the target |
|
1099 * of the copy operation. |
|
1100 * @param aOffset The offset from the start of the source descriptor data area from where |
|
1101 * copying is to begin. This value must be greater than or equal to zero. |
|
1102 * |
|
1103 * @panic This function will panic the client if the ReadL() leaves |
|
1104 */ |
|
1105 { |
|
1106 C32LOG3(KC32Detail, _L8("CCommSession::Read(), Pos (%d), Offset (%d)"), aPos, aOffset); |
|
1107 |
|
1108 TInt ret = aMessage.Read(aPos, aDes, aOffset); |
|
1109 if (ret!=KErrNone) |
|
1110 { |
|
1111 C32LOG1(KC32Detail, _L8("Error at the time of reading data from client")); |
|
1112 PanicClient(EBadDescriptor,aMessage); |
|
1113 } |
|
1114 return ret; |
|
1115 } |
|
1116 |
|
1117 |
|
1118 TInt CCommSession::Write(TInt aPos, const RMessagePtr2& aMessage , const TDesC16& aDes, TInt aOffset) |
|
1119 /** |
|
1120 * Write and kill the client if it leaves. |
|
1121 * |
|
1122 * (see CCommSession::Write() with 8-bit descriptor) |
|
1123 * |
|
1124 * @param aPtr A pointer to a valid address within the client thread's address space. |
|
1125 * The data type at this location must be a modifiable descriptor, i.e. aTDes16 type. |
|
1126 * @param aDes A 16 bit descriptor in the server address space. This is the source of the copy operation. |
|
1127 * @param aOffset The offset from the start of the target descriptor data area where copying is to begin. |
|
1128 * This value must be greater than or equal to zero. |
|
1129 * |
|
1130 * @panic This function will panic the client if the WriteL() leaves |
|
1131 */ |
|
1132 { |
|
1133 |
|
1134 //C32LOG4(KC32Detail, _L8("CCommSession::Write(), Data = (%s), Pos (%d), Offset (%d)"), aDes.Ptr(), aPos, aOffset); |
|
1135 |
|
1136 TInt ret = aMessage.Write(aPos, aDes, aOffset); |
|
1137 if (ret!=KErrNone) |
|
1138 { |
|
1139 PanicClient(EBadDescriptor,aMessage); |
|
1140 } |
|
1141 return ret; |
|
1142 } |
|
1143 |
|
1144 |
|
1145 TInt CCommSession::Read(TInt aPos, const RMessagePtr2& aMessage , TDes16& aDes, TInt aOffset) |
|
1146 /** |
|
1147 * Read and kill the client if it leaves. |
|
1148 * |
|
1149 * (see CCommSession::Write() with 8-bit descriptor) |
|
1150 * |
|
1151 * @param aPtr A pointer to a valid address within the client thread's address space. |
|
1152 * The data at this pointer must be a descriptor, i.e. a TDesC16 type. |
|
1153 * @param aDes A 16 bit descriptor in the server address space. This is the target |
|
1154 * of the copy operation. |
|
1155 * @param aOffset The offset from the start of the source descriptor data area from where |
|
1156 * copying is to begin. This value must be greater than or equal to zero. |
|
1157 * |
|
1158 * @panic This function will panic the client if the ReadL() leaves |
|
1159 */ |
|
1160 { |
|
1161 C32LOG3(KC32Detail, _L8("CCommSession::Read(), Pos (%d), Offset (%d)"), aPos, aOffset); |
|
1162 |
|
1163 TInt ret = aMessage.Read(aPos, aDes, aOffset); |
|
1164 if (ret!=KErrNone) |
|
1165 { |
|
1166 C32LOG1(KC32Detail, _L8("Error at the time of reading data from client")); |
|
1167 PanicClient(EBadDescriptor,aMessage); |
|
1168 } |
|
1169 return ret; |
|
1170 } |
|
1171 |
|
1172 /** |
|
1173 Checks for a null'd handle before attempting complete. |
|
1174 If handle is null'd then don't complete as this will panic server. |
|
1175 |
|
1176 @param aMessage Message to complete |
|
1177 @param aCompletionCode Completion code. |
|
1178 */ |
|
1179 void SafeComplete(const RMessagePtr2& aMessage, TInt aCompletionCode) |
|
1180 { |
|
1181 if(!aMessage.IsNull()) |
|
1182 { |
|
1183 C32LOG3(KC32Dealer,_L8("CCommSession::SafeComplete(%08x) Completion code: %d"),aMessage.Handle(),aCompletionCode); |
|
1184 aMessage.Complete(aCompletionCode); |
|
1185 } |
|
1186 else |
|
1187 { |
|
1188 C32LOG3(KC32Detail,_L8("CCommSession::SafeComplete(%08x) - cannot complete message since Null! Completion code was meant to be: %d"),aMessage.Handle(),aCompletionCode); |
|
1189 } |
|
1190 } |
|
1191 |
|
1192 |
|
1193 |
|
1194 TInt AddCSYExtension(TFileName& aFilename, const RMessage2& aMessage) |
|
1195 // implements variation whereby filename is 16-bit, and we want to panic client if the extension won't fit |
|
1196 // KErrNone if no probs or extension already present, KErrBadDescriptor if too short |
|
1197 { |
|
1198 TInt r=aFilename.LocateReverse('.'); |
|
1199 if (r==KErrNotFound) |
|
1200 { |
|
1201 if (aFilename.Length()>KMaxFileName - (TInt)KCSYExtension.iTypeLength) //< valid filename is checked here |
|
1202 { |
|
1203 PanicClient(EBadDescriptor,aMessage); |
|
1204 return KErrBadDescriptor; |
|
1205 } |
|
1206 aFilename.Append(KCSYExtension); |
|
1207 } |
|
1208 return KErrNone; |
|
1209 } |
|
1210 |
|
1211 |
|
1212 // |
|
1213 // CCommSubSession |
|
1214 // |
|
1215 |
|
1216 /** |
|
1217 Constructor |
|
1218 */ |
|
1219 CCommSubSession::CCommSubSession(CCommSession* aSession, CPort* aPort, CC32Player* aPlayer) |
|
1220 : iPlayer(aPlayer), |
|
1221 iAccessCount(1), |
|
1222 iPort(aPort), |
|
1223 iSession(aSession) |
|
1224 { |
|
1225 C32LOG4(KC32Detail, _L8("CCommSubSession(%08x):\tCPort Port(%08x):\tCCommSubSession Session(%08x)"), this, iPort, iSession ); |
|
1226 } |
|
1227 |
|
1228 #ifdef _DEBUG |
|
1229 CCommSubSession::~CCommSubSession() |
|
1230 { |
|
1231 C32LOG3(KC32Detail, _L8("CCommSubSession(%08x):\t~CCommSubSession Session(%08x)"), this, iSession ); |
|
1232 } |
|
1233 #endif |
|
1234 |
|
1235 void CCommSubSession::RemoveAndDestroy() |
|
1236 { |
|
1237 // Remove from the Player's container and delete |
|
1238 C32LOG3(KC32Detail, _L8("CCommSubSession(%08x):\tRemoveAndDestroy(), session=%08x"), this, iSession ); |
|
1239 CC32Player::TSubSessionContainer& subSessions = Player().SubSessions(); |
|
1240 TInt sessIdx = subSessions.Find(this); |
|
1241 if(sessIdx >= 0) |
|
1242 { |
|
1243 subSessions.Remove(sessIdx); |
|
1244 if(subSessions.Count() == 0) |
|
1245 { |
|
1246 CC32WorkerThread& workerThread = Player().WorkerThread(); |
|
1247 if(workerThread.ShuttingDown()) |
|
1248 { |
|
1249 workerThread.MaybeTriggerThreadShutdownCallback(); |
|
1250 } |
|
1251 } |
|
1252 } |
|
1253 delete this; |
|
1254 } |
|
1255 |
|
1256 CCommSubSession* CCommSubSession::NewL(CCommSession *aSession, CPort* aPort, CC32Player* aPlayer) |
|
1257 { |
|
1258 CCommSubSession *s=new (ELeave) CCommSubSession(aSession, aPort, aPlayer); |
|
1259 return s; |
|
1260 } |
|
1261 |
|
1262 // EOF - CS_SES.CPP |
|
1263 |