|
1 /* |
|
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Implements CScsServer functionality. See class and functions definitions |
|
16 * for more detail. |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 /** |
|
22 @file |
|
23 */ |
|
24 |
|
25 #include <scs/scsserver.h> |
|
26 #include "scsserverconstants.h" |
|
27 |
|
28 static const TInt defaultPolicyRangeCount = 1; |
|
29 static const TInt defaultPolicyRanges[defaultPolicyRangeCount] = |
|
30 { |
|
31 0 // All requests |
|
32 }; |
|
33 |
|
34 static const TUint8 defaultPolicyElementsIndex[defaultPolicyRangeCount] = |
|
35 { |
|
36 CPolicyServer::EAlwaysPass |
|
37 }; |
|
38 |
|
39 static const CPolicyServer::TPolicyElement defaultPolicyPolicyElements[1] = {}; |
|
40 |
|
41 |
|
42 static const CPolicyServer::TPolicy defaultPolicy = |
|
43 { |
|
44 CPolicyServer::EAlwaysPass, // Allow all connects |
|
45 defaultPolicyRangeCount, |
|
46 defaultPolicyRanges, |
|
47 defaultPolicyElementsIndex, |
|
48 defaultPolicyPolicyElements, |
|
49 }; |
|
50 |
|
51 EXPORT_C CScsServer::CScsServer(const TVersion& aVersion, CActive::TPriority aPriority) |
|
52 /** |
|
53 Record this server's version so it can be compared against the requested |
|
54 version in NewSessionL. |
|
55 |
|
56 @param aVersion This server's version. This is compared against each |
|
57 client's requested version when the client tries to connect. |
|
58 @param aPriority This server's active object priority. |
|
59 */ |
|
60 : CPolicyServer(aPriority, defaultPolicy, ESharableSessions) |
|
61 ,iVersion(aVersion) |
|
62 // ,iSessionCount(0) |
|
63 { |
|
64 // empty. |
|
65 } |
|
66 |
|
67 EXPORT_C CScsServer::CScsServer(const TVersion& aVersion, const CPolicyServer::TPolicy& aPolicy, CActive::TPriority aPriority) |
|
68 /** |
|
69 Record this server's version so it can be compared against the requested |
|
70 version in NewSessionL. |
|
71 |
|
72 @param aVersion This server's version. This is compared against each |
|
73 client's requested version when the client tries to connect. |
|
74 @param aPolicy Can be used to configure security for server connect and session functions |
|
75 @param aPriority This server's active object priority. |
|
76 |
|
77 Note that aPolicy must be configured to allow all functions |
|
78 covered by the KScsFunctionMask mask. |
|
79 */ |
|
80 : CPolicyServer(aPriority, aPolicy, ESharableSessions) |
|
81 ,iVersion(aVersion) |
|
82 // ,iSessionCount(0) |
|
83 { |
|
84 // empty. |
|
85 } |
|
86 |
|
87 EXPORT_C void CScsServer::ConstructL(TInt aShutdownPeriodUs) |
|
88 /** |
|
89 Second-phase constructor allocates the shutdown timer for this server object. |
|
90 |
|
91 If aShutdownPeriodUs is not 0, this function starts the shutdown |
|
92 timer because the server starts up with no current sessions. |
|
93 |
|
94 If aShutdownPeriodUs is 0, the timer is not started and the server |
|
95 will not auto-exit. |
|
96 |
|
97 nb. It must be called, even if you do not want a shutdown timer. |
|
98 |
|
99 This function does not start the server, i.e. it does not call StartL. The |
|
100 calling function must do this after this function returns. |
|
101 |
|
102 @param aShutdownPeriodUs Shutdown period in microseconds. |
|
103 */ |
|
104 { |
|
105 if(aShutdownPeriodUs > 0) |
|
106 { |
|
107 iShutdownTimer = CShutdownTimer::NewL(aShutdownPeriodUs); |
|
108 iShutdownTimer->Restart(); |
|
109 } |
|
110 |
|
111 iContainerIndex = CObjectConIx::NewL(); |
|
112 |
|
113 TCallBack cb(RemoveCompletedRequests, this); |
|
114 // EPriorityHigh to encourage the active scheduler to action the |
|
115 // delete ASAP, in particular ahead of pending or new requests. |
|
116 iAsyncCleanup = new(ELeave) CAsyncCallBack(cb, CActive::EPriorityHigh); |
|
117 } |
|
118 |
|
119 |
|
120 EXPORT_C void CScsServer::DisableShutdownTimer() |
|
121 /** |
|
122 The server will no longer shutdown after the last client session closes. |
|
123 Client calls to RScsClientBase::ShutdownServer will fail with KErrNotSupported. |
|
124 */ |
|
125 { |
|
126 if(iShutdownTimer) |
|
127 { |
|
128 iShutdownTimer->Cancel(); |
|
129 } |
|
130 delete iShutdownTimer; |
|
131 iShutdownTimer = 0; |
|
132 } |
|
133 |
|
134 EXPORT_C void CScsServer::EnableShutdownTimerL(TInt aShutdownPeriodUs) |
|
135 /** |
|
136 Enable shutdown timer support in the server. |
|
137 If there are currently no client sessions the timer will be immediately started, otherwise |
|
138 it will be started when the last client session closes. |
|
139 If the timer expires, before another client creates a session, the server will shutdown. |
|
140 The RScsClientBase::ShutdownServer api will now be supported, if called the server timeout |
|
141 will effectively be reduced to 0. |
|
142 */ |
|
143 { |
|
144 if(aShutdownPeriodUs <= 0) |
|
145 { |
|
146 return; |
|
147 } |
|
148 DisableShutdownTimer(); |
|
149 iShutdownTimer = CShutdownTimer::NewL(aShutdownPeriodUs); |
|
150 if(iSessionCount == 0) |
|
151 { |
|
152 iShutdownTimer->Restart(); |
|
153 } |
|
154 } |
|
155 |
|
156 |
|
157 EXPORT_C CScsServer::~CScsServer() |
|
158 /** |
|
159 Frees resources used at this level. Specifically, frees the |
|
160 container index, which is used to generate subsession containers, |
|
161 the shutdown timer, and the async request cleanup object. |
|
162 */ |
|
163 { |
|
164 __ASSERT_DEBUG(iSessionCount == 0, PanicServer(ESvrRemSessions)); |
|
165 __ASSERT_DEBUG(iAsyncCleanup == 0 || !iAsyncCleanup->IsActive(), PanicServer(ESvrRemCleanup)); |
|
166 __ASSERT_DEBUG(iAsyncRequests.Count() == 0, PanicServer(ESvrRemRequests)); |
|
167 |
|
168 delete iContainerIndex; |
|
169 delete iShutdownTimer; |
|
170 |
|
171 delete iAsyncCleanup; |
|
172 iAsyncRequests.Reset(); |
|
173 } |
|
174 |
|
175 // -------- sessions -------- |
|
176 |
|
177 EXPORT_C CSession2* CScsServer::NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const |
|
178 /** |
|
179 Implement CServer2 by allocating a new session object. This function |
|
180 delegates the actual allocation to the subclass. Before creating the |
|
181 session object, it compares the requested version with its own version. |
|
182 After creating the session object, it increments the session count, which |
|
183 reset the shutdown timer if it is the only session. |
|
184 |
|
185 @param aVersion Version of server which client requires. |
|
186 @param aMessage Connect message. |
|
187 @return New initialized instance of CSession2 subclass. |
|
188 */ |
|
189 { |
|
190 TBool versionOk = User::QueryVersionSupported(/* aCurrent */ iVersion, /* aRequested */ aVersion); |
|
191 if (! versionOk) |
|
192 User::Leave(KErrNotSupported); |
|
193 |
|
194 CScsSession* s = const_cast<CScsServer*>(this)->DoNewSessionL(aMessage); |
|
195 |
|
196 return s; |
|
197 } |
|
198 |
|
199 EXPORT_C void CScsServer::DoPreHeapMarkOrCheckL() |
|
200 { |
|
201 } |
|
202 |
|
203 EXPORT_C void CScsServer::DoPostHeapMarkOrCheckL() |
|
204 { |
|
205 } |
|
206 |
|
207 void CScsServer::IncrementSessionCount() |
|
208 /** |
|
209 Record the fact that another session has been created. If this new |
|
210 session is the only session then cancel the shutdown timer. |
|
211 */ |
|
212 { |
|
213 ++iSessionCount; |
|
214 if (iSessionCount == 1) |
|
215 { |
|
216 if(iShutdownTimer) |
|
217 { |
|
218 iShutdownTimer->Cancel(); |
|
219 } |
|
220 } |
|
221 } |
|
222 |
|
223 void CScsServer::DecrementSessionCount() |
|
224 /** |
|
225 Record the fact that a session has been deleted. If this was the |
|
226 only remaining session then start the shutdown timer. |
|
227 |
|
228 Note the shutdown timer may be deferred if a request cleanup is |
|
229 pending. |
|
230 */ |
|
231 { |
|
232 --iSessionCount; |
|
233 if (iShutdownTimer && (iSessionCount == 0) && (! iAsyncCleanup->IsActive())) |
|
234 { |
|
235 iShutdownTimer->Restart(); |
|
236 } |
|
237 } |
|
238 |
|
239 EXPORT_C void CScsServer::ShutdownWhenIdleL() |
|
240 /** |
|
241 Shutdown immediately when server is next idle. If the server |
|
242 is not transient (ie. has no shutdown timer), this call is |
|
243 prohibited and will leave with KErrNotSupported. |
|
244 */ |
|
245 { |
|
246 if(! iShutdownTimer) |
|
247 { |
|
248 // We do not allow shutdown of non-transient servers. |
|
249 User::Leave(KErrNotSupported); |
|
250 } |
|
251 |
|
252 // Next time we are idle, shutdown immediately. |
|
253 iShutdownTimer->ImmediateTimeoutNextRestart(); |
|
254 } |
|
255 |
|
256 |
|
257 |
|
258 // -------- asynchronous requests -------- |
|
259 |
|
260 CAsyncRequest* CScsServer::FindAsyncRequest( |
|
261 CScsSession* aSession, CScsSubsession* aSubsession, TInt aFunction) |
|
262 /** |
|
263 Find the outstanding request which matches the supplied criteria. |
|
264 |
|
265 @param aSession Session which hosts the request. |
|
266 @param aSubsession Subsession which hosts the request, NULL if |
|
267 the request is relative to a session. |
|
268 @param aFunction The function identifier, without any SCS code. |
|
269 @return The matching asynchronous request, NULL if not |
|
270 found. |
|
271 */ |
|
272 { |
|
273 TInt reqCount = iAsyncRequests.Count(); |
|
274 for (TInt i = reqCount - 1; i >= 0; --i) |
|
275 { |
|
276 CAsyncRequest* req = iAsyncRequests[i]; |
|
277 |
|
278 if (req->iSession != aSession) |
|
279 continue; |
|
280 |
|
281 if (req->iSubsession != aSubsession) |
|
282 continue; |
|
283 |
|
284 if (req->iFunction != aFunction) |
|
285 continue; |
|
286 |
|
287 return req; |
|
288 } |
|
289 |
|
290 return 0; // request not found |
|
291 } |
|
292 |
|
293 void CScsServer::AddAsyncRequestL(CAsyncRequest* aAsyncRequest) |
|
294 /** |
|
295 Add the supplied request to the server's collection. |
|
296 |
|
297 @param aAsyncRequest Request to add. If this function succeeds |
|
298 then ownership has been transferred to the |
|
299 collection. |
|
300 */ |
|
301 { |
|
302 // ensure this session does not already have an outstanding request |
|
303 // for the same function |
|
304 CAsyncRequest* existReq = FindAsyncRequest( |
|
305 aAsyncRequest->iSession, aAsyncRequest->iSubsession, |
|
306 aAsyncRequest->iFunction); |
|
307 |
|
308 if (existReq != 0) |
|
309 User::Leave(KErrScsAsyncAlreadyQueued); |
|
310 |
|
311 iAsyncRequests.AppendL(aAsyncRequest); |
|
312 } |
|
313 |
|
314 void CScsServer::CancelAsyncRequest( |
|
315 CScsSession* aSession, CScsSubsession* aSubsession, TInt aFunction) |
|
316 /** |
|
317 Cancels a specific (sub)session request in response to a client |
|
318 command. Also completes the client request. |
|
319 |
|
320 CancelOutstandingRequest should be called when a (sub)session is closed. |
|
321 |
|
322 @param aSession Session which hosts the request. |
|
323 @param aSubsession Subsession which hosts the request, NULL if |
|
324 the request is relative to a session. |
|
325 @param aFunction The function identifier, without any SCS code. |
|
326 */ |
|
327 { |
|
328 CAsyncRequest* req = FindAsyncRequest(aSession, aSubsession, aFunction); |
|
329 |
|
330 // not an error if the request is not queued; could have been |
|
331 // completed before the cancel function was processed. |
|
332 if (req != 0) |
|
333 req->CancelCompleteAndMarkForDeletion(); |
|
334 } |
|
335 |
|
336 void CScsServer::CancelOutstandingRequests(CScsSession* aSession, TBool aCompleteClientRequests) |
|
337 /** |
|
338 Cancels and deletes all outstanding asynchronous requests associated |
|
339 with the supplied session or any of its subsessions. Does not complete |
|
340 the associated client requests. |
|
341 |
|
342 This function should be called when a session is closed. |
|
343 CancelAsyncRequest should be called when a specific request is cancelled. |
|
344 |
|
345 @param aSession Session which is being closed. |
|
346 @param aCompleteClientRequests Whether to complete the client-side requests |
|
347 with KErrCancel. |
|
348 */ |
|
349 { |
|
350 CancelOutstandingRequests(aSession, KWildSubsession, aCompleteClientRequests); |
|
351 } |
|
352 |
|
353 void CScsServer::CancelOutstandingRequests(CScsSession* aSession, CScsSubsession* aSubsession, TBool aCompleteClientRequests) |
|
354 /** |
|
355 Cancels and deletes all outstanding asynchronous requests associated |
|
356 with the supplied session and subsession. This should be called when |
|
357 a session or subsession is closed. |
|
358 |
|
359 As an exception, the user-side request is completed when a subsession is |
|
360 closed, else the request would not be completed until the session itself |
|
361 was destroyed. |
|
362 |
|
363 CancelAsyncRequest should be called when a specific request is cancelled. |
|
364 |
|
365 @param aSession Session which is being closed. |
|
366 @param aSubsession Subsession which is being closed. If this is |
|
367 KWildSubsession then a session is being closed so all of |
|
368 its subsession requests should be destroyed as well. |
|
369 @param aCompleteClientRequests Whether to complete the client-side requests |
|
370 with KErrCancel. |
|
371 */ |
|
372 { |
|
373 TBool wildSubsession = (aSubsession == KWildSubsession); |
|
374 |
|
375 TInt reqCount = iAsyncRequests.Count(); |
|
376 for (TInt i = reqCount - 1; i >= 0; --i) |
|
377 { |
|
378 CAsyncRequest* req = iAsyncRequests[i]; |
|
379 |
|
380 TBool sessionMatch = (req->iSession == aSession); |
|
381 if (! sessionMatch) |
|
382 continue; |
|
383 |
|
384 TBool subsessionMatch = wildSubsession || (req->iSubsession == aSubsession); |
|
385 if (! subsessionMatch) |
|
386 continue; |
|
387 |
|
388 if (aCompleteClientRequests) |
|
389 req->CancelCompleteAndMarkForDeletion(); |
|
390 else |
|
391 { |
|
392 req->DoCleanup(); |
|
393 req->MarkForDeletion(); |
|
394 } |
|
395 } |
|
396 } |
|
397 |
|
398 TInt CScsServer::RemoveCompletedRequests(TAny* aPtr) |
|
399 /** |
|
400 This static function is called when iAsyncCleanup |
|
401 runs. It interprets its argument as a pointer to |
|
402 an instance of CScsServer and removes any asynchronous |
|
403 requests which have been completed. |
|
404 |
|
405 @param aPtr Required callback argument. Interpreted |
|
406 as a pointer to an instance of CScsServer. |
|
407 @return KErrNone. Required to satisfy the TCallBack |
|
408 function signature. |
|
409 @see RemoveCompletedRequests() |
|
410 */ |
|
411 { |
|
412 CScsServer* svr = static_cast<CScsServer*>(aPtr); |
|
413 svr->RemoveCompletedRequests(); |
|
414 return KErrNone; |
|
415 } |
|
416 |
|
417 void CScsServer::RemoveCompletedRequests() |
|
418 /** |
|
419 Delete any asynchronous requests which are marked for deletion. |
|
420 */ |
|
421 { |
|
422 // The requests have already been completed; they just need to be removed. |
|
423 TInt reqCount = iAsyncRequests.Count(); |
|
424 for (TInt i = reqCount - 1; i >= 0; --i) |
|
425 { |
|
426 CAsyncRequest* req = iAsyncRequests[i]; |
|
427 if (req->iSession != 0) // still outstanding if iSession != 0 |
|
428 continue; |
|
429 |
|
430 delete req; |
|
431 iAsyncRequests.Remove(i); |
|
432 } |
|
433 |
|
434 // if no more outstanding requests then reset array so heap balances |
|
435 if (iAsyncRequests.Count() == 0) |
|
436 iAsyncRequests.Compress(); |
|
437 |
|
438 // if the shutdown timer was deferred because of an impending |
|
439 // cleanup then launch it now. |
|
440 if (iShutdownTimer && (iSessionCount == 0)) |
|
441 { |
|
442 iShutdownTimer->Restart(); |
|
443 } |
|
444 } |
|
445 // End of file |
|
446 |