diff options
Diffstat (limited to 'indra/llmessage/llsdrpcserver.cpp')
-rw-r--r-- | indra/llmessage/llsdrpcserver.cpp | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp new file mode 100644 index 0000000000..0348147a71 --- /dev/null +++ b/indra/llmessage/llsdrpcserver.cpp @@ -0,0 +1,322 @@ +/** + * @file llsdrpcserver.cpp + * @author Phoenix + * @date 2005-10-11 + * @brief Implementation of the LLSDRPCServer and related classes. + * + * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" +#include "llsdrpcserver.h" + +#include "llbuffer.h" +#include "llbufferstream.h" +#include "llmemtype.h" +#include "llpumpio.h" +#include "llsdserialize.h" +#include "llstl.h" + +static const char FAULT_PART_1[] = "{'fault':{'code':i"; +static const char FAULT_PART_2[] = ", 'description':'"; +static const char FAULT_PART_3[] = "'}}"; + +static const char RESPONSE_PART_1[] = "{'response':"; +static const char RESPONSE_PART_2[] = "}"; + +static const S32 FAULT_GENERIC = 1000; +static const S32 FAULT_METHOD_NOT_FOUND = 1001; + +static const std::string LLSDRPC_METHOD_SD_NAME("method"); +static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter"); + + +/** + * LLSDRPCServer + */ +LLSDRPCServer::LLSDRPCServer() : + mState(LLSDRPCServer::STATE_NONE), + mPump(NULL), + mLock(0) +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); +} + +LLSDRPCServer::~LLSDRPCServer() +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); + std::for_each( + mMethods.begin(), + mMethods.end(), + llcompose1( + DeletePointerFunctor<LLSDRPCMethodCallBase>(), + llselect2nd<method_map_t::value_type>())); + std::for_each( + mCallbackMethods.begin(), + mCallbackMethods.end(), + llcompose1( + DeletePointerFunctor<LLSDRPCMethodCallBase>(), + llselect2nd<method_map_t::value_type>())); +} + + +// virtual +ESDRPCSStatus LLSDRPCServer::deferredResponse( + const LLChannelDescriptors& channels, + LLBufferArray* data) { + // subclass should provide a sane implementation + return ESDRPCS_DONE; +} + +void LLSDRPCServer::clearLock() +{ + if(mLock && mPump) + { + mPump->clearLock(mLock); + mPump = NULL; + mLock = 0; + } +} + +// virtual +LLIOPipe::EStatus LLSDRPCServer::process_impl( + const LLChannelDescriptors& channels, + buffer_ptr_t& buffer, + bool& eos, + LLSD& context, + LLPumpIO* pump) +{ + PUMP_DEBUG; + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); +// lldebugs << "LLSDRPCServer::process_impl" << llendl; + // Once we have all the data, We need to read the sd on + // the the in channel, and respond on the out channel + if(!eos) return STATUS_BREAK; + if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET; + + std::string method_name; + LLIOPipe::EStatus status = STATUS_DONE; + + switch(mState) + { + case STATE_DEFERRED: + PUMP_DEBUG; + if(ESDRPCS_DONE != deferredResponse(channels, buffer.get())) + { + buildFault( + channels, + buffer.get(), + FAULT_GENERIC, + "deferred response failed."); + } + mState = STATE_DONE; + return STATUS_DONE; + + case STATE_DONE: +// lldebugs << "STATE_DONE" << llendl; + break; + case STATE_CALLBACK: +// lldebugs << "STATE_CALLBACK" << llendl; + PUMP_DEBUG; + method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); + if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) + { + if(ESDRPCS_DONE != callbackMethod( + method_name, + mRequest[LLSDRPC_PARAMETER_SD_NAME], + channels, + buffer.get())) + { + buildFault( + channels, + buffer.get(), + FAULT_GENERIC, + "Callback method call failed."); + } + } + else + { + // this should never happen, since we should not be in + // this state unless we originally found a method and + // params during the first call to process. + buildFault( + channels, + buffer.get(), + FAULT_GENERIC, + "Invalid LLSDRPC sever state - callback without method."); + } + pump->clearLock(mLock); + mLock = 0; + mState = STATE_DONE; + break; + case STATE_NONE: +// lldebugs << "STATE_NONE" << llendl; + default: + { + // First time we got here - process the SD request, and call + // the method. + PUMP_DEBUG; + LLBufferStream istr(channels, buffer.get()); + mRequest.clear(); + LLSDSerialize::fromNotation(mRequest, istr); + + // { 'method':'...', 'parameter': ... } + method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); + if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) + { + ESDRPCSStatus rv = callMethod( + method_name, + mRequest[LLSDRPC_PARAMETER_SD_NAME], + channels, + buffer.get()); + switch(rv) + { + case ESDRPCS_DEFERRED: + mPump = pump; + mLock = pump->setLock(); + mState = STATE_DEFERRED; + status = STATUS_BREAK; + break; + + case ESDRPCS_CALLBACK: + { + mState = STATE_CALLBACK; + LLPumpIO::LLLinkInfo link; + link.mPipe = LLIOPipe::ptr_t(this); + link.mChannels = channels; + LLPumpIO::links_t links; + links.push_back(link); + pump->respond(links, buffer, context); + mLock = pump->setLock(); + status = STATUS_BREAK; + break; + } + case ESDRPCS_DONE: + mState = STATE_DONE; + break; + case ESDRPCS_ERROR: + default: + buildFault( + channels, + buffer.get(), + FAULT_GENERIC, + "Method call failed."); + break; + } + } + else + { + // send a fault + buildFault( + channels, + buffer.get(), + FAULT_GENERIC, + "Unable to find method and parameter in request."); + } + break; + } + } + + PUMP_DEBUG; + return status; +} + +// virtual +ESDRPCSStatus LLSDRPCServer::callMethod( + const std::string& method, + const LLSD& params, + const LLChannelDescriptors& channels, + LLBufferArray* response) +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); + // Try to find the method in the method table. + ESDRPCSStatus rv = ESDRPCS_DONE; + method_map_t::iterator it = mMethods.find(method); + if(it != mMethods.end()) + { + rv = (*it).second->call(params, channels, response); + } + else + { + it = mCallbackMethods.find(method); + if(it == mCallbackMethods.end()) + { + // method not found. + std::ostringstream message; + message << "rpc server unable to find method: " << method; + buildFault( + channels, + response, + FAULT_METHOD_NOT_FOUND, + message.str()); + } + else + { + // we found it in the callback methods - tell the process + // to coordinate calling on the pump callback. + return ESDRPCS_CALLBACK; + } + } + return rv; +} + +// virtual +ESDRPCSStatus LLSDRPCServer::callbackMethod( + const std::string& method, + const LLSD& params, + const LLChannelDescriptors& channels, + LLBufferArray* response) +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); + // Try to find the method in the callback method table. + ESDRPCSStatus rv = ESDRPCS_DONE; + method_map_t::iterator it = mCallbackMethods.find(method); + if(it != mCallbackMethods.end()) + { + rv = (*it).second->call(params, channels, response); + } + else + { + std::ostringstream message; + message << "pcserver unable to find callback method: " << method; + buildFault( + channels, + response, + FAULT_METHOD_NOT_FOUND, + message.str()); + } + return rv; +} + +// static +void LLSDRPCServer::buildFault( + const LLChannelDescriptors& channels, + LLBufferArray* data, + S32 code, + const std::string& msg) +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); + LLBufferStream ostr(channels, data); + ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3; + llinfos << "LLSDRPCServer::buildFault: " << code << ", " << msg << llendl; +} + +// static +void LLSDRPCServer::buildResponse( + const LLChannelDescriptors& channels, + LLBufferArray* data, + const LLSD& response) +{ + LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER); + LLBufferStream ostr(channels, data); + ostr << RESPONSE_PART_1; + LLSDSerialize::toNotation(response, ostr); + ostr << RESPONSE_PART_2; +#if LL_DEBUG + std::ostringstream debug_ostr; + debug_ostr << "LLSDRPCServer::buildResponse: "; + LLSDSerialize::toNotation(response, debug_ostr); + llinfos << debug_ostr.str() << llendl; +#endif +} |