|
1 // Copyright (c) 2004-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalComponent |
|
19 */ |
|
20 |
|
21 #include <bluetooth/logger.h> |
|
22 #include <remconinterfaceselector.h> |
|
23 #include <remcon/remconinterfacebase.h> |
|
24 #include <remconerrorobserver.h> |
|
25 #include <remcon/remconinterfacefeatures.h> |
|
26 #include <remcon/remconifdetails.h> |
|
27 #include <s32mem.h> |
|
28 #include "bulkreceiver.h" |
|
29 #include "receiver.h" |
|
30 #include "remconclient.h" |
|
31 #include "remconbulkclient.h" |
|
32 #include "utils.h" |
|
33 |
|
34 |
|
35 const TInt KMaxSharedThreadHeapSize = 0x0400; |
|
36 |
|
37 |
|
38 #ifdef __FLOG_ACTIVE |
|
39 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_IF_SEL); |
|
40 #endif |
|
41 |
|
42 #ifdef _DEBUG |
|
43 PANICCATEGORY("ifsel"); |
|
44 #endif |
|
45 |
|
46 #define RCIS_VERBOSE_PANIC(code) \ |
|
47 { \ |
|
48 LOG1(_L("Panicking with RemConIfSel / %d"), code); \ |
|
49 User::Panic(KRemConIfSelPanicCat, code); \ |
|
50 } |
|
51 |
|
52 #define RCIS_VERBOSE_ASSERT(cond, code) \ |
|
53 { \ |
|
54 if ( !(cond) ) \ |
|
55 { \ |
|
56 RCIS_VERBOSE_PANIC(code); \ |
|
57 } \ |
|
58 } |
|
59 |
|
60 void CloseDeleteAndNull(TAny* aPtr) |
|
61 { |
|
62 RRemCon** sessionPtrPtr = static_cast<RRemCon**>(aPtr); |
|
63 RRemCon* session = *sessionPtrPtr; |
|
64 session->Close(); |
|
65 delete session; |
|
66 *sessionPtrPtr = NULL; |
|
67 } |
|
68 |
|
69 void CleanupCloseDeleteAndNullPushL(RRemCon** aSession) |
|
70 { |
|
71 TCleanupItem item(CloseDeleteAndNull, aSession); |
|
72 CleanupStack::PushL(item); |
|
73 } |
|
74 |
|
75 EXPORT_C CRemConInterfaceSelector* CRemConInterfaceSelector::NewL() |
|
76 { |
|
77 CONNECT_LOGGER |
|
78 LOG_STATIC_FUNC |
|
79 |
|
80 CRemConInterfaceSelector* ifSel = new(ELeave) CRemConInterfaceSelector; |
|
81 CleanupStack::PushL(ifSel); |
|
82 ifSel->ConstructL(); |
|
83 CleanupStack::Pop(ifSel); |
|
84 return ifSel; |
|
85 } |
|
86 |
|
87 void CRemConInterfaceSelector::ConstructL() |
|
88 { |
|
89 iSharedThreadHeap = UserHeap::ChunkHeap(NULL, 0, KMaxSharedThreadHeapSize); |
|
90 if(!iSharedThreadHeap) |
|
91 { |
|
92 LEAVEL(KErrNoMemory); |
|
93 } |
|
94 iBulkCleanupCall = new(ELeave) RSpecificThreadCallBack; |
|
95 TCallBack bulkCleanupCb(StaticBulkCleanup, this); |
|
96 LEAVEIFERRORL(iBulkCleanupCall->Create(bulkCleanupCb, CActive::EPriorityStandard)); |
|
97 |
|
98 // allocate in the shared objects heap. |
|
99 RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap); |
|
100 CleanupSwitchHeapPushL(*currentHeap); |
|
101 { |
|
102 iInterfaces = CRemConInterfaceDetailsArray::NewL(); |
|
103 } |
|
104 CleanupStack::PopAndDestroy(currentHeap); |
|
105 |
|
106 RNestableLock* lock = new (ELeave) RNestableLock; |
|
107 CleanupStack::PushL(lock); |
|
108 LEAVEIFERRORL(lock->CreateLocal()); |
|
109 CleanupStack::Pop(lock); |
|
110 iLock = lock; |
|
111 } |
|
112 |
|
113 CRemConInterfaceSelector::CRemConInterfaceSelector() |
|
114 { |
|
115 LOG_FUNC |
|
116 iTargetReceiver = NULL; |
|
117 } |
|
118 |
|
119 EXPORT_C CRemConInterfaceSelector::~CRemConInterfaceSelector() |
|
120 { |
|
121 LOG_FUNC |
|
122 |
|
123 // The easy one... (i.e. non-bulk interfaces) |
|
124 for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix) |
|
125 { |
|
126 CRemConInterfaceDetails* const details = iInterfaces->Array()[ix]; |
|
127 ASSERT_DEBUG(details); |
|
128 if(!details->IsBulk()) |
|
129 { |
|
130 CRemConInterfaceBase* interface = details->Interface(); |
|
131 details->Interface() = NULL; |
|
132 delete interface; |
|
133 } |
|
134 } |
|
135 |
|
136 // The tricky one... |
|
137 // we have to use the thread specific cleanup because they have to |
|
138 // cancel some objects... |
|
139 TInt err = iBulkCleanupCall->CallBack(); |
|
140 if(err == KErrDied) |
|
141 { |
|
142 // If the other thread is dead then we cannot cleanly cleanup |
|
143 // but if the heap is shared then we should be ok. |
|
144 if(iBulkHeap == &User::Heap()) |
|
145 { |
|
146 BulkCleanup(); |
|
147 } |
|
148 } |
|
149 |
|
150 // Finally tidy-up shared thread objects. |
|
151 RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap); |
|
152 { |
|
153 delete iInterfaces; |
|
154 } |
|
155 User::SwitchHeap(currentHeap); |
|
156 |
|
157 |
|
158 delete iTargetReceiver; |
|
159 delete iControllerReceiver; |
|
160 // delete iBulkReceiver; // This is done in the bulk thread cleanup. |
|
161 |
|
162 if(iControllerSession) |
|
163 { |
|
164 iControllerSession->Close(); |
|
165 delete iControllerSession; |
|
166 } |
|
167 |
|
168 if(iTargetSession) |
|
169 { |
|
170 iTargetSession->Close(); |
|
171 delete iTargetSession; |
|
172 } |
|
173 |
|
174 // iBulkSession.Close(); // This is done in the bulk thread cleanup. |
|
175 |
|
176 iBulkCleanupCall->Close(); |
|
177 delete iBulkCleanupCall; |
|
178 |
|
179 iSharedThreadHeap->Close(); |
|
180 |
|
181 iBulkThread.Close(); |
|
182 |
|
183 iLock->Wait(); |
|
184 iLock->Close(); |
|
185 delete iLock; |
|
186 |
|
187 CLOSE_LOGGER |
|
188 } |
|
189 |
|
190 TInt CRemConInterfaceSelector::StaticBulkCleanup(TAny* aSelf) |
|
191 { |
|
192 LOG_STATIC_FUNC |
|
193 reinterpret_cast<CRemConInterfaceSelector*>(aSelf)->BulkCleanup(); |
|
194 return KErrNone; |
|
195 } |
|
196 |
|
197 void CRemConInterfaceSelector::BulkCleanup() |
|
198 { |
|
199 LOG_FUNC |
|
200 CBulkReceiver* recv = iBulkReceiver; |
|
201 iBulkReceiver = NULL; |
|
202 delete recv; |
|
203 if(RThread().Id() == iBulkThread.Id() && iBulkSession) |
|
204 { |
|
205 iBulkSession->Close(); |
|
206 delete iBulkSession; |
|
207 iBulkSession = NULL; |
|
208 } |
|
209 for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix) |
|
210 { |
|
211 CRemConInterfaceDetails* const details = iInterfaces->Array()[ix]; |
|
212 ASSERT_DEBUG(details); |
|
213 if(details->IsBulk()) |
|
214 { |
|
215 CRemConInterfaceBase* interface = details->Interface(); |
|
216 details->Interface() = NULL; |
|
217 delete interface; |
|
218 } |
|
219 } |
|
220 } |
|
221 |
|
222 void CRemConInterfaceSelector::EstablishBulkThreadBindingL() |
|
223 { |
|
224 LOG_FUNC |
|
225 if(iBulkHeap) |
|
226 { |
|
227 // Already bound |
|
228 RCIS_VERBOSE_ASSERT(RThread().Id() == iBulkThread.Id(), ERemConIfSelMultipleBulkInterfaceThreads); |
|
229 } |
|
230 else |
|
231 { |
|
232 // Create Binding. |
|
233 LEAVEIFERRORL(iBulkThread.Duplicate(RThread())); |
|
234 CleanupClosePushL(iBulkThread); |
|
235 LEAVEIFERRORL(iBulkCleanupCall->Start()); |
|
236 iBulkReceiver = CBulkReceiver::NewL(*this); |
|
237 iBulkHeap = &User::Heap(); |
|
238 CleanupStack::Pop(&iBulkThread); |
|
239 } |
|
240 |
|
241 } |
|
242 |
|
243 void CRemConInterfaceSelector::RegisterInterfaceCommonL(CRemConInterfaceBase& aInterface, const TDesC8& aFeatures) |
|
244 { |
|
245 LOG_FUNC |
|
246 |
|
247 const TBool bulkIf = aInterface.Bulk(); |
|
248 if(bulkIf) |
|
249 { |
|
250 EstablishBulkThreadBindingL(); |
|
251 } |
|
252 |
|
253 // Check an instance of the same interface (same interface UID and type) |
|
254 // has not already been added. |
|
255 const TUint count = iInterfaces->Array().Count(); |
|
256 for(TUint ii=0; ii<count; ++ii) |
|
257 { |
|
258 CRemConInterfaceBase* const iface = iInterfaces->Array()[ii]->Interface(); |
|
259 RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError); |
|
260 RCIS_VERBOSE_ASSERT( (iface->InterfaceUid() != aInterface.InterfaceUid()) || (iface->Type() != aInterface.Type()), |
|
261 ERemConIfSelInterfaceOfThatTypeAlreadyRegistered); |
|
262 } |
|
263 |
|
264 // Registration of interfaces should occur before we try to use any of |
|
265 // them. |
|
266 RCIS_VERBOSE_ASSERT(!TargetOpened() && !ControllerOpened(), ERemConIfSelTardyInterfaceRegistration); |
|
267 |
|
268 iLock->Wait(); // critical session |
|
269 RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap); |
|
270 CleanupSwitchHeapPushL(*currentHeap); |
|
271 { |
|
272 CRemConInterfaceDetails* details = CRemConInterfaceDetails::NewLC(aInterface.InterfaceUid(), aInterface.Type(), bulkIf, &aInterface, aFeatures); |
|
273 iInterfaces->AppendL(details); |
|
274 CleanupStack::Pop(details); |
|
275 } |
|
276 CleanupStack::PopAndDestroy(currentHeap); |
|
277 iLock->Signal(); // end of critical session |
|
278 |
|
279 // The interface has been appended OK, so adjust iMaxDataLength. |
|
280 const TUint interfaceMaxLength = aInterface.MaxLength(); |
|
281 if(!bulkIf && interfaceMaxLength > iControlMaxDataLength) |
|
282 { |
|
283 iControlMaxDataLength = interfaceMaxLength; |
|
284 } |
|
285 else if(bulkIf && interfaceMaxLength > iBulkMaxDataLength) |
|
286 { |
|
287 iBulkMaxDataLength = interfaceMaxLength; |
|
288 } |
|
289 } |
|
290 |
|
291 EXPORT_C void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface) |
|
292 { |
|
293 LOG_FUNC |
|
294 |
|
295 RegisterInterfaceCommonL(aInterface, KNullDesC8); |
|
296 } |
|
297 |
|
298 void CRemConInterfaceSelector::RegisterInterfaceL(CRemConInterfaceBase& aInterface, RRemConInterfaceFeatures& aRemConInterfaceFeatures) |
|
299 { |
|
300 LOG_FUNC |
|
301 |
|
302 RegisterInterfaceCommonL(aInterface, aRemConInterfaceFeatures.SupportedOperations()); |
|
303 } |
|
304 |
|
305 EXPORT_C void CRemConInterfaceSelector::RegisterErrorObserver(MRemConErrorObserver* aObserver) |
|
306 { |
|
307 LOG_FUNC |
|
308 LOG1(_L("\taObserver = 0x%08x"), aObserver); |
|
309 |
|
310 iErrorObserver = aObserver; |
|
311 } |
|
312 |
|
313 EXPORT_C void CRemConInterfaceSelector::OpenControllerL() |
|
314 { |
|
315 LOG_FUNC |
|
316 |
|
317 // An attempt to open a controller session when one is already open |
|
318 // is an exceptional condition. |
|
319 if (ControllerOpened()) |
|
320 { |
|
321 LEAVEL(KErrInUse); |
|
322 } |
|
323 |
|
324 // NB We don't enforce that there are some interfaces registered here |
|
325 // because the client might be connecting just to watch connection |
|
326 // statuses. |
|
327 |
|
328 iControllerSession = new(ELeave)RRemConController(); |
|
329 LEAVEIFERRORL(iControllerSession->Connect()); |
|
330 CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iControllerSession)); |
|
331 |
|
332 RegisterInterestedApisL(ERemConClientTypeController); |
|
333 |
|
334 // Now there's a session to receive on, start the receiver. |
|
335 RCIS_VERBOSE_ASSERT(!iControllerReceiver, ERemConIfSelInternalError); |
|
336 iControllerReceiver = CReceiver::NewL(*iControllerSession, *this, iControlMaxDataLength, ERemConClientTypeController); |
|
337 CleanupStack::Pop(&iControllerSession); |
|
338 } |
|
339 |
|
340 void CRemConInterfaceSelector::RegisterInterestedApisL(TRemConClientType aType) |
|
341 { |
|
342 LOG_FUNC |
|
343 |
|
344 TBool target = CRemConInterfaceBase::Target(aType); |
|
345 |
|
346 // First get the size of the data we are going to pass to the server. |
|
347 RCountSizeWriteStream counter; |
|
348 iInterfaces->ExternalizeL(counter, aType); |
|
349 TInt size = counter.Size(); |
|
350 counter.Close(); |
|
351 |
|
352 // Create a suitable size buffer. |
|
353 RBuf8 ipcBuf; |
|
354 ipcBuf.CreateL(size); |
|
355 ipcBuf.CleanupClosePushL(); |
|
356 |
|
357 // Encode the interface details into the buffer. |
|
358 RDesWriteStream ipcStream(ipcBuf); |
|
359 iInterfaces->ExternalizeL(ipcStream, aType); |
|
360 ipcStream.CommitL(); |
|
361 ipcStream.Close(); |
|
362 |
|
363 // Inform the correct session about the interfaces |
|
364 if(!target) |
|
365 { |
|
366 LEAVEIFERRORL(iControllerSession->RegisterInterestedAPIs(ipcBuf)); |
|
367 } |
|
368 else |
|
369 { |
|
370 LEAVEIFERRORL(iTargetSession->RegisterInterestedAPIs(ipcBuf)); |
|
371 } |
|
372 |
|
373 CleanupStack::PopAndDestroy(&ipcBuf); |
|
374 } |
|
375 |
|
376 void CRemConInterfaceSelector::OpenTargetCommonL() |
|
377 { |
|
378 LOG_FUNC |
|
379 |
|
380 // NB We don't enforce that there are some interfaces registered here |
|
381 // because the client might be connecting just to watch connection |
|
382 // statuses. |
|
383 CleanupCloseDeleteAndNullPushL(reinterpret_cast<RRemCon**>(&iTargetSession)); |
|
384 |
|
385 RegisterInterestedApisL(ERemConClientTypeTarget); |
|
386 |
|
387 // Now we are finished with the features, so we can release some memory. |
|
388 RHeap* currentHeap = User::SwitchHeap(iSharedThreadHeap); |
|
389 { |
|
390 for(TInt ix = 0; ix < iInterfaces->Array().Count(); ++ix) |
|
391 { |
|
392 CRemConInterfaceDetails* const details = iInterfaces->Array()[ix]; |
|
393 ASSERT_DEBUG(details); |
|
394 details->DeleteFeatures(); |
|
395 } |
|
396 } |
|
397 User::SwitchHeap(currentHeap); |
|
398 |
|
399 // Now there's a session to receive on, start the receiver. |
|
400 RCIS_VERBOSE_ASSERT(!iTargetReceiver, ERemConIfSelInternalError); |
|
401 iTargetReceiver = CReceiver::NewL(*iTargetSession, *this, iControlMaxDataLength, ERemConClientTypeTarget); |
|
402 CleanupDeleteAndNullPushL(iTargetReceiver); |
|
403 |
|
404 if(iBulkReceiver) |
|
405 { |
|
406 // We delegate the call to the thread the receiver is running |
|
407 // in - waiting until it has completed (with success or error). |
|
408 iBulkReceiver->WaitUntilConnectedL(); |
|
409 } |
|
410 |
|
411 CleanupStack::Pop(2, &iTargetSession); // iTargetReceiver, iTargetSession |
|
412 } |
|
413 |
|
414 EXPORT_C void CRemConInterfaceSelector::OpenTargetL() |
|
415 { |
|
416 LOG_FUNC |
|
417 |
|
418 // An attempt to open a target session when one is already open |
|
419 // is an exceptional condition. |
|
420 if (TargetOpened()) |
|
421 { |
|
422 LEAVEL(KErrInUse); |
|
423 } |
|
424 |
|
425 iTargetSession = new(ELeave)RRemConTarget(); |
|
426 TInt err = iTargetSession->Connect(); |
|
427 if(err == KErrNone) |
|
428 { |
|
429 OpenTargetCommonL(); |
|
430 } |
|
431 else |
|
432 { |
|
433 delete iTargetSession; |
|
434 iTargetSession = NULL; |
|
435 LEAVEL(err); |
|
436 } |
|
437 } |
|
438 |
|
439 /** |
|
440 This should be run from the thread in which the bulk interfaces are to run. |
|
441 */ |
|
442 void CRemConInterfaceSelector::BulkSessionConnectL() |
|
443 { |
|
444 LOG_FUNC |
|
445 |
|
446 RRemConBulk* bulkSession = new(ELeave)RRemConBulk; |
|
447 CleanupStack::PushL(bulkSession); |
|
448 LEAVEIFERRORL(bulkSession->Connect()); |
|
449 CleanupClosePushL(*bulkSession); |
|
450 RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError); |
|
451 iBulkReceiver->InitialiseL(*bulkSession, iBulkMaxDataLength); |
|
452 CleanupStack::Pop(2, bulkSession); |
|
453 iBulkSession = bulkSession; |
|
454 } |
|
455 |
|
456 /** |
|
457 Opens a target session to RemCon. |
|
458 |
|
459 If any bulk interfaces have been registered on this interface selector the |
|
460 the thread in which the first bulk interface was created must be ready to run and |
|
461 not blocked waiting for the completion of this function. Failure to do so will lead |
|
462 to deadlock. |
|
463 |
|
464 @param aPlayerType The type of player |
|
465 @param aPlayerSubType The sub-type of the player |
|
466 @param aPlayerName The name of the player |
|
467 @leave KErrInUse If a target session is already open. |
|
468 */ |
|
469 EXPORT_C void CRemConInterfaceSelector::OpenTargetL(TPlayerType aPlayerType, TPlayerSubType aPlayerSubType, const TDesC8& aPlayerName) |
|
470 { |
|
471 LOG_FUNC |
|
472 |
|
473 // An attempt to open a target session when one is already open |
|
474 // is an exceptional condition. |
|
475 if (TargetOpened()) |
|
476 { |
|
477 LEAVEL(KErrInUse); |
|
478 } |
|
479 |
|
480 iTargetSession = new(ELeave)RRemConTarget(); |
|
481 TInt err = iTargetSession->Connect(aPlayerType,aPlayerSubType,aPlayerName); |
|
482 if(err == KErrNone) |
|
483 { |
|
484 OpenTargetCommonL(); |
|
485 } |
|
486 else |
|
487 { |
|
488 delete iTargetSession; |
|
489 iTargetSession = NULL; |
|
490 LEAVEL(err); |
|
491 } |
|
492 } |
|
493 |
|
494 EXPORT_C TBool CRemConInterfaceSelector::ControllerOpened() const |
|
495 { |
|
496 ASSERT_DEBUG((iControllerSession && iControllerSession->Handle()) || !iControllerSession); |
|
497 return iControllerSession ? ETrue : EFalse; |
|
498 } |
|
499 |
|
500 EXPORT_C TBool CRemConInterfaceSelector::TargetOpened() const |
|
501 { |
|
502 ASSERT_DEBUG((iTargetSession && iTargetSession->Handle()) || !iTargetSession); |
|
503 return iTargetSession ? ETrue : EFalse; |
|
504 } |
|
505 |
|
506 TBool CRemConInterfaceSelector::BulkOpened() const |
|
507 { |
|
508 ASSERT_DEBUG((iBulkSession && iBulkSession->Handle()) || !iBulkSession); |
|
509 return iBulkSession ? ETrue : EFalse; |
|
510 } |
|
511 |
|
512 EXPORT_C void CRemConInterfaceSelector::GoConnectionOrientedL(const TRemConAddress& aConnection) |
|
513 { |
|
514 LOG_FUNC |
|
515 |
|
516 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
517 |
|
518 LEAVEIFERRORL(iControllerSession->GoConnectionOriented(aConnection)); |
|
519 |
|
520 // Store the address. This means that if the server dies we know all |
|
521 // we need to to return the existing sessions to usability without |
|
522 // troubling the app. |
|
523 iAddress = aConnection; |
|
524 } |
|
525 |
|
526 EXPORT_C void CRemConInterfaceSelector::GoConnectionlessL() |
|
527 { |
|
528 LOG_FUNC |
|
529 |
|
530 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
531 |
|
532 LEAVEIFERRORL(iControllerSession->GoConnectionless()); |
|
533 |
|
534 // Unset any stored address, so we know we are connectionless. |
|
535 iAddress.BearerUid() = KNullUid; |
|
536 } |
|
537 |
|
538 EXPORT_C void CRemConInterfaceSelector::ConnectBearer(TRequestStatus& aStat) |
|
539 { |
|
540 LOG_FUNC |
|
541 |
|
542 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
543 |
|
544 iControllerSession->ConnectBearer(aStat); |
|
545 } |
|
546 |
|
547 EXPORT_C TInt CRemConInterfaceSelector::ConnectBearerCancel() |
|
548 { |
|
549 LOG_FUNC |
|
550 |
|
551 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
552 |
|
553 //Ignore Return code because |
|
554 // a) It'll mostly be other than KErrNone because the server has terminated, in which |
|
555 // case the original async request will have completed with the error anyway! |
|
556 // b) It's meaningless to the client whatever the return code is. |
|
557 (void)iControllerSession->ConnectBearerCancel(); |
|
558 |
|
559 return KErrNone; |
|
560 } |
|
561 |
|
562 EXPORT_C void CRemConInterfaceSelector::DisconnectBearer(TRequestStatus& aStat) |
|
563 { |
|
564 LOG_FUNC |
|
565 |
|
566 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
567 |
|
568 iControllerSession->DisconnectBearer(aStat); |
|
569 } |
|
570 |
|
571 EXPORT_C TInt CRemConInterfaceSelector::DisconnectBearerCancel() |
|
572 { |
|
573 LOG_FUNC |
|
574 |
|
575 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
576 |
|
577 //See CRemConInterfaceSelector::ConnectBearerCancel() for comment |
|
578 (void)iControllerSession->DisconnectBearerCancel(); |
|
579 |
|
580 return KErrNone; |
|
581 } |
|
582 |
|
583 EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus, |
|
584 TUid aInterfaceUid, |
|
585 TUint aOperationId, |
|
586 TUint& aNumRemotes, |
|
587 TRemConMessageType aMsgType, |
|
588 const TDesC8& aData) |
|
589 { |
|
590 LOG_FUNC |
|
591 |
|
592 Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aMsgType, ERemConMessageDefault, aData); |
|
593 } |
|
594 |
|
595 EXPORT_C void CRemConInterfaceSelector::Send(TRequestStatus& aStatus, |
|
596 TUid aInterfaceUid, |
|
597 TUint aOperationId, |
|
598 TUint& aNumRemotes, |
|
599 TRemConMessageType aMsgType, |
|
600 TRemConMessageSubType aSubType, |
|
601 const TDesC8& aData) |
|
602 { |
|
603 LOG_FUNC |
|
604 |
|
605 switch ( aMsgType ) |
|
606 { |
|
607 case ERemConCommand: |
|
608 case ERemConNotifyCommand: |
|
609 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
610 iControllerSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData); |
|
611 break; |
|
612 |
|
613 case ERemConResponse: |
|
614 RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession); |
|
615 iTargetSession->Send(aStatus, aInterfaceUid, aOperationId, aNumRemotes, aSubType, aData); |
|
616 break; |
|
617 |
|
618 default: |
|
619 RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType); |
|
620 break; |
|
621 } |
|
622 } |
|
623 |
|
624 /** |
|
625 Sends a notify command to the remote device. |
|
626 |
|
627 @see CRemConInterfaceSelector::Send() |
|
628 */ |
|
629 EXPORT_C void CRemConInterfaceSelector::SendNotify(TRequestStatus& aStatus, |
|
630 TUid aInterfaceUid, |
|
631 TUint aOperationId, |
|
632 TRemConMessageType aMsgType, |
|
633 TRemConMessageSubType aSubType, |
|
634 const TDesC8& aData) |
|
635 { |
|
636 LOG_FUNC |
|
637 if (aMsgType == ERemConNotifyCommand) |
|
638 { |
|
639 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
640 iControllerSession->SendNotify(aStatus, aInterfaceUid, aOperationId, aSubType, aData); |
|
641 } |
|
642 else |
|
643 { |
|
644 RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType); |
|
645 } |
|
646 } |
|
647 |
|
648 EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable( |
|
649 TUid aInterfaceUid, |
|
650 TUint aOperationId, |
|
651 TRemConMessageType aMsgType, |
|
652 const TDesC8& aData) |
|
653 { |
|
654 LOG_FUNC |
|
655 |
|
656 return SendUnreliable(aInterfaceUid, aOperationId, aMsgType, ERemConMessageDefault, aData); |
|
657 } |
|
658 |
|
659 EXPORT_C TInt CRemConInterfaceSelector::SendUnreliable( |
|
660 TUid aInterfaceUid, |
|
661 TUint aOperationId, |
|
662 TRemConMessageType aMsgType, |
|
663 TRemConMessageSubType aSubType, |
|
664 const TDesC8& aData) |
|
665 { |
|
666 LOG_FUNC |
|
667 |
|
668 TInt ret = KErrNone; |
|
669 |
|
670 switch ( aMsgType ) |
|
671 { |
|
672 case ERemConCommand: |
|
673 case ERemConNotifyCommand: |
|
674 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
675 ret = iControllerSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData); |
|
676 break; |
|
677 |
|
678 case ERemConResponse: |
|
679 RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession); |
|
680 ret = iTargetSession->SendUnreliable(aInterfaceUid, aOperationId, aSubType, aData); |
|
681 break; |
|
682 |
|
683 default: |
|
684 RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType); |
|
685 break; |
|
686 } |
|
687 return ret; |
|
688 } |
|
689 |
|
690 EXPORT_C TInt CRemConInterfaceSelector::SendCancel(TRemConMessageType aMsgType) |
|
691 { |
|
692 LOG_FUNC |
|
693 |
|
694 switch ( aMsgType ) |
|
695 { |
|
696 case ERemConCommand: |
|
697 case ERemConNotifyCommand: |
|
698 RCIS_VERBOSE_ASSERT(ControllerOpened(), ERemConIfSelNoControllerSession); |
|
699 //See CRemConInterfaceSelector::ConnectBearerCancel() for comment |
|
700 (void)iControllerSession->SendCancel(); |
|
701 break; |
|
702 |
|
703 case ERemConResponse: |
|
704 RCIS_VERBOSE_ASSERT(TargetOpened(), ERemConIfSelNoTargetSession); |
|
705 //See CRemConInterfaceSelector::ConnectBearerCancel() for comment |
|
706 (void)iTargetSession->SendCancel(); |
|
707 break; |
|
708 |
|
709 default: |
|
710 RCIS_VERBOSE_PANIC(ERemConIfSelBadMessageType); |
|
711 break; |
|
712 } |
|
713 |
|
714 return KErrNone; |
|
715 } |
|
716 |
|
717 EXPORT_C void CRemConInterfaceSelector::SendBulk(TRequestStatus& aStatus, |
|
718 TUid aInterfaceUid, |
|
719 TUint aOperationId, |
|
720 const TDesC8& aData) |
|
721 { |
|
722 LOG_FUNC |
|
723 |
|
724 // Panic as Target Session, because bulkness is transparent to client |
|
725 RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession); |
|
726 iBulkSession->Send(aStatus, aInterfaceUid, aOperationId, aData); |
|
727 } |
|
728 |
|
729 EXPORT_C TInt CRemConInterfaceSelector::SendBulkUnreliable( |
|
730 TUid aInterfaceUid, |
|
731 TUint aOperationId, |
|
732 const TDesC8& aData) |
|
733 { |
|
734 LOG_FUNC |
|
735 |
|
736 // Panic as Target Session, because bulkness is transparent to client |
|
737 RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession); |
|
738 return iBulkSession->SendUnreliable(aInterfaceUid, aOperationId, aData); |
|
739 } |
|
740 |
|
741 EXPORT_C TInt CRemConInterfaceSelector::SendBulkCancel() |
|
742 { |
|
743 LOG_FUNC |
|
744 |
|
745 RCIS_VERBOSE_ASSERT(BulkOpened(), ERemConIfSelNoTargetSession); |
|
746 //See CRemConInterfaceSelector::ConnectBearerCancel() for comment |
|
747 (void)iBulkSession->SendCancel(); |
|
748 |
|
749 return KErrNone; |
|
750 } |
|
751 |
|
752 void CRemConInterfaceSelector::ReceiveComplete(TUid aInterfaceUid, |
|
753 TUint aOperationId, |
|
754 TRemConMessageSubType aMsgSubType, |
|
755 const TRemConAddress& aRemoteAddress, |
|
756 const TDesC8& aData, |
|
757 TRemConClientType aType) |
|
758 { |
|
759 LOG_FUNC |
|
760 LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid); |
|
761 LOG1(_L("\taOperationId = 0x%02x"), aOperationId); |
|
762 LOG1(_L("\taRemoteAddress.BearerUid = 0x%08x"), aRemoteAddress.BearerUid()); |
|
763 |
|
764 const TUint count = iInterfaces->Array().Count(); |
|
765 for ( TUint ii = 0 ; ii < count ; ++ii ) |
|
766 { |
|
767 CRemConInterfaceDetails* const details = iInterfaces->Array()[ii]; |
|
768 ASSERT_DEBUG(details); |
|
769 CRemConInterfaceBase* const iface = details->Interface(); |
|
770 RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError); |
|
771 |
|
772 if ( iface->InterfaceUid() == aInterfaceUid |
|
773 && iface->Type() == aType ) |
|
774 { |
|
775 ASSERT_DEBUG(!details->IsBulk()); |
|
776 MRemConInterfaceIf3* interfaceIf3 = reinterpret_cast<MRemConInterfaceIf3*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf3))); |
|
777 if (interfaceIf3) |
|
778 { |
|
779 interfaceIf3->MrcibNewMessage(aOperationId, aData, aMsgSubType, aRemoteAddress); |
|
780 break; |
|
781 } |
|
782 MRemConInterfaceIf2* interfaceIf2 = reinterpret_cast<MRemConInterfaceIf2*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf2))); |
|
783 if (interfaceIf2) |
|
784 { |
|
785 interfaceIf2->MrcibNewMessage(aOperationId, aData, aMsgSubType); |
|
786 break; |
|
787 } |
|
788 MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1))); |
|
789 RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation); |
|
790 interfaceIf->MrcibNewMessage(aOperationId, aData); |
|
791 break; |
|
792 } |
|
793 } |
|
794 } |
|
795 |
|
796 void CRemConInterfaceSelector::BulkReceiveComplete(TUid aInterfaceUid, TUint aOperationId, const TDesC8& aData) |
|
797 { |
|
798 LOG_FUNC |
|
799 LOG1(_L("\taInterfaceUid = 0x%08x"), aInterfaceUid); |
|
800 LOG1(_L("\taOperationId = 0x%02x"), aOperationId); |
|
801 |
|
802 const TUint count = iInterfaces->Array().Count(); |
|
803 for ( TUint ii = 0 ; ii < count ; ++ii ) |
|
804 { |
|
805 CRemConInterfaceDetails* const details = iInterfaces->Array()[ii]; |
|
806 ASSERT_DEBUG(details); |
|
807 CRemConInterfaceBase* const iface = details->Interface(); |
|
808 RCIS_VERBOSE_ASSERT(iface, ERemConIfSelInternalError); |
|
809 |
|
810 if(details->IsBulk() && iface->InterfaceUid() == aInterfaceUid) |
|
811 { |
|
812 MRemConInterfaceIf* interfaceIf = reinterpret_cast<MRemConInterfaceIf*>(iface->GetInterfaceIf(TUid::Uid(KRemConInterfaceIf1))); |
|
813 RCIS_VERBOSE_ASSERT(interfaceIf, ERemConIfSelNoInterfaceImplementation); |
|
814 interfaceIf->MrcibNewMessage(aOperationId, aData); |
|
815 } |
|
816 } |
|
817 } |
|
818 |
|
819 void CRemConInterfaceSelector::Error(TInt aError) |
|
820 { |
|
821 LOG_FUNC |
|
822 LOG1(_L("\taError = %d"), aError); |
|
823 LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver); |
|
824 |
|
825 if(aError == KErrServerTerminated) |
|
826 { |
|
827 // Initially try and deal with server death in a way that is |
|
828 // transparent to the app. |
|
829 TInt err = TryToReconnect(); |
|
830 LOG1(_L("\tTryToReconnect error = %d"), err); |
|
831 |
|
832 // If we fail inform any registered app. Unregistered apps |
|
833 // just take the risk that they may not realise the server has |
|
834 // died if it errors on a receive. |
|
835 if(err && iErrorObserver) |
|
836 { |
|
837 iErrorObserver->MrceoError(KErrServerTerminated); |
|
838 } |
|
839 } |
|
840 } |
|
841 |
|
842 void CRemConInterfaceSelector::BulkError(TInt aError) |
|
843 { |
|
844 LOG_FUNC |
|
845 LOG1(_L("\taError = %d"), aError); |
|
846 LOG1(_L("\tiErrorObserver = 0x%08x"), iErrorObserver); |
|
847 |
|
848 if(aError == KErrServerTerminated) |
|
849 { |
|
850 // Initially try and deal with server death in a way that is |
|
851 // transparent to the app. |
|
852 TInt err = TryToReconnectBulk(); |
|
853 LOG1(_L("\tTryToReconnectBulk error = %d"), err); |
|
854 |
|
855 // If we fail inform any registered app. Unregistered apps |
|
856 // just take the risk that they may not realise the server has |
|
857 // died if it errors on a receive. |
|
858 if(err && iErrorObserver) |
|
859 { |
|
860 iErrorObserver->MrceoError(KErrServerTerminated); |
|
861 } |
|
862 } |
|
863 } |
|
864 |
|
865 EXPORT_C TInt CRemConInterfaceSelector::GetConnections(TSglQue<TRemConAddress>& aConnections) |
|
866 { |
|
867 LOG_FUNC |
|
868 |
|
869 // It doesn't matter which session we use for this. |
|
870 RRemCon* sess = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession); |
|
871 AssertSession(sess, ERemConIfSelNoSession); |
|
872 |
|
873 return sess->GetConnections(aConnections); |
|
874 } |
|
875 |
|
876 EXPORT_C void CRemConInterfaceSelector::NotifyConnectionsChange(TRequestStatus& aStatus) |
|
877 { |
|
878 LOG_FUNC |
|
879 |
|
880 // It doesn't matter which session we use for this. |
|
881 iNotificationSession = ControllerOpened() ? reinterpret_cast<RRemCon*>(iControllerSession) : reinterpret_cast<RRemCon*>(iTargetSession); |
|
882 AssertSession(iNotificationSession, ERemConIfSelNoSession); |
|
883 |
|
884 iNotificationSession->NotifyConnectionsChange(aStatus); |
|
885 } |
|
886 |
|
887 EXPORT_C TInt CRemConInterfaceSelector::NotifyConnectionsChangeCancel() |
|
888 { |
|
889 LOG_FUNC |
|
890 |
|
891 // Get the session we used for posting the original notification. It won't |
|
892 // have gone away in the meantime as that only happens when 'this' is |
|
893 // destroyed, but the client may call this without ever having called the |
|
894 // original notification. |
|
895 AssertSession(iNotificationSession, ERemConIfSelNoSession); |
|
896 |
|
897 //See CRemConInterfaceSelector::ConnectBearerCancel() for comment |
|
898 (void)iNotificationSession->NotifyConnectionsChangeCancel(); |
|
899 |
|
900 return KErrNone; |
|
901 } |
|
902 |
|
903 void CRemConInterfaceSelector::AssertSession(RRemCon* aSess, TInt aPanicCode) const |
|
904 { |
|
905 LOG_FUNC |
|
906 |
|
907 RCIS_VERBOSE_ASSERT(aSess && aSess->Handle(), aPanicCode); |
|
908 } |
|
909 |
|
910 /** |
|
911 Resurrects sessions in case of server death. |
|
912 |
|
913 For the target and controller session we try to open a new |
|
914 session. If this succeeds we can then set the old session |
|
915 to point to the new one after closing our old defunct |
|
916 session. |
|
917 |
|
918 On success we are left with happy functioning handles. |
|
919 On failure we are left with defunct handles, which are still |
|
920 valid but will complete all requests with KErrServerTerminated. |
|
921 |
|
922 This means that we won't cause an application to get a bad handle |
|
923 panic if it hasn't done anything wrong. |
|
924 */ |
|
925 TInt CRemConInterfaceSelector::TryToReconnect() |
|
926 { |
|
927 LOG_FUNC |
|
928 |
|
929 // Always want to stop receiving. The receiver itself should stop issuing |
|
930 // further receives on completion, but we only want to have the error function |
|
931 // called once, so Cancel() receivers in case we had both. |
|
932 if(TargetOpened()) |
|
933 { |
|
934 RCIS_VERBOSE_ASSERT(iTargetReceiver, ERemConIfSelInternalError); |
|
935 iTargetReceiver->Cancel(); |
|
936 } |
|
937 |
|
938 if(ControllerOpened()) |
|
939 { |
|
940 RCIS_VERBOSE_ASSERT(iControllerReceiver, ERemConIfSelInternalError); |
|
941 iControllerReceiver->Cancel(); |
|
942 } |
|
943 |
|
944 // Now try and create new sessions. We do all the failable work first |
|
945 // so we aren't left in a half alive situation. |
|
946 TInt err = KErrNone; |
|
947 RRemConTarget newTarget; |
|
948 RRemConController newController; |
|
949 |
|
950 if(TargetOpened()) |
|
951 { |
|
952 // See if we can kick RemCon back into life |
|
953 err = newTarget.Connect(); |
|
954 } |
|
955 |
|
956 if(!err && ControllerOpened()) |
|
957 { |
|
958 // See if we can kick RemCon back into life |
|
959 err = newController.Connect(); |
|
960 |
|
961 if(!err && !iAddress.IsNull()) |
|
962 { |
|
963 // If an address is set the session was connection oriented, |
|
964 // resurrect that now. |
|
965 err = newController.GoConnectionOriented(iAddress); |
|
966 } |
|
967 } |
|
968 |
|
969 if(!err) |
|
970 { |
|
971 // RemCon lives! Set our sessions to be the nice new ones. |
|
972 if(TargetOpened()) |
|
973 { |
|
974 iTargetSession->Close(); |
|
975 iTargetSession->SetHandle(newTarget.Handle()); |
|
976 iTargetReceiver->Receive(); |
|
977 } |
|
978 |
|
979 if(ControllerOpened()) |
|
980 { |
|
981 iControllerSession->Close(); |
|
982 iControllerSession->SetHandle(newController.Handle()); |
|
983 iControllerReceiver->Receive(); |
|
984 } |
|
985 } |
|
986 else |
|
987 { |
|
988 // We may not have successfully opened these, but it's safe to |
|
989 // close them anyway. |
|
990 newTarget.Close(); |
|
991 newController.Close(); |
|
992 } |
|
993 |
|
994 return err; |
|
995 } |
|
996 |
|
997 |
|
998 |
|
999 /** |
|
1000 Resurrects bulk sessions in case of server death. |
|
1001 |
|
1002 For the bulk session we try to open a new |
|
1003 session. If this succeeds we can then set the old session |
|
1004 to point to the new one after closing our old defunct |
|
1005 session. |
|
1006 |
|
1007 On success we are left with happy functioning handles. |
|
1008 On failure we are left with defunct handles, which are still |
|
1009 valid but will complete all requests with KErrServerTerminated. |
|
1010 |
|
1011 This means that we won't cause an application to get a bad handle |
|
1012 panic if it hasn't done anything wrong. |
|
1013 */ |
|
1014 TInt CRemConInterfaceSelector::TryToReconnectBulk() |
|
1015 { |
|
1016 LOG_FUNC |
|
1017 |
|
1018 // Always want to stop receiving. The receiver itself should stop issuing |
|
1019 // further receives on completion, but we only want to have the error function |
|
1020 // called once, so Cancel() receivers in case we had both. |
|
1021 if(BulkOpened()) |
|
1022 { |
|
1023 RCIS_VERBOSE_ASSERT(iBulkReceiver, ERemConIfSelInternalError); |
|
1024 iBulkReceiver->Cancel(); |
|
1025 } |
|
1026 |
|
1027 // Now try and create new sessions. We do all the failable work first |
|
1028 // so we aren't left in a half alive situation. |
|
1029 TInt err = KErrNone; |
|
1030 RRemConBulk newBulk; |
|
1031 |
|
1032 if(BulkOpened()) |
|
1033 { |
|
1034 // See if we can kick RemCon back into life |
|
1035 err = newBulk.Connect(); |
|
1036 } |
|
1037 |
|
1038 if(err == KErrNone) |
|
1039 { |
|
1040 // RemCon lives! Set our session to be the nice new one. |
|
1041 if(BulkOpened()) |
|
1042 { |
|
1043 iBulkSession->Close(); |
|
1044 iBulkSession->SetHandle(newBulk.Handle()); |
|
1045 iBulkReceiver->Receive(); |
|
1046 } |
|
1047 } |
|
1048 else |
|
1049 { |
|
1050 // We may not have successfully opened this, but it's safe to |
|
1051 // close it anyway. |
|
1052 newBulk.Close(); |
|
1053 } |
|
1054 |
|
1055 return err; |
|
1056 } |
|
1057 |