PageRenderTime 55ms CodeModel.GetById 31ms app.highlight 20ms 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
  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
 29#include "linden_common.h"
 30#include "llsdrpcserver.h"
 31
 32#include "llbuffer.h"
 33#include "llbufferstream.h"
 34#include "llmemtype.h"
 35#include "llpumpio.h"
 36#include "llsdserialize.h"
 37#include "llstl.h"
 38
 39static const char FAULT_PART_1[] = "{'fault':{'code':i";
 40static const char FAULT_PART_2[] = ", 'description':'";
 41static const char FAULT_PART_3[] = "'}}";
 42
 43static const char RESPONSE_PART_1[] = "{'response':";
 44static const char RESPONSE_PART_2[] = "}";
 45
 46static const S32 FAULT_GENERIC = 1000;
 47static const S32 FAULT_METHOD_NOT_FOUND = 1001;
 48
 49static const std::string LLSDRPC_METHOD_SD_NAME("method");
 50static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter");
 51
 52
 53/**
 54 * LLSDRPCServer
 55 */
 56LLSDRPCServer::LLSDRPCServer() :
 57	mState(LLSDRPCServer::STATE_NONE),
 58	mPump(NULL),
 59	mLock(0)
 60{
 61	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
 62}
 63
 64LLSDRPCServer::~LLSDRPCServer()
 65{
 66	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
 67	std::for_each(
 68		mMethods.begin(),
 69		mMethods.end(),
 70		llcompose1(
 71			DeletePointerFunctor<LLSDRPCMethodCallBase>(),
 72			llselect2nd<method_map_t::value_type>()));
 73	std::for_each(
 74		mCallbackMethods.begin(),
 75		mCallbackMethods.end(),
 76		llcompose1(
 77			DeletePointerFunctor<LLSDRPCMethodCallBase>(),
 78			llselect2nd<method_map_t::value_type>()));
 79}
 80
 81
 82// virtual
 83ESDRPCSStatus LLSDRPCServer::deferredResponse(
 84        const LLChannelDescriptors& channels,
 85	LLBufferArray* data) {
 86    // subclass should provide a sane implementation
 87    return ESDRPCS_DONE;
 88}
 89
 90void LLSDRPCServer::clearLock()
 91{
 92	if(mLock && mPump)
 93	{
 94		mPump->clearLock(mLock);
 95		mPump = NULL;
 96		mLock = 0;
 97	}
 98}
 99
