|
1 // Copyright (c) 2003-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 // Implements the avdtp logical channel factory |
|
15 // which creates the logical (L2CAP) channels for transport and signalling channels |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalComponent |
|
22 */ |
|
23 |
|
24 #include <bluetooth/logger.h> |
|
25 #include <bluetoothav.h> |
|
26 |
|
27 #include "bt.h" |
|
28 #include "avdtpLogicalChannelFactory.h" |
|
29 #include "gavdpinterface.h" |
|
30 #include "avdtputil.h" |
|
31 #include "avdtp.h" |
|
32 #include "avdtpDirectChannel.h" |
|
33 |
|
34 #ifdef __FLOG_ACTIVE |
|
35 _LIT8(KLogComponent, LOG_COMPONENT_AVDTP); |
|
36 #endif |
|
37 |
|
38 CLogicalChannelFactory* CLogicalChannelFactory::NewL(CBluetoothProtocolBase& aProtocol, CProtocolBase& aSAPFactory) |
|
39 { |
|
40 LOG_STATIC_FUNC |
|
41 CLogicalChannelFactory* f = new (ELeave) CLogicalChannelFactory(aProtocol, aSAPFactory); |
|
42 CleanupStack::PushL(f); |
|
43 f->ConstructL(); |
|
44 CleanupStack::Pop(f); |
|
45 return f; |
|
46 } |
|
47 |
|
48 |
|
49 CLogicalChannelFactory::CLogicalChannelFactory(CBluetoothProtocolBase& aProtocol, |
|
50 CProtocolBase& aSAPFactory) |
|
51 : iProtocol(aProtocol), iBearerSAPFactory(aSAPFactory), |
|
52 iUnclaimedLogicalChannels(_FOFF(CManagedLogicalChannel, iFactoryQLink)), |
|
53 iPendingActiveJobs(_FOFF(CLogicalChannelFactoryRequest, iFactoryQLink)), |
|
54 iPendingPassiveSignallingJobs(_FOFF(CLogicalChannelFactoryRequest, iFactoryQLink)), |
|
55 iPendingPassiveSessionJobs(_FOFF(CLogicalChannelFactoryRequest, iFactoryQLink)), |
|
56 iCloseChannelJobs(_FOFF(CLogicalChannelFactoryRequest, iFactoryQLink)) |
|
57 { |
|
58 LOG_FUNC |
|
59 } |
|
60 |
|
61 CLogicalChannelFactory::~CLogicalChannelFactory() |
|
62 { |
|
63 LOG_FUNC |
|
64 iProtocol.StopProtocolListening(); |
|
65 // iterator through jobs and destroy - they'll take down unclaimed channels |
|
66 TSglQueIter<CLogicalChannelFactoryActiveRequest> iter(iPendingActiveJobs); |
|
67 |
|
68 while (iter) |
|
69 { |
|
70 delete iter++; |
|
71 } |
|
72 |
|
73 TSglQueIter<CCloseSessionLogicalChannels> closeIter(iCloseChannelJobs); |
|
74 while(closeIter) |
|
75 { |
|
76 delete closeIter++; |
|
77 } |
|
78 |
|
79 TDblQueIter<CManagedLogicalChannel> unclaimedChannelsIter(iUnclaimedLogicalChannels); |
|
80 |
|
81 while (unclaimedChannelsIter) |
|
82 { |
|
83 delete unclaimedChannelsIter++; |
|
84 } |
|
85 |
|
86 // We shouldn't be deleted when we have a job outstanding |
|
87 __ASSERT_DEBUG(!iAsyncTryNextJob->IsActive(), Panic(EAvdtpLogicalChannelFactoryDeletionWhileJobPending)); |
|
88 delete iAsyncTryNextJob; |
|
89 delete iCurrentActiveJob; |
|
90 } |
|
91 |
|
92 void CLogicalChannelFactory::ConstructL() |
|
93 { |
|
94 LOG_FUNC |
|
95 TCallBack callback(TryNextJob, this); |
|
96 iAsyncTryNextJob = new(ELeave) CAsyncCallBack(callback, CActive::EPriorityStandard); |
|
97 } |
|
98 |
|
99 |
|
100 CCreateSignallingLogicalChannel* CCreateSignallingLogicalChannel::NewLC(const TBTDevAddr& aAddr, |
|
101 XLogicalChannelFactoryClient& aClient, |
|
102 TLogicalChannelFactoryRequestId aId, |
|
103 CLogicalChannelFactory& aLogicalChannelFactory) |
|
104 { |
|
105 LOG_STATIC_FUNC |
|
106 CCreateSignallingLogicalChannel* r = new (ELeave) CCreateSignallingLogicalChannel(aAddr, aClient, aId); |
|
107 CleanupStack::PushL(r); |
|
108 r->ConstructL(aLogicalChannelFactory); // create the channel holders |
|
109 return r; |
|
110 } |
|
111 |
|
112 CCreateSignallingLogicalChannel* CCreateSignallingLogicalChannel::NewL(const TBTDevAddr& aAddr, |
|
113 XLogicalChannelFactoryClient& aClient, |
|
114 TLogicalChannelFactoryRequestId aId, |
|
115 CLogicalChannelFactory& aLogicalChannelFactory) |
|
116 { |
|
117 LOG_STATIC_FUNC |
|
118 CCreateSignallingLogicalChannel* r = |
|
119 CCreateSignallingLogicalChannel::NewLC(aAddr, |
|
120 aClient, |
|
121 aId, |
|
122 aLogicalChannelFactory); |
|
123 CleanupStack::Pop(); |
|
124 return r; |
|
125 } |
|
126 |
|
127 |
|
128 void CCreateSignallingLogicalChannel::ConstructL(CLogicalChannelFactory& aLogicalChannelFactory) |
|
129 { |
|
130 LOG_FUNC |
|
131 iLogicalChannels[0] = CManagedLogicalChannel::NewL(aLogicalChannelFactory, |
|
132 iRemoteDev, |
|
133 KInitialSequenceNumber, |
|
134 iId); |
|
135 } |
|
136 |
|
137 |
|
138 CCreateSignallingLogicalChannel::CCreateSignallingLogicalChannel(const TBTDevAddr& aAddr, XLogicalChannelFactoryClient& aClient, TLogicalChannelFactoryRequestId aId) |
|
139 : CLogicalChannelFactoryActiveRequest(aAddr, aClient, aId) |
|
140 { |
|
141 LOG_FUNC |
|
142 // this job has one channel |
|
143 iNumChannelsRequired = 1; |
|
144 // so SAP[0] is a signalling SAP |
|
145 } |
|
146 |
|
147 CCreateSessionLogicalChannels* CCreateSessionLogicalChannels::NewLC(const TBTDevAddr& aAddr, |
|
148 XLogicalChannelFactoryClient& aClient, |
|
149 TLogicalChannelFactoryRequestId aId, |
|
150 TInt aNumRequired) |
|
151 { |
|
152 LOG_STATIC_FUNC |
|
153 CCreateSessionLogicalChannels* r = |
|
154 new (ELeave) CCreateSessionLogicalChannels(aAddr, aClient, aId, aNumRequired); |
|
155 CleanupStack::PushL(r); |
|
156 return r; |
|
157 } |
|
158 |
|
159 CCreateSessionLogicalChannels* CCreateSessionLogicalChannels::NewL(const TBTDevAddr& aAddr, |
|
160 XLogicalChannelFactoryClient& aClient, |
|
161 TLogicalChannelFactoryRequestId aId, |
|
162 TInt aNumRequired) |
|
163 { |
|
164 LOG_STATIC_FUNC |
|
165 CCreateSessionLogicalChannels* r = new (ELeave) CCreateSessionLogicalChannels(aAddr, |
|
166 aClient, |
|
167 aId, |
|
168 aNumRequired); |
|
169 return r; |
|
170 } |
|
171 |
|
172 CCreateSessionLogicalChannels::CCreateSessionLogicalChannels(const TBTDevAddr& aAddr, |
|
173 XLogicalChannelFactoryClient& aClient, |
|
174 TLogicalChannelFactoryRequestId aId, |
|
175 TInt aNumRequired) |
|
176 : CLogicalChannelFactoryActiveRequest(aAddr, aClient, aId) |
|
177 { |
|
178 LOG_FUNC |
|
179 // this job has one, two or three channels - but all need to come up for success |
|
180 iNumChannelsRequired = aNumRequired; |
|
181 } |
|
182 |
|
183 //************************************************************************ |
|
184 // Close Logical Channels |
|
185 //************************************************************************ |
|
186 |
|
187 CCloseSessionLogicalChannels* CCloseSessionLogicalChannels::NewL(XLogicalChannelFactoryClient& aClient, |
|
188 TLogicalChannelFactoryRequestId aId) |
|
189 { |
|
190 LOG_STATIC_FUNC |
|
191 CCloseSessionLogicalChannels* r = CCloseSessionLogicalChannels::NewLC(aClient, aId); |
|
192 CleanupStack::Pop(r); |
|
193 return r; |
|
194 } |
|
195 |
|
196 CCloseSessionLogicalChannels* CCloseSessionLogicalChannels::NewLC(XLogicalChannelFactoryClient& aClient, |
|
197 TLogicalChannelFactoryRequestId aId) |
|
198 { |
|
199 LOG_STATIC_FUNC |
|
200 CCloseSessionLogicalChannels* r = new (ELeave) CCloseSessionLogicalChannels(aClient, |
|
201 aId); |
|
202 CleanupStack::PushL(r); |
|
203 return r; |
|
204 } |
|
205 |
|
206 CCloseSessionLogicalChannels::~CCloseSessionLogicalChannels() |
|
207 { |
|
208 LOG_STATIC_FUNC |
|
209 BTSocketTimer::Remove(iTimerEntry); |
|
210 CloseChannels(EFalse); |
|
211 } |
|
212 |
|
213 /** |
|
214 One of this job's logical channels has been closed by the remote. If this |
|
215 is the final remaining channel the job is completed. |
|
216 |
|
217 @param aChannel The channel that has been closed. |
|
218 */ |
|
219 void CCloseSessionLogicalChannels::ChannelClosed(CManagedLogicalChannel* aChannel) |
|
220 { |
|
221 LOG_FUNC |
|
222 |
|
223 TBool channelsRemaining = EFalse; |
|
224 |
|
225 for(TInt i = 0; i < KAvdtpChannelArraySize; i++) |
|
226 { |
|
227 if(iLogicalChannels[i] == aChannel) |
|
228 { |
|
229 iLogicalChannels[i] = NULL; |
|
230 } |
|
231 else if(iLogicalChannels[i]) |
|
232 { |
|
233 channelsRemaining = ETrue; |
|
234 } |
|
235 } |
|
236 |
|
237 aChannel->Shutdown(); |
|
238 delete aChannel; |
|
239 |
|
240 if(!channelsRemaining) |
|
241 { |
|
242 BTSocketTimer::Remove(iTimerEntry); |
|
243 |
|
244 // Notify factory of request completion |
|
245 TLogicalChannelFactoryTicket ticket(NULL, iId); |
|
246 iClient.LogicalChannelFactoryRequestComplete(ticket, KErrNone); |
|
247 } |
|
248 } |
|
249 |
|
250 /** |
|
251 Begin the job. |
|
252 |
|
253 @param aTimeout Number of milliseconds to wait for the remote to close |
|
254 the channels before locally initiating the shutdown. |
|
255 */ |
|
256 void CCloseSessionLogicalChannels::StartJob(TInt aTimeout) |
|
257 { |
|
258 LOG_FUNC |
|
259 |
|
260 if(aTimeout) |
|
261 { |
|
262 TCallBack callBack(WatchdogBarked, this); |
|
263 iTimerEntry.Set(callBack); |
|
264 |
|
265 BTSocketTimer::Queue(aTimeout, iTimerEntry); |
|
266 } |
|
267 else |
|
268 { |
|
269 CloseChannels(ETrue); |
|
270 } |
|
271 } |
|
272 |
|
273 /** |
|
274 Static function called on expiry of channel close watchdog. |
|
275 */ |
|
276 TInt CCloseSessionLogicalChannels::WatchdogBarked(TAny* aCloseLogicalChannels) |
|
277 { |
|
278 LOG_STATIC_FUNC |
|
279 static_cast<CCloseSessionLogicalChannels*>(aCloseLogicalChannels)->CloseChannels(ETrue); |
|
280 |
|
281 return KErrNone; |
|
282 } |
|
283 |
|
284 /** |
|
285 Close all remaining channels. |
|
286 |
|
287 @param aNotifyCompletion if ETrue then inform client that job is complete |
|
288 if EFalse then silently close remaining channels |
|
289 */ |
|
290 void CCloseSessionLogicalChannels::CloseChannels(TBool aNotifyCompletion) |
|
291 { |
|
292 LOG_FUNC |
|
293 |
|
294 for(TInt i = 0; i < KAvdtpChannelArraySize; i++) |
|
295 { |
|
296 if(iLogicalChannels[i]) |
|
297 { |
|
298 iLogicalChannels[i]->Shutdown(); |
|
299 delete iLogicalChannels[i]; |
|
300 iLogicalChannels[i] = NULL; |
|
301 } |
|
302 } |
|
303 |
|
304 if(aNotifyCompletion) |
|
305 { |
|
306 // Notify factory of request completion |
|
307 TLogicalChannelFactoryTicket ticket(NULL, iId); |
|
308 iClient.LogicalChannelFactoryRequestComplete(ticket, KErrNone); |
|
309 } |
|
310 } |
|
311 |
|
312 /** |
|
313 Constructor. |
|
314 |
|
315 @param aClient Client to be notified on completion of this job. |
|
316 @param aId The job id of this job. |
|
317 */ |
|
318 CCloseSessionLogicalChannels::CCloseSessionLogicalChannels(XLogicalChannelFactoryClient& aClient, |
|
319 TLogicalChannelFactoryRequestId aId) |
|
320 : CLogicalChannelFactoryRequest(aClient, aId) |
|
321 { |
|
322 LOG_FUNC |
|
323 } |
|
324 |
|
325 CLogicalChannelFactoryRequest::CLogicalChannelFactoryRequest(XLogicalChannelFactoryClient& aClient, |
|
326 TLogicalChannelFactoryRequestId aId) |
|
327 : iClient(aClient), iId(aId) |
|
328 { |
|
329 LOG_FUNC |
|
330 } |
|
331 |
|
332 CLogicalChannelFactoryPassiveRequest::CLogicalChannelFactoryPassiveRequest(XLogicalChannelFactoryClient& aClient, |
|
333 TLogicalChannelFactoryRequestId aId, |
|
334 CBluetoothProtocolBase& aAvdtp) |
|
335 : CLogicalChannelFactoryRequest(aClient, aId), iAvdtp(aAvdtp) |
|
336 { |
|
337 LOG_FUNC |
|
338 } |
|
339 |
|
340 CLogicalChannelFactoryPassiveRequest::~CLogicalChannelFactoryPassiveRequest() |
|
341 { |
|
342 LOG_FUNC |
|
343 iAvdtp.DecrementListeners(); |
|
344 } |
|
345 |
|
346 void CLogicalChannelFactoryPassiveRequest::BaseConstructL() |
|
347 { |
|
348 LOG_FUNC |
|
349 User::LeaveIfError(iAvdtp.IncrementListeners()); |
|
350 } |
|
351 |
|
352 CLogicalChannelFactoryActiveRequest::CLogicalChannelFactoryActiveRequest(const TBTDevAddr& aAddr, XLogicalChannelFactoryClient& aClient, TLogicalChannelFactoryRequestId aId) |
|
353 : CLogicalChannelFactoryRequest(aClient, aId), iRemoteDev(aAddr) |
|
354 { |
|
355 LOG_FUNC |
|
356 } |
|
357 |
|
358 CExpectSignallingLogicalChannel* CExpectSignallingLogicalChannel::NewL(XLogicalChannelFactoryClient& aClient, |
|
359 TLogicalChannelFactoryRequestId aId, |
|
360 CBluetoothProtocolBase& aAvdtp) |
|
361 { |
|
362 LOG_STATIC_FUNC |
|
363 CExpectSignallingLogicalChannel* req = new (ELeave)CExpectSignallingLogicalChannel(aClient, aId, aAvdtp); |
|
364 CleanupStack::PushL(req); |
|
365 req->ConstructL(); |
|
366 CleanupStack::Pop(req); |
|
367 return req; |
|
368 } |
|
369 |
|
370 void CExpectSignallingLogicalChannel::ConstructL() |
|
371 { |
|
372 LOG_FUNC |
|
373 BaseConstructL(); |
|
374 } |
|
375 |
|
376 CExpectSignallingLogicalChannel::CExpectSignallingLogicalChannel(XLogicalChannelFactoryClient& aClient, |
|
377 TLogicalChannelFactoryRequestId aId, |
|
378 CBluetoothProtocolBase& aAvdtp) |
|
379 : CLogicalChannelFactoryPassiveRequest(aClient, aId, aAvdtp) |
|
380 { |
|
381 LOG_FUNC |
|
382 iNumChannelsRequired = 1; |
|
383 } |
|
384 |
|
385 CExpectSessionLogicalChannels* CExpectSessionLogicalChannels::NewL(XLogicalChannelFactoryClient& aClient, |
|
386 TLogicalChannelFactoryRequestId aId, |
|
387 TInt aNumRequired, |
|
388 CBluetoothProtocolBase& aAvdtp) |
|
389 { |
|
390 LOG_STATIC_FUNC |
|
391 CExpectSessionLogicalChannels* req = new (ELeave)CExpectSessionLogicalChannels(aClient, aId, aNumRequired, aAvdtp); |
|
392 CleanupStack::PushL(req); |
|
393 req->ConstructL(); |
|
394 CleanupStack::Pop(req); |
|
395 return req; |
|
396 } |
|
397 |
|
398 void CExpectSessionLogicalChannels::ConstructL() |
|
399 { |
|
400 LOG_FUNC |
|
401 BaseConstructL(); |
|
402 } |
|
403 |
|
404 CExpectSessionLogicalChannels::CExpectSessionLogicalChannels(XLogicalChannelFactoryClient& aClient, |
|
405 TLogicalChannelFactoryRequestId aId, |
|
406 TInt aNumRequired, |
|
407 CBluetoothProtocolBase& aAvdtp) |
|
408 : CLogicalChannelFactoryPassiveRequest(aClient, aId, aAvdtp) |
|
409 { |
|
410 LOG_FUNC |
|
411 iNumChannelsRequired = aNumRequired; |
|
412 } |
|
413 |
|
414 CLogicalChannelFactoryActiveRequest::~CLogicalChannelFactoryActiveRequest() |
|
415 { |
|
416 LOG_FUNC |
|
417 // clear up any unclaimed stuff - array will be empty if saps claimed |
|
418 for (TInt i=0; i<iLogicalChannels.Count(); i++) |
|
419 { |
|
420 delete iLogicalChannels[i]; |
|
421 } |
|
422 } |
|
423 |
|
424 void CLogicalChannelFactory::DeleteRequest(CLogicalChannelFactoryRequest *aRequest) |
|
425 { |
|
426 LOG_FUNC |
|
427 |
|
428 iIdManager.FreeId(aRequest->iId); // free the ID associated with this request |
|
429 |
|
430 delete aRequest; |
|
431 } |
|
432 |
|
433 void CLogicalChannelFactory::Cancel(TLogicalChannelFactoryTicket& aJobSpec) |
|
434 /* |
|
435 The caller has decided they don't want to have the SAPs |
|
436 we need to find the job and update it as Cancelled |
|
437 we MUST then disconnect these channels as the remote entity will |
|
438 misunderstand what sessions could be running over them |
|
439 i.e. we cannot keep these SAPs just in case someone else wants them! |
|
440 */ |
|
441 { |
|
442 LOG_FUNC |
|
443 // only cancel if the job is outstanding |
|
444 if (aJobSpec.State()==TLogicalChannelFactoryTicket::ERequestOutstanding) |
|
445 { |
|
446 TSglQueIter<CLogicalChannelFactoryRequest> iter(iPendingActiveJobs); |
|
447 CLogicalChannelFactoryRequest* request = NULL; |
|
448 TBool found = EFalse; |
|
449 |
|
450 while (iter) |
|
451 { |
|
452 // try active jobs first |
|
453 request = iter++; |
|
454 if (request->iId==aJobSpec.iId) |
|
455 { |
|
456 iPendingActiveJobs.Remove(*static_cast<CLogicalChannelFactoryActiveRequest*>(request)); |
|
457 DeleteRequest(request); |
|
458 found = ETrue; |
|
459 } |
|
460 } |
|
461 |
|
462 if (!found) |
|
463 { |
|
464 // go through pending *passive signalling* jobs now |
|
465 iter = iPendingPassiveSignallingJobs; |
|
466 |
|
467 while (iter) |
|
468 { |
|
469 request = iter++; |
|
470 if (request->iId==aJobSpec.iId) |
|
471 { |
|
472 iPendingPassiveSignallingJobs.Remove(*static_cast<CLogicalChannelFactoryPassiveRequest*>(request)); |
|
473 DeleteRequest(request); |
|
474 found = ETrue; |
|
475 } |
|
476 } |
|
477 } |
|
478 |
|
479 if (!found) |
|
480 { |
|
481 // go through pending *passive session* jobs now |
|
482 iter = iPendingPassiveSessionJobs; |
|
483 |
|
484 while (iter) |
|
485 { |
|
486 request = iter++; |
|
487 if (request->iId==aJobSpec.iId) |
|
488 { |
|
489 iPendingPassiveSessionJobs.Remove(*static_cast<CLogicalChannelFactoryPassiveRequest*>(request)); |
|
490 DeleteRequest(request); |
|
491 found = ETrue; |
|
492 } |
|
493 } |
|
494 } |
|
495 |
|
496 if (!found) |
|
497 { |
|
498 // perhaps it's the current one |
|
499 if (iCurrentActiveJob && iCurrentActiveJob->iId == aJobSpec.iId) |
|
500 { |
|
501 iCurrentJobCancelled = ETrue; |
|
502 } |
|
503 } |
|
504 |
|
505 if (found) |
|
506 { |
|
507 aJobSpec.SetState(TLogicalChannelFactoryTicket::ERequestIdle); |
|
508 } |
|
509 } |
|
510 } |
|
511 |
|
512 void CLogicalChannelFactory::FreeId(TAny* aFactory) |
|
513 { |
|
514 LOG_STATIC_FUNC |
|
515 CLogicalChannelFactory *fact = static_cast<CLogicalChannelFactory*>(aFactory); |
|
516 fact->iIdManager.FreeId(fact->iId); |
|
517 } |
|
518 |
|
519 TLogicalChannelFactoryTicket CLogicalChannelFactory::CreateSignallingLogicalChannelL(const TBTDevAddr& aAddr, XLogicalChannelFactoryClient& aClient) |
|
520 { |
|
521 LOG_FUNC |
|
522 // check that we don't have an inbound one from remote |
|
523 // if we have then we just use that unclaimed one |
|
524 // if we don't then go and create an outbound one |
|
525 TLogicalChannelFactoryRequestId id; |
|
526 TLogicalChannelFactoryTicket::TLogicalChannelFactoryRequestState state; |
|
527 |
|
528 CManagedLogicalChannel* ch = FindUnclaimedLogicalChannel(aAddr, ESignalling, id); |
|
529 if (ch) |
|
530 { |
|
531 state = TLogicalChannelFactoryTicket::ERequestComplete; |
|
532 // they'll come back and get SAP off their request |
|
533 } |
|
534 else |
|
535 { |
|
536 // need to create a new one |
|
537 User::LeaveIfError(iIdManager.GetId(id)); |
|
538 iId = id; // just in case we need to clean it up this needs to be stored |
|
539 CleanupStack::PushL(TCleanupItem(FreeId, (TAny*)this)); |
|
540 CCreateSignallingLogicalChannel* req = |
|
541 CCreateSignallingLogicalChannel::NewL(aAddr, |
|
542 aClient, |
|
543 id, |
|
544 *this); |
|
545 CleanupStack::Pop(); |
|
546 // got a complete job to do - put into job list |
|
547 iPendingActiveJobs.AddLast(*req); |
|
548 |
|
549 state = TLogicalChannelFactoryTicket::ERequestOutstanding; |
|
550 TryNextActiveJob(); |
|
551 } |
|
552 |
|
553 TLogicalChannelFactoryTicket ticket(this, id); |
|
554 ticket.SetState(state); |
|
555 return ticket; |
|
556 } |
|
557 |
|
558 TLogicalChannelFactoryTicket CLogicalChannelFactory::CreateSessionLogicalChannelsL( |
|
559 const TBTDevAddr& aAddr, |
|
560 XLogicalChannelFactoryClient& aClient, |
|
561 TInt aNumRequired) |
|
562 { |
|
563 LOG_FUNC |
|
564 //#pragma message("Check not already got or getting signalling channel for remote") |
|
565 |
|
566 TLogicalChannelFactoryRequestId id; |
|
567 User::LeaveIfError(iIdManager.GetId(id)); |
|
568 |
|
569 iId = id; // just in case we need to clean it up this needs to be stored |
|
570 CleanupStack::PushL(TCleanupItem(FreeId, (TAny*)this)); |
|
571 CCreateSessionLogicalChannels* req = CCreateSessionLogicalChannels::NewLC(aAddr, aClient, id, aNumRequired); |
|
572 |
|
573 CManagedLogicalChannel* ch; |
|
574 // we connect up the SAPs backwards to save a member variable (a counter) |
|
575 // so the sequence number needs to go backwards |
|
576 // then the claimer (who specifies sequence number) is really getting the |
|
577 // right sequence number (e.g. the 3rd channel connected really was the 3rd) |
|
578 for (TInt chIndex=aNumRequired-1; chIndex>=0; chIndex--) |
|
579 { |
|
580 // sequene number is 1 indexed, so chIndex+1... |
|
581 ch = CManagedLogicalChannel::NewL(*this, aAddr, chIndex+1, id); |
|
582 // transfer ownership to request |
|
583 req->iLogicalChannels[chIndex] = ch; |
|
584 } |
|
585 |
|
586 CleanupStack::Pop(req); |
|
587 CleanupStack::Pop(); |
|
588 // got a complete job to do - put into job list |
|
589 iPendingActiveJobs.AddLast(*req); |
|
590 TryNextActiveJob(); |
|
591 |
|
592 TLogicalChannelFactoryTicket ticket(this, id); |
|
593 ticket.SetState(TLogicalChannelFactoryTicket::ERequestOutstanding); |
|
594 return ticket; |
|
595 } |
|
596 |
|
597 /** |
|
598 Request some logical channels be closed. This takes ownership of the lower protocol |
|
599 SAPs from the transport channels. Unlike other logical channel factory jobs this does |
|
600 not require a client to callback on completion, as it is anticipated that clients do |
|
601 not have actions that are required on channel closure. |
|
602 |
|
603 This does not support multiplexed channels. |
|
604 |
|
605 @param aChannels CTransportChannels that are the current owners of the lower SAPs. All transport |
|
606 channels should be passed so they can be appropriately informed that they no longer |
|
607 have a valid lower SAP. Note that although ownership of the lower SAP is passed |
|
608 ownership of the CTransportChannel itself is not. |
|
609 @param aTimeout If this is non-zero then this job will wait for the remote to initiate |
|
610 a close of the channels, with a guard timer of aTimeout milliseconds, after |
|
611 which it will initiate the shutdown locally. |
|
612 */ |
|
613 void CLogicalChannelFactory::CloseSessionLogicalChannelsL( |
|
614 TArray<CDirectChannel*>& aChannels, |
|
615 TInt aTimeout) |
|
616 { |
|
617 LOG_FUNC |
|
618 |
|
619 TLogicalChannelFactoryRequestId id; |
|
620 User::LeaveIfError(iIdManager.GetId(id)); |
|
621 |
|
622 iId = id; // just in case we need to clean it up this needs to be stored |
|
623 CleanupStack::PushL(TCleanupItem(FreeId, (TAny*)this)); |
|
624 |
|
625 // We want to take all or none of the SAP's, so we will wait until after the failable |
|
626 // allocations before transferring SAP ownership |
|
627 CCloseSessionLogicalChannels* req = CCloseSessionLogicalChannels::NewLC(*this, id); |
|
628 |
|
629 CManagedLogicalChannel* ch; |
|
630 |
|
631 for (TInt i = 0; i < KAvdtpChannelArraySize; i++) |
|
632 { |
|
633 // default the channel to NULL |
|
634 // so it doesn't appear in the job we are creating |
|
635 req->iLogicalChannels[i] = NULL; |
|
636 if (aChannels[i]) |
|
637 { |
|
638 ch = CManagedLogicalChannel::NewL(*this, id); |
|
639 // transfer ownership to request |
|
640 req->iLogicalChannels[i] = ch; |
|
641 } |
|
642 } |
|
643 |
|
644 // failing stuff all done now - no leaving after this point |
|
645 |
|
646 for (TInt i = 0; i < KAvdtpChannelArraySize; i++) |
|
647 { |
|
648 if (aChannels[i]) |
|
649 { |
|
650 CServProviderBase* sap = aChannels[i]->ObtainSAP(); |
|
651 /* |
|
652 NOTE it IS possible that the channel is NOT totally setup |
|
653 if the remote is behaving badly. |
|
654 So in case check the channel has a SAP BEFORE |
|
655 calling shutdown. */ |
|
656 if (sap) |
|
657 { |
|
658 req->iLogicalChannels[i]->ProvideSAP(sap); |
|
659 } |
|
660 } |
|
661 } |
|
662 |
|
663 req->StartJob(aTimeout); |
|
664 |
|
665 CleanupStack::Pop(req); |
|
666 CleanupStack::Pop(); |
|
667 |
|
668 iCloseChannelJobs.AddLast(*req); |
|
669 } |
|
670 |
|
671 void CLogicalChannelFactory::DoObtainChannelL() |
|
672 { |
|
673 LOG_FUNC |
|
674 __ASSERT_DEBUG(iCurrentActiveJob && iCurrentActiveJob->iNumChannelsRequired, Panic(EAvdtpLogicalChannelFactoryJobHasNoLogicalChannels)); |
|
675 |
|
676 static const TInt KAVDTPPSM = 0x19; |
|
677 |
|
678 TInt iter = 0; |
|
679 TInt currentLogicalChannel; |
|
680 |
|
681 //Get the actual channel counts, (iter-1) |
|
682 while(++iter <= iCurrentActiveJob->iLogicalChannels.Count() && iCurrentActiveJob->iLogicalChannels[iter-1] != NULL) |
|
683 { |
|
684 } |
|
685 //currentLogicalChannel's value will increase for each call, |
|
686 //as iCurrentActiveJob->iNumChannelsRequired decreases each time |
|
687 currentLogicalChannel = iter - iCurrentActiveJob->iNumChannelsRequired - 1; |
|
688 |
|
689 //Make sure that channel's index in the array matches its sequence number('iSequenceNumber') |
|
690 //Correct match is: index = 0 ----> iSequenceNumber = 1 (Media Channel) |
|
691 // index = 1 ----> iSequenceNumber = 2 (Reporting/Recovery Channel) |
|
692 // index = 2 ----> iSequenceNumber = 3 (Reporting/Recovery Channel) |
|
693 //Please refer to function: CLogicalChannelFactory::CreateSessionLogicalChannelsL() |
|
694 __ASSERT_DEBUG(iCurrentActiveJob->iLogicalChannels[currentLogicalChannel]->iSequenceNumber == currentLogicalChannel + 1, |
|
695 Panic(EAvdtpLogicalChannelArrayMismatchesIndexAndSequence)); |
|
696 |
|
697 // working forwards through array of SAPs requiring connections |
|
698 CServProviderBase& sap = |
|
699 *iCurrentActiveJob->iLogicalChannels[currentLogicalChannel]->iLogicalChannelSAP; |
|
700 |
|
701 // for the 'active' SAP we become the socket for now |
|
702 sap.SetNotify(this); |
|
703 |
|
704 TBTServiceSecurity sec; |
|
705 sec.SetAuthentication(EMitmDesired); |
|
706 sec.SetAuthorisation(EFalse); |
|
707 sec.SetEncryption(ETrue); |
|
708 sec.SetDenied(EFalse); |
|
709 |
|
710 TL2CAPSockAddr addr; |
|
711 addr.SetBTAddr(iCurrentActiveJob->iRemoteDev); |
|
712 addr.SetPort(KAVDTPPSM); |
|
713 addr.SetSecurity(sec); |
|
714 |
|
715 TInt err = sap.SetRemName(addr); |
|
716 __ASSERT_DEBUG(err==KErrNone, Panic(EAvdtpUnexpectedErrorFromL2CAP)); |
|
717 |
|
718 sap.ActiveOpen(); |
|
719 |
|
720 // The call to ActiveOpen could affect iCurrentActiveJob if |
|
721 // L2CAP synchrononously errors -- in which case iCurrentActiveJob could now |
|
722 // have become NULL. Make sure it is still valid. |
|
723 if (iCurrentActiveJob) |
|
724 { |
|
725 // decrement how many more channels required for this job |
|
726 --iCurrentActiveJob->iNumChannelsRequired; |
|
727 iCurrentJobCancelled = EFalse; |
|
728 } |
|
729 // a next job may be attempted from a synchronous error from l2cap |
|
730 } |
|
731 |
|
732 /** |
|
733 This examines the job queue and tries to pass off the new channel to an outstanding |
|
734 job. |
|
735 |
|
736 @param aRemote The device from which the connection orginates |
|
737 @param aSAP An L2CAP SAP. The job initiator takes this from the factory on |
|
738 successful job completion. |
|
739 @return KErrNone if the connection was successfully taken by the job. |
|
740 KErrNotReady if there are no jobs on this queue. |
|
741 System wide error if the new PendingLogicalChannel could not be created. |
|
742 */ |
|
743 TInt CLogicalChannelFactory::TryToTakeConnection(const TBTDevAddr& aRemote, |
|
744 CServProviderBase* aSAP, TSglQue<CLogicalChannelFactoryPassiveRequest>& aJobQueue) |
|
745 { |
|
746 LOG_FUNC |
|
747 |
|
748 if(aJobQueue.IsEmpty()) |
|
749 { |
|
750 // No jobs on this queue mate! |
|
751 return KErrNotReady; |
|
752 } |
|
753 |
|
754 CLogicalChannelFactoryPassiveRequest* job = aJobQueue.First(); |
|
755 |
|
756 // need to place this newSAP into a logical channel - then put that into job |
|
757 TInt seqNumber = KInitialSequenceNumber; |
|
758 TDblQueIter<CManagedLogicalChannel> iter(iUnclaimedLogicalChannels); |
|
759 |
|
760 while (iter) |
|
761 { |
|
762 CManagedLogicalChannel* r = iter++; |
|
763 if (r->iRemoteAddress == aRemote) |
|
764 { |
|
765 seqNumber++; |
|
766 } |
|
767 } |
|
768 |
|
769 // job doesnt take ownership yet |
|
770 CManagedLogicalChannel* pch = NULL; |
|
771 TRAPD(err, pch = CManagedLogicalChannel::NewL(*this, aRemote, seqNumber, job->iId, aSAP)); |
|
772 if (err==KErrNone) |
|
773 { |
|
774 iUnclaimedLogicalChannels.AddFirst(*pch); |
|
775 if (--job->iNumChannelsRequired == 0) |
|
776 { |
|
777 // all channels obtained |
|
778 aJobQueue.Remove(*job); |
|
779 NotifyComplete(KErrNone, *job); |
|
780 delete job; |
|
781 } |
|
782 } |
|
783 |
|
784 return err; |
|
785 } |
|
786 |
|
787 TInt CLogicalChannelFactory::BearerConnectComplete(const TBTDevAddr& aRemote, |
|
788 CServProviderBase* aSAP) |
|
789 { |
|
790 LOG_FUNC |
|
791 // inbound connection!! |
|
792 // then bung on queue and notify |
|
793 |
|
794 if (iPendingPassiveSignallingJobs.IsEmpty() && iPendingPassiveSessionJobs.IsEmpty()) |
|
795 { |
|
796 return KErrNotReady; // connection will be auto-disposed by listener |
|
797 } |
|
798 |
|
799 if (iCurrentActiveJob) |
|
800 { |
|
801 // we're doing outbound stuff - need to make sure it's not to same remote |
|
802 // as it would then be being naughty... |
|
803 if (iCurrentActiveJob->iRemoteDev == aRemote) |
|
804 { |
|
805 //tsk tsk |
|
806 return KErrAlreadyExists; // connection will be auto-disposed |
|
807 } |
|
808 } |
|
809 |
|
810 TInt res; |
|
811 // We need to work out what type of session this is. Because the first, and only |
|
812 // the first, channel to each remote must be a signalling channel we can use this |
|
813 // information to decide whether to use this new channel to complete a signalling |
|
814 // job or a session job. |
|
815 if((static_cast<CAvdtpProtocol&>(iProtocol)).FindSignallingChannel(aRemote)) |
|
816 { |
|
817 // Already got a signalling channel, complete a session job if we have one |
|
818 LOG(_L("Looking for a session job to complete")); |
|
819 res = TryToTakeConnection(aRemote, aSAP, iPendingPassiveSessionJobs); |
|
820 } |
|
821 else |
|
822 { |
|
823 // No signalling channel yet, complete a signalling job if we have one |
|
824 LOG(_L("Looking for a signalling job to complete")); |
|
825 res = TryToTakeConnection(aRemote, aSAP, iPendingPassiveSignallingJobs); |
|
826 } |
|
827 |
|
828 return res; |
|
829 } |
|
830 |
|
831 |
|
832 // from MSocketNotify |
|
833 void CLogicalChannelFactory::NewData(TUint /*aCount*/) |
|
834 { |
|
835 LOG_FUNC |
|
836 // we should have transferred ownership before newdata is called |
|
837 __DEBUGGER(); |
|
838 } |
|
839 |
|
840 void CLogicalChannelFactory::CanSend() |
|
841 { |
|
842 LOG_FUNC |
|
843 // we don't send data |
|
844 __DEBUGGER(); |
|
845 } |
|
846 |
|
847 void CLogicalChannelFactory::ConnectComplete() |
|
848 { |
|
849 LOG_FUNC |
|
850 // that's what we want! |
|
851 TBool done = CheckActiveJobComplete(*iCurrentActiveJob); |
|
852 |
|
853 if (done) |
|
854 { |
|
855 // LOG1(_L("ConnectComplete for request: id=%d"), iCurrentActiveJob->iId) |
|
856 CompleteActiveJob(KErrNone); |
|
857 } |
|
858 else |
|
859 { |
|
860 // more channels required for job |
|
861 // LOG1(_L("ConnectComplete for request: id=%d (but more channels needed)"), iCurrentActiveJob->iId) |
|
862 TRAPD(err, DoObtainChannelL()); |
|
863 if (err) |
|
864 { |
|
865 CompleteActiveJob(KErrNoMemory); |
|
866 } |
|
867 } |
|
868 } |
|
869 |
|
870 void CLogicalChannelFactory::ConnectComplete(const TDesC8& /*aConnectData*/) |
|
871 { |
|
872 LOG_FUNC |
|
873 // no connect data supported |
|
874 ConnectComplete(); |
|
875 } |
|
876 |
|
877 void CLogicalChannelFactory::ConnectComplete(CServProviderBase& /*aSAP*/) |
|
878 { |
|
879 LOG_FUNC |
|
880 __DEBUGGER(); // should have come via protocol's listener |
|
881 } |
|
882 |
|
883 void CLogicalChannelFactory::ConnectComplete(CServProviderBase& /*aSAP*/,const TDesC8& /*aConnectData*/) |
|
884 { |
|
885 LOG_FUNC |
|
886 // not used |
|
887 __DEBUGGER(); |
|
888 } |
|
889 |
|
890 void CLogicalChannelFactory::CanClose(TDelete /*aDelete*/) |
|
891 { |
|
892 LOG_FUNC |
|
893 // not used |
|
894 __DEBUGGER(); |
|
895 } |
|
896 |
|
897 void CLogicalChannelFactory::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/) |
|
898 { |
|
899 LOG_FUNC |
|
900 // not used |
|
901 __DEBUGGER(); |
|
902 } |
|
903 |
|
904 void CLogicalChannelFactory::Error(TInt aError,TUint /*aOperationMask*/) |
|
905 { |
|
906 LOG_FUNC |
|
907 // whoops - need to find the job on which the sap is |
|
908 // eventually we may process jobs out of order see! |
|
909 |
|
910 // at present we error the whole job if any channel fails |
|
911 CompleteActiveJob(aError); |
|
912 } |
|
913 |
|
914 void CLogicalChannelFactory::Disconnect() |
|
915 { |
|
916 LOG_FUNC |
|
917 // not used |
|
918 __DEBUGGER(); |
|
919 } |
|
920 |
|
921 void CLogicalChannelFactory::Disconnect(TDesC8& /*aDisconnectData*/) |
|
922 { |
|
923 LOG_FUNC |
|
924 //not used |
|
925 __DEBUGGER(); |
|
926 } |
|
927 |
|
928 void CLogicalChannelFactory::IoctlComplete(TDesC8* /*aBuf*/) |
|
929 { |
|
930 LOG_FUNC |
|
931 // not used |
|
932 __DEBUGGER(); |
|
933 } |
|
934 |
|
935 void CLogicalChannelFactory::NoBearer(const TDesC8& /*aConnectionInfo*/) |
|
936 { |
|
937 LOG_FUNC |
|
938 // not used |
|
939 __DEBUGGER(); |
|
940 } |
|
941 |
|
942 void CLogicalChannelFactory::Bearer(const TDesC8& /*aConnectionInfo*/) |
|
943 { |
|
944 LOG_FUNC |
|
945 // not used |
|
946 __DEBUGGER(); |
|
947 } |
|
948 |
|
949 /*static*/ TInt CLogicalChannelFactory::TryNextJob(TAny* aAny) |
|
950 { |
|
951 LOG_STATIC_FUNC |
|
952 CLogicalChannelFactory* self = static_cast<CLogicalChannelFactory*>(aAny); |
|
953 self->TryNextActiveJob(); |
|
954 return KErrNone; |
|
955 } |
|
956 |
|
957 |
|
958 void CLogicalChannelFactory::TryNextActiveJob() |
|
959 { |
|
960 LOG_FUNC |
|
961 // since each channel *might* take a different amount of time to come up we |
|
962 // must serialise these so that we *and* the remote agree on the transport session |
|
963 // that will flow over the l2cap logical channel. |
|
964 |
|
965 // so we don't call DoObtainChannel until the previous job is completed, or there are none waiting |
|
966 if (!iCurrentActiveJob) |
|
967 { |
|
968 if (!iPendingActiveJobs.IsEmpty()) |
|
969 { |
|
970 iCurrentActiveJob = iPendingActiveJobs.First(); |
|
971 // iCurrent Job takes ownership from queue... |
|
972 iPendingActiveJobs.Remove(*iCurrentActiveJob); |
|
973 LOG1(_L("Obtaining channel for current active request: id=%d"), iCurrentActiveJob->iId); |
|
974 TRAPD(error, DoObtainChannelL()); |
|
975 if (error != KErrNone) |
|
976 { |
|
977 CompleteActiveJob(error); |
|
978 iCurrentActiveJob = NULL; |
|
979 TryNextActiveJob(); |
|
980 } |
|
981 } |
|
982 } |
|
983 } |
|
984 |
|
985 CManagedLogicalChannel* CLogicalChannelFactory::FindUnclaimedLogicalChannel( |
|
986 const TBTDevAddr& aAddr, |
|
987 TInt aSequenceNumber, |
|
988 TLogicalChannelFactoryRequestId& aId) |
|
989 { |
|
990 LOG_FUNC |
|
991 TDblQueIter<CManagedLogicalChannel> iter(iUnclaimedLogicalChannels); |
|
992 |
|
993 while (iter) |
|
994 { |
|
995 CManagedLogicalChannel* ch = iter++; |
|
996 if (ch->iRemoteAddress == aAddr && ch->iSequenceNumber == aSequenceNumber) |
|
997 { |
|
998 aId = ch->iId; |
|
999 return ch; |
|
1000 } |
|
1001 } |
|
1002 return NULL; |
|
1003 } |
|
1004 |
|
1005 |
|
1006 TBool CLogicalChannelFactory::CheckActiveJobComplete(CLogicalChannelFactoryActiveRequest& aJob) |
|
1007 { |
|
1008 LOG_FUNC |
|
1009 //if we get to zero - or error occurs - job is done |
|
1010 if (iCurrentJobCancelled) |
|
1011 { |
|
1012 // we left the cancelled job running, to sequence the channels |
|
1013 // but proceed no more with other channels, destroy via completion of job |
|
1014 CompleteActiveJob(KErrCancel); |
|
1015 return ETrue; |
|
1016 } |
|
1017 return (!aJob.iNumChannelsRequired); |
|
1018 } |
|
1019 |
|
1020 |
|
1021 void CLogicalChannelFactory::CompleteActiveJob(TInt aError) |
|
1022 { |
|
1023 LOG_FUNC |
|
1024 if ((!iCurrentJobCancelled) && (iCurrentActiveJob)) |
|
1025 { |
|
1026 if (aError == KErrNone) |
|
1027 { |
|
1028 for (TInt index = 0; index<iCurrentActiveJob->iLogicalChannels.Count(); index++) |
|
1029 { |
|
1030 CManagedLogicalChannel* ch = iCurrentActiveJob->iLogicalChannels[index]; |
|
1031 if (ch) |
|
1032 { |
|
1033 // put on unclaimed queue now - caller may come back synchronously |
|
1034 iUnclaimedLogicalChannels.AddFirst(*ch); |
|
1035 |
|
1036 // transferred ownership, so take them off job array |
|
1037 iCurrentActiveJob->iLogicalChannels[index] = NULL; |
|
1038 } |
|
1039 } |
|
1040 } |
|
1041 else |
|
1042 { |
|
1043 // leave to be destroyed below |
|
1044 } |
|
1045 NotifyComplete(aError, *iCurrentActiveJob); |
|
1046 } |
|
1047 else |
|
1048 { |
|
1049 // cleanup |
|
1050 if (iCurrentActiveJob) |
|
1051 { |
|
1052 iIdManager.FreeId(iCurrentActiveJob->iId); |
|
1053 } |
|
1054 // rest of cleanup will be done on destruction of job |
|
1055 } |
|
1056 |
|
1057 // the job is done, and the logical channels transferred onto pending queue, so delete job |
|
1058 delete iCurrentActiveJob; |
|
1059 iCurrentActiveJob = NULL; |
|
1060 iAsyncTryNextJob->CallBack(); |
|
1061 } |
|
1062 |
|
1063 void CLogicalChannelFactory::NotifyComplete(TInt aError, CLogicalChannelFactoryRequest& aRequest) |
|
1064 { |
|
1065 LOG_FUNC |
|
1066 |
|
1067 // if client cancelled this request, ID was already freed and NotifyComplete() should not be called |
|
1068 __ASSERT_DEBUG(aError!=KErrCancel, Panic(EAvdtpNotifyCompleteCancelledRequest)); |
|
1069 |
|
1070 TLogicalChannelFactoryTicket ticket(this, aRequest.iId); |
|
1071 ticket.SetState((aError==KErrNone) ? TLogicalChannelFactoryTicket::ERequestComplete : TLogicalChannelFactoryTicket::ERequestErrored); |
|
1072 |
|
1073 aRequest.iClient.LogicalChannelFactoryRequestComplete(ticket, aError); |
|
1074 |
|
1075 // LogicalChannelFactoryRequestComplete() does not free the ID of errorred jobs |
|
1076 if (aError != KErrNone) |
|
1077 { |
|
1078 iIdManager.FreeId(aRequest.iId); |
|
1079 } |
|
1080 |
|
1081 } |
|
1082 |
|
1083 TLogicalChannelRecord CLogicalChannelFactory::ClaimLogicalChannel(TInt aSequenceNumber, TLogicalChannelFactoryRequestId aId, TBool& aFinished) |
|
1084 { |
|
1085 LOG_FUNC |
|
1086 __ASSERT_DEBUG(aSequenceNumber>=KInitialSequenceNumber, Panic(EAvdtpLogicalChannelFactoryBadClaimLogicalChannel)); |
|
1087 CManagedLogicalChannel* ch = NULL; |
|
1088 CManagedLogicalChannel* chFound = NULL; |
|
1089 TDblQueIter<CManagedLogicalChannel> iter(iUnclaimedLogicalChannels); |
|
1090 TInt channelsWithId=0; |
|
1091 |
|
1092 aFinished = EFalse; // set to true below if last channel of job retrieved |
|
1093 |
|
1094 while (iter) |
|
1095 { |
|
1096 ch = iter++; |
|
1097 if (ch->iId == aId) |
|
1098 { |
|
1099 // channel is part of the request - count it |
|
1100 ++channelsWithId; |
|
1101 |
|
1102 if (ch->iSequenceNumber == aSequenceNumber) |
|
1103 { |
|
1104 // this is the channel explicitly sought |
|
1105 ch->iFactoryQLink.Deque(); // this one link is claimed - may be more on job |
|
1106 chFound = ch; |
|
1107 } |
|
1108 // don't break loop - we want to continue to see if this is the last channel for the job |
|
1109 } |
|
1110 } |
|
1111 |
|
1112 __ASSERT_DEBUG(chFound, Panic(EAvdtpLogicalChannelFactoryBadClaimLogicalChannel)); |
|
1113 |
|
1114 TLogicalChannelRecord rec; |
|
1115 rec.iLogicalChannelSAP = chFound->ObtainSAP(); |
|
1116 rec.iDataCount = chFound->iDataCount; |
|
1117 rec.iEndOfData = chFound->iEndOfData; |
|
1118 |
|
1119 // logicalchannel is no longer pending, so remove |
|
1120 delete chFound; |
|
1121 |
|
1122 // but don't release the id until all the logical channels on the job claimed |
|
1123 if (channelsWithId==1) |
|
1124 { |
|
1125 // that was the last channel on the job, so the job id can be freed |
|
1126 iIdManager.FreeId(aId); |
|
1127 aFinished = ETrue; |
|
1128 } |
|
1129 |
|
1130 return rec; |
|
1131 } |
|
1132 |
|
1133 TLogicalChannelFactoryTicket CLogicalChannelFactory::ExpectSignallingLogicalChannelL(XLogicalChannelFactoryClient& aClient) |
|
1134 { |
|
1135 LOG_FUNC |
|
1136 TLogicalChannelFactoryRequestId id; |
|
1137 User::LeaveIfError(iIdManager.GetId(id)); |
|
1138 |
|
1139 iId = id; // just in case we need to clean it up this needs to be stored |
|
1140 CleanupStack::PushL(TCleanupItem(FreeId, (TAny*)this)); |
|
1141 CExpectSignallingLogicalChannel* req = CExpectSignallingLogicalChannel::NewL(aClient, id, iProtocol); |
|
1142 CleanupStack::Pop(); |
|
1143 |
|
1144 // got a complete job to do - put into job list |
|
1145 iPendingPassiveSignallingJobs.AddLast(*req); |
|
1146 |
|
1147 TLogicalChannelFactoryTicket ticket(this, id); |
|
1148 ticket.SetState(TLogicalChannelFactoryTicket::ERequestOutstanding); |
|
1149 return ticket; |
|
1150 } |
|
1151 |
|
1152 |
|
1153 TLogicalChannelFactoryTicket CLogicalChannelFactory:: |
|
1154 ExpectSessionLogicalChannelsL(XLogicalChannelFactoryClient& aClient, |
|
1155 TInt aNumRequired) |
|
1156 { |
|
1157 LOG_FUNC |
|
1158 |
|
1159 TLogicalChannelFactoryRequestId id; |
|
1160 User::LeaveIfError(iIdManager.GetId(id)); //Qualified |
|
1161 |
|
1162 iId = id; // just in case we need to clean it up this needs to be stored |
|
1163 CleanupStack::PushL(TCleanupItem(FreeId, (TAny*)this)); |
|
1164 CExpectSessionLogicalChannels* req = CExpectSessionLogicalChannels::NewL(aClient,id, aNumRequired, iProtocol); //Qualified |
|
1165 CleanupStack::Pop(); |
|
1166 |
|
1167 // got a complete job to do - put into job list |
|
1168 iPendingPassiveSessionJobs.AddLast(*req); |
|
1169 |
|
1170 TLogicalChannelFactoryTicket ticket(this, id); |
|
1171 ticket.SetState(TLogicalChannelFactoryTicket::ERequestOutstanding); |
|
1172 return ticket; |
|
1173 } |
|
1174 |
|
1175 /** |
|
1176 For some jobs that clients are not interested in the results of we act as the client, dealing |
|
1177 with completion of the job. |
|
1178 */ |
|
1179 void CLogicalChannelFactory::LogicalChannelFactoryRequestComplete(TLogicalChannelFactoryTicket aTicket, TInt aResult) |
|
1180 { |
|
1181 LOG_FUNC |
|
1182 #ifdef _DEBUG |
|
1183 TBool found = EFalse; |
|
1184 #endif |
|
1185 |
|
1186 CCloseSessionLogicalChannels* clc = NULL; |
|
1187 TSglQueIter<CCloseSessionLogicalChannels> iter(iCloseChannelJobs); |
|
1188 while(iter) |
|
1189 { |
|
1190 clc = iter++; |
|
1191 if(clc->iId == aTicket.iId) |
|
1192 { |
|
1193 #ifdef _DEBUG |
|
1194 found = ETrue; |
|
1195 #endif |
|
1196 iCloseChannelJobs.Remove(*clc); |
|
1197 delete clc; |
|
1198 // Only free the ID of successful jobs - NotifyComplete() frees the ID of unsuccessful jobs |
|
1199 if (aResult == KErrNone) |
|
1200 { |
|
1201 iIdManager.FreeId(aTicket.iId); |
|
1202 } |
|
1203 break; |
|
1204 } |
|
1205 } |
|
1206 |
|
1207 __ASSERT_DEBUG(found, Panic(EAvdtpJobCompleteForUnknownCloseChannelJob)); |
|
1208 } |
|
1209 |
|
1210 CServProviderBase* CManagedLogicalChannel::ObtainSAP() |
|
1211 { |
|
1212 LOG_FUNC |
|
1213 CServProviderBase* sap = iLogicalChannelSAP; |
|
1214 iLogicalChannelSAP = NULL; |
|
1215 return sap; |
|
1216 } |
|
1217 |
|
1218 void CManagedLogicalChannel::ProvideSAP(CServProviderBase* aSAP) |
|
1219 { |
|
1220 __ASSERT_DEBUG(aSAP, Panic(EAvdtpPassingNullSapOwnershipToChannel)); |
|
1221 __ASSERT_DEBUG(!iLogicalChannelSAP, Panic(EAvdtpPassingSapOwnershipToChannelThatAlreadyHasASap)); |
|
1222 iLogicalChannelSAP = aSAP; |
|
1223 iLogicalChannelSAP->SetNotify(this); |
|
1224 } |
|
1225 |
|
1226 void CLogicalChannelFactory::LogicalChannelLost(CManagedLogicalChannel* aChannel) |
|
1227 { |
|
1228 LOG_FUNC |
|
1229 |
|
1230 // This could be a channel we've been asked to disconnect, or a channel |
|
1231 // we've brought up with has been lost before being claimed. |
|
1232 |
|
1233 TSglQueIter<CCloseSessionLogicalChannels> closeChannelIter(iCloseChannelJobs); |
|
1234 while(closeChannelIter) |
|
1235 { |
|
1236 CCloseSessionLogicalChannels* clc = closeChannelIter++; |
|
1237 if(clc->iId == aChannel->iId) |
|
1238 { |
|
1239 clc->ChannelClosed(aChannel); |
|
1240 return; |
|
1241 } |
|
1242 } |
|
1243 |
|
1244 // We weren't waiting for this channel to go down, check the unclaimed channels |
|
1245 // find, remove and delete |
|
1246 TDblQueIter<CManagedLogicalChannel> unclaimedIter(iUnclaimedLogicalChannels); |
|
1247 |
|
1248 while (unclaimedIter) |
|
1249 { |
|
1250 CManagedLogicalChannel* ch = unclaimedIter++; |
|
1251 if (ch == aChannel) |
|
1252 { |
|
1253 ch->iFactoryQLink.Deque(); |
|
1254 delete ch; |
|
1255 break; // cos we're adding at head |
|
1256 } |
|
1257 } |
|
1258 } |
|
1259 |
|
1260 |
|
1261 CManagedLogicalChannel* CManagedLogicalChannel::NewL(CLogicalChannelFactory& aFactory, |
|
1262 const TBTDevAddr& aAddr, |
|
1263 TInt aSequenceNumber, |
|
1264 TLogicalChannelFactoryRequestId aId, |
|
1265 CServProviderBase* aPrecreatedSAP/*=NULL*/) |
|
1266 { |
|
1267 LOG_STATIC_FUNC |
|
1268 CManagedLogicalChannel* self = new (ELeave) CManagedLogicalChannel(aFactory, aAddr, aSequenceNumber, aId); |
|
1269 CleanupStack::PushL(self); |
|
1270 self->ConstructL(aPrecreatedSAP); |
|
1271 CleanupStack::Pop(self); |
|
1272 return self; |
|
1273 } |
|
1274 |
|
1275 CManagedLogicalChannel* CManagedLogicalChannel::NewL(CLogicalChannelFactory& aFactory, |
|
1276 TLogicalChannelFactoryRequestId aId) |
|
1277 { |
|
1278 LOG_STATIC_FUNC |
|
1279 // We don't call the ConstructL here as this overload of NewL is used when the SAP |
|
1280 // will be provided later. |
|
1281 CManagedLogicalChannel* self = new (ELeave) CManagedLogicalChannel(aFactory, aId); |
|
1282 return self; |
|
1283 } |
|
1284 |
|
1285 void CManagedLogicalChannel::ConstructL(CServProviderBase* aPrecreatedSAP) |
|
1286 { |
|
1287 LOG_FUNC |
|
1288 iLogicalChannelSAP = aPrecreatedSAP ? aPrecreatedSAP : |
|
1289 iFactory.SAPFactory().NewSAPL(KSockSeqPacket); |
|
1290 |
|
1291 // There are two things we may need to change here, depending on what |
|
1292 // sort of channel we're creating: |
|
1293 // - On outgoing request for a signalling channel we need to |
|
1294 // request a reliable channel |
|
1295 // - On any request for a transport channel we need to bump up the channel priority |
|
1296 |
|
1297 TPckgBuf<TL2CapConfig> configBuf; |
|
1298 iLogicalChannelSAP->GetOption(KSolBtL2CAP, KL2CAPUpdateChannelConfig, configBuf); |
|
1299 |
|
1300 if(iSequenceNumber != KInitialSequenceNumber) |
|
1301 { |
|
1302 configBuf().ConfigureChannelPriority(TL2CapConfig::EHigh); |
|
1303 iLogicalChannelSAP->SetOption(KSolBtL2CAP, KL2CAPUpdateChannelConfig, configBuf); |
|
1304 } |
|
1305 else if(!aPrecreatedSAP) |
|
1306 { |
|
1307 // FIXME consider value of rtx timer, should consider Tgavdp |
|
1308 // Note: The 'rtx timer' actually sets max retransmit count instead [Piotr]. |
|
1309 configBuf().ConfigureReliableChannel(500); |
|
1310 iLogicalChannelSAP->SetOption(KSolBtL2CAP, KL2CAPUpdateChannelConfig, configBuf); |
|
1311 } |
|
1312 |
|
1313 // tell sap who its socket is |
|
1314 iLogicalChannelSAP->SetNotify(this); |
|
1315 iLogicalChannelSAP->Start(); |
|
1316 } |
|
1317 |
|
1318 CManagedLogicalChannel::CManagedLogicalChannel(CLogicalChannelFactory& aFactory, |
|
1319 const TBTDevAddr& aAddr, |
|
1320 TInt aSequenceNumber , |
|
1321 TLogicalChannelFactoryRequestId aId) |
|
1322 : iFactory(aFactory), iRemoteAddress(aAddr), iSequenceNumber(aSequenceNumber), iId(aId) |
|
1323 { |
|
1324 LOG_FUNC |
|
1325 __ASSERT_DEBUG(iSequenceNumber>=KInitialSequenceNumber, Panic(EAvdtpLogicalChannelFactoryBadSequenceNumber)); |
|
1326 } |
|
1327 |
|
1328 CManagedLogicalChannel::CManagedLogicalChannel(CLogicalChannelFactory& aFactory, |
|
1329 TLogicalChannelFactoryRequestId aId) |
|
1330 : iFactory(aFactory), iId(aId) |
|
1331 { |
|
1332 LOG_FUNC |
|
1333 } |
|
1334 |
|
1335 CManagedLogicalChannel::~CManagedLogicalChannel() |
|
1336 { |
|
1337 LOG_FUNC |
|
1338 // need to clear up SAP (we're unclaimed at this point) |
|
1339 delete iLogicalChannelSAP; |
|
1340 } |
|
1341 |
|
1342 void CManagedLogicalChannel::Shutdown() |
|
1343 { |
|
1344 /* |
|
1345 NOTE it IS possible that the channel is NOT totally setup |
|
1346 if the remote is behaving badly. |
|
1347 So in case check the channel has a SAP BEFORE |
|
1348 calling shutdown. */ |
|
1349 if (iLogicalChannelSAP) |
|
1350 { |
|
1351 iLogicalChannelSAP->Shutdown(CServProviderBase::EImmediate); |
|
1352 } |
|
1353 } |
|
1354 |
|
1355 void CManagedLogicalChannel::NewData(TUint aCount) |
|
1356 { |
|
1357 LOG_FUNC |
|
1358 // this class doesn't "know" the protocol. it just leaves the data in l2cap |
|
1359 // for the eventual user of this sap to extract |
|
1360 if (aCount==KNewDataEndofData) |
|
1361 { |
|
1362 iEndOfData = ETrue; |
|
1363 } |
|
1364 else |
|
1365 { |
|
1366 iDataCount+=aCount; |
|
1367 } |
|
1368 } |
|
1369 |
|
1370 void CManagedLogicalChannel::CanSend() |
|
1371 { |
|
1372 LOG_FUNC |
|
1373 // we never send |
|
1374 __DEBUGGER(); |
|
1375 } |
|
1376 |
|
1377 void CManagedLogicalChannel::ConnectComplete() |
|
1378 { |
|
1379 LOG_FUNC |
|
1380 // we never connect |
|
1381 __DEBUGGER(); |
|
1382 } |
|
1383 |
|
1384 void CManagedLogicalChannel::ConnectComplete(const TDesC8& /*aConnectData*/) |
|
1385 { |
|
1386 LOG_FUNC |
|
1387 // we never connect |
|
1388 __DEBUGGER(); |
|
1389 } |
|
1390 |
|
1391 void CManagedLogicalChannel::ConnectComplete(CServProviderBase& /*aSSP*/) |
|
1392 { |
|
1393 LOG_FUNC |
|
1394 // we never connect |
|
1395 __DEBUGGER(); |
|
1396 } |
|
1397 |
|
1398 void CManagedLogicalChannel::ConnectComplete(CServProviderBase& /*aSSP*/,const TDesC8& /*aConnectData*/) |
|
1399 { |
|
1400 LOG_FUNC |
|
1401 // we never connect |
|
1402 __DEBUGGER(); |
|
1403 } |
|
1404 |
|
1405 void CManagedLogicalChannel::CanClose(TDelete /*aDelete*/) |
|
1406 { |
|
1407 LOG_FUNC |
|
1408 // we only shutdown immediately |
|
1409 __DEBUGGER(); |
|
1410 } |
|
1411 |
|
1412 void CManagedLogicalChannel::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/) |
|
1413 { |
|
1414 LOG_FUNC |
|
1415 // we only shutdown immediately |
|
1416 __DEBUGGER(); |
|
1417 } |
|
1418 |
|
1419 void CManagedLogicalChannel::Error(TInt /*aError*/,TUint /*aOperationMask*/) |
|
1420 { |
|
1421 LOG_FUNC |
|
1422 iFactory.LogicalChannelLost(this); // will delete us |
|
1423 } |
|
1424 |
|
1425 void CManagedLogicalChannel::Disconnect() |
|
1426 { |
|
1427 LOG_FUNC |
|
1428 iFactory.LogicalChannelLost(this); // will delete us |
|
1429 } |
|
1430 |
|
1431 void CManagedLogicalChannel::Disconnect(TDesC8& /*aDisconnectData*/) |
|
1432 { |
|
1433 LOG_FUNC |
|
1434 // bearer doesnt support disconnect data |
|
1435 __DEBUGGER(); |
|
1436 Disconnect(); |
|
1437 } |
|
1438 |
|
1439 void CManagedLogicalChannel::IoctlComplete(TDesC8* /*aBuf*/) |
|
1440 { |
|
1441 LOG_FUNC |
|
1442 // we don't issue ioctls |
|
1443 __DEBUGGER(); |
|
1444 } |
|
1445 |
|
1446 void CManagedLogicalChannel::NoBearer(const TDesC8& /*aConnectionInfo*/) |
|
1447 { |
|
1448 LOG_FUNC |
|
1449 // a redundant artefact of IP nonsense |
|
1450 __DEBUGGER(); |
|
1451 } |
|
1452 |
|
1453 void CManagedLogicalChannel::Bearer(const TDesC8& /*aConnectionInfo*/) |
|
1454 { |
|
1455 LOG_FUNC |
|
1456 // a redundant artefact of IP nonsense |
|
1457 __DEBUGGER(); |
|
1458 } |
|
1459 |
|
1460 |
|
1461 TLogicalChannelFactoryTicket::TLogicalChannelFactoryTicket(CLogicalChannelFactory* aFactory, TLogicalChannelFactoryRequestId aId) |
|
1462 : iFactory(aFactory) |
|
1463 , iId(aId) |
|
1464 , iState(TLogicalChannelFactoryTicket::ERequestIdle) |
|
1465 { |
|
1466 LOG_FUNC |
|
1467 } |
|
1468 |
|
1469 TLogicalChannelFactoryTicket::TLogicalChannelFactoryTicket() |
|
1470 : iState(TLogicalChannelFactoryTicket::ERequestIdle) |
|
1471 { |
|
1472 LOG_FUNC |
|
1473 } |
|
1474 |
|
1475 TLogicalChannelRecord TLogicalChannelFactoryTicket::GetLogicalChannel(TInt aSequenceNumber/*=1*/) |
|
1476 { |
|
1477 LOG_FUNC |
|
1478 __ASSERT_DEBUG(iState != ERequestErrored, Panic(EAvdtpInvalidResponseInUse)); |
|
1479 TBool finished = EFalse; |
|
1480 TLogicalChannelRecord rec = iFactory->ClaimLogicalChannel(aSequenceNumber, iId, finished); |
|
1481 if (finished) |
|
1482 { |
|
1483 // to stop people forgetting |
|
1484 iState = ERequestComplete; |
|
1485 } |
|
1486 return rec; |
|
1487 } |
|
1488 |
|
1489 void TLogicalChannelFactoryTicket::SetState(TLogicalChannelFactoryRequestState aNewState) |
|
1490 { |
|
1491 LOG_FUNC |
|
1492 LOG2(_L("State Transition %d -> %d"), iState, aNewState); |
|
1493 iState = aNewState; |
|
1494 } |
|
1495 |
|
1496 |
|
1497 TLogicalChannelFactoryTicketInspector::TLogicalChannelFactoryTicketInspector( |
|
1498 TLogicalChannelFactoryTicket& aTicket, |
|
1499 TBool aRequireReporting, |
|
1500 TBool aRequireRecovery, TBool aMuxed) |
|
1501 : iTicket(aTicket) |
|
1502 , iSignallingSequenceNumber(KInitialSequenceNumber) |
|
1503 , iMediaSequenceNumber(KInitialSequenceNumber) |
|
1504 , iCached(EFalse) |
|
1505 { |
|
1506 LOG_FUNC |
|
1507 #ifdef _DEBUG |
|
1508 // to assert against later |
|
1509 iRequireReporting = aRequireReporting; |
|
1510 iRequireRecovery = aRequireRecovery; |
|
1511 #endif |
|
1512 if (aMuxed) |
|
1513 { |
|
1514 // the reporting and media go in one channel, the first created |
|
1515 // this class knows a bit about the strategy of mux allocation |
|
1516 iReportingSequenceNumber = 1; // with media |
|
1517 iRecoverySequenceNumber = 2; |
|
1518 } |
|
1519 else |
|
1520 { |
|
1521 iReportingSequenceNumber = 2; |
|
1522 iRecoverySequenceNumber = aRequireReporting & aRequireRecovery ? 3 : 2; |
|
1523 } |
|
1524 } |
|
1525 |
|
1526 TLogicalChannelRecord TLogicalChannelFactoryTicketInspector::GetLogicalChannel(TAvdtpTransportSessionType aType) |
|
1527 { |
|
1528 LOG_FUNC |
|
1529 TLogicalChannelRecord rec; |
|
1530 |
|
1531 if (!iCached) |
|
1532 { |
|
1533 const TInt* index; |
|
1534 switch (aType) |
|
1535 { |
|
1536 case ESignalling: |
|
1537 index = &iSignallingSequenceNumber; |
|
1538 break; |
|
1539 case EMedia: |
|
1540 index = &iMediaSequenceNumber; |
|
1541 break; |
|
1542 case EReporting: |
|
1543 __ASSERT_DEBUG(iRequireReporting, Panic(EAvdtpLogicalChannelFactoryBadClaimLogicalChannel)); |
|
1544 index = &iReportingSequenceNumber; |
|
1545 break; |
|
1546 case ERecovery: |
|
1547 __ASSERT_DEBUG(iRequireRecovery, Panic(EAvdtpLogicalChannelFactoryBadClaimLogicalChannel)); |
|
1548 index = &iRecoverySequenceNumber; |
|
1549 break; |
|
1550 default: |
|
1551 index = NULL; |
|
1552 } |
|
1553 __ASSERT_DEBUG(index, Panic(EAvdtpLogicalChannelFactoryBadClaimLogicalChannel)); |
|
1554 rec = iTicket.GetLogicalChannel(*index); |
|
1555 |
|
1556 if (iReportingSequenceNumber==iMediaSequenceNumber) |
|
1557 { |
|
1558 // we're in muxed case... |
|
1559 // this helper helps further by caching the record |
|
1560 // so that the client can claim again for reporting, even if same record |
|
1561 // that the factory will have (rightly) purged |
|
1562 // therefore cache this |
|
1563 iCachedRecord = rec; |
|
1564 iCached = ETrue; |
|
1565 } |
|
1566 } |
|
1567 else |
|
1568 { |
|
1569 // cached - use same record, and allow arbitrary order of |
|
1570 // collection of cache-able session types |
|
1571 if (aType == EMedia || aType == EReporting) |
|
1572 { |
|
1573 rec = iCachedRecord; |
|
1574 iCached = EFalse; |
|
1575 } |
|
1576 } |
|
1577 return rec; |
|
1578 } |