PageRenderTime 71ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llsdrpcserver.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 346 lines | 267 code | 24 blank | 55 comment | 19 complexity | b1d37106289b4695c9925fab631845a1 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llsdrpcserver.cpp
  3. * @author Phoenix
  4. * @date 2005-10-11
  5. * @brief Implementation of the LLSDRPCServer and related classes.
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #include "linden_common.h"
  29. #include "llsdrpcserver.h"
  30. #include "llbuffer.h"
  31. #include "llbufferstream.h"
  32. #include "llmemtype.h"
  33. #include "llpumpio.h"
  34. #include "llsdserialize.h"
  35. #include "llstl.h"
  36. static const char FAULT_PART_1[] = "{'fault':{'code':i";
  37. static const char FAULT_PART_2[] = ", 'description':'";
  38. static const char FAULT_PART_3[] = "'}}";
  39. static const char RESPONSE_PART_1[] = "{'response':";
  40. static const char RESPONSE_PART_2[] = "}";
  41. static const S32 FAULT_GENERIC = 1000;
  42. static const S32 FAULT_METHOD_NOT_FOUND = 1001;
  43. static const std::string LLSDRPC_METHOD_SD_NAME("method");
  44. static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter");
  45. /**
  46. * LLSDRPCServer
  47. */
  48. LLSDRPCServer::LLSDRPCServer() :
  49. mState(LLSDRPCServer::STATE_NONE),
  50. mPump(NULL),
  51. mLock(0)
  52. {
  53. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  54. }
  55. LLSDRPCServer::~LLSDRPCServer()
  56. {
  57. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  58. std::for_each(
  59. mMethods.begin(),
  60. mMethods.end(),
  61. llcompose1(
  62. DeletePointerFunctor<LLSDRPCMethodCallBase>(),
  63. llselect2nd<method_map_t::value_type>()));
  64. std::for_each(
  65. mCallbackMethods.begin(),
  66. mCallbackMethods.end(),
  67. llcompose1(
  68. DeletePointerFunctor<LLSDRPCMethodCallBase>(),
  69. llselect2nd<method_map_t::value_type>()));
  70. }
  71. // virtual
  72. ESDRPCSStatus LLSDRPCServer::deferredResponse(
  73. const LLChannelDescriptors& channels,
  74. LLBufferArray* data) {
  75. // subclass should provide a sane implementation
  76. return ESDRPCS_DONE;
  77. }
  78. void LLSDRPCServer::clearLock()
  79. {
  80. if(mLock && mPump)
  81. {
  82. mPump->clearLock(mLock);
  83. mPump = NULL;
  84. mLock = 0;
  85. }
  86. }
  87. static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_SERVER("SDRPC Server");
  88. // virtual
  89. LLIOPipe::EStatus LLSDRPCServer::process_impl(
  90. const LLChannelDescriptors& channels,
  91. buffer_ptr_t& buffer,
  92. bool& eos,
  93. LLSD& context,
  94. LLPumpIO* pump)
  95. {
  96. LLFastTimer t(FTM_PROCESS_SDRPC_SERVER);
  97. PUMP_DEBUG;
  98. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  99. // lldebugs << "LLSDRPCServer::process_impl" << llendl;
  100. // Once we have all the data, We need to read the sd on
  101. // the the in channel, and respond on the out channel
  102. if(!eos) return STATUS_BREAK;
  103. if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
  104. std::string method_name;
  105. LLIOPipe::EStatus status = STATUS_DONE;
  106. switch(mState)
  107. {
  108. case STATE_DEFERRED:
  109. PUMP_DEBUG;
  110. if(ESDRPCS_DONE != deferredResponse(channels, buffer.get()))
  111. {
  112. buildFault(
  113. channels,
  114. buffer.get(),
  115. FAULT_GENERIC,
  116. "deferred response failed.");
  117. }
  118. mState = STATE_DONE;
  119. return STATUS_DONE;
  120. case STATE_DONE:
  121. // lldebugs << "STATE_DONE" << llendl;
  122. break;
  123. case STATE_CALLBACK:
  124. // lldebugs << "STATE_CALLBACK" << llendl;
  125. PUMP_DEBUG;
  126. method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
  127. if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
  128. {
  129. if(ESDRPCS_DONE != callbackMethod(
  130. method_name,
  131. mRequest[LLSDRPC_PARAMETER_SD_NAME],
  132. channels,
  133. buffer.get()))
  134. {
  135. buildFault(
  136. channels,
  137. buffer.get(),
  138. FAULT_GENERIC,
  139. "Callback method call failed.");
  140. }
  141. }
  142. else
  143. {
  144. // this should never happen, since we should not be in
  145. // this state unless we originally found a method and
  146. // params during the first call to process.
  147. buildFault(
  148. channels,
  149. buffer.get(),
  150. FAULT_GENERIC,
  151. "Invalid LLSDRPC sever state - callback without method.");
  152. }
  153. pump->clearLock(mLock);
  154. mLock = 0;
  155. mState = STATE_DONE;
  156. break;
  157. case STATE_NONE:
  158. // lldebugs << "STATE_NONE" << llendl;
  159. default:
  160. {
  161. // First time we got here - process the SD request, and call
  162. // the method.
  163. PUMP_DEBUG;
  164. LLBufferStream istr(channels, buffer.get());
  165. mRequest.clear();
  166. LLSDSerialize::fromNotation(
  167. mRequest,
  168. istr,
  169. buffer->count(channels.in()));
  170. // { 'method':'...', 'parameter': ... }
  171. method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
  172. if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
  173. {
  174. ESDRPCSStatus rv = callMethod(
  175. method_name,
  176. mRequest[LLSDRPC_PARAMETER_SD_NAME],
  177. channels,
  178. buffer.get());
  179. switch(rv)
  180. {
  181. case ESDRPCS_DEFERRED:
  182. mPump = pump;
  183. mLock = pump->setLock();
  184. mState = STATE_DEFERRED;
  185. status = STATUS_BREAK;
  186. break;
  187. case ESDRPCS_CALLBACK:
  188. {
  189. mState = STATE_CALLBACK;
  190. LLPumpIO::LLLinkInfo link;
  191. link.mPipe = LLIOPipe::ptr_t(this);
  192. link.mChannels = channels;
  193. LLPumpIO::links_t links;
  194. links.push_back(link);
  195. pump->respond(links, buffer, context);
  196. mLock = pump->setLock();
  197. status = STATUS_BREAK;
  198. break;
  199. }
  200. case ESDRPCS_DONE:
  201. mState = STATE_DONE;
  202. break;
  203. case ESDRPCS_ERROR:
  204. default:
  205. buildFault(
  206. channels,
  207. buffer.get(),
  208. FAULT_GENERIC,
  209. "Method call failed.");
  210. break;
  211. }
  212. }
  213. else
  214. {
  215. // send a fault
  216. buildFault(
  217. channels,
  218. buffer.get(),
  219. FAULT_GENERIC,
  220. "Unable to find method and parameter in request.");
  221. }
  222. break;
  223. }
  224. }
  225. PUMP_DEBUG;
  226. return status;
  227. }
  228. // virtual
  229. ESDRPCSStatus LLSDRPCServer::callMethod(
  230. const std::string& method,
  231. const LLSD& params,
  232. const LLChannelDescriptors& channels,
  233. LLBufferArray* response)
  234. {
  235. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  236. // Try to find the method in the method table.
  237. ESDRPCSStatus rv = ESDRPCS_DONE;
  238. method_map_t::iterator it = mMethods.find(method);
  239. if(it != mMethods.end())
  240. {
  241. rv = (*it).second->call(params, channels, response);
  242. }
  243. else
  244. {
  245. it = mCallbackMethods.find(method);
  246. if(it == mCallbackMethods.end())
  247. {
  248. // method not found.
  249. std::ostringstream message;
  250. message << "rpc server unable to find method: " << method;
  251. buildFault(
  252. channels,
  253. response,
  254. FAULT_METHOD_NOT_FOUND,
  255. message.str());
  256. }
  257. else
  258. {
  259. // we found it in the callback methods - tell the process
  260. // to coordinate calling on the pump callback.
  261. return ESDRPCS_CALLBACK;
  262. }
  263. }
  264. return rv;
  265. }
  266. // virtual
  267. ESDRPCSStatus LLSDRPCServer::callbackMethod(
  268. const std::string& method,
  269. const LLSD& params,
  270. const LLChannelDescriptors& channels,
  271. LLBufferArray* response)
  272. {
  273. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  274. // Try to find the method in the callback method table.
  275. ESDRPCSStatus rv = ESDRPCS_DONE;
  276. method_map_t::iterator it = mCallbackMethods.find(method);
  277. if(it != mCallbackMethods.end())
  278. {
  279. rv = (*it).second->call(params, channels, response);
  280. }
  281. else
  282. {
  283. std::ostringstream message;
  284. message << "pcserver unable to find callback method: " << method;
  285. buildFault(
  286. channels,
  287. response,
  288. FAULT_METHOD_NOT_FOUND,
  289. message.str());
  290. }
  291. return rv;
  292. }
  293. // static
  294. void LLSDRPCServer::buildFault(
  295. const LLChannelDescriptors& channels,
  296. LLBufferArray* data,
  297. S32 code,
  298. const std::string& msg)
  299. {
  300. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  301. LLBufferStream ostr(channels, data);
  302. ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
  303. llinfos << "LLSDRPCServer::buildFault: " << code << ", " << msg << llendl;
  304. }
  305. // static
  306. void LLSDRPCServer::buildResponse(
  307. const LLChannelDescriptors& channels,
  308. LLBufferArray* data,
  309. const LLSD& response)
  310. {
  311. LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
  312. LLBufferStream ostr(channels, data);
  313. ostr << RESPONSE_PART_1;
  314. LLSDSerialize::toNotation(response, ostr);
  315. ostr << RESPONSE_PART_2;
  316. #if LL_DEBUG
  317. std::ostringstream debug_ostr;
  318. debug_ostr << "LLSDRPCServer::buildResponse: ";
  319. LLSDSerialize::toNotation(response, debug_ostr);
  320. llinfos << debug_ostr.str() << llendl;
  321. #endif
  322. }