00001 // 00002 // This code is derived from Symbian Ltd provided and copyrighted 00003 // example code from year 2000. Note, however, the boilerplate nature 00004 // of most Symbian client-server code, and therefore the lack of 00005 // originality in such code. 00006 // 00007 00008 #include "epoc-cliapi-server.hpp" 00009 00010 #include "epoc-cl2app-clientserver.hpp" 00011 00012 #include "lua_cl2.h" 00013 #include "utils_cl2.h" // for string conversions 00014 #include "symbian_auto_ptr.hpp" 00015 00016 #include "common/gxlowmem.h" 00017 #include "common/logging.h" 00018 #include "common/platform_error.h" 00019 #include "common/sh_utils.h" 00020 00021 #include <glib.h> 00022 00023 // -------------------------------------------------- 00024 // utilities 00025 // -------------------------------------------------- 00026 00027 _LIT(KServerPanicCat, "cl2cliserv"); 00028 00029 enum TMyPanic 00030 { 00031 EPanicBadDescriptor = 1, 00032 EPanicIllegalFunction, 00033 EPanicAlreadyReceiving 00034 }; 00035 00036 static void PanicClient(const RMessagePtr2& aMessage, TMyPanic aPanicNum) 00037 // 00038 // RMessage::Panic() also completes the message. This is: 00039 // (a) important for efficient cleanup within the kernel 00040 // (b) a problem if the message is completed a second time 00041 // 00042 { 00043 aMessage.Panic(KServerPanicCat, aPanicNum); 00044 } 00045 00046 // -------------------------------------------------- 00047 // session interface 00048 // -------------------------------------------------- 00049 00050 class CCliapiSession : public CSession2 00051 { 00052 public: 00053 CCliapiSession(); 00054 void CreateL(); 00055 void Send(const TDesC& aMessage); 00056 private: 00057 ~CCliapiSession(); 00058 inline CCliapiServer& Server(); 00059 void ServiceL(const RMessage2& aMessage); 00060 void ServiceError(const RMessage2& aMessage,TInt aError); 00061 inline TBool ReceivePending() const; 00062 private: 00063 RMessagePtr2 iReceiveMsg; 00064 TInt iReceiveLen; 00065 }; 00066 00067 // -------------------------------------------------- 00068 // server implementation 00069 // -------------------------------------------------- 00070 00071 TInt CCliapiServer::Start() 00072 { 00073 return CServer2::Start(KMyServerName); 00074 } 00075 00076 // This is private, so okay to define as "inline" here. 00077 inline CCliapiServer::CCliapiServer() : 00078 CServer2(CActive::EPriorityStandard, ESharableSessions) 00079 {} 00080 00081 CCliapiServer* CCliapiServer::NewLC() 00082 { 00083 CCliapiServer* self = new (ELeave) CCliapiServer; 00084 CleanupStack::PushL(self); 00085 self->ConstructL(); 00086 return self; 00087 } 00088 00089 CCliapiServer* CCliapiServer::NewL() 00090 { 00091 CCliapiServer* self = NewLC(); 00092 CleanupStack::Pop(); 00093 return self; 00094 } 00095 00096 void CCliapiServer::ConstructL() 00097 // 00098 // 2nd phase construction - ensure the timer and server objects are running 00099 // 00100 { 00101 //User::LeaveIfError(StartL()); // no automatic start for us 00102 } 00103 00104 CSession2* CCliapiServer::NewSessionL(const TVersion&,const RMessage2&) const 00105 // 00106 // Cretae a new client session. This should really check the version number. 00107 // 00108 { 00109 return new(ELeave) CCliapiSession(); 00110 } 00111 00112 void CCliapiServer::AddSession() 00113 // 00114 // A new session is being created 00115 // 00116 { 00117 ++iSessionCount; 00118 } 00119 00120 void CCliapiServer::DropSession() 00121 // 00122 // A session is being destroyed 00123 // 00124 { 00125 iSessionCount--; 00126 } 00127 00128 void CCliapiServer::Send(const TDesC& aMessage) 00129 // 00130 // Pass on the signal to all clients 00131 // 00132 { 00133 iSessionIter.SetToFirst(); 00134 CSession2* s; 00135 while ((s=iSessionIter++)!=0) 00136 static_cast<CCliapiSession*>(s)->Send(aMessage); 00137 } 00138 00139 // -------------------------------------------------- 00140 // session implementation 00141 // -------------------------------------------------- 00142 00143 inline CCliapiSession::CCliapiSession() 00144 {} 00145 00146 inline CCliapiServer& CCliapiSession::Server() 00147 { 00148 return *static_cast<CCliapiServer*>(const_cast<CServer2*>(CSession2::Server())); 00149 } 00150 00151 inline TBool CCliapiSession::ReceivePending() const 00152 { 00153 return !iReceiveMsg.IsNull(); 00154 } 00155 00156 void CCliapiSession::CreateL() 00157 // 00158 // 2nd phase construct for sessions - called by the CServer framework 00159 // 00160 { 00161 Server().AddSession(); 00162 } 00163 00164 CCliapiSession::~CCliapiSession() 00165 { 00166 Server().DropSession(); 00167 } 00168 00169 void CCliapiSession::Send(const TDesC& aMessage) 00170 // 00171 // Deliver the message to the client, truncating if required 00172 // If the write fails, panic the client, not the sender 00173 // 00174 { 00175 if (ReceivePending()) 00176 { 00177 TPtrC m(aMessage); 00178 if (iReceiveLen < aMessage.Length()) 00179 m.Set(m.Left(iReceiveLen)); 00180 TInt r = iReceiveMsg.Write(0, m); 00181 if (r == KErrNone) 00182 iReceiveMsg.Complete(KErrNone); 00183 else 00184 PanicClient(iReceiveMsg, EPanicBadDescriptor); 00185 } 00186 } 00187 00188 /* 00189 class MaybeCharPtr 00190 { 00191 public: 00192 MaybeCharPtr() : iPtr(NULL) {} 00193 ~MaybeCharPtr() { if (iPtr) g_free(iPtr); } 00194 char* iPtr; 00195 }; 00196 */ 00197 00198 void CCliapiSession::ServiceL(const RMessage2& aMessage) 00199 // 00200 // Handle a client request. 00201 // Leaving is handled by CCliapiServer::ServiceError() which reports 00202 // the error code to the client 00203 // 00204 { 00205 switch (aMessage.Function()) 00206 { 00207 case ETickCountFresh: 00208 { 00209 TUint tc = User::TickCount(); 00210 TPckg<TUint> result(tc); 00211 aMessage.WriteL(0, result); 00212 aMessage.Complete(KErrNone); 00213 break; 00214 } 00215 00216 case ETryEvalScript: 00217 { 00218 // It is somewhat of an issue if the client has to allocate a 00219 // "large enough" buffer for us to write the result to, but we 00220 // cannot really go and allocate memory for the client side, 00221 // can we now? 00222 00223 TInt errCode = KErrNone; 00224 00225 // No docs or examples about the use of text descriptors to be 00226 // found, but experimentation shows that the length is in 00227 // characters, not bytes, so it is the length of the original 00228 // descriptor, not that of the Pckg. 00229 TInt srcLen = aMessage.GetDesLengthL(0); 00230 00231 TInt dstLen = aMessage.GetDesMaxLengthL(2); 00232 00233 // Must allocate a srcLen size buffer into which to read the 00234 // data. 00235 HBufC* sc = HBufC::NewLC(srcLen); 00236 TPtr s(sc->Des()); 00237 aMessage.ReadL(0, s); 00238 CleanupStack::PopAndDestroy(sc); 00239 00240 // This service message is reserved for experiments. Now we 00241 // happen to do this instead of anything useful. 00242 TPckg<TInt> srcLenPk(dstLen); 00243 aMessage.WriteL(1, srcLenPk); 00244 00245 aMessage.Complete(errCode); 00246 break; 00247 } 00248 00249 case EEvalGetResult: 00250 { 00251 TInt errCode = KErrNone; 00252 00253 // No docs or examples about the use of text descriptors to be 00254 // found, but experimentation shows that the length is in 00255 // characters, not bytes, so it is the length of the original 00256 // descriptor, not that of the Pckg. 00257 TInt srcLen = aMessage.GetDesLengthL(0); 00258 00259 // It is somewhat of an issue if the client has to allocate a 00260 // "large enough" buffer for us to write the result to, but we 00261 // cannot really go and allocate memory for the client side, 00262 // can we now? 00263 TInt dstLen = aMessage.GetDesMaxLengthL(2); 00264 00265 // Must allocate a srcLen size buffer into which to read the 00266 // data. 00267 HBufC* srcBuf = HBufC::NewLC(srcLen); 00268 TPtr srcDes(srcBuf->Des()); 00269 aMessage.ReadL(0, srcDes); 00270 HBufC8* srcBuf8 = ConvToUtf8ZL(srcDes); 00271 CleanupStack::PopAndDestroy(srcBuf); 00272 00273 e_auto_ptr<HBufC8> cleanupSrcBuf8(srcBuf8); // takes ownership 00274 const TUint8* srcU = srcBuf8->Ptr(); 00275 const char* srcC = (const char*)srcU; 00276 logt(srcC); 00277 00278 // Now must have a Lua VM evaluate the data. The expression 00279 // should evaluate to a string. Lua's strings are 8-bit clean, 00280 // so we can use UTF-8, and Unicode can hence appear in string 00281 // literals, but Unicode in variable names is likely to cause 00282 // a parse error. 00283 lua_State *L = cl_lua_new_libs(); 00284 if (!L) 00285 User::Leave(KErrNoMemory); 00286 lua_State_auto_ptr cleanupLuaState(L); 00287 00288 const char* luaResult = NULL; 00289 #define luaResultBuf_size 100 00290 gchar luaResultBuf[luaResultBuf_size]; 00291 00292 // When we don't get an actual Symbian error, we set the error 00293 // code KErrLuaErr; this way all the errors we write to the 00294 // client are Symbian style. 00295 // 00296 // Note that retrieving the error message when none is 00297 // available can in itself cause an exception, and a USER-EXEC 00298 // 3 panic. 00299 TInt evalErr = 0; 00300 TRAPD(leaveErr, evalErr = luaL_loadstring(L, srcC)); 00301 if (leaveErr) { 00302 logg("leave %d in luaL_loadstring!", leaveErr); 00303 evalErr = leaveErr; 00304 luaResult = "<Symbian exception in load>"; 00305 } else if (evalErr) { 00306 logg("luaL_loadstring error %d", evalErr); 00307 switch (evalErr) { 00308 case LUA_ERRSYNTAX: 00309 { 00310 luaResult = "<syntax error during precompilation>"; 00311 break; 00312 } 00313 case LUA_ERRMEM: 00314 { 00315 luaResult = "<out of memory>"; 00316 break; 00317 } 00318 default: 00319 { 00320 if (!lua_isnone(L, -1)) // if acceptable index 00321 luaResult = lua_tostring(L, -1); 00322 if (!luaResult) 00323 luaResult = "<unknown error in load>"; 00324 break; 00325 } 00326 } 00327 evalErr = KErrLuaErr; 00328 } else /* load okay */ { 00329 logt("luaL_loadstring ok"); 00330 00331 // We should get 0 (for success), or one of LUA_ERRRUN, 00332 // LUA_ERRMEM, or LUA_ERRERR (all positive values), or a 00333 // Symbian error code (a negative value). Plus if there was 00334 // an error we should have a string error message as well. 00335 TRAP(leaveErr, evalErr = lua_pcall(L, 0, 1, 0)); 00336 if (leaveErr) { 00337 // This should not happen. 00338 logg("leave %d escaped lua_pcall!", leaveErr); 00339 evalErr = leaveErr; 00340 luaResult = "<escaped Symbian exception in eval>"; 00341 } else if (evalErr) { 00342 logg("lua_pcall err %d", evalErr); 00343 if (!lua_isnone(L, -1)) // if acceptable index 00344 luaResult = lua_tostring(L, -1); 00345 if (!luaResult) { 00346 // evalErr here may be a Symbian error as well. They are 00347 // negative, while the Lua errors are positive. 00348 switch (evalErr) { 00349 case LUA_ERRRUN: 00350 { 00351 luaResult = "<runtime error>"; 00352 break; 00353 } 00354 case LUA_ERRERR: 00355 { 00356 luaResult = "<error handler error>"; 00357 break; 00358 } 00359 case LUA_ERRMEM: 00360 { 00361 luaResult = "<out of memory>"; 00362 break; 00363 } 00364 default: 00365 { 00366 TRAP_OOM_FAIL({ 00367 g_snprintf(luaResultBuf, luaResultBuf_size, 00368 "Symbian error in eval: %s (%d)", 00369 symbian_error_strerror(evalErr), evalErr); 00370 }); 00371 luaResult = luaResultBuf; 00372 break; 00373 fail: 00374 luaResult = "<out of memory>"; 00375 break; 00376 } 00377 } 00378 } 00379 evalErr = KErrLuaErr; 00380 } else /* eval okay */ { 00381 if (lua_isnone(L, -1)) { 00382 luaResult = "<eval to no value>"; 00383 } else { 00384 luaResult = lua_tostring(L, -1); 00385 if (!luaResult) { 00386 evalErr = KErrLuaErr; 00387 luaResult = "<eval to non-string value>"; 00388 } 00389 } 00390 } 00391 } 00392 logt(luaResult); 00393 00394 // Convert to Unicode descriptor. 00395 TPtrC8 resultDes8((TUint8*)luaResult); 00396 e_auto_ptr<HBufC> resultBuf16(ConvFromUtf8L(resultDes8)); // takes ownership 00397 TPtrC resultDes(*resultBuf16); 00398 00399 // I think we shall return an overflow error if the result 00400 // does not fit into the client-side buffer, but must check 00401 // for that of course. 00402 if (resultDes.Length() > dstLen) 00403 User::Leave(KErrOverflow); 00404 00405 // We do not consider a Lua code evaluation error to be a 00406 // Symbian client-server session error as such, and we should 00407 // complete with KErrNone, and report the error code. An error 00408 // text will have been written if the error code is 00409 // KErrLuaErr. 00410 TPckg<TInt> evalErrPk(evalErr); 00411 aMessage.WriteL(1, evalErrPk); 00412 00413 // Write the result string to the client side. 00414 aMessage.WriteL(2, resultDes); 00415 00416 aMessage.Complete(errCode); 00417 break; 00418 } 00419 00420 default: 00421 { 00422 PanicClient(aMessage, EPanicIllegalFunction); 00423 break; 00424 } 00425 } 00426 } 00427 00428 void CCliapiSession::ServiceError(const RMessage2& aMessage,TInt aError) 00429 // 00430 // Handle an error from CCliapiSession::ServiceL() 00431 // A bad descriptor error implies a badly programmed client, so panic it; 00432 // otherwise use the default handling (report the error to the client) 00433 // 00434 { 00435 /* 00436 if (aError==KErrBadDescriptor) 00437 PanicClient(aMessage,EPanicBadDescriptor); 00438 */ 00439 CSession2::ServiceError(aMessage,aError); 00440 } 00441 00442 /** 00443 00444 epoc-cliapi-server.cpp 00445 00446 Copyright 2009 Helsinki Institute for Information Technology (HIIT) 00447 and the authors. All rights reserved. 00448 00449 Authors: Tero Hasu <tero.hasu@hut.fi> 00450 00451 Permission is hereby granted, free of charge, to any person 00452 obtaining a copy of this software and associated documentation files 00453 (the "Software"), to deal in the Software without restriction, 00454 including without limitation the rights to use, copy, modify, merge, 00455 publish, distribute, sublicense, and/or sell copies of the Software, 00456 and to permit persons to whom the Software is furnished to do so, 00457 subject to the following conditions: 00458 00459 The above copyright notice and this permission notice shall be 00460 included in all copies or substantial portions of the Software. 00461 00462 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00463 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00464 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00465 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00466 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00467 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00468 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00469 SOFTWARE. 00470 00471 **/
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:52 2011 by Doxygen 1.6.1