|
1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Symbian Foundation License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <bluetooth/logger.h> |
|
17 #include "activehelper.h" |
|
18 #include "bearermanager.h" |
|
19 #include "controllersession.h" |
|
20 #include "messagequeue.h" |
|
21 #include "remconmessage.h" |
|
22 #include "remconserver.h" |
|
23 #include "server.h" |
|
24 #include "utils.h" |
|
25 |
|
26 #ifdef __FLOG_ACTIVE |
|
27 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER); |
|
28 #endif |
|
29 |
|
30 #ifdef _DEBUG |
|
31 PANICCATEGORY("ctsession"); |
|
32 #endif |
|
33 |
|
34 |
|
35 CRemConControllerSession* CRemConControllerSession::NewL(CRemConServer& aServer, |
|
36 CBearerManager& aBearerManager, |
|
37 const TClientInfo& aClientInfo, |
|
38 TUint aId) |
|
39 { |
|
40 LOG_STATIC_FUNC; |
|
41 CRemConControllerSession* self = new(ELeave) CRemConControllerSession(aServer, aBearerManager, aId); |
|
42 CleanupStack::PushL(self); |
|
43 self->ConstructL(aClientInfo); |
|
44 CLEANUPSTACK_POP1(self); |
|
45 return self; |
|
46 } |
|
47 |
|
48 CRemConControllerSession::~CRemConControllerSession() |
|
49 { |
|
50 LOG_FUNC; |
|
51 |
|
52 delete iPendingMsgProcessor; |
|
53 |
|
54 // we will need to tell the server which bearer this used to be connected to |
|
55 // this enables the server to not inform a bearer that is already connected |
|
56 // that its been connected |
|
57 // Tell the server we've gone away- it may start its shutdown timer. |
|
58 iServer.ControllerClientClosed(*this, iRemoteAddress.BearerUid()); |
|
59 iPlayerName.Close(); |
|
60 } |
|
61 |
|
62 CRemConControllerSession::CRemConControllerSession(CRemConServer& aServer, |
|
63 CBearerManager& aBearerManager, |
|
64 TUint aId) |
|
65 : CRemConSession(aServer, aBearerManager, aId) |
|
66 { |
|
67 LOG_FUNC; |
|
68 } |
|
69 |
|
70 void CRemConControllerSession::ConstructL(const TClientInfo& aClientInfo) |
|
71 { |
|
72 LOG_FUNC; |
|
73 |
|
74 BaseConstructL(aClientInfo); |
|
75 |
|
76 iPendingMsgProcessor = new (ELeave) CActiveHelper(*this); |
|
77 |
|
78 LEAVEIFERRORL(iServer.ControllerClientOpened(*this)); |
|
79 |
|
80 // Set our pointer into the connection history at the current/'Last' item. |
|
81 // Can't do this til we've told the server we exist |
|
82 iServer.SetConnectionHistoryPointer(Id()); |
|
83 } |
|
84 |
|
85 TBool CRemConControllerSession::SupportedMessage(const CRemConMessage& aMsg) const |
|
86 { |
|
87 LOG_FUNC; |
|
88 LOG1(_L("\taMsg.InterfaceUid() = 0x%08x"), aMsg.InterfaceUid()); |
|
89 |
|
90 // Return true unless this is a command for an unsupported interface |
|
91 TBool result = !(aMsg.MsgType() == ERemConCommand && !FindInterfaceByUid(aMsg.InterfaceUid())); |
|
92 |
|
93 LOG1(_L("result = %d"), result); |
|
94 return result; |
|
95 } |
|
96 |
|
97 void CRemConControllerSession::SetPlayerType(const RMessage2& aMessage) |
|
98 { |
|
99 LOG_FUNC; |
|
100 |
|
101 // Controller clients don't provide the additional parameters are optional, |
|
102 // so we just complete the message with KErrNone. |
|
103 CompleteClient(aMessage, KErrNone); |
|
104 } |
|
105 |
|
106 void CRemConControllerSession::CompleteConnect(const TRemConAddress& aAddr, TInt aError) |
|
107 { |
|
108 LOG_FUNC; |
|
109 LOG2(_L("\taError = %d, aAddr.BearerUid = 0x%08x"), aError, aAddr.BearerUid()); |
|
110 |
|
111 LOG1(_L("\tiRemoteAddress.BearerUid = 0x%08x"), iRemoteAddress.BearerUid()); |
|
112 LOG1(_L("\tiConnectBearerMsg.Handle = %d"), iConnectBearerMsg.Handle()); |
|
113 |
|
114 if ( iRemoteAddress == aAddr ) |
|
115 { |
|
116 if ( iConnectBearerMsg.Handle() ) |
|
117 { |
|
118 // We are a session that has an outstanding request on this specific |
|
119 // connection address. |
|
120 CompleteClient(iConnectBearerMsg, aError); |
|
121 } |
|
122 else |
|
123 { |
|
124 // Connect bearer message is not valid. |
|
125 // Check for pending messages. |
|
126 CheckForPendingMsg(); |
|
127 } |
|
128 } |
|
129 } |
|
130 |
|
131 void CRemConControllerSession::CompleteDisconnect(const TRemConAddress& aAddr, TInt aError) |
|
132 { |
|
133 LOG_FUNC; |
|
134 LOG2(_L("\taError = %d, aAddr.BearerUid = 0x%08x"), aError, aAddr.BearerUid()); |
|
135 |
|
136 LOG1(_L("\tiRemoteAddress.BearerUid = 0x%08x"), iRemoteAddress.BearerUid()); |
|
137 LOG1(_L("\tiDisconnectBearerMsg.Handle = %d"), iDisconnectBearerMsg.Handle()); |
|
138 |
|
139 if ( iRemoteAddress == aAddr ) |
|
140 { |
|
141 if ( iDisconnectBearerMsg.Handle() ) |
|
142 { |
|
143 // We are a session that has an outstanding request on this specific |
|
144 // connection address. |
|
145 CompleteClient(iDisconnectBearerMsg, aError); |
|
146 } |
|
147 else |
|
148 { |
|
149 // Diconnect bearer message is not valid. |
|
150 // Check for pending messages. |
|
151 CheckForPendingMsg(); |
|
152 } |
|
153 |
|
154 } |
|
155 } |
|
156 |
|
157 void CRemConControllerSession::ProcessPendingMsgL() |
|
158 { |
|
159 LOG_FUNC; |
|
160 if (!iPendingMsg.Handle()) |
|
161 { |
|
162 // This means that the pending connect or disconnect message, |
|
163 // has been cancelled by the time we got here. |
|
164 // (It was cancelled between two following calls: |
|
165 // iPendingMsgProcessor::Complete and iPendingMsgProcessor::RunL |
|
166 return; |
|
167 } |
|
168 |
|
169 ServiceL(iPendingMsg); |
|
170 if (iPendingMsg.Handle()) |
|
171 { |
|
172 // This means that the pending msg has not been completed in ServiceL call. |
|
173 // It was stored either in iConnectBearerMsg or iDisconnectBearerMsg member. |
|
174 // This also means that this message is not "pending" any more |
|
175 // (as processing of its copy has been started). |
|
176 // However because the copy will get completed we need to |
|
177 // clean iPendingMsg.iHandle here |
|
178 // To supress coverity error for uninitialized use of 'emptyMsg' coverity annotations |
|
179 // are used as the in-line default constructor of RMessage2 doesn't initialize all member variables. |
|
180 // coverity[var_decl] |
|
181 RMessage2 emptyMsg; |
|
182 iPendingMsg = emptyMsg; |
|
183 } |
|
184 } |
|
185 |
|
186 void CRemConControllerSession::CheckForPendingMsg() const |
|
187 { |
|
188 LOG_FUNC; |
|
189 if (iPendingMsg.Handle()) |
|
190 { |
|
191 ASSERT_DEBUG(iPendingMsgProcessor); |
|
192 iPendingMsgProcessor->Complete(); |
|
193 } |
|
194 } |
|
195 |
|
196 CRemConMessage* CRemConControllerSession::DoPrepareSendMessageL(const RMessage2& aMessage) |
|
197 { |
|
198 LOG_FUNC; |
|
199 |
|
200 // Check we don't have a disconnect outstanding- this makes no sense from |
|
201 // a client viewpoint (they should cancel the disconnect first). |
|
202 // [The client is allowed to have a connect request outstanding- the |
|
203 // bearer manager makes sure a bearer-level connect is not posted on the |
|
204 // same address twice.] |
|
205 if ( iDisconnectBearerMsg.Handle() ) |
|
206 { |
|
207 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
208 return NULL; |
|
209 } |
|
210 |
|
211 // Get the data the client wants to send. |
|
212 TUid interfaceUid; |
|
213 TUint operationId; |
|
214 |
|
215 TRemConMessageSubType messageSubType; |
|
216 RBuf8 sendDes; |
|
217 if (!DoGetSendInfoLC(aMessage, interfaceUid, operationId, messageSubType, sendDes)) |
|
218 { |
|
219 // DoGetSendInfoLC() panicked the message |
|
220 return NULL; |
|
221 } |
|
222 |
|
223 CRemConMessage* msg = NULL; |
|
224 LOG(_L("\tCONTROLLER send")); |
|
225 if ( (messageSubType == ERemConNotifyCommandAwaitingInterim) |
|
226 || (messageSubType == ERemConNotifyCommandAwaitingChanged) |
|
227 ) |
|
228 { |
|
229 LOG(_L("\terror, not allowed to use Send() to send notify command")); |
|
230 CleanupStack::PopAndDestroy(&sendDes); |
|
231 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc); |
|
232 } |
|
233 else |
|
234 { |
|
235 msg = CRemConMessage::NewL( |
|
236 iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP) |
|
237 ERemConCommand, |
|
238 messageSubType, |
|
239 interfaceUid, |
|
240 operationId, |
|
241 sendDes, // msg takes ownership |
|
242 Id(), // session id for when the response comes back |
|
243 0, // we let the bearer manager invent a new transaction id when the message gets to it |
|
244 ETrue); |
|
245 CLEANUPSTACK_POP1(&sendDes); // now owned by msg |
|
246 } |
|
247 |
|
248 return msg; |
|
249 } |
|
250 |
|
251 void CRemConControllerSession::SendUnreliable(const RMessage2& aMessage) |
|
252 { |
|
253 LOG_FUNC; |
|
254 |
|
255 // Check we've had our features set... |
|
256 if (!ClientAvailable()) |
|
257 { |
|
258 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
259 return; |
|
260 } |
|
261 |
|
262 // Check we don't have a disconnect outstanding- this makes no sense from |
|
263 // a client viewpoint (they should cancel the disconnect first). |
|
264 // [The client is allowed to have a connect request outstanding- the |
|
265 // bearer manager makes sure a bearer-level connect is not posted on the |
|
266 // same address twice.] |
|
267 if ( iDisconnectBearerMsg.Handle() ) |
|
268 { |
|
269 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
270 return; |
|
271 } |
|
272 |
|
273 CRemConMessage* msg = NULL; |
|
274 TRAPD(err, msg = DoCreateUnreliableMessageL(aMessage)); |
|
275 CompleteClient(aMessage, err); |
|
276 if (err == KErrNone) |
|
277 { |
|
278 ASSERT_DEBUG(iSendQueue); |
|
279 if (iSending || !iSendQueue->IsEmpty()) |
|
280 { |
|
281 iSendQueue->Append(*msg); |
|
282 } |
|
283 else |
|
284 { |
|
285 SendToServer(*msg); |
|
286 } |
|
287 } |
|
288 } |
|
289 |
|
290 CRemConMessage* CRemConControllerSession::DoCreateUnreliableMessageL(const RMessage2& aMessage) |
|
291 { |
|
292 LOG_FUNC; |
|
293 |
|
294 // Get the data the client wants to send. |
|
295 TUid interfaceUid; |
|
296 TUint operationId; |
|
297 TRemConMessageSubType messageSubType; |
|
298 RBuf8 sendDes; |
|
299 DoGetSendInfoLC(aMessage, interfaceUid, operationId, messageSubType, sendDes); |
|
300 |
|
301 // Before we ask the server to send, we must set our ClientInfo |
|
302 // correctly so the TSP can get information about the client. |
|
303 iClientInfo.Message() = aMessage; |
|
304 |
|
305 CRemConMessage* msg = NULL; |
|
306 |
|
307 LOG(_L("\tCONTROLLER send")); |
|
308 |
|
309 // A client is not allowed to send an unreliable notify command. |
|
310 if ( (messageSubType == ERemConNotifyCommandAwaitingInterim) |
|
311 || (messageSubType == ERemConNotifyCommandAwaitingChanged) |
|
312 ) |
|
313 { |
|
314 LOG(_L8("\tNot allowed to send unreliable notify command")); |
|
315 CleanupStack::PopAndDestroy(&sendDes); |
|
316 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc); |
|
317 LEAVEL(KErrBadDescriptor); |
|
318 } |
|
319 |
|
320 msg = CRemConMessage::NewL( |
|
321 iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP) |
|
322 ERemConCommand, // controllers can only send commands |
|
323 messageSubType, |
|
324 interfaceUid, |
|
325 operationId, |
|
326 sendDes, // msg takes ownership |
|
327 Id(), // session id for when the response comes back |
|
328 0, // we let the bearer manager invent a new transaction id when the message gets to it |
|
329 EFalse); |
|
330 CLEANUPSTACK_POP1(&sendDes); // now owned by msg |
|
331 |
|
332 return msg; |
|
333 } |
|
334 |
|
335 void CRemConControllerSession::RegisterInterestedAPIs(const RMessage2& aMessage) |
|
336 { |
|
337 LOG_FUNC; |
|
338 // No interfaces should have been registered yet! |
|
339 ASSERT_DEBUG(iInterestedAPIs == NULL); |
|
340 |
|
341 TRAPD(err, iInterestedAPIs = ExtractInterestedAPIsL(aMessage)); |
|
342 |
|
343 iServer.ControllerClientAvailable(); |
|
344 |
|
345 CompleteClient(aMessage, err); |
|
346 } |
|
347 |
|
348 void CRemConControllerSession::GoConnectionOriented(const RMessage2& aMessage) |
|
349 { |
|
350 LOG_FUNC; |
|
351 |
|
352 // Check we've had our features set... |
|
353 if (!ClientAvailable()) |
|
354 { |
|
355 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
356 return; |
|
357 } |
|
358 |
|
359 if ( !iRemoteAddress.IsNull() ) |
|
360 { |
|
361 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicAlreadyConnectionOriented); |
|
362 return; |
|
363 } |
|
364 |
|
365 if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() || iSendMsg.Handle()) |
|
366 { |
|
367 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
368 return; |
|
369 } |
|
370 if (iSending != ENotSending) |
|
371 { |
|
372 DoSendCancel(); |
|
373 } |
|
374 EmptySendQueue(); |
|
375 |
|
376 // Get the desired address from the message and check it. |
|
377 const TUid uid = TUid::Uid(aMessage.Int0()); |
|
378 LOG1(_L("\tuid = 0x%08x"), uid); |
|
379 // Check the requested bearer exists. |
|
380 TBool bearerExists = iBearerManager.BearerExists(uid); |
|
381 if ( !bearerExists) |
|
382 { |
|
383 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerPluginIncorrectInterface); |
|
384 return; |
|
385 } |
|
386 // Check the bearer-specific part of the address. |
|
387 TBuf8<TRemConAddress::KMaxAddrSize> buf; |
|
388 TInt err = aMessage.Read(1, buf); |
|
389 if ( err != KErrNone ) |
|
390 { |
|
391 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor); |
|
392 return; |
|
393 } |
|
394 |
|
395 // Do security check- if this client won't be allowed to use the bearer |
|
396 // then fail the request. |
|
397 // NB This security check (repeated in debug at ConnectBearer and |
|
398 // DisconnectBearer time) is all that stands between a connection-oriented |
|
399 // client and the bearer, and is all the caps checking that RemCon does! |
|
400 err = KErrPermissionDenied; |
|
401 if ( iBearerManager.CheckPolicy(uid, aMessage) ) |
|
402 { |
|
403 err = KErrNone; |
|
404 } |
|
405 |
|
406 |
|
407 // if alls well and we're connection oriented then set up as such |
|
408 if (KErrNone == err) |
|
409 { |
|
410 // The client has passed all our checks- set our data member. |
|
411 iRemoteAddress.BearerUid() = uid; |
|
412 iRemoteAddress.Addr() = buf; |
|
413 // tell the server |
|
414 iServer.ClientGoConnectionOriented(*this,uid); |
|
415 } |
|
416 |
|
417 CompleteClient(aMessage, err); |
|
418 } |
|
419 |
|
420 void CRemConControllerSession::GoConnectionless(const RMessage2& aMessage) |
|
421 { |
|
422 LOG_FUNC; |
|
423 |
|
424 // Check we've had our features set... |
|
425 if (!ClientAvailable()) |
|
426 { |
|
427 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
428 return; |
|
429 } |
|
430 |
|
431 if ( iRemoteAddress.IsNull() ) |
|
432 { |
|
433 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented); |
|
434 return; |
|
435 } |
|
436 |
|
437 if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() || iSendMsg.Handle()) |
|
438 { |
|
439 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
440 return; |
|
441 } |
|
442 |
|
443 if (iSending != ENotSending) |
|
444 { |
|
445 DoSendCancel(); |
|
446 } |
|
447 EmptySendQueue(); |
|
448 |
|
449 // we will need to tell the server which bearer this used to be connected to |
|
450 // this enables the server to not inform a bearer that is already connected |
|
451 // that its been connected |
|
452 TUid oldUid = iRemoteAddress.BearerUid(); |
|
453 |
|
454 iRemoteAddress.BearerUid() = KNullUid; |
|
455 |
|
456 // tell the server |
|
457 iServer.ClientGoConnectionless(*this, oldUid); |
|
458 |
|
459 CompleteClient(aMessage, KErrNone); |
|
460 } |
|
461 |
|
462 void CRemConControllerSession::ConnectBearer(const RMessage2& aMessage) |
|
463 { |
|
464 LOG_FUNC; |
|
465 |
|
466 // Check we've had our features set... |
|
467 if (!ClientAvailable()) |
|
468 { |
|
469 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
470 return; |
|
471 } |
|
472 |
|
473 if ( iConnectBearerMsg.Handle() || iDisconnectBearerMsg.Handle() ) |
|
474 { |
|
475 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
476 return; |
|
477 } |
|
478 |
|
479 if ( iRemoteAddress.IsNull() ) |
|
480 { |
|
481 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented); |
|
482 return; |
|
483 } |
|
484 |
|
485 // Check the requested bearer exists. |
|
486 TBool bearerExists = iBearerManager.BearerExists(iRemoteAddress.BearerUid()); |
|
487 // This check was done at GoConnectionOriented time. |
|
488 ASSERT_DEBUG(bearerExists); |
|
489 // So was this one. |
|
490 ASSERT_DEBUG(iBearerManager.CheckPolicy(iRemoteAddress.BearerUid(), aMessage)); |
|
491 |
|
492 // Check the state of our given connection at the bearer level. If it is: |
|
493 // -) disconnected request the connection to come up, |
|
494 // -) connecting or disconnecting, add message to the queue of pending |
|
495 // messages, and process it once connecting/disconnecting has been completed |
|
496 // -) connected, complete the client's message, |
|
497 |
|
498 TConnectionState conState; |
|
499 conState = iServer.ConnectionState(iRemoteAddress); |
|
500 |
|
501 if ( conState == EDisconnected ) |
|
502 { |
|
503 // The bearer may indicate connection synchronously, so set this |
|
504 // message _before_ we ask them |
|
505 iConnectBearerMsg = aMessage; |
|
506 TInt err = iBearerManager.Connect(iRemoteAddress); |
|
507 if ( err != KErrNone ) |
|
508 { |
|
509 CompleteClient(iConnectBearerMsg, err); |
|
510 } |
|
511 } |
|
512 else if ( conState == EDisconnecting || conState == EConnecting ) |
|
513 { |
|
514 if ( iPendingMsg.Handle() ) |
|
515 { |
|
516 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
517 return; |
|
518 } |
|
519 // Store the message, it will get processed later. |
|
520 iPendingMsg = aMessage; |
|
521 } |
|
522 else // EConnected |
|
523 { |
|
524 CompleteClient(aMessage, KErrNone); |
|
525 } |
|
526 |
|
527 } |
|
528 |
|
529 void CRemConControllerSession::ConnectBearerCancel(const RMessage2& aMessage) |
|
530 { |
|
531 LOG_FUNC; |
|
532 |
|
533 // Check we've had our features set... |
|
534 if (!ClientAvailable()) |
|
535 { |
|
536 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
537 return; |
|
538 } |
|
539 |
|
540 if ( iConnectBearerMsg.Handle() ) |
|
541 { |
|
542 CompleteClient(iConnectBearerMsg, KErrCancel); |
|
543 } |
|
544 else if ( iPendingMsg.Handle() && ( iPendingMsg.Function() == ERemConConnectBearer )) |
|
545 { |
|
546 CompleteClient(iPendingMsg, KErrCancel); |
|
547 } |
|
548 |
|
549 CompleteClient(aMessage, KErrNone); |
|
550 // At no point do we make any change to the processes going on underneath |
|
551 // us- 'Cancel' APIs are just for cancelling interest in an async |
|
552 // operation. |
|
553 } |
|
554 |
|
555 void CRemConControllerSession::DisconnectBearer(const RMessage2& aMessage) |
|
556 { |
|
557 LOG_FUNC; |
|
558 |
|
559 // Check we've had our features set... |
|
560 if (!ClientAvailable()) |
|
561 { |
|
562 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
563 return; |
|
564 } |
|
565 |
|
566 if ( iDisconnectBearerMsg.Handle() || iConnectBearerMsg.Handle() || iSendMsg.Handle()) |
|
567 { |
|
568 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
569 return; |
|
570 } |
|
571 |
|
572 if ( iRemoteAddress.IsNull() ) |
|
573 { |
|
574 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicNotConnectionOriented); |
|
575 return; |
|
576 } |
|
577 |
|
578 if (iSending != ENotSending) |
|
579 { |
|
580 DoSendCancel(); |
|
581 } |
|
582 EmptySendQueue(); |
|
583 |
|
584 // Check the requested bearer exists. |
|
585 TBool bearerExists = iBearerManager.BearerExists(iRemoteAddress.BearerUid()); |
|
586 // This check was done at GoConnectionOriented time. |
|
587 ASSERT_DEBUG(bearerExists); |
|
588 // So was this one. |
|
589 ASSERT_DEBUG(iBearerManager.CheckPolicy(iRemoteAddress.BearerUid(), aMessage)); |
|
590 |
|
591 // Check the state of the given connection. If it is: |
|
592 // -) connected, request connection to go away, |
|
593 // -) disconnected, compete the client's message, |
|
594 // -) connecting or disconnecting, add message to the queue of pending |
|
595 // messages, and process it once connecting/disconnecting has been completed |
|
596 |
|
597 TInt err; |
|
598 TConnectionState conState; |
|
599 conState = iServer.ConnectionState(iRemoteAddress); |
|
600 |
|
601 if ( conState == EConnected ) |
|
602 { |
|
603 // The bearer may indicate disconnection synchronously, so set this |
|
604 // message _before_ we ask them |
|
605 iDisconnectBearerMsg = aMessage; |
|
606 err = iBearerManager.Disconnect(iRemoteAddress); |
|
607 if ( err != KErrNone ) |
|
608 { |
|
609 CompleteClient(iDisconnectBearerMsg, err); |
|
610 } |
|
611 } |
|
612 else if ( conState == EDisconnecting || conState == EConnecting ) |
|
613 { |
|
614 if ( iPendingMsg.Handle() ) |
|
615 { |
|
616 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
617 return; |
|
618 } |
|
619 // Store the message, it will get processed later. |
|
620 iPendingMsg = aMessage; |
|
621 } |
|
622 else //disconnected |
|
623 { |
|
624 CompleteClient(aMessage, KErrNone); |
|
625 } |
|
626 } |
|
627 |
|
628 void CRemConControllerSession::DisconnectBearerCancel(const RMessage2& aMessage) |
|
629 { |
|
630 LOG_FUNC; |
|
631 |
|
632 // Check we've had our features set... |
|
633 if (!ClientAvailable()) |
|
634 { |
|
635 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
636 return; |
|
637 } |
|
638 |
|
639 if ( iDisconnectBearerMsg.Handle() ) |
|
640 { |
|
641 CompleteClient(iDisconnectBearerMsg, KErrCancel); |
|
642 } |
|
643 else if ( iPendingMsg.Handle() && (iPendingMsg.Function() == ERemConDisconnectBearer )) |
|
644 { |
|
645 CompleteClient(iPendingMsg, KErrCancel); |
|
646 } |
|
647 |
|
648 CompleteClient(aMessage, KErrNone); |
|
649 } |
|
650 |
|
651 /** |
|
652 Sends a notify message to the remote device. |
|
653 |
|
654 This function is intended for the RemCon controller client to send a notify |
|
655 command to the remote device. |
|
656 */ |
|
657 void CRemConControllerSession::SendNotify(const RMessage2& aMessage) |
|
658 { |
|
659 LOG_FUNC; |
|
660 |
|
661 // Check we're not already sending... |
|
662 if ( iSendMsg.Handle()) |
|
663 { |
|
664 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicSendAlreadyOutstanding); |
|
665 return; |
|
666 } |
|
667 |
|
668 iSendMsg = aMessage; |
|
669 |
|
670 // Check we've had our features set... |
|
671 if (!ClientAvailable()) |
|
672 { |
|
673 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicClientFeaturesNotSet); |
|
674 return; |
|
675 } |
|
676 |
|
677 // Check we don't have a disconnect outstanding- this makes no sense from |
|
678 // a client viewpoint (they should cancel the disconnect first). |
|
679 // [The client is allowed to have a connect request outstanding- the |
|
680 // bearer manager makes sure a bearer-level connect is not posted on the |
|
681 // same address twice.] |
|
682 if ( iDisconnectBearerMsg.Handle() ) |
|
683 { |
|
684 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBearerControlOutstanding); |
|
685 return; |
|
686 } |
|
687 |
|
688 TRAPD(err, DoSendNotifyL(aMessage)); |
|
689 if ( err != KErrNone ) |
|
690 { |
|
691 CompleteClient(aMessage, err); |
|
692 } |
|
693 } |
|
694 |
|
695 /** |
|
696 @see CRemConControllerSession::SendNotify |
|
697 */ |
|
698 void CRemConControllerSession::DoSendNotifyL(const RMessage2& aMessage) |
|
699 { |
|
700 LOG_FUNC; |
|
701 |
|
702 // Get the data the client wants to send. |
|
703 const TUid interfaceUid = TUid::Uid(aMessage.Int0()); |
|
704 LOG1(_L("\tinterfaceUid = 0x%08x"), interfaceUid); |
|
705 |
|
706 if (aMessage.GetDesLengthL(1) != sizeof(TOperationInformation)) |
|
707 { |
|
708 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor); |
|
709 return; |
|
710 } |
|
711 |
|
712 TPckgBuf<TOperationInformation> opInfoPckg; |
|
713 TInt err= aMessage.Read( |
|
714 1, // location of the descriptor in the client's message (as we expect them to have set it up) |
|
715 opInfoPckg, // descriptor to write to from client memory space |
|
716 0 // offset into our descriptor to put the client's data |
|
717 ); |
|
718 |
|
719 if ( err != KErrNone ) |
|
720 { |
|
721 LOG1(_L("\taMessage.Read = %d"), err); |
|
722 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor); |
|
723 return; |
|
724 } |
|
725 |
|
726 const TUint operationId = opInfoPckg().iOperationId; |
|
727 LOG1(_L("\toperationId = 0x%02x"), operationId); |
|
728 |
|
729 const TRemConMessageSubType messageSubType = opInfoPckg().iMessageSubType; |
|
730 LOG1(_L("\tmessageSubType = 0x%02x"), messageSubType); |
|
731 |
|
732 const TUint dataLength = (TUint)aMessage.GetDesLengthL(2); |
|
733 LOG1(_L("\tdataLength = %d"), dataLength); |
|
734 |
|
735 // If the client wanted to send some operation-associated data, read it |
|
736 // from them. |
|
737 RBuf8 sendDes; |
|
738 if ( dataLength != 0 ) |
|
739 { |
|
740 sendDes.CreateL(dataLength); |
|
741 TInt err = aMessage.Read( |
|
742 2, // location of the descriptor in the client's message (as we expect them to have set it up) |
|
743 sendDes, // descriptor to write to from client memory space |
|
744 0 // offset into our descriptor to put the client's data |
|
745 ); |
|
746 // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client |
|
747 // descriptor is a panicking offence for them, not an 'error the |
|
748 // request' offence. |
|
749 if ( err != KErrNone ) |
|
750 { |
|
751 LOG1(_L("\taMessage.Read = %d"), err); |
|
752 sendDes.Close(); |
|
753 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor); |
|
754 return; |
|
755 } |
|
756 } |
|
757 |
|
758 // Before we ask the server to send, we must set our ClientInfo |
|
759 // correctly so the TSP can get information about the client. |
|
760 iClientInfo.Message() = aMessage; |
|
761 |
|
762 CRemConMessage* msg = NULL; |
|
763 |
|
764 if (messageSubType != ERemConNotifyCommandAwaitingInterim) |
|
765 { |
|
766 sendDes.Close(); |
|
767 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc); |
|
768 return; |
|
769 } |
|
770 |
|
771 CleanupClosePushL(sendDes); |
|
772 msg = CRemConMessage::NewL( |
|
773 iRemoteAddress, // either specified (if we're connection-oriented) or null (we're connectionless- this field will be filled in by the TSP) |
|
774 ERemConNotifyCommand, |
|
775 messageSubType, |
|
776 interfaceUid, |
|
777 operationId, |
|
778 sendDes, // msg takes ownership |
|
779 Id(), // session id for when the response comes back |
|
780 0, // we let the bearer manager invent a new transaction id when the message gets to it |
|
781 ETrue); |
|
782 CLEANUPSTACK_POP1(&sendDes); // now owned by msg |
|
783 |
|
784 LOG(_L("\tCONTROLLER send")); |
|
785 ASSERT_DEBUG(iSendQueue); |
|
786 if (iSending != ENotSending || !iSendQueue->IsEmpty()) |
|
787 { |
|
788 iSendQueue->Append(*msg); |
|
789 } |
|
790 else |
|
791 { |
|
792 SendToServer(*msg); |
|
793 } |
|
794 } |
|
795 |
|
796 void CRemConControllerSession::SendToServer(CRemConMessage& aMsg) |
|
797 { |
|
798 LOG_FUNC; |
|
799 |
|
800 // Set our completion members. |
|
801 NumRemotes() = 0; |
|
802 NumRemotesToTry() = 0; |
|
803 SendError() = KErrNone; |
|
804 |
|
805 |
|
806 iSending = (aMsg.IsReliableSend()) ? ESendingReliable: ESendingUnreliable; |
|
807 |
|
808 iServer.SendCommand(aMsg); |
|
809 } |
|
810 |
|
811 void CRemConControllerSession::EmptySendQueue() |
|
812 { |
|
813 LOG_FUNC; |
|
814 |
|
815 ASSERT_DEBUG(!iSendMsg.Handle()) |
|
816 ASSERT_DEBUG(iSendNextCallBack); |
|
817 iSendNextCallBack->Cancel(); |
|
818 CRemConMessage* msg; |
|
819 ASSERT_DEBUG(iSendQueue); |
|
820 TSglQueIter<CRemConMessage>& iter = iSendQueue->SetToFirst(); |
|
821 while ((msg = iter++) != NULL) |
|
822 { |
|
823 iSendQueue->RemoveAndDestroy(*msg); |
|
824 } |
|
825 } |
|
826 |
|
827 void CRemConControllerSession::DoSendCancel() |
|
828 { |
|
829 LOG_FUNC; |
|
830 // We must tell the server, and pull the CRemConMessage from the |
|
831 // 'outgoing pending TSP' queue if it's on it. If the TSP is currently |
|
832 // processing the CRemConMessage, we must tell it to stop before we |
|
833 // can complete the RMessage2 iSendMsg- the TSP might still be |
|
834 // dereferencing bits of it. (The TSP is given iSendMsg so it can |
|
835 // access the client's secure ID and do a capability check.) |
|
836 // NB This only matters for commands- responses don't go through the |
|
837 // TSP. |
|
838 // Not also that this processing *stops* this |
|
839 // CRemConSession::SendCancel method from being the very simple 'I'm |
|
840 // no longer interested in the completion of the asynchronous request' |
|
841 // type of API it (and all cancels) should be. It actually does work |
|
842 // as well. As long as this work is implemented _synchronously_, we |
|
843 // should be OK. |
|
844 iServer.SendCancel(*this); |
|
845 |
|
846 NumRemotesToTry() = 0; |
|
847 iSendError = KErrCancel; |
|
848 CompleteSend(); |
|
849 } |
|
850 |
|
851 void CRemConControllerSession::CompleteMessage(const CRemConMessage& aMessage) |
|
852 { |
|
853 LOG_FUNC; |
|
854 |
|
855 switch (aMessage.MsgType()) |
|
856 { |
|
857 case ERemConCommand: |
|
858 case ERemConResponse: |
|
859 case ERemConReject: |
|
860 { |
|
861 CompleteSend(); |
|
862 break; |
|
863 } |
|
864 case ERemConNotifyCommand: |
|
865 { |
|
866 CompleteSendNotify(); |
|
867 break; |
|
868 } |
|
869 default: |
|
870 ASSERT_DEBUG(EFalse); |
|
871 break; |
|
872 } |
|
873 |
|
874 } |
|
875 |
|
876 void CRemConControllerSession::DoReceive() |
|
877 { |
|
878 // Request messages from the server for this controller session. |
|
879 // If there's anything waiting to be given to us, ReceiveRequest will call |
|
880 // back to us with it. |
|
881 iServer.ReceiveRequest(*this); |
|
882 } |
|
883 |
|
884 void CRemConControllerSession::MrcmsoMessageSendResult(const CRemConMessage& aMessage, TInt aError) |
|
885 { |
|
886 LOG_FUNC; |
|
887 |
|
888 // We should not already be sending a message to n remotes |
|
889 ASSERT_DEBUG(NumRemotesToTry() == 0); |
|
890 |
|
891 SendError() = aError; |
|
892 CompleteMessage(aMessage); |
|
893 } |
|
894 |
|
895 void CRemConControllerSession::MrcmsoMessageSendOneOrMoreAttempt(const CRemConMessage& /*aMessage*/, TUint aNumRemotes) |
|
896 { |
|
897 LOG_FUNC; |
|
898 |
|
899 // We should not already be sending a message |
|
900 ASSERT_DEBUG(NumRemotesToTry() == 0); |
|
901 |
|
902 NumRemotes() = 0; |
|
903 NumRemotesToTry() = aNumRemotes; |
|
904 SendError() = KErrNone; |
|
905 } |
|
906 |
|
907 void CRemConControllerSession::MrcmsoMessageSendOneOrMoreIncremental(const CRemConMessage& /*aMessage*/, TUint /*aNumRemotes*/) |
|
908 { |
|
909 LOG_FUNC; |
|
910 |
|
911 // This method should never be called, as it is not required to support controller sessions. |
|
912 ASSERT_DEBUG(EFalse); |
|
913 } |
|
914 |
|
915 void CRemConControllerSession::MrcmsoMessageSendOneOrMoreAttemptFailed(const CRemConMessage& aMessage, TInt aError) |
|
916 { |
|
917 LOG_FUNC; |
|
918 |
|
919 // We should not already be sending a message |
|
920 ASSERT_DEBUG(NumRemotesToTry() == 0); |
|
921 |
|
922 NumRemotes() = 0; |
|
923 SendError() = aError; |
|
924 CompleteMessage(aMessage); |
|
925 } |
|
926 |
|
927 void CRemConControllerSession::MrcmsoMessageSendOneOrMoreResult(const CRemConMessage& aMessage, TInt aError) |
|
928 { |
|
929 LOG_FUNC; |
|
930 |
|
931 // Ignore notification if client has been completed |
|
932 if (NumRemotesToTry() > 0) |
|
933 { |
|
934 // Only set error if different from KErrNone |
|
935 if (aError == KErrNone) |
|
936 { |
|
937 ++NumRemotes(); |
|
938 } |
|
939 else |
|
940 { |
|
941 SendError() = aError; |
|
942 } |
|
943 |
|
944 --NumRemotesToTry(); |
|
945 if (NumRemotesToTry() == 0) |
|
946 { |
|
947 CompleteMessage(aMessage); |
|
948 } |
|
949 } |
|
950 } |
|
951 |
|
952 void CRemConControllerSession::MrcmsoMessageSendOneOrMoreAbandoned(const CRemConMessage& /*aMessage*/) |
|
953 { |
|
954 LOG_FUNC; |
|
955 |
|
956 // This method should never be called, as it is not required to support controller sessions. |
|
957 ASSERT_DEBUG(EFalse); |
|
958 } |