|
1 // Copyright (c) 2004-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 // SPUD binder manager |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalComponent |
|
21 */ |
|
22 |
|
23 #include "bindman.h" |
|
24 #include "spudnotify.h" |
|
25 #include "mux.h" |
|
26 #include <nifman.h> |
|
27 |
|
28 /** Default name of lower NIF */ |
|
29 _LIT(KDefaultLowerNifName, "rawip"); |
|
30 |
|
31 #ifdef __FLOG_ACTIVE |
|
32 #define BINDMAN_LOG(x) SpudMan()->x |
|
33 #else |
|
34 #define BINDMAN_LOG(x) |
|
35 #endif |
|
36 |
|
37 //***************************************************************************** |
|
38 // CBindMan |
|
39 //***************************************************************************** |
|
40 |
|
41 /** |
|
42 Constructs BindMan. Ownership of aMux and aProto is transferred to this object. |
|
43 |
|
44 @param aSpudMan Reference to SpudMan object |
|
45 @param aMux Pointer to SpudMux object (ownership is transferred) |
|
46 @param aProto Pointer to SpudProtocol object (ownership is transferred) |
|
47 */ |
|
48 CBindMan::CBindMan(CSpudMan& aSpudMan, CSpudMux* aMux, CSpudProtocol* aProto) |
|
49 : iSpudMan(aSpudMan), iMux(aMux), iDeleteMux(ETrue), iSpudProtocol(aProto) |
|
50 { |
|
51 ReadLowerNifName(); |
|
52 } |
|
53 |
|
54 CBindMan::~CBindMan() |
|
55 { |
|
56 BINDMAN_LOG(__FLOG(_L("BindMan::~BindMan"))); |
|
57 |
|
58 #ifdef __FLOG_ACTIVE // Log for diagnostic purposes |
|
59 TInt idx; |
|
60 for(idx = 0; idx < iBinders.Count(); ++idx) |
|
61 { |
|
62 if(iBinders[idx] && iBinders[idx]->IsBound()) |
|
63 { |
|
64 BINDMAN_LOG(__FLOG_1(_L("~BindMan: deleting bound lower NIF binding for context[%d]"), idx)); |
|
65 } |
|
66 } |
|
67 #endif |
|
68 |
|
69 iBinders.DeleteAll(); |
|
70 delete iSpudProtocol; |
|
71 if (iDeleteMux) |
|
72 { |
|
73 delete iMux; |
|
74 } |
|
75 } |
|
76 |
|
77 /** |
|
78 Reads the lower NIF name from CommDb. |
|
79 |
|
80 @todo This function incorrectly returns the default value when IfParams is of the form: |
|
81 "notlowernif=UNWANTED,lowernif=IGNORED". |
|
82 This defect is also present in CPppLcp::InitL. |
|
83 */ |
|
84 void CBindMan::ReadLowerNifName(void) |
|
85 { |
|
86 TBuf<KCommsDbSvrMaxFieldLength> params; |
|
87 _LIT(KInterfaceIdentifier,"lowernif="); |
|
88 const TInt KLinkEqualsLength = 9; // length of "lowernif=" |
|
89 ASSERT(static_cast<const TDesC&>(KInterfaceIdentifier).Length() == KLinkEqualsLength); |
|
90 |
|
91 // Read IfParams field |
|
92 iSpudMan.Notify()->ReadDes(TPtrC(ISP_IF_PARAMS), params); |
|
93 |
|
94 TInt paramStartMarker = params.Find(KInterfaceIdentifier); |
|
95 |
|
96 if (paramStartMarker == KErrNotFound) |
|
97 { |
|
98 // "lowernif=" not found in the string - use default lower layer |
|
99 iLowerNifName = KDefaultLowerNifName; |
|
100 BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName)); |
|
101 } |
|
102 else |
|
103 { |
|
104 // "lowernif=<nifname>" found in the string - extract the lower layer Nif name |
|
105 |
|
106 if (paramStartMarker > 0 && params[paramStartMarker-1] != ',') |
|
107 { |
|
108 // "xyzlowernif=<xxx>" found rather than "lowernif=<xxx>" - use default lower layer |
|
109 iLowerNifName = KDefaultLowerNifName; |
|
110 BINDMAN_LOG(__FLOG_1(_L("Lower NIF name not configured; defaulting to %S"), &iLowerNifName)); |
|
111 } |
|
112 else |
|
113 { |
|
114 // String of the form "[...,]lowernif=<nifname>[,...]" found - extract the Nif name |
|
115 TPtrC postfix(params.Mid(paramStartMarker + KLinkEqualsLength)); |
|
116 TInt comma = postfix.Locate(','); |
|
117 if (comma != KErrNotFound) |
|
118 { |
|
119 postfix.Set(postfix.Ptr(), comma); |
|
120 } |
|
121 iLowerNifName = postfix; |
|
122 } |
|
123 } |
|
124 } |
|
125 |
|
126 /** |
|
127 Informs CSpudProtocol of the CProtocolBase pointer from the L3 protocol. |
|
128 */ |
|
129 void CBindMan::SetProtocolBaseL(CProtocolBase* aProtocolBase) const |
|
130 { |
|
131 iSpudProtocol->SetProtocolBaseL(aProtocolBase); |
|
132 } |
|
133 |
|
134 /** |
|
135 Returns the binder for the given context ID. |
|
136 @param aContextId context ID |
|
137 @return Pointer to binder object |
|
138 @leave KErrBadHandle or KErrNotReady if context ID is invalid or not found |
|
139 */ |
|
140 CSpudBinderRef* CBindMan::GetRefL(TContextId aContextId) const |
|
141 { |
|
142 if (aContextId < 0 || aContextId >= iBinders.Count()) |
|
143 { |
|
144 BINDMAN_LOG(__FLOG_1(_L("CBindMan::GetRefL invalid context ID %d"), aContextId)); |
|
145 User::Leave(KErrBadHandle); |
|
146 } |
|
147 CSpudBinderRef* ref = iBinders[aContextId]; |
|
148 if (ref == NULL) |
|
149 { |
|
150 // This situation can frequently occur when looping through all binders |
|
151 User::Leave(KErrNotReady); |
|
152 } |
|
153 return ref; |
|
154 } |
|
155 |
|
156 /** |
|
157 Returns the binder for any lower NIF that is available and bound. |
|
158 @return Pointer to binder object |
|
159 @leave KErrNotReady if no lower NIF is found |
|
160 */ |
|
161 CSpudBinderRef* CBindMan::GetAnyRefL() const |
|
162 { |
|
163 TInt index; |
|
164 for (index=0; index < iBinders.Count(); ++index) |
|
165 { |
|
166 CSpudBinderRef* ref = iBinders[index]; |
|
167 if (ref && ref->IsBound() && ref->State() != ESpudWaitBinderDelete) |
|
168 { |
|
169 return ref; |
|
170 } |
|
171 } |
|
172 BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetAnyRefL Can't find any bound NIF"))); |
|
173 User::Leave(KErrNotReady); |
|
174 return NULL; // never reached |
|
175 } |
|
176 |
|
177 /** |
|
178 Returns the context ID the given lower NIF. |
|
179 @param aNifBase pointer to lower NIF |
|
180 @return context ID |
|
181 @leave KErrNotReady if lower NIF is not found |
|
182 */ |
|
183 TContextId CBindMan::FindContextIdL(const CNifIfBase* aNifBase) const |
|
184 { |
|
185 TContextId index; |
|
186 for (index=0; index < iBinders.Count(); ++index) |
|
187 { |
|
188 CSpudBinderRef* ref = iBinders[index]; |
|
189 if (ref && ref->MatchBase(aNifBase)) |
|
190 { |
|
191 return index; |
|
192 } |
|
193 } |
|
194 BINDMAN_LOG(__FLOG_1(_L("CBindMan::FindContextIdL Can't find aNifBase %x"), aNifBase)); |
|
195 User::Leave(KErrNotReady); |
|
196 return KAllContexts; // never reached |
|
197 } |
|
198 |
|
199 /** |
|
200 Returns the number of bound contexts. |
|
201 @return Number of bound contexts |
|
202 */ |
|
203 TUint CBindMan::NumContexts() const |
|
204 { |
|
205 TInt index; |
|
206 TUint count = 0; |
|
207 for (index=0; index < iBinders.Count(); ++index) |
|
208 { |
|
209 CSpudBinderRef* ref = iBinders[index]; |
|
210 if (ref && ref->IsBound()) |
|
211 { |
|
212 ++count; |
|
213 } |
|
214 } |
|
215 return count; |
|
216 } |
|
217 |
|
218 /** |
|
219 Checks if this is is the last 'valid' context in SPUD, i.e. it is bound and not marked for deletion. |
|
220 |
|
221 @param aContextID the ID of the context to check |
|
222 @return ETrue if and only if aContextId (the subject bindre) is the only valid, bound, unmarked binder. |
|
223 */ |
|
224 TBool CBindMan::IsLastContext(TContextId aContextId)const |
|
225 { |
|
226 ASSERT(aContextId >= 0 && NumContexts() > 0); // we shouldn't be called unless we have at least 1 ctx |
|
227 |
|
228 TUint numLiveBoundBinders(0); |
|
229 TBool isTargetBinderFound(EFalse); // The binder for the subject context exists, is bound, and not marked for deletion. |
|
230 |
|
231 TInt binderIdx; |
|
232 for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // sift through all the binders |
|
233 { |
|
234 if(iBinders[binderIdx] && // binder exists |
|
235 iBinders[binderIdx]->IsBound() && // is bound |
|
236 ESpudWaitBinderDelete != iBinders[binderIdx]->State() // not marked for deletion |
|
237 ) |
|
238 { |
|
239 ++numLiveBoundBinders; |
|
240 |
|
241 if(binderIdx == aContextId) |
|
242 { |
|
243 isTargetBinderFound = ETrue; |
|
244 } |
|
245 } |
|
246 } |
|
247 ASSERT(isTargetBinderFound); // sanity check: we have a referene to the subject binder, |
|
248 // and it is 'valid': bound and not marked for deletion. |
|
249 |
|
250 if(0 == numLiveBoundBinders) // No valid bound binders remain. |
|
251 { |
|
252 ASSERT(EFalse); // spudman thinks it has valid binders, when there are none. |
|
253 |
|
254 // In release builds, we can't say that there are more binders, because we have no |
|
255 // references to them. |
|
256 return ETrue; // EFalse implies that we have at least 1 binder |
|
257 } |
|
258 else if(1 == numLiveBoundBinders) |
|
259 { |
|
260 // In release builds: if live binder is not the subject context, we can't claim that the |
|
261 // subject context is the last one, or SPUD may shutdown when it has a context. |
|
262 return isTargetBinderFound; // Is there another valid binder beside the subject? |
|
263 } |
|
264 else // > 1 |
|
265 { |
|
266 // Regardless of whether the subject context was found, we have more. |
|
267 return EFalse; |
|
268 } |
|
269 } |
|
270 |
|
271 /** |
|
272 Creates and returns a pointer to a new binder object. Ownership remains with BindMan; |
|
273 DeleteRef() must be called to delete the binder reference object. |
|
274 |
|
275 @param aContextId Holds the new context ID on return |
|
276 @return Pointer to binder object |
|
277 @leave KErrNotSupported if we are out of PDP contexts, or KErrNoMemory if out of RAM |
|
278 */ |
|
279 CSpudBinderRef* CBindMan::GetNewRefForSecondaryL(TContextId& aContextId) |
|
280 { |
|
281 // Reusing the slot of the primary context is not allowed. |
|
282 static const TContextId KFirst2ndaryCtxIdx(KPrimaryContextId + 1); |
|
283 TContextId index; |
|
284 for (index = KFirst2ndaryCtxIdx; index < iBinders.Count(); ++index) |
|
285 { |
|
286 CSpudBinderRef*& ref = iBinders[index]; |
|
287 if (ref == NULL) |
|
288 { |
|
289 // Create a binder in this new slot |
|
290 aContextId = index; |
|
291 // ref is a reference to a pointer that is owned by Bindman. It will be deleted in the |
|
292 // destructor. There is no need for CleanupStack. |
|
293 ref = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan()); |
|
294 ref->ConstructL(iSpudMan.Notify(), aContextId); |
|
295 return ref; |
|
296 } |
|
297 else if (!ref->IsBound()) |
|
298 { |
|
299 // This binder was previously constructed but unbound |
|
300 ASSERT(ref->Notify() == iSpudMan.Notify()); |
|
301 aContextId = index; |
|
302 return ref; |
|
303 } |
|
304 } |
|
305 BINDMAN_LOG(__FLOG_0(_L("CBindMan::GetNewRefForSecondaryL No room for new binder reference"))); |
|
306 User::Leave(KErrNotSupported); |
|
307 return NULL; // never reached |
|
308 } |
|
309 |
|
310 |
|
311 |
|
312 /** |
|
313 Creates and returns a pointer to the new binder for the Primary PDP context. |
|
314 The primary is a special case, because it can be created only once, and it uses a special |
|
315 ID = 0. If the primary fails then a secondary can be promoted to primary status |
|
316 even in this case ID = 0 is not re-used because GetNewRefForSecondaryL prevents this. |
|
317 This means that KPrimaryContextId is only significant once at startup time! |
|
318 |
|
319 Ownership remains with BindMan; |
|
320 DeleteRef() must be called to delete the binder reference object. |
|
321 |
|
322 @return the pointer to the binder object for the primary pdp context. |
|
323 @leave if the construction of the binder leaves. |
|
324 */ |
|
325 CSpudBinderRef* CBindMan::GetNewRefForPrimaryL() |
|
326 { |
|
327 CSpudBinderRef*& primRef = iBinders[KPrimaryContextId]; |
|
328 if(primRef) // We must not try to create the primary more than once. |
|
329 { |
|
330 ASSERT(EFalse); |
|
331 User::Leave(KErrAlreadyExists); // Release builds |
|
332 } |
|
333 // primRef is a reference to a pointer that is owned by Bindman. It will be deleted in the |
|
334 // destructor. There is no need for CleanupStack. |
|
335 primRef = new (ELeave) CSpudBinderRef(*iSpudMan.BindMan()); |
|
336 primRef->ConstructL(iSpudMan.Notify(), KPrimaryContextId); |
|
337 return primRef; |
|
338 } |
|
339 |
|
340 |
|
341 |
|
342 /** |
|
343 Loads a new lower NIF and bind to the binder ref |
|
344 |
|
345 @param aName Protocol name desired |
|
346 @param aBinder the binder to bind the lower NIF into. |
|
347 @see CNifAgentRef::ServiceStarted() |
|
348 */ |
|
349 void CBindMan::LoadNifL(const TDesC& aName, CSpudBinderRef& aBinder) |
|
350 { |
|
351 BINDMAN_LOG(__FLOG_2(_L("CBindMan::LoadNifL loading NIF %S for protocol %S"), &iLowerNifName, &aName)); |
|
352 |
|
353 CNifIfLink* lowerNif=static_cast<CNifIfLink*>(Nif::CreateInterfaceL(iLowerNifName, aBinder.Notify())); |
|
354 |
|
355 // Increment reference count |
|
356 lowerNif->Open(); |
|
357 |
|
358 CleanupClosePushL(*lowerNif); |
|
359 // Create CNifIfBase and bind it |
|
360 // Maybe binding should be left to CSpudBinderRef |
|
361 CNifIfBase* nifBase = lowerNif->GetBinderL(aName); |
|
362 CleanupStack::Pop(); |
|
363 |
|
364 // Increment reference count |
|
365 nifBase->Open(); |
|
366 |
|
367 // Bind the lower NIF into the SPUD |
|
368 aBinder.Bind(lowerNif, nifBase); |
|
369 |
|
370 // Bind the lower NIF to SpudProtocol |
|
371 nifBase->BindL(iSpudProtocol); |
|
372 } |
|
373 |
|
374 |
|
375 /** Deletes the dead (marked for deletion) references to lower NIF bindings.. |
|
376 |
|
377 @return the number of contexts remaining after the deletion |
|
378 */ |
|
379 TUint CBindMan::SweepBinders() |
|
380 { |
|
381 TUint liveContexts(0); |
|
382 TInt binderIdx; |
|
383 for(binderIdx = 0; binderIdx < iBinders.Count(); ++binderIdx) // Sift through all the binders |
|
384 { |
|
385 if(iBinders[binderIdx] && iBinders[binderIdx]->IsBound()) // Binder exists and is bound to a lower NIF |
|
386 { |
|
387 if(ESpudWaitBinderDelete == iBinders[binderIdx]->State()) //Must be deleted |
|
388 { |
|
389 BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: deleting binder for context[%d]"), binderIdx)); |
|
390 delete iBinders[binderIdx]; |
|
391 iBinders[binderIdx] = NULL; |
|
392 } |
|
393 else // Binder exists and is bound, but is not eligible for deletion. |
|
394 { |
|
395 BINDMAN_LOG(__FLOG_1(_L("CBindMan::SweepBinders: context[%d] is alive."), binderIdx)); |
|
396 ++liveContexts; |
|
397 } |
|
398 } |
|
399 // Binder is not bound. We don't care. It will be taken care of in the destructor. |
|
400 } |
|
401 return liveContexts; |
|
402 } |
|
403 |
|
404 //***************************************************************************** |
|
405 // CSpudBinderRef |
|
406 //***************************************************************************** |
|
407 |
|
408 |
|
409 CSpudBinderRef::CSpudBinderRef(CBindMan& aBindMan) |
|
410 :iBindMan(aBindMan) |
|
411 { |
|
412 } |
|
413 |
|
414 CSpudBinderRef::~CSpudBinderRef() |
|
415 { |
|
416 if (IsBound()) |
|
417 { |
|
418 // This call causes the NIF base to delete itself |
|
419 iNifBase->Close(); |
|
420 |
|
421 // This call causes the NIF link to delete itself |
|
422 iNifLink->Close(); |
|
423 } |
|
424 |
|
425 delete iNotify; |
|
426 } |
|
427 |
|
428 /** |
|
429 Creates a SpudNotify object. |
|
430 @leave KErrNoMemory if out of RAM |
|
431 */ |
|
432 void CSpudBinderRef::ConstructL(MNifIfNotify* aNotify, TContextId aContextId) |
|
433 { |
|
434 iNotify = new (ELeave) CSpudNotify(iBindMan, aNotify, aContextId); |
|
435 } |