|
1 // ProxyServer.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "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 // Accenture - Initial contribution |
|
11 // |
|
12 #include "ProxyServer.h" |
|
13 #include <fshell/memoryaccess.h> |
|
14 |
|
15 #define LOG(x...) |
|
16 #define LOG8(x...) |
|
17 //#include <e32debug.h> |
|
18 //#define LOG(x...) RDebug::Print(x) |
|
19 //#define LOG8(x...) RDebug::Printf(x) |
|
20 |
|
21 //const TInt KShutdownProxy = 1000; |
|
22 //const TInt KPingProxy = 1001; |
|
23 |
|
24 NONSHARABLE_CLASS(CAsyncWaiter) : public CActive |
|
25 { |
|
26 public: |
|
27 CAsyncWaiter(RUnderlyingSession& aRealSession, const RMessage2& aOriginalMessage, const TIpcArgs& aArgs); |
|
28 ~CAsyncWaiter(); |
|
29 //void ForwardMessageL(); |
|
30 |
|
31 protected: |
|
32 void RunL(); |
|
33 void DoCancel(); |
|
34 |
|
35 private: |
|
36 RUnderlyingSession& iRealSession; |
|
37 RMessage2 iMsg; |
|
38 TIpcArgs iArgs; |
|
39 }; |
|
40 |
|
41 CProxyServer* CProxyServer::NewInSeparateThreadL(const TDesC& aServerToReplace, MMessageHandler* aHandler) |
|
42 { |
|
43 CProxyServer* self = new(ELeave) CProxyServer(aServerToReplace, aHandler); |
|
44 CleanupStack::PushL(self); |
|
45 self->ThreadConstructL(); |
|
46 CleanupStack::Pop(self); |
|
47 return self; |
|
48 } |
|
49 |
|
50 CProxyServer::CProxyServer(const TDesC& aServerToReplace, MMessageHandler* aHandler) |
|
51 : CServer2(0, ESharableSessions), iServerName(aServerToReplace), iHandler(aHandler) |
|
52 { |
|
53 // Name the server after tid and this pointer, should be unique enough |
|
54 iRealServerName.AppendNum(RThread().Id(), EHex); |
|
55 iRealServerName.Append('.'); |
|
56 iRealServerName.AppendNum((TInt)this, EHex); |
|
57 } |
|
58 |
|
59 void CProxyServer::ThreadConstructL() |
|
60 { |
|
61 User::LeaveIfError(iServerThread.Create(iRealServerName, &StartServerThreadFunction, 8192, NULL, this)); |
|
62 TRequestStatus stat; |
|
63 iServerThread.Rendezvous(stat); |
|
64 if (stat == KRequestPending) |
|
65 { |
|
66 iServerThread.Resume(); |
|
67 } |
|
68 else |
|
69 { |
|
70 iServerThread.Kill(stat.Int()); |
|
71 } |
|
72 User::WaitForRequest(stat); |
|
73 User::LeaveIfError(stat.Int()); |
|
74 } |
|
75 |
|
76 void CProxyServer::ConstructL() |
|
77 { |
|
78 iShutdownCallback = new(ELeave) CAsyncCallBack(CActive::EPriorityHigh); |
|
79 iShutdownCallback->Set(TCallBack(&Shutdown, this)); |
|
80 |
|
81 User::LeaveIfError(iMemAccess.Open()); |
|
82 if (iRealServerName.Length() > iServerName.Length()) User::Leave(KErrTooBig); // Mem access doesn't like this |
|
83 |
|
84 _LIT(KTempName, "TemporaryReallyLongServerNameThatLeavesUsSpaceToManuever"); |
|
85 StartL(KTempName); |
|
86 |
|
87 TServerKernelInfoBuf buf; |
|
88 TInt err = iMemAccess.GetObjectInfo(EServer, iServerName, buf); |
|
89 User::LeaveIfError(err); |
|
90 TUint8* realServer = buf().iAddressOfKernelObject; |
|
91 err = iMemAccess.GetObjectInfo(EServer, KTempName, buf); |
|
92 User::LeaveIfError(err); |
|
93 TUint8* myServer = buf().iAddressOfKernelObject; |
|
94 |
|
95 // Should really have some kind of swap operation here... |
|
96 TBuf8<KMaxName> name8; |
|
97 name8.Copy(iRealServerName); |
|
98 iMemAccess.InPlaceObjectRename(EServer, realServer, name8); |
|
99 name8.Copy(iServerName); |
|
100 iMemAccess.InPlaceObjectRename(EServer, myServer, name8); |
|
101 iProxying = ETrue; |
|
102 } |
|
103 |
|
104 TInt CProxyServer::Shutdown(TAny* aSelf) |
|
105 { |
|
106 CProxyServer* self = static_cast<CProxyServer*>(aSelf); |
|
107 delete self; |
|
108 CActiveScheduler::Stop(); |
|
109 return 0; |
|
110 } |
|
111 |
|
112 void CProxyServer::Destroy() |
|
113 { |
|
114 if (iShutdownCallback && iServerThread.Handle() && iServerThread.Id() != RThread().Id()) // Don't try shutting down the thread if the server is actually running in the main thread |
|
115 { |
|
116 TRequestStatus stat; |
|
117 // This is far harder than it should be... need to make sure we don't reference any member vars after calling the shutdown callback |
|
118 RThread serverThread; |
|
119 Mem::Swap(&serverThread, &iServerThread, sizeof(RThread)); |
|
120 serverThread.Logon(stat); |
|
121 iShutdownCallback->CallBack(); |
|
122 User::WaitForRequest(stat); |
|
123 serverThread.Close(); |
|
124 } |
|
125 else |
|
126 { |
|
127 delete this; |
|
128 } |
|
129 } |
|
130 |
|
131 CProxyServer::~CProxyServer() |
|
132 { |
|
133 if (iProxying) |
|
134 { |
|
135 TServerKernelInfoBuf buf; |
|
136 TInt err = iMemAccess.GetObjectInfo(EServer, iRealServerName, buf); |
|
137 if (!err) |
|
138 { |
|
139 TUint8* realServer = buf().iAddressOfKernelObject; |
|
140 TBuf8<KMaxName> name8; |
|
141 name8.Copy(iServerName); |
|
142 iMemAccess.InPlaceObjectRename(EServer, realServer, name8); |
|
143 // Temporarily both us and the real server will have name iServerName. When we finish destructing, we'll clean up and the system should be back in a sensible state |
|
144 } |
|
145 } |
|
146 delete iShutdownCallback; |
|
147 iServerThread.Close(); |
|
148 iMemAccess.Close(); |
|
149 } |
|
150 |
|
151 CSession2* CProxyServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const |
|
152 { |
|
153 CProxySession* res = new(ELeave) CProxySession(); |
|
154 CleanupStack::PushL(res); |
|
155 res->ConstructL(iRealServerName, aVersion); |
|
156 CleanupStack::Pop(res); |
|
157 return res; |
|
158 } |
|
159 |
|
160 |
|
161 void CProxyServer::ServerThreadRunL() |
|
162 { |
|
163 CActiveScheduler* scheduler = new(ELeave) CActiveScheduler; |
|
164 CleanupStack::PushL(scheduler); |
|
165 CActiveScheduler::Install(scheduler); |
|
166 |
|
167 ConstructL(); |
|
168 RThread::Rendezvous(KErrNone); |
|
169 |
|
170 CActiveScheduler::Start(); |
|
171 CleanupStack::PopAndDestroy(scheduler); |
|
172 } |
|
173 |
|
174 TInt CProxyServer::StartServerThreadFunction(TAny* aSelf) |
|
175 { |
|
176 TInt err = KErrNoMemory; |
|
177 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
178 if (cleanup) |
|
179 { |
|
180 TRAP(err, static_cast<CProxyServer*>(aSelf)->ServerThreadRunL()); |
|
181 delete cleanup; |
|
182 } |
|
183 return err; |
|
184 } |
|
185 |
|
186 MMessageHandler* CProxyServer::Handler() const |
|
187 { |
|
188 return iHandler; |
|
189 } |
|
190 |
|
191 // |
|
192 |
|
193 void CProxySession::ConstructL(const TDesC& aServerName, const TVersion& aVersion) |
|
194 { |
|
195 User::LeaveIfError(iSession.CreateSession(aServerName, aVersion)); |
|
196 } |
|
197 |
|
198 CProxyServer& CProxySession::Server() |
|
199 { |
|
200 return *const_cast<CProxyServer*>(static_cast<const CProxyServer*>(CSession2::Server())); |
|
201 } |
|
202 |
|
203 const CProxyServer& CProxySession::Server() const |
|
204 { |
|
205 return *static_cast<const CProxyServer*>(CSession2::Server()); |
|
206 } |
|
207 |
|
208 void CProxySession::ServiceL(const RMessage2 &aMessage) |
|
209 { |
|
210 MMessageHandler* handler = Server().Handler(); |
|
211 TBool handled = EFalse; |
|
212 if (handler) |
|
213 { |
|
214 handled = handler->HandleMessageL(this, aMessage); |
|
215 } |
|
216 |
|
217 if (!handled) |
|
218 { |
|
219 ForwardUnhandledMessageL(aMessage); |
|
220 } |
|
221 } |
|
222 |
|
223 TInt Val(const RMessage2& aMessage, TInt aIndex) |
|
224 { |
|
225 switch (aIndex) |
|
226 { |
|
227 case 0: |
|
228 return aMessage.Int0(); |
|
229 case 1: |
|
230 return aMessage.Int1(); |
|
231 case 2: |
|
232 return aMessage.Int2(); |
|
233 case 3: |
|
234 return aMessage.Int3(); |
|
235 default: |
|
236 return 0; |
|
237 } |
|
238 } |
|
239 |
|
240 void CleanupArgs(TAny* aArgs) |
|
241 { |
|
242 TIpcArgs& args = *static_cast<TIpcArgs*>(aArgs); |
|
243 for (TInt i = 0; i < KMaxMessageArguments; i++) |
|
244 { |
|
245 if (args.iFlags & (TIpcArgs::EFlagDes<<(i*TIpcArgs::KBitsPerType))) |
|
246 { |
|
247 LOG8("+++ deleting %x", args.iArgs[i]); |
|
248 delete (TAny*)args.iArgs[i]; |
|
249 } |
|
250 } |
|
251 args.iFlags = 0; |
|
252 } |
|
253 |
|
254 void CProxySession::ForwardUnhandledMessageL(const RMessage2& aMessage) |
|
255 { |
|
256 TIpcArgs args; |
|
257 CleanupStack::PushL(TCleanupItem(&CleanupArgs, &args)); |
|
258 |
|
259 LOG(_L("Forwarding message fn=%d"), aMessage.Function()); |
|
260 |
|
261 for (TInt i = 0; i < KMaxMessageArguments; i++) |
|
262 { |
|
263 // For each arg, try and figure out if it's a descriptor and if so what type |
|
264 TInt len = aMessage.GetDesLength(i); |
|
265 if (len < 0) |
|
266 { |
|
267 // Not a descriptor |
|
268 args.Set(i, Val(aMessage, i)); |
|
269 LOG(_L("Int arg %d: %d"), i, args.iArgs[i]); |
|
270 } |
|
271 else |
|
272 { |
|
273 // It's a descriptor, now see if it's 16-bit or 8-bit |
|
274 TBuf<1> wbuf; |
|
275 TInt err = aMessage.Read(i, wbuf); // This check only works if platsec enforcement is turned on (!) but fshell.bat was the only thing that generally ran with enforcement off, and I've fixed that |
|
276 if (err == KErrNone) |
|
277 { |
|
278 // 16-bit |
|
279 // Gaah where's HBuf when you need it |
|
280 TPtr* buf = (TPtr*)User::AllocL(len*2 + sizeof(TPtr)); |
|
281 new(buf) TPtr((TUint16*)(buf+1), len); |
|
282 aMessage.ReadL(i, *buf); |
|
283 |
|
284 // Figure out if it's writeable by trying to write back what we just read |
|
285 TBool writeable = (aMessage.Write(i, *buf) == KErrNone); |
|
286 |
|
287 if (writeable) |
|
288 { |
|
289 LOG(_L("TDes16 arg %d: %S"), i, buf); |
|
290 args.Set(i, buf); |
|
291 } |
|
292 else |
|
293 { |
|
294 LOG(_L("TDesC16 arg %d: %S"), i, buf); |
|
295 args.Set(i, (const TDesC16*)buf); |
|
296 } |
|
297 } |
|
298 else |
|
299 { |
|
300 // 8-bit |
|
301 // Gaah where's HBuf when you need it |
|
302 TPtr8* buf = (TPtr8*)User::AllocL(len + sizeof(TPtr8)); |
|
303 new(buf) TPtr8((TUint8*)(buf+1), len); |
|
304 aMessage.ReadL(i, *buf); |
|
305 |
|
306 // Figure out if it's writeable by trying to write back what we just read |
|
307 TBool writeable = (aMessage.Write(i, *buf) == KErrNone); |
|
308 |
|
309 if (writeable) |
|
310 { |
|
311 LOG8("TDes8 arg %d: %S", i, buf); |
|
312 args.Set(i, buf); |
|
313 } |
|
314 else |
|
315 { |
|
316 LOG8("TDesC8 arg %d: %S", i, buf); |
|
317 args.Set(i, (const TDesC8*)buf); |
|
318 } |
|
319 } |
|
320 } |
|
321 } |
|
322 ForwardMessageArgsL(aMessage, args); |
|
323 CleanupStack::Pop(&args); // ForwardMessageArgs takes ownership |
|
324 } |
|
325 |
|
326 void CProxySession::ForwardMessageArgsL(const RMessage2& aMessage, const TIpcArgs& aArgs) |
|
327 { |
|
328 CAsyncWaiter* waiter = new(ELeave) CAsyncWaiter(iSession, aMessage, aArgs); |
|
329 // That's all that's needed |
|
330 } |
|
331 |
|
332 void CProxySession::Disconnect(const RMessage2 &aMessage) |
|
333 { |
|
334 iSession.Close(); |
|
335 //TODO Need to wait for any CAsyncWaiters to be completed? If so, do it here and defer the super call until that time |
|
336 CSession2::Disconnect(aMessage); |
|
337 } |
|
338 |
|
339 // CAsyncWaiter |
|
340 |
|
341 CAsyncWaiter::CAsyncWaiter(RUnderlyingSession& aRealSession, const RMessage2& aOriginalMessage, const TIpcArgs& aArgs) |
|
342 : CActive(CActive::EPriorityStandard), iRealSession(aRealSession), iMsg(aOriginalMessage), iArgs(aArgs) |
|
343 { |
|
344 CActiveScheduler::Add(this); |
|
345 LOG(_L("Sending to real server: fn=%d, args=%x,%x,%x,%x flags=%x"), aOriginalMessage.Function(), iArgs.iArgs[0], iArgs.iArgs[1], iArgs.iArgs[2], iArgs.iArgs[3], iArgs.iFlags); |
|
346 iRealSession.SendReceive(aOriginalMessage.Function(), iArgs, iStatus); |
|
347 SetActive(); |
|
348 } |
|
349 |
|
350 CAsyncWaiter::~CAsyncWaiter() |
|
351 { |
|
352 CleanupArgs(&iArgs); |
|
353 } |
|
354 |
|
355 void CAsyncWaiter::RunL() |
|
356 { |
|
357 const TInt serverErr = iStatus.Int(); |
|
358 TInt writeErr = KErrNone; |
|
359 |
|
360 // First check for any TDes args that we need to write back to the real client |
|
361 for (TInt i = 0; i < KMaxMessageArguments; i++) |
|
362 { |
|
363 if ((iArgs.iFlags & (TIpcArgs::EFlagDes<<(i*TIpcArgs::KBitsPerType))) && !(iArgs.iFlags & (TIpcArgs::EFlagConst<<(i*TIpcArgs::KBitsPerType)))) |
|
364 { |
|
365 if (iArgs.iFlags & (TIpcArgs::EFlag16Bit<<(i*TIpcArgs::KBitsPerType))) |
|
366 { |
|
367 TDes16* des = (TDes16*)iArgs.iArgs[i]; |
|
368 writeErr = iMsg.Write(i, *des); |
|
369 LOG(_L("Writing back %S returned %d"), des, writeErr); |
|
370 } |
|
371 else |
|
372 { |
|
373 TDes8* des = (TDes8*)iArgs.iArgs[i]; |
|
374 writeErr = iMsg.Write(i, *des); |
|
375 LOG8("Writing back %S returned %d", des, writeErr); |
|
376 } |
|
377 |
|
378 if (writeErr) break; // Who knows how the real server would have handled such a case |
|
379 } |
|
380 } |
|
381 |
|
382 LOG(_L("Completing original request function %d with writeErr=%d serverErr=%d"), iMsg.Function(), writeErr, serverErr); |
|
383 if (writeErr) iMsg.Complete(writeErr); |
|
384 else iMsg.Complete(serverErr); |
|
385 |
|
386 delete this; // Our work here is done |
|
387 } |
|
388 |
|
389 void CAsyncWaiter::DoCancel() |
|
390 { |
|
391 // We never call Cancel on our waiters |
|
392 } |
|
393 |
|
394 /* |
|
395 EXPORT_C TInt ShutdownProxyNotifier() |
|
396 { |
|
397 RDebugNotifier notifier; |
|
398 TInt err = notifier.Connect(); |
|
399 if (err == KErrNotFound) |
|
400 { |
|
401 // Oh dear, !Notifier isn't running. Meaning we renamed it then crashed, probably. Try renaming the real one |
|
402 RMemoryAccess::LoadDriver(); |
|
403 RMemoryAccess mem; |
|
404 err = mem.Open(); |
|
405 if (err) return err; |
|
406 TServerKernelInfoBuf buf; |
|
407 TInt err = mem.GetObjectInfo(EServer, KRealNotifierServerName, buf); |
|
408 if (!err) |
|
409 { |
|
410 TUint8* realServer = buf().iAddressOfKernelObject; |
|
411 mem.InPlaceObjectRename(EServer, realServer, _L8("!Notifier")); |
|
412 } |
|
413 mem.Close(); |
|
414 return err; |
|
415 } |
|
416 |
|
417 err = notifier.ShutdownProxy(); |
|
418 if (err == KErrServerTerminated) err = KErrNone; // It's expected to get KErrServerTerminated, because we deliberately don't complete the message. This way the client is more likely to get the completion once the server has actually gone, and not slightly before |
|
419 notifier.Close(); |
|
420 |
|
421 return err; |
|
422 } |
|
423 |
|
424 EXPORT_C TBool NotifierProxyIsRunning() |
|
425 { |
|
426 RDebugNotifier notifier; |
|
427 TInt err = notifier.Connect(); |
|
428 if (err) return EFalse; // Not even original notifier is running?! |
|
429 err = notifier.PingProxy(); |
|
430 notifier.Close(); |
|
431 return err == KErrNone; // The real proxy will return KErrNotSupported in this scenario |
|
432 } |
|
433 */ |