commands/testexecute/ProxyServer.cpp
changeset 5 9c58252c6740
equal deleted inserted replaced
4:c061fa280d92 5:9c58252c6740
       
     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 */