|
1 // Copyright (c) 2008-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 // Remote Control bulk session implementation. |
|
15 // |
|
16 |
|
17 |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalComponent |
|
22 */ |
|
23 #include "bulksession.h" |
|
24 #include "remconserver.h" |
|
25 |
|
26 #include "bulkserver.h" |
|
27 #include "remconmessage.h" |
|
28 #include "utils.h" |
|
29 |
|
30 #include "messagequeue.h" |
|
31 |
|
32 #include <bluetooth/logger.h> |
|
33 |
|
34 #ifdef __FLOG_ACTIVE |
|
35 _LIT8(KLogComponent, LOG_COMPONENT_REMCON_SERVER); |
|
36 #endif |
|
37 |
|
38 #ifdef _DEBUG |
|
39 PANICCATEGORY("bulksess"); |
|
40 #endif |
|
41 |
|
42 CRemConBulkSession* CRemConBulkSession::NewL(CRemConBulkServer& aServer, |
|
43 const RMessage2& aMessage) |
|
44 { |
|
45 LOG_STATIC_FUNC; |
|
46 CRemConBulkSession* self = new(ELeave) CRemConBulkSession(aServer); |
|
47 CleanupStack::PushL(self); |
|
48 self->ConstructL(aMessage); |
|
49 CLEANUPSTACK_POP1(self); |
|
50 return self; |
|
51 } |
|
52 |
|
53 CRemConBulkSession::CRemConBulkSession(CRemConBulkServer& aServer) |
|
54 : iServer(aServer), |
|
55 iId(KNullClientId) |
|
56 { |
|
57 LOG_FUNC; |
|
58 } |
|
59 |
|
60 void CRemConBulkSession::ConstructL(const RMessage2& aMessage) |
|
61 { |
|
62 LOG_FUNC; |
|
63 |
|
64 // Get the client's process ID. |
|
65 RThread thread; |
|
66 LEAVEIFERRORL(aMessage.Client(thread)); |
|
67 CleanupClosePushL(thread); |
|
68 RProcess process; |
|
69 LEAVEIFERRORL(thread.Process(process)); |
|
70 iClientInfo.ProcessId() = process.Id(); |
|
71 process.Close(); |
|
72 iClientInfo.SecureId() = thread.SecureId(); |
|
73 CleanupStack::PopAndDestroy(&thread); |
|
74 |
|
75 // Tell the server about us. |
|
76 LEAVEIFERRORL(iServer.ClientOpened(*this, iClientInfo.ProcessId())); |
|
77 } |
|
78 |
|
79 CRemConBulkSession::~CRemConBulkSession() |
|
80 { |
|
81 LOG_FUNC; |
|
82 |
|
83 iInterestedAPIs.Close(); |
|
84 |
|
85 // Tell the server we've gone away- it may start its shutdown timer. |
|
86 iServer.ClientClosed(*this); |
|
87 } |
|
88 |
|
89 void CRemConBulkSession::ServiceL(const RMessage2& aMessage) |
|
90 { |
|
91 LOG_FUNC; |
|
92 LOG1(_L8("\taMessage.Function() = %d"), aMessage.Function()); |
|
93 |
|
94 // Switch on the IPC number and call a 'message handler'. Message handlers |
|
95 // complete aMessage (either with Complete or Panic), or make a note of |
|
96 // the message for later asynchronous completion. |
|
97 // Message handlers should not leave- the server does not have an Error |
|
98 // function. |
|
99 |
|
100 switch ( aMessage.Function() ) |
|
101 { |
|
102 // Heap failure testing APIs. |
|
103 case ERemConBulkDbgMarkHeap: |
|
104 #ifdef _DEBUG |
|
105 LOG(_L8("\tmark heap")); |
|
106 __UHEAP_MARK; |
|
107 #endif // _DEBUG |
|
108 CompleteClient(aMessage, KErrNone); |
|
109 break; |
|
110 |
|
111 case ERemConBulkDbgCheckHeap: |
|
112 #ifdef _DEBUG |
|
113 LOG1(_L8("\tcheck heap (expecting %d cells)"), aMessage.Int0()); |
|
114 __UHEAP_CHECK(aMessage.Int0()); |
|
115 #endif // _DEBUG |
|
116 CompleteClient(aMessage, KErrNone); |
|
117 break; |
|
118 |
|
119 case ERemConBulkDbgMarkEnd: |
|
120 #ifdef _DEBUG |
|
121 LOG1(_L8("\tmark end (expecting %d cells)"), aMessage.Int0()); |
|
122 __UHEAP_MARKENDC(aMessage.Int0()); |
|
123 #endif // _DEBUG |
|
124 CompleteClient(aMessage, KErrNone); |
|
125 break; |
|
126 |
|
127 case ERemConBulkDbgFailNext: |
|
128 #ifdef _DEBUG |
|
129 { |
|
130 LOG1(_L8("\tfail next (simulating failure after %d allocation(s))"), aMessage.Int0()); |
|
131 if ( aMessage.Int0() == 0 ) |
|
132 { |
|
133 __UHEAP_RESET; |
|
134 } |
|
135 else |
|
136 { |
|
137 __UHEAP_FAILNEXT(aMessage.Int0()); |
|
138 } |
|
139 } |
|
140 #endif // _DEBUG |
|
141 CompleteClient(aMessage, KErrNone); |
|
142 break; |
|
143 |
|
144 case ERemConBulkSend: |
|
145 Send(aMessage); |
|
146 break; |
|
147 |
|
148 case ERemConBulkSendUnreliable: |
|
149 SendUnreliable(aMessage); |
|
150 break; |
|
151 |
|
152 case ERemConBulkSendCancel: |
|
153 SendCancel(aMessage); |
|
154 ASSERT_DEBUG(aMessage.Handle() == 0); |
|
155 break; |
|
156 |
|
157 case ERemConBulkReceive: |
|
158 Receive(aMessage); |
|
159 break; |
|
160 |
|
161 case ERemConBulkReceiveCancel: |
|
162 ReceiveCancel(aMessage); |
|
163 ASSERT_DEBUG(aMessage.Handle() == 0); |
|
164 break; |
|
165 |
|
166 default: |
|
167 // Unknown message |
|
168 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicIllegalIpc); |
|
169 break; |
|
170 } |
|
171 } |
|
172 |
|
173 void CRemConBulkSession::CompleteClient(const RMessage2& aMessage, TInt aError) |
|
174 { |
|
175 LOG1(_L("\tcompleting client message with %d"), aError); |
|
176 TBool cleanClientInfoMessage = (iClientInfo.Message().Handle() == aMessage.Handle()); |
|
177 aMessage.Complete(aError); |
|
178 if(cleanClientInfoMessage) |
|
179 { |
|
180 iClientInfo.Message() = RMessage2(); |
|
181 } |
|
182 } |
|
183 |
|
184 TInt CRemConBulkSession::WriteMessageToClient(const CRemConMessage& aMsg) |
|
185 { |
|
186 LOG_FUNC; |
|
187 |
|
188 ASSERT_DEBUG(iReceiveMsg.Handle()); |
|
189 |
|
190 TInt err = KErrNone; |
|
191 TPckg<TUint> uid(aMsg.InterfaceUid().iUid); |
|
192 |
|
193 //check if our client is interested in this API |
|
194 //Only need to check commands because it is safe to assume that we are interested |
|
195 //in the response if we have sent out a command. |
|
196 |
|
197 if(aMsg.MsgType() == ERemConCommand && iInterestedAPIs.Find(aMsg.InterfaceUid())==KErrNotFound) |
|
198 { |
|
199 //The server will clean up the resource allocated for this msg |
|
200 err = KErrArgument; |
|
201 } |
|
202 else |
|
203 { |
|
204 err = iReceiveMsg.Write(0, uid); |
|
205 } |
|
206 |
|
207 if ( err == KErrNone ) |
|
208 { |
|
209 TPckg<TUint> opId(aMsg.OperationId()); |
|
210 err = iReceiveMsg.Write(1, opId); |
|
211 if ( err == KErrNone ) |
|
212 { |
|
213 // This logging code left in for maintenance. |
|
214 //LOG1(_L8("\t\tOperationData = \"%S\""), &aMsg.OperationData()); |
|
215 // Note that we do not panic the client if their descriptor is not |
|
216 // big enough to hold the operation-specific data. If we did, then |
|
217 // a buggy remote could take down a client of RemCon. Just error |
|
218 // the client instead. |
|
219 err = iReceiveMsg.Write(2, aMsg.OperationData()); |
|
220 } |
|
221 } |
|
222 |
|
223 CompleteClient(iReceiveMsg, err); |
|
224 LOG1(_L8("\terr = %d"), err); |
|
225 |
|
226 return err; |
|
227 } |
|
228 |
|
229 void CRemConBulkSession::Receive(const RMessage2& aMessage) |
|
230 { |
|
231 LOG_FUNC; |
|
232 |
|
233 if ( iReceiveMsg.Handle() ) |
|
234 { |
|
235 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicReceiveAlreadyOutstanding); |
|
236 return; |
|
237 } |
|
238 |
|
239 iReceiveMsg = aMessage; |
|
240 // If there's anything waiting to be given to us, ReceiveRequest will call |
|
241 // back to us with it. |
|
242 iServer.ReceiveRequest(*this); |
|
243 } |
|
244 |
|
245 void CRemConBulkSession::ReceiveCancel(const RMessage2& aMessage) |
|
246 { |
|
247 LOG_FUNC; |
|
248 |
|
249 if ( iReceiveMsg.Handle() ) |
|
250 { |
|
251 CompleteClient(iReceiveMsg, KErrCancel); |
|
252 } |
|
253 CompleteClient(aMessage, KErrNone); |
|
254 // At no point do we make any change to the processes going on underneath |
|
255 // us- 'Cancel' APIs are just for cancelling interest in an async |
|
256 // operation. |
|
257 } |
|
258 |
|
259 void CRemConBulkSession::Send(const RMessage2& aMessage) |
|
260 { |
|
261 LOG_FUNC; |
|
262 TRAPD(err, DoSendL(aMessage)); |
|
263 CompleteClient(aMessage, err); |
|
264 } |
|
265 |
|
266 void CRemConBulkSession::DoSendL(const RMessage2& aMessage) |
|
267 { |
|
268 LOG_FUNC; |
|
269 |
|
270 CRemConMessage* msg = DoCreateMessageL(aMessage, ETrue); |
|
271 LEAVEIFERRORL(SendToServer(*msg)); |
|
272 } |
|
273 |
|
274 void CRemConBulkSession::SendUnreliable(const RMessage2& aMessage) |
|
275 { |
|
276 LOG_FUNC; |
|
277 |
|
278 CRemConMessage* msg = NULL; |
|
279 TRAPD(err, msg = DoCreateMessageL(aMessage, EFalse)); |
|
280 CompleteClient(aMessage, err); |
|
281 if (err == KErrNone) |
|
282 { |
|
283 static_cast<void>(SendToServer(*msg)); // unreliable so ignore error. |
|
284 } |
|
285 } |
|
286 |
|
287 CRemConMessage* CRemConBulkSession::DoCreateMessageL(const RMessage2& aMessage, TBool aReliable) |
|
288 { |
|
289 LOG_FUNC; |
|
290 |
|
291 // Get the data the client wants to send. |
|
292 const TUid interfaceUid = TUid::Uid(aMessage.Int0()); |
|
293 LOG1(_L8("\tinterfaceUid = 0x%08x"), interfaceUid); |
|
294 |
|
295 const TUint operationId = aMessage.Int1(); |
|
296 LOG1(_L8("\toperationId = 0x%08x"), operationId); |
|
297 |
|
298 const TUint dataLength = (TUint)aMessage.GetDesLengthL(2); |
|
299 LOG1(_L8("\tdataLength = %d"), dataLength); |
|
300 |
|
301 // If the client wanted to send some operation-associated data, read it |
|
302 // from them. |
|
303 RBuf8 sendDes; |
|
304 if ( dataLength != 0 ) |
|
305 { |
|
306 sendDes.CreateL(dataLength); |
|
307 TInt err = aMessage.Read( |
|
308 2, // location of the descriptor in the client's message (as we expect them to have set it up) |
|
309 sendDes, // descriptor to write to from client memory space |
|
310 0 // offset into our descriptor to put the client's data |
|
311 ); |
|
312 // NB We don't do LEAVEIFERRORL(aMessage.Read) because a bad client |
|
313 // descriptor is a panicking offence for them, not an 'error the |
|
314 // request' offence. |
|
315 if ( err != KErrNone ) |
|
316 { |
|
317 LOG1(_L8("\taMessage.Read = %d"), err); |
|
318 sendDes.Close(); |
|
319 PANIC_MSG(aMessage, KRemConClientPanicCat, ERemConClientPanicBadDescriptor); |
|
320 LEAVEL(KErrBadDescriptor); |
|
321 } |
|
322 } |
|
323 CleanupClosePushL(sendDes); |
|
324 |
|
325 CRemConMessage* msg = CRemConMessage::NewL( |
|
326 TRemConAddress(), // we don't know which remotes it's going to yet |
|
327 ERemConResponse, // targets can only send responses |
|
328 ERemConMessageDefault, |
|
329 interfaceUid, |
|
330 operationId, |
|
331 sendDes, // msg takes ownership |
|
332 Id(), // session id to match this response against the originating command |
|
333 0, // transaction id not yet known |
|
334 aReliable); |
|
335 CLEANUPSTACK_POP1(&sendDes); // now owned by msg |
|
336 |
|
337 iClientInfo.Message() = aMessage; |
|
338 |
|
339 return msg; |
|
340 } |
|
341 |
|
342 TInt CRemConBulkSession::SendToServer(CRemConMessage& aMsg) |
|
343 { |
|
344 LOG_FUNC; |
|
345 return iServer.SendResponse(aMsg, *this); |
|
346 } |
|
347 |
|
348 void CRemConBulkSession::SendCancel(const RMessage2& aMessage) |
|
349 { |
|
350 LOG_FUNC; |
|
351 |
|
352 // This is left as an actual function on the server for interface |
|
353 // reasons. In fact the sending is (unlike in the control server) |
|
354 // processed synchronously - so currently there is never be anything |
|
355 // to cancel when this arrives. |
|
356 |
|
357 CompleteClient(aMessage, KErrNone); |
|
358 } |
|
359 |