100static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_SERVER("SDRPC Server");
101
102// virtual
103LLIOPipe::EStatus LLSDRPCServer::process_impl(
104	const LLChannelDescriptors& channels,
105	buffer_ptr_t& buffer,
106	bool& eos,
107	LLSD& context,
108	LLPumpIO* pump)
109{
110	LLFastTimer t(FTM_PROCESS_SDRPC_SERVER);
111	PUMP_DEBUG;
112	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
113//	lldebugs << "LLSDRPCServer::process_impl" << llendl;
114	// Once we have all the data, We need to read the sd on
115	// the the in channel, and respond on  the out channel
116	if(!eos) return STATUS_BREAK;
117	if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
118
119	std::string method_name;
120	LLIOPipe::EStatus status = STATUS_DONE;
121
122	switch(mState)
123	{
124	case STATE_DEFERRED:
125		PUMP_DEBUG;
126		if(ESDRPCS_DONE != deferredResponse(channels, buffer.get()))
127		{
128			buildFault(
129				channels,
130				buffer.get(),
131				FAULT_GENERIC,
132				"deferred response failed.");
133		}
134		mState = STATE_DONE;
135		return STATUS_DONE;
136
137	case STATE_DONE:
138//		lldebugs << "STATE_DONE" << llendl;
139		break;
140	case STATE_CALLBACK:
141//		lldebugs << "STATE_CALLBACK" << llendl;
142		PUMP_DEBUG;
143		method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
144		if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
145		{
146			if(ESDRPCS_DONE != callbackMethod(
147				   method_name,
148				   mRequest[LLSDRPC_PARAMETER_SD_NAME],
149				   channels,
150				   buffer.get()))
151			{
152				buildFault(
153					channels,
154					buffer.get(),
155					FAULT_GENERIC,
156					"Callback method call failed.");
157			}
158		}
159		else
160		{
161			// this should never happen, since we should not be in
162			// this state unless we originally found a method and
163			// params during the first call to process.
164			buildFault(
165				channels,
166				buffer.get(),
167				FAULT_GENERIC,
168				"Invalid LLSDRPC sever state - callback without method.");
169		}
170		pump->clearLock(mLock);
171		mLock = 0;
172		mState = STATE_DONE;
173		break;
174	case STATE_NONE:
175//		lldebugs << "STATE_NONE" << llendl;
176	default:
177	{
178		// First time we got here - process the SD request, and call
179		// the method.
180		PUMP_DEBUG;
181		LLBufferStream istr(channels, buffer.get());
182		mRequest.clear();
183		LLSDSerialize::fromNotation(
184			mRequest,
185			istr,
186			buffer->count(channels.in()));
187
188		// { 'method':'...', 'parameter': ... }
189		method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString();
190		if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME))
191		{
192			ESDRPCSStatus rv = callMethod(
193				method_name,
194				mRequest[LLSDRPC_PARAMETER_SD_NAME],
195				channels,
196				buffer.get());
197			switch(rv)
198			{
199			case ESDRPCS_DEFERRED:
200				mPump = pump;
201				mLock = pump->setLock();
202				mState = STATE_DEFERRED;
203				status = STATUS_BREAK;
204				break;
205
206			case ESDRPCS_CALLBACK:
207			{
208				mState = STATE_CALLBACK;
209				LLPumpIO::LLLinkInfo link;
210				link.mPipe = LLIOPipe::ptr_t(this);
211				link.mChannels = channels;
212				LLPumpIO::links_t links;
213				links.push_back(link);
214				pump->respond(links, buffer, context);
215				mLock = pump->setLock();
216				status = STATUS_BREAK;
217				break;
218			}
219			case ESDRPCS_DONE:
220				mState = STATE_DONE;
221				break;
222			case ESDRPCS_ERROR:
223			default:
224				buildFault(
225					channels,
226					buffer.get(),
227					FAULT_GENERIC,
228					"Method call failed.");
229				break;
230			}
231		}
232		else
233		{
234			// send a fault
235			buildFault(
236				channels,
237				buffer.get(),
238				FAULT_GENERIC,
239				"Unable to find method and parameter in request.");
240		}
241		break;
242	}
243	}
244
245	PUMP_DEBUG;
246	return status;
247}
248
249// virtual
250ESDRPCSStatus LLSDRPCServer::callMethod(
251	const std::string& method,
252	const LLSD& params,
253	const LLChannelDescriptors& channels,
254	LLBufferArray* response)
255{
256	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
257	// Try to find the method in the method table.
258	ESDRPCSStatus rv = ESDRPCS_DONE;
259	method_map_t::iterator it = mMethods.find(method);
260	if(it != mMethods.end())
261	{
262		rv = (*it).second->call(params, channels, response);
263	}
264	else
265	{
266		it = mCallbackMethods.find(method);
267		if(it == mCallbackMethods.end())
268		{
269			// method not found.
270			std::ostringstream message;
271			message << "rpc server unable to find method: " << method;
272			buildFault(
273				channels,
274				response,
275				FAULT_METHOD_NOT_FOUND,
276				message.str());
277		}
278		else
279		{
280			// we found it in the callback methods - tell the process
281			// to coordinate calling on the pump callback.
282			return ESDRPCS_CALLBACK;
283		}
284	}
285	return rv;
286}
287
288// virtual
289ESDRPCSStatus LLSDRPCServer::callbackMethod(
290	const std::string& method,
291	const LLSD& params,
292	const LLChannelDescriptors& channels,
293	LLBufferArray* response)
294{
295	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
296	// Try to find the method in the callback method table.
297	ESDRPCSStatus rv = ESDRPCS_DONE;
298	method_map_t::iterator it = mCallbackMethods.find(method);
299	if(it != mCallbackMethods.end())
300	{
301		rv = (*it).second->call(params, channels, response);
302	}
303	else
304	{
305		std::ostringstream message;
306		message << "pcserver unable to find callback method: " << method;
307		buildFault(
308			channels,
309			response,
310			FAULT_METHOD_NOT_FOUND,
311			message.str());
312	}
313	return rv;
314}
315
316// static
317void LLSDRPCServer::buildFault(
318	const LLChannelDescriptors& channels,
319	LLBufferArray* data,
320	S32 code,
321	const std::string& msg)
322{
323	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
324	LLBufferStream ostr(channels, data);
325	ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3;
326	llinfos << "LLSDRPCServer::buildFault: " << code << ", " << msg << llendl;
327}
328
329// static
330void LLSDRPCServer::buildResponse(
331	const LLChannelDescriptors& channels,
332	LLBufferArray* data,
333	const LLSD& response)
334{
335	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
336	LLBufferStream ostr(channels, data);
337	ostr << RESPONSE_PART_1;
338	LLSDSerialize::toNotation(response, ostr);
339	ostr << RESPONSE_PART_2;
340#if LL_DEBUG
341	std::ostringstream debug_ostr;
342	debug_ostr << "LLSDRPCServer::buildResponse: ";
343	LLSDSerialize::toNotation(response, debug_ostr);
344	llinfos << debug_ostr.str() << llendl;
345#endif
346}