|
1 // Copyright (c) 1999-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 #include <s32mem.h> |
|
17 #include <e32svr.h> |
|
18 #include "BTManServer.h" |
|
19 |
|
20 |
|
21 #include "BTSec.h" |
|
22 #include "BtManServerSecurityPolicy.h" |
|
23 #include <bluetooth/logger.h> |
|
24 |
|
25 #ifdef __FLOG_ACTIVE |
|
26 _LIT8(KLogComponent, LOG_COMPONENT_BT_MANAGER_SERVER); |
|
27 #endif |
|
28 |
|
29 static const TInt KMessageArrayGranularity = 4; //< The granularity of the array used to hold TBTManMessage objects |
|
30 static const TInt KBTManClientServerProtocolSlot = 2; // the slot that points to the struct buf used between client and server |
|
31 |
|
32 inline CBTManServerShutdown::CBTManServerShutdown() |
|
33 :CTimer(-1) |
|
34 { |
|
35 LOG_FUNC |
|
36 CActiveScheduler::Add(this); |
|
37 } |
|
38 |
|
39 inline void CBTManServerShutdown::ConstructL() |
|
40 { |
|
41 LOG_FUNC |
|
42 CTimer::ConstructL(); |
|
43 } |
|
44 |
|
45 inline void CBTManServerShutdown::Start() |
|
46 { |
|
47 LOG_FUNC |
|
48 After(KBTManServerShutdownDelay); |
|
49 } |
|
50 |
|
51 // |
|
52 |
|
53 |
|
54 void CBTManServerShutdown::RunL() |
|
55 /** |
|
56 Initiate server exit when the timer expires |
|
57 **/ |
|
58 { |
|
59 LOG_FUNC |
|
60 CActiveScheduler::Stop(); |
|
61 } |
|
62 |
|
63 //===================================================================== |
|
64 // CBTManServer |
|
65 //===================================================================== |
|
66 |
|
67 inline CBTManServer::CBTManServer() |
|
68 : CPolicyServer(EPriorityStandard,KBtmanServerPolicy,ESharableSessions) |
|
69 { |
|
70 LOG_FUNC |
|
71 } |
|
72 |
|
73 CServer2* CBTManServer::NewLC() |
|
74 { |
|
75 LOG_STATIC_FUNC |
|
76 CBTManServer* self=new(ELeave) CBTManServer; |
|
77 CleanupStack::PushL(self); |
|
78 self->ConstructL(); |
|
79 return self; |
|
80 } |
|
81 |
|
82 void CBTManServer::ConstructL() |
|
83 { |
|
84 LOG_FUNC |
|
85 StartL(KBTManServerName); |
|
86 //Ensure that the server will exit even if the 1st client fails to connect |
|
87 iShutdown.ConstructL(); |
|
88 iShutdown.Start(); |
|
89 |
|
90 TInt err; |
|
91 err = iProperty.Define(KPropertyUidBluetoothCategory, |
|
92 KPropertyKeyBluetoothGetRegistryTableChange, |
|
93 RProperty::EInt, |
|
94 KLOCAL_SERVICES, |
|
95 KBTMAN_SID_PROT_SERV); |
|
96 |
|
97 FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure")); |
|
98 |
|
99 err = iProperty.Define(KPropertyUidBluetoothCategory, |
|
100 KPropertyKeyBluetoothCorruptRegistryReset, |
|
101 RProperty::EInt, |
|
102 KLOCAL_SERVICES, |
|
103 KLOCAL_SERVICES_AND_NETWORK_CONTROL); |
|
104 |
|
105 FLOGIFERR(err,_L("CBTManServer::ConstructL() - iProperty.Define Failure")); |
|
106 |
|
107 //Create the service providers... |
|
108 iRegistry = CBTRegistry::NewL(); |
|
109 |
|
110 iContainerIndex = CObjectConIx::NewL(); |
|
111 // don't stop the server if we can't provide this service... |
|
112 } |
|
113 |
|
114 |
|
115 CObjectCon* CBTManServer::NewContainerL() |
|
116 /** |
|
117 Return a new object container |
|
118 **/ |
|
119 { |
|
120 LOG_FUNC |
|
121 return iContainerIndex->CreateL(); |
|
122 } |
|
123 |
|
124 void CBTManServer::DeleteContainer(CObjectCon* aCon) |
|
125 { |
|
126 LOG_FUNC |
|
127 iContainerIndex->Remove(aCon); |
|
128 } |
|
129 |
|
130 CBTManServer::~CBTManServer() |
|
131 { |
|
132 LOG_FUNC |
|
133 |
|
134 // Delete defined properties |
|
135 TInt err; |
|
136 err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetRegistryTableChange); |
|
137 FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure")); |
|
138 err = iProperty.Delete(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothCorruptRegistryReset); |
|
139 FLOGIFERR(err,_L("CBTManServer::~CBTManServer() - iProperty.Delete Failure")); |
|
140 // Close the RProperty handle in case it is ever attached. |
|
141 iProperty.Close(); |
|
142 |
|
143 delete iRegistry; |
|
144 delete iContainerIndex; |
|
145 } |
|
146 |
|
147 CSession2* CBTManServer::NewSessionL(const TVersion &aVersion, const RMessage2& aMessage) const |
|
148 { |
|
149 LOG_FUNC |
|
150 TVersion v(KBTManServerMajorVersionNumber,KBTManServerMinorVersionNumber,KBTManServerBuildVersionNumber); |
|
151 if (!User::QueryVersionSupported(v,aVersion)) |
|
152 { |
|
153 User::Leave(KErrNotSupported); |
|
154 } |
|
155 // make new session |
|
156 return new(ELeave) CBTManSession(*iRegistry, aMessage); |
|
157 } |
|
158 |
|
159 void CBTManServer::AddSession() |
|
160 /** |
|
161 A new session is being created |
|
162 Cancel the shutdown timer if it was running |
|
163 **/ |
|
164 { |
|
165 LOG_FUNC |
|
166 ++iSessionCount; |
|
167 if (iSessionCount > iMaxSessionCount) |
|
168 { |
|
169 iMaxSessionCount = iSessionCount; |
|
170 } |
|
171 iShutdown.Cancel(); |
|
172 } |
|
173 |
|
174 void CBTManServer::DropSession() |
|
175 /** |
|
176 A session is being destroyed |
|
177 Start the shutdown timer if it is the last session. |
|
178 **/ |
|
179 { |
|
180 LOG_FUNC |
|
181 __ASSERT_DEBUG(iSessionCount > 0, PanicServer(EBTManBadState)); |
|
182 |
|
183 if (--iSessionCount==0) |
|
184 { |
|
185 iShutdown.Start(); |
|
186 } |
|
187 } |
|
188 |
|
189 void CBTManServer::Publish(TUint aKey, TInt aValue) |
|
190 { |
|
191 LOG_FUNC |
|
192 TInt err; |
|
193 err = iProperty.Set(KPropertyUidBluetoothCategory, |
|
194 aKey, |
|
195 aValue); |
|
196 FLOGIFERR(err,_L("CBTManServer::Publish() - iProperty.Set Failure")); |
|
197 } |
|
198 |
|
199 void CBTManServer::NotifyViewChange(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor) |
|
200 { |
|
201 LOG_FUNC |
|
202 // For views owned by subsessions. |
|
203 |
|
204 // Go through all sessions - they'll dispatch so all the subessions apart from the one calling here |
|
205 iSessionIter.SetToFirst(); |
|
206 |
|
207 while (iSessionIter != NULL) |
|
208 { |
|
209 CBTManSession* s = static_cast<CBTManSession*>(iSessionIter++); |
|
210 s->SubSessionHasOverlappingView(aSubSessionViewOwner, aViewDescriptor); |
|
211 } |
|
212 } |
|
213 |
|
214 void PanicClient(const RMessage2& aMessage,TInt aPanic, CBTManSession* aSession) |
|
215 /** |
|
216 RMessage2::Panic() also completes the message. This is: |
|
217 (a) important for efficient cleanup within the kernel |
|
218 (b) a problem if the message is completed a second time |
|
219 **/ |
|
220 { |
|
221 LOG_STATIC_FUNC |
|
222 LOG1(_L("PanicClient: Reason = %d"), aPanic); |
|
223 //remove the message from the message table so we don't complete it again |
|
224 //The message may not yet be in the table, so check for NULL before deleting it |
|
225 //This code could be more efficient, but hopefully it won't be called enough to make |
|
226 //it worthwhile improving it ;-) |
|
227 |
|
228 __DEBUGGER(); |
|
229 |
|
230 /*** ORDER MATTERS! ***/ |
|
231 //First find the message in the session's stored messages |
|
232 //This must be done BEFORE panicking the client because |
|
233 //panicking the client resets the RMessage2 handle value to |
|
234 //zero and so almost always renders the FindMessage method useless! |
|
235 CBTManMessage* m = aSession->FindMessage(aMessage); |
|
236 |
|
237 //Now panic the client - this is safer done before deleting |
|
238 //the message from the message array, just in case the RMessage2 |
|
239 //object is obtained from that array and not directly from the client |
|
240 aMessage.Panic(KBTManPanic,aPanic); |
|
241 |
|
242 //Now delete the message from the session's queue. This is vital |
|
243 //if we are not to attempt to complete on a dead message |
|
244 if (m) |
|
245 { |
|
246 //aMessage will not be usable after the next line if it is obtained from the message array |
|
247 //instead of the one directly supplied by the client |
|
248 aSession->DeleteMessage(m); |
|
249 } |
|
250 } |
|
251 |
|
252 void PanicServer(TInt aPanic) |
|
253 /** |
|
254 Panic our own thread |
|
255 **/ |
|
256 { |
|
257 LOG_STATIC_FUNC |
|
258 LOG1(_L("PanicServer: Reason = %d"), aPanic); |
|
259 User::Panic(KBTManPanic, aPanic); |
|
260 } |
|
261 |
|
262 |
|
263 static void RunServerL() |
|
264 /** |
|
265 Perform all server initialisation, in particular creation of the |
|
266 scheduler and server and then run the scheduler |
|
267 **/ |
|
268 { |
|
269 LOG_STATIC_FUNC |
|
270 // create and install the active scheduler we need |
|
271 CActiveScheduler* scheduler=new(ELeave) CActiveScheduler; |
|
272 CleanupStack::PushL(scheduler); |
|
273 CActiveScheduler::Install(scheduler); |
|
274 // |
|
275 // create the server (leave it on the cleanup stack) |
|
276 CServer2* server = CBTManServer::NewLC(); |
|
277 // |
|
278 |
|
279 #ifdef __BTMANSERVER_NO_PROCESSES__ |
|
280 RThread::Rendezvous(KErrNone); |
|
281 #else |
|
282 // naming the server thread after the server helps to debug panics |
|
283 // ignore error - we tried the best we could |
|
284 User::RenameThread(KBTManServerName); |
|
285 |
|
286 RProcess::Rendezvous(KErrNone); |
|
287 #endif |
|
288 |
|
289 // |
|
290 // Ready to run |
|
291 CActiveScheduler::Start(); |
|
292 // |
|
293 // Cleanup the server and scheduler |
|
294 CleanupStack::PopAndDestroy(server); |
|
295 CleanupStack::PopAndDestroy(scheduler); |
|
296 } |
|
297 |
|
298 TInt E32Main() |
|
299 /** |
|
300 Main entry-point for the server process |
|
301 **/ |
|
302 { |
|
303 CONNECT_LOGGER |
|
304 LOG_STATIC_FUNC |
|
305 LOG(_L("BTManServer RunServer")); |
|
306 |
|
307 __UHEAP_MARK; |
|
308 #ifdef TEST_OOM //define TEST_OOM in preprocessor definitions in project settings |
|
309 __UHEAP_SETFAIL(RHeap::ERandom, 100); |
|
310 #endif |
|
311 CTrapCleanup* cleanup=CTrapCleanup::New(); |
|
312 TInt r=KErrNoMemory; |
|
313 if (cleanup) |
|
314 { |
|
315 TRAP(r,RunServerL()); |
|
316 delete cleanup; |
|
317 } |
|
318 // |
|
319 __UHEAP_MARKEND; |
|
320 CLOSE_LOGGER |
|
321 return r; |
|
322 } |
|
323 |
|
324 |
|
325 //===================================================================== |
|
326 //CBTManMessage |
|
327 //===================================================================== |
|
328 |
|
329 // This framework is retained as it allows instrinsically asynchronous actions to be |
|
330 // looked after easily. At present such actions are limited to change notifications |
|
331 // pretty much everything else is handled synchronously once the Server has had |
|
332 // its ServiceL called. |
|
333 |
|
334 CBTManMessage* CBTManMessage::NewL(const RMessage2& aMessage) |
|
335 { |
|
336 LOG_STATIC_FUNC |
|
337 CBTManMessage* m = new (ELeave) CBTManMessage(aMessage); |
|
338 CleanupStack::PushL(m); |
|
339 m->ConstructL(); |
|
340 CleanupStack::Pop(m); |
|
341 return m; |
|
342 } |
|
343 |
|
344 CBTManMessage::CBTManMessage(const RMessage2& aMessage) |
|
345 : iMessage(aMessage) |
|
346 { |
|
347 LOG_FUNC |
|
348 } |
|
349 |
|
350 void CBTManMessage::ConstructL() |
|
351 { |
|
352 LOG_FUNC |
|
353 if (iMessage.Ptr2()) |
|
354 { |
|
355 TPckgBuf<TBTManClientServerMessage> msgBuf; |
|
356 iMessage.ReadL(KBTManClientServerProtocolSlot, msgBuf); |
|
357 |
|
358 iCancelPtr = msgBuf().iClientStatusToCancel; |
|
359 } |
|
360 } |
|
361 |
|
362 |
|
363 CBTManMessage::~CBTManMessage() |
|
364 { |
|
365 LOG_FUNC |
|
366 //ensure we delete the helper if there is one |
|
367 if (iHelper) |
|
368 { |
|
369 iHelper->Delete(); |
|
370 } |
|
371 } |
|
372 |
|
373 void CBTManMessage::SetHelper(MBTManHelper* aHelper) |
|
374 /** |
|
375 Assigns a helper to the message. |
|
376 The helper will then be told to delete itself when the message is completed. |
|
377 This is especially important when cancelling or under leave conditions. |
|
378 **/ |
|
379 { |
|
380 LOG_FUNC |
|
381 __ASSERT_DEBUG(iHelper==NULL, PanicServer(EBTManBadHelper)); |
|
382 __ASSERT_DEBUG((aHelper->Message()).Ptr2() == iCancelPtr, PanicServer(EBTManBadHelper)); |
|
383 iHelper = aHelper; |
|
384 } |
|
385 |
|
386 void CBTManMessage::RemoveHelper() |
|
387 /** |
|
388 Disassociates a helper with a message. |
|
389 **/ |
|
390 { |
|
391 LOG_FUNC |
|
392 iHelper = NULL; |
|
393 } |
|
394 |
|
395 void CBTManMessage::Complete(TInt aReason) |
|
396 /** |
|
397 Completes the RMessage2 and deletes any associated helper. |
|
398 **/ |
|
399 { |
|
400 LOG_FUNC |
|
401 //complete the message |
|
402 iMessage.Complete(aReason); |
|
403 //delete the helper if there is one |
|
404 if (iHelper) |
|
405 iHelper->Delete(); |
|
406 } |
|
407 |
|
408 const RMessage2& CBTManMessage::Message() |
|
409 { |
|
410 LOG_FUNC |
|
411 return iMessage; |
|
412 } |
|
413 |
|
414 const TAny* CBTManMessage::CancelPtr() |
|
415 /** |
|
416 The CancelPtr is the address of the TRequestStatus of the client-side active object |
|
417 dealing with the request. When a request is cancelled, it is located server-side using |
|
418 this address. |
|
419 **/ |
|
420 { |
|
421 LOG_FUNC |
|
422 return iCancelPtr; |
|
423 } |
|
424 |
|
425 |
|
426 MBTManHelper* CBTManMessage::Helper() |
|
427 { |
|
428 LOG_FUNC |
|
429 return iHelper; |
|
430 } |
|
431 |
|
432 TBool CBTManMessage::operator==(CBTManMessage& aMessage) const |
|
433 { |
|
434 LOG_FUNC |
|
435 if (iMessage == aMessage.Message()) |
|
436 return ETrue; |
|
437 return EFalse; |
|
438 } |
|
439 |
|
440 //===================================================================== |
|
441 //CBTManSession |
|
442 //===================================================================== |
|
443 |
|
444 CBTManServer& CBTManSession::Server() |
|
445 { |
|
446 LOG_FUNC |
|
447 return *static_cast<CBTManServer*>(const_cast<CServer2*>(CSession2::Server())); |
|
448 } |
|
449 |
|
450 CBTManSession::CBTManSession(CBTRegistry& aRegistry, const RMessage2& aMessage) |
|
451 : iRegistry(aRegistry), iCurrentMessage(aMessage) |
|
452 { |
|
453 LOG_FUNC |
|
454 } |
|
455 |
|
456 void CBTManSession::CreateL() |
|
457 /** |
|
458 2nd phase construct for sessions - called by the CServer2 framework |
|
459 **/ |
|
460 { |
|
461 LOG_FUNC |
|
462 //CSession2::CreateL(); // private and does nowt so removed |
|
463 //Add session to server first. If anything leaves, it will be removed by the destructor |
|
464 Server().AddSession(); |
|
465 ConstructL(); |
|
466 } |
|
467 |
|
468 void CBTManSession::ConstructL() |
|
469 { |
|
470 LOG_FUNC |
|
471 //Create new object index |
|
472 iSubSessions = CObjectIx::NewL(); |
|
473 iContainer = Server().NewContainerL(); |
|
474 |
|
475 iMessageArray = new(ELeave) CArrayPtrFlat<CBTManMessage>(KMessageArrayGranularity); |
|
476 } |
|
477 |
|
478 CBTManSession::~CBTManSession() |
|
479 { |
|
480 LOG_FUNC |
|
481 if (iMessageArray) |
|
482 { |
|
483 CompleteOutstandingMessages(); |
|
484 iMessageArray->ResetAndDestroy(); |
|
485 } |
|
486 delete iMessageArray; |
|
487 delete iSubSessions; |
|
488 Server().DeleteContainer(iContainer); |
|
489 Server().DropSession(); |
|
490 } |
|
491 |
|
492 void CBTManSession::CompleteOutstandingMessages() |
|
493 /** |
|
494 Completes any messages left in the CBTManMessage array. |
|
495 **/ |
|
496 { |
|
497 LOG_FUNC |
|
498 CBTManMessage* ptr; |
|
499 TInt count = iMessageArray->Count(); |
|
500 LOG1(_L("CBTManSession::CompleteOutstandingMessages(): %d"), count); |
|
501 for (TInt i=(count-1); i>=0; i--) |
|
502 { |
|
503 ptr = iMessageArray->At(i); |
|
504 ptr->Complete(KErrDied); |
|
505 iMessageArray->Delete(i); |
|
506 delete ptr; |
|
507 ptr = NULL; |
|
508 } |
|
509 } |
|
510 |
|
511 |
|
512 CBTManSubSession* CBTManSession::SubSessionFromHandle(TInt aHandle) |
|
513 /** |
|
514 Returns a subsession given a handle |
|
515 |
|
516 @param aHandle the handle given by the client |
|
517 @param aMessage only used if we need to panic client's having used a dodgy handle |
|
518 **/ |
|
519 { |
|
520 LOG_FUNC |
|
521 CBTManSubSession* p = static_cast<CBTManSubSession*>(iSubSessions->At(aHandle)); |
|
522 return p; |
|
523 } |
|
524 |
|
525 TInt CBTManSession::HandleError(TInt aError, const RMessage2 &aMessage) |
|
526 /** |
|
527 Handle an error from ServiceL() |
|
528 A bad descriptor error implies a badly programmed client, so panic it; |
|
529 otherwise report the error to the client |
|
530 **/ |
|
531 { |
|
532 LOG_FUNC |
|
533 LOG1(_L("CBTManSession::HandleError(): %d"), aError); |
|
534 if (aError==KErrBadDescriptor || aError==KErrBadHandle) |
|
535 { |
|
536 #ifdef _DEBUG |
|
537 __DEBUGGER(); //******** SERVER STOP ****************** |
|
538 #endif |
|
539 TInt convErr = aError==KErrBadDescriptor?EBTManBadDescriptor:EBTManBadSubSessionHandle; |
|
540 PanicClient(aMessage, convErr, this); |
|
541 } |
|
542 else |
|
543 { |
|
544 CompleteMessage(aMessage, aError); |
|
545 } |
|
546 Server().ReStart(); |
|
547 return KErrNone; // handled the error fully |
|
548 } |
|
549 |
|
550 |
|
551 void CBTManSession::ServiceL(const RMessage2 &aMessage) |
|
552 /** |
|
553 Handle a client request. |
|
554 Leaving is handled by HandleError() which reports the error code |
|
555 to the client |
|
556 **/ |
|
557 { |
|
558 LOG_FUNC |
|
559 //We don't need to create a message object if message is handled by session |
|
560 //Simply dispatch and complete the message |
|
561 TBool handled = ETrue; |
|
562 |
|
563 TRAPD(err, handled = DispatchSessMessageL(aMessage)); |
|
564 if (handled || (err!=KErrNone)) |
|
565 { |
|
566 if (!iClientPanic) |
|
567 { |
|
568 // Don't complete messages already completed by ClientPanic |
|
569 aMessage.Complete(err); |
|
570 } |
|
571 else |
|
572 { |
|
573 //Client Panic Handled - Reset Flag. |
|
574 iClientPanic = EFalse; |
|
575 } |
|
576 return; |
|
577 } |
|
578 |
|
579 //not handled by session so must be for subsession |
|
580 //Create a message object to handle this |
|
581 //We need to trap this so a leave doesn't propogate to active scheduler |
|
582 err = KErrNone; |
|
583 TRAP(err, CreateBTManMessageL(aMessage)); |
|
584 if (err) |
|
585 { |
|
586 aMessage.Complete(err); |
|
587 return; |
|
588 } |
|
589 |
|
590 //Trap dispatchSubSessMessage so we can handle error here |
|
591 err=KErrNone; |
|
592 TRAP(err, DispatchSubSessMessageL(aMessage)); |
|
593 //if we have an error, try to handle it with handleerror. If this fails, leave |
|
594 //and let the active scheduler sort it out. |
|
595 if (err != KErrNone) |
|
596 { |
|
597 // tell subsessions to try to reduce footprint and rollback |
|
598 for (TInt i = 0; i<iSubSessions->Count(); i++) |
|
599 { |
|
600 //check this element is an actual object rather than an empty memory |
|
601 //cell on the free list |
|
602 if((*iSubSessions)[i]) |
|
603 { |
|
604 static_cast<CBTManSubSession*>((*iSubSessions)[i])->Cleanup(err); |
|
605 } |
|
606 } |
|
607 // Tidy up of logic and construct |
|
608 if (err != KErrNone) |
|
609 { |
|
610 User::LeaveIfError(HandleError(err, aMessage)); |
|
611 return; |
|
612 } |
|
613 } |
|
614 } |
|
615 |
|
616 void CBTManSession::CreateBTManMessageL(const RMessage2& aMessage) |
|
617 /** |
|
618 Creates a CBTManMessage and appends it to iMessageArray. |
|
619 These are used for the BTMan server to conduct asynchronous activities itself |
|
620 |
|
621 Many activities that the BTMan Server does at present are synchronously handled; but |
|
622 for conformity all the subsessions use this framework so that any asynchronous |
|
623 tasks can be added later |
|
624 |
|
625 @param aMessage The original client message |
|
626 **/ |
|
627 { |
|
628 LOG_FUNC |
|
629 CBTManMessage* m = CBTManMessage::NewL(aMessage); |
|
630 CleanupStack::PushL(m); |
|
631 iMessageArray->AppendL(m); |
|
632 CleanupStack::Pop(); |
|
633 } |
|
634 |
|
635 |
|
636 TBool CBTManSession::DispatchSessMessageL(const RMessage2 &aMessage) |
|
637 /** |
|
638 Handles the request - it may not actually be for the session |
|
639 |
|
640 @param aMessage The current message being handled. |
|
641 @return ETrue: The message was meant for the session. |
|
642 @return EFalse: The message was meant for a subsession. |
|
643 **/ |
|
644 { |
|
645 LOG_FUNC |
|
646 switch (aMessage.Function()) |
|
647 { |
|
648 case EBTManCreateRegistrySubSession: |
|
649 NewSubSessionL(ERegistry, aMessage); |
|
650 return ETrue; |
|
651 case EBTManCreateLocalDeviceSubSession: |
|
652 NewSubSessionL(ELocalDevice, aMessage); |
|
653 return ETrue; |
|
654 case EBTManCreateCommPortSettingsSubSession: |
|
655 NewSubSessionL(ECommPortSettings, aMessage); |
|
656 return ETrue; |
|
657 case EBTManCreateHostResolverSubSession: |
|
658 NewSubSessionL(EHostResolver, aMessage); |
|
659 return ETrue; |
|
660 case EBTManCancelRequest: |
|
661 CancelRequest(aMessage); |
|
662 return ETrue; |
|
663 case EBTManCloseSubSession: |
|
664 CloseSubSession(aMessage); |
|
665 return ETrue; |
|
666 case EBTManSetHeapFailure: |
|
667 #ifdef _DEBUG |
|
668 User::__DbgSetAllocFail(RHeap::EUser,RHeap::TAllocFail(aMessage.Int0()),aMessage.Int1()); |
|
669 #endif |
|
670 return ETrue; |
|
671 case EBTManSubSessionCount: |
|
672 { |
|
673 #ifdef _DEBUG |
|
674 TPckgBuf<TInt> pckg(iSubSessions->Count()); |
|
675 aMessage.WriteL(0, pckg); |
|
676 #endif |
|
677 return ETrue; |
|
678 } |
|
679 default: |
|
680 //not handled here so must be for subsession |
|
681 return EFalse; |
|
682 } |
|
683 } |
|
684 |
|
685 void CBTManSession::DispatchSubSessMessageL(const RMessage2& aMessage) |
|
686 /** |
|
687 Handles subsession requests. |
|
688 |
|
689 @param aMessage The current message being handled. |
|
690 **/ |
|
691 { |
|
692 LOG_FUNC |
|
693 CBTManSubSession& ss = *SubSessionFromHandle(aMessage.Int3()); |
|
694 if (&ss == NULL) |
|
695 { |
|
696 User::Leave(KErrBadHandle); |
|
697 } |
|
698 |
|
699 // Get the status of the client request (sent on all msgs in slot2) |
|
700 switch (aMessage.Function()) |
|
701 { |
|
702 case EBTManRegistrySearch: |
|
703 { |
|
704 TBTRegistrySearchPckgBuf pckg; |
|
705 aMessage.ReadL(0, pckg); |
|
706 static_cast<CBTRegistrySubSession*>(&ss)->OpenViewL(pckg(), aMessage); |
|
707 break; |
|
708 } |
|
709 case EBTRegistryAddDevice: |
|
710 { |
|
711 // create a new device subsession and add the device - may change API to require |
|
712 // previously opened subsession?? |
|
713 // need to internalise a contiguated buffer |
|
714 |
|
715 TInt len = aMessage.GetDesLengthL(0); |
|
716 HBufC8* buffer = HBufC8::NewLC(len); |
|
717 TPtr8 ptr(buffer->Des()); |
|
718 |
|
719 aMessage.ReadL(0, ptr); |
|
720 RDesReadStream stream; |
|
721 stream.Open(ptr); |
|
722 CleanupClosePushL(stream); |
|
723 |
|
724 CBTDevice* addDetails = CBTDevice::NewLC(); |
|
725 addDetails->InternalizeL(stream); |
|
726 |
|
727 static_cast<CBTRegistrySubSession*>(&ss)->AddDeviceL(*addDetails, aMessage); |
|
728 |
|
729 CleanupStack::PopAndDestroy(3); //addDetails, stream, buffer |
|
730 break; |
|
731 } |
|
732 case EBTRegistryModifyNamelessDevice: |
|
733 { |
|
734 LOG(_L("CBTManSession -> ModifyNamelessDevice")); |
|
735 TBTNamelessDevicePckgBuf pckg; |
|
736 aMessage.ReadL(0, pckg); |
|
737 static_cast<CBTRegistrySubSession*>(&ss)->ModifyL(pckg(), aMessage); |
|
738 break; |
|
739 } |
|
740 case EBTRegistryGetNamelessDevice: |
|
741 { |
|
742 TBTNamelessDevicePckgBuf pckg; |
|
743 aMessage.ReadL(0, pckg); |
|
744 static_cast<CBTRegistrySubSession*>(&ss)->GetDeviceL(pckg(), aMessage); |
|
745 break; |
|
746 } |
|
747 case EBTManExtractRegistryDataIntoServer: |
|
748 { |
|
749 static_cast<CBTRegistrySubSession*>(&ss)->PreLoadL(aMessage); |
|
750 break; |
|
751 } |
|
752 |
|
753 case EBTManRetrieveRegistryData: |
|
754 { |
|
755 static_cast<CBTRegistrySubSession*>(&ss)->RetrieveL(aMessage); |
|
756 break; |
|
757 } |
|
758 |
|
759 case EBTRegistryDeleteLinkKey: |
|
760 { |
|
761 TBTDevAddrPckgBuf pckg; |
|
762 aMessage.ReadL(0, pckg); |
|
763 static_cast<CBTRegistrySubSession*>(&ss)->UnpairL(pckg(), aMessage); |
|
764 break; |
|
765 } |
|
766 |
|
767 case EBTRegistryDeleteDevices: |
|
768 { |
|
769 //nothing to read |
|
770 static_cast<CBTRegistrySubSession*>(&ss)->DeleteViewL(aMessage); |
|
771 break; |
|
772 } |
|
773 |
|
774 case EBTRegistryModifyBluetoothName: |
|
775 case EBTRegistryModifyFriendlyName: |
|
776 { |
|
777 // read the address - this could move into the handler |
|
778 TBTDevAddrPckgBuf addr; |
|
779 aMessage.ReadL(0, addr); |
|
780 static_cast<CBTRegistrySubSession*>(&ss)->ModifyNameL(addr(), aMessage); |
|
781 break; |
|
782 } |
|
783 |
|
784 case EBTRegistryGetLocalDevice: |
|
785 { |
|
786 //nothing to read |
|
787 static_cast<CBTLocalDeviceSubSession*>(&ss)->GetL(aMessage); |
|
788 break; |
|
789 } |
|
790 |
|
791 case EBTRegistryUpdateLocalDevice: |
|
792 { |
|
793 TPckgBuf<TBTLocalDevice> pckg; |
|
794 aMessage.ReadL(0, pckg); |
|
795 static_cast<CBTLocalDeviceSubSession*>(&ss)->UpdateL(pckg(), aMessage); |
|
796 break; |
|
797 } |
|
798 |
|
799 case EBTRegistryGetCommPortSettings: |
|
800 { |
|
801 TPckgBuf<TBTCommPortSettings> pckg; |
|
802 aMessage.ReadL(0, pckg); |
|
803 static_cast<CBTCommPortSettingsSubSession*>(&ss)->GetL(pckg(), aMessage); |
|
804 break; |
|
805 } |
|
806 |
|
807 case EBTRegistryUpdateCommPortSettings: |
|
808 { |
|
809 TPckgBuf<TBTCommPortSettings> pckg; |
|
810 aMessage.ReadL(0, pckg); |
|
811 static_cast<CBTCommPortSettingsSubSession*>(&ss)->UpdateL(pckg(), aMessage); |
|
812 break; |
|
813 } |
|
814 |
|
815 case EBTRegistryDeleteCommPortSettings: |
|
816 { |
|
817 TPckgBuf<TBTCommPortSettings> pckg; |
|
818 aMessage.ReadL(0, pckg); |
|
819 static_cast<CBTCommPortSettingsSubSession*>(&ss)->DeleteL(pckg(), aMessage); |
|
820 break; |
|
821 } |
|
822 |
|
823 case EBTRegistryUnpairView: |
|
824 { |
|
825 static_cast<CBTRegistrySubSession*>(&ss)->UnpairViewL(aMessage); |
|
826 break; |
|
827 } |
|
828 |
|
829 case EBTRegistryCloseView: |
|
830 { |
|
831 static_cast<CBTRegistrySubSession*>(&ss)->CloseView(aMessage); |
|
832 break; |
|
833 } |
|
834 |
|
835 case EBTRegistryNotifyViewChange: |
|
836 { |
|
837 ss.SetViewChangeNotificationMessage(aMessage); |
|
838 break; |
|
839 } |
|
840 |
|
841 case EBTHostResolverDeviceRequest: |
|
842 case EBTHostResolverDeviceModifyDevice: |
|
843 default: |
|
844 PanicClient(aMessage, EBTManBadRequest, this); |
|
845 return; |
|
846 } |
|
847 } |
|
848 |
|
849 void CBTManSession::NewSubSessionL(TSubSessionType aType, const RMessage2 &aMessage) |
|
850 /** |
|
851 Create a subsession of type aType and add it to the object index. |
|
852 **/ |
|
853 { |
|
854 LOG_FUNC |
|
855 //Make new counter object |
|
856 CBTManSubSession* ss = NULL; |
|
857 switch (aType) |
|
858 { |
|
859 case ERegistry: |
|
860 ss = CBTRegistrySubSession::NewL(*this, iRegistry); |
|
861 break; |
|
862 case ELocalDevice: |
|
863 ss = CBTLocalDeviceSubSession::NewL(*this, iRegistry); |
|
864 break; |
|
865 case ECommPortSettings: |
|
866 ss = CBTCommPortSettingsSubSession::NewL(*this, iRegistry); |
|
867 break; |
|
868 case EHostResolver: |
|
869 default: |
|
870 PanicServer(EBTManBadSubSessionType); |
|
871 } |
|
872 |
|
873 //add to container to generate unique id |
|
874 //If anything goes wrong, make sure we close the subsession. |
|
875 CleanupClosePushL(*ss); |
|
876 |
|
877 iContainer->AddL(ss); |
|
878 |
|
879 //add to object index - this returns a unique handle |
|
880 // From inspection of CObjectIx::AddL(), it will can only leave BEFORE ss is added to the index. |
|
881 // Therefore, we must close the subsession and leave if anything goes wrong, |
|
882 // and NOT call CObjectIx::Remove(). |
|
883 TInt handle = 0; |
|
884 handle = iSubSessions->AddL(ss); |
|
885 |
|
886 //ss now has an owner so we can pop it off the cleanupstack |
|
887 CleanupStack::Pop(); //ss |
|
888 |
|
889 //Write handle to client |
|
890 //If anything goes wrong, call CObjectIx::Remove(). This will close the subsession for us. |
|
891 TPckg<TInt> pckg(handle); |
|
892 TRAPD(err, aMessage.WriteL(3, pckg)); |
|
893 if (err!=KErrNone) |
|
894 { |
|
895 iSubSessions->Remove(handle); |
|
896 User::Leave(err); |
|
897 } |
|
898 //increase resource count |
|
899 iResourceCount++; |
|
900 } |
|
901 |
|
902 void CBTManSession::DeleteSubsession(TInt aHandle, const RMessage2 &aMessage) |
|
903 { |
|
904 LOG_FUNC |
|
905 //panic client if bad handle |
|
906 CBTManSubSession* ss = (CBTManSubSession*)iSubSessions->At(aHandle); |
|
907 if (ss == NULL) |
|
908 { |
|
909 PanicClient(aMessage, EBTManBadSubSessionRemove, this); |
|
910 //Flag that Client has been panic'd |
|
911 //so that the message is not completed twice |
|
912 iClientPanic = ETrue; |
|
913 } |
|
914 else |
|
915 { |
|
916 iSubSessions->Remove(aHandle); |
|
917 //decrement resource count |
|
918 iResourceCount--; |
|
919 } |
|
920 } |
|
921 |
|
922 void CBTManSession::CloseSubSession(const RMessage2 &aMessage) |
|
923 { |
|
924 LOG_FUNC |
|
925 // handle for subsession is in slot3 |
|
926 DeleteSubsession(aMessage.Int3(), aMessage); |
|
927 } |
|
928 |
|
929 void CBTManSession::CompleteMessage(const RMessage2& aMessage, TInt aReason) |
|
930 /** |
|
931 Finds a message based on aMessage and completes it. |
|
932 **/ |
|
933 { |
|
934 LOG_FUNC |
|
935 CBTManMessage* m = FindMessage(aMessage); |
|
936 __ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage)); |
|
937 DoCompleteMessage(*m, aReason); |
|
938 } |
|
939 |
|
940 void CBTManSession::CompleteMessage(MBTManHelper* aHelper, TInt aReason) |
|
941 /** |
|
942 Finds a message based on aHelper and completes it. |
|
943 **/ |
|
944 { |
|
945 LOG_FUNC |
|
946 CBTManMessage* m = FindMessage(aHelper); |
|
947 __ASSERT_DEBUG(m!=NULL, PanicServer(EBTManBadBTManMessage)); |
|
948 DoCompleteMessage(*m, aReason); |
|
949 } |
|
950 |
|
951 void CBTManSession::DoCompleteMessage(CBTManMessage& aMessage, TInt aReason) |
|
952 /** |
|
953 Actually does the completion |
|
954 **/ |
|
955 { |
|
956 LOG_FUNC |
|
957 if (aMessage.Message().Ptr2()) |
|
958 { |
|
959 // notify clientAPI that we've serviced it - not needed if the client has |
|
960 // not asked us to (typically for synchronous calls) |
|
961 TBTManClientServerMessage clientMsg; |
|
962 TPckg<TBTManClientServerMessage> clientMsgBuf(clientMsg); |
|
963 TRAPD(err_read, aMessage.Message().ReadL(KBTManClientServerProtocolSlot, clientMsgBuf)); |
|
964 clientMsg.iClientBusy=EFalse; |
|
965 TRAPD(err_write, aMessage.Message().WriteL(KBTManClientServerProtocolSlot, clientMsgBuf)); |
|
966 |
|
967 if(err_read != KErrNone || err_write != KErrNone) |
|
968 { |
|
969 PanicClient(aMessage.Message(),EBTManBadBTManMessage, this); |
|
970 return; |
|
971 } |
|
972 } |
|
973 // now tell the kernel |
|
974 aMessage.Complete(aReason); |
|
975 DeleteMessage(&aMessage); |
|
976 } |
|
977 |
|
978 CBTManMessage* CBTManSession::FindMessage(const RMessage2& aMessage) |
|
979 /** |
|
980 Searches the array of CBTManMessages for the one dealing with aMessage. |
|
981 **/ |
|
982 { |
|
983 LOG_FUNC |
|
984 CBTManMessage* ptr; |
|
985 for (TInt i=0; i<iMessageArray->Count(); i++) |
|
986 { |
|
987 ptr = iMessageArray->At(i); |
|
988 if(ptr->Message() == aMessage) |
|
989 { |
|
990 return ptr; |
|
991 } |
|
992 } |
|
993 return NULL; |
|
994 } |
|
995 |
|
996 CBTManMessage* CBTManSession::FindMessage(MBTManHelper* aHelper) |
|
997 /** |
|
998 Searches the array of CBTManMessages for the one containing a pointer to aHelper. |
|
999 **/ |
|
1000 { |
|
1001 LOG_FUNC |
|
1002 CBTManMessage* ptr; |
|
1003 for (TInt i=0; i<iMessageArray->Count(); i++) |
|
1004 { |
|
1005 ptr = iMessageArray->At(i); |
|
1006 if(ptr->Helper() == aHelper) |
|
1007 { |
|
1008 return ptr; |
|
1009 } |
|
1010 } |
|
1011 return NULL; |
|
1012 } |
|
1013 |
|
1014 void CBTManSession::DeleteMessage(CBTManMessage* aMessage) |
|
1015 /** |
|
1016 Find the CBTManMessage in the message array and delete it. |
|
1017 **/ |
|
1018 { |
|
1019 LOG_FUNC |
|
1020 CBTManMessage* ptr; |
|
1021 TInt count = iMessageArray->Count(); |
|
1022 for (TInt i=(count-1); i>=0; i--) |
|
1023 { |
|
1024 ptr = iMessageArray->At(i); |
|
1025 if(ptr == aMessage) |
|
1026 { |
|
1027 //Delete the message first before removing from the array since a helper associated |
|
1028 //with the message will try to find the message by parsing the array as part of the |
|
1029 //destruction the message. |
|
1030 delete ptr; |
|
1031 iMessageArray->Delete(i); |
|
1032 ptr = NULL; |
|
1033 break; |
|
1034 } |
|
1035 } |
|
1036 //compress the array if the count is less than the length - granularity AND if the count != 0 |
|
1037 if (iMessageArray->Count()) |
|
1038 { |
|
1039 if (iMessageArray->Length() - iMessageArray->Count() >= KMessageArrayGranularity) |
|
1040 { |
|
1041 iMessageArray->Compress(); |
|
1042 } |
|
1043 } |
|
1044 } |
|
1045 |
|
1046 void CBTManSession::CancelRequest(const RMessage2& aMessage) |
|
1047 /** |
|
1048 Cancels an asyncronous request. |
|
1049 We need to find the asynchronous message we are cancelling |
|
1050 - we can do this by comparing the TRequestStatus held |
|
1051 in Ptr2() of the message. This is ok since ALL asynchronous |
|
1052 requests to this server have the TRequestStatus passed over |
|
1053 in Ptr2() and only these may be cancelled. The TRequestStatus |
|
1054 is sent over in ptr0() of the cancel request so we don't confuse |
|
1055 the cancel message with the one we are trying to cancel. |
|
1056 **/ |
|
1057 { |
|
1058 LOG_FUNC |
|
1059 CBTManMessage* m; |
|
1060 TInt count = iMessageArray->Count(); |
|
1061 for (TInt i=(count-1); i>=0; i--) |
|
1062 { |
|
1063 m = iMessageArray->At(i); |
|
1064 if (m->CancelPtr() == aMessage.Ptr0()) |
|
1065 { |
|
1066 //Complete the message |
|
1067 m->Complete(KErrCancel); |
|
1068 //delete the message from the array |
|
1069 iMessageArray->Delete(i); |
|
1070 delete m; |
|
1071 m = NULL; |
|
1072 break; |
|
1073 } |
|
1074 } |
|
1075 //aMessage will be completed by CBTManSession::ServiceL() |
|
1076 } |
|
1077 |
|
1078 TBool CBTManSession::SubSessionHasOverlappingView(CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor) |
|
1079 { |
|
1080 LOG_FUNC |
|
1081 // Iterate over all subsessions apart from the view owner |
|
1082 TBool overlapFound = EFalse; |
|
1083 for (TInt i = 0; i < iContainer->Count(); i++) |
|
1084 { |
|
1085 CBTManSubSession* ss = static_cast<CBTManSubSession*>((*iContainer)[i]); |
|
1086 if (&aSubSessionViewOwner != ss) |
|
1087 { |
|
1088 if (ss->IsOverlappingView(aViewDescriptor)) |
|
1089 { |
|
1090 // Overlaps - subsession will have completed the Notify message |
|
1091 // With bool return, we can test if indeed it did. |
|
1092 overlapFound = ETrue; |
|
1093 } |
|
1094 } |
|
1095 } |
|
1096 |
|
1097 return overlapFound; |
|
1098 } |
|
1099 |
|
1100 |
|
1101 //===================================================================== |
|
1102 // CBTManSubSession |
|
1103 //===================================================================== |
|
1104 |
|
1105 CBTManSubSession::CBTManSubSession(CBTManSession& aSession, CBTRegistry& aRegistry) : |
|
1106 iSession(aSession), iRegistry(aRegistry) |
|
1107 { |
|
1108 LOG_FUNC |
|
1109 } |
|
1110 |
|
1111 void CBTManSubSession::NotifyChange(TUint aTableChanged) |
|
1112 { |
|
1113 LOG_FUNC |
|
1114 iSession.Server().Publish(KPropertyKeyBluetoothGetRegistryTableChange, |
|
1115 aTableChanged); |
|
1116 } |
|
1117 |
|
1118 void CBTManSubSession::NotifyChange(TUint aTableChanged, CBTManSubSession& aSubSessionViewOwner, const TDesC& aViewDescriptor) |
|
1119 { |
|
1120 LOG_FUNC |
|
1121 NotifyChange(aTableChanged); |
|
1122 iSession.Server().NotifyViewChange(aSubSessionViewOwner, aViewDescriptor); |
|
1123 } |
|
1124 |
|
1125 /*virtual*/ TBool CBTManSubSession::IsOverlappingView(const TDesC& /*aViewDescriptor*/) |
|
1126 { |
|
1127 LOG_FUNC |
|
1128 // By default, not supported - so no overlapping view. |
|
1129 return EFalse; |
|
1130 } |
|
1131 |
|
1132 /*virtual*/ void CBTManSubSession::SetViewChangeNotificationMessage(const RMessage2& aMessage) |
|
1133 { |
|
1134 LOG_FUNC |
|
1135 // By default, not supported |
|
1136 iSession.CompleteMessage(aMessage, KErrNotSupported); |
|
1137 } |
|
1138 |
|
1139 #ifdef __BTMANSERVER_NO_PROCESSES__ |
|
1140 |
|
1141 // The server binary is an "EPOCEXE" target type |
|
1142 // Thus the server parameter passing and startup code for WINS and EPOC are |
|
1143 // significantly different. |
|
1144 // |
|
1145 // In EKA1 WINS, the EPOCEXE target is a DLL with an entry point called WinsMain, |
|
1146 // taking no parameters and returning TInt. This is not really valid as a thread |
|
1147 // function which takes a TAny* parameter which we need. |
|
1148 // |
|
1149 // So the DLL entry-point WinsMain() is used to return a TInt representing the |
|
1150 // real thread function within the DLL. This is good as long as |
|
1151 // sizeof(TInt)>=sizeof(TThreadFunction). |
|
1152 // |
|
1153 |
|
1154 static TInt ThreadFunction(TAny*) |
|
1155 // |
|
1156 // WINS thread entry-point function. |
|
1157 // |
|
1158 { |
|
1159 LOG_FUNC |
|
1160 return E32Main(); |
|
1161 } |
|
1162 |
|
1163 IMPORT_C TInt WinsMain(); |
|
1164 EXPORT_C TInt WinsMain() |
|
1165 // |
|
1166 // WINS DLL entry-point. Just return the real thread function |
|
1167 // cast to TInt |
|
1168 // |
|
1169 { |
|
1170 LOG_FUNC |
|
1171 return reinterpret_cast<TInt>(&ThreadFunction); |
|
1172 } |
|
1173 |
|
1174 TInt E32Dll(TDllReason) |
|
1175 { |
|
1176 LOG_FUNC |
|
1177 return KErrNone; |
|
1178 } |
|
1179 |
|
1180 #endif |