|
1 // Copyright (c) 2005-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 // EPOC includes |
|
17 #include <e32base.h> |
|
18 #include <e32property.h> |
|
19 #include <es_sock.h> |
|
20 #include <in_sock.h> |
|
21 #include <c32root.h> |
|
22 |
|
23 // Test system includes |
|
24 #include "TestStepESockSSA.h" |
|
25 #include "blocker.h" |
|
26 #include "ES_DUMMY.H" |
|
27 |
|
28 |
|
29 RMultipleWait::RMultipleWait(TInt aInitialCount) |
|
30 : iCount(aInitialCount) |
|
31 { |
|
32 iOwnerThread.Open(RThread().Id()); |
|
33 } |
|
34 |
|
35 void RMultipleWait::Close() |
|
36 { |
|
37 iOwnerThread.Close(); |
|
38 inherited::Close(); |
|
39 } |
|
40 |
|
41 void RMultipleWait::Signal(TInt aDelta) |
|
42 { |
|
43 inherited::Wait(); |
|
44 iCount += aDelta; |
|
45 iOwnerThread.RequestSignal(); |
|
46 inherited::Signal(); |
|
47 } |
|
48 |
|
49 void RMultipleWait::Wait() |
|
50 { |
|
51 while(iCount < 0) |
|
52 { |
|
53 User::WaitForAnyRequest(); |
|
54 } |
|
55 inherited::Wait(); |
|
56 --iCount; |
|
57 inherited::Signal(); |
|
58 } |
|
59 |
|
60 CTestStepESockSSA::CTestStepESockSSA() |
|
61 { |
|
62 } |
|
63 |
|
64 CTestStepESockSSA::~CTestStepESockSSA() |
|
65 { |
|
66 } |
|
67 |
|
68 void CTestStepESockSSA::SetDummyBlocking() |
|
69 { |
|
70 // Set the blocking state, so that when the blocking module is loaded it will block |
|
71 TSecurityPolicy nullPolicy(ECapability_None); |
|
72 TInt err = RProperty::Define(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, RProperty::EInt, nullPolicy, nullPolicy); |
|
73 if(err == KErrNone || err == KErrAlreadyExists) |
|
74 { |
|
75 RProperty::Set(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, CBlockerChannelHandler::EStateBlock); |
|
76 } |
|
77 } |
|
78 |
|
79 void CTestStepESockSSA::ClearDummyBlocking() |
|
80 { |
|
81 // Set the blocking state, so that when the blocking module is loaded it will block |
|
82 TSecurityPolicy nullPolicy(ECapability_None); |
|
83 TInt err = RProperty::Define(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, RProperty::EInt, nullPolicy, nullPolicy); |
|
84 if(err == KErrNone || err == KErrAlreadyExists) |
|
85 { |
|
86 RProperty::Set(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey, CBlockerChannelHandler::EStateRelease); |
|
87 } |
|
88 } |
|
89 |
|
90 void CTestStepESockSSA::DoDataThreadL(TDataThreadControl& aControl) |
|
91 { |
|
92 User::LeaveIfError(aControl.iSession.Connect()); |
|
93 |
|
94 // Wait for blocker to start blocking; we can then create an IP socket as it will have already loaded |
|
95 RProperty blockProp; |
|
96 TInt err = blockProp.Attach(TBlockerSID, CBlockerChannelHandler::EBlockingStateKey); |
|
97 if(err == KErrNone) |
|
98 { |
|
99 TRequestStatus status; |
|
100 do |
|
101 { |
|
102 blockProp.Subscribe(status); |
|
103 TInt blockState; |
|
104 err = blockProp.Get(blockState); |
|
105 if(err != KErrNone || blockState >= CBlockerChannelHandler::EStateBlocking) |
|
106 { |
|
107 blockProp.Cancel(); |
|
108 } |
|
109 User::WaitForRequest(status); |
|
110 } while(status == KErrNone); |
|
111 blockProp.Close(); |
|
112 } |
|
113 |
|
114 switch(aControl.iRequest) |
|
115 { |
|
116 case TDataThreadControl::ESocketOpen: |
|
117 { |
|
118 RSocket sock; |
|
119 User::LeaveIfError(sock.Open(aControl.iSession, KAfInet, KSockDatagram, KProtocolInetUdp)); |
|
120 sock.Close(); |
|
121 aControl.iBlocked = ETrue; |
|
122 aControl.iBlockSemaphore.Signal(1); |
|
123 aControl.iResult = sock.Open(aControl.iSession, KDummyOneName); // should block |
|
124 sock.Close(); |
|
125 break; |
|
126 } |
|
127 case TDataThreadControl::EHostResolverOpen: |
|
128 { |
|
129 RHostResolver hr; |
|
130 hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp); |
|
131 hr.Close(); |
|
132 aControl.iBlocked = ETrue; |
|
133 aControl.iBlockSemaphore.Signal(1); |
|
134 aControl.iResult = hr.Open(aControl.iSession, KDummyAddrFamily, KDummyOne); // should block |
|
135 hr.Close(); |
|
136 break; |
|
137 } |
|
138 case TDataThreadControl::EHostResolverOpenMulti: |
|
139 { |
|
140 RHostResolver hr; |
|
141 aControl.iBlocked = ETrue; |
|
142 aControl.iBlockSemaphore.Signal(1); |
|
143 aControl.iResult = hr.Open(aControl.iSession, KDummyAddrFamily, KDummyOne); // should block |
|
144 hr.Close(); |
|
145 break; |
|
146 } |
|
147 case TDataThreadControl::EServiceResolverOpen: |
|
148 { |
|
149 RServiceResolver sr; |
|
150 sr.Open(aControl.iSession, KAfInet, KSockDatagram, KProtocolInetUdp); |
|
151 sr.Close(); |
|
152 aControl.iBlocked = ETrue; |
|
153 aControl.iBlockSemaphore.Signal(1); |
|
154 aControl.iResult = sr.Open(aControl.iSession, KDummyAddrFamily, KSockDatagram, KDummyOne); // should block |
|
155 sr.Close(); |
|
156 break; |
|
157 } |
|
158 case TDataThreadControl::ENetDBOpen: |
|
159 { |
|
160 RNetDatabase ndb; |
|
161 ndb.Open(aControl.iSession, KAfInet, KProtocolInetUdp); |
|
162 ndb.Close(); |
|
163 aControl.iBlocked = ETrue; |
|
164 aControl.iBlockSemaphore.Signal(1); |
|
165 aControl.iResult = ndb.Open(aControl.iSession, KDummyAddrFamily, KDummyOne); // should block |
|
166 ndb.Close(); |
|
167 break; |
|
168 } |
|
169 case TDataThreadControl::ENumProtocols: |
|
170 { |
|
171 TUint numOfProtocols; |
|
172 aControl.iBlocked = ETrue; |
|
173 aControl.iBlockSemaphore.Signal(1); |
|
174 aControl.iResult = aControl.iSession.NumProtocols(numOfProtocols); // should block |
|
175 break; |
|
176 } |
|
177 case TDataThreadControl::EGetProtocolInfo: |
|
178 { |
|
179 TUint absentIndex = 99; |
|
180 TProtocolDesc protocolDesc; |
|
181 RHostResolver hr; |
|
182 hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp); |
|
183 hr.Close(); |
|
184 aControl.iBlocked = ETrue; |
|
185 aControl.iBlockSemaphore.Signal(1); |
|
186 aControl.iResult = aControl.iSession.GetProtocolInfo(absentIndex, protocolDesc); // should block |
|
187 break; |
|
188 } |
|
189 case TDataThreadControl::EFindProtocol: |
|
190 { |
|
191 _LIT(KAbsentProtocolName,"NoSuchProtocol"); |
|
192 TProtocolDesc protocolDesc; |
|
193 RHostResolver hr; |
|
194 hr.Open(aControl.iSession, KAfInet, KProtocolInetUdp); |
|
195 hr.Close(); |
|
196 aControl.iBlocked = ETrue; |
|
197 aControl.iBlockSemaphore.Signal(1); |
|
198 aControl.iResult = aControl.iSession.FindProtocol(KAbsentProtocolName(), protocolDesc); // should block |
|
199 break; |
|
200 } |
|
201 default: |
|
202 ASSERT(0); |
|
203 } |
|
204 } |
|
205 |
|
206 TInt CTestStepESockSSA::DataThreadEntry(TDataThreadControl& aControl) |
|
207 { |
|
208 CTrapCleanup* cleanupStack = CTrapCleanup::New(); |
|
209 if(!cleanupStack) |
|
210 { |
|
211 return KErrNoMemory; |
|
212 } |
|
213 TRAPD(err, DoDataThreadL(aControl)); |
|
214 // Signal that the thread is exiting. If we got here by a Leave() we still need to signal the control thread |
|
215 aControl.iBlockSemaphore.Signal(1); |
|
216 |
|
217 delete cleanupStack; |
|
218 return err; |
|
219 } |
|
220 |
|
221 TInt CTestStepESockSSA::CreateDataThread(TDataThreadControl::TRequestType aRequest, TDataThreadControl& aControl) |
|
222 { |
|
223 aControl.iRequest = aRequest; |
|
224 aControl.iResult = KRequestPending; |
|
225 aControl.iBlocked = EFalse; |
|
226 return aControl.iThread.Create(KNullDesC, reinterpret_cast<TThreadFunction>(CTestStepESockSSA::DataThreadEntry), 8192, NULL, &aControl); |
|
227 } |
|
228 |
|
229 TVerdict CTestStepESockSSA::WaitForDataThreadsToBlock(TDataThreadControl* aThreads, TInt aNumThreads) |
|
230 { |
|
231 TVerdict verdict = EPass; |
|
232 Logger().WriteFormat(_L("Resuming %d data thread(s) & waiting for blocking"), aNumThreads); |
|
233 for(TInt i = 0; i < aNumThreads; ++i) |
|
234 { |
|
235 aThreads[i].iThread.Resume(); |
|
236 User::After(1000000); |
|
237 Logger().WriteFormat(_L("Data thread: #%d %d %d"), i, aThreads[i].iThread.ExitReason(), aThreads[i].iBlocked); |
|
238 } |
|
239 |
|
240 aThreads[0].iBlockSemaphore.Wait(); // blocks until all data threads signal. If it hangs forever then check if one died |
|
241 User::After(KBlockedRequestIssueDelay); |
|
242 // Check whether all data threads have blocked |
|
243 for(TInt i = 0; i < aNumThreads; ++i) |
|
244 { |
|
245 if(!aThreads[i].iBlocked) |
|
246 { |
|
247 Logger().WriteFormat(_L("ERROR: Data thread #%d never got to block"), i); |
|
248 verdict = EFail; |
|
249 } |
|
250 else if(aThreads[i].iResult != KRequestPending) |
|
251 { |
|
252 Logger().WriteFormat(_L("ERROR: Data thread #%d went past block with %d"), i, aThreads[i].iResult); |
|
253 verdict = EFail; |
|
254 } |
|
255 } |
|
256 return verdict; |
|
257 } |
|
258 |
|
259 TVerdict CTestStepESockSSA::WaitForDataThreadsToComplete(TDataThreadControl* aThreads, TInt aNumThreads) |
|
260 { |
|
261 TVerdict verdict = EPass; |
|
262 Logger().WriteFormat(_L("Resuming ESOCK boot & waiting for %d data thread(s) to complete"), aNumThreads); |
|
263 aThreads[0].iBlockSemaphore.Signal(- aNumThreads + 1); |
|
264 ClearDummyBlocking(); |
|
265 aThreads[0].iBlockSemaphore.Wait(); // blocks until all data threads signal. If it hangs forever then check if one died |
|
266 |
|
267 User::After(KBlockedRequestCompletionDelay); |
|
268 // Check whether all data threads completed their requests properly |
|
269 for(TInt i = 0; i < aNumThreads; ++i) |
|
270 { |
|
271 if(aThreads[i].iResult != aThreads[i].iExpectedResult) |
|
272 { |
|
273 Logger().WriteFormat(_L("ERROR: Data thread #%d completed with %d, expected %d"), i, aThreads[i].iResult, aThreads[i].iExpectedResult); |
|
274 verdict = EFail; |
|
275 } |
|
276 } |
|
277 return verdict; |
|
278 } |
|
279 |
|
280 void CTestStepESockSSA::UnloadBlockerL() |
|
281 { |
|
282 // Unload the blocker module if it's there |
|
283 Logger().WriteFormat(_L("Unloading blocker module")); |
|
284 TAutoClose<RRootServ> rootserver; |
|
285 User::LeaveIfError(rootserver.iObj.Connect()); |
|
286 rootserver.PushL(); |
|
287 TRequestStatus status; |
|
288 TCFModuleName blockerName(KBlockerCPMName); |
|
289 rootserver.iObj.UnloadCpm(status, blockerName, EGraceful); |
|
290 User::WaitForRequest(status); |
|
291 rootserver.Pop(); |
|
292 Logger().WriteFormat(_L("Request completed with %d"), status.Int()); |
|
293 } |
|
294 |
|
295 void CTestStepESockSSA::KillC32Start() |
|
296 { |
|
297 // Start by looking for the running configurator and kill it if found. The caller |
|
298 // needs the appropriate capability to do this |
|
299 |
|
300 RDebug::Printf("Finding existing configurator process."); |
|
301 _LIT(KC32StartName, "*"); |
|
302 TInt result; |
|
303 TBool configuratorWasPresent; |
|
304 TInt count = 0; |
|
305 const TInt KMaxKillRetry = 10; |
|
306 do |
|
307 { |
|
308 configuratorWasPresent = EFalse; |
|
309 TFullName fn; |
|
310 TFindProcess fp(KC32StartName); |
|
311 while(fp.Next(fn) == KErrNone) |
|
312 { |
|
313 RProcess proc; |
|
314 result = proc.Open(fn); |
|
315 if(result == KErrNone) |
|
316 { |
|
317 TUidType type = proc.Type(); |
|
318 if(type[2] == TUid::Uid(KUidC32StartProcess) && proc.ExitType() == EExitPending) |
|
319 { |
|
320 // Kill the existing configurator process. |
|
321 RDebug::Print(_L("Opened existing configurator process \"%S\""), &fn); |
|
322 TRequestStatus status; |
|
323 proc.Logon(status); |
|
324 proc.Kill(KErrNone); |
|
325 RDebug::Printf("Killed process."); |
|
326 User::WaitForRequest(status); |
|
327 TExitType exitType = proc.ExitType(); |
|
328 |
|
329 // Create a timer in case some other entity holds an open handle on the |
|
330 // configurator which prevents the kernel from destroying it. We timeout |
|
331 // after one second. |
|
332 TAutoClose<RTimer> timer; |
|
333 if(timer.iObj.CreateLocal() == KErrNone) |
|
334 { |
|
335 // Request destruction notification so we know when it is safe to start |
|
336 // the process again. |
|
337 TRequestStatus destructionStatus; |
|
338 proc.NotifyDestruction(destructionStatus); |
|
339 proc.Close(); |
|
340 |
|
341 enum{ KProcessDestructionTimeout = 1000000 }; |
|
342 |
|
343 TRequestStatus timerStatus; |
|
344 timer.iObj.After(timerStatus, KProcessDestructionTimeout); |
|
345 |
|
346 // Wait for the process to be destroyed or for the timeout. |
|
347 User::WaitForRequest(destructionStatus, timerStatus); |
|
348 if(timerStatus.Int() == KRequestPending) |
|
349 { |
|
350 timer.iObj.Cancel(); |
|
351 User::WaitForRequest(timerStatus); |
|
352 } |
|
353 else |
|
354 { |
|
355 User::CancelMiscNotifier(destructionStatus); |
|
356 User::WaitForRequest(destructionStatus); |
|
357 |
|
358 RDebug::Printf("Existing configurator process has still not been destroyed after %f.0s", KProcessDestructionTimeout / 1000000.0); |
|
359 } |
|
360 } |
|
361 else |
|
362 { |
|
363 proc.Close(); |
|
364 } |
|
365 |
|
366 RDebug::Printf("Process logon completed with %d, exitType %d", status.Int(), exitType); |
|
367 configuratorWasPresent = ETrue; |
|
368 } |
|
369 else |
|
370 { |
|
371 proc.Close(); |
|
372 } |
|
373 } |
|
374 } |
|
375 } while(configuratorWasPresent && ++count < KMaxKillRetry); |
|
376 |
|
377 if (count >= KMaxKillRetry) |
|
378 { |
|
379 RDebug::Printf("KillC32Start - Cannot kill the configurator process, we will try continue and hope all is well"); |
|
380 } |
|
381 |
|
382 // Restart the boot sequence from scratch - the configurator reads this. |
|
383 RProperty::Set(KUidSystemCategory, KUidC32StartPropertyKey.iUid, EReset); |
|
384 } |
|
385 |
|
386 TVerdict CTestStepESockSSA::doTestStepPreambleL() |
|
387 { |
|
388 SetDummyBlocking(); |
|
389 RProperty ::Set(KUidSystemCategory, KUidC32StartPropertyKey.iUid, EReset); |
|
390 UnloadBlockerL(); |
|
391 KillC32Start(); |
|
392 return EPass; |
|
393 } |
|
394 |
|
395 TVerdict CTestStepESockSSA::doTestStepPostambleL() |
|
396 { |
|
397 UnloadBlockerL(); |
|
398 return EPass; |
|
399 } |
|
400 |