|
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // AVCTP muxer |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalComponent |
|
21 */ |
|
22 |
|
23 #include <bluetooth/logger.h> |
|
24 #include <bt_sock.h> |
|
25 #include <es_mbuf.h> |
|
26 |
|
27 #include "avctpmuxer.h" |
|
28 #include "avctpcommon.h" |
|
29 #include "avctpmuxerstates.h" |
|
30 #include "Avctp.h" |
|
31 #include "avctputils.h" |
|
32 #include "avctppacket.h" |
|
33 #include "avctpsap.h" |
|
34 #include "avctpPacketMgr.h" |
|
35 |
|
36 #ifdef __FLOG_ACTIVE |
|
37 _LIT8(KLogComponent, LOG_COMPONENT_AVCTP); |
|
38 #endif |
|
39 |
|
40 #ifdef _DEBUG |
|
41 PANICCATEGORY("avctpmux"); |
|
42 #endif |
|
43 |
|
44 using namespace SymbianAvctp; |
|
45 |
|
46 #ifdef __FLOG_ACTIVE |
|
47 #define LOG_CLIENTS LogClients(); |
|
48 #else |
|
49 #define LOG_CLIENTS |
|
50 #endif |
|
51 |
|
52 /** |
|
53 Factory function for CAvctpTransport - called when local device initiates |
|
54 the connection. |
|
55 |
|
56 Note the CProtocolBase passed in so that the muxer can create its own L2CAP SAP |
|
57 |
|
58 @internalComponent |
|
59 @leave KErrNoMemory if the muxer could not be allocated |
|
60 @param aProtocol The AVCTP protocol object, used to make callbacks on the protocol |
|
61 @return A new muxer in the right state |
|
62 */ |
|
63 CAvctpTransport* CAvctpTransport::NewL(CAvctpProtocol& aProtocol) |
|
64 { |
|
65 LOG_STATIC_FUNC |
|
66 |
|
67 CAvctpTransport* transport = new(ELeave) CAvctpTransport(aProtocol); |
|
68 CleanupStack::PushL(transport); |
|
69 transport->ConstructL(); |
|
70 CleanupStack::Pop(transport); |
|
71 return transport; |
|
72 } |
|
73 |
|
74 /** |
|
75 AVCTP SubConnection Provider Constructor |
|
76 |
|
77 Set up the async. callback. |
|
78 |
|
79 @internalComponent |
|
80 @param aProt The protocol object |
|
81 */ |
|
82 CAvctpTransport::CAvctpTransport(CAvctpProtocol& aProt) : |
|
83 iProtocol(aProt), |
|
84 iSecondChannelSocket(*this), |
|
85 iState(&(aProt.MuxerStateFactory().GetState(CAvctpMuxerStateFactory::EClosed))), |
|
86 iAddress(TBTDevAddr(0)) |
|
87 { |
|
88 LOG_FUNC |
|
89 |
|
90 TCallBack cb(IdleTimerExpired, this); |
|
91 iIdleTimerEntry.Set(cb); |
|
92 }; |
|
93 |
|
94 /** |
|
95 Second phase muxer construction. |
|
96 |
|
97 @internalComponent |
|
98 */ |
|
99 void CAvctpTransport::ConstructL() |
|
100 { |
|
101 LOG_FUNC |
|
102 |
|
103 TCallBack cb(SecondChannelNewDataAsyncCallBack, this); |
|
104 iNewDataAsyncCallBack = new (ELeave)CAsyncCallBack(cb, EActiveHighPriority); |
|
105 iPacketMgr = CAvctpPacketMgr::NewL(*this, iProtocol); |
|
106 |
|
107 SetSendBlocked(KAvctpPrimaryChannel); |
|
108 SetSendBlocked(KAvctpSecondaryChannel); |
|
109 CheckForIdle(); |
|
110 } |
|
111 |
|
112 /** |
|
113 Muxer d'tor |
|
114 |
|
115 We only Shutdown the lower protocol sap in an immediate way because in normal |
|
116 circumstances we will have decided to die after idling for a while which means |
|
117 no-one had data to send via this muxer. Hence there should be little chance |
|
118 of losing data that could otherwise have been left in the L2CAP sap. If we did a |
|
119 graceful close we would then have had to wait for the CanClose response which is |
|
120 an unnecessary overhead if we've already used a timeout to decide no-one wants |
|
121 the link. |
|
122 |
|
123 If the muxer died gracefully, there will be no data in the system that needs |
|
124 to be sent over this muxer, however if the muxer goes down suddenly, e.g. the |
|
125 remote disconnects, a connection attempt fails or a Shutdown is called there |
|
126 will be data left in the protocol as a whole that would attempt a reconnection |
|
127 to the remote device of this muxer. Hence we tell the saps we've gone down to |
|
128 let them decide whether or not their packets have become stale or not. |
|
129 |
|
130 @internalComponent |
|
131 */ |
|
132 CAvctpTransport::~CAvctpTransport() |
|
133 { |
|
134 LOG_FUNC |
|
135 |
|
136 DequeIdleTimer(); |
|
137 |
|
138 iProtocol.SignalMuxerDownToSaps(DevAddr()); |
|
139 iProtocol.RemoveTransport(*this); // it's okay to deque the link even if that's already been done |
|
140 |
|
141 // the first channel (index 0) is the most important, so better closing from the last one |
|
142 |
|
143 TInt index; |
|
144 for(index = iChannelSAPs.Count()-1;index>=0;index--) |
|
145 { |
|
146 if (iChannelSAPs[index]) |
|
147 { |
|
148 iChannelSAPs[index]->Shutdown(CServProviderBase::EImmediate); |
|
149 delete iChannelSAPs[index]; |
|
150 } |
|
151 } |
|
152 |
|
153 CancelSecondChannelNewDataAsyncCallBack(); |
|
154 delete iNewDataAsyncCallBack; |
|
155 |
|
156 delete iPacketMgr; |
|
157 iClientItems.Close(); |
|
158 } |
|
159 |
|
160 |
|
161 TInt CAvctpTransport::AddSecondChannel(CServProviderBase& aSAP) |
|
162 { |
|
163 LOG_FUNC |
|
164 return iState->AddSecondChannel(*this, aSAP); |
|
165 } |
|
166 |
|
167 TBool CAvctpTransport::HasSecondChannel() const |
|
168 { |
|
169 LOG_FUNC |
|
170 return iChannelSAPs[KAvctpSecondaryChannel] != NULL ? ETrue : EFalse; |
|
171 } |
|
172 |
|
173 void CAvctpTransport::RemoveSecondChannel() |
|
174 { |
|
175 LOG_FUNC |
|
176 iState->RemoveSecondChannel(*this); |
|
177 } |
|
178 |
|
179 TInt CAvctpTransport::GetChannelMtu(TInt aChannel, TInt& aMtu) const |
|
180 { |
|
181 LOG_FUNC |
|
182 |
|
183 TInt err = KErrNotReady; |
|
184 if(iChannelSAPs[aChannel]) |
|
185 { |
|
186 TPckgBuf<TInt> mtuBuf; |
|
187 err = iChannelSAPs[aChannel]->GetOption(KSolBtL2CAP, KL2CAPNegotiatedOutboundMTU, mtuBuf); |
|
188 if (err == KErrNone) |
|
189 { |
|
190 // MTU for AVCTP clients is L2CAP MTU - AVCTP Header |
|
191 aMtu = mtuBuf() - SymbianAvctp::ENormalHeaderLength; |
|
192 } |
|
193 } |
|
194 |
|
195 return err; |
|
196 } |
|
197 |
|
198 |
|
199 /****************************************************************************/ |
|
200 /* |
|
201 Notifications from the MSocketNotify interface |
|
202 I.e calls from iChannelSAPs[KAvctpPrimaryChannel] |
|
203 */ |
|
204 |
|
205 /** |
|
206 Called when new data is available. |
|
207 |
|
208 This is called each time a new packet of data arrives from L2CAP. |
|
209 We get to the data by calling GetData on the L2CAP SAP. |
|
210 |
|
211 This assumes a packet interface from L2CAP. |
|
212 |
|
213 @internalComponent |
|
214 @param aCount Number of new packets waiting |
|
215 */ |
|
216 void CAvctpTransport::NewData(TUint aCount) |
|
217 { |
|
218 LOG_FUNC |
|
219 |
|
220 LOG1(_L("%d packets available"), aCount); |
|
221 |
|
222 if (aCount == KNewDataEndofData) |
|
223 { |
|
224 Disconnect(); |
|
225 } |
|
226 else |
|
227 { |
|
228 // for latency reasons, we process channel 1 data synchronously |
|
229 // Only need to do this once rather than for each NewData call |
|
230 // because these calls are all synchronous and hence the MTU |
|
231 // of L2CAP can't change in-between GetData calls (changing |
|
232 // the MTU requires negotiation with a remote device |
|
233 // which is naturally asynchronous) |
|
234 TInt mtu = GetCurrentInboundMtu(KAvctpPrimaryChannel); |
|
235 |
|
236 if(mtu >= 0) |
|
237 { |
|
238 __DEBUG_ONLY(TInt err;) |
|
239 while (aCount--) |
|
240 { |
|
241 if ((__DEBUG_ONLY(err =) iState->NewData(*this, mtu, 0)) != KErrNone) |
|
242 { |
|
243 __ASSERT_DEBUG(err == KErrMuxerShutDown, Panic(EUnexpectedErrorCode)); |
|
244 break; |
|
245 } |
|
246 } |
|
247 } |
|
248 } |
|
249 } |
|
250 |
|
251 |
|
252 /** |
|
253 Notification that we can now send data to the lower layer. |
|
254 |
|
255 @internalComponent |
|
256 */ |
|
257 void CAvctpTransport::CanSend() |
|
258 { |
|
259 LOG_FUNC |
|
260 iState->CanSend(*this, KAvctpPrimaryChannel); //channel is implicitly primary one because this upcall from the sap1 |
|
261 } |
|
262 |
|
263 /** |
|
264 Signal from the lower protocol SAP that a connection has occurred. |
|
265 |
|
266 Part of the MSocketNotify interface. This is called when L2CAP |
|
267 has brought up the lower layer link to the remote device. |
|
268 |
|
269 @internalComponent |
|
270 */ |
|
271 void CAvctpTransport::ConnectComplete() |
|
272 { |
|
273 LOG_FUNC |
|
274 |
|
275 IF_FLOGGING |
|
276 ( |
|
277 TBuf<KBTAddressLength> address; |
|
278 iRemoteAddr.GetReadable(address); |
|
279 ) |
|
280 |
|
281 LOG1(_L("from BT Device 0x%S"), &address); |
|
282 |
|
283 iState->ConnectComplete(*this); |
|
284 } |
|
285 |
|
286 /** |
|
287 Version with connection data. |
|
288 |
|
289 Ignore the data (since L2CAP should never provide this!) |
|
290 |
|
291 @internalComponent |
|
292 @param aConnectData The data received on connection |
|
293 */ |
|
294 void CAvctpTransport::ConnectComplete(const TDesC8& /*aConnectData*/) |
|
295 { |
|
296 LOG_FUNC |
|
297 LOG(_L("ConnectComplete with aConnectData")); |
|
298 ConnectComplete(); |
|
299 } |
|
300 |
|
301 /** |
|
302 Incoming connection completed on listening socket. |
|
303 |
|
304 @internalComponent |
|
305 @param aSSP The new SAP for the completed connection |
|
306 */ |
|
307 void CAvctpTransport::ConnectComplete(CServProviderBase& /*aSSP*/) |
|
308 { |
|
309 LOG_FUNC |
|
310 LOG(_L("ConnectComplete with aSSP")); |
|
311 ConnectComplete(); |
|
312 } |
|
313 |
|
314 /** |
|
315 Incoming connection completed on listening socket with connection data. |
|
316 |
|
317 @internalComponent |
|
318 @param aSSP The new SAP for the completed connection |
|
319 */ |
|
320 void CAvctpTransport::ConnectComplete(CServProviderBase& /*aSSP*/,const TDesC8& /*aConnectData*/) |
|
321 { |
|
322 LOG_FUNC |
|
323 LOG(_L("ConnectComplete with aSSP and aConnectData")); |
|
324 ConnectComplete(); |
|
325 } |
|
326 |
|
327 /** |
|
328 We must have asked the lower protocol socket to shutdown, which means we're dying. |
|
329 However we only ask for an immediate shutdown so we shouldn't get a CanClose callback |
|
330 |
|
331 @internalComponent |
|
332 @param aDelete How to shutdown |
|
333 */ |
|
334 void CAvctpTransport::CanClose(TDelete /*aDelete*/) |
|
335 { |
|
336 LOG_FUNC |
|
337 Panic(ELowerProtocolSapCanClose); |
|
338 } |
|
339 |
|
340 /** |
|
341 The lower socket can close, with disconnection data. |
|
342 |
|
343 We don't support this so panic |
|
344 |
|
345 @internalComponent |
|
346 @param aDisconnectData Data from the disconnecting socket |
|
347 @param aDelete How to shutdown |
|
348 */ |
|
349 void CAvctpTransport::CanClose(const TDesC8& /*aDisconnectData*/, TDelete /*aDelete*/) |
|
350 { |
|
351 LOG_FUNC |
|
352 Panic(ELowerProtocolSapCanClose); |
|
353 } |
|
354 |
|
355 /** |
|
356 Something has gone wrong. |
|
357 |
|
358 We get told whether it's just this operation or others that are |
|
359 affected. We use this to decide what to do. |
|
360 |
|
361 @internalComponent |
|
362 @param aError The error code |
|
363 @param aOperationMask The operation(s) affected |
|
364 */ |
|
365 void CAvctpTransport::Error(TInt aError, TUint aOperationMask) |
|
366 { |
|
367 LOG_FUNC |
|
368 |
|
369 LOG2(_L("Error %d, OperationMask 0b%b"), aError, aOperationMask); |
|
370 iState->Error(*this, aError, aOperationMask, KAvctpPrimaryChannel); |
|
371 } |
|
372 |
|
373 /** |
|
374 The L2CAP link has disconnected. This is the result of a remote device disconnecting |
|
375 |
|
376 @internalComponent |
|
377 */ |
|
378 void CAvctpTransport::Disconnect() |
|
379 { |
|
380 LOG_FUNC |
|
381 iState->Disconnect(*this); |
|
382 } |
|
383 |
|
384 /** |
|
385 Disconnect with disconnection data. |
|
386 |
|
387 Ignore the data (since L2CAP should never provide this!) |
|
388 |
|
389 @internalComponent |
|
390 @param aDisconnectData Data from the disconnecting socket |
|
391 */ |
|
392 void CAvctpTransport::Disconnect(TDesC8& /*aDisconnectData*/) |
|
393 { |
|
394 LOG_FUNC |
|
395 LOG(_L("Disconnect with aDisconnectData")); |
|
396 Disconnect(); |
|
397 } |
|
398 |
|
399 /** |
|
400 IOCTL forwarding not support, and none initiated by AVCTP so NOP |
|
401 */ |
|
402 void CAvctpTransport::IoctlComplete(TDesC8* /*aBuf*/) |
|
403 { |
|
404 LOG_FUNC |
|
405 __PANIC_UNEXPECTED_CALL |
|
406 } |
|
407 |
|
408 /** |
|
409 This function allows the muxer to be shutdown irrespective of whether |
|
410 it is idle. This is intended to be used to punish a remote device that |
|
411 has done something naughty. |
|
412 |
|
413 @internalComponent |
|
414 */ |
|
415 void CAvctpTransport::Shutdown(TInt aError) |
|
416 { |
|
417 LOG_FUNC |
|
418 NotifyLinkDown(iAddress, KAvctpPrimaryChannel, aError); |
|
419 iState->Shutdown(*this, aError); |
|
420 } |
|
421 |
|
422 TBool CAvctpTransport::HasDataToSend() |
|
423 { |
|
424 LOG_FUNC |
|
425 |
|
426 TBool ret = PacketMgr().WouldLikeToSend(); |
|
427 if (ret == EFalse) |
|
428 { |
|
429 ret = iProtocol.SapsHaveDataFor(DevAddr()); |
|
430 } |
|
431 return ret; |
|
432 } |
|
433 |
|
434 /**********************************************************************/ |
|
435 /* |
|
436 Commands from the AVCTP SAP. |
|
437 */ |
|
438 |
|
439 |
|
440 TInt CAvctpTransport::Start(const TBTDevAddr& aAddr, TUint16 aClientId) |
|
441 { |
|
442 LOG_FUNC |
|
443 |
|
444 IF_FLOGGING |
|
445 ( |
|
446 TBuf<KBTAddressLength> address; |
|
447 aAddr.GetReadable(address); |
|
448 ) |
|
449 |
|
450 LOG1(_L("from BT Device 0x%S"), &address); |
|
451 |
|
452 iAddress = aAddr; |
|
453 |
|
454 return iState->Start(*this, aAddr, aClientId); |
|
455 } |
|
456 |
|
457 TInt CAvctpTransport::StartIncoming(const TBTDevAddr& aAddr, CServProviderBase* aL2CAPConSAP) |
|
458 { |
|
459 LOG_FUNC |
|
460 LOG1(_L("CServProviderBase* aL2CAPConSAP 0x%08x"), aL2CAPConSAP); |
|
461 |
|
462 iAddress = aAddr; |
|
463 |
|
464 TInt err = iState->StartIncoming(*this, aAddr, aL2CAPConSAP); |
|
465 return err; |
|
466 } |
|
467 |
|
468 |
|
469 /**********************************************************************/ |
|
470 /* |
|
471 Internal functions. |
|
472 */ |
|
473 |
|
474 /** |
|
475 Set the BTDevAddr for this Muxer & add us to the Protocol's Q |
|
476 |
|
477 @internalComponent |
|
478 @param aDevAddr The Muxer's new remote address |
|
479 @return KErrInUse if there is already a Muxer on aRemoteAddr, otherwise KErrNone |
|
480 */ |
|
481 void CAvctpTransport::AssignToDevice(const TBTDevAddr& aRemoteAddr) |
|
482 { |
|
483 LOG_FUNC |
|
484 |
|
485 // Note the below assumes that there is at most one data client (or they're all on the same PID) |
|
486 __ASSERT_DEBUG(iRemoteAddr == TBTDevAddr(0) || iRemoteAddr == aRemoteAddr, Panic(EMuxerAlreadyBound)); |
|
487 |
|
488 if (iRemoteAddr == TBTDevAddr(0)) |
|
489 { |
|
490 iRemoteAddr = aRemoteAddr; |
|
491 } |
|
492 } |
|
493 |
|
494 /** |
|
495 New data on the secondary channel is async because we want to be responsive while processing a |
|
496 potentially big amount of data |
|
497 */ |
|
498 /*static*/ TInt CAvctpTransport::SecondChannelNewDataAsyncCallBack(TAny* aTransport) |
|
499 { |
|
500 LOG_STATIC_FUNC |
|
501 |
|
502 CAvctpTransport* t = static_cast<CAvctpTransport*>(aTransport); |
|
503 |
|
504 // Only need to do this once rather than for each NewData call |
|
505 // because these calls are all synchronous and hence the MTU |
|
506 // of L2CAP can't change in-between GetData calls (changing |
|
507 // the MTU requires negotiation with a remote device |
|
508 // which is naturally asynchronous) |
|
509 TInt mtu = t->GetCurrentInboundMtu(1); |
|
510 __DEBUG_ONLY(TInt err;) |
|
511 if(mtu >= 0) |
|
512 { |
|
513 while (t->iSecondChannelPacketsWaiting) |
|
514 { |
|
515 if ((__DEBUG_ONLY(err =) t->iState->NewData(*t, mtu, KAvctpSecondaryChannel)) != KErrNone) |
|
516 { |
|
517 __ASSERT_DEBUG(err == KErrMuxerShutDown, Panic(EUnexpectedErrorCode)); |
|
518 break; |
|
519 } |
|
520 --(t->iSecondChannelPacketsWaiting); |
|
521 } |
|
522 } |
|
523 // else we have an error getting the MTU, this is probably because the |
|
524 // L2CAP channel is in the process of shutting down. We leave the data |
|
525 // there where it'll be cleared up later. If not we'll pick this data |
|
526 // up next time we get signalled NewData from the lower protocol. |
|
527 |
|
528 return EFalse; |
|
529 } |
|
530 |
|
531 /** |
|
532 Check to see if we're still needed. If not, Q a delayed delete. |
|
533 |
|
534 @internalComponent |
|
535 */ |
|
536 void CAvctpTransport::CheckForIdle() |
|
537 { |
|
538 LOG_FUNC |
|
539 |
|
540 if ( IsIdle()) |
|
541 { |
|
542 QueIdleTimer(); |
|
543 } |
|
544 } |
|
545 |
|
546 /** |
|
547 @return System wide error code if the value could not be retrieved, otherwise the current |
|
548 inbound MTU. |
|
549 */ |
|
550 TInt CAvctpTransport::GetCurrentInboundMtu(TInt aChannel) |
|
551 { |
|
552 LOG_FUNC |
|
553 TPckgBuf<TInt> buf; |
|
554 |
|
555 __ASSERT_DEBUG(iChannelSAPs[aChannel], Panic(ENullLowerProtocolSap)); |
|
556 |
|
557 TInt err = iChannelSAPs[aChannel]->GetOption(KSolBtL2CAP, KL2CAPInboundMTU, buf); |
|
558 if(!err) |
|
559 { |
|
560 return buf(); |
|
561 } |
|
562 else |
|
563 { |
|
564 return err; |
|
565 } |
|
566 } |
|
567 |
|
568 /** |
|
569 @return System wide error code if the value could not be retrieved, otherwise the current |
|
570 outbound MTU. |
|
571 */ |
|
572 TInt CAvctpTransport::GetCurrentOutboundMtu(TInt aChannel) |
|
573 { |
|
574 LOG_FUNC |
|
575 TPckgBuf<TInt> buf; |
|
576 |
|
577 __ASSERT_DEBUG(iChannelSAPs[aChannel], Panic(ENullLowerProtocolSap)); |
|
578 TInt err = iChannelSAPs[aChannel]->GetOption(KSolBtL2CAP, KL2CAPOutboundMTUForBestPerformance, buf); |
|
579 if(!err) |
|
580 { |
|
581 return buf(); |
|
582 } |
|
583 else |
|
584 { |
|
585 return err; |
|
586 } |
|
587 } |
|
588 |
|
589 TInt CAvctpTransport::DoWrite(RMBufChain& aPDU, TInt aChannel) |
|
590 { |
|
591 LOG_FUNC |
|
592 |
|
593 __ASSERT_DEBUG(iChannelSAPs[aChannel], Panic(ENullLowerProtocolSap)); |
|
594 return iChannelSAPs[aChannel]->Write(aPDU,0); |
|
595 } |
|
596 |
|
597 /** |
|
598 Check to see if the Muxer is idle. |
|
599 Note this subConProvider shouldn't have any direct data clients. |
|
600 It's only important if there are control clients or there are saps that have data to send |
|
601 through the muxer. So a data client could effectively keep us non idle by queueing data |
|
602 for us. |
|
603 |
|
604 @internalComponent |
|
605 */ |
|
606 TBool CAvctpTransport::IsIdle() |
|
607 { |
|
608 LOG_FUNC |
|
609 return iState->IsIdle(*this); |
|
610 } |
|
611 |
|
612 /** |
|
613 Queues the idle timer if necessary |
|
614 |
|
615 @internalComponent |
|
616 */ |
|
617 void CAvctpTransport::QueIdleTimer() |
|
618 { |
|
619 LOG_FUNC |
|
620 |
|
621 if (!iIdleTimerQueued) |
|
622 { |
|
623 LOG(_L("Queued idle timer")); |
|
624 |
|
625 iIdleTimerQueued = ETrue; |
|
626 BTSocketTimer::Queue(KTransportIdleTimeout, iIdleTimerEntry); |
|
627 } |
|
628 } |
|
629 |
|
630 /** |
|
631 Deques idle timer if necessary |
|
632 |
|
633 @internalComponent |
|
634 */ |
|
635 void CAvctpTransport::DequeIdleTimer() |
|
636 { |
|
637 LOG_FUNC |
|
638 |
|
639 if (iIdleTimerQueued) |
|
640 { |
|
641 LOG(_L("Dequeued idle timer")); |
|
642 |
|
643 iIdleTimerQueued = EFalse; |
|
644 BTSocketTimer::Remove(iIdleTimerEntry); |
|
645 } |
|
646 } |
|
647 |
|
648 /** |
|
649 Static idle callback. |
|
650 |
|
651 This is entered if we remain idle (as defined by IsIdle()) for the duration of the timer. |
|
652 @internalComponent |
|
653 @param aMux The muxer that is idle |
|
654 @return EFalse - do no reissue callback |
|
655 */ |
|
656 TInt CAvctpTransport::IdleTimerExpired(TAny* aTransport) |
|
657 { |
|
658 LOG_STATIC_FUNC |
|
659 LOG1(_L("on Transport 0x%08x"), aTransport); |
|
660 |
|
661 CAvctpTransport* transport = static_cast<CAvctpTransport*>(aTransport); |
|
662 |
|
663 __ASSERT_DEBUG(transport, Panic(ENullMuxer)); |
|
664 // If the following panics it means we've not cancelled our IdleTimer at some previous point |
|
665 __ASSERT_DEBUG(transport->IsIdle(), Panic(EIdleTimeoutWhenNotIdle)); |
|
666 |
|
667 transport->iIdleTimerQueued = EFalse; // Obviously... |
|
668 |
|
669 transport->iState->IdleTimerExpired(*transport); |
|
670 |
|
671 return EFalse; |
|
672 } |
|
673 |
|
674 void CAvctpTransport::NotifyLinkState(const TBTDevAddr& aAddr, TControlIoctls aIotcl, TInt aChannel, TInt aError) |
|
675 { |
|
676 LOG_FUNC |
|
677 TControlIoctlMessage msg(aIotcl, aAddr, aError); |
|
678 TPckgC<TControlIoctlMessage> pck(msg); |
|
679 |
|
680 TClientItemIter iter(iClientItems); |
|
681 while(iter.NextKey()) |
|
682 { |
|
683 const TClientItem** pitem = iter.CurrentValue(); |
|
684 MSocketNotify* socket = aChannel == KAvctpSecondaryChannel ? (*pitem)->SecondaryChannel() : (*pitem)->PrimaryChannel(); |
|
685 if(socket) |
|
686 { |
|
687 socket->IoctlComplete(&pck); |
|
688 } |
|
689 } |
|
690 } |
|
691 |
|
692 void CAvctpTransport::NotifyLinkUp(const TBTDevAddr& aAddr, TBool aIsSecondChannel) |
|
693 { |
|
694 LOG_FUNC |
|
695 iProtocol.NotifyLinkUp(aAddr, aIsSecondChannel); |
|
696 } |
|
697 |
|
698 void CAvctpTransport::NotifyLinkDown(const TBTDevAddr& aAddr, TInt aChannel, TInt aError) |
|
699 { |
|
700 LOG_FUNC |
|
701 NotifyLinkState(aAddr, ELinkDown, aChannel, aError); |
|
702 } |
|
703 |
|
704 void CAvctpTransport::NotifyAttachConfirm(TInt aError, TBool aIsSecondChannel) |
|
705 { |
|
706 LOG_FUNC |
|
707 TControlIoctlMessage msg(SymbianAvctp::EAttachConfirm, iRemoteAddr, aError); |
|
708 TPckgC<TControlIoctlMessage> pck(msg); |
|
709 |
|
710 TClientItemIter iter(iClientItems); |
|
711 while(iter.NextKey()) |
|
712 { |
|
713 const TClientItem** pitem = iter.CurrentValue(); |
|
714 MSocketNotify* socket = aIsSecondChannel ? (*pitem)->SecondaryChannel() : (*pitem)->PrimaryChannel(); |
|
715 __ASSERT_DEBUG(socket, Panic(EAvctpInvalidChannelNotify)); |
|
716 socket->IoctlComplete(&pck); |
|
717 } |
|
718 } |
|
719 |
|
720 void CAvctpTransport::NotifyAttachConfirm(TUint16 aClientId, TInt aError, TBool aIsSecondChannel) |
|
721 { |
|
722 LOG_FUNC |
|
723 TPtrC8 addr(iRemoteAddr.Des()); |
|
724 TControlIoctlMessage msg(SymbianAvctp::EAttachConfirm, iRemoteAddr, aError); |
|
725 TPckgC<TControlIoctlMessage> pck(msg); |
|
726 |
|
727 const TClientItem** pitem = iClientItems.Find(aClientId); |
|
728 if (pitem) |
|
729 { |
|
730 MSocketNotify* socket = aIsSecondChannel ? (*pitem)->SecondaryChannel() : (*pitem)->PrimaryChannel(); |
|
731 if (aIsSecondChannel && !(*pitem)->IsSecondaryChannelAttached()) |
|
732 return; |
|
733 |
|
734 __ASSERT_DEBUG(socket, Panic(EAvctpInvalidChannelNotify)); |
|
735 if (socket) |
|
736 { |
|
737 socket->IoctlComplete(&pck); |
|
738 } |
|
739 } |
|
740 } |
|
741 |
|
742 void CAvctpTransport::NotifyDetachConfirm(TUint16 aClientId, TInt aError, TBool aIsSecondChannel) |
|
743 { |
|
744 LOG_FUNC |
|
745 TPtrC8 addr(iRemoteAddr.Des()); |
|
746 TControlIoctlMessage msg(SymbianAvctp::EDetachConfirm, iRemoteAddr, aError); |
|
747 TPckgC<TControlIoctlMessage> pck(msg); |
|
748 |
|
749 const TClientItem** pitem = iClientItems.Find(aClientId); |
|
750 if (*pitem) |
|
751 { |
|
752 MSocketNotify* socket = aIsSecondChannel ? (*pitem)->SecondaryChannel() : (*pitem)->PrimaryChannel(); |
|
753 __ASSERT_DEBUG(socket, Panic(EAvctpInvalidChannelNotify)); |
|
754 socket->IoctlComplete(&pck); |
|
755 } |
|
756 } |
|
757 |
|
758 void CAvctpTransport::NotifyLinkError(TInt aError, TBool aIsSecondChannel) |
|
759 { |
|
760 LOG_FUNC |
|
761 TPtrC8 addr(iRemoteAddr.Des()); |
|
762 TControlIoctlMessage msg(SymbianAvctp::EError, iRemoteAddr, aError); |
|
763 TPckgC<TControlIoctlMessage> pck(msg); |
|
764 |
|
765 TClientItemIter iter(iClientItems); |
|
766 while(iter.NextKey()) |
|
767 { |
|
768 const TClientItem** pitem = iter.CurrentValue(); |
|
769 MSocketNotify* notify = aIsSecondChannel ? (*pitem)->SecondaryChannel() : (*pitem)->PrimaryChannel(); |
|
770 if (notify) |
|
771 { |
|
772 notify->IoctlComplete(&pck); |
|
773 } |
|
774 } |
|
775 } |
|
776 |
|
777 void CAvctpTransport::MbpsnNewData(TUint aCount) |
|
778 { |
|
779 // new data from the second channel |
|
780 |
|
781 LOG_FUNC |
|
782 |
|
783 LOG1(_L("%d packets available"), aCount); |
|
784 |
|
785 if (aCount == KNewDataEndofData) |
|
786 { |
|
787 this->MbpsnDisconnect(); |
|
788 } |
|
789 else |
|
790 { |
|
791 iSecondChannelPacketsWaiting += aCount; |
|
792 StartSecondChannelNewDataAsyncCallBack(); |
|
793 } |
|
794 |
|
795 } |
|
796 |
|
797 void CAvctpTransport::MbpsnCanSend() |
|
798 { |
|
799 LOG_FUNC |
|
800 iState->CanSend(*this, KAvctpSecondaryChannel); //channel is implicitly the second channel with this upcall |
|
801 } |
|
802 |
|
803 void CAvctpTransport::MbpsnConnectComplete() |
|
804 { |
|
805 LOG_FUNC |
|
806 |
|
807 IF_FLOGGING |
|
808 ( |
|
809 TBuf<KBTAddressLength> address; |
|
810 iRemoteAddr.GetReadable(address); |
|
811 ) |
|
812 |
|
813 LOG1(_L("from BT Device 0x%S"), &address); |
|
814 |
|
815 // state machine should be able to resolve the difference in saps completing |
|
816 iState->ConnectComplete(*this); |
|
817 } |
|
818 |
|
819 void CAvctpTransport::MbpsnConnectComplete(CServProviderBase& aSAP) |
|
820 { |
|
821 LOG_FUNC |
|
822 // it is an incoming connection and we don't know the pid. |
|
823 // but that's fine because it will be ignored in the state machine. |
|
824 iState->AddSecondChannel(*this, aSAP); |
|
825 } |
|
826 |
|
827 //only initiate immediate shutdowns so there should be no canclose callback |
|
828 void CAvctpTransport::MbpsnCanClose(MSocketNotify::TDelete /*aDelete*/) |
|
829 { |
|
830 LOG_FUNC |
|
831 Panic(ELowerProtocolSapCanClose); |
|
832 } |
|
833 |
|
834 void CAvctpTransport::MbpsnError(TInt aError, TUint aOperationMask) |
|
835 { |
|
836 LOG_FUNC |
|
837 |
|
838 LOG2(_L("Error %d, OperationMask 0b%b"), aError, aOperationMask); |
|
839 |
|
840 iState->Error(*this, aError, aOperationMask, KAvctpSecondaryChannel); |
|
841 } |
|
842 |
|
843 void CAvctpTransport::MbpsnDisconnect() |
|
844 { |
|
845 LOG_FUNC |
|
846 iState->SecondChannelRemoved(*this); |
|
847 } |
|
848 |
|
849 void CAvctpTransport::SetSecondChannelCtrlNotify(TUint16 aClientId, MSocketNotify& aSecondChannelControlSocket) |
|
850 { |
|
851 LOG_FUNC |
|
852 iProtocol.SetSecondChannelCtrlNotify(aClientId, aSecondChannelControlSocket); |
|
853 } |
|
854 |
|
855 |
|
856 TInt CAvctpTransport::AddPrimaryChannelRef(const TClientItem* item) |
|
857 { |
|
858 LOG_FUNC |
|
859 DequeIdleTimer(); // adding a client reference means not to be idle anymore |
|
860 TUint16 clientId = item->ClientId(); |
|
861 return iClientItems.Insert(clientId, item); |
|
862 } |
|
863 |
|
864 void CAvctpTransport::AddSecondaryChannelRef() |
|
865 { |
|
866 iSecondaryChannelClientRefCount++; |
|
867 } |
|
868 |
|
869 void CAvctpTransport::RemovePrimaryChannelRef(TUint16 aClientId) |
|
870 { |
|
871 LOG_FUNC |
|
872 |
|
873 TClientItem** item = const_cast<TClientItem**>(iClientItems.Find(aClientId)); |
|
874 if (item && *item) |
|
875 { |
|
876 iClientItems.Remove(aClientId); |
|
877 } |
|
878 if (iClientItems.Count() == 0 && IsIdle()) |
|
879 { |
|
880 iProtocol.RemoveTransport(*this); |
|
881 delete this; |
|
882 } |
|
883 } |
|
884 |
|
885 /** |
|
886 This method is called from ReleaseExtendedTransport() and RemoveSap(). |
|
887 When called from RemoveSap (that is called when the sap is shutdown) the secondary channel |
|
888 may or may not exist. If the muxer state is, for example, Open then the secondary channel |
|
889 does not exist. In this case, HasSecondChannel() return false and the method exits. |
|
890 If the muxer is in SecondChannelPending state HasSecondChannel returns true. we can have a |
|
891 situation where |
|
892 */ |
|
893 void CAvctpTransport::RemoveSecondaryChannelRef(TUint16 aClientId) |
|
894 { |
|
895 LOG_FUNC |
|
896 |
|
897 if (HasSecondChannel()) |
|
898 { |
|
899 TClientItem** item = const_cast<TClientItem**>(iClientItems.Find(aClientId)); |
|
900 __ASSERT_DEBUG(item, Panic(EAvctpClientNotFound)); |
|
901 |
|
902 if (iSecondaryChannelClientRefCount > 0) |
|
903 { |
|
904 iSecondaryChannelClientRefCount--; |
|
905 } |
|
906 |
|
907 if (iSecondaryChannelClientRefCount == 0) |
|
908 { |
|
909 RemoveSecondChannel(); |
|
910 } |
|
911 } |
|
912 } |
|
913 |
|
914 TInt CAvctpTransport::ClientCount() |
|
915 { |
|
916 return iClientItems.Count(); |
|
917 } |
|
918 |
|
919 TInt CAvctpTransport::ClientSecondaryChannelCount() |
|
920 { |
|
921 TInt count = 0; |
|
922 TClientItemIter iter(iClientItems); |
|
923 while(iter.NextKey()) |
|
924 { |
|
925 const TClientItem** pitem = iter.CurrentValue(); |
|
926 if ((*pitem)->IsSecondaryChannelAttached()) |
|
927 { |
|
928 count++; |
|
929 } |
|
930 } |
|
931 return count; |
|
932 } |
|
933 |
|
934 TBool CAvctpTransport::HasClient(TUint16 aClientId) |
|
935 { |
|
936 LOG_FUNC |
|
937 return (iClientItems.Find(aClientId) != NULL) ? ETrue : EFalse; |
|
938 } |
|
939 |
|
940 void CAvctpTransport::BindSecondaryChannelSap(CServProviderBase& aSAP) |
|
941 { |
|
942 iChannelSAPs[KAvctpSecondaryChannel] = &aSAP; |
|
943 iChannelSAPs[KAvctpSecondaryChannel]->SetNotify(&iSecondChannelSocket); |
|
944 } |
|
945 |
|
946 //pseudosocket stuff |
|
947 TAvctpSecondChannelPseudoSocket::TAvctpSecondChannelPseudoSocket(MSecondChannelPseudoSocketNotify& aNotify) |
|
948 :iNotify(aNotify) |
|
949 { |
|
950 LOG_FUNC |
|
951 } |
|
952 |
|
953 |
|
954 void TAvctpSecondChannelPseudoSocket::NewData(TUint aCount) |
|
955 { |
|
956 LOG_FUNC |
|
957 iNotify.MbpsnNewData(aCount); |
|
958 } |
|
959 |
|
960 void TAvctpSecondChannelPseudoSocket::CanSend() |
|
961 { |
|
962 LOG_FUNC |
|
963 iNotify.MbpsnCanSend(); |
|
964 } |
|
965 |
|
966 void TAvctpSecondChannelPseudoSocket::ConnectComplete() |
|
967 { |
|
968 LOG_FUNC |
|
969 iNotify.MbpsnConnectComplete(); |
|
970 } |
|
971 |
|
972 void TAvctpSecondChannelPseudoSocket::ConnectComplete(const TDesC8& /*aConnectData*/) |
|
973 { |
|
974 LOG_FUNC |
|
975 /*drop*/ |
|
976 } |
|
977 |
|
978 void TAvctpSecondChannelPseudoSocket::ConnectComplete(CServProviderBase& aSSP) |
|
979 { |
|
980 LOG_FUNC |
|
981 iNotify.MbpsnConnectComplete(aSSP); |
|
982 } |
|
983 |
|
984 void TAvctpSecondChannelPseudoSocket::ConnectComplete(CServProviderBase& /*aSSP*/,const TDesC8& /*aConnectData*/) |
|
985 { |
|
986 LOG_FUNC |
|
987 /*drop*/ |
|
988 } |
|
989 |
|
990 void TAvctpSecondChannelPseudoSocket::CanClose(TDelete aDelete) |
|
991 { |
|
992 LOG_FUNC |
|
993 iNotify.MbpsnCanClose(aDelete); |
|
994 } |
|
995 |
|
996 void TAvctpSecondChannelPseudoSocket::CanClose(const TDesC8& /*aDisconnectData*/,TDelete /*aDelete*/) |
|
997 { |
|
998 LOG_FUNC |
|
999 /*drop*/ |
|
1000 } |
|
1001 |
|
1002 void TAvctpSecondChannelPseudoSocket::Error(TInt aError, TUint aOperationMask) |
|
1003 { |
|
1004 LOG_FUNC |
|
1005 iNotify.MbpsnError(aError, aOperationMask); |
|
1006 } |
|
1007 |
|
1008 void TAvctpSecondChannelPseudoSocket::Disconnect() |
|
1009 { |
|
1010 LOG_FUNC |
|
1011 iNotify.MbpsnDisconnect(); |
|
1012 } |
|
1013 |
|
1014 void TAvctpSecondChannelPseudoSocket::IoctlComplete(TDesC8* /*aBuf*/) |
|
1015 { |
|
1016 LOG_FUNC |
|
1017 } |