|
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 // mobilityactivities.cpp |
|
15 // Mobility Connection Provider activity definitions. |
|
16 // |
|
17 // |
|
18 // |
|
19 |
|
20 /** |
|
21 @file |
|
22 @internalComponent |
|
23 */ |
|
24 |
|
25 #include <comms-infras/mobilitycpr.h> |
|
26 #include "mobilitycpractivities.h" |
|
27 #include <comms-infras/mobilitycprstates.h> |
|
28 #include <comms-infras/ss_coreprstates.h> |
|
29 |
|
30 #include <comms-infras/ss_nodemessages.h> |
|
31 #include <comms-infras/corecpractivities.h> |
|
32 #include <elements/nm_messages_errorrecovery.h> |
|
33 |
|
34 |
|
35 #ifdef _DEBUG |
|
36 // Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module |
|
37 // (if it could happen through user error then you should give it an explicit, documented, category + code) |
|
38 _LIT(KSpecAssert_ESockMbCrCPRAct, "ESockMbCrCPRAct"); |
|
39 #endif |
|
40 |
|
41 |
|
42 using namespace ESock; |
|
43 using namespace Messages; |
|
44 using namespace MeshMachine; |
|
45 using namespace NetStateMachine; |
|
46 using namespace MobilityCprActivities; |
|
47 using namespace MobilityCprStates; |
|
48 using namespace CorePanics; |
|
49 |
|
50 // |
|
51 //Panics |
|
52 #ifdef _DEBUG |
|
53 _LIT (KCoreMobileCprPanic,"CoreMobileCprPanic"); |
|
54 #endif |
|
55 |
|
56 namespace CprMobilityActivity |
|
57 { |
|
58 /** |
|
59 Activity responsible for interacting with the ESock client mobility extension |
|
60 API and with the MCPR for the acceptance or rejection of requests to migrate |
|
61 bearer. |
|
62 */ |
|
63 DECLARE_DEFINE_CUSTOM_NODEACTIVITY(ECFActivityCprMobility, MobilityCprMobility, TCFMobilityProvider::TStartMobility, CMobilityActivity::NewL) |
|
64 FIRST_NODEACTIVITY_ENTRY(MobilityCprStates::TAwaitingStartMobility, MeshMachine::TNoTag) |
|
65 |
|
66 // Attempt to start mobility activity on the meta plane |
|
67 NODEACTIVITY_ENTRY(KNoTag, MobilityCprStates::TSendStartMobility, MobilityCprStates::TAwaitingMobilityStartedOrError, MeshMachine::TNoTagOrErrorTag) |
|
68 |
|
69 // Success - complete the IPC client |
|
70 THROUGH_NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TCompleteMobilityClient, TTag<CMobilityActivity::KWaitForMobility>) |
|
71 |
|
72 //<BEGIN> MAIN LOOP **************** |
|
73 //Awaiting mobility triggers, which can either be: |
|
74 //(1) TMigrationNotification (PreferredCarrierAvailable) coming from the control provider (presumably as a response to changing availability) |
|
75 //(2) TMigrationRejected (NewCarrierRejected) coming from the control client (who's presumably not content with the currently offered carrier). |
|
76 //(3) TError coming from the control provider in response to the previous rejection. The client rejected the current bearer, but there are no more bearers to offer. |
|
77 NODEACTIVITY_ENTRY(CMobilityActivity::KWaitForMobility, MeshMachine::TDoNothing, MobilityCprStates::TAwaitingNewCarrierOrErrorOrRelayAndConsumeCurrentCarrierRejected, CMobilityActivity::TStartHandshakeOrErrorTagBlockedByClientNotReady) |
|
78 |
|
79 // Notify the ESock client that a preferred carrier is available and await the client to respond |
|
80 // The response may be: |
|
81 // (1) TCFMobilityProvider::TMigrationRequested - proceed with the migration - the tuple will jump (with KNoTag) to await for the control provider to supply the new bearer. |
|
82 // (2) TCFMobilityProvider::TMigrationRejected - abort the migration - the tuple will jump (with KWaitForMobility | EBackaward) back to awaiting for the preferred bearer. |
|
83 // Note that TAwaitAndRelayMigrationRequestedOrMigrationRejected does the job of forwarding both messages to the control provider. |
|
84 NODEACTIVITY_ENTRY(CMobilityActivity::KStartHandshake, CMobilityActivity::TNotifyClientPreferredCarrierAvailable, MobilityCprStates::TAwaitAndRelayMigrationRequestedOrMigrationRejected, CMobilityActivity::TNoTagOrWaitForMobilityBackwards) |
|
85 |
|
86 //We've just told the control provider (see above: TAwaitAndRelayMigrationRequested...) that the offered carrier has been accepted - the client is requesting migration. |
|
87 //The control provider may respond threefold: |
|
88 //(1) TMigrationComplete - Proceed with the migration - the tuple will jump (with KNoTag) to starting of the bearer; |
|
89 //(2) TMigrationNotification - offer another bearer (if the current one became out of date) - the tuple will jump back to the processing of the new bearer |
|
90 //(3) TError - abort mobility if the current bearer is out of date and there are no more bearers to offer - the tuple will jump to the KErrorTag tuple who will decide what kind of error it is. |
|
91 NODEACTIVITY_ENTRY(KNoTag, MeshMachine::TDoNothing, MobilityCprStates::TAwaitingMigrationCompleteOrNewCarrierOrError, MobilityCprStates::TNoTagOrStartHandshakeBackwardsOrError) |
|
92 THROUGH_NODEACTIVITY_ENTRY(KErrorTag, CMobilityActivity::TCompleteMobilityClient, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>) |
|
93 |
|
94 // Start the new connection |
|
95 NODEACTIVITY_ENTRY(KNoTag, CoreNetStates::TStartServiceProvider, MobilityCprStates::TAwaitingStartedOrError, CMobilityActivity::TNoTagOrErrorTagBlockedByClientNotReady) |
|
96 NODEACTIVITY_ENTRY(KErrorTag, TSendErrorRecoveryReq, MeshMachine::TAwaitingErrorRecoveryResponseOrError, CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrErrorBlockedByClientNotReady) |
|
97 |
|
98 //If the bearer fails to start, the can be another bearer available, so we need to notify the control provider in case it can offer one. |
|
99 //This node does that by rejecting the current bearer. |
|
100 THROUGH_NODEACTIVITY_ENTRY(CoreStates::KRecoverableErrorTag, MobilityCprStates::TSendMigrationRejected, TTag<CMobilityActivity::KWaitForMobility|EBackward>) |
|
101 THROUGH_NODEACTIVITY_ENTRY(KErrorTag, CMobilityActivity::TCompleteMobilityClient, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>) |
|
102 |
|
103 NODEACTIVITY_ENTRY(KNoTag, CMobilityActivity::TNotifyClientNewCarrierActive, MobilityCprStates::TAwaitAndRelayMigrationAcceptedOrMigrationRejected, MeshMachine::TTag<CMobilityActivity::KWaitForMobility|EBackward>) |
|
104 //<END> MAIN LOOP ************** |
|
105 |
|
106 NODEACTIVITY_END() |
|
107 } // namespace CprMobilityActivity |
|
108 |
|
109 namespace MobilityCprActivities |
|
110 { |
|
111 DEFINE_EXPORT_ACTIVITY_MAP(mobilityCprActivities) |
|
112 ACTIVITY_MAP_ENTRY(CprMobilityActivity, MobilityCprMobility) |
|
113 ACTIVITY_MAP_END_BASE(CprActivities, coreCprActivities) |
|
114 } |
|
115 |
|
116 // |
|
117 // CMobilityActivity |
|
118 CMobilityActivity::CMobilityActivity(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
119 : MeshMachine::CNodeRetryActivity(aActivitySig, aNode) |
|
120 { |
|
121 __ASSERT_DEBUG(static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity == NULL, User::Panic(KCoreMobileCprPanic, KPanicActivity)); |
|
122 } |
|
123 |
|
124 CMobilityActivity::~CMobilityActivity() |
|
125 { |
|
126 //This pointer becomes invalid now, clear if still set. |
|
127 static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity = NULL; |
|
128 CCommsApiExtResponder::Complete(iResponder, Error() ? Error() : KErrAbort); //Safe if NULL |
|
129 SetError(KErrNone); |
|
130 } |
|
131 |
|
132 MeshMachine::CNodeActivityBase* CMobilityActivity::NewL(const MeshMachine::TNodeActivity& aActivitySig, MeshMachine::AMMNodeBase& aNode) |
|
133 { |
|
134 CMobilityActivity* self = new(ELeave) CMobilityActivity(aActivitySig, aNode); |
|
135 return self; |
|
136 } |
|
137 |
|
138 void CMobilityActivity::SetResponder(ESock::CCommsApiExtResponder& aResponder) |
|
139 { |
|
140 __ASSERT_DEBUG(iResponder==NULL, User::Panic(KSpecAssert_ESockMbCrCPRAct, 7)); |
|
141 __ASSERT_DEBUG(&aResponder, User::Panic(KSpecAssert_ESockMbCrCPRAct, 8)); |
|
142 iResponder = &aResponder; |
|
143 |
|
144 //CMobilityActivity::TMobilityClientNotReadyMutex may have CMobilityActivity await for |
|
145 //iResponder to pop up and if it is waiting, we need to signal it. |
|
146 TNodeNullContext context(iNode, this); |
|
147 Signal(context); |
|
148 } |
|
149 |
|
150 TBool CMobilityActivity::TMobilityClientNotReadyMutex::IsBlocked(MeshMachine::TNodeContextBase& aContext) |
|
151 { |
|
152 __ASSERT_DEBUG(aContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity)); |
|
153 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*aContext.iNodeActivity); |
|
154 return activity.iResponder? EFalse : ETrue; |
|
155 } |
|
156 |
|
157 //Cpr::CMobilityActivity has no originators |
|
158 void CMobilityActivity::StartL(TNodeContextBase& aContext, const Messages::XNodePeerId& aOriginator, const TStateTriple& aFirst) |
|
159 { |
|
160 //This activity does not support multiple clients. Any subsequent client should be completed with KErrNotSupported |
|
161 //from CMobilityConnectionProvider::OpenExtensionInterface(). |
|
162 __ASSERT_DEBUG(iOriginators.Count()==0, User::Panic(KSpecAssert_ESockMbCrCPRAct, 1)); |
|
163 |
|
164 MeshMachine::CNodeRetryActivity::StartL(aContext, aOriginator, aFirst); |
|
165 |
|
166 TCFMobilityProvider::TStartMobility& msg = message_cast<TCFMobilityProvider::TStartMobility>(aContext.iMessage); |
|
167 iResponder = static_cast<CCommsApiExtResponder*>(msg.iPtr); |
|
168 iClientId = msg.iValue; |
|
169 __ASSERT_DEBUG(msg.iValue != 0, User::Panic(KSpecAssert_ESockMbCrCPRAct, 2)); //Client id must be valid here. |
|
170 |
|
171 //Set a pointer to the mobility activity in the node on which it's running |
|
172 __ASSERT_DEBUG(static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity == NULL, User::Panic(KSpecAssert_ESockMbCrCPRAct, 3)); |
|
173 static_cast<CMobilityConnectionProvider&>(iNode).iMobilityActivity = this; |
|
174 } |
|
175 |
|
176 void CMobilityActivity::Cancel(TNodeContextBase& aContext) |
|
177 { |
|
178 RNodeInterface* cp = iNode.GetFirstClient<TDefaultClientMatchPolicy>(TClientType(TCFClientType::ECtrlProvider)); |
|
179 __ASSERT_DEBUG(cp, User::Panic(KSpecAssert_ESockMbCrCPRAct, 4)); //We are a Cpr, must exist. |
|
180 |
|
181 //PostedTo() could be our service provider or possibly other peer |
|
182 if (PostedToId() != cp->RecipientId()) |
|
183 { |
|
184 cp->PostMessage(TNodeCtxId(ActivityId(), iNode.Id()), |
|
185 TEBase::TCancel().CRef()); |
|
186 } |
|
187 |
|
188 MeshMachine::CNodeRetryActivity::Cancel(aContext); //Send TCancel to iPostedTo |
|
189 } |
|
190 |
|
191 |
|
192 DEFINE_SMELEMENT(CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrError, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
193 TInt CMobilityActivity::TNoTagBackwardsOrRecoverableErrorOrError::TransitionTag() |
|
194 { |
|
195 if (iContext.iMessage.IsMessage<TEErrorRecovery::TErrorRecoveryResponse>()) |
|
196 { |
|
197 TErrResponse& resp = message_cast<TEErrorRecovery::TErrorRecoveryResponse>(iContext.iMessage).iErrResponse; |
|
198 if (resp.iAction == TErrResponse::ERetry) |
|
199 { |
|
200 return KNoTag | NetStateMachine::EBackward; |
|
201 } |
|
202 else if (resp.iAction == TErrResponse::EPropagate || resp.iError == KErrCancel) |
|
203 { |
|
204 return KErrorTag; |
|
205 } |
|
206 else if (resp.iAction == TErrResponse::EIgnore) // and or iError is KErrCancel |
|
207 { |
|
208 //TODO RZ: This looks inappropriate. EIgnore and EPropagate flags are not |
|
209 //really complimentary. They're simply invalid in soem scenarios. |
|
210 //Here we use ignore to an activity that attempted error recovery, |
|
211 //it technically cannot ignore the error. It will propagate it back |
|
212 //to the MCPR (and not to the client) by rejecting the current bearer. |
|
213 //It feels thought clearing the error doesn't belong here. It probably |
|
214 //belongs to the error activity. |
|
215 iContext.Activity()->SetError(KErrNone); |
|
216 return CoreStates::KRecoverableErrorTag; |
|
217 } |
|
218 } |
|
219 return KNoTag; |
|
220 } |
|
221 |
|
222 |
|
223 DEFINE_SMELEMENT(CMobilityActivity::TNoTagOrWaitForMobilityBackwards, NetStateMachine::MStateFork, CMobilityActivity::TContext) |
|
224 TInt CMobilityActivity::TNoTagOrWaitForMobilityBackwards::TransitionTag() |
|
225 { |
|
226 if(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRequested>()) |
|
227 { |
|
228 return KNoTag; |
|
229 } |
|
230 else |
|
231 { |
|
232 __ASSERT_DEBUG(iContext.iMessage.IsMessage<TCFMobilityProvider::TMigrationRejected>(), User::Panic(KSpecAssert_ESockMbCrCPRAct, 6)); |
|
233 return CMobilityActivity::KWaitForMobility|EBackward; |
|
234 } |
|
235 } |
|
236 |
|
237 |
|
238 //Transitions |
|
239 |
|
240 DEFINE_SMELEMENT(CMobilityActivity::TCompleteMobilityClient, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
241 void CMobilityActivity::TCompleteMobilityClient::DoL() |
|
242 { |
|
243 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity)); |
|
244 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
245 CCommsApiExtResponder::Complete(activity.iResponder, activity.Error()); |
|
246 |
|
247 //There is only one way to kill the mobility activity and it is by the client closing the API extension. |
|
248 //This will be manifested with KErrCancel. |
|
249 if (activity.Error() == KErrCancel) |
|
250 { |
|
251 activity.SetIdle(); |
|
252 } |
|
253 activity.SetError(KErrNone); //The error has been handled |
|
254 activity.ClearPostedTo(); |
|
255 } |
|
256 |
|
257 DEFINE_SMELEMENT(CMobilityActivity::TNotifyClientPreferredCarrierAvailable, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
258 void CMobilityActivity::TNotifyClientPreferredCarrierAvailable::DoL() |
|
259 { |
|
260 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity)); |
|
261 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
262 TCFMobilityControlClient::TMigrationNotification& msg = message_cast<TCFMobilityControlClient::TMigrationNotification>(iContext.iMessage); |
|
263 |
|
264 activity.iCurrentAp = msg.iValue1; |
|
265 activity.iPreferredAp = msg.iValue2; |
|
266 activity.iIsUpgrade = msg.iValue3; |
|
267 |
|
268 CCommsMobilitySrvResp* responder = static_cast<CCommsMobilitySrvResp*>(activity.iResponder); |
|
269 activity.iResponder = NULL; |
|
270 CCommsMobilitySrvResp::PreferredCarrierAvailable(responder, TAccessPointInfo(activity.iCurrentAp), TAccessPointInfo(activity.iPreferredAp), activity.iIsUpgrade, EFalse); |
|
271 activity.ClearPostedTo(); |
|
272 } |
|
273 |
|
274 DEFINE_SMELEMENT(CMobilityActivity::TNotifyClientNewCarrierActive, NetStateMachine::MStateTransition, CMobilityActivity::TContext) |
|
275 void CMobilityActivity::TNotifyClientNewCarrierActive::DoL() |
|
276 { |
|
277 __ASSERT_DEBUG(iContext.iNodeActivity, User::Panic(KCoreMobileCprPanic, KPanicNoActivity)); |
|
278 CMobilityActivity& activity = static_cast<CMobilityActivity&>(*iContext.iNodeActivity); |
|
279 CCommsMobilitySrvResp* responder = static_cast<CCommsMobilitySrvResp*>(activity.iResponder); |
|
280 activity.iResponder = NULL; |
|
281 CCommsMobilitySrvResp::NewCarrierActive(responder, TAccessPointInfo(activity.iPreferredAp), EFalse); |
|
282 activity.ClearPostedTo(); |
|
283 } |
|
284 |
|
285 |