|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // BTComm state machine state implementation. |
|
15 // |
|
16 // |
|
17 |
|
18 #include <bluetooth/logger.h> |
|
19 #include <cs_port.h> |
|
20 #include "btcomm.h" |
|
21 #include "btstate.h" |
|
22 #include "btcommactive.h" |
|
23 #include <bt_sock.h> |
|
24 #include "sdpkey.h" |
|
25 #include "sdpclientcsy.h" |
|
26 #include <e32test.h> |
|
27 #include <btmanclient.h> |
|
28 #include "btcommutil.h" |
|
29 |
|
30 #ifdef __FLOG_ACTIVE |
|
31 _LIT8(KLogComponent, LOG_COMPONENT_BT_COMM); |
|
32 #endif |
|
33 |
|
34 #define BAD_BTCOMM_EVENT PanicInState(EBTCommBadEventForThisState); |
|
35 |
|
36 |
|
37 |
|
38 TBTPortState::TBTPortState(CBTPortStateFactory* aParent) |
|
39 : iFactory(aParent) |
|
40 /** |
|
41 TBTPortState c'tor. |
|
42 TBTPortState is the abstract base class that all CSY state |
|
43 objects inherit from. However, it is not a 'C' class but |
|
44 a 'T' class which is slightly bogus but the best way to |
|
45 implement the base state for the pattern. |
|
46 **/ |
|
47 { |
|
48 LOG_FUNC |
|
49 } |
|
50 |
|
51 TBTPortState::~TBTPortState() |
|
52 { |
|
53 LOG_FUNC |
|
54 } |
|
55 |
|
56 /** |
|
57 Calls the appropriate panic function to encode the panic |
|
58 code with the current state identifier. |
|
59 @param aPanic The panic code that the state is panicking with. |
|
60 */ |
|
61 void TBTPortState::PanicInState(TBTCommPanic aPanic) const |
|
62 { |
|
63 LOG_FUNC |
|
64 BTCommUtil::Panic(aPanic, iFactory->StateIndex(this)); |
|
65 } |
|
66 |
|
67 // ***** Default state ***** |
|
68 |
|
69 TBTPortDefaultState::TBTPortDefaultState(CBTPortStateFactory* aParent) |
|
70 : TBTPortState(aParent) |
|
71 { |
|
72 LOG_FUNC |
|
73 } |
|
74 |
|
75 TBTPortDefaultState::~TBTPortDefaultState() |
|
76 { |
|
77 LOG_FUNC |
|
78 } |
|
79 |
|
80 void TBTPortDefaultState::Open(CBTPortProxy* /*aContext*/) |
|
81 { |
|
82 LOG_FUNC |
|
83 BAD_BTCOMM_EVENT |
|
84 } |
|
85 |
|
86 void TBTPortDefaultState::Close(CBTPortProxy* /*aContext*/) |
|
87 { |
|
88 LOG_FUNC |
|
89 BAD_BTCOMM_EVENT |
|
90 } |
|
91 |
|
92 void TBTPortDefaultState::Read(CBTPortProxy* /*aContext*/,TAny* /*aPtr*/,TInt /*aLength*/) |
|
93 /** |
|
94 TBTPortDefaultState Read. |
|
95 **/ |
|
96 { |
|
97 LOG_FUNC |
|
98 BAD_BTCOMM_EVENT |
|
99 } |
|
100 |
|
101 void TBTPortDefaultState::Write(CBTPortProxy* /*aContext*/,TAny* /*aPtr*/,TInt /*aLength*/) |
|
102 /** |
|
103 TBTPortDefaultState Write. |
|
104 **/ |
|
105 { |
|
106 LOG_FUNC |
|
107 BAD_BTCOMM_EVENT |
|
108 } |
|
109 |
|
110 void TBTPortDefaultState::ReadCancel(CBTPortProxy* /*aContext*/) |
|
111 { |
|
112 LOG_FUNC |
|
113 BAD_BTCOMM_EVENT |
|
114 } |
|
115 |
|
116 void TBTPortDefaultState::WriteCancel(CBTPortProxy* /*aContext*/) |
|
117 { |
|
118 LOG_FUNC |
|
119 BAD_BTCOMM_EVENT |
|
120 } |
|
121 |
|
122 void TBTPortDefaultState::DoRunL(CBTPortProxy* /*aContext*/) |
|
123 { |
|
124 LOG_FUNC |
|
125 BAD_BTCOMM_EVENT |
|
126 } |
|
127 |
|
128 void TBTPortDefaultState::DoCancel(CBTPortProxy* /*aContext*/) |
|
129 { |
|
130 LOG_FUNC |
|
131 BAD_BTCOMM_EVENT |
|
132 } |
|
133 |
|
134 void TBTPortDefaultState::DoLockedAction(CBTPortProxy* /*aContext*/) |
|
135 { |
|
136 LOG_FUNC |
|
137 BAD_BTCOMM_EVENT |
|
138 } |
|
139 |
|
140 void TBTPortDefaultState::DoWriteCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
141 { |
|
142 LOG_FUNC |
|
143 BAD_BTCOMM_EVENT |
|
144 } |
|
145 |
|
146 void TBTPortDefaultState::DoReadCompleted(CBTPortProxy* /*aContext*/,TInt aError) |
|
147 { |
|
148 // because we managed to get reopened before destruction |
|
149 // and this event sources from the reader's request completing |
|
150 // after a read cancel was issued from the closing. |
|
151 LOG_FUNC |
|
152 if(aError==KErrCancel) {return;} |
|
153 |
|
154 BAD_BTCOMM_EVENT |
|
155 } |
|
156 |
|
157 |
|
158 void TBTPortDefaultState::Error(CBTPortProxy* aContext,TInt aError) |
|
159 /** |
|
160 This will call each state's error loging and move the CSY to the error state. |
|
161 */ |
|
162 { |
|
163 LOG_FUNC |
|
164 LogStateError(aContext,aError); |
|
165 aContext->iLastError=aError; // record this before we lose context |
|
166 aContext->MoveToErrorState(); |
|
167 } |
|
168 |
|
169 |
|
170 // ****** Common Pre-Connection I/O Base State ***** |
|
171 |
|
172 TBTPortCommonBaseState::TBTPortCommonBaseState(CBTPortStateFactory* aParent) |
|
173 :TBTPortDefaultState(aParent) |
|
174 { |
|
175 LOG_FUNC |
|
176 } |
|
177 |
|
178 void TBTPortCommonBaseState::Read(CBTPortProxy* aContext,TAny* aPtr, TInt aLength) |
|
179 { |
|
180 LOG_FUNC |
|
181 |
|
182 if(aLength) |
|
183 { |
|
184 aContext->iClientReadPtr=aPtr; |
|
185 aContext->iClientReadLength=aLength; |
|
186 aContext->iClientRemainderToRead=aLength; |
|
187 #ifdef _DEBUG |
|
188 aContext->iReadsPending++; |
|
189 #endif |
|
190 } |
|
191 else |
|
192 { |
|
193 //zero length read, complete it immediately |
|
194 aContext->iPort->ReadCompleted(KErrNone); |
|
195 } |
|
196 } |
|
197 |
|
198 void TBTPortCommonBaseState::Write(CBTPortProxy* aContext,TAny* aPtr, TInt aLength) |
|
199 { |
|
200 LOG_FUNC |
|
201 |
|
202 aContext->iClientWritePtr=aPtr; |
|
203 aContext->iClientWriteLength=aLength; |
|
204 aContext->iClientLengthWrittenSoFar=aLength; |
|
205 } |
|
206 |
|
207 void TBTPortCommonBaseState::WriteCancel(CBTPortProxy* aContext) |
|
208 /** |
|
209 Cancel initial Write if there was one or do nothing. |
|
210 */ |
|
211 { |
|
212 LOG_FUNC |
|
213 |
|
214 if(aContext->iClientWritePtr) |
|
215 { |
|
216 aContext->iClientWritePtr=NULL; |
|
217 aContext->iClientWriteLength=0; |
|
218 aContext->iClientLengthWrittenSoFar=0; |
|
219 aContext->iPort->WriteCompleted(KErrCancel); |
|
220 } |
|
221 } |
|
222 |
|
223 void TBTPortCommonBaseState::ReadCancel(CBTPortProxy* aContext) |
|
224 /** |
|
225 Cancel initial Read if there was one or do nothing. |
|
226 */ |
|
227 { |
|
228 LOG_FUNC |
|
229 |
|
230 if(aContext->iClientReadPtr) |
|
231 { |
|
232 aContext->iClientReadPtr=NULL; |
|
233 aContext->iClientReadLength=0; |
|
234 aContext->iClientRemainderToRead=0; |
|
235 #ifdef _DEBUG |
|
236 aContext->iReadsPending--; |
|
237 #endif |
|
238 aContext->iPort->ReadCompleted(KErrCancel); |
|
239 } |
|
240 } |
|
241 |
|
242 void TBTPortCommonBaseState::Close(CBTPortProxy* aContext) |
|
243 { |
|
244 LOG_FUNC |
|
245 |
|
246 aContext->StopReader(); |
|
247 |
|
248 //check to see if we had any client requests cached and cancel them |
|
249 if(aContext->iClientReadPtr) |
|
250 { |
|
251 ReadCancel(aContext); |
|
252 } |
|
253 if(aContext->iClientWritePtr) |
|
254 { |
|
255 WriteCancel(aContext); |
|
256 } |
|
257 |
|
258 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing)); |
|
259 } |
|
260 |
|
261 // ***** Idle state ***** |
|
262 |
|
263 TBTPortStateIdle::TBTPortStateIdle(CBTPortStateFactory* aParent) |
|
264 :TBTPortCommonBaseState(aParent) |
|
265 { |
|
266 LOG_FUNC |
|
267 } |
|
268 |
|
269 TBTPortStateIdle::~TBTPortStateIdle() |
|
270 { |
|
271 LOG_FUNC |
|
272 } |
|
273 |
|
274 void TBTPortStateIdle::Open(CBTPortProxy* aContext) |
|
275 /** |
|
276 This function is the entry point for the BT CSY state machine. |
|
277 The first thing we will do is to pretend we opened a BTCOMM connection. |
|
278 The reason for this is to avoid any deadlock across the C32-ESock-ETel |
|
279 trilogy. |
|
280 **/ |
|
281 { |
|
282 LOG_FUNC |
|
283 aContext->CancelShutDownTimer(); // just in case we were going down before this call |
|
284 } |
|
285 |
|
286 void TBTPortStateIdle::Close(CBTPortProxy* aContext) |
|
287 /** |
|
288 A call to this method will cancel any pending requests. |
|
289 It will also cancel any transition to any other state. |
|
290 */ |
|
291 { |
|
292 LOG_FUNC |
|
293 |
|
294 aContext->Cancel();// any transition |
|
295 |
|
296 //check to see if we had any client requests cached and cancel them |
|
297 ReadCancel(aContext); |
|
298 WriteCancel(aContext); |
|
299 } |
|
300 |
|
301 |
|
302 void TBTPortStateIdle::Read(CBTPortProxy* aContext,TAny* aPtr,TInt aLength) |
|
303 /** |
|
304 Caches the Read() for completion after the connection is setup, starts the protocol and state machine. |
|
305 */ |
|
306 { |
|
307 LOG_FUNC |
|
308 LOG(_L("**TBTPortStateIdle::Read -- Queueing one**")); |
|
309 TBTPortCommonBaseState::Read(aContext,aPtr,aLength); |
|
310 // Connect to ESock |
|
311 SockServConnect(aContext); |
|
312 } |
|
313 |
|
314 void TBTPortStateIdle::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength) |
|
315 /** |
|
316 Caches the Write() for completion after the connection is setup, starts the protocol and state machine. |
|
317 */ |
|
318 { |
|
319 LOG_FUNC |
|
320 LOG(_L("**TBTPortStateIdle::Write -- Queueing one**")); |
|
321 TBTPortCommonBaseState::Write(aContext,aPtr,aLength); |
|
322 // Connect to ESock |
|
323 SockServConnect(aContext); |
|
324 } |
|
325 |
|
326 |
|
327 void TBTPortStateIdle::DoRunL(CBTPortProxy* /*aContext*/) |
|
328 /** |
|
329 Will be called only after we decided to close in the Discovering state. |
|
330 This is a NoOp method. |
|
331 */ |
|
332 { |
|
333 LOG_FUNC |
|
334 } |
|
335 |
|
336 void TBTPortStateIdle::SockServConnect(CBTPortProxy* aContext) |
|
337 /** |
|
338 Makes an asynchronous attempt to connect to ESock and moves to the next state. |
|
339 **/ |
|
340 { |
|
341 LOG_FUNC |
|
342 aContext->iSockServConnector->SockServConnect(aContext->iStatus); |
|
343 |
|
344 // now move to the next state where we pre-load the protocol |
|
345 aContext->SetState(iFactory->GetState(CBTPortStateFactory::ELoadingProtocol)); |
|
346 aContext->SetActive(); |
|
347 } |
|
348 |
|
349 void TBTPortStateIdle::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
350 { |
|
351 LOG_FUNC |
|
352 } |
|
353 |
|
354 // ***** Loading Protocol state ***** |
|
355 |
|
356 TBTPortStateLoadingProtocol::TBTPortStateLoadingProtocol(CBTPortStateFactory* aParent) |
|
357 :TBTPortCommonBaseState(aParent), iClosePending(EFalse) |
|
358 { |
|
359 LOG_FUNC |
|
360 } |
|
361 |
|
362 TBTPortStateLoadingProtocol::~TBTPortStateLoadingProtocol() |
|
363 { |
|
364 LOG_FUNC |
|
365 } |
|
366 |
|
367 void TBTPortStateLoadingProtocol::Read(CBTPortProxy* aContext,TAny* aPtr, TInt aLength) |
|
368 { |
|
369 LOG_FUNC |
|
370 |
|
371 // Cache the read ready for when our connection is up. |
|
372 if(aLength) |
|
373 { |
|
374 aContext->iClientReadPtr=aPtr; |
|
375 aContext->iClientReadLength=aLength; |
|
376 aContext->iClientRemainderToRead=aLength; |
|
377 #ifdef _DEBUG |
|
378 aContext->iReadsPending++; |
|
379 #endif |
|
380 } |
|
381 else |
|
382 { |
|
383 //zero length read, complete it immediately |
|
384 aContext->iPort->ReadCompleted(KErrNone); |
|
385 } |
|
386 |
|
387 // If we were planning on closing this reopens us - we've cached the read as |
|
388 // normal, just unset the close pending flag and we can carry on setting up |
|
389 // the connection as normal. |
|
390 if(!iClosePending) |
|
391 { |
|
392 iClosePending = EFalse; |
|
393 } |
|
394 } |
|
395 |
|
396 void TBTPortStateLoadingProtocol::Write(CBTPortProxy* aContext,TAny* aPtr, TInt aLength) |
|
397 { |
|
398 LOG_FUNC |
|
399 |
|
400 // Cache the write ready for when our connection is up. |
|
401 aContext->iClientWritePtr=aPtr; |
|
402 aContext->iClientWriteLength=aLength; |
|
403 aContext->iClientLengthWrittenSoFar=aLength; |
|
404 |
|
405 // If we were planning on closing this reopens us - we've cached the write as |
|
406 // normal, just unset the close pending flag and we can carry on setting up |
|
407 // the connection as normal. |
|
408 if(iClosePending) |
|
409 { |
|
410 iClosePending = EFalse; |
|
411 } |
|
412 } |
|
413 |
|
414 void TBTPortStateLoadingProtocol::Close(CBTPortProxy* aContext) |
|
415 /** |
|
416 A call to this method will cancel any pending requests. |
|
417 It will also cancel any transition to any other state. |
|
418 */ |
|
419 { |
|
420 LOG_FUNC |
|
421 |
|
422 // If we're in this state our connection attempt on ESock hasn't |
|
423 // completed yet. We can't transition to the closing state yet |
|
424 // because we don't have the handle for our ESock session which |
|
425 // we need to close. When the connection request completes we'll |
|
426 // do the transition, unless there's a Read or Write before then, |
|
427 // when we'll allow the connection set up to continue. |
|
428 |
|
429 //check to see if we had any client requests cached and cancel them |
|
430 ReadCancel(aContext); |
|
431 WriteCancel(aContext); |
|
432 |
|
433 // Set the flag so we know where to go when the Esock connect has |
|
434 // completed |
|
435 iClosePending = ETrue; |
|
436 } |
|
437 |
|
438 void TBTPortStateLoadingProtocol::DoRunL(CBTPortProxy* aContext) |
|
439 /** |
|
440 Will be called only after we decided to close in the Discovering state. |
|
441 This is a NoOp method. |
|
442 */ |
|
443 { |
|
444 LOG_FUNC |
|
445 |
|
446 if (aContext->iStatus != KErrNone) |
|
447 { |
|
448 Error(aContext, aContext->iStatus.Int()); // couldn't connect to esock |
|
449 return; |
|
450 } |
|
451 |
|
452 // If we're waiting for the ESock handle to allow us to close, transition |
|
453 // to the closing state now, otherwise continue connection set up. |
|
454 if(iClosePending) |
|
455 { |
|
456 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing)); |
|
457 aContext->SetActive(); |
|
458 TRequestStatus* pStatus = &(aContext->iStatus); |
|
459 User::RequestComplete(pStatus, KErrNone); |
|
460 |
|
461 // Reset this incase we come back through the state machine later |
|
462 iClosePending = EFalse; |
|
463 } |
|
464 else |
|
465 { |
|
466 StartProtocol(aContext); |
|
467 } |
|
468 } |
|
469 |
|
470 void TBTPortStateLoadingProtocol::StartProtocol(CBTPortProxy* aContext) |
|
471 /** |
|
472 Makes an asynchronous attempt to invoke RSocketServ::StartProtocol() and moves to the next state. |
|
473 **/ |
|
474 { |
|
475 LOG_FUNC |
|
476 // now async load Bluetooth RFComm protocol to stop comm port open thread lock. |
|
477 RSocketServ &sockServ = aContext->iSockServ; |
|
478 LOG1(_L("TBTPortStateLoadingProtocol::Start L2CAP Protocol OK, iSockServ=0x%x"),sockServ.Handle()); |
|
479 sockServ.StartProtocol(KBTAddrFamily,KSockSeqPacket,KL2CAP,aContext->iStatus); |
|
480 // now move to the next state were the results will be handled |
|
481 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EDiscovering)); |
|
482 aContext->SetActive(); |
|
483 } |
|
484 |
|
485 void TBTPortStateLoadingProtocol::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
486 { |
|
487 LOG_FUNC |
|
488 } |
|
489 |
|
490 // ***** Discovering state ***** |
|
491 |
|
492 TBTPortStateDiscovering::TBTPortStateDiscovering(CBTPortStateFactory* aParent) |
|
493 : TBTPortCommonBaseState(aParent) |
|
494 { |
|
495 LOG_FUNC |
|
496 } |
|
497 |
|
498 TBTPortStateDiscovering::~TBTPortStateDiscovering() |
|
499 { |
|
500 LOG_FUNC |
|
501 } |
|
502 |
|
503 |
|
504 void TBTPortStateDiscovering::DoRunL(CBTPortProxy* aContext) |
|
505 /** |
|
506 Find-out the port's corresponding device and settings. |
|
507 This is done by looking at the registry default settings for this |
|
508 BTComm port. |
|
509 **/ |
|
510 { |
|
511 LOG_FUNC |
|
512 TInt ret=aContext->iStatus.Int(); |
|
513 if (ret!=KErrNone) |
|
514 {// could not start Bluetooth protocol |
|
515 // must error here so that the user notices this |
|
516 Error(aContext,ret); |
|
517 LOG(_L(" Could not load Bluetooth protocol !")); |
|
518 // do tidy up here |
|
519 return; |
|
520 } |
|
521 else |
|
522 {// we have successfully started Bluetooth, lets discover the settings for this port |
|
523 aContext->iDefaultService.SetPort(aContext->iPortNo); |
|
524 ret=aContext->iPortSettings.Get(aContext->iDefaultService); |
|
525 |
|
526 if(ret!=KErrNone) |
|
527 { |
|
528 LOG(_L(" Could not find default device !")); |
|
529 Error(aContext,ret); |
|
530 return; |
|
531 } |
|
532 aContext->iBdaddr=aContext->iDefaultService.BDAddr(); |
|
533 |
|
534 // In the context of RFCOMM, at this stage, we would be looking |
|
535 // to do an SDP service search query on the remote RFCOMM service |
|
536 // which means opening an SDP sap first which is a synchronous |
|
537 // action so has to be done as a locked action. |
|
538 aContext->StartLocker(); |
|
539 } |
|
540 } |
|
541 |
|
542 void TBTPortStateDiscovering::DoLockedAction(CBTPortProxy* aContext) |
|
543 /** |
|
544 Do an SDP query for the remote service port number as a synchronous (locked) action. |
|
545 At this point we have locked the session. We now need to open |
|
546 our NetDB and then follow that with our async state change action |
|
547 which is an SDP query. |
|
548 **/ |
|
549 { |
|
550 LOG_FUNC |
|
551 // need to open the netdb, fire off an async SDP Connect Query |
|
552 // and then do the state transition. |
|
553 RNetDatabase& netdb=aContext->iNetDatabase; |
|
554 RSocketServ ss=aContext->iSockServ; |
|
555 // note this needs to be a reference. |
|
556 TInt ret=netdb.Open(ss,KBTAddrFamily,KSDP); |
|
557 // sync action completed ok - now stop locker. |
|
558 aContext->StopLocker(); |
|
559 if (ret!=KErrNone) |
|
560 { |
|
561 Error(aContext,ret); |
|
562 return; |
|
563 } |
|
564 |
|
565 // if NetDB was opened ok make a note of it for cleanup on closing state |
|
566 aContext->SetNetDbInUse(); |
|
567 |
|
568 // now queue async action and move into next state |
|
569 // which is an SDP connect query on remote RFCOMM service. |
|
570 TSDPConnectQuery connQ; |
|
571 connQ.iQueryType = KSDPConnectQuery; |
|
572 connQ.iAddr = aContext->iBdaddr; |
|
573 aContext->iSDPRequest.Copy(TSDPConnectBuf(connQ)); |
|
574 aContext->iSDPResult.SetMax(); |
|
575 netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus); |
|
576 aContext->SetActive(); |
|
577 aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPConnected)); |
|
578 } |
|
579 |
|
580 void TBTPortStateDiscovering::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
581 /** |
|
582 TBTPortStateDiscovering Error. |
|
583 Reaching this error means that we haven't found a device. |
|
584 **/ |
|
585 { |
|
586 LOG_FUNC |
|
587 } |
|
588 |
|
589 // ***** SDP Connected state ***** |
|
590 |
|
591 TBTPortStateSDPConnected::TBTPortStateSDPConnected(CBTPortStateFactory* aParent) |
|
592 : TBTPortCommonBaseState(aParent) |
|
593 { |
|
594 LOG_FUNC |
|
595 } |
|
596 |
|
597 TBTPortStateSDPConnected::~TBTPortStateSDPConnected() |
|
598 { |
|
599 LOG_FUNC |
|
600 } |
|
601 |
|
602 void TBTPortStateSDPConnected::DoRunL(CBTPortProxy* aContext) |
|
603 /** |
|
604 Entry at this call signals that the SDP connection query has completed. |
|
605 We now need to check the remote port number to connect to before |
|
606 invoking the locker to handle the opening of the port proxy's socket. |
|
607 **/ |
|
608 { |
|
609 LOG_FUNC |
|
610 TInt ret=aContext->iStatus.Int(); |
|
611 if (ret!=KErrNone) |
|
612 {// didn't manage to succeed with SDP Connect query. |
|
613 Error(aContext,ret); |
|
614 LOG(_L("CSY: Could not connect to remote SDP server !")); |
|
615 return; |
|
616 } |
|
617 // we have successfully found the remote SDP server. |
|
618 RNetDatabase& netdb=aContext->iNetDatabase; |
|
619 |
|
620 // here we create the SDP service search query. |
|
621 TSDPServiceSearchKey key; |
|
622 key.iQueryType = KSDPServiceQuery; |
|
623 key.iMaxCount = 20; |
|
624 key.iUUID = aContext->iDefaultService.UUID(); |
|
625 |
|
626 key.iStateLength = 0; |
|
627 |
|
628 aContext->iSDPRequest.Copy(TSDPServiceSearchKeyBuf(key)); |
|
629 aContext->iSDPServRecordHandle.SetMax(); |
|
630 netdb.Query(aContext->iSDPRequest,aContext->iSDPServRecordHandle,aContext->iStatus); |
|
631 aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPServiceQuery)); |
|
632 aContext->SetActive(); |
|
633 } |
|
634 |
|
635 void TBTPortStateSDPConnected::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
636 /** |
|
637 Reaching this error means that we haven't found a remote device |
|
638 with the right service level on it. ie. the SDP/IAS query failed. |
|
639 **/ |
|
640 { |
|
641 LOG_FUNC |
|
642 } |
|
643 |
|
644 |
|
645 // ***** SDP Service Retrieved State ***** |
|
646 |
|
647 TBTPortStateSDPServiceQuery::TBTPortStateSDPServiceQuery(CBTPortStateFactory* aParent) |
|
648 : TBTPortCommonBaseState(aParent) |
|
649 { |
|
650 LOG_FUNC |
|
651 } |
|
652 |
|
653 TBTPortStateSDPServiceQuery::~TBTPortStateSDPServiceQuery() |
|
654 { |
|
655 LOG_FUNC |
|
656 } |
|
657 |
|
658 void TBTPortStateSDPServiceQuery::DoRunL(CBTPortProxy* aContext) |
|
659 { |
|
660 LOG_FUNC |
|
661 // we have completed the SDP service search query |
|
662 // get number of record handles in this response |
|
663 TInt ret=aContext->iStatus.Int(); |
|
664 |
|
665 if (ret!=KErrNone) |
|
666 {// could not start Bluetooth protocol |
|
667 // must error here so that the user notices this |
|
668 Error(aContext,ret); |
|
669 LOG(_L("SDPService query - error.")); |
|
670 // do tidy up here |
|
671 return; |
|
672 } |
|
673 else |
|
674 { |
|
675 |
|
676 iFactory->iSDPServRecordHandleCount=BigEndian::Get16(&aContext->iSDPServRecordHandle[2]); |
|
677 if (!iFactory->iSDPServRecordHandleCount) |
|
678 {// this is an error - found no matching service records. |
|
679 Error(aContext,KErrNotFound); |
|
680 return; |
|
681 } |
|
682 if (iFactory->iSDPServRecordHandleCount*4 > aContext->iSDPServRecordHandle.Length() - 5) |
|
683 {// this is a check on the length of the response. |
|
684 Error(aContext,KErrUnknown); |
|
685 LOG2(_L("Bad length field %d on results length %d"), |
|
686 iFactory->iSDPServRecordHandleCount*4,aContext->iSDPServRecordHandle.Length()); |
|
687 return; |
|
688 } |
|
689 |
|
690 LOG(_L("\nFound Service records for UUID 0x03\n")); //add the number of records found |
|
691 |
|
692 //now retrieve the ServiceClassIDList from the first ServiceRecordHandle |
|
693 RNetDatabase& netdb=aContext->iNetDatabase; |
|
694 |
|
695 TSDPAttributeKey key; |
|
696 key.iQueryType = KSDPAttributeQuery; |
|
697 // suck out the first service record handle. |
|
698 iFactory->iExtractedHandleCount = 1; |
|
699 key.iServiceRecordHandle = BigEndian::Get32(&aContext->iSDPServRecordHandle[4]); |
|
700 key.iMaxLength = 200; |
|
701 key.iRange = EFalse; |
|
702 key.iAttribute = KSdpAttrIdServiceClassIDList; |
|
703 key.iStateLength = 0; |
|
704 aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key)); |
|
705 aContext->iSDPResult.SetMax(); |
|
706 // Now go away and do the SDP attribute request query |
|
707 netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus); |
|
708 aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPServiceIDListRetrieved)); |
|
709 aContext->SetActive(); |
|
710 } |
|
711 } |
|
712 |
|
713 void TBTPortStateSDPServiceQuery::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
714 /** |
|
715 Reaching this error means that we haven't found a remote device |
|
716 with the right service level on it. ie. the SDP query failed. |
|
717 **/ |
|
718 { |
|
719 LOG_FUNC |
|
720 } |
|
721 |
|
722 |
|
723 |
|
724 // ***** SDP Service ID List Retrieved State ***** |
|
725 |
|
726 TBTPortStateServiceIDListRetrieved::TBTPortStateServiceIDListRetrieved(CBTPortStateFactory* aParent) |
|
727 : TBTPortCommonBaseState(aParent) |
|
728 { |
|
729 LOG_FUNC |
|
730 } |
|
731 |
|
732 |
|
733 TBTPortStateServiceIDListRetrieved::~TBTPortStateServiceIDListRetrieved() |
|
734 { |
|
735 LOG_FUNC |
|
736 } |
|
737 |
|
738 void TBTPortStateServiceIDListRetrieved::DoRunL(CBTPortProxy* aContext) |
|
739 { |
|
740 LOG_FUNC |
|
741 |
|
742 TInt ret=aContext->iStatus.Int(); |
|
743 if (ret!=KErrNone) |
|
744 {// could not start Bluetooth protocol |
|
745 // must error here so that the user notices this |
|
746 Error(aContext,ret); |
|
747 LOG(_L("Service ID List error.")); |
|
748 // do tidy up here |
|
749 return; |
|
750 } |
|
751 else |
|
752 { |
|
753 RNetDatabase& netdb=aContext->iNetDatabase; |
|
754 |
|
755 const TInt KRspAttributeCountSize = 2; |
|
756 const TInt KContStateHeader = 1; |
|
757 |
|
758 LOG(_L("Successful Attribute query!!\r\nHere's the result....\n")); |
|
759 FTRACE(FHex(aContext->iSDPResult)); |
|
760 |
|
761 if (aContext->iSDPResult.Length() < KRspAttributeCountSize+KContStateHeader) |
|
762 { |
|
763 Error(aContext,KErrNotSupported); |
|
764 LOG1(_L("Result is far too short at %d bytes\r\n"),aContext->iSDPResult.Length()); |
|
765 return; |
|
766 } |
|
767 // suck out the byte count |
|
768 TUint16 bytecount=BigEndian::Get16(&aContext->iSDPResult[0]); |
|
769 if (aContext->iSDPResult.Length() < KRspAttributeCountSize+bytecount+KContStateHeader) |
|
770 { |
|
771 Error(aContext,KErrNotSupported); |
|
772 return; |
|
773 } |
|
774 if (aContext->iSDPResult[KRspAttributeCountSize+bytecount]!=0) |
|
775 {// continuation state to deal with |
|
776 // fixme - do something here! |
|
777 Error(aContext,KErrNotSupported); |
|
778 LOG(_L("Continuation state to deal with in SDP attr query response!!\r\n")); |
|
779 return; |
|
780 } |
|
781 |
|
782 //check for the expected UUID in the ServiceIDList |
|
783 |
|
784 CRFCommClass* builder=CRFCommClass::NewL(aContext->iDefaultService.UUID()); |
|
785 CleanupStack::PushL(builder); |
|
786 CElementParser* parser = CElementParser::NewL(builder); |
|
787 CleanupStack::PushL(parser); |
|
788 //Parsing simple attribute list |
|
789 TRAPD(err, parser->ParseElementsL(aContext->iSDPResult.Mid(KRspAttributeCountSize,bytecount))); |
|
790 if (err) |
|
791 { |
|
792 LOG1(_L("Parser left with error %d\n"),err); |
|
793 Error(aContext,err); |
|
794 return; |
|
795 } |
|
796 |
|
797 TBool getProtocolDesc = builder->InService(); |
|
798 CleanupStack::PopAndDestroy(2); |
|
799 |
|
800 TSDPAttributeKey key; |
|
801 key.iMaxLength = 200; |
|
802 key.iRange = EFalse; |
|
803 key.iStateLength = 0; |
|
804 key.iQueryType = KSDPAttributeQuery; |
|
805 |
|
806 aContext->iSDPResult.Zero(); |
|
807 aContext->iSDPResult.SetMax(); |
|
808 |
|
809 if (getProtocolDesc) |
|
810 { |
|
811 LOG(_L("**UUID found in ServiceClassIDList, moving on to getting Protocol Desc **")); |
|
812 |
|
813 |
|
814 // suck out the next service record handle. |
|
815 //if there are still some Handles left |
|
816 key.iServiceRecordHandle = BigEndian::Get32(&aContext-> |
|
817 iSDPServRecordHandle[4*iFactory->iExtractedHandleCount]); //this handle |
|
818 key.iAttribute = KSdpAttrIdProtocolDescriptorList; |
|
819 aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key)); |
|
820 // Now go away and do the SDP attribute request query |
|
821 // i.e search for the first service record, to find what protocols are supported |
|
822 netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus); |
|
823 aContext->SetState(iFactory->GetState(CBTPortStateFactory::ESDPAttribListRetrieved)); |
|
824 aContext->SetActive(); |
|
825 } |
|
826 else if ( iFactory->iExtractedHandleCount < (iFactory->iSDPServRecordHandleCount) ) |
|
827 { |
|
828 LOG(_L("**UUID not found in ServiceClassIDList, inquire of next ServiceRecordHandle **")); |
|
829 |
|
830 // suck out the next service record handle. |
|
831 //if there are still some Handles left |
|
832 iFactory->iExtractedHandleCount++; |
|
833 key.iServiceRecordHandle = BigEndian::Get32(&aContext-> |
|
834 iSDPServRecordHandle[4*iFactory->iExtractedHandleCount]); //next handle |
|
835 key.iAttribute = KSdpAttrIdServiceClassIDList; |
|
836 aContext->iSDPRequest.Copy(TSDPAttributeKeyBuf(key)); |
|
837 // Now go away and do the SDP attribute request query |
|
838 netdb.Query(aContext->iSDPRequest,aContext->iSDPResult,aContext->iStatus); |
|
839 //state is remaining unchanged so no need to call aContext->SetState() |
|
840 aContext->SetActive(); |
|
841 |
|
842 } |
|
843 else //UUID has not been found & there are no more ServiceRecordHandles |
|
844 { |
|
845 LOG(_L("**UUID not found and no ServiceRecordHandles left **")); |
|
846 Error(aContext,KErrNotFound); |
|
847 } |
|
848 } |
|
849 } |
|
850 |
|
851 |
|
852 void TBTPortStateServiceIDListRetrieved::LogStateError(CBTPortProxy* /*aContext*/, TInt /*aError*/) |
|
853 { |
|
854 LOG_FUNC |
|
855 } |
|
856 |
|
857 |
|
858 // ***** SDP Attribute List Retrieved State ***** |
|
859 |
|
860 TBTPortStateSDPAttributeListRetrieved::TBTPortStateSDPAttributeListRetrieved(CBTPortStateFactory* aParent) |
|
861 : TBTPortCommonBaseState(aParent) |
|
862 { |
|
863 LOG_FUNC |
|
864 } |
|
865 |
|
866 TBTPortStateSDPAttributeListRetrieved::~TBTPortStateSDPAttributeListRetrieved() |
|
867 { |
|
868 LOG_FUNC |
|
869 } |
|
870 |
|
871 |
|
872 void TBTPortStateSDPAttributeListRetrieved::DoRunL(CBTPortProxy* aContext) |
|
873 /** |
|
874 The SDP attribute request query completed and here we parse the results. |
|
875 */ |
|
876 { |
|
877 LOG_FUNC |
|
878 TInt ret=aContext->iStatus.Int(); |
|
879 if (ret!=KErrNone) |
|
880 {// could not start Bluetooth protocol |
|
881 // must error here so that the user notices this |
|
882 Error(aContext,ret); |
|
883 LOG(_L("AttributeListRetrieved - error.")); |
|
884 // do tidy up here |
|
885 return; |
|
886 } |
|
887 else |
|
888 { |
|
889 const TInt KContStateHeader = 1; |
|
890 const TInt KRspAttributeCountSize = 2; |
|
891 |
|
892 if (aContext->iSDPResult.Length() < KRspAttributeCountSize+KContStateHeader) |
|
893 { |
|
894 Error(aContext,KErrNotSupported); |
|
895 LOG1(_L("Result is far too short at %d bytes\r\n"),aContext->iSDPResult.Length()); |
|
896 return; |
|
897 } |
|
898 // suck out the byte count |
|
899 TUint16 bytecount=BigEndian::Get16(&aContext->iSDPResult[0]); |
|
900 if (aContext->iSDPResult.Length() < KRspAttributeCountSize+bytecount+KContStateHeader) |
|
901 { |
|
902 Error(aContext,KErrNotSupported); |
|
903 return; |
|
904 } |
|
905 if (aContext->iSDPResult[KRspAttributeCountSize+bytecount]!=0) |
|
906 {// continuation state to deal with |
|
907 // fixme - do something here! |
|
908 Error(aContext,KErrNotSupported); |
|
909 LOG(_L("Continuation state to deal with in SDP attr query response!!\r\n")); |
|
910 return; |
|
911 } |
|
912 LOG(_L("Successful Attribute query!!\r\nHere's the result....\n")); |
|
913 FTRACE(FHex(aContext->iSDPResult)); |
|
914 |
|
915 // Parse the attribute list |
|
916 |
|
917 CRFCommAttribs* builder=CRFCommAttribs::NewL(NULL); |
|
918 CleanupStack::PushL(builder); |
|
919 CElementParser* parser = CElementParser::NewL(builder); |
|
920 CleanupStack::PushL(parser); |
|
921 //Parsing simple attribute list |
|
922 TUint rem=0; |
|
923 |
|
924 TRAPD(err,rem=parser->ParseElementsL(aContext->iSDPResult.Mid(KRspAttributeCountSize,bytecount))); |
|
925 if (err) |
|
926 { |
|
927 LOG1(_L("Parser left with error %d\n"),err); |
|
928 Error(aContext,err); |
|
929 // cleanup since the leave/error does not get propagated and we return. |
|
930 CleanupStack::PopAndDestroy(2); |
|
931 return; |
|
932 } |
|
933 else |
|
934 { |
|
935 LOG1(_L("Parser returned %d\n"),rem); |
|
936 } |
|
937 |
|
938 (void)(rem != KMaxTUint); // keep the compiler happy by taking rem as an r-value in urel |
|
939 |
|
940 // get the remote rfcomm port number to connect to. |
|
941 |
|
942 err = builder->GetRFCommPort(aContext->iRemoteRfcommPortNumber); // channel number |
|
943 if (err != KErrNone) |
|
944 { |
|
945 LOG1(_L("Error %d determining RFCOMM server channel\n"), err); |
|
946 Error(aContext,err); |
|
947 } |
|
948 |
|
949 CleanupStack::PopAndDestroy(2); // getting rid of parser and builder. |
|
950 |
|
951 // do an RFCOMM connect on the remote RFCOMM port |
|
952 // which means opening the socket first which is a synchronous |
|
953 // action so has to be done as a locked action. |
|
954 aContext->StartLocker(); |
|
955 } |
|
956 } |
|
957 |
|
958 void TBTPortStateSDPAttributeListRetrieved::DoLockedAction(CBTPortProxy* aContext) |
|
959 /** |
|
960 Get a locked connection to the Socket server/RFComm and attempt a connection to the remote RFComm port. |
|
961 **/ |
|
962 { |
|
963 LOG_FUNC |
|
964 |
|
965 TPckgBuf<TUint8> aSig; |
|
966 RSocket& sock=aContext->iSocket; |
|
967 RSocketServ ss=aContext->iSockServ; |
|
968 // note this needs to be a reference. |
|
969 TInt ret=sock.Open(ss,KBTAddrFamily,KSockStream,KRFCOMM); |
|
970 if (ret!=KErrNone) |
|
971 { |
|
972 Error(aContext,ret); |
|
973 LOG(_L("**TBTPortStateSDPAttributeListRetrieved could NOT open RFComm socket connection **")); |
|
974 return; |
|
975 } |
|
976 aSig = KModemSignalDV; // KModemSignalRTC and KModemSignalRTR have been turned off |
|
977 sock.SetOpt(KRFCOMMErrOnMSC, KSolBtRFCOMM, aSig); |
|
978 // sync action completed ok - now stop locker. |
|
979 aContext->StopLocker(); |
|
980 // now queue async action and move into next state |
|
981 // which is an RFComm connect on remote port. |
|
982 aContext->iAddr.SetBTAddr(aContext->iBdaddr); |
|
983 aContext->iAddr.SetPort(aContext->iRemoteRfcommPortNumber); |
|
984 |
|
985 TBTServiceSecurity security; |
|
986 security.SetAuthentication(aContext->iDefaultService.IsSecuritySet()); // note: does this need to be updated to be SSP aware? |
|
987 |
|
988 TBool doEncrypt = aContext->iDefaultService.IsEncryptionSet(); |
|
989 security.SetEncryption(doEncrypt); |
|
990 |
|
991 aContext->iAddr.SetSecurity(security); |
|
992 |
|
993 sock.Connect(aContext->iAddr, aContext->iStatus); |
|
994 aContext->SetActive(); |
|
995 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EConnecting)); |
|
996 } |
|
997 |
|
998 |
|
999 void TBTPortStateSDPAttributeListRetrieved::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
1000 /** |
|
1001 Signals a problem with the retrieval of the remote SDP attribute List. |
|
1002 **/ |
|
1003 { |
|
1004 LOG_FUNC |
|
1005 } |
|
1006 |
|
1007 |
|
1008 // ***** Connecting state ***** |
|
1009 |
|
1010 TBTPortStateConnecting::TBTPortStateConnecting(CBTPortStateFactory* aParent) |
|
1011 : TBTPortCommonBaseState(aParent) |
|
1012 { |
|
1013 LOG_FUNC |
|
1014 } |
|
1015 |
|
1016 TBTPortStateConnecting::~TBTPortStateConnecting() |
|
1017 { |
|
1018 LOG_FUNC |
|
1019 } |
|
1020 |
|
1021 void TBTPortStateConnecting::DoRunL(CBTPortProxy* aContext) |
|
1022 /** |
|
1023 At this point we have finally got our connection response. |
|
1024 If successful then we are in the open state and can begin |
|
1025 to freely handle reads and writes. The only state transition |
|
1026 that can take us away from the open state is a close. |
|
1027 **/ |
|
1028 { |
|
1029 LOG_FUNC |
|
1030 TInt ret=aContext->iStatus.Int(); |
|
1031 if (ret!=KErrNone) |
|
1032 {// didn't manage to succeed with connect. |
|
1033 Error(aContext,ret); |
|
1034 LOG(_L("Didn't manage to succeed with connect")); |
|
1035 return; |
|
1036 } |
|
1037 else |
|
1038 {// we have successfully connected!!!! |
|
1039 // so we can transition to the open state. |
|
1040 // first we check if we have any queued writes |
|
1041 // to do and we also queue a read. |
|
1042 if (aContext->iClientWritePtr) |
|
1043 { |
|
1044 if (aContext->iClientWriteLength>KBTCOMMSendBufferLength) |
|
1045 { |
|
1046 aContext->iClientLengthWrittenSoFar=KBTCOMMSendBufferLength; |
|
1047 aContext->iMoreSendsToCome=ETrue; |
|
1048 } |
|
1049 //else see TBTPortStateConnecting::Write(..) |
|
1050 |
|
1051 TPtr8& sendptr=aContext->iSendBufPtr; |
|
1052 sendptr.SetLength(0); |
|
1053 TPtr8 ptr((TUint8*)sendptr.Ptr(),0,aContext->iClientLengthWrittenSoFar); |
|
1054 if(aContext->iClientLengthWrittenSoFar>0) |
|
1055 { // to avoid panicing on zero length write to from client |
|
1056 aContext->iPort->IPCRead(aContext->iClientWritePtr,ptr,0); |
|
1057 } |
|
1058 sendptr.Append(ptr); |
|
1059 aContext->iSendBufPtr.SetLength(aContext->iClientLengthWrittenSoFar); |
|
1060 aContext->StartWriter(); |
|
1061 } |
|
1062 |
|
1063 if((aContext->iClientReadLength==0)&&(aContext->iClientReadPtr)) |
|
1064 {// someone asked for a zero length read |
|
1065 aContext->iPort->ReadCompleted(KErrNone); |
|
1066 } |
|
1067 aContext->StartReader(); |
|
1068 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EOpen)); |
|
1069 } |
|
1070 } |
|
1071 |
|
1072 void TBTPortStateConnecting::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
1073 /** |
|
1074 TBTPortStateConnecting Error. |
|
1075 At this point our RFComm connect has failed for some reason. |
|
1076 **/ |
|
1077 { |
|
1078 LOG_FUNC |
|
1079 } |
|
1080 |
|
1081 // ***** Open state ***** |
|
1082 |
|
1083 TBTPortStateOpen::TBTPortStateOpen(CBTPortStateFactory* aParent) |
|
1084 : TBTPortCommonBaseState(aParent) |
|
1085 { |
|
1086 LOG_FUNC |
|
1087 } |
|
1088 |
|
1089 TBTPortStateOpen::~TBTPortStateOpen() |
|
1090 { |
|
1091 LOG_FUNC |
|
1092 } |
|
1093 |
|
1094 void TBTPortStateOpen::Close(CBTPortProxy* aContext) |
|
1095 /** |
|
1096 TBTPortStateOpen Close. |
|
1097 This function is called when the user has invoked a Close on |
|
1098 the CSY session. |
|
1099 It will stop the reader and begin the shutdown and close of the socket |
|
1100 session. |
|
1101 **/ |
|
1102 { |
|
1103 LOG_FUNC |
|
1104 |
|
1105 aContext->StopReader(); |
|
1106 |
|
1107 // the close() call is a direct call to C32 from the client (in ESock probably) |
|
1108 // thus can pre-empt both DoLockedAction() and DoRunL(). Consequently |
|
1109 // if someone issued a WriteCancel(), just before the call |
|
1110 // this needs to be serviced within a DoLockedAction. But since Shutdown |
|
1111 // starts here, this will not be needed. Therefore we will NOT stop the locker |
|
1112 // here and will check wether a cancel is pending in the Closing state's |
|
1113 // DoLockedAction(). |
|
1114 |
|
1115 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing)); |
|
1116 aContext->SetActive(); |
|
1117 TRequestStatus* pStatus = &(aContext->iStatus); |
|
1118 User::RequestComplete(pStatus, KErrNone); |
|
1119 } |
|
1120 |
|
1121 void TBTPortStateOpen::Read(CBTPortProxy* aContext,TAny* aPtr,TInt aLength) |
|
1122 /** |
|
1123 The client side has requested that a read call be completed. |
|
1124 Moreover if the reader (for the socket reads) was stoped it |
|
1125 will be restarted from here if the low watermark for the CBTPortProxy |
|
1126 read-in circular buffer was reached. |
|
1127 **/ |
|
1128 { |
|
1129 LOG_FUNC |
|
1130 #ifdef _DEBUG |
|
1131 aContext->iReadsPending++; |
|
1132 #endif |
|
1133 |
|
1134 aContext->iClientReadPtr=aPtr; |
|
1135 aContext->iClientReadLength=aLength; |
|
1136 aContext->iClientRemainderToRead=aLength; |
|
1137 aContext->iClientWriteOffset=0; // to indicate the offset in the buf |
|
1138 // for the first write back to client |
|
1139 if(aLength) |
|
1140 { |
|
1141 // need to check if there's anything in the circular buffer. |
|
1142 HandleIPCWriteToClient(aContext); |
|
1143 } |
|
1144 else |
|
1145 { |
|
1146 aContext->iPort->ReadCompleted(KErrNone); |
|
1147 } |
|
1148 // unfortunately the state has to decide whether the reader should be |
|
1149 // kicked into action again or not, because there are states like the |
|
1150 // Idle one where this is irrelevant. |
|
1151 if(aContext->ReadInBufferLowWatermarkReached()) |
|
1152 { |
|
1153 // and the reader was previously stoped |
|
1154 if(!aContext->iPortReader->IsReading()) |
|
1155 { |
|
1156 aContext->StartReader(); |
|
1157 } |
|
1158 } |
|
1159 } |
|
1160 |
|
1161 void TBTPortStateOpen::DoReadCompleted(CBTPortProxy* aContext,TInt aError) |
|
1162 /** |
|
1163 New data arrived from the socket to C32 |
|
1164 This method is called by the CBTportProxy when new data arrive |
|
1165 from the socket. |
|
1166 |
|
1167 This function first needs to see if there's anything that needs to |
|
1168 be written client side. HandleIPCWriteToClient() does the actual |
|
1169 work of invoking the c32 IPCWrite. |
|
1170 |
|
1171 Then it checks to see if more reads to the socket should be queued or |
|
1172 whether the CBTPortProxy read-in buffer is filling up. |
|
1173 **/ |
|
1174 { |
|
1175 LOG_FUNC |
|
1176 #ifdef _DEBUG |
|
1177 aContext->iReadsPending--; |
|
1178 #endif |
|
1179 |
|
1180 if ((aError!=KErrNone)&&(aError!=KErrCancel)) |
|
1181 {// we need to break out of here without requeueing the reader. |
|
1182 aContext->iPort->ReadCompleted(aError); |
|
1183 return; |
|
1184 } |
|
1185 if (aContext->iClientReadPtr) |
|
1186 {// we have a read queued - |
|
1187 // need to see if we can do IPCWrite client side |
|
1188 HandleIPCWriteToClient(aContext); |
|
1189 } |
|
1190 |
|
1191 // check to see if we've reached or surpased our watermark |
|
1192 if(aContext->ReadInBufferHighWatermarkReached()) |
|
1193 { |
|
1194 aContext->StopReader(); |
|
1195 return; |
|
1196 } |
|
1197 // else |
|
1198 aContext->StartReader(); |
|
1199 |
|
1200 } |
|
1201 |
|
1202 void TBTPortStateOpen::HandleIPCWriteToClient(CBTPortProxy* aContext) |
|
1203 /** |
|
1204 This function works out how much of the circular buffer to write back to the client. |
|
1205 The c32 ReadCompleted() function is only invoked when the complete read has been done. |
|
1206 **/ |
|
1207 { |
|
1208 LOG_FUNC |
|
1209 TInt dataLenInBuf=aContext->iCircularReadBuf->Count(); |
|
1210 if (dataLenInBuf==0) |
|
1211 { |
|
1212 return; //nothing to do |
|
1213 } |
|
1214 |
|
1215 TInt bytesToCopy=0; |
|
1216 TPtr8& readptr=aContext->iReadBufPtr; // incoming data buffer |
|
1217 readptr.SetLength(0); |
|
1218 TUint8* ptr=CONST_CAST(TUint8*,(readptr.Ptr())); |
|
1219 TInt clientMaxLen=aContext->iClientReadLength; |
|
1220 |
|
1221 // This should cover terminated reads, plain reads and some read one |
|
1222 // or more cases |
|
1223 if(dataLenInBuf>=clientMaxLen) |
|
1224 { |
|
1225 // complete if possible any terminated reads for both larger or smaller |
|
1226 // client buffers than ours |
|
1227 if(aContext->iTerminatedReads) |
|
1228 { // try to find the terminated string |
|
1229 // bytesToCopy here can be greater than the clientMaxLen |
|
1230 // or can be -1 so we have to check |
|
1231 bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm); |
|
1232 if((bytesToCopy>clientMaxLen) || (bytesToCopy == KErrNotFound)) |
|
1233 { |
|
1234 bytesToCopy=clientMaxLen; |
|
1235 } |
|
1236 // else the terminated reads complete with no terminator because |
|
1237 // the client buffer can be filled completely. |
|
1238 } |
|
1239 else |
|
1240 { |
|
1241 // The plain reads where the client has a smaller buffer should |
|
1242 // complete here for the same reason. |
|
1243 // Read one or more would complete anyway for this case. |
|
1244 bytesToCopy=clientMaxLen; |
|
1245 } |
|
1246 } |
|
1247 // This should cover Receive one or more for the rest of the cases |
|
1248 |
|
1249 //will allow the full coverage of the high watermark case even if we do not do bounded reads |
|
1250 //#define BTCOMM_TEST_HIGH_WATERMARK |
|
1251 #ifndef BTCOMM_TEST_HIGH_WATERMARK |
|
1252 else if(aContext->iClientReadOneOrMore) |
|
1253 { |
|
1254 // if we reached this point it means that datLenInBuf<clientMaxLen |
|
1255 bytesToCopy=dataLenInBuf; |
|
1256 } |
|
1257 #endif |
|
1258 // Our client can handle lots of data, more than we can |
|
1259 else if(KBTCOMMCircularBufferLength<clientMaxLen) |
|
1260 { |
|
1261 if(aContext->iClientRemainderToRead<=dataLenInBuf) |
|
1262 { // then this is the last chunk of a multi write to client |
|
1263 if(aContext->iTerminatedReads) |
|
1264 { // try to find the terminated string |
|
1265 // bytesToCopy here can be -1 |
|
1266 // hence we have to check |
|
1267 bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm); |
|
1268 if(bytesToCopy==KErrNotFound) |
|
1269 {// ternminator was requested but not found... what the heck |
|
1270 bytesToCopy=aContext->iClientRemainderToRead; |
|
1271 } |
|
1272 } |
|
1273 else |
|
1274 { |
|
1275 // this is the last chunk to be read for this client read |
|
1276 // write as much as needed to the client |
|
1277 bytesToCopy=aContext->iClientRemainderToRead; |
|
1278 } |
|
1279 } |
|
1280 else if(aContext->ReadInBufferHighWatermarkReached()) // to minimise IPC |
|
1281 { |
|
1282 if(aContext->iTerminatedReads) |
|
1283 { // try to find the terminated string |
|
1284 // bytesToCopy here can be -1 |
|
1285 // hence we have to check |
|
1286 bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm); |
|
1287 if(bytesToCopy==KErrNotFound) |
|
1288 {// terminator was not found... but |
|
1289 // we have almost filled our buffer; write what we've got to the client |
|
1290 bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,dataLenInBuf); |
|
1291 __ASSERT_DEBUG(bytesToCopy==dataLenInBuf,PanicInState(EBTCommOpenStateWriteToClientPossibleLossOfData)); |
|
1292 |
|
1293 // fill their buf as much as we can and continue |
|
1294 readptr.SetLength(bytesToCopy); |
|
1295 TInt offset=aContext->iClientWriteOffset; |
|
1296 aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset); |
|
1297 aContext->iClientRemainderToRead-=bytesToCopy; |
|
1298 aContext->iClientWriteOffset+=bytesToCopy; // offset for next write to client |
|
1299 return; //our work is done wait for the next |
|
1300 } |
|
1301 // else the terminator was found hence copy data up to the |
|
1302 // terminator and complete the read |
|
1303 } |
|
1304 else // if no terminated reads were requested but the high watermark was reached |
|
1305 { |
|
1306 // copy what we have across and keep track of the offset |
|
1307 bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,dataLenInBuf); |
|
1308 __ASSERT_DEBUG(bytesToCopy==dataLenInBuf,PanicInState(EBTCommOpenStateWriteToClientPossibleLossOfData)); |
|
1309 |
|
1310 // fill their buf as much as we can and continue |
|
1311 readptr.SetLength(bytesToCopy); |
|
1312 TInt offset=aContext->iClientWriteOffset; |
|
1313 aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset); |
|
1314 aContext->iClientRemainderToRead-=bytesToCopy; |
|
1315 aContext->iClientWriteOffset+=bytesToCopy; // offset for next write to client |
|
1316 return; //our work is done wait for the next |
|
1317 } |
|
1318 } //matches else if(aContext->ReadInBufferHighWatermarkReached()) |
|
1319 // if the high watermark was not reached but we do terminated reads |
|
1320 #ifndef BTCOMM_TEST_HIGH_WATERMARK |
|
1321 else if (aContext->iTerminatedReads) |
|
1322 { |
|
1323 bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm); |
|
1324 } |
|
1325 #endif |
|
1326 } |
|
1327 // complete if possible any terminated reads for smaller |
|
1328 // client buffers than ours |
|
1329 else if(aContext->iTerminatedReads) |
|
1330 { // try to find the terminated string |
|
1331 // bytesToCopy here cannot be greater than the clientMaxLen |
|
1332 bytesToCopy=aContext->iCircularReadBuf->ScanForTerminator(aContext->iTerm); |
|
1333 } |
|
1334 |
|
1335 if(bytesToCopy>KErrNone) |
|
1336 { |
|
1337 // do the copy to the client buffer |
|
1338 TInt offset=aContext->iClientWriteOffset; |
|
1339 readptr.SetLength(bytesToCopy); |
|
1340 bytesToCopy=aContext->iCircularReadBuf->Remove(ptr,bytesToCopy); |
|
1341 aContext->iPort->IPCWrite(aContext->iClientReadPtr,readptr,offset); |
|
1342 |
|
1343 // reset the offsets and counters and complete the read |
|
1344 aContext->iClientReadLength=0; |
|
1345 aContext->iClientReadPtr=0; |
|
1346 aContext->iClientRemainderToRead=0; |
|
1347 aContext->iClientWriteOffset=0; |
|
1348 |
|
1349 aContext->iPort->ReadCompleted(KErrNone); |
|
1350 } |
|
1351 } |
|
1352 |
|
1353 void TBTPortStateOpen::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength) |
|
1354 /** |
|
1355 TBTPortState Open. |
|
1356 Store the client side ptr and length and then signal |
|
1357 start write immediately. |
|
1358 **/ |
|
1359 { |
|
1360 LOG_FUNC |
|
1361 // this is again due to the fact that we have to be asynchronous to avoid |
|
1362 // deadlocks with (mostly ESock) other comms components. |
|
1363 if(aContext->IsWriteCancelPending()) |
|
1364 { |
|
1365 aContext->iPort->WriteCompleted(KErrNotReady); |
|
1366 //aContext->DoWriteCancel(); a deadlock example ! |
|
1367 return; |
|
1368 } |
|
1369 |
|
1370 LOG(_L("**TBTPortStateOpen::Write**")); |
|
1371 aContext->iClientWritePtr=aPtr; |
|
1372 aContext->iClientWriteLength=aLength; |
|
1373 aContext->iClientLengthWrittenSoFar=aLength; |
|
1374 |
|
1375 if (aLength>KBTCOMMSendBufferLength) |
|
1376 { |
|
1377 aContext->iClientLengthWrittenSoFar=KBTCOMMSendBufferLength; |
|
1378 aContext->iMoreSendsToCome=ETrue; |
|
1379 } |
|
1380 TPtr8& sendptr=aContext->iSendBufPtr; |
|
1381 sendptr.SetLength(0); |
|
1382 // now read the client side data |
|
1383 TPtr8 ptr((TUint8*)sendptr.Ptr(),0,aContext->iClientLengthWrittenSoFar); |
|
1384 aContext->iPort->IPCRead(aPtr,ptr,0); |
|
1385 |
|
1386 sendptr.Append(ptr); |
|
1387 aContext->iSendBufPtr.SetLength(aContext->iClientLengthWrittenSoFar); |
|
1388 aContext->StartWriter(); |
|
1389 } |
|
1390 |
|
1391 void TBTPortStateOpen::DoWriteCompleted(CBTPortProxy* aContext,TInt aError) |
|
1392 /** |
|
1393 TBTPortStateOpen DoWriteCompleted. |
|
1394 If there is no error here, at this point the write |
|
1395 has successfully completed and |
|
1396 can be signalled complete back to the client code. |
|
1397 **/ |
|
1398 { |
|
1399 LOG_FUNC |
|
1400 if (aContext->iMoreSendsToCome) |
|
1401 {// we need to keep going |
|
1402 LOG(_L("**TBTPortStateOpen::DoWriteCompleted - more to come**")); |
|
1403 |
|
1404 TInt lentowrite=aContext->iClientWriteLength-aContext->iClientLengthWrittenSoFar; |
|
1405 TInt lensofar=aContext->iClientLengthWrittenSoFar; |
|
1406 if (lentowrite>KBTCOMMSendBufferLength) |
|
1407 {// still more to come |
|
1408 lentowrite=KBTCOMMSendBufferLength; |
|
1409 aContext->iClientLengthWrittenSoFar+=KBTCOMMSendBufferLength; |
|
1410 aContext->iMoreSendsToCome=ETrue; |
|
1411 } |
|
1412 else |
|
1413 { |
|
1414 aContext->iClientLengthWrittenSoFar+=lentowrite; |
|
1415 aContext->iMoreSendsToCome=EFalse; |
|
1416 } |
|
1417 TPtr8 sendptr=aContext->iSendBufPtr; |
|
1418 sendptr.SetLength(0); |
|
1419 // read the client side data |
|
1420 TPtr8 ptr((TUint8*)sendptr.Ptr(),0,lentowrite); |
|
1421 aContext->iPort->IPCRead(aContext->iClientWritePtr,ptr,lensofar); |
|
1422 |
|
1423 sendptr.Append(ptr); |
|
1424 aContext->iSendBufPtr.SetLength(lentowrite); |
|
1425 aContext->StartWriter(); |
|
1426 } |
|
1427 else |
|
1428 {// we have finished - can signal to client and 0 the client stuff. |
|
1429 LOG(_L("**TBTPortStateOpen::DoWriteCompleted - finished**")); |
|
1430 aContext->iMoreSendsToCome=EFalse; |
|
1431 aContext->iClientLengthWrittenSoFar=0; |
|
1432 aContext->iClientWritePtr=0; |
|
1433 aContext->iClientWriteLength=0; |
|
1434 aContext->iPort->WriteCompleted(aError); |
|
1435 } |
|
1436 } |
|
1437 |
|
1438 void TBTPortStateOpen::WriteCancel(CBTPortProxy* aContext) |
|
1439 /** |
|
1440 It will complete the cancelation to the client and then request it from the server. |
|
1441 */ |
|
1442 { |
|
1443 LOG_FUNC |
|
1444 // do say yes you cancelled and then cancel if necessary |
|
1445 aContext->iPort->WriteCompleted(KErrCancel); |
|
1446 aContext->SetWriteCancelPending(); |
|
1447 aContext->StartLocker(); |
|
1448 } |
|
1449 |
|
1450 void TBTPortStateOpen::ReadCancel(CBTPortProxy* aContext) |
|
1451 /** |
|
1452 It will complete the cancelation to the client. |
|
1453 */ |
|
1454 { |
|
1455 LOG_FUNC |
|
1456 #ifdef _DEBUG |
|
1457 aContext->iReadsPending--; |
|
1458 #endif |
|
1459 // do say yes you cancelled and then cancel if necessary |
|
1460 aContext->iPort->ReadCompleted(KErrCancel); |
|
1461 // Read Cancel does not need to be propagated to the underlying socket |
|
1462 // since CSY has a ring buffer which is filled with inbound data regardless |
|
1463 // of what the upper app is up to with its RComm |
|
1464 } |
|
1465 |
|
1466 void TBTPortStateOpen::DoLockedAction(CBTPortProxy* aContext) |
|
1467 { |
|
1468 LOG_FUNC |
|
1469 TInt ret=aContext->iStatus.Int(); |
|
1470 if (ret!=KErrNone) |
|
1471 { |
|
1472 aContext->StopLocker(); |
|
1473 Error(aContext,ret); |
|
1474 return; |
|
1475 } |
|
1476 if(aContext->IsWriteCancelPending()) |
|
1477 { |
|
1478 aContext->DoWriteCancel(); // the locked action for which we came in here |
|
1479 } |
|
1480 else //default handle - stray event must be caught |
|
1481 { |
|
1482 ((TBTPortDefaultState*)this)->DoLockedAction(aContext); |
|
1483 } |
|
1484 aContext->StopLocker(); |
|
1485 //NOTE: we remain in this state |
|
1486 } |
|
1487 |
|
1488 void TBTPortStateOpen::LogStateError(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
1489 { |
|
1490 LOG_FUNC |
|
1491 } |
|
1492 |
|
1493 // ***** Closing state ***** |
|
1494 |
|
1495 TBTPortStateClosing::TBTPortStateClosing(CBTPortStateFactory* aParent) |
|
1496 : TBTPortCommonBaseState(aParent) |
|
1497 { |
|
1498 LOG_FUNC |
|
1499 } |
|
1500 |
|
1501 TBTPortStateClosing::~TBTPortStateClosing() |
|
1502 { |
|
1503 LOG_FUNC |
|
1504 } |
|
1505 |
|
1506 void TBTPortStateClosing::Close(CBTPortProxy* /*aContext*/) |
|
1507 { |
|
1508 LOG_FUNC |
|
1509 } |
|
1510 |
|
1511 void TBTPortStateClosing::Read(CBTPortProxy* aContext, TAny* aPtr,TInt aLength) |
|
1512 /** |
|
1513 Read in this state indirectly calls the DoLockedAction to get out and in the state machine again. |
|
1514 This is done because of the huge window of opportunity for race conditions |
|
1515 while the async timer is ticking before shutdown. Since we need the |
|
1516 shutdown timer for the closing to be async (to avoid deadlocks with Etel etc), |
|
1517 hence we should close the socket etc and transfer the Read() to the |
|
1518 Idle state. |
|
1519 */ |
|
1520 { |
|
1521 LOG_FUNC |
|
1522 |
|
1523 LOG(_L("**TBTPortStateClosing Canceling the shutdown timer **")); |
|
1524 aContext->CancelShutDownTimer(); |
|
1525 |
|
1526 // cache the read |
|
1527 aContext->iClientReadPtr=aPtr; |
|
1528 aContext->iClientReadLength=aLength; |
|
1529 aContext->iClientRemainderToRead=aLength; |
|
1530 // close sockets resolver etc |
|
1531 aContext->StartLocker(); // next call is to our DoLockedAction(..); |
|
1532 // we now know that someone re-opened us while going down so... |
|
1533 // transfer the call |
|
1534 } |
|
1535 |
|
1536 void TBTPortStateClosing::Write(CBTPortProxy* aContext,TAny* aPtr,TInt aLength) |
|
1537 /** |
|
1538 Write in this state indirectly calls the DoLockedAction to get out and in the state machine again. |
|
1539 This is done because of the huge window of opportunity for race conditions |
|
1540 while the async timer is ticking before shutdown. Since we need the |
|
1541 shutdown timer for the closing to be async (to avoid deadlocks with Etel etc), |
|
1542 hence we should close the socket etc and transfer the write() to the |
|
1543 Idle state. |
|
1544 */ |
|
1545 { |
|
1546 LOG_FUNC |
|
1547 |
|
1548 LOG(_L("**TBTPortStateClosing Canceling the shutdown timer **")); |
|
1549 aContext->CancelShutDownTimer(); |
|
1550 |
|
1551 // cache the write |
|
1552 aContext->iClientWritePtr=aPtr; |
|
1553 aContext->iClientWriteLength=aLength; |
|
1554 aContext->iClientLengthWrittenSoFar=aLength; |
|
1555 |
|
1556 // close sockets resolver etc |
|
1557 //next call is in our DoLockedAction(..); |
|
1558 aContext->StartLocker(); |
|
1559 // we now know that someone re-opened us while going down so... |
|
1560 // transfer the call |
|
1561 } |
|
1562 |
|
1563 void TBTPortStateClosing::DoRunL(CBTPortProxy* aContext) |
|
1564 /** |
|
1565 At this point our socket shutdown has returned. |
|
1566 We can now close down the host resolver, netdb and finally |
|
1567 the session to the socket server itself. These are all |
|
1568 synchronous actions so must be handled by the locker. |
|
1569 |
|
1570 But we need to defer the actual completion of the final closing for later |
|
1571 in order to give some time for other components like Etel to close first. |
|
1572 Note the values used here are arbitrary and should be considered a |
|
1573 hacked fix :-(. |
|
1574 |
|
1575 NOTE: the next transition is in TBTPortStateClosing::DoLockedAction |
|
1576 unless the shutdown timer is cancelled by a new read or write |
|
1577 **/ |
|
1578 { |
|
1579 LOG_FUNC |
|
1580 TInt ret=aContext->iStatus.Int(); |
|
1581 if (ret!=KErrNone) |
|
1582 {// didn't manage to succeed with socket shutdown somehow. |
|
1583 LOG(_L("**TBTPortStateClosing Closing with an error !**")); |
|
1584 aContext->StartShutdownTimerL();// this will eventually call aContext->StartLocker() |
|
1585 } |
|
1586 else |
|
1587 {// we have successfully shutdown the socket. |
|
1588 aContext->StartShutdownTimerL();// this will eventually call aContext->StartLocker() |
|
1589 } |
|
1590 //NOTE: the next transition is in TBTPortStateClosing::DoLockedAction |
|
1591 // unless the shutdown timer is cancelled by a new read or write |
|
1592 } |
|
1593 |
|
1594 void TBTPortStateClosing::DoLockedAction(CBTPortProxy* aContext) |
|
1595 /** |
|
1596 TBTPortStateClosing DoLockedAction. |
|
1597 At this point we have obtained the lock hence we are able to undertake |
|
1598 the locked actions. |
|
1599 This method should be called indirectly by the shutdown timer or due to |
|
1600 a previous WriteCancel call at the open state, followed by a |
|
1601 Close() call ( which brought as here in this state). |
|
1602 **/ |
|
1603 { |
|
1604 LOG_FUNC |
|
1605 if(aContext->IsWriteCancelPending()) |
|
1606 { |
|
1607 LOG(_L("**TBTPortStateClosing::DoLockedAction -- Servicing Write cancelations first**")); |
|
1608 aContext->DoWriteCancel(); // the locked action for which we came in here |
|
1609 aContext->StopLocker(); |
|
1610 return; |
|
1611 } |
|
1612 |
|
1613 if(aContext->IsNetDbInUse()) |
|
1614 { |
|
1615 // we need this in the case of cancelation before the netdb.Open() |
|
1616 // because the kernel will panic us if it doesn't find the session |
|
1617 RNetDatabase& netdb=aContext->iNetDatabase; |
|
1618 netdb.Cancel(); |
|
1619 netdb.Close(); |
|
1620 aContext->SetNetDbNotInUse(); |
|
1621 LOG(_L("**TBTPortStateClosing, NetDB session clean-up done **")); |
|
1622 } |
|
1623 |
|
1624 // the following immediate shutdown will not stiff C32 and is needed for |
|
1625 // the next close to be possible in ESock without it being blocked waiting |
|
1626 // for the protocol SAP to be cleaned |
|
1627 // |
|
1628 // This shutdown will cause any outstanding socket ops to be cancelled so |
|
1629 // we can safely call aContext->Cancel() afterwards. |
|
1630 if(aContext->iSocket.SubSessionHandle()) |
|
1631 {// Make sure we had managed to open the socket connection before we arriveed here |
|
1632 aContext->iSocket.Shutdown(RSocket::EImmediate,aContext->iStatus); |
|
1633 User::WaitForRequest(aContext->iStatus); |
|
1634 } |
|
1635 |
|
1636 // Do BT CSY specific locked action. |
|
1637 aContext->iSocket.Close(); |
|
1638 |
|
1639 // We can only make synch calls to ESock from within the locker, otherwise |
|
1640 // we risk deadlock. This means we can't put any Cancel()s that may end |
|
1641 // up in ESock in the port proxy's DoCancel() unless we guarantee that Cancel() |
|
1642 // can only be called from within the locker. Instead we ensure we've done |
|
1643 // all the necessary cancelling before calling Cancel(). |
|
1644 aContext->Cancel(); |
|
1645 |
|
1646 |
|
1647 // We should never transition to the closing state whilst waiting for |
|
1648 // an ESock connection, unless I've bugged the state machine. |
|
1649 __ASSERT_DEBUG(!aContext->iSockServConnector->IsActive(), PanicInState(EBTCommCloseWhileWaitingForSockServHandle)); |
|
1650 |
|
1651 if(aContext->iSockServ.Handle()) |
|
1652 { |
|
1653 aContext->iSockServ.Close(); |
|
1654 } |
|
1655 aContext->StopLocker(); // sync actions completed ok - now stop locker. |
|
1656 |
|
1657 // we do this just before destruction, just in case someone has reopened us |
|
1658 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EIdle)); |
|
1659 // UGLY |
|
1660 aContext->DestructContext(); // will not do anything if we got reopened |
|
1661 } |
|
1662 |
|
1663 void TBTPortStateClosing::DoWriteCompleted(CBTPortProxy * /*aContext*/,TInt /*aError*/) |
|
1664 { |
|
1665 LOG_FUNC |
|
1666 } |
|
1667 |
|
1668 void TBTPortStateClosing::DoReadCompleted(CBTPortProxy * /*aContext*/, TInt /*aError*/) |
|
1669 { |
|
1670 LOG_FUNC |
|
1671 } |
|
1672 |
|
1673 void TBTPortStateClosing::LogStateError(CBTPortProxy * /*aContext*/,TInt /*aError*/) |
|
1674 { |
|
1675 LOG_FUNC |
|
1676 } |
|
1677 |
|
1678 |
|
1679 // Error State |
|
1680 |
|
1681 TBTPortErrorState::TBTPortErrorState(CBTPortStateFactory* aParent) |
|
1682 : TBTPortState(aParent) |
|
1683 { |
|
1684 LOG_FUNC |
|
1685 } |
|
1686 |
|
1687 TBTPortErrorState::~TBTPortErrorState() |
|
1688 { |
|
1689 LOG_FUNC |
|
1690 } |
|
1691 |
|
1692 void TBTPortErrorState::Open(CBTPortProxy* /*aContext*/) |
|
1693 { |
|
1694 LOG_FUNC |
|
1695 } |
|
1696 |
|
1697 void TBTPortErrorState::Read(CBTPortProxy* aContext,TAny* /*aPtr*/,TInt /*aLength*/) |
|
1698 /** |
|
1699 Notify the client about this recent error. |
|
1700 */ |
|
1701 { |
|
1702 LOG_FUNC |
|
1703 aContext->iPort->ReadCompleted(aContext->iLastError); |
|
1704 } |
|
1705 |
|
1706 void TBTPortErrorState::Write(CBTPortProxy* aContext,TAny* /*aPtr*/,TInt /*aLength*/) |
|
1707 /** |
|
1708 Notify the client about this recent error. |
|
1709 */ |
|
1710 { |
|
1711 LOG_FUNC |
|
1712 aContext->iPort->WriteCompleted(aContext->iLastError); |
|
1713 } |
|
1714 |
|
1715 void TBTPortErrorState::Close(CBTPortProxy* aContext) |
|
1716 { |
|
1717 LOG_FUNC |
|
1718 aContext->SetState(iFactory->GetState(CBTPortStateFactory::EClosing)); |
|
1719 |
|
1720 // check to see if the error came before we managed to do the locked action |
|
1721 // ..and cancel the pending locked action then |
|
1722 if(aContext->IsLockerOn()) |
|
1723 { |
|
1724 aContext->StopLocker(); |
|
1725 } |
|
1726 aContext->SetActive(); |
|
1727 TRequestStatus* pStatus = &(aContext->iStatus); |
|
1728 User::RequestComplete(pStatus, KErrNone); |
|
1729 } |
|
1730 |
|
1731 void TBTPortErrorState::DoRunL(CBTPortProxy* /*aContext*/) |
|
1732 { |
|
1733 LOG_FUNC |
|
1734 } |
|
1735 |
|
1736 void TBTPortErrorState::DoCancel(CBTPortProxy* /*aContext*/) |
|
1737 { |
|
1738 LOG_FUNC |
|
1739 } |
|
1740 |
|
1741 void TBTPortErrorState::WriteCancel(CBTPortProxy* /*aContext*/) |
|
1742 { |
|
1743 LOG_FUNC |
|
1744 } |
|
1745 |
|
1746 void TBTPortErrorState::ReadCancel(CBTPortProxy* /*aContext*/) |
|
1747 { |
|
1748 LOG_FUNC |
|
1749 } |
|
1750 |
|
1751 void TBTPortErrorState::DoLockedAction(CBTPortProxy* /*aContext*/) |
|
1752 { |
|
1753 LOG_FUNC |
|
1754 BAD_BTCOMM_EVENT |
|
1755 } |
|
1756 |
|
1757 void TBTPortErrorState::DoWriteCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
1758 { |
|
1759 LOG_FUNC |
|
1760 } |
|
1761 |
|
1762 void TBTPortErrorState::DoReadCompleted(CBTPortProxy* /*aContext*/,TInt /*aError*/) |
|
1763 { |
|
1764 LOG_FUNC |
|
1765 } |
|
1766 |
|
1767 void TBTPortErrorState::Error(CBTPortProxy* aContext,TInt aError) |
|
1768 /** |
|
1769 Error will be the first method to be called in entering this state. |
|
1770 So here Error will check to see if there are any Queued reads, which |
|
1771 it will immediately complete. |
|
1772 |
|
1773 This should only be called on moving from any other state to the error |
|
1774 state and not otherwise. |
|
1775 */ |
|
1776 { |
|
1777 LOG_FUNC |
|
1778 if (aContext->iClientReadPtr) |
|
1779 { // this means that a read was queued already so we need to signal |
|
1780 // the error immediately |
|
1781 aContext->iPort->ReadCompleted(aError); |
|
1782 } |
|
1783 if (aContext->iClientWritePtr) |
|
1784 { // same for write |
|
1785 aContext->iPort->WriteCompleted(aError); |
|
1786 } |
|
1787 } |
|
1788 |