1 // Copyright (c) 2007-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 // |
|
15 |
|
16 #include <elements/nm_messages_errorrecovery.h> |
|
17 #include <comms-infras/ss_coreprstates.h> |
|
18 #include "mobilitymcpractivities.h" |
|
19 #include <comms-infras/mobilitymcprstates.h> |
|
20 #include <comms-infras/ss_nodemessages_selector.h> |
|
21 #include <comms-infras/ss_nodemessages_mobility.h> |
|
22 #include <comms-infras/ss_nodemessages_availability.h> |
|
23 #include <comms-infras/ss_logext.h> |
|
24 |
|
25 |
|
26 #ifdef _DEBUG |
|
27 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
28 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
29 _LIT(KSpecAssert_ESockMbCrMCPRAct, "ESockMbCrMCPRAct"); |
|
30 #endif |
|
31 |
|
32 #ifdef __CFLOG_ACTIVE |
|
33 #define KCoreMCprStatesTag KESockMetaConnectionTag |
|
34 _LIT8(KCoreMCprStatesSubTag, "coremcprstate"); |
|
35 #endif |
|
36 |
|
37 using namespace ESock; |
|
38 using namespace CorePanics; |
|
39 using namespace MCprStates; |
|
40 using namespace NetStateMachine; |
|
41 using namespace MCprActivities; |
|
42 using namespace MobilityMCprActivities; |
|
43 using namespace Messages; |
|
44 using namespace MeshMachine; |
|
45 |
|
46 // |
|
47 //Panics |
|
48 #ifdef _DEBUG |
|
49 _LIT (KCoreMobileMCprPanic,"CoreMobileMCprPanic"); |
|
50 #endif |
|
51 |
|
52 namespace MobilityMCprPrioritisedSelectActivity |
|
53 { |
|
54 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivitySelect, MCprPrioritisedSelect, TCFSelector::TSimpleSelect, CSelectNextLayerActivity::NewL) |
|
55 //Reply from TAwaitingSelectNextLayer if no choices, otherwise accept |
|
56 FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingSelectNextLayer, MeshMachine::TNoTag) |
|
57 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TProcessPrioritisedSelectionPolicy, MCprStates::TSelectedProvider) |
|
58 //Start the selection main loop |
|
59 NODEACTIVITY_ENTRY(MCprStates::KSelectedProvider, CSelectNextLayerActivity::TFindOrCreateTierManager, MCprStates::TAwaitingTierManagerCreated, MeshMachine::TNoTag) |
|
60 NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TJoinTierManager, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag) |
|
61 //Select next provider and enter the selection internal loop if provider received. Break if SelectComplete(NULL). |
|
62 NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSelectNextLayer, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagOrSelectedProviderIsNull) |
|
63 NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TAddProviderInfo, MCprStates::TAwaitingSelectComplete, CSelectNextLayerActivity::TNoTagBackwardsOrJoinServiceProvider) |
|
64 //Break the selection internal loop if SelectComplete(NULL), otherwise stay in this tripple |
|
65 NODEACTIVITY_ENTRY(MCprStates::KJoinServiceProvider, CSelectNextLayerActivity::TJoinServiceProvider, CoreStates::TAwaitingJoinComplete, MeshMachine::TNoTag) |
|
66 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CSelectNextLayerActivity::TSendSelectComplete, CSelectNextLayerActivity::TSelectedProviderIsNullOrJoinServiceProviderBackward) |
|
67 //Break the selection main loop if no more choices, otherwise go back again |
|
68 THROUGH_NODEACTIVITY_ENTRY(MCprStates::KSelectedProviderIsNull, CSelectNextLayerActivity::TLeaveTierManager, CSelectNextLayerActivity::TNoTagOrSelectedProviderBackward) |
|
69 //Finish the activity |
|
70 LAST_NODEACTIVITY_ENTRY(KNoTag, MCprStates::TSendFinalSelectComplete) |
|
71 NODEACTIVITY_END() |
|
72 } |
|
73 |
|
74 namespace MobilityMCprMobilityActivity |
|
75 { |
|
76 //This activity monitors availability status on this node |
|
77 //NOTE: This activity assumes there is only one data client (Cpr) of this MCpr! |
|
78 //NOTE: This activity can only be executed in the context of CMobilityMetaConnectionProvider (or derived) |
|
79 //NOTE: TError may come from the availability activity only. It is handled by the ECFActivityError. |
|
80 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityMCprMobility, MCprMobility, TCFMobilityProvider::TStartMobility, MobilityMCprActivities::CMobilityActivity::NewL) |
|
81 //The activity only makes sense after the startup sequence completed on this layer |
|
82 FIRST_NODEACTIVITY_ENTRY(MobilityMCprStates::TAwaitingStartMobility, MeshMachine::TNoTag/*BlockedByNoServiceProviderStarted*/) |
|
83 //Report to the client that we have successfully started |
|
84 THROUGH_NODEACTIVITY_ENTRY(KNoTag, MobilityMCprStates::TReplyMobilityStarted, MeshMachine::TNoTag) |
|
85 //Register with self for availability notifications. Self will report _any_ availabilty change (even available->available) back to |
|
86 //this activity. This activity can trigger mobility (see CMobilityActivity::TNoTagOrErrorTagOrStartMobilityHandshakeBackwardsOnMobilityTriggerBlockedByErrorRecovery) |
|
87 //if it sees that the availability notification has influcenced what the currently preffered bearer should be. |
|
88 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TSendAvailabilityRequest, MeshMachine::TTag<MobilityMCprStates::KStartMobilityHandshake>) |
|
89 |
|
90 //<BEGIN> MAIN LOOP **************** |
|
91 //The main mobility handshake loop. The loop is executed when performing migration from one service provider to another. |
|
92 //The entry condition for the loop is that: |
|
93 //- upgrade: a better then current access point is now available (a better access point reported available) |
|
94 //- downgrade: |
|
95 // (a) the current access point is being rejected by the client (e.g.: the current access point doesn't seem to route traffic where required) |
|
96 // (b) the current access point ceases to be available (reports availability below reasonable threshold). |
|
97 // NOTE: if the current bearer ceases to be available completely (goes down), then this will be assisted by an error recovery request; |
|
98 // NOTE: This tuple doesn't actually do (b), i.e.: assumes the threshold of '1' (in 0..100 availability score range) |
|
99 //Before awaitng for availability change or rejection by the client (TAwaitingCurrentCarrierRejectedOrAvailabilityChange), the activity |
|
100 //first checks (TNoTagOrAwaitMobilityBlockedByErrorRecovery) if the availability has changed since it last checked |
|
101 //(availability could have been reported amidst the previous handshake loop) |
|
102 THROUGH_NODEACTIVITY_ENTRY(MobilityMCprStates::KStartMobilityHandshake, CMobilityActivity::TClearHandshakingFlag, CMobilityActivity::TNoTagOrAwaitMobilityBlockedByErrorRecovery) |
|
103 NODEACTIVITY_ENTRY(MobilityMCprStates::KAwaitMobility, MeshMachine::TDoNothing, CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange, CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTriggerBlockedByErrorRecovery) |
|
104 |
|
105 //Mobility has been triggered ((a) or (b)). Start mobility handshake (set handshaking flag and inform the client about the preferred bearer) |
|
106 NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag, MobilityMCprStates::TAwaitingMigrationRequestedOrRejected, CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards) |
|
107 //The client accepts the new access point. |
|
108 //For the moment it is sufficient to use the re-connect activity, in the future we may want to |
|
109 //customise the behavior, for example start the new layer before rebinding it, etc. |
|
110 //Should rebinding fail, the mobility activity will be set to an error mode. The error mode will be cleared if |
|
111 //there are other bearers this activity can offer. If there aren't the data client will be errored. |
|
112 NODEACTIVITY_ENTRY(MobilityMCprStates::KReConnect, CMobilityActivity::TRequestReConnect, MCprStates::TAwaitingReConnectCompleteOrError, CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards) |
|
113 //Rebinding has been successful. As far as MCPR is concerned, the mobility is finished, but the MCPR must await |
|
114 //for the handshake (accept|reject) before it can offer another bearer. |
|
115 NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TInformMigrationCompleted, MobilityMCprStates::TAwaitingMigrationAcceptedOrRejected, MeshMachine::TTag<MobilityMCprStates::KStartMobilityHandshake|EBackward>) |
|
116 NODEACTIVITY_END() |
|
117 } |
|
118 |
|
119 namespace MCprConnectionStartRecoveryActivity |
|
120 { |
|
121 //MCprConnectionStartRecovery activity belongs to a group of Error Recovery Activities. |
|
122 //Error Recovery Activities need to handle their own errors (generated as well as returned). |
|
123 |
|
124 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionStartRecovery, MCprConnectionStartRecovery, TEErrorRecovery::TErrorRecoveryRequest, CConnectionRecoveryActivity::NewL) |
|
125 FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingConnectionStartRecoveryRequest, MobilityMCprStates::TNoTagOrErrorTagIfMobilityRunning) |
|
126 LAST_NODEACTIVITY_ENTRY(KErrorTag, CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse) |
|
127 |
|
128 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TStoreErrorContext, MeshMachine::TNoTag) |
|
129 //Decide if it it possible/sensible to reconnect and retry |
|
130 //This transition will leave if not possible to recover (==TSendPropagateRecoveryResponse from Transition::Error()) |
|
131 NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest, MCprStates::TAwaitingReConnectCompleteOrError, MeshMachine::TNoTagOrErrorTag) //Own error handling |
|
132 //Respond with retry |
|
133 LAST_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TSendRetryRecoveryResponse) |
|
134 //Respond with propagate - the reconnect failed (we could think of re-trying reconnect again though..) |
|
135 LAST_NODEACTIVITY_ENTRY(KErrorTag, CConnectionRecoveryActivity::TSendPropagateRecoveryResponse) |
|
136 NODEACTIVITY_END() |
|
137 } |
|
138 |
|
139 namespace MCprConnectionGoneDownRecoveryActivity |
|
140 { |
|
141 //MCprConnectionGoneDownRecovery activity belongs to a group of Error Recovery Activities. |
|
142 //Error Recovery Activities need to handle their own errors (generated as well as returned). |
|
143 |
|
144 //NOTE: This activity is only a reference one. All it does it waits for the mobility handshake to finish before |
|
145 //continuing with the stack cleanup originated by TGoneDown. |
|
146 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityConnectionGoneDownRecovery, MCprConnectionGoneDownRecovery, TEErrorRecovery::TErrorRecoveryRequest, CConnectionRecoveryActivity::NewL) |
|
147 FIRST_NODEACTIVITY_ENTRY(MCprStates::TAwaitingConnectionGoneDownRecoveryRequest, MeshMachine::TNoTag) |
|
148 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TStoreErrorContext, CoreStates::TNoTagOrNoPeer) |
|
149 LAST_NODEACTIVITY_ENTRY(CoreStates::KNoPeer, MCprStates::TSendPropagateRecoveryResponse) //Take error codes directly from the request |
|
150 THROUGH_NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MobilityMCprStates::TNoTagBlockedByMobilityHandshaking) |
|
151 //Decide if it it possible/sensible to retry |
|
152 //This transition will leave if not possible to recover (==TSendPropagateRecoveryResponse from Transition::Error()) |
|
153 LAST_NODEACTIVITY_ENTRY(KNoTag, CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest) //Take error codes from the request directly |
|
154 NODEACTIVITY_END() |
|
155 } |
|
156 |
|
157 namespace MobilityMCprActivities |
|
158 { |
|
159 DEFINE_EXPORT_ACTIVITY_MAP(mobilityMCprActivities) |
|
160 ACTIVITY_MAP_ENTRY(MobilityMCprPrioritisedSelectActivity, MCprPrioritisedSelect) |
|
161 ACTIVITY_MAP_ENTRY(MobilityMCprMobilityActivity, MCprMobility) |
|
162 ACTIVITY_MAP_ENTRY(MCprConnectionStartRecoveryActivity,MCprConnectionStartRecovery) |
|
163 ACTIVITY_MAP_ENTRY(MCprConnectionGoneDownRecoveryActivity,MCprConnectionGoneDownRecovery) |
|
164 ACTIVITY_MAP_END_BASE(MCprActivities, coreMCprActivities) |
|
165 } |
|
166 |
|
167 // |
|
168 // CMobilityActivity |
|
169 MeshMachine::CNodeActivityBase* MobilityMCprActivities::CMobilityActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
170 { |
|
171 return new (ELeave) CMobilityActivity(aActivitySig, aNode); |
|
172 } |
|
173 |
|
174 CMobilityActivity::CMobilityActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
175 : MeshMachine::CNodeRetryActivity(aActivitySig, aNode), |
|
176 //NOTE: This reference implementation will currently only react to availability oscilating around |
|
177 //the middle point on the availability scale |
|
178 iAvailabilityScoreTreshold((TAvailabilityStatus::EMinAvailabilityScore + TAvailabilityStatus::EMaxAvailabilityScore) / 2) |
|
179 { |
|
180 } |
|
181 |
|
182 CMobilityActivity::~CMobilityActivity() |
|
183 { |
|
184 //cancel availablilty subscription. |
|
185 RClientInterface::OpenPostMessageClose(TNodeCtxId(ActivityId(), iNode.Id()), iNode.Id(), TEBase::TCancel().CRef()); |
|
186 ClearHandshakingFlag(); |
|
187 } |
|
188 |
|
189 TBool CMobilityActivity::EvaluatePreference(CMobilityActivity::TContext& aContext) |
|
190 { |
|
191 //Find the most preferred Service Provider |
|
192 TClientIter<TDefaultClientMatchPolicy> iter = iNode.GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider)); |
|
193 __ASSERT_DEBUG(iter[0], User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); //A Service Provider must exist! |
|
194 |
|
195 //If we are evaluating the preferences as a result of carrier rejection, we will |
|
196 //not propose the most recently rejected one. |
|
197 //NOTE: This implementation does not provide a blacklisting mechanism. |
|
198 //It does not store any blacklisting information. |
|
199 //lastRejected is only the recently rejected carrier that may not be proposed again for the client |
|
200 //to be able to renegotiate the old bearer and continue using the connection. |
|
201 //NOTE: This reference implementation will work only when at least one of the two most preferred carriers |
|
202 //can be used (accepted) by the mobility client at any given time. |
|
203 RMetaServiceProviderInterface* candidate = NULL; |
|
204 RMetaServiceProviderInterface* lastRejected = NULL; |
|
205 if ( Error() != KErrNone ) |
|
206 { |
|
207 //The activity is running in an error mode attempting to recover from it. |
|
208 //There's a couple of reasons why the activity may be in an error mode: |
|
209 //- rejection |
|
210 // - current bearer rejected; |
|
211 // - proposed bearer rejected; |
|
212 // - failure to migrate to the proposed bearer; |
|
213 lastRejected = iAvailable ? iAvailable : |
|
214 static_cast<RMetaServiceProviderInterface*>(aContext.Node().ServiceProvider()); |
|
215 } |
|
216 |
|
217 iCandidate = iAvailable; |
|
218 iAvailable = NULL; //Do not remember rejected candidate any longer |
|
219 while ((candidate = static_cast<RMetaServiceProviderInterface*>(iter++)) != NULL) |
|
220 { |
|
221 const TAvailabilityStatus& status = candidate->AvailabilityStatus(); |
|
222 if (!status.IsKnown()) |
|
223 { |
|
224 //We are still waiting for the availability check results for this AP |
|
225 //Ignore the whole evaluation now as we may soon receive a better candidate |
|
226 //to propose to the mobility client. |
|
227 return EFalse; |
|
228 } |
|
229 |
|
230 if (status.Score() > iAvailabilityScoreTreshold |
|
231 && candidate!=lastRejected) |
|
232 { |
|
233 if (candidate==aContext.Node().ServiceProvider() |
|
234 && Error() == KErrNone ) |
|
235 { |
|
236 //The preferred one is the current one, is still available and was not just rejected. |
|
237 //No need to do anything more. |
|
238 return EFalse; |
|
239 } |
|
240 |
|
241 //A new match found |
|
242 iAvailable = candidate; |
|
243 return ETrue; |
|
244 } |
|
245 } |
|
246 |
|
247 //There is no choice for migration |
|
248 return EFalse; //No match found |
|
249 } |
|
250 |
|
251 void CMobilityActivity::SetHandshakingFlag() |
|
252 { |
|
253 static_cast<CMobilityMetaConnectionProvider&>(iNode).iIsHandshakingNow = ETrue; |
|
254 } |
|
255 |
|
256 void CMobilityActivity::ClearHandshakingFlag() |
|
257 { |
|
258 static_cast<CMobilityMetaConnectionProvider&>(iNode).iIsHandshakingNow = EFalse; |
|
259 } |
|
260 |
|
261 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
262 TInt CMobilityActivity::TNoTagOrReConnectOrStartMobilityHandshakeBackwards::TransitionTag() |
|
263 { |
|
264 if (iContext.Activity()->Error() == KErrNone && |
|
265 (message_cast<TCFMobilityProvider::TMigrationRequested>(&iContext.iMessage) || |
|
266 message_cast<TCFMcpr::TReConnectComplete>(&iContext.iMessage))) |
|
267 { |
|
268 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
269 if( activity.iCurrent!=activity.iAvailable ) |
|
270 return MobilityMCprStates::KReConnect | NetStateMachine::EForward; |
|
271 else |
|
272 return MeshMachine::KNoTag | NetStateMachine::EForward; |
|
273 } |
|
274 return MobilityMCprStates::KStartMobilityHandshake | NetStateMachine::EBackward; |
|
275 } |
|
276 |
|
277 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
278 TInt CMobilityActivity::TNoTagOrStartMobilityHandshakeBackwards::TransitionTag() |
|
279 { |
|
280 if (iContext.Activity()->Error() == KErrNone && |
|
281 (message_cast<TCFMobilityProvider::TMigrationRequested>(&iContext.iMessage) || |
|
282 message_cast<TCFMcpr::TReConnectComplete>(&iContext.iMessage))) |
|
283 { |
|
284 return MeshMachine::KNoTag | NetStateMachine::EForward; |
|
285 } |
|
286 return MobilityMCprStates::KStartMobilityHandshake | NetStateMachine::EBackward; |
|
287 } |
|
288 |
|
289 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTrigger, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
290 TInt CMobilityActivity::TNoTagOrAwaitMobilityBackwardsOnMobilityTrigger::TransitionTag() |
|
291 { |
|
292 //This is where the judgement is made on whether to trigger mobility (offer the client another bearer) |
|
293 //or ignore and come back waiting. |
|
294 __ASSERT_DEBUG(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>() || |
|
295 iContext.iMessage.IsMessage<TCFAvailabilityControlClient::TAvailabilityNotification>(), |
|
296 User::Panic(KCoreMobileMCprPanic, KPanicIncorrectMessage)); |
|
297 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
298 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
299 |
|
300 if (activity.EvaluatePreference(iContext)) |
|
301 { |
|
302 activity.SetError(KErrNone); |
|
303 return KNoTag; |
|
304 } |
|
305 else if (activity.Error() != KErrNone ) |
|
306 { |
|
307 activity.PostToOriginators(TEBase::TError(activity.Error()).CRef()); |
|
308 activity.SetError(KErrNone); |
|
309 } |
|
310 return MobilityMCprStates::KAwaitMobility | NetStateMachine::EBackward; |
|
311 } |
|
312 |
|
313 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrAwaitMobility, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
314 TInt CMobilityActivity::TNoTagOrAwaitMobility::TransitionTag() |
|
315 { |
|
316 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
317 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
318 |
|
319 if (activity.EvaluatePreference(iContext)) |
|
320 { |
|
321 activity.SetError(KErrNone); |
|
322 return KNoTag; |
|
323 } |
|
324 else if (activity.Error() != KErrNone ) |
|
325 { |
|
326 activity.PostToOriginators(TEBase::TError(activity.Error()).CRef()); |
|
327 activity.SetError(KErrNone); |
|
328 } |
|
329 return MobilityMCprStates::KAwaitMobility; |
|
330 } |
|
331 |
|
332 DEFINE_SMELEMENT(CMobilityActivity::TSendAvailabilityRequest, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
333 void CMobilityActivity::TSendAvailabilityRequest::DoL() |
|
334 { |
|
335 //Issue availability notification registration to start the availability activity on this node. |
|
336 //NOTE: since we've requested availability from self, we are interested in any change (even available->available) |
|
337 //since we could be switching from AP1 available to AP2 available. Either way we must recalculate. |
|
338 //We're hence interested in TAvailabilitySubscriptionOptions::EAnyNestedChange. |
|
339 TAvailabilitySubscriptionOptions availabilityOptions(TAvailabilitySubscriptionOptions::EAnyNestedChange); |
|
340 TCFAvailabilityProvider::TAvailabilityNotificationRegistration msg(availabilityOptions); |
|
341 RClientInterface::OpenPostMessageClose(TNodeCtxId(iContext.ActivityId(), iContext.NodeId()), iContext.NodeId(), msg); |
|
342 //Do not set iPostedTo. We are not waiting for the responses. |
|
343 } |
|
344 |
|
345 DEFINE_SMELEMENT(CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
346 void CMobilityActivity::TInformMigrationAvailableAndSetHandshakingFlag::DoL() |
|
347 { |
|
348 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
349 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
350 |
|
351 //Inform the CPR that a potential migration is available. We only support a single data client |
|
352 //in this implementation. |
|
353 __ASSERT_DEBUG(activity.iAvailable, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); |
|
354 |
|
355 //Compute all this here to keep EvaluatePreference() as fast as possible |
|
356 activity.iCurrent = static_cast<RMetaServiceProviderInterface*>(iContext.Node().ServiceProvider()); |
|
357 __ASSERT_DEBUG(activity.iCurrent, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); |
|
358 |
|
359 //Perform a simple check if this is an upgrade or not |
|
360 TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider)); |
|
361 RNodeInterface* sp = iter++; |
|
362 while (sp && sp!=activity.iCurrent && sp!=activity.iAvailable) |
|
363 { |
|
364 sp = iter++; |
|
365 } |
|
366 |
|
367 TBool isUpgrade = (sp != activity.iCurrent); //If current was found first -> this is not an upgrade |
|
368 if( activity.iCurrent == activity.iAvailable && activity.iCandidate ) |
|
369 { |
|
370 // The available client is the same as the current and a candidate exists, this indicates that |
|
371 // an error has occured when trying to start the candidate bearer and the control as reverted to |
|
372 // the current bearer. In this situation the notification needs to look as if the bearer has |
|
373 // migrated from the failed candidate to the current bearer. |
|
374 TCFMobilityControlClient::TMigrationNotification msg(activity.iCandidate->ProviderInfo().APId(), |
|
375 activity.iAvailable->ProviderInfo().APId(), |
|
376 isUpgrade, EFalse); |
|
377 activity.PostToOriginators(msg); |
|
378 } |
|
379 else |
|
380 { |
|
381 // Standard case where migration is going from current to available. |
|
382 TCFMobilityControlClient::TMigrationNotification msg(activity.iCurrent->ProviderInfo().APId(), |
|
383 activity.iAvailable->ProviderInfo().APId(), |
|
384 isUpgrade, EFalse); |
|
385 activity.PostToOriginators(msg); |
|
386 } |
|
387 |
|
388 activity.ClearPostedTo(); |
|
389 activity.SetHandshakingFlag(); |
|
390 } |
|
391 |
|
392 |
|
393 DEFINE_SMELEMENT(CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange, NetStateMachine::MState, CMobilityActivity::TContext) |
|
394 TBool CMobilityActivity::TAwaitingCurrentCarrierRejectedOrAvailabilityChange::Accept() |
|
395 { |
|
396 if (iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>()) |
|
397 { |
|
398 iContext.Activity()->SetError(KErrNotFound); |
|
399 return ETrue; |
|
400 } |
|
401 return iContext.iMessage.IsMessage<TCFAvailabilityControlClient::TAvailabilityNotification>(); |
|
402 } |
|
403 |
|
404 |
|
405 DEFINE_SMELEMENT(CMobilityActivity::TRequestReConnect, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
406 void CMobilityActivity::TRequestReConnect::DoL() |
|
407 { |
|
408 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
409 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
410 |
|
411 __ASSERT_DEBUG(activity.iAvailable, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); |
|
412 __ASSERT_DEBUG(activity.iCurrent, User::Panic(KCoreMobileMCprPanic, KPanicNoServiceProvider)); |
|
413 __ASSERT_DEBUG(activity.iCurrent!=activity.iAvailable, User::Panic(KSpecAssert_ESockMbCrMCPRAct, 1)); |
|
414 |
|
415 // For the moment it is sufficient to use the re-connect activity, in the future we may want to |
|
416 // customise the behavior, for example start the new layer before rebinding it, etc. |
|
417 TCFMcpr::TReConnect msg(activity.iCurrent->RecipientId(), activity.iAvailable->RecipientId()); |
|
418 activity.PostRequestTo(iContext.NodeId(), msg); |
|
419 } |
|
420 |
|
421 DEFINE_SMELEMENT(CMobilityActivity::TInformMigrationCompleted, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
422 void CMobilityActivity::TInformMigrationCompleted::DoL() |
|
423 { |
|
424 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
425 iContext.iNodeActivity->PostToOriginators(TCFMobilityProvider::TMigrationComplete().CRef()); |
|
426 iContext.iNodeActivity->ClearPostedTo(); |
|
427 } |
|
428 |
|
429 DEFINE_SMELEMENT(CMobilityActivity::TClearHandshakingFlag, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
430 void CMobilityActivity::TClearHandshakingFlag::DoL() |
|
431 { |
|
432 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
433 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
434 activity.ClearHandshakingFlag(); |
|
435 } |
|
436 |
|
437 |
|
438 // |
|
439 //CConnectionRecoveryActivity |
|
440 MeshMachine::CNodeActivityBase* CConnectionRecoveryActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
441 { |
|
442 return new (ELeave) CConnectionRecoveryActivity(aActivitySig, aNode); |
|
443 } |
|
444 |
|
445 CConnectionRecoveryActivity::CConnectionRecoveryActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
446 : MeshMachine::CNodeRetryActivity(aActivitySig, aNode) |
|
447 { |
|
448 } |
|
449 |
|
450 void CConnectionRecoveryActivity::ReplyToOriginators(TEErrorRecovery::TErrorRecoveryResponse& aCFMessageSig) |
|
451 { |
|
452 NM_LOG_START_BLOCK(KESockMeshMachine, _L8("CConnectionRecoveryActivity::ReplyToOriginators")); |
|
453 NM_LOG((KESockMeshMachine, _L8("[this=0x%08x] "), this)); |
|
454 NM_LOG_MESSAGE(KESockMeshMachine, aCFMessageSig); |
|
455 NM_LOG_END_BLOCK(KESockMeshMachine, _L8("CConnectionRecoveryActivity::ReplyToOriginators")); |
|
456 for (TInt n = iOriginators.Count() - 1;n>=0; n--) |
|
457 { |
|
458 Messages::TNodePeerId& peerId = iOriginators[n]; |
|
459 TCFSafeMessage::TResponseCarrierWest<TEErrorRecovery::TErrorRecoveryResponse> resp(aCFMessageSig, peerId.RecipientId()); |
|
460 peerId.PostMessage(iNode.Id(), resp); |
|
461 } |
|
462 } |
|
463 |
|
464 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TAwaitingReConnectComplete, NetStateMachine::MState, CConnectionRecoveryActivity::TContext) |
|
465 TBool CConnectionRecoveryActivity::TAwaitingReConnectComplete::Accept() |
|
466 { |
|
467 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
468 TEBase::TError* msg = message_cast<TEBase::TError>(&iContext.iMessage); |
|
469 if(msg) |
|
470 { |
|
471 CConnectionRecoveryActivity& ac = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
472 TErrResponse propagateResp(TErrResponse::EPropagate,ac.iOriginalErrContext.iStateChange.iError,ac.iOriginalErrContext.iMessageId); |
|
473 TEErrorRecovery::TErrorRecoveryResponse errResp(propagateResp); |
|
474 ac.ReplyToOriginators(errResp); |
|
475 ac.SetIdle(); |
|
476 iContext.iMessage.ClearMessageId(); |
|
477 return EFalse; |
|
478 } |
|
479 return (iContext.iMessage.IsMessage<TCFMcpr::TReConnectComplete>())? ETrue : EFalse; |
|
480 } |
|
481 |
|
482 void CConnectionRecoveryActivity::TTransitionBase::Error(TInt /*aError*/) |
|
483 { |
|
484 //Reply to the Error Activity and terminate |
|
485 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
486 CConnectionRecoveryActivity& ac = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
487 TEErrorRecovery::TErrorRecoveryResponse errResp(TErrResponse(TErrResponse::EPropagate,ac.iOriginalErrContext.iStateChange.iError,ac.iOriginalErrContext.iMessageId)); |
|
488 ac.ReplyToOriginators(errResp); |
|
489 iContext.iNodeActivity->SetIdle(); |
|
490 } |
|
491 |
|
492 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TStoreErrorContext, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
493 void CConnectionRecoveryActivity::TStoreErrorContext::DoL() |
|
494 { |
|
495 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
496 CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
497 activity.iOriginalErrContext = message_cast<TEErrorRecovery::TErrorRecoveryRequest>(iContext.iMessage).iErrContext; |
|
498 } |
|
499 |
|
500 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
501 void CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest::DoL() |
|
502 { |
|
503 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
504 RNodeInterface* newSP = NULL; |
|
505 RNodeInterface* curSP = iContext.Node().ServiceProvider(); //Our current started Service Provider. |
|
506 |
|
507 //Choose Service Providers to work on |
|
508 TClientIter<TDefaultClientMatchPolicy> iter = iContext.Node().GetClientIter<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EServProvider)); |
|
509 RNodeInterface* itf = NULL; |
|
510 for (itf = iter++; itf!=NULL && newSP==NULL; itf = iter++) |
|
511 { |
|
512 if (itf==curSP) |
|
513 { |
|
514 newSP = iter++; //And the new one to try next |
|
515 } |
|
516 } |
|
517 |
|
518 //Sanity check. |
|
519 //The new provider must not be started, there can be only one started at a time. |
|
520 __ASSERT_DEBUG(newSP==NULL || (newSP->Flags() & TCFClientType::EStarted)==0, User::Panic(KSpecAssert_ESockMbCrMCPRAct, 3)); |
|
521 |
|
522 //If there is no other Service Provider to try, return KErrNotFound |
|
523 if (newSP==NULL || curSP == NULL) |
|
524 { |
|
525 #ifdef __CFLOG_ACTIVE |
|
526 __CFLOG_VAR((KCoreMCprStatesTag, KCoreMCprStatesSubTag, _L8("WARNING: CConnectionRecoveryActivity::TProcessConnectionStartRecoveryRequest::DoL() - no more choices, abandoning recovery."))); |
|
527 #endif |
|
528 User::Leave(KErrNotFound); |
|
529 } |
|
530 |
|
531 //Diagnostinc - there must be a data client or we cannot be here |
|
532 __ASSERT_DEBUG(iContext.Node().GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::EData)), User::Panic(KCoreMobileMCprPanic, KPanicNoDataClient)); |
|
533 iContext.iNodeActivity->PostRequestTo(iContext.NodeId(), |
|
534 TCFMcpr::TReConnect(curSP->RecipientId(), newSP->RecipientId()).CRef()); |
|
535 } |
|
536 |
|
537 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
538 void CConnectionRecoveryActivity::TProcessConnectionGoneDownRecoveryRequest::DoL() |
|
539 { |
|
540 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
541 CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
542 |
|
543 RNodeInterface* started = iContext.Node().ServiceProvider(); |
|
544 TUint apId = (TUint)activity.iOriginalErrContext.iInfo; |
|
545 RNodeInterface* gonedownsp = iContext.Node().FindServiceProvider(apId); |
|
546 if (started && started != gonedownsp) |
|
547 { |
|
548 CConnectionRecoveryActivity::TSendRetryRecoveryResponse tr(iContext); |
|
549 tr.DoL(); |
|
550 } |
|
551 else |
|
552 { |
|
553 CConnectionRecoveryActivity::TSendPropagateRecoveryResponse tr(iContext); |
|
554 tr.DoL(); |
|
555 } |
|
556 } |
|
557 |
|
558 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendRetryRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
559 void CConnectionRecoveryActivity::TSendRetryRecoveryResponse::DoL() |
|
560 { |
|
561 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
562 CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
563 TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::ERetry,KErrNone,activity.iOriginalErrContext.iMessageId)); |
|
564 activity.ReplyToOriginators(err); |
|
565 } |
|
566 |
|
567 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendPropagateRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
568 void CConnectionRecoveryActivity::TSendPropagateRecoveryResponse::DoL() |
|
569 { |
|
570 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
571 CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
572 TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::EPropagate, |
|
573 activity.iOriginalErrContext.iStateChange.iError,activity.iOriginalErrContext.iMessageId)); |
|
574 activity.ReplyToOriginators(err); |
|
575 } |
|
576 |
|
577 DEFINE_SMELEMENT(CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse, NetStateMachine::MStateTransition, CConnectionRecoveryActivity::TContext) |
|
578 void CConnectionRecoveryActivity::TSendIgnoreRecoveryResponse::DoL() |
|
579 { |
|
580 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileMCprPanic, KPanicNoActivity)); |
|
581 CConnectionRecoveryActivity& activity = static_cast<CConnectionRecoveryActivity&>(*iContext.iNodeActivity); |
|
582 TEErrorRecovery::TErrorRecoveryResponse err(TErrResponse(TErrResponse::EIgnore,KErrNone,activity.iOriginalErrContext.iMessageId)); |
|
583 activity.ReplyToOriginators(err); |
|
584 } |
|
585 |
|
586 |
|