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(
00186                         mRequest,
00187                         istr,
00188                         buffer->count(channels.in()));
00189 
00190                 // { 'method':'...', 'parameter': ... }
00191                 method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
00192                 if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
00193                 {
00194                         ESDRPCSStatus rv = callMethod(
00195                                 method_name,
00196                                 mRequest[LLSDRPC_PARAMETER_SD_NAME],
00197                                 channels,
00198                                 buffer.get());
00199                         switch(rv)
00200                         {
00201                         case ESDRPCS_DEFERRED:
00202                                 mPump = pump;
00203                                 mLock = pump->setLock();
00204                                 mState = STATE_DEFERRED;
00205                                 status = STATUS_BREAK;
00206                                 break;
00207 
00208                         case ESDRPCS_CALLBACK:
00209                         {
00210                                 mState = STATE_CALLBACK;
00211                                 LLPumpIO::LLLinkInfo link;
00212                                 link.mPipe = LLIOPipe::ptr_t(this);
00213                                 link.mChannels = channels;
00214                                 LLPumpIO::links_t links;
00215                                 links.push_back(link);
00216                                 pump->respond(links, buffer, context);
00217                                 mLock = pump->setLock();
00218                                 status = STATUS_BREAK;
00219                                 break;
00220                         }
00221                         case ESDRPCS_DONE:
00222                                 mState = STATE_DONE;
00223                                 break;
00224                         case ESDRPCS_ERROR:
00225                         default:
00226                                 buildFault(
00227                                         channels,
00228                                         buffer.get(),
00229                                         FAULT_GENERIC,
00230                                         "Method call failed.");
00231                                 break;
00232                         }
00233                 }
00234                 else
00235                 {
00236                         // send a fault
00237                         buildFault(
00238                                 channels,
00239                                 buffer.get(),
00240                                 FAULT_GENERIC,
00241                                 "Unable to find method and parameter in request.");
00242                 }
00243                 break;
00244         }
00245         }
00246 
00247         PUMP_DEBUG;
00248         return status;
00249 }
00250 
00251 // virtual
00252 ESDRPCSStatus LLSDRPCServer::callMethod(
00253         const std::string& method,
00254         const LLSD& params,
00255         const LLChannelDescriptors& channels,
00256         LLBufferArray* response)
00257 {
00258         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00259         // Try to find the method in the method table.
00260         ESDRPCSStatus rv = ESDRPCS_DONE;
00261         method_map_t::iterator it = mMethods.find(method);
00262         if(it != mMethods.end())
00263         {
00264                 rv = (*it).second->call(params, channels, response);
00265         }
00266         else
00267         {
00268                 it = mCallbackMethods.find(method);
00269                 if(it == mCallbackMethods.end())
00270                 {
00271                         // method not found.
00272                         std::ostringstream message;
00273                         message << "rpc server unable to find method: " << method;
00274                         buildFault(
00275                                 channels,
00276                                 response,
00277                                 FAULT_METHOD_NOT_FOUND,
00278                                 message.str());
00279                 }
00280                 else
00281                 {
00282                         // we found it in the callback methods - tell the process
00283                         // to coordinate calling on the pump callback.
00284                         return ESDRPCS_CALLBACK;
00285                 }
00286         }
00287         return rv;
00288 }
00289 
00290 // virtual
00291 ESDRPCSStatus LLSDRPCServer::callbackMethod(
00292         const std::string& method,
00293         const LLSD& params,
00294         const LLChannelDescriptors& channels,
00295         LLBufferArray* response)
00296 {
00297         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00298         // Try to find the method in the callback method table.
00299         ESDRPCSStatus rv = ESDRPCS_DONE;
00300         method_map_t::iterator it = mCallbackMethods.find(method);
00301         if(it != mCallbackMethods.end())
00302         {
00303                 rv = (*it).second->call(params, channels, response);
00304         }
00305         else
00306         {
00307                 std::ostringstream message;
00308                 message << "pcserver unable to find callback method: " << method;
00309                 buildFault(
00310                         channels,
00311                         response,
00312                         FAULT_METHOD_NOT_FOUND,
00313                         message.str());
00314         }
00315         return rv;
00316 }
00317 
00318 // static
00319 void LLSDRPCServer::buildFault(
00320         const LLChannelDescriptors& channels,
00321         LLBufferArray* data,
00322         S32 code,
00323         const std::string& msg)
00324 {
00325         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00326         LLBufferStream ostr(channels, data);
00327         ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
00328         llinfos << "LLSDRPCServer::buildFault: " << code << ", " << msg << llendl;
00329 }
00330 
00331 // static
00332 void LLSDRPCServer::buildResponse(
00333         const LLChannelDescriptors& channels,
00334         LLBufferArray* data,
00335         const LLSD& response)
00336 {
00337         LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
00338         LLBufferStream ostr(channels, data);
00339         ostr << RESPONSE_PART_1;
00340         LLSDSerialize::toNotation(response, ostr);
00341         ostr << RESPONSE_PART_2;
00342 #if LL_DEBUG
00343         std::ostringstream debug_ostr;
00344         debug_ostr << "LLSDRPCServer::buildResponse: ";
00345         LLSDSerialize::toNotation(response, debug_ostr);
00346         llinfos << debug_ostr.str() << llendl;
00347 #endif
00348 }

Generated on Fri May 16 08:32:30 2008 for SecondLife by  doxygen 1.5.5