/indra/llmessage/llsdrpcserver.h

https://bitbucket.org/lindenlab/viewer-beta/ · C++ Header · 360 lines · 144 code · 33 blank · 183 comment · 0 complexity · 324970ba81c223cef1becb9286abe600 MD5 · raw file

  1. /**
  2. * @file llsdrpcserver.h
  3. * @author Phoenix
  4. * @date 2005-10-11
  5. * @brief Declaration of the structured data remote procedure call server.
  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. #ifndef LL_LLSDRPCSERVER_H
  29. #define LL_LLSDRPCSERVER_H
  30. /**
  31. * I've set this up to be pretty easy to use when you want to make a
  32. * structured data rpc server which responds to methods by
  33. * name. Derive a class from the LLSDRPCServer, and during
  34. * construction (or initialization if you have the luxury) map method
  35. * names to pointers to member functions. This will look a lot like:
  36. *
  37. * <code>
  38. * class LLMessageAgents : public LLSDRPCServer {<br>
  39. * public:<br>
  40. * typedef LLSDRPCServer<LLUsher> mem_fn_t;<br>
  41. * LLMessageAgents() {<br>
  42. * mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br>
  43. * mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br>
  44. * }<br>
  45. * protected:<br>
  46. * rpc_IM(const LLSD& params,
  47. * const LLChannelDescriptors& channels,
  48. * LLBufferArray* data)
  49. * {...}<br>
  50. * rpc_Alert(const LLSD& params,
  51. * const LLChannelDescriptors& channels,
  52. * LLBufferArray* data)
  53. * {...}<br>
  54. * };<br>
  55. * </code>
  56. *
  57. * The params are an array where each element in the array is a single
  58. * parameter in the call.
  59. *
  60. * It is up to you to pack a valid serialized llsd response into the
  61. * data object passed into the method, but you can use the helper
  62. * methods below to help.
  63. */
  64. #include <map>
  65. #include "lliopipe.h"
  66. #include "lliohttpserver.h"
  67. #include "llfiltersd2xmlrpc.h"
  68. class LLSD;
  69. /**
  70. * @brief Enumeration for specifying server method call status. This
  71. * enumeration controls how the server class will manage the pump
  72. * process/callback mechanism.
  73. */
  74. enum ESDRPCSStatus
  75. {
  76. // The call went ok, but the response is not yet ready. The
  77. // method will arrange for the clearLock() call to be made at
  78. // a later date, after which, once the chain is being pumped
  79. // again, deferredResponse() will be called to gather the result
  80. ESDRPCS_DEFERRED,
  81. // The LLSDRPCServer would like to handle the method on the
  82. // callback queue of the pump.
  83. ESDRPCS_CALLBACK,
  84. // The method call finished and generated output.
  85. ESDRPCS_DONE,
  86. // Method failed for some unspecified reason - you should avoid
  87. // this. A generic fault will be sent to the output.
  88. ESDRPCS_ERROR,
  89. ESDRPCS_COUNT,
  90. };
  91. /**
  92. * @class LLSDRPCMethodCallBase
  93. * @brief Base class for calling a member function in an sd rpcserver
  94. * implementation.
  95. */
  96. class LLSDRPCMethodCallBase
  97. {
  98. public:
  99. LLSDRPCMethodCallBase() {}
  100. virtual ~LLSDRPCMethodCallBase() {}
  101. virtual ESDRPCSStatus call(
  102. const LLSD& params,
  103. const LLChannelDescriptors& channels,
  104. LLBufferArray* response) = 0;
  105. protected:
  106. };
  107. /**
  108. * @class LLSDRPCMethodCall
  109. * @brief Class which implements member function calls.
  110. */
  111. template<class Server>
  112. class LLSDRPCMethodCall : public LLSDRPCMethodCallBase
  113. {
  114. public:
  115. typedef ESDRPCSStatus (Server::*mem_fn)(
  116. const LLSD& params,
  117. const LLChannelDescriptors& channels,
  118. LLBufferArray* data);
  119. LLSDRPCMethodCall(Server* s, mem_fn fn) :
  120. mServer(s),
  121. mMemFn(fn)
  122. {
  123. }
  124. virtual ~LLSDRPCMethodCall() {}
  125. virtual ESDRPCSStatus call(
  126. const LLSD& params,
  127. const LLChannelDescriptors& channels,
  128. LLBufferArray* data)
  129. {
  130. return (*mServer.*mMemFn)(params, channels, data);
  131. }
  132. protected:
  133. Server* mServer;
  134. mem_fn mMemFn;
  135. //bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data);
  136. };
  137. /**
  138. * @class LLSDRPCServer
  139. * @brief Basic implementation of a structure data rpc server
  140. *
  141. * The rpc server is also designed to appropriately straddle the pump
  142. * <code>process()</code> and <code>callback()</code> to specify which
  143. * thread you want to work on when handling a method call. The
  144. * <code>mMethods</code> methods are called from
  145. * <code>process()</code>, while the <code>mCallbackMethods</code> are
  146. * called when a pump is in a <code>callback()</code> cycle.
  147. */
  148. class LLSDRPCServer : public LLIOPipe
  149. {
  150. public:
  151. LLSDRPCServer();
  152. virtual ~LLSDRPCServer();
  153. /**
  154. * enumeration for generic fault codes
  155. */
  156. enum
  157. {
  158. FAULT_BAD_REQUEST = 2000,
  159. FAULT_NO_RESPONSE = 2001,
  160. };
  161. /**
  162. * @brief Call this method to return an rpc fault.
  163. *
  164. * @param channel The channel for output on the data buffer
  165. * @param data buffer which will recieve the final output
  166. * @param code The fault code
  167. * @param msg The fault message
  168. */
  169. static void buildFault(
  170. const LLChannelDescriptors& channels,
  171. LLBufferArray* data,
  172. S32 code,
  173. const std::string& msg);
  174. /**
  175. * @brief Call this method to build an rpc response.
  176. *
  177. * @param channel The channel for output on the data buffer
  178. * @param data buffer which will recieve the final output
  179. * @param response The return value from the method call
  180. */
  181. static void buildResponse(
  182. const LLChannelDescriptors& channels,
  183. LLBufferArray* data,
  184. const LLSD& response);
  185. protected:
  186. /* @name LLIOPipe virtual implementations
  187. */
  188. //@{
  189. /**
  190. * @brief Process the data in buffer
  191. */
  192. virtual EStatus process_impl(
  193. const LLChannelDescriptors& channels,
  194. buffer_ptr_t& buffer,
  195. bool& eos,
  196. LLSD& context,
  197. LLPumpIO* pump);
  198. //@}
  199. protected:
  200. /**
  201. * @brief Enumeration to track the state of the rpc server instance
  202. */
  203. enum EState
  204. {
  205. STATE_NONE,
  206. STATE_CALLBACK,
  207. STATE_DEFERRED,
  208. STATE_DONE
  209. };
  210. /**
  211. * @brief This method is called when an http post comes in.
  212. *
  213. * The default behavior is to look at the method name, look up the
  214. * method in the method table, and call it. If the method is not
  215. * found, this function will build a fault response. You can
  216. * implement your own version of this function if you want to hard
  217. * wire some behavior or optimize things a bit.
  218. * @param method The method name being called
  219. * @param params The parameters
  220. * @param channel The channel for output on the data buffer
  221. * @param data The http data
  222. * @return Returns the status of the method call, done/deferred/etc
  223. */
  224. virtual ESDRPCSStatus callMethod(
  225. const std::string& method,
  226. const LLSD& params,
  227. const LLChannelDescriptors& channels,
  228. LLBufferArray* data);
  229. /**
  230. * @brief This method is called when a pump callback is processed.
  231. *
  232. * The default behavior is to look at the method name, look up the
  233. * method in the callback method table, and call it. If the method
  234. * is not found, this function will build a fault response. You
  235. * can implement your own version of this function if you want to
  236. * hard wire some behavior or optimize things a bit.
  237. * @param method The method name being called
  238. * @param params The parameters
  239. * @param channel The channel for output on the data buffer
  240. * @param data The http data
  241. * @return Returns the status of the method call, done/deferred/etc
  242. */
  243. virtual ESDRPCSStatus callbackMethod(
  244. const std::string& method,
  245. const LLSD& params,
  246. const LLChannelDescriptors& channels,
  247. LLBufferArray* data);
  248. /**
  249. * @brief Called after a deferred service is unlocked
  250. *
  251. * If a method returns ESDRPCS_DEFERRED, then the service chain
  252. * will be locked and not processed until some other system calls
  253. * clearLock() on the service instance again. At that point,
  254. * once the pump starts processing the chain again, this method
  255. * will be called so the service can output the final result
  256. * into the buffers.
  257. */
  258. virtual ESDRPCSStatus deferredResponse(
  259. const LLChannelDescriptors& channels,
  260. LLBufferArray* data);
  261. // donovan put this public here 7/27/06
  262. public:
  263. /**
  264. * @brief unlock a service that as ESDRPCS_DEFERRED
  265. */
  266. void clearLock();
  267. protected:
  268. EState mState;
  269. LLSD mRequest;
  270. LLPumpIO* mPump;
  271. S32 mLock;
  272. typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t;
  273. method_map_t mMethods;
  274. method_map_t mCallbackMethods;
  275. };
  276. /**
  277. * @name Helper Templates for making LLHTTPNodes
  278. *
  279. * These templates help in creating nodes for handing a service from
  280. * either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer.
  281. *
  282. * To use it:
  283. * \code
  284. * class LLUsefulServer : public LLSDRPCServer { ... }
  285. *
  286. * LLHTTPNode& root = LLCreateHTTPWireServer(...);
  287. * root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>);
  288. * root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>);
  289. * \endcode
  290. */
  291. //@{
  292. template<class Server>
  293. class LLSDRPCServerFactory : public LLChainIOFactory
  294. {
  295. public:
  296. virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
  297. {
  298. lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
  299. chain.push_back(LLIOPipe::ptr_t(new Server));
  300. return true;
  301. }
  302. };
  303. template<class Server>
  304. class LLSDRPCNode : public LLHTTPNodeForFactory<
  305. LLSDRPCServerFactory<Server> >
  306. {
  307. };
  308. template<class Server>
  309. class LLXMLRPCServerFactory : public LLChainIOFactory
  310. {
  311. public:
  312. virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
  313. {
  314. lldebugs << "LLXMLSDRPCServerFactory::build" << llendl;
  315. chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD));
  316. chain.push_back(LLIOPipe::ptr_t(new Server));
  317. chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse));
  318. return true;
  319. }
  320. };
  321. template<class Server>
  322. class LLXMLRPCNode : public LLHTTPNodeForFactory<
  323. LLXMLRPCServerFactory<Server> >
  324. {
  325. };
  326. //@}
  327. #endif // LL_LLSDRPCSERVER_H