llsdrpcserver.cpp

Go to the documentation of this file.
00001 
00034 #include "linden_common.h"
00035 #include "llsdrpcserver.h"
00036 
00037 #include "llbuffer.h"
00038 #include "llbufferstream.h"
00039 #include "llmemtype.h"
00040 #include "llpumpio.h"
00041 #include "llsdserialize.h"
00042 #include "llstl.h"
00043 
00044 static const char FAULT_PART_1[] = "{'fault':{'code':i";
00045 static const char FAULT_PART_2[] = ", 'description':'";
00046 static const char FAULT_PART_3[] = "'}}";
00047 
00048 static const char RESPONSE_PART_1[] = "{'response':";
00049 static const char RESPONSE_PART_2[] = "}";
00050 
00051 static const S32 FAULT_GENERIC = 1000;
00052 static const S32 FAULT_METHOD_NOT_FOUND = 1001;
00053 
00054 static const std::string LLSDRPC_METHOD_SD_NAME("method");
00055 static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter");
00056 
00057 
00061 LLSDRPCServer::LLSDRPCServer() :
00062         mState(LLSDRPCServer::STATE_NONE),
00063         mPump(NULL),
00064         mLock(0)
00065 {
00066         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00067 }
00068 
00069 LLSDRPCServer::~LLSDRPCServer()
00070 {
00071         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00072         std::for_each(
00073                 mMethods.begin(),
00074                 mMethods.end(),
00075                 llcompose1(
00076                         DeletePointerFunctor<LLSDRPCMethodCallBase>(),
00077                         llselect2nd<method_map_t::value_type>()));
00078         std::for_each(
00079                 mCallbackMethods.begin(),
00080                 mCallbackMethods.end(),
00081                 llcompose1(
00082                         DeletePointerFunctor<LLSDRPCMethodCallBase>(),
00083                         llselect2nd<method_map_t::value_type>()));
00084 }
00085 
00086 
00087 // virtual
00088 ESDRPCSStatus LLSDRPCServer::deferredResponse(
00089         const LLChannelDescriptors& channels,
00090         LLBufferArray* data) {
00091     // subclass should provide a sane implementation
00092     return ESDRPCS_DONE;
00093 }
00094 
00095 void LLSDRPCServer::clearLock()
00096 {
00097         if(mLock && mPump)
00098         {
00099                 mPump->clearLock(mLock);
00100                 mPump = NULL;
00101                 mLock = 0;
00102         }
00103 }
00104 
00105 // virtual
00106 LLIOPipe::EStatus LLSDRPCServer::process_impl(
00107         const LLChannelDescriptors& channels,
00108         buffer_ptr_t& buffer,
00109         bool& eos,
00110         LLSD& context,
00111         LLPumpIO* pump)
00112 {
00113         PUMP_DEBUG;
00114         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00115 //      lldebugs << "LLSDRPCServer::process_impl" << llendl;
00116         // Once we have all the data, We need to read the sd on
00117         // the the in channel, and respond on  the out channel
00118         if(!eos) return STATUS_BREAK;
00119         if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
00120 
00121         std::string method_name;
00122         LLIOPipe::EStatus status = STATUS_DONE;
00123 
00124         switch(mState)
00125         {
00126         case STATE_DEFERRED:
00127                 PUMP_DEBUG;
00128                 if(ESDRPCS_DONE != deferredResponse(channels, buffer.get()))
00129                 {
00130                         buildFault(
00131                                 channels,
00132                                 buffer.get(),
00133                                 FAULT_GENERIC,
00134                                 "deferred response failed.");
00135                 }
00136                 mState = STATE_DONE;
00137                 return STATUS_DONE;
00138 
00139         case STATE_DONE:
00140 //              lldebugs << "STATE_DONE" << llendl;
00141                 break;
00142         case STATE_CALLBACK:
00143 //              lldebugs << "STATE_CALLBACK" << llendl;
00144                 PUMP_DEBUG;
00145                 method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
00146                 if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
00147                 {
00148                         if(ESDRPCS_DONE != callbackMethod(
00149                                    method_name,
00150                                    mRequest[LLSDRPC_PARAMETER_SD_NAME],
00151                                    channels,
00152                                    buffer.get()))
00153                         {
00154                                 buildFault(
00155                                         channels,
00156                                         buffer.get(),
00157                                         FAULT_GENERIC,
00158                                         "Callback method call failed.");
00159                         }
00160                 }
00161                 else
00162                 {
00163                         // this should never happen, since we should not be in
00164                         // this state unless we originally found a method and
00165                         // params during the first call to process.
00166                         buildFault(
00167                                 channels,
00168                                 buffer.get(),
00169                                 FAULT_GENERIC,
00170                                 "Invalid LLSDRPC sever state - callback without method.");
00171                 }
00172                 pump->clearLock(mLock);
00173                 mLock = 0;
00174                 mState = STATE_DONE;
00175                 break;
00176         case STATE_NONE:
00177 //              lldebugs << "STATE_NONE" << llendl;
00178         default:
00179         {
00180                 // First time we got here - process the SD request, and call
00181                 // the method.
00182                 PUMP_DEBUG;
00183                 LLBufferStream istr(channels, buffer.get());
00184                 mRequest.clear();
00185                 LLSDSerialize::fromNotation(mRequest, istr);
00186 
00187                 // { 'method':'...', 'parameter': ... }
00188                 method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
00189                 if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
00190                 {
00191                         ESDRPCSStatus rv = callMethod(
00192                                 method_name,
00193                                 mRequest[LLSDRPC_PARAMETER_SD_NAME],
00194                                 channels,
00195                                 buffer.get());
00196                         switch(rv)
00197                         {
00198                         case ESDRPCS_DEFERRED:
00199                                 mPump = pump;
00200                                 mLock = pump->setLock();
00201                                 mState = STATE_DEFERRED;
00202                                 status = STATUS_BREAK;
00203                                 break;
00204 
00205                         case ESDRPCS_CALLBACK:
00206                         {
00207                                 mState = STATE_CALLBACK;
00208                                 LLPumpIO::LLLinkInfo link;
00209                                 link.mPipe = LLIOPipe::ptr_t(this);
00210                                 link.mChannels = channels;
00211                                 LLPumpIO::links_t links;
00212                                 links.push_back(link);
00213                                 pump->respond(links, buffer, context);
00214                                 mLock = pump->setLock();
00215                                 status = STATUS_BREAK;
00216                                 break;
00217                         }
00218                         case ESDRPCS_DONE:
00219                                 mState = STATE_DONE;
00220                                 break;
00221                         case ESDRPCS_ERROR:
00222                         default:
00223                                 buildFault(
00224                                         channels,
00225                                         buffer.get(),
00226                                         FAULT_GENERIC,
00227                                         "Method call failed.");
00228                                 break;
00229                         }
00230                 }
00231                 else
00232                 {
00233                         // send a fault
00234                         buildFault(
00235                                 channels,
00236                                 buffer.get(),
00237                                 FAULT_GENERIC,
00238                                 "Unable to find method and parameter in request.");
00239                 }
00240                 break;
00241         }
00242         }
00243 
00244         PUMP_DEBUG;
00245         return status;
00246 }
00247 
00248 // virtual
00249 ESDRPCSStatus LLSDRPCServer::callMethod(
00250         const std::string& method,
00251         const LLSD& params,
00252         const LLChannelDescriptors& channels,
00253         LLBufferArray* response)
00254 {
00255         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00256         // Try to find the method in the method table.
00257         ESDRPCSStatus rv = ESDRPCS_DONE;
00258         method_map_t::iterator it = mMethods.find(method);
00259         if(it != mMethods.end())
00260         {
00261                 rv = (*it).second->call(params, channels, response);
00262         }
00263         else
00264         {
00265                 it = mCallbackMethods.find(method);
00266                 if(it == mCallbackMethods.end())
00267                 {
00268                         // method not found.
00269                         std::ostringstream message;
00270                         message << "rpc server unable to find method: " << method;
00271                         buildFault(
00272                                 channels,
00273                                 response,
00274                                 FAULT_METHOD_NOT_FOUND,
00275                                 message.str());
00276                 }
00277                 else
00278                 {
00279                         // we found it in the callback methods - tell the process
00280                         // to coordinate calling on the pump callback.
00281                         return ESDRPCS_CALLBACK;
00282                 }
00283         }
00284         return rv;
00285 }
00286 
00287 // virtual
00288 ESDRPCSStatus LLSDRPCServer::callbackMethod(
00289         const std::string& method,
00290         const LLSD& params,
00291         const LLChannelDescriptors& channels,
00292         LLBufferArray* response)
00293 {
00294         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00295         // Try to find the method in the callback method table.
00296         ESDRPCSStatus rv = ESDRPCS_DONE;
00297         method_map_t::iterator it = mCallbackMethods.find(method);
00298         if(it != mCallbackMethods.end())
00299         {
00300                 rv = (*it).second->call(params, channels, response);
00301         }
00302         else
00303         {
00304                 std::ostringstream message;
00305                 message << "pcserver unable to find callback method: " << method;
00306                 buildFault(
00307                         channels,
00308                         response,
00309                         FAULT_METHOD_NOT_FOUND,
00310                         message.str());
00311         }
00312         return rv;
00313 }
00314 
00315 // static
00316 void LLSDRPCServer::buildFault(
00317         const LLChannelDescriptors& channels,
00318         LLBufferArray* data,
00319         S32 code,
00320         const std::string& msg)
00321 {
00322         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00323         LLBufferStream ostr(channels, data);
00324         ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
00325         llinfos << "LLSDRPCServer::buildFault: " << code << ", " << msg << llendl;
00326 }
00327 
00328 // static
00329 void LLSDRPCServer::buildResponse(
00330         const LLChannelDescriptors& channels,
00331         LLBufferArray* data,
00332         const LLSD& response)
00333 {
00334         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00335         LLBufferStream ostr(channels, data);
00336         ostr << RESPONSE_PART_1;
00337         LLSDSerialize::toNotation(response, ostr);
00338         ostr << RESPONSE_PART_2;
00339 #if LL_DEBUG
00340         std::ostringstream debug_ostr;
00341         debug_ostr << "LLSDRPCServer::buildResponse: ";
00342         LLSDSerialize::toNotation(response, debug_ostr);
00343         llinfos << debug_ostr.str() << llendl;
00344 #endif
00345 }

Generated on Thu Jul 1 06:09:08 2010 for Second Life Viewer by  doxygen 1.4.7