1 /* |
|
2 * Copyright (c) 2010 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 "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: Main handler for incoming requests |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "limitedpdpplugin.h" |
|
19 #include <centralrepository.h> |
|
20 #include "limitedpdpplugincopiedkeys.h" |
|
21 #include "debug.h" |
|
22 |
|
23 // Internal constants |
|
24 const TInt KDialupOverrideEnabled = 1; |
|
25 const TInt KCloseTimeoutInterval = 15000000; // 15 secs |
|
26 const TInt KCleanUpWaitTimeout = 300000; // 300 ms |
|
27 #ifdef _DEBUG |
|
28 const TInt KUsecToMSecDivider = 1000; |
|
29 #endif |
|
30 |
|
31 // --------------------------------------------------------------------------- |
|
32 // Two-phased constructor. |
|
33 // --------------------------------------------------------------------------- |
|
34 // |
|
35 CLimitedPdpPlugin* CLimitedPdpPlugin::NewL() |
|
36 { |
|
37 CLimitedPdpPlugin* self = new ( ELeave ) CLimitedPdpPlugin(); |
|
38 CleanupStack::PushL( self ); |
|
39 self->ConstructL(); |
|
40 CleanupStack::Pop( self ); |
|
41 return self; |
|
42 } |
|
43 |
|
44 // --------------------------------------------------------------------------- |
|
45 // Destructor. |
|
46 // --------------------------------------------------------------------------- |
|
47 // |
|
48 CLimitedPdpPlugin::~CLimitedPdpPlugin() |
|
49 { |
|
50 TRACE_FUNC_ENTRY |
|
51 |
|
52 // Check validity of handles so that Cancel functions can be called |
|
53 if ( iProperty.Handle() != NULL ) |
|
54 { |
|
55 // Cancel just in case in spite of the fact that with current |
|
56 // architecture cancelling of the operation is not possible |
|
57 iProperty.Cancel(); |
|
58 iProperty.Close(); |
|
59 } |
|
60 if ( iCancelTimer.Handle() != NULL ) |
|
61 { |
|
62 iCancelTimer.Cancel(); |
|
63 iCancelTimer.Close(); |
|
64 } |
|
65 |
|
66 TRACE_FUNC_EXIT |
|
67 } |
|
68 |
|
69 // --------------------------------------------------------------------------- |
|
70 // CLimitedPdpPlugin::CLimitedPdpPlugin |
|
71 // --------------------------------------------------------------------------- |
|
72 // |
|
73 CLimitedPdpPlugin::CLimitedPdpPlugin() : |
|
74 CATExtPluginBase() |
|
75 { |
|
76 // Nothing to do here, resources are initialized in ConstructL |
|
77 } |
|
78 |
|
79 // --------------------------------------------------------------------------- |
|
80 // CLimitedPdpPlugin::ConstructL |
|
81 // --------------------------------------------------------------------------- |
|
82 // |
|
83 void CLimitedPdpPlugin::ConstructL() |
|
84 { |
|
85 TRACE_FUNC_ENTRY |
|
86 |
|
87 // No need to use cleanup stack here, since these will be closed in |
|
88 // destructor anyway. |
|
89 User::LeaveIfError( iCancelTimer.CreateLocal() ); |
|
90 User::LeaveIfError( iProperty.Attach( KCopyOfConnectionMonitorPS, |
|
91 KCopyOfDialUpConnection ) ); |
|
92 iFeatureSupported = EFalse; |
|
93 iFeatureSupported = CheckFeatureEnablement(); |
|
94 |
|
95 TRACE_FUNC_EXIT |
|
96 } |
|
97 |
|
98 // --------------------------------------------------------------------------- |
|
99 // Reports connection identifier name to the extension plugin. |
|
100 // --------------------------------------------------------------------------- |
|
101 // |
|
102 void CLimitedPdpPlugin::ReportConnectionName( const TDesC8& /*aName*/) |
|
103 { |
|
104 } |
|
105 |
|
106 // --------------------------------------------------------------------------- |
|
107 // Reports the support status of an AT command. This is a synchronous API. |
|
108 // --------------------------------------------------------------------------- |
|
109 // |
|
110 TBool CLimitedPdpPlugin::IsCommandSupported( const TDesC8& /*aCmd*/) |
|
111 { |
|
112 TRACE_FUNC_ENTRY |
|
113 // Set the return value according to feature support |
|
114 TRACE_INFO(( _L("Returning feature support value %d"), |
|
115 static_cast<TInt>(iFeatureSupported))); |
|
116 TRACE_FUNC_EXIT |
|
117 return iFeatureSupported; |
|
118 } |
|
119 |
|
120 // --------------------------------------------------------------------------- |
|
121 // Handles an AT command. Cancelling of the pending request is done by |
|
122 // HandleCommandCancel(). The implementation in the extension plugin should |
|
123 // be asynchronous, but in this case we must use blocking behavior. This has |
|
124 // a couple of drawbacks. First, the ATEXT thread is blocked and possible, |
|
125 // which is against the requirements, and secondly and more importantly, the |
|
126 // cancelling of this operation is not supported. |
|
127 // --------------------------------------------------------------------------- |
|
128 // |
|
129 void CLimitedPdpPlugin::HandleCommand( const TDesC8& /*aCmd*/, |
|
130 RBuf8& /*aReply*/, |
|
131 TBool /*aReplyNeeded*/) |
|
132 { |
|
133 TRACE_FUNC_ENTRY |
|
134 |
|
135 // Double check that we are actually supporting the feature |
|
136 if ( iFeatureSupported ) |
|
137 { |
|
138 // Request ConnMon to close existing packet data connections |
|
139 TInt retTemp = CloseExistingConnections(); |
|
140 if ( retTemp == KErrNone ) |
|
141 { |
|
142 retTemp = BlockThreadUntilConnectionsClosed(); |
|
143 if ( retTemp == KErrNone ) |
|
144 { |
|
145 // Internal connections closed. We need to wait for a while |
|
146 // to make sure that lower layer resources are properly |
|
147 // cleaned in order to avoid conflicts in resource |
|
148 // allocation. Again thread needs to be blocked, therefore |
|
149 // User::After. |
|
150 // NOTE: This is definitely a bad workaround and unreliable |
|
151 // approach, but there aren't too many options... |
|
152 TRACE_INFO(( _L("Block for %d ms for resource cleanup"), |
|
153 ( KCleanUpWaitTimeout / KUsecToMSecDivider ))); |
|
154 User::After( KCleanUpWaitTimeout ); |
|
155 TRACE_INFO(( _L("Cleanup wait completed, exit"))); |
|
156 } |
|
157 } |
|
158 } |
|
159 |
|
160 TRACE_FUNC_EXIT |
|
161 } |
|
162 |
|
163 // --------------------------------------------------------------------------- |
|
164 // Cancels a pending HandleCommand request. |
|
165 // --------------------------------------------------------------------------- |
|
166 // |
|
167 void CLimitedPdpPlugin::HandleCommandCancel() |
|
168 { |
|
169 TRACE_FUNC_ENTRY |
|
170 TRACE_FUNC_EXIT |
|
171 } |
|
172 |
|
173 // --------------------------------------------------------------------------- |
|
174 // Next reply part's length. |
|
175 // The value must be equal or less than KDefaultCmdBufLength. |
|
176 // When the reply from this method is zero, ATEXT stops calling |
|
177 // GetNextPartOfReply(). |
|
178 // --------------------------------------------------------------------------- |
|
179 // |
|
180 TInt CLimitedPdpPlugin::NextReplyPartLength() |
|
181 { |
|
182 TRACE_FUNC_ENTRY |
|
183 TRACE_FUNC_EXIT |
|
184 return KErrNotSupported; |
|
185 } |
|
186 |
|
187 // --------------------------------------------------------------------------- |
|
188 // Gets the next part of reply initially set by HandleCommandComplete(). |
|
189 // Length of aNextReply must be equal or less than KDefaultCmdBufLength. |
|
190 // --------------------------------------------------------------------------- |
|
191 // |
|
192 TInt CLimitedPdpPlugin::GetNextPartOfReply( RBuf8& /*aNextReply*/) |
|
193 { |
|
194 TRACE_FUNC_ENTRY |
|
195 TRACE_FUNC_EXIT |
|
196 return KErrNotSupported; |
|
197 } |
|
198 |
|
199 // --------------------------------------------------------------------------- |
|
200 // Receives unsolicited results. Cancelling of the pending request is done by |
|
201 // by ReceiveUnsolicitedResultCancel(). The implementation in the extension |
|
202 // plugin should be asynchronous. |
|
203 // --------------------------------------------------------------------------- |
|
204 // |
|
205 void CLimitedPdpPlugin::ReceiveUnsolicitedResult() |
|
206 { |
|
207 TRACE_FUNC_ENTRY |
|
208 TRACE_FUNC_EXIT |
|
209 } |
|
210 |
|
211 // --------------------------------------------------------------------------- |
|
212 // Cancels a pending ReceiveUnsolicitedResult request. |
|
213 // --------------------------------------------------------------------------- |
|
214 // |
|
215 void CLimitedPdpPlugin::ReceiveUnsolicitedResultCancel() |
|
216 { |
|
217 TRACE_FUNC_ENTRY |
|
218 TRACE_FUNC_EXIT |
|
219 } |
|
220 |
|
221 // --------------------------------------------------------------------------- |
|
222 // Reports NVRAM status change to the plugins. |
|
223 // --------------------------------------------------------------------------- |
|
224 // |
|
225 void CLimitedPdpPlugin::ReportNvramStatusChange( const TDesC8& /*aNvram*/) |
|
226 { |
|
227 TRACE_FUNC_ENTRY |
|
228 TRACE_FUNC_EXIT |
|
229 } |
|
230 |
|
231 // --------------------------------------------------------------------------- |
|
232 // Reports about external handle command error condition. |
|
233 // This is for cases when for example DUN decided the reply contained an |
|
234 // error condition but the plugin is still handling the command internally. |
|
235 // Example: "AT+TEST;+TEST2" was given in command line; "AT+TEST" returns |
|
236 // non-EReplyTypeError condition and "AT+TEST2" returns EReplyTypeError. |
|
237 // As the plugin(s) returning the non-EReplyTypeError may still have some |
|
238 // ongoing operation then these plugins are notified about the external |
|
239 // EReplyTypeError in command line processing. It is to be noted that |
|
240 // HandleCommandCancel() is not sufficient to stop the processing as the |
|
241 // command handling has already finished. |
|
242 // --------------------------------------------------------------------------- |
|
243 // |
|
244 void CLimitedPdpPlugin::ReportExternalHandleCommandError() |
|
245 { |
|
246 TRACE_FUNC_ENTRY |
|
247 TRACE_FUNC_EXIT |
|
248 } |
|
249 |
|
250 // --------------------------------------------------------------------------- |
|
251 // Reads CenRep key to check whether requested functionality is active. |
|
252 // --------------------------------------------------------------------------- |
|
253 // |
|
254 TBool CLimitedPdpPlugin::CheckFeatureEnablement() |
|
255 { |
|
256 TRACE_FUNC_ENTRY |
|
257 TBool enabled( EFalse ); |
|
258 CRepository* cmRepository = NULL; |
|
259 TRAP_IGNORE( cmRepository = CRepository::NewL ( KCopyOfCRUidCmManager ) ); |
|
260 if ( cmRepository ) |
|
261 { |
|
262 TInt overrideValue = KErrNotFound; |
|
263 TInt retTemp = cmRepository->Get( KCopyOfDialUpOverride, |
|
264 overrideValue ); |
|
265 |
|
266 if ( ( retTemp == KErrNone ) && ( overrideValue |
|
267 == KDialupOverrideEnabled ) ) |
|
268 { |
|
269 enabled = ETrue; |
|
270 TRACE_INFO(( _L("Dialup override feature enabled"))); |
|
271 } |
|
272 } |
|
273 delete cmRepository; |
|
274 TRACE_FUNC_EXIT |
|
275 return enabled; |
|
276 } |
|
277 |
|
278 // --------------------------------------------------------------------------- |
|
279 // Ask ConnMon to close all existing packet data connections |
|
280 // --------------------------------------------------------------------------- |
|
281 // |
|
282 TInt CLimitedPdpPlugin::CloseExistingConnections() |
|
283 { |
|
284 TRACE_FUNC_ENTRY |
|
285 |
|
286 TInt dialupState( EConnMonReady ); |
|
287 TInt retVal( KErrNone ); |
|
288 |
|
289 retVal = iProperty.Get( dialupState ); |
|
290 if ( retVal == KErrNone ) |
|
291 { |
|
292 TRACE_INFO(( _L("Current dialup connection PS key value %d"), |
|
293 dialupState )); |
|
294 if ( dialupState != EConnMonDialUpInit ) |
|
295 { |
|
296 TRACE_INFO(( _L("Setting dialup connection PS key to value %d"), |
|
297 EConnMonDialUpInit )); |
|
298 retVal = iProperty.Set( EConnMonDialUpInit ); |
|
299 } |
|
300 else |
|
301 { |
|
302 // Error situation, we should not end up to this function if |
|
303 // the connection closing is already in init state. |
|
304 retVal = KErrNotReady; |
|
305 } |
|
306 } |
|
307 TRACE_INFO(( _L("Closing existing connections done with status %d"), |
|
308 retVal )); |
|
309 TRACE_FUNC_EXIT |
|
310 return retVal; |
|
311 } |
|
312 |
|
313 // --------------------------------------------------------------------------- |
|
314 // Synchronously block thread until ConnMon indicates that connections are |
|
315 // closed or operation timeouts. |
|
316 // --------------------------------------------------------------------------- |
|
317 // |
|
318 TInt CLimitedPdpPlugin::BlockThreadUntilConnectionsClosed() |
|
319 { |
|
320 TRACE_FUNC_ENTRY |
|
321 |
|
322 TInt dialupState( EConnMonDialUpInit ); |
|
323 TInt retVal( KErrNone ); |
|
324 |
|
325 // Read the dialup value just to check if ConnMon has been able to update |
|
326 // it already to reflect correct state. |
|
327 retVal = iProperty.Get( dialupState ); |
|
328 |
|
329 if ( retVal == KErrNone ) |
|
330 { |
|
331 TRACE_INFO(( _L("Dialup connection PS key value before wait: %d"), |
|
332 dialupState )); |
|
333 if ( dialupState == EConnMonDialUpInit ) |
|
334 { |
|
335 // Block thread until value changes |
|
336 TRequestStatus propertyStatus; |
|
337 TRequestStatus timeoutStatus; |
|
338 // Set operation to timeout if closing internal contexts fails. |
|
339 // If timeout expires before PS key is updated, this plugin |
|
340 // will pass the ATD*99# command to modem. Most probably |
|
341 // that will fail due to lack of resources. However, if |
|
342 // internal connections are not closed within this timeframe |
|
343 // there will be problems anyway. So this is only to hasten |
|
344 // end user feedback on error situation. |
|
345 iCancelTimer.After( timeoutStatus, KCloseTimeoutInterval ); |
|
346 |
|
347 // Loop for property subscription just in case the ConnMon does |
|
348 // not set correct value in first attempt. The loop exiting is |
|
349 // done separately below, but this condition is better than using |
|
350 // while ( ETrue ) |
|
351 while ( dialupState != EConnMonReady ) |
|
352 { |
|
353 iProperty.Subscribe( propertyStatus ); |
|
354 |
|
355 TRACE_INFO(( _L("Blocking thread to wait connection closing") )); |
|
356 User::WaitForRequest( propertyStatus, timeoutStatus ); |
|
357 |
|
358 // Wait completed, check which condition was valid |
|
359 if ( propertyStatus != KRequestPending ) |
|
360 { |
|
361 if ( propertyStatus == KErrNone ) |
|
362 { |
|
363 // ConnMon changed the value, check if it is valid |
|
364 TInt retVal = iProperty.Get( dialupState ); |
|
365 if ( retVal == KErrNone ) |
|
366 { |
|
367 if ( dialupState == EConnMonReady ) |
|
368 { |
|
369 TRACE_INFO(( _L("Existing connections closed successfully") )); |
|
370 } |
|
371 else |
|
372 { |
|
373 // Otherwise retry |
|
374 TRACE_INFO(( _L("Wrong internal connection state (%d), retry"), |
|
375 dialupState )); |
|
376 continue; |
|
377 } |
|
378 } |
|
379 } |
|
380 else |
|
381 { |
|
382 retVal = propertyStatus.Int(); |
|
383 } |
|
384 // We should exit the loop, either due success of error |
|
385 // Cancel and wait for timeout request to complete |
|
386 TRACE_INFO((_L("Existing connections closed (status: %d), cancel timer"), |
|
387 retVal )); |
|
388 iCancelTimer.Cancel(); |
|
389 // Wait... If the completion of Cancel() is not waited |
|
390 // here, CActiveScheduler will panic due to stray signal |
|
391 // (E32USER-CBase panic code 46) |
|
392 User::WaitForRequest( timeoutStatus ); |
|
393 TRACE_INFO(( _L("Timeout cancelled (timeoutStatus: %d), exit wait"), |
|
394 timeoutStatus.Int() )); |
|
395 break; |
|
396 } |
|
397 else if ( timeoutStatus != KRequestPending ) |
|
398 { |
|
399 // Timeout or error, exit |
|
400 TRACE_INFO(( _L("Wait for existing connections timeouted (status: %d)"), |
|
401 timeoutStatus.Int() )); |
|
402 // Cancel PS subscription and wait for its completion |
|
403 iProperty.Cancel(); |
|
404 User::WaitForRequest( propertyStatus ); |
|
405 retVal = iProperty.Set( EConnMonDialUpClosed ); |
|
406 TRACE_INFO(( _L("Subscription cancelled (status: %d) and state reset, exit"), |
|
407 propertyStatus.Int() )); |
|
408 retVal = KErrTimedOut; |
|
409 break; |
|
410 } |
|
411 } |
|
412 } |
|
413 } |
|
414 // All done, exit |
|
415 TRACE_INFO(( _L("Exiting from wait with status %d"), retVal )); |
|
416 |
|
417 TRACE_FUNC_EXIT |
|
418 return retVal; |
|
419 } |
|
420 |
